Skip to content

Commit a399b08

Browse files
committed
Merge branch 'develop' into gridRE-dev
2 parents 3c0004b + 3dfbb76 commit a399b08

19 files changed

+9194
-119
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,21 @@ Classify the change according to the following categories:
5151
### Fixed
5252
- Make **ElectricTariff** **export_rate_beyond_net_metering_limit** and **wholesale_rate** with sub-hour time step work
5353

54-
## Develop
55-
## leap-year-fix
54+
## develop
55+
### Added
56+
- New parameter `force_dispatch` in the **ASHPSpaceHeater** and **ASHPWaterHeater** technologies (default = `true`). When kept at `true`, the ASHP's thermal output will be the minimum of the site load(s) served and the system size (adjusted for timestep-specific capacity factor) in each period. If set to `false`, ASHP will do economic dispatch considering COP and CF along with electricity prices.
5657
### Fixed
58+
- Align heating and cooling load profiles based on electric load year input, if using custom electric load profile with simulated (CRB or schedule-based flatloads) heating/cooling loads
5759
- Handling of leap years for `ElectricLoad.loads_kw` inputs to align with URDB rate structures
60+
### Changed
61+
- Make `year` input required with any custom load profile input (e.g. `ElectricLoad.loads_kw`, `SpaceHeatingLoad.fuel_loads_mmbtu_per_hour`)
62+
- Shift and adjust CRB load profiles (i.e. with `doe_reference_name` input) based on the `year` input
5863

5964

65+
## v0.49.1
66+
### Changed
67+
- Swap an error for a warning with inconsistent load-year between electric and heating; soon to
68+
6069
## v0.49.0
6170
### Added
6271
- Ability to normalize and scale a custom load profile input to annual or monthly energy input values, for all load types

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "REopt"
22
uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"
33
authors = ["Nick Laws", "Hallie Dunham <[email protected]>", "Bill Becker <[email protected]>", "Bhavesh Rathod <[email protected]>", "Alex Zolan <[email protected]>", "Amanda Farthing <[email protected]>", "Xiangkun Li <[email protected]>", "An Pham <[email protected]>", "Byron Pullutasig <[email protected]>"]
4-
version = "0.48.2"
4+
version = "0.49.1"
55

66
[deps]
77
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3"

src/constraints/thermal_tech_constraints.jl

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,75 @@ end
107107

108108

