-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MPC TLDRD #418
base: develop
Are you sure you want to change the base?
MPC TLDRD #418
Conversation
can_grid_charge::Bool = true | ||
grid_charge_efficiency::Float64 = can_grid_charge ? charge_efficiency : 0.0 | ||
size_kw::Float64 = charge_limit_kw + discharge_limit_kw | ||
max_kw::Float64 = min(charge_limit_kw, discharge_limit_kw) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the reason that we need these max fields in all the MPC storage structs when the sizes are fixed?
soc_init_fraction::Float64 = 0.5 | ||
can_grid_charge::Bool = true | ||
grid_charge_efficiency::Float64 = can_grid_charge ? charge_efficiency : 0.0 | ||
size_kw::Float64 = charge_limit_kw + discharge_limit_kw |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why would the size be this sum? do we even want this field? looks like the constraint that uses it is commented out and would be duplicative since we already have the charge and discharge limits.
- `thermal_to_space_heating_load_series_mmbtu_per_hour` # Thermal power production to serve the space heating load series [MMBtu/hr] | ||
- `thermal_to_process_heat_load_series_mmbtu_per_hour` # Thermal power production to serve the process heating load series [MMBtu/hr] | ||
|
||
!!! note "'Series' and 'Annual' energy outputs are average annual" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this note applies to MPC?
end | ||
r["thermal_to_space_heating_load_series_mmbtu_per_hour"] = round.(value.(ElectricHeaterToSpaceHeatingKW ./ KWH_PER_MMBTU), digits=5) | ||
|
||
if "ProcessHeat" in p.heating_loads && p.s.electric_heater.can_serve_space_heating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this supposed to be can_use_process_heat instead of can_serve_space_heating?
@expression(m, ElectricHeaterToHotTESKW[ts in p.time_steps], 0.0) | ||
@expression(m, ElectricHeaterToHotTESByQualityKW[q in p.heating_loads, ts in p.time_steps], 0.0) | ||
end | ||
r["thermal_to_storage_series_mmbtu_per_hour"] = round.(value.(ElectricHeaterToHotTESKW) / KWH_PER_MMBTU, digits=3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should time_steps_per_hour be considered in these calcs? I see they aren't in the non-MPC version above either
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually never mind maybe not since it's thermal_to_storage_series_mmbtu_per_hour so we want the hour in the units
@@ -5,6 +5,8 @@ | |||
- `size_kwh` Optimal storage capacity | |||
- `soc_series_fraction` Vector of normalized (0-1) state of charge values over the first year | |||
- `storage_to_load_series_kw` Vector of power used to meet load over the first year | |||
- `storage_to_electrolyzer_series_kw` Vector of power used by electrolyzer over the first year |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does storage to electric heater also need to be added?
@@ -43,9 +45,21 @@ function add_electric_storage_results(m::JuMP.AbstractModel, p::REoptInputs, d:: | |||
)) | |||
end | |||
end | |||
|
|||
if !isempty(p.techs.electrolyzer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, I think either storage_to_electrolyzer_series_kw and storage_to_compressor_series_kw should be created and set to [] if these tech sets are empty, or they should only be created in the else below if the corresponding sets aren't empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the latter for consistency with elsewhere
@@ -4,6 +4,8 @@ | |||
- `annual_energy_supplied_kwh` # Total energy supplied from the grid in an average year. | |||
- `electric_to_load_series_kw` # Vector of power drawn from the grid to serve load. | |||
- `electric_to_storage_series_kw` # Vector of power drawn from the grid to charge the battery. | |||
- `electric_to_electrolyzer_series_kw` # Vector of power drawn from the grid to be used by electrolyzer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does electric heater need to be added too?
|
||
if p.s.storage.attr["ElectricStorage"].size_kwh > 0 | ||
GridToBatt = @expression(m, [ts in p.time_steps], | ||
sum(m[Symbol("dvGridToStorage"*_n)][b, ts] for b in p.s.storage.types.elec) | ||
) | ||
r["to_battery_series_kw"] = round.(value.(GridToBatt), digits=3).data | ||
r["electric_to_storage_series_kw"] = round.(value.(GridToBatt), digits=3).data | ||
else | ||
GridToBatt = zeros(length(p.time_steps)) | ||
end | ||
GridToLoad = @expression(m, [ts in p.time_steps], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to subtract out grid to other things here too? e.g. electrolyzer
r["electric_to_compressor_series_kw"] = round.(value.(GridToCompressor), digits=3) | ||
end | ||
|
||
if _n=="" #only output emissions results if not a multinode model |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this because we output all the nodes combined for multinode?
- `to_grid_series_kw` | ||
- `to_load_series_kw` | ||
- `annual_fuel_consumption_gal` | ||
- `electric_to_storage_series_kw` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why can't generator supply hydrogen techs?
|
||
""" | ||
MPC `HeatingLoad` results keys: | ||
- `process_heat_thermal_load_series_mmbtu_per_hour` vector of site space heating boiler load in every time step |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly confused about why it's only process heat some places but others there's also dhw and space heating
@@ -77,6 +77,9 @@ function add_hot_storage_results(m::JuMP.AbstractModel, p::MPCInputs, d::Dict, b | |||
soc = (m[Symbol("dvStoredEnergy"*_n)][b, ts] for ts in p.time_steps) | |||
r["soc_series_fraction"] = round.(value.(soc) ./ p.s.storage.attr[b].size_kwh, digits=3) | |||
|
|||
discharge = (sum(m[Symbol("dvHeatFromStorage"*_n)][b,q,ts] for b in p.s.storage.types.hot, q in p.heating_loads) for ts in p.time_steps) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why sum all the separate heating loads?
@@ -69,3 +69,64 @@ function add_wind_results(m::JuMP.AbstractModel, p::REoptInputs, d::Dict; _n="") | |||
d[t] = r | |||
nothing | |||
end | |||
|
|||
""" | |||
MPC `Wind` results keys: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can wind serve electric heater too?
r["electric_to_storage_series_kw"] = WindtoBatt | ||
|
||
if !isempty(p.s.electric_tariff.export_bins) | ||
WindtoGrid = @expression(m, [ts in p.time_steps], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen issues with results being expressions and thus the type is JuMP.Containers.DenseAxisArray instead of vector
|
||
WindtoCUR = (m[Symbol("dvCurtail"*_n)][t, ts] for ts in p.time_steps) | ||
r["electric_curtailed_series_kw"] = round.(value.(WindtoCUR), digits=3) | ||
WindtoLoad = (m[Symbol("dvRatedProduction"*_n)][t, ts] * p.production_factor[t, ts] * p.levelization_factor[t] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does levelization factor apply in MPC?
@@ -8,6 +8,8 @@ MPC Scenarios will return a results Dict with the following keys: | |||
- `ElectricUtility` | |||
- `PV` | |||
- `Generator` | |||
- `Electrolyzer` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should electric heater be added to this list?
No description provided.