Skip to content
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

Draft
wants to merge 3,028 commits into
base: develop
Choose a base branch
from
Draft

MPC TLDRD #418

wants to merge 3,028 commits into from

Conversation

hdunham
Copy link
Collaborator

@hdunham hdunham commented Jun 18, 2024

No description provided.

hdunham and others added 30 commits September 6, 2023 15:01
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)
Copy link
Collaborator Author

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
Copy link
Collaborator Author

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"
Copy link
Collaborator Author

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
Copy link
Collaborator Author

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)
Copy link
Collaborator Author

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

Copy link
Collaborator Author

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
Copy link
Collaborator Author

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)
Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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.
Copy link
Collaborator Author

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],
Copy link
Collaborator Author

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
Copy link
Collaborator Author

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`
Copy link
Collaborator Author

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
Copy link
Collaborator Author

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)
Copy link
Collaborator Author

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:
Copy link
Collaborator Author

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],
Copy link
Collaborator Author

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]
Copy link
Collaborator Author

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`
Copy link
Collaborator Author

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants