Maintainer triage (June 29, 2026)
- Status: Verified bug against the current
master source in this fork.
- Severity: High.
- Area labels: area:reactors.
- Tackle batch: P3 - documented-mode crashes and tooling breakages.
The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Severity: High / Medium · Category: crash (control-flow + API misuse) · Part of #67
Three Reactors.py defects, each of which makes a documented reactor configuration crash. Grouped as one "make the reactor module runnable in all advertised modes" fix.
1. (High) PlugFlowReactor.solve_steady reads non-existent Inlet.concentr
Location: PharmaPy/Reactors.py:1604-1607
c_inlet = self.Inlet.concentr (1604), then indexed. No phase/stream stores concentr: LiquidPhase.__set_amounts sets only mole_conc/mass_conc/mole_frac/mass_frac; LiquidStream.updatePhase maps its concentr argument positionally onto the base mole_conc. There is no concentr property anywhere.
- Trigger: build a PFR, assign a
LiquidStream inlet, call reactor.solve_steady(vol_rxn) (also feeds plot_steady/concProfSteady/tempProfSteady).
- Wrong result:
AttributeError: 'LiquidStream' object has no attribute 'concentr'; the entire steady-state PFR solver and plot_steady are unrunnable.
- Fix: use
self.Inlet.mole_conc (the dynamic path already uses self.Liquid_1.mole_conc).
2. (Medium) CSTR / SemibatchReactor solve_unit(eval_sens=True) leaves problem undefined
Location: PharmaPy/Reactors.py:1134-1144 (and 1326-1336)
if eval_sens: pass (1134-1135) never builds problem; only the else branch creates Explicit_Problem. Execution then unconditionally reaches solver = CVode(problem) (1144). paramest_wrapper calls solve_unit(eval_sens=True) whenever self.return_sens is True, which defaults True in the CSTR/Semibatch constructors.
- Trigger: sensitivity-based parameter estimation on a CSTR/SemibatchReactor with default
return_sens=True.
- Wrong result:
NameError: name 'problem' is not defined; CSTR/Semibatch parameter estimation crashes immediately.
- Fix: implement the
eval_sens problem setup (mirror BatchReactor.solve_unit 800-813 with get_sundials_callable, problem.jac, problem.rhs_sens), or raise NotImplementedError instead of pass.
3. (Medium) heat_transfer ht_mode='coil' leaves heat_transf undefined
Location: PharmaPy/Reactors.py:294-302
if self.ht_mode == 'coil': pass (296-297) never assigns heat_transf, yet return heat_transf (302) is reached unconditionally. The tank reactors' energy balances call self.heat_transfer(...) for any non-isothermal run (BatchReactor 711; CSTR 1060/1066). 'coil' is an advertised ht_mode (docstring 603-605).
- Trigger:
BatchReactor(isothermal=False, ht_mode='coil') (or CSTR), solve_unit.
- Wrong result:
UnboundLocalError: local variable 'heat_transf' referenced before assignment on the first RHS evaluation.
- Fix: implement coil-mode area/duty, or raise
NotImplementedError for ht_mode=='coil' rather than falling through.
Related (not duplicates): #55 (sensitivity Jacobian block sizing), #54 (temp_ht metadata), #33 (PFR specific area diam/4) are distinct defects.
Maintainer triage (June 29, 2026)
mastersource in this fork.The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Severity: High / Medium · Category: crash (control-flow + API misuse) · Part of #67
Three
Reactors.pydefects, each of which makes a documented reactor configuration crash. Grouped as one "make the reactor module runnable in all advertised modes" fix.1. (High)
PlugFlowReactor.solve_steadyreads non-existentInlet.concentrLocation:
PharmaPy/Reactors.py:1604-1607c_inlet = self.Inlet.concentr(1604), then indexed. No phase/stream storesconcentr:LiquidPhase.__set_amountssets onlymole_conc/mass_conc/mole_frac/mass_frac;LiquidStream.updatePhasemaps itsconcentrargument positionally onto the basemole_conc. There is noconcentrproperty anywhere.LiquidStreaminlet, callreactor.solve_steady(vol_rxn)(also feedsplot_steady/concProfSteady/tempProfSteady).AttributeError: 'LiquidStream' object has no attribute 'concentr'; the entire steady-state PFR solver andplot_steadyare unrunnable.self.Inlet.mole_conc(the dynamic path already usesself.Liquid_1.mole_conc).2. (Medium)
CSTR/SemibatchReactorsolve_unit(eval_sens=True)leavesproblemundefinedLocation:
PharmaPy/Reactors.py:1134-1144(and1326-1336)if eval_sens: pass(1134-1135) never buildsproblem; only theelsebranch createsExplicit_Problem. Execution then unconditionally reachessolver = CVode(problem)(1144).paramest_wrappercallssolve_unit(eval_sens=True)wheneverself.return_sensis True, which defaults True in the CSTR/Semibatch constructors.return_sens=True.NameError: name 'problem' is not defined; CSTR/Semibatch parameter estimation crashes immediately.eval_sensproblem setup (mirrorBatchReactor.solve_unit800-813 withget_sundials_callable,problem.jac,problem.rhs_sens), or raiseNotImplementedErrorinstead ofpass.3. (Medium)
heat_transferht_mode='coil'leavesheat_transfundefinedLocation:
PharmaPy/Reactors.py:294-302if self.ht_mode == 'coil': pass(296-297) never assignsheat_transf, yetreturn heat_transf(302) is reached unconditionally. The tank reactors' energy balances callself.heat_transfer(...)for any non-isothermal run (BatchReactor 711; CSTR 1060/1066).'coil'is an advertisedht_mode(docstring 603-605).BatchReactor(isothermal=False, ht_mode='coil')(or CSTR),solve_unit.UnboundLocalError: local variable 'heat_transf' referenced before assignmenton the first RHS evaluation.NotImplementedErrorforht_mode=='coil'rather than falling through.Related (not duplicates): #55 (sensitivity Jacobian block sizing), #54 (
temp_htmetadata), #33 (PFR specific areadiam/4) are distinct defects.