Skip to content
Empty file.
56 changes: 56 additions & 0 deletions electrolyzer/components/classifiers/cell_classifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import numpy as np
import openmdao.api as om


class CellClassification(om.ExplicitComponent):
def initialize(self):
self.options.declare("tech_config", types=dict, default={})
self.options.declare("plant_config", types=dict, default={})

def setup(self):
self.add_input("I_max", val=0.0, shape=1, units="A")
self.add_input("I_min", val=0.0, shape=1, units="A")
self.add_input("I_ref_points", val=0.0, shape_by_conn=True, units="A")

self.vars_to_units = {
"J": "A/(cm**2)",
"P": "kW",
"H2": "kg/h",
"O2": "kg/h",
# "H2O": "kg/s",
"V": "V",
}

ref_shape = "I_ref_points"
for v, u in self.vars_to_units.items():
self.add_input(f"{v}_in", val=0.0, copy_shape=ref_shape, units=u)
self.add_output(f"{v}_min", val=0.0, shape=1, units=u)
self.add_output(f"{v}_max", val=0.0, shape=1, units=u)

# energy bounds
self.add_output("efficiency_min", val=0.0, shape=1, units="kW*h/kg")
self.add_output("efficiency_max", val=0.0, shape=1, units="kW*h/kg")
# Should output:
# - rated cell voltage
# - rated current density
# - rated power consumption
# - rated h2 production rate
# - rated efficiency
# - rated o2 production rate
# - rated water consumption rate

# self.add_input("J_max", val=self.config.J_max, shape=1, units="A/(cm**2)")
# self.add_input("J_min", val=self.config.J_max, shape=1, units="A/(cm**2)")

def compute(self, inputs, outputs):
idx_ref_min = np.argwhere(inputs["I_ref_points"] <= inputs["I_min"]).flatten()[-1]
idx_ref_max = np.argwhere(inputs["I_ref_points"] >= inputs["I_max"]).flatten()[0]

for v in list(self.vars_to_units.keys()):
outputs[f"{v}_min"] = inputs[f"{v}_in"][idx_ref_min]
outputs[f"{v}_max"] = inputs[f"{v}_in"][idx_ref_max]

# kWh/kg
efficiency = inputs["P_in"] / inputs["H2_in"]
outputs["efficiency_min"] = efficiency[idx_ref_min]
outputs["efficiency_max"] = efficiency[idx_ref_max]
64 changes: 64 additions & 0 deletions electrolyzer/connectors/series_scalar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import openmdao.api as om


class GenericSeriesConverter(om.ExplicitComponent):
def initialize(self):
self.options.declare("scaling_component", types=str)
self.options.declare("n_comps", types=(int, float), default=1.0)

def setup(self):
self.add_input(
f"n_{self.options['scaling_component']}",
val=self.options["n_comps"],
shape=1,
units="unitless",
)
vars_to_units = {
"J": "A/(cm**2)",
"I": "A",
"P": "W",
"H2": "kg/s",
"O2": "kg/s",
# "H2O": "kg/s",
"V": "V",
# "V_deg": "V"
}

ref_shape = None
for v, u in vars_to_units.items():
if ref_shape is None:
self.add_input(f"{v}_in", val=0.0, shape_by_conn=True, units=u)
self.add_output(f"{v}_out", val=0.0, copy_shape=f"{v}_in", units=u)
ref_shape = f"{v}_in"
else:
self.add_input(f"{v}_in", val=0.0, copy_shape=ref_shape, units=u)
self.add_output(f"{v}_out", val=0.0, copy_shape=ref_shape, units=u)


class SplitAcrossSerialComponents(GenericSeriesConverter):
"""Scale power down"""

def compute(self, inputs, outputs):
for o_name in outputs.keys():
in_name = o_name.replace("_out", "_in")

if o_name == "I_out" or o_name == "J_out":
outputs[o_name] = inputs[in_name]
else:
outputs[o_name] = inputs[in_name] / inputs[f"n_{self.options['scaling_component']}"]


class CombineSerialComponents(GenericSeriesConverter):
"""Scale power down"""

def setup(self):
super().setup()

def compute(self, inputs, outputs):
for o_name in outputs.keys():
in_name = o_name.replace("_out", "_in")

if o_name == "I_out" or o_name == "J_out":
outputs[o_name] = inputs[in_name]
else:
outputs[o_name] = inputs[in_name] * inputs[f"n_{self.options['scaling_component']}"]
Loading
Loading