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

Syncing GreenSteel and GreenHEART features #322

Merged
merged 24 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
016df73
limit pyyaml-include version
kbrunik Apr 1, 2024
b1530dd
autoformatter
kbrunik Apr 1, 2024
072586a
merge PR changes
kbrunik Apr 2, 2024
39cb5db
ran black autoformatter
kbrunik Apr 2, 2024
4a21e2f
reformat examples
kbrunik Apr 2, 2024
0231cf0
Merge remote-tracking branch 'upstream/greensteel-eco-sync' into gree…
kbrunik Apr 18, 2024
bd324b4
update variable name
kbrunik Apr 18, 2024
ee7aae2
GreenSteel tests
kbrunik Apr 19, 2024
c92ed97
Merge remote-tracking branch 'upstream/greensteel-eco-sync' into gree…
kbrunik May 1, 2024
9e25783
Merge remote-tracking branch 'jared/uniform-output' into greenheart-l…
kbrunik May 1, 2024
14f1c38
fix ammonia lcoh value
kbrunik May 21, 2024
d50f28c
Merge remote-tracking branch 'upstream/greensteel-eco-sync' into gree…
kbrunik May 21, 2024
28f28dc
update financial inputs.
kbrunik May 24, 2024
db88f3a
update greensteel and greenheart tests
kbrunik May 24, 2024
9dc2f1a
update tests with updated greenheart features
kbrunik May 24, 2024
2f65406
Merge branch 'greensteel-eco-sync' into gs-test-pr
jaredthomas68 May 27, 2024
4e3aa5c
fix input check
jaredthomas68 May 27, 2024
c8191e8
Merge pull request #36 from jaredthomas68/gs-test-pr
kbrunik Jun 5, 2024
4d55862
Merge remote-tracking branch 'upstream/greensteel-eco-sync' into gree…
kbrunik Jun 5, 2024
611ba48
update key value for ss storage
kbrunik Jun 6, 2024
093de7d
update examples with key changes
kbrunik Jun 6, 2024
2f42947
fixed h2 storage sizing bug
kbrunik Jun 6, 2024
81e55f8
clean up hydrogen mgmt logic
kbrunik Jun 7, 2024
137b6ae
fix typo
kbrunik Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ h2_transport_pipe:
outlet_pressure: 10 # bar - from example in code from Jamie #TODO check this value
h2_storage:
size_capacity_from_demand:
flag: False # If True, then storage is sized to provide steady-state storage
flag: True # If True, then storage is sized to provide steady-state storage
capacity_from_max_on_turbine_storage: False # if True, then days of storage is ignored and storage capacity is based on how much h2 storage fits on the turbines in the plant using Kottenstete 2003.
type: "lined_rock_cavern" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 8.57267 # from `hydrogen_storage_duration_hr` = 205.74419987482239 [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
days: -1 #8.57267 # from `hydrogen_storage_duration_hr` = 205.74419987482239 [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)

policy_parameters: # these should be adjusted for inflation prior to application - order of operations: rate in 1992 $,
#then prevailing wage multiplier if applicable, then inflation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ h2_transport_pipe:
outlet_pressure: 10 # bar - from example in code from Jamie #TODO check this value
h2_storage:
size_capacity_from_demand:
flag: False # If True, then storage is sized to provide steady-state storage
flag: True # If True, then storage is sized to provide steady-state storage
capacity_from_max_on_turbine_storage: False # if True, then days of storage is ignored and storage capacity is based on how much h2 storage fits on the turbines in the plant using Kottenstete 2003.
type: "none" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 19.783 # from `hydrogen_storage_duration_hr` = 474.7948370015298 [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
type: "salt_cavern" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: -1 #19.783 # from `hydrogen_storage_duration_hr` = 474.7948370015298 [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)

