Skip to content

Commit 7e42d4b

Browse files
committed
Restore dimensional output ports on GLC via update override
1 parent 5f4605d commit 7e42d4b

2 files changed

Lines changed: 88 additions & 24 deletions

File tree

src/pathsim_chem/tritium/glc.py

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -383,22 +383,18 @@ class GLC(BVP1D):
383383
transfer via Sieverts' law, and hydrostatic pressure variation along
384384
the column.
385385
386-
The block is a thin specialisation of the native
387-
:class:`~pathsim.blocks.BVP1D` block: the constructor seeds the parent with
388-
the Malara right-hand side and boundary conditions, and the four block
389-
inputs supply the per-evaluation boundary data. The hydrodynamic
390-
correlations and dimensionless groups are computed from the current input
391-
inside the collocation callbacks. As for any ``BVP1D``, the solve is
392-
warm-started from the previous mesh and skipped entirely when the input is
393-
unchanged.
394-
395-
The block output is the dimensionless solution sampled at the two domain
396-
endpoints (``xi=0`` liquid outlet, ``xi=1`` liquid inlet), in the
397-
:class:`~pathsim.blocks.BVP1D` row-major layout
398-
``[x_T(0), x_T(1), x_T'(0), x_T'(1), y_T2(0), y_T2(1), y_T2'(0), y_T2'(1)]``.
399-
Use :meth:`results` to post-process the current solution into dimensional
400-
quantities (concentrations, extraction efficiency, molar flows, mass
401-
balance).
386+
The block is a specialisation of the native :class:`~pathsim.blocks.BVP1D`
387+
block: the constructor seeds the parent with the Malara right-hand side and
388+
boundary conditions, and the four block inputs supply the per-evaluation
389+
boundary data. The hydrodynamic correlations and dimensionless groups are
390+
computed from the current input inside the collocation callbacks. As for any
391+
``BVP1D``, the solve is warm-started from the previous mesh and skipped
392+
entirely when the input is unchanged. After each solve the dimensionless
393+
endpoint solution is post-processed into the dimensional output ports.
394+
395+
Use :meth:`results` to retrieve the full dimensional result dictionary,
396+
which additionally contains partial pressures, physical properties and the
397+
dimensionless groups.
402398
403399
Reference: https://doi.org/10.13182/FST95-A30485
404400
@@ -408,6 +404,16 @@ class GLC(BVP1D):
408404
``y_T2_inlet`` -- T₂ mole fraction in inlet gas [-],
409405
``flow_g`` -- gas mass flow rate [kg/s].
410406
407+
**Output ports:**
408+
``c_T_out`` -- dissolved tritium concentration in liquid outlet [mol/m³],
409+
``y_T2_out`` -- T₂ mole fraction in outlet gas [-],
410+
``eff`` -- extraction efficiency [-],
411+
``P_out`` -- total gas outlet pressure [Pa],
412+
``Q_l`` -- liquid volumetric flow rate [m³/s],
413+
``Q_g_out`` -- gas volumetric flow rate at outlet [m³/s],
414+
``n_T_out_liquid`` -- tritium molar flow in liquid outlet [mol/s],
415+
``n_T_out_gas`` -- tritium molar flow in gas outlet [mol/s].
416+
411417
Parameters
412418
----------
413419
P_in : float
@@ -439,6 +445,16 @@ class GLC(BVP1D):
439445
"y_T2_inlet": 2,
440446
"flow_g": 3,
441447
}
448+
output_port_labels = {
449+
"c_T_out": 0,
450+
"y_T2_out": 1,
451+
"eff": 2,
452+
"P_out": 3,
453+
"Q_l": 4,
454+
"Q_g_out": 5,
455+
"n_T_out_liquid": 6,
456+
"n_T_out_gas": 7,
457+
}
442458