109109
function add_ashp_force_in_constraints(m, p; _n="")
110-
if "ASHPSpaceHeater" in p.techs.ashp && p.s.ashp.force_into_system
111-
for t in setdiff(p.techs.can_serve_space_heating, ["ASHPSpaceHeater"])
112-
for ts in p.time_steps
113-
fix(m[Symbol("dvHeatingProduction"*_n)][t,"SpaceHeating",ts], 0.0, force=true)
114-
fix(m[Symbol("dvProductionToWaste"*_n)][t,"SpaceHeating",ts], 0.0, force=true)
110+
if "ASHPSpaceHeater" in p.techs.ashp
111+
if p.s.ashp.force_into_system
112+
for t in setdiff(p.techs.can_serve_space_heating, ["ASHPSpaceHeater"])
113+
for ts in p.time_steps
114+
fix(m[Symbol("dvHeatingProduction"*_n)][t,"SpaceHeating",ts], 0.0, force=true)
115+
fix(m[Symbol("dvProductionToWaste"*_n)][t,"SpaceHeating",ts], 0.0, force=true)
116+
end
117+
end
118+
elseif p.s.ashp.force_dispatch
119+
dv = "binASHPSHSizeExceedsThermalLoad"*_n
120+
m[Symbol(dv)] = @variable(m, [p.time_steps], binary=true, base_name=dv)
121+
dv = "dvASHPSHSizeTimesExcess"*_n
122+
m[Symbol(dv)] = @variable(m, [p.time_steps], lower_bound=0, base_name=dv)
123+
if p.s.ashp.can_serve_cooling
124+
max_sh_size_bigM = 2*max(p.max_sizes["ASHPSpaceHeater"], maximum(p.heating_loads_kw["SpaceHeating"] ./ p.heating_cf["ASHPSpaceHeater"])+maximum(p.s.cooling_load.loads_kw_thermal ./ p.cooling_cf["ASHPSpaceHeater"]))
125+
@constraint(m, [ts in p.time_steps],
126+
m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts] >= (
127+
m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"]
128+
- (p.heating_loads_kw["SpaceHeating"][ts] / p.heating_cf["ASHPSpaceHeater"][ts])
129+
- (p.s.cooling_load.loads_kw_thermal[ts] / p.cooling_cf["ASHPSpaceHeater"][ts])
130+
) / max_sh_size_bigM
131+
)
132+
@constraint(m, [ts in p.time_steps],
133+
m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts] <= 1 - (
134+
(p.heating_loads_kw["SpaceHeating"][ts] / p.heating_cf["ASHPSpaceHeater"][ts])
135+
+ (p.s.cooling_load.loads_kw_thermal[ts] / p.cooling_cf["ASHPSpaceHeater"][ts])
136+
- m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"]
137+
) / max_sh_size_bigM
138+
)
139+
# set dvASHPSHSizeTimesExcess = binASHPSHSizeExceedsThermalLoad * dvSize
140+
# big-M is min CF times heat load
141+
@constraint(m, [ts in p.time_steps],
142+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] >= m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"] - max_sh_size_bigM * (1-m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts])
143+
)
144+
@constraint(m, [ts in p.time_steps],
145+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] <= m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"]
146+
)
147+
@constraint(m, [ts in p.time_steps],
148+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] <= max_sh_size_bigM * m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts]
149+
)
150+
#Enforce dispatch: output = system size - (overage)
151+
@constraint(m, [ts in p.time_steps],
152+
m[Symbol("dvHeatingProduction"*_n)]["ASHPSpaceHeater","SpaceHeating",ts] / p.heating_cf["ASHPSpaceHeater"][ts] + m[Symbol("dvCoolingProduction"*_n)]["ASHPSpaceHeater",ts] / p.cooling_cf["ASHPSpaceHeater"][ts] >= m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"] - m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] + (p.heating_loads_kw["SpaceHeating"][ts] / p.heating_cf["ASHPSpaceHeater"][ts] + p.s.cooling_load.loads_kw_thermal[ts] / p.cooling_cf["ASHPSpaceHeater"][ts] ) * m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts]
153+
)
154+
else
155+
# binary variable enforcement for size >= load
156+
max_sh_size_bigM = 2*max(p.max_sizes["ASHPSpaceHeater"], maximum(p.heating_loads_kw["SpaceHeating"] ./ p.heating_cf["ASHPSpaceHeater"]))
157+
@constraint(m, [ts in p.time_steps],
158+
m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts] >= (m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"] - p.heating_loads_kw["SpaceHeating"][ts] / p.heating_cf["ASHPSpaceHeater"][ts]) / max_sh_size_bigM
159+
)
160+
@constraint(m, [ts in p.time_steps],
161+
m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts] <= 1 - (p.heating_loads_kw["SpaceHeating"][ts] / p.heating_cf["ASHPSpaceHeater"][ts] - m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"]) / max_sh_size_bigM
162+
)
163+
# set dvASHPSHSizeTimesExcess = binASHPSHSizeExceedsThermalLoad * dvSize
164+
# big-M is min CF times heat load
165+
166+
@constraint(m, [ts in p.time_steps],
167+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] >= p.heating_cf["ASHPSpaceHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"] - max_sh_size_bigM * (1-m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts])
168+
)
169+
@constraint(m, [ts in p.time_steps],
170+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] <= p.heating_cf["ASHPSpaceHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"]
171+
)
172+
@constraint(m, [ts in p.time_steps],
173+
m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] <= max_sh_size_bigM * m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts]
174+
)
175+
#Enforce dispatch: output = system size - (overage)
176+
@constraint(m, [ts in p.time_steps],
177+
m[Symbol("dvHeatingProduction"*_n)]["ASHPSpaceHeater","SpaceHeating",ts] >= p.heating_cf["ASHPSpaceHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPSpaceHeater"] - m[Symbol("dvASHPSHSizeTimesExcess"*_n)][ts] + p.heating_loads_kw["SpaceHeating"][ts] * m[Symbol("binASHPSHSizeExceedsThermalLoad"*_n)][ts]
178+
)
115179
end
116180
end
117181
end
@@ -124,13 +188,44 @@ function add_ashp_force_in_constraints(m, p; _n="")
124188
end
125189
end
126190

