Skip to content

Commit 1029930

Browse files
committed
removed commented out code and simplified some docstrings
1 parent 17e241d commit 1029930

File tree

4 files changed

+29
-259
lines changed

4 files changed

+29
-259
lines changed

h2integrate/storage/battery/pysam_battery.py

Lines changed: 14 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ class PySAMBatteryPerformanceModelConfig(StoragePerformanceBaseConfig):
2121
and reference module characteristics.
2222
2323
Attributes:
24-
max_capacity (float):
25-
Maximum battery energy capacity in kilowatt-hours (kWh).
24+
max_capacity (float): Maximum battery energy capacity in kilowatt-hours (kWh).
2625
Must be greater than zero.
27-
max_charge_rate (float):
28-
Rated power capacity of the battery in kilowatts (kW).
26+
max_charge_rate (float): Rated power capacity of the battery in kilowatts (kW).
2927
Must be greater than zero.
3028
demand_profile (int | float | list): Demand values for each timestep, in
3129
the same units as `commodity_rate_units`. May be a scalar for constant
@@ -36,20 +34,14 @@ class PySAMBatteryPerformanceModelConfig(StoragePerformanceBaseConfig):
3634
3735
- PySAM: ``"LFPGraphite"``, ``"LMOLTO"``, ``"LeadAcid"``, ``"NMCGraphite"``
3836
39-
min_soc_fraction (float):
40-
Minimum allowable state of charge as a fraction (0 to 1).
41-
max_soc_fraction (float):
42-
Maximum allowable state of charge as a fraction (0 to 1).
43-
init_soc_fraction (float):
44-
Initial state of charge as a fraction (0 to 1).
45-
control_variable (str):
46-
Control mode for the PySAM battery, either ``"input_power"``
37+
min_soc_fraction (float): Minimum allowable state of charge as a fraction (0 to 1).
38+
max_soc_fraction (float): Maximum allowable state of charge as a fraction (0 to 1).
39+
init_soc_fraction (float): Initial state of charge as a fraction (0 to 1).
40+
control_variable (str): Control mode for the PySAM battery, either ``"input_power"``
4741
or ``"input_current"``.
48-
ref_module_capacity (int | float, optional):
49-
Reference module capacity in kilowatt-hours (kWh).
42+
ref_module_capacity (int | float, optional): Reference module capacity in kWh.
5043
Defaults to 400.
51-
ref_module_surface_area (int | float, optional):
52-
Reference module surface area in square meters (m²).
44+
ref_module_surface_area (int | float, optional): Reference module surface area in m².
5345
Defaults to 30.
5446
Cp (int | float, optional): Battery specific heat capacity [J/kg*K].
5547
Defaults to 900.
@@ -61,12 +53,11 @@ class PySAMBatteryPerformanceModelConfig(StoragePerformanceBaseConfig):
6153

