bloc.chem.conservation#
Post-solve mass and energy conservation checks, per physical node.
These checks assume the solved network represents a steady operating point:
for a node with no accumulation, mass and energy flowing in must equal mass
and energy flowing out. A node that fails to close is a signal worth
surfacing – it may be a real accounting bug, a mis-specified connection
(e.g. mismatched MassFlowController rates), or – for residence-time-sized
reactors such as ContinuousMixingReactor
– a sign that the stage has not actually reached steady state yet (advanced
for only ~1 nominal residence time, still accumulating mass/energy).
Pure boundary nodes (a source Reservoir with no inlet, or a terminal sink
with no outlet) are excluded from the pass/fail verdict: conservation is only
meaningful for nodes with mass flow on both sides.
Attributes#
Exceptions#
Raised when one or more nodes fail mass/energy conservation. |
Classes#
Mass and energy balance for one physical node. |
Functions#
|
Per-node mass balance: sum(mdot_in) vs sum(mdot_out), in kg/s. |
|
Run mass + energy conservation checks at every physical node. |
|
Log a per-node conservation summary; return True iff every node closes. |
|
Non-boundary nodes that fail either the mass or the energy check. |
|
Raise |
|
JSON-safe serialization of a report, for caching/bundle storage. |
Module Contents#
- bloc.chem.conservation.logger#
- bloc.chem.conservation.DEFAULT_RTOL = 0.005#
- class bloc.chem.conservation.NodeConservationResult#
Mass and energy balance for one physical node.
- node: str#
- mass_in_kg_s: float#
- mass_out_kg_s: float#
- energy_in_kw: float#
- energy_out_kw: float#
- property is_boundary: bool#
True for a pure source/sink (mass flow on only one side).
- property mass_imbalance_rel: float#
- property energy_imbalance_rel: float#
- mass_closes(rtol=DEFAULT_RTOL)#
- energy_closes(rtol=DEFAULT_RTOL)#
- bloc.chem.conservation.check_mass_conservation(sim, connection_mass_flows_kg_s=None, connection_endpoints=None)#
Per-node mass balance: sum(mdot_in) vs sum(mdot_out), in kg/s.
Mirrors
collect_energy_flows()’s two data sources: connection-based (from a solvedSimulationResult) when available, else the live network’s.outlets(mass_flow_rate/downstream).- Parameters:
sim (
cantera.ReactorNet) – The solved reactor network.- Returns:
{node_name: {"mdot_in_kg_s": ..., "mdot_out_kg_s": ...}}.- Return type:
dict
- bloc.chem.conservation.run_conservation_checks(sim, connection_mass_flows_kg_s=None, connection_endpoints=None)#
Run mass + energy conservation checks at every physical node.
Does not raise or filter by tolerance itself – see
NodeConservationResult.mass_closes()/energy_closes(orlog_conservation_report()) to turn this into a pass/fail verdict.
- bloc.chem.conservation.log_conservation_report(results, rtol=DEFAULT_RTOL, log=None)#
Log a per-node conservation summary; return True iff every node closes.
Passing (and boundary) nodes log at debug level; a failing node logs a warning with its computed imbalance, so it shows up in normal operation without configuring debug logging.
- bloc.chem.conservation.failing_nodes(report, rtol=DEFAULT_RTOL)#
Non-boundary nodes that fail either the mass or the energy check.
- exception bloc.chem.conservation.ConservationCheckFailed(failing)#
Bases:
RuntimeErrorRaised when one or more nodes fail mass/energy conservation.
Used to hard-block Calculation Note export when running headless (a CLI script, CI): shipping an engineering deliverable built from a non-physical solve with no one watching is worse than refusing to export it. In an interactive GUI session,
require_conservation_ok()is called withinteractive=Trueinstead and never raises this – the failure is already visible vialog_conservation_report()and the per-node"conservation"entry (seeBlocConverterinbloc/core/converter.py), and a human can judge whether to proceed. Carries the failingNodeConservationResultentries (.failing) for callers that want to format their own message instead of this one.- failing#
- bloc.chem.conservation.require_conservation_ok(report, rtol=DEFAULT_RTOL, *, interactive=False)#
Raise
ConservationCheckFailedif any node fails to close.interactive=True(a human is watching a live GUI session, as opposed to a headless CLI/CI run – seeBLOC_NO_GUIinbloc/reporting/orchestrator_stone.py) downgrades this to a no-op: the failure was already surfaced vialog_conservation_report(), and hard-blocking the export mid-session would be more disruptive than informative when someone can just look at the warning and decide. The default (False) keeps the hard-block for unattended callers.
- bloc.chem.conservation.conservation_report_to_dicts(report)#
JSON-safe serialization of a report, for caching/bundle storage.