127-
if "ASHPWaterHeater" in p.techs.ashp && p.s.ashp_wh.force_into_system
128-
for t in setdiff(p.techs.can_serve_dhw, ["ASHPWaterHeater"])
129-
for ts in p.time_steps
130-
fix(m[Symbol("dvHeatingProduction"*_n)][t,"DomesticHotWater",ts], 0.0, force=true)
131-
fix(m[Symbol("dvProductionToWaste"*_n)][t,"DomesticHotWater",ts], 0.0, force=true)
191+
if "ASHPWaterHeater" in p.techs.ashp
192+
if p.s.ashp_wh.force_into_system
193+
for t in setdiff(p.techs.can_serve_dhw, ["ASHPWaterHeater"])
194+
for ts in p.time_steps
195+
fix(m[Symbol("dvHeatingProduction"*_n)][t,"DomesticHotWater",ts], 0.0, force=true)
196+
fix(m[Symbol("dvProductionToWaste"*_n)][t,"DomesticHotWater",ts], 0.0, force=true)
197+
end
132198
end
133-
end
199+
elseif p.s.ashp_wh.force_dispatch
200+
dv = "binASHPWHSizeExceedsThermalLoad"*_n
201+
m[Symbol(dv)] = @variable(m, [p.time_steps], binary=true, base_name=dv)
202+
dv = "dvASHPWHSizeTimesExcess"*_n
203+
m[Symbol(dv)] = @variable(m, [p.time_steps], lower_bound=0, base_name=dv)
204+
# binary variable enforcement for size >= load
205+
max_wh_size_bigM = 2*max(p.max_sizes["ASHPWaterHeater"], maximum(p.heating_loads_kw["DomesticHotWater"] ./ p.heating_cf["ASHPWaterHeater"]))
206+
@constraint(m, [ts in p.time_steps],
207+
m[Symbol("binASHPWHSizeExceedsThermalLoad"*_n)][ts] >= (m[Symbol("dvSize"*_n)]["ASHPWaterHeater"] - p.heating_loads_kw["DomesticHotWater"][ts] / p.heating_cf["ASHPWaterHeater"][ts]) / max_wh_size_bigM
208+
)
209+
@constraint(m, [ts in p.time_steps],
210+
m[Symbol("binASHPWHSizeExceedsThermalLoad"*_n)][ts] <= 1 - (p.heating_loads_kw["DomesticHotWater"][ts] / p.heating_cf["ASHPWaterHeater"][ts] - m[Symbol("dvSize"*_n)]["ASHPWaterHeater"]) / max_wh_size_bigM
211+
)
212+
# set dvASHPWHSizeTimesExcess = binASHPWHSizeExceedsThermalLoad * dvSize
213+
# big-M is min CF times heat load
214+
215+
@constraint(m, [ts in p.time_steps],
216+
m[Symbol("dvASHPWHSizeTimesExcess"*_n)][ts] >= p.heating_cf["ASHPWaterHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPWaterHeater"] - max_wh_size_bigM * (1-m[Symbol("binASHPWHSizeExceedsThermalLoad"*_n)][ts])
217+
)
218+
@constraint(m, [ts in p.time_steps],
219+
m[Symbol("dvASHPWHSizeTimesExcess"*_n)][ts] <= p.heating_cf["ASHPWaterHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPWaterHeater"]
220+
)
221+
@constraint(m, [ts in p.time_steps],
222+
m[Symbol("dvASHPWHSizeTimesExcess"*_n)][ts] <= max_wh_size_bigM * m[Symbol("binASHPWHSizeExceedsThermalLoad"*_n)][ts]
223+
)
224+
#Enforce dispatch: output = system size - (overage)
225+
@constraint(m, [ts in p.time_steps],
226+
m[Symbol("dvHeatingProduction"*_n)]["ASHPWaterHeater","DomesticHotWater",ts] >= p.heating_cf["ASHPWaterHeater"][ts]*m[Symbol("dvSize"*_n)]["ASHPWaterHeater"] - m[Symbol("dvASHPWHSizeTimesExcess"*_n)][ts] + p.heating_loads_kw["DomesticHotWater"][ts] * m[Symbol("binASHPWHSizeExceedsThermalLoad"*_n)][ts]
227+
)
228+
end
134229
end
135230
end
136231

0 commit comments

Comments
 (0)