6254
max_capacity: float = field(validator=gt_zero)
6355
max_charge_rate: float = field(validator=gt_zero)
64-
# demand_profile: int | float | list = field()
56+
6557
chemistry: str = field(
6658
validator=contains(["LFPGraphite", "LMOLTO", "LeadAcid", "NMCGraphite"]),
6759
)
68-
# min_soc_fraction: float = field(validator=range_val(0, 1))
69-
# max_soc_fraction: float = field(validator=range_val(0, 1))
60+
7061
init_soc_fraction: float = field(validator=range_val(0, 1))
7162
control_variable: str = field(
7263
default="input_power", validator=contains(["input_power", "input_current"])
@@ -90,68 +81,18 @@ class PySAMBatteryPerformanceModel(StoragePerformanceBase):
9081
bounds set by the user. It may exceed the bounds by up to 5% SOC.
9182
9283
Attributes:
93-
config (PySAMBatteryPerformanceModelConfig):
94-
Configuration parameters for the battery performance model.
95-
system_model (``BatteryStateful``):
96-
Instance of the PySAM BatteryStateful model, initialized with
97-
the selected chemistry and configuration parameters.
98-
outputs (BatteryOutputs):
99-
Container for simulation outputs such as SOC, chargeable/dischargeable
100-
power, unmet demand, and unused commodities.
101-
unmet_demand (float):
102-
Tracks unmet demand during simulation (kW).
103-
unused_commodity (float):
104-
Tracks unused commodity during simulation (kW).
105-
106-
Inputs:
107-
max_charge_rate (float):
108-
Battery charge rate in kilowatts per hour (kW).
109-
storage_capacity (float):
110-
Total energy storage capacity in kilowatt-hours (kWh).
111-
electricity_demand (ndarray):
112-
Power demand time series (kW).
113-
electricity_in (ndarray):
114-
Commanded input electricity (kW), typically from dispatch.
115-
116-
Outputs:
117-
unmet_demand_out (ndarray):
118-
Remaining unmet demand after discharge (kW).
119-
unused_commodity_out (ndarray):
120-
Unused energy not absorbed by the battery (kW).
121-
electricity_out (ndarray):
122-
Dispatched electricity to meet demand (kW), including electricity from
123-
electricity_in that was never used to charge the battery and
124-
battery_electricity.
125-
SOC (ndarray):
126-
Battery state of charge (%).
127-
battery_electricity (ndarray):
128-
Electricity output from the battery model (kW).
84+
system_model (``BatteryStateful``): Instance of the PySAM BatteryStateful model, initialized
85+
with the selected chemistry and configuration parameters.
86+
12987
13088
Methods:
131-
setup():
132-
Defines model inputs, outputs, configuration, and connections
133-
to plant-level dispatch (if applicable).
13489
compute(inputs, outputs, discrete_inputs, discrete_outputs):
13590
Runs the PySAM BatteryStateful model for a simulation timestep,
13691
updating outputs such as SOC, charge/discharge limits, unmet
13792
demand, and unused commodities.
138-
simulate(electricity_in, electricity_demand, time_step_duration, control_variable,
139-
sim_start_index=0):
140-
Simulates the battery behavior across timesteps using either
141-
input power or input current as control. This method is similar to what is
142-
provided in typical compute methods in H2Integrate for running models, but
143-
needs to be a separate method here to allow the dispatch function to call
144-
and manage the performance model.
14593
_set_control_mode(control_mode=1.0, input_power=0.0, input_current=0.0,
14694
control_variable="input_power"):
14795
Sets the battery control mode (power or current).
148-
149-
Notes:
150-
- Default timestep is 1 hour (``dt=1.0``).
151-
- State of charge (SOC) bounds are set using the configuration's
152-
``min_soc_fraction`` and ``max_soc_fraction``.
153-
- If a Pyomo dispatch solver is provided, the battery will simulate
154-
dispatch decisions using solver inputs.
15596
"""
15697

15798
def initialize(self):
@@ -179,29 +120,12 @@ def setup(self):
179120
# Initialize the PySAM BatteryStateful model with defaults
180121
self.system_model = BatteryStateful.default(self.config.chemistry)
181122

182-
# Renaming outputs from battery to storage
183-
# battery_electricity_discharge -> storage_electricity_discharge
184-
# battery_electricity_charge -> storage_electricity_charge
185-
# battery_electricity_out -> storage_electricity_out
186-
187123
def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
188124
"""Run the PySAM Battery model for one simulation step.
189125
190126
Configures the battery stateful model parameters (SOC limits, timestep,
191127
thermal properties, etc.), executes the simulation, and stores the
192128
results in OpenMDAO outputs.
193-
194-
Args:
195-
inputs (dict):
196-
Continuous input values (e.g., electricity_in, electricity_demand) or
197-
battery design parameters.
198-
outputs (dict):
199-
Dictionary where model outputs (SOC, battery_discharge, unmet demand, etc.)
200-
are written.
201-
discrete_inputs (dict):
202-
Discrete inputs such as control mode or Pyomo solver.
203-
discrete_outputs (dict):
204-
Discrete outputs (unused in this component).
205129
"""
206130

207131
# Size the battery based on inputs -> method brought from HOPP
@@ -241,7 +165,7 @@ def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
241165
self.system_model.value("input_power", 0.0)
242166
self.system_model.execute(0)
243167

244-
self.run_storage(
168+
outputs = self.run_storage(
245169
inputs["max_charge_rate"][0],
246170
inputs["max_charge_rate"][0],
247171
inputs["storage_capacity"][0],
@@ -384,8 +308,3 @@ def _set_control_mode(
384308
self.system_model.value("input_current", input_current)
385309
# Either `input_power` or `input_current`; need to adjust `control_mode` above
386310
self.control_variable = control_variable
387-
388-
389-
def dummy_function():
390-
# this function is required for initializing the pyomo control input and nothing else
391-
pass

h2integrate/storage/simple_storage_auto_sizing.py

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ class StorageSizingModelConfig(StoragePerformanceBaseConfig):
4141
commodity: str = field(converter=(str.strip, str.lower))
4242
commodity_rate_units: str = field(converter=str.strip)
4343

44-
# min_soc_fraction: float = field(validator=range_val(0, 1))
45-
# max_soc_fraction: float = field(validator=range_val(0, 1))
46-
4744
# TODO: add in logic for having different discharge rate
4845
# charge_equals_discharge: bool = field(default=True)
4946
set_demand_as_avg_commodity_in: bool = field()
@@ -92,38 +89,6 @@ class StorageAutoSizingModel(StoragePerformanceBase):
9289
9390
Then simulates performance of a basic storage component using the charge rate and
9491
capacity calculated.
95-
96-
Note: this storage performance model is intended to be used with the
97-
`SimpleStorageOpenLoopController` controller and is not compatible with the
98-
`DemandOpenLoopStorageController` controller.
99-
100-
Inputs:
101-
{commodity}_in (float): Input commodity flow timeseries (e.g., hydrogen production)
102-
used to estimate the demand if `commodity_demand_profile` is zero.
103-
- Units: Defined in `commodity_rate_units` (e.g., "kg/h").
104-
{commodity}_set_point (float): Input commodity flow timeseries (e.g., hydrogen production)
105-
used as the available input commodity to meet the demand.
106-
{commodity}_demand_profile (float): Demand profile of commodity.
107-
- Units: Defined in `commodity_rate_units` (e.g., "kg/h").
108-
109-
Outputs:
110-
max_capacity (float): Maximum storage capacity of the commodity.
111-
- Units: in non-rate units, e.g., "kg" if `commodity_rate_units` is "kg/h"
112-
max_charge_rate (float): Maximum rate at which the commodity can be charged
113-
- Units: Defined in `commodity_rate_units` (e.g., "kg/h").
114-
Assumed to also be the discharge rate.
115-
{commodity}_out (np.ndarray): the commodity used to meet demand from the available
116-
input commodity and storage component. Defined in `commodity_rate_units`.
117-
total_{commodity}_produced (float): sum of commodity discharged from storage over
118-
the simulation. Defined in `commodity_amount_units`
119-
rated_{commodity}_production (float): maximum commodity that could be discharged
120-
in a timestep. Defined in `commodity_rate_units`
121-
annual_{commodity}_produced (np.ndarray): total commodity discharged per year.
122-
Defined in `commodity_amount_units/year`
123-
capacity_factor (np.ndarray): ratio of commodity discharged to the maximum
124-
commodity that could be discharged over the simulation.
125-
Defined as a ratio (units of `unitless`)
126-
12792
"""
12893

12994
def setup(self):
@@ -192,12 +157,9 @@ def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
192157
1) Estimate the starting SOC (as a fraction) at the start of the simulation.
193158
Take the first value in the SOC profile (in `commodity_amount_units`)
194159
and divide by the storage capacity
195-
2) If `commodity_set_point` is an input, simulate the storage performance
196-
using the `simulate()` method with the dispatch command input `commodity_set_point`.
197-
Otherwise, make an input dictionary containing the calculated demand profile,
198-
storage capacity, and storage fill rate, and run the input dispatch method.
199-
3) Calculate the unmet demand, unused commodity, SOC, combined commodity output, etc.
200-
160+
2) Make an input dictionary containing the calculated demand profile,
161+
storage capacity, and storage fill rate, and run the storage performance.
162+
3) Calculate the outputs
201163
"""
202164

203165
# Part 0: get demand profile based on user input parameters
@@ -267,9 +229,7 @@ def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
267229
outputs["max_discharge_rate"] = storage_max_empty_rate
268230
outputs["storage_capacity"] = rated_storage_capacity
269231

270-
# 2. Simulate the storage performance using the `simulate()`
271-
272-
# Make dictionary of inputs containing information to pass to the controller
232+
# 2. Make dictionary of inputs containing information to pass to the controller
273233
# (such as demand profile, charge rate, and storage capacity)
274234
inputs_adjusted = dict(inputs.items())
275235
if self.config.set_demand_as_avg_commodity_in:
@@ -279,6 +239,7 @@ def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
279239
inputs_adjusted["storage_capacity"] = np.array([rated_storage_capacity])
280240
inputs_adjusted["max_charge_rate"] = np.array([storage_max_fill_rate])
281241

242+
# 3. Simulate the storage performance and calculate outputs
282243
outputs = self.run_storage(
283244
storage_max_fill_rate,
284245
storage_max_empty_rate,

h2integrate/storage/storage_baseclass.py

Lines changed: 8 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -24,65 +24,6 @@ class StoragePerformanceBaseConfig(BaseConfig):
2424
max_soc_fraction: float = field(validator=range_val(0, 1))
2525
demand_profile: int | float | list = field()
2626

27-
# Below is used in StoragePerformance and StorageAutoSizing
28-
# commodity: str = field(converter=str.strip)
29-
# commodity_rate_units: str = field(converter=str.strip)
30-
# commodity_amount_units: str = field(default=None)
31-
# charge_efficiency: float | None = field(default=None, validator=range_val_or_none(0, 1))
32-
# discharge_efficiency: float | None = field(default=None, validator=range_val_or_none(0, 1))
33-
# round_trip_efficiency: float | None = field(default=None, validator=range_val_or_none(0, 1))
34-
35-
# # Below is only used in StoragePerformance
36-
# max_discharge_rate: float | None = field(default=None)
37-
# charge_equals_discharge: bool = field(default=True)
38-
39-
# # Below is used in StoragePerformance and PySAMBattery
40-
# max_capacity: float = field(validator=gt_zero)
41-
# max_charge_rate: float = field(validator=gt_zero)
42-
# init_soc_fraction: float = field(validator=range_val(0, 1))
43-
44-
# def __attrs_post_init__(self):
45-
# if (self.round_trip_efficiency is not None) and (
46-
# self.charge_efficiency is None and self.discharge_efficiency is None
47-
# ):
48-
# # Calculate charge and discharge efficiencies from round-trip efficiency
49-
# self.charge_efficiency = np.sqrt(self.round_trip_efficiency)
50-
# self.discharge_efficiency = np.sqrt(self.round_trip_efficiency)
51-
# self.round_trip_efficiency = None
52-
# if self.charge_efficiency is None or self.discharge_efficiency is None:
53-
# raise ValueError(
54-
# "Exactly one of the following sets of parameters must be set: (a) "
55-
# "`round_trip_efficiency`, or (b) both `charge_efficiency` "
56-
# "and `discharge_efficiency`."
57-
# )
58-
59-
## Below only for StoragePerformance
60-
61-
# if self.charge_equals_discharge:
62-
# if (
63-
# self.max_discharge_rate is not None
64-
# and self.max_discharge_rate != self.max_charge_rate
65-
# ):
66-
# msg = (
67-
# "Max discharge rate does not equal charge rate but charge_equals_discharge"
68-
# f"is True. Discharge rate is {self.max_discharge_rate} and charge rate "
69-
# f"is {self.max_charge_rate}."
70-
# )
71-
# raise ValueError(msg)
72-
73-
# self.max_discharge_rate = self.max_charge_rate
74-
75-
# if not self.charge_equals_discharge and self.max_discharge_rate is None:
76-
# msg = (
77-
# "max_discharge_rate is a required key when charge_equals_discharge is True."
78-
# "Please set a value for the max_discharge_rate."
79-
# )
80-
# raise ValueError(msg)
81-
82-
## Below NOT used in PySAM battery
83-
# if self.commodity_amount_units is None:
84-
# self.commodity_amount_units = f"({self.commodity_rate_units})*h"
85-
8627

8728
class StoragePerformanceBase(PerformanceModelBaseClass):
8829
"""
@@ -123,6 +64,13 @@ class StoragePerformanceBase(PerformanceModelBaseClass):
12364
"""
12465

12566
def setup(self):
67+
"""Set up the storage performance model in OpenMDAO.
68+
69+
Initializes the configuration and defines inputs/outputs for OpenMDAO.
70+
If dispatch connections are specified, it also sets up a discrete
71+
input for Pyomo solver integration.
72+
"""
73+
12674
# Below should be done in models that inherit it
12775
# self.commodity = self.config.commodity
12876
# self.commodity_rate_units = self.config.commodity_rate_units
@@ -288,7 +236,7 @@ def compute(self, inputs, outputs, discrete_inputs=[], discrete_outputs=[]):
288236
# discharge_rate = inputs["max_discharge_rate"][0]
289237
# else:
290238
# discharge_rate = inputs["max_charge_rate"][0]
291-
# storage_capacity = inputs["storage_capacity"]
239+
# storage_capacity = inputs["storage_capacity"][0]
292240
# outputs = self.run_storage(
293241
# charge_rate, discharge_rate, storage_capacity, inputs, outputs, discrete_inputs
294242
# )

0 commit comments

Comments
 (0)