Solve size_batch loading time analytically when sizing by V_max - #250
Merged
Conversation
…ng time in closed form When called with V_max and no N_reactors/loading_time (e.g., NRELEthanolFermentation(..., V_max=...)), size_batch solved for the loading time by fixed-point iteration. The iterated map always admits the spurious root tau_loading = -(tau_reaction + tau_cleaning), which is attracting whenever F_vol*(tau_reaction + tau_cleaning) < V_max*V_wf; wegstein (called with convergence checks disabled) then silently converges to it, yielding ceil(0) = 0 reactors and a ZeroDivisionError in the released 2.53.11 (masked on master by the max(N_reactors, 2) clamps, which leave the fragile iteration in place). The fixed-point equations have an exact closed-form solution, tau_loading = V_max*V_wf/F_vol (the loading time of a reactor at maximum working volume under constant filling), from which the minimum number of reactors follows directly and is always >= 2. Use it instead of iterating; drop the now-unneeded clamps and flexsolve import; update the docstring notes and the stale constant-loading doctest (failing on master since the clamps changed the output).
size_batch loading time in closed form when sizing by V_maxsize_batch loading time analytically when sizing by V_max
yoelcortes
approved these changes
Aug 20, 2026
yoelcortes
left a comment
Member
There was a problem hiding this comment.
I double check the math by hand. I never realized it had a closed solution until now. Good catch!!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #249.
Fix
The fixed-point equations have an exact analytical solution: the quadratic's discriminant collapses to a perfect square, giving
— the time to fill a reactor at maximum working volume under constant filling. This PR uses it directly:
The subsequent (already-existing) recompute of
V_T,V_i, andtau_loadingfrom the integerN_reactorsis unchanged. Consequences:ZeroDivisionError.N_reactors = ceil(F_vol*(tau_reaction + tau_cleaning)/(V_max*V_wf) + 1)is the minimum count satisfyingV_i <= V_max, and is always >= 2, so themax(N_reactors, 2)clamps are removed as redundant.from flexsolve import wegsteinimport is dropped.N-consistent) output.Verification
All on Python 3.14.7 / thermosteam 0.53.5:
NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL NUMBER ELLIPSIS):pytest --doctest-modules biosteam/units/design_tools/batch.py— passes (fails on master);pytest --doctest-modules biosteam/units/nrel_bioreactor.py— passes (theN=8docstring example is byte-identical, confirming theN-given path is untouched).NRELEthanolFermentationwithtau=8, V_max=3785, the docstring feed):ZeroDivisionErrorinsize_batch.