policy_parameters: # these should be adjusted for inflation prior to application - order of operations: rate in 1992 $,
#then prevailing wage multiplier if applicable, then inflation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ h2_transport_pipe:
outlet_pressure: 10 # bar - from example in code from Jamie #TODO check this value
h2_storage:
size_capacity_from_demand:
flag: False # If True, then storage is sized to provide steady-state storage
flag: True # If True, then storage is sized to provide steady-state storage
capacity_from_max_on_turbine_storage: False # if True, then days of storage is ignored and storage capacity is based on how much h2 storage fits on the turbines in the plant using Kottenstete 2003.
type: "none" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 3 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
type: "salt_cavern" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: -1 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
# platform:
# opex_rate: 0.0111 # % of capex to determine opex (see table 5 in https://www.acm.nl/sites/default/files/documents/study-on-estimation-method-for-additional-efficient-offshore-grid-opex.pdf)
# installation_days: 14 # days
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ h2_transport_pipe:
outlet_pressure: 10 # bar - from example in code from Jamie #TODO check this value
h2_storage:
size_capacity_from_demand:
flag: False # If True, then storage is sized to provide steady-state storage
flag: True # If True, then storage is sized to provide steady-state storage
capacity_from_max_on_turbine_storage: False # if True, then days of storage is ignored and storage capacity is based on how much h2 storage fits on the turbines in the plant using Kottenstete 2003.
type: "none" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 3 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
type: "lined_rock_cavern" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 0 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
# platform:
# opex_rate: 0.0111 # % of capex to determine opex (see table 5 in https://www.acm.nl/sites/default/files/documents/study-on-estimation-method-for-additional-efficient-offshore-grid-opex.pdf)
# installation_days: 14 # days
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ h2_transport_pipe:
outlet_pressure: 10 # bar - from example in code from Jamie #TODO check this value
h2_storage:
size_capacity_from_demand:
flag: False # If True, then storage is sized to provide steady-state storage
flag: True # If True, then storage is sized to provide steady-state storage
capacity_from_max_on_turbine_storage: False # if True, then days of storage is ignored and storage capacity is based on how much h2 storage fits on the turbines in the plant using Kottenstete 2003.
type: "none" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 3 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
type: "lined_rock_cavern" # can be one of ["none", "pipe", "turbine", "pressure_vessel", "salt_cavern", "lined_rock_cavern"]
days: 0 # [days] how many days worth of production we should be able to store (this is ignored if `capacity_from_max_on_turbine_storage` is set to True)
kbrunik marked this conversation as resolved.
Show resolved Hide resolved
# platform:
# opex_rate: 0.0111 # % of capex to determine opex (see table 5 in https://www.acm.nl/sites/default/files/documents/study-on-estimation-method-for-additional-efficient-offshore-grid-opex.pdf)
# installation_days: 14 # days
Expand Down
24 changes: 13 additions & 11 deletions greenheart/tools/eco/hydrogen_mgmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ def run_h2_storage(
hydrogen_storage_capacity_kg, hydrogen_storage_duration_hr, hydrogen_storage_soc = hydrogen_storage_capacity(electrolyzer_physics_results['H2_Results'], greenheart_config['electrolyzer']['rating'], hydrogen_storage_demand)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks like we have two separate sets of logic around sizing, pressurized tower and demand/type. I think we should combine these sets of logic into a single if/else set starting with type for zero storage capacity, then checking demand, from max turbine storage, and finally using hour and max fill rate as default if the others are not specified. Eventually this should have the sizing type as a variable rather than potentially conflicting inputs, but for now we can at least simplify/clarify the logic

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 changed the logic so that we have a single if/elif/else statement around sizing and then a signle if/elif/else statement around h2 storage technology type. I moved the logic around if on a turbine to inside the specific technology (pressure vessel and turbine) and included a check up front for illegal technology choices based on turbine location selection.

greenheart_config["h2_capacity"] = hydrogen_storage_capacity_kg
kbrunik marked this conversation as resolved.
Show resolved Hide resolved
h2_storage_results["h2_storage_kg"] = hydrogen_storage_capacity_kg

else:
greenheart_config["h2_capacity"] = h2_capacity
h2_storage_results["h2_storage_kg"] = h2_capacity
Expand Down Expand Up @@ -355,7 +356,7 @@ def run_h2_storage(
area_site,
mass_tank_empty_site,
_,
) = h2_storage.distributed_storage_vessels(h2_capacity, 1)
) = h2_storage.distributed_storage_vessels(greenheart_config["h2_capacity"], 1)
kbrunik marked this conversation as resolved.
Show resolved Hide resolved
# ) = h2_storage.distributed_storage_vessels(h2_capacity, nturbines)
# capex, opex, energy = h2_storage.calculate_from_fit(h2_capacity)

Expand All @@ -368,15 +369,15 @@ def run_h2_storage(
]
) # total in kWh
h2_storage_results["tank_mass_full_kg"] = (
h2_storage.get_tank_mass(h2_capacity)[1] + h2_capacity
h2_storage.get_tank_mass(greenheart_config["h2_capacity"])[1] + greenheart_config["h2_capacity"]
)
h2_storage_results["tank_footprint_m2"] = h2_storage.get_tank_footprint(
h2_capacity, upright=True
greenheart_config["h2_capacity"], upright=True
)[1]
h2_storage_results[
"tank volume (m^3)"
] = h2_storage.compressed_gas_function.Vtank
h2_storage_results["Number of tanks"] = h2_storage.get_tanks(h2_capacity)
h2_storage_results["Number of tanks"] = h2_storage.get_tanks(greenheart_config["h2_capacity"])
if verbose:
print("ENERGY FOR STORAGE: ", energy * 1e-3 / (365 * 24), " MW")
print("Tank volume (M^3): ", h2_storage_results["tank volume (m^3)"])
Expand All @@ -397,7 +398,7 @@ def run_h2_storage(
storage_input = dict()

# pull parameters from plat_config file
storage_input["h2_storage_kg"] = h2_capacity
storage_input["h2_storage_kg"] = greenheart_config["h2_capacity"]
storage_input["compressor_output_pressure"] = greenheart_config[
"h2_storage_compressor"
]["output_pressure"]
Expand Down Expand Up @@ -426,7 +427,7 @@ def run_h2_storage(
h2_storage = PressureVessel(Energy_cost=energy_cost)
h2_storage.run()

capex, opex, energy = h2_storage.calculate_from_fit(h2_capacity)
capex, opex, energy = h2_storage.calculate_from_fit(greenheart_config["h2_capacity"])

h2_storage_results["storage_capex"] = capex
h2_storage_results["storage_opex"] = opex
Expand All @@ -437,10 +438,10 @@ def run_h2_storage(
]
) # total in kWh
h2_storage_results["tank_mass_full_kg"] = (
h2_storage.get_tank_mass(h2_capacity)[1] + h2_capacity
h2_storage.get_tank_mass(greenheart_config["h2_capacity"])[1] + greenheart_config["h2_capacity"]
)
h2_storage_results["tank_footprint_m2"] = h2_storage.get_tank_footprint(
h2_capacity, upright=True
greenheart_config["h2_capacity"], upright=True
)[1]
h2_storage_results[
"tank volume (m^3)"
Expand All @@ -461,8 +462,8 @@ def run_h2_storage(
# initialize dictionary for salt cavern storage parameters
storage_input = dict()

# pull parameters from plat_config file
storage_input["h2_storage_kg"] = h2_capacity
# pull parameters from plant_config file
storage_input["h2_storage_kg"] = greenheart_config["h2_capacity"]
storage_input["system_flow_rate"] = storage_max_fill_rate
storage_input["model"] = "papadias"

Expand Down Expand Up @@ -495,7 +496,7 @@ def run_h2_storage(
storage_input = dict()

# pull parameters from plat_config file
storage_input["h2_storage_kg"] = h2_capacity
storage_input["h2_storage_kg"] = greenheart_config["h2_capacity"]
storage_input["system_flow_rate"] = storage_max_fill_rate
storage_input["model"] = "papadias"

Expand All @@ -521,6 +522,7 @@ def run_h2_storage(

if verbose:
print("\nH2 Storage Results:")
print("H2 Storage capacity (kg): ",greenheart_config["h2_capacity"])
print("H2 storage capex: ${0:,.0f}".format(h2_storage_results["storage_capex"]))
print(
"H2 storage annual opex: ${0:,.0f}/yr".format(
Expand Down
6 changes: 3 additions & 3 deletions tests/greenheart/test_greenheart_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_simulation_wind_wave_solar(subtests):
# prior to 20240207 value was approx(10.823798551850347)
# TODO base this test value on something. Currently just based on output at writing.
with subtests.test("lcoh"):
assert lcoh == approx(12.71510378132601, rel=rtol)
assert lcoh == approx(12.715103781326011, rel=rtol)

# prior to 20240207 value was approx(0.11035426429749774)
# TODO base this test value on something. Currently just based on output at writing.
Expand Down Expand Up @@ -397,15 +397,15 @@ def test_simulation_wind_onshore_steel_ammonia_ss_h2storage(subtests):

# TODO base this test value on something
with subtests.test("lcoh"):
assert lcoh == approx(4.023687007795485, rel=rtol)
assert lcoh == approx(10.0064010897151, rel=rtol)

# TODO base this test value on something
with subtests.test("lcoe"):
assert lcoe == approx(0.03486192934806013, rel=rtol)

# TODO base this test value on something
with subtests.test("steel_finance"):
lcos_expected = 1414.0330270955506
lcos_expected = 1812.985744428756

assert steel_finance.sol.get("price") == approx(lcos_expected, rel=rtol)

Expand Down
Loading