443459
def __init__(
444460
self,
@@ -529,6 +545,39 @@ def _bc(self, Sa, Sb, p, u):
529545
y_T2_in = max(u[2], 1e-20)
530546
return _boundary_conditions(Sa, Sb, dim, y_T2_in, self.BCs)
531547

548+
def update(self, t):
549+
"""Solve the BVP and expose the dimensional results at the output ports.
550+
551+
Delegates the solve to :class:`~pathsim.blocks.BVP1D` (warm-started, and
552+
skipped when the input is unchanged), then post-processes the
553+
dimensionless endpoint solution into the eight dimensional output ports.
554+
555+
Parameters
556+
----------
557+
t : float
558+
evaluation time
559+
560+
Raises
561+
------
562+
RuntimeError
563+
if the BVP solve did not converge
564+
"""
565+
super().update(t)
566+
if not self.success:
567+
raise RuntimeError("BVP solver failed to converge.")
568+
569+
res = self.results()
570+
self.outputs.update_from_array(np.array([
571+
res["c_T_outlet [mol/m^3]"],
572+
res["y_T2_outlet_gas"],
573+
res["extraction_efficiency [fraction]"],
574+
res["total_gas_P_outlet [Pa]"],
575+
res["liquid_vol_flow [m^3/s]"],
576+
res["gas_vol_flow_outlet [m^3/s]"],
577+
res["tritium_out_liquid [mol/s]"],
578+
res["tritium_out_gas [mol/s]"],
579+
]))
580+
532581
def results(self):
533582
"""Post-process the current BVP solution into dimensional results.
534583

tests/tritium/test_glc.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ def test_init(self):
8787
self.assertEqual(len(blk.inputs), 4)
8888
for label in ("c_T_in", "flow_l", "y_T2_inlet", "flow_g"):
8989
self.assertIn(label, blk.input_port_labels)
90+
#eight named dimensional output ports
91+
for label in ("c_T_out", "y_T2_out", "eff", "P_out", "Q_l", "Q_g_out",
92+
"n_T_out_liquid", "n_T_out_gas"):
93+
self.assertIn(label, blk.output_port_labels)
9094
#no successful solve yet, so no dimensional results
9195
self.assertIsNone(blk.results())
9296

@@ -139,17 +143,25 @@ def test_results_physical(self):
139143
res["Total tritium out [mol/s]"], places=12)
140144

141145

142-
def test_output_layout(self):
143-
"""The block output is the dimensionless solution at the two endpoints."""
146+
def test_output_ports(self):
147+
"""The eight dimensional output ports match the results dictionary."""
144148
blk = GLC(BCs="C-C", **_BASE)
145149
blk.inputs.update_from_array(np.array(_INPUT))
146150
blk.update(0.0)
147151

148-
#row-major [x_T(0), x_T(1), ...]; output[0] is the dimensionless outlet
149-
#liquid concentration, i.e. c_T_out / c_T_in
150152
res = blk.results()
151-
self.assertAlmostEqual(blk.outputs[0],
152-
res["c_T_outlet [mol/m^3]"] / _INPUT[0], places=12)
153+
for label, key in (
154+
("c_T_out", "c_T_outlet [mol/m^3]"),
155+
("y_T2_out", "y_T2_outlet_gas"),
156+
("eff", "extraction_efficiency [fraction]"),
157+
("P_out", "total_gas_P_outlet [Pa]"),
158+
("Q_l", "liquid_vol_flow [m^3/s]"),
159+
("Q_g_out", "gas_vol_flow_outlet [m^3/s]"),
160+
("n_T_out_liquid", "tritium_out_liquid [mol/s]"),
161+
("n_T_out_gas", "tritium_out_gas [mol/s]"),
162+
):
163+
idx = blk.output_port_labels[label]
164+
self.assertAlmostEqual(blk.outputs[idx], res[key], places=12)
153165

154166

155167
def test_unknown_bc_raises(self):
@@ -218,7 +230,9 @@ def test_simulation(self):
218230
blocks=[*srcs, block, sco],
219231
connections=(
220232
[Connection(srcs[i], block[i]) for i in range(4)]
221-
+ [Connection(block[0], sco[0])]
233+
#connect the named efficiency output port, as a downstream
234+
#consumer would
235+
+ [Connection(block["eff"], sco[0])]
222236
),
223237
log=False,
224238
)
@@ -227,7 +241,8 @@ def test_simulation(self):
227241
self.assertTrue(block.success)
228242
res = block.results()
229243
np.testing.assert_allclose(
230-
block.outputs[0], res["c_T_outlet [mol/m^3]"] / _INPUT[0], atol=1e-12
244+
block.outputs[block.output_port_labels["eff"]],
245+
res["extraction_efficiency [fraction]"], atol=1e-12
231246
)
232247

233248

0 commit comments

Comments
 (0)