diff --git a/CHANGELOG.md b/CHANGELOG.md index efb4da9c9..dce32addd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ Classify the change according to the following categories: ### Deprecated ### Removed +## v0.32.2 +### Fixed +- Fixed bug in multiple PVs pv_to_location dictionary creation. +- Fixed bug in reporting of grid purchase results when multiple energy tiers are present. +- Fixed bug in TOU demand charge calculation when multiple demand tiers are present. + ## v0.32.1 ### Fixed - In `backup_reliability.jl`: diff --git a/Project.toml b/Project.toml index 691553501..64f51da9a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "REopt" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" authors = ["Nick Laws", "Hallie Dunham ", "Bill Becker ", "Bhavesh Rathod ", "Alex Zolan ", "Amanda Farthing "] -version = "0.32.1" +version = "0.32.2" [deps] ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3" diff --git a/src/constraints/electric_utility_constraints.jl b/src/constraints/electric_utility_constraints.jl index c6942d542..c4893ef66 100644 --- a/src/constraints/electric_utility_constraints.jl +++ b/src/constraints/electric_utility_constraints.jl @@ -356,7 +356,7 @@ function add_elec_utility_expressions(m, p; _n="") if !isempty(p.s.electric_tariff.tou_demand_rates) m[Symbol("DemandTOUCharges"*_n)] = @expression(m, p.pwf_e * sum( p.s.electric_tariff.tou_demand_rates[r] * m[Symbol("dvPeakDemandTOU"*_n)][r, tier] - for r in p.ratchets, tier in p.s.electric_tariff.n_tou_demand_tiers) + for r in p.ratchets, tier in 1:p.s.electric_tariff.n_tou_demand_tiers) ) else m[Symbol("DemandTOUCharges"*_n)] = 0 diff --git a/src/core/reopt_inputs.jl b/src/core/reopt_inputs.jl index f170918c2..d402b409c 100644 --- a/src/core/reopt_inputs.jl +++ b/src/core/reopt_inputs.jl @@ -310,10 +310,10 @@ function setup_tech_inputs(s::AbstractScenario) seg_max_size = Dict{String, Dict{Int, Real}}() seg_yint = Dict{String, Dict{Int, Real}}() - # PV specific arrays pvlocations = [:roof, :ground, :both] - pv_to_location = Dict(t => Dict(loc => 0) for (t, loc) in zip(techs.pv, pvlocations)) - maxsize_pv_locations = DenseAxisArray([1.0e5, 1.0e5, 1.0e5], pvlocations) + d = Dict(loc => 0 for loc in pvlocations) + pv_to_location = Dict(t => copy(d) for t in techs.pv) + maxsize_pv_locations = DenseAxisArray([1.0e9, 1.0e9, 1.0e9], pvlocations) # default to large max size per location. Max size by roof, ground, both if !isempty(techs.pv) @@ -471,11 +471,11 @@ function setup_pv_inputs(s::AbstractScenario, max_sizes, min_sizes, roof_existing_pv_kw, ground_existing_pv_kw, both_existing_pv_kw = 0.0, 0.0, 0.0 roof_max_kw, land_max_kw = 1.0e5, 1.0e5 - for pv in s.pvs + for pv in s.pvs production_factor[pv.name, :] = get_production_factor(pv, s.site.latitude, s.site.longitude; time_steps_per_hour=s.settings.time_steps_per_hour) for location in pvlocations - if pv.location == location + if pv.location == String(location) # Must convert symbol to string pv_to_location[pv.name][location] = 1 else pv_to_location[pv.name][location] = 0 diff --git a/src/results/electric_utility.jl b/src/results/electric_utility.jl index 7eb0ef6ee..328de62da 100644 --- a/src/results/electric_utility.jl +++ b/src/results/electric_utility.jl @@ -59,17 +59,17 @@ function add_electric_utility_results(m::JuMP.AbstractModel, p::AbstractInputs, r = Dict{String, Any}() Year1UtilityEnergy = p.hours_per_time_step * sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] - for ts in p.time_steps, tier in p.s.electric_tariff.n_energy_tiers) + for ts in p.time_steps, tier in 1:p.s.electric_tariff.n_energy_tiers) r["annual_energy_supplied_kwh"] = round(value(Year1UtilityEnergy), digits=2) if !isempty(p.s.storage.types.elec) - GridToLoad = (sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in p.s.electric_tariff.n_energy_tiers) + GridToLoad = (sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in 1:p.s.electric_tariff.n_energy_tiers) - sum(m[Symbol("dvGridToStorage"*_n)][b, ts] for b in p.s.storage.types.elec) for ts in p.time_steps) GridToBatt = (sum(m[Symbol("dvGridToStorage"*_n)][b, ts] for b in p.s.storage.types.elec) for ts in p.time_steps) else - GridToLoad = (sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in p.s.electric_tariff.n_energy_tiers) + GridToLoad = (sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in 1:p.s.electric_tariff.n_energy_tiers) for ts in p.time_steps) GridToBatt = zeros(length(p.time_steps)) end @@ -107,7 +107,7 @@ function add_electric_utility_results(m::JuMP.AbstractModel, p::MPCInputs, d::Di Year1UtilityEnergy = p.hours_per_time_step * sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for ts in p.time_steps, - tier in p.s.electric_tariff.n_energy_tiers) + tier in 1:p.s.electric_tariff.n_energy_tiers) r["energy_supplied_kwh"] = round(value(Year1UtilityEnergy), digits=2) if p.s.storage.attr["ElectricStorage"].size_kwh > 0 @@ -119,7 +119,7 @@ function add_electric_utility_results(m::JuMP.AbstractModel, p::MPCInputs, d::Di GridToBatt = zeros(length(p.time_steps)) end GridToLoad = @expression(m, [ts in p.time_steps], - sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in p.s.electric_tariff.n_energy_tiers) - + sum(m[Symbol("dvGridPurchase"*_n)][ts, tier] for tier in 1:p.s.electric_tariff.n_energy_tiers) - GridToBatt[ts] ) r["to_load_series_kw"] = round.(value.(GridToLoad), digits=3).data diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index 1f5529f71..3189e795c 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -566,6 +566,8 @@ end m = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) results = run_reopt(m, "./scenarios/tiered_rate.json") @test results["ElectricTariff"]["year_one_energy_cost_before_tax"] ≈ 2342.88 + @test results["ElectricUtility"]["annual_energy_supplied_kwh"] ≈ 24000.0 atol=0.1 + @test results["ElectricLoad"]["annual_calculated_kwh"] ≈ 24000.0 atol=0.1 end @testset "Lookback Demand Charges" begin