fix(mass_transfer): deprecate silently-ignored m_slope arg in ntu_og#11
Open
fix(mass_transfer): deprecate silently-ignored m_slope arg in ntu_og#11
Conversation
…ross-section PlantGeometry.COLUMN_CROSS_SECTION_M2 was computed with the literal 3.14159, which truncates pi at the 6th significant figure. For the 0.1 m absorber column the resulting area is off by ~8e-9 m² — small in absolute terms but it propagates into every K_OGa and H_OG calculation that uses the default geometry, and the discrepancy is visible against any independent re-derivation. Use math.pi so the constant is exact to double precision. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PlantGeometry.SAMPLING_HEIGHTS_M, ExperimentLabels.LABELS, and ExperimentLabels.COOLING_WATER_FLOWRATES_KG_H were defined as plain list/dict attributes on a class with no instances. Because Python class attributes are shared, any caller that mutated these (e.g. SAMPLING_HEIGHTS_M.append(...) or COOLING_WATER_FLOWRATES_KG_H["A"] = 0) would silently corrupt the value for every other consumer in the same process. The risk is real for notebook workflows where the same kernel is reused across analyses. Switch the lists to tuples and wrap the dict in types.MappingProxyType so mutations raise TypeError immediately. The public read API is unchanged — indexing, iteration, len(), and `in` all behave identically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The efficiency() docstring already states that η > 1 indicates measurement inconsistency (instrumentation drift, heat gain, or a swapped stream assignment), but the function never surfaced this — it returned the value silently and downstream U / ε / NTU calculations propagated the inconsistency. Emit a logger.warning with the offending duties and concrete remediation hints. Behaviour is unchanged for callers that don't configure logging (the package-level NullHandler swallows it), so this is non-breaking for existing scripts but immediately visible to anyone running with logging.basicConfig(level=logging.WARNING) or structured-log handlers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous implementation called np.mean inside a Python for-loop, paying
NumPy's per-call overhead once per element. cProfile against a 100k-sample
input showed 1.2M function calls and 222 ms wall time — completely dominated
by 100k np.mean dispatches.
Replace the loop with the standard cumulative-sum trick: build a padded
cumsum once, then index it twice to get every trailing-window sum in a
single vectorised expression. The leading edge (where a full window is not
yet available) is handled by counting actual window length per index, which
preserves the previous behaviour exactly (verified by the existing 19 unit
tests, all passing).
Benchmark (Apple M-series, Python 3.13.5, NumPy 2.x, window=60, best-of-5):
size before after speedup
----------- ------------ ----------- --------
1,000 ~2.2 ms 0.013 ms ~170x
10,000 27.2 ms 0.078 ms 349x
100,000 222.5 ms 0.893 ms 249x
1,000,000 2,223.3 ms 11.69 ms 190x
cProfile call count for size=100k drops from 1,200,006 to 11.
Also adds benchmarks/bench_rolling_mean.py — a reproducible script with the
exact baseline + cProfile dump so future regressions are easy to spot.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
) ntu_og(y_bottom, y_top, m_slope=...) accepted m_slope and the docstring promised "a rigorous calculation including the equilibrium back-pressure" when a non-zero value was passed. The function body never references m_slope at any point — every call returns the dilute-limit ln(Y_b / Y_t) regardless. Callers running the supposed "rigorous mode" were silently getting the dilute approximation, an optimistic NTU on real plant data. This is the v0.1.x semver-clean fix: * Non-zero m_slope now emits DeprecationWarning pointing at issue #5 and documenting that the parameter will be removed in v0.2.0. * The default m_slope=0.0 path stays warning-free, so existing scripts and the existing test suite are unaffected. * Two new tests pin the behaviour: - non-zero m_slope warns and returns the same value as m_slope=0 - default-call path is warning-free under warnings.simplefilter("error") A proper Colburn-equation entry point taking the absorption factor explicitly will land in v0.2.0 (tracked in #5). Fixes #5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
defnalk
added a commit
that referenced
this pull request
Apr 9, 2026
Records the four direct commits landed on main this session and the ntu_og(m_slope) deprecation arriving via PR #11 / issue #5. Each entry follows Keep a Changelog conventions and is filed under the appropriate heading (Fixed / Changed / Performance / Added / Deprecated). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI was failing on this branch with: UP035 Import from `collections.abc` instead: `Mapping` --> src/meapy/constants.py:20 Move the Mapping import. Behaviour unchanged — Mapping is the same ABC in either location since Python 3.9.
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 #5
Summary
Why a deprecation, not an immediate fix?
The current signature has no way to compute Colburn's equation — it would also need the L/G molar flows. Implementing the rigorous form requires a breaking signature change, which belongs in v0.2.0 under semver. Until then, the honest move is to surface the bug loudly without breaking existing scripts that pass `m_slope=0`.
Before / after
```python
BEFORE — silent dilute-limit answer regardless of m_slope
```python
AFTER — same value, but the user is told
The default `m_slope=0` call path is unchanged:
```python
Testing notes
Two new tests pin the behaviour in `tests/unit/test_mass_transfer.py::TestNTUOG`:
Local run:
```
$ pytest tests/unit/test_mass_transfer.py -q
40 passed in 0.13s
```
Full unit suite (124 + 2 new + the four other commits already on main):
```
$ pytest tests/ -q
130 passed
```
Out of scope (follow-ups)
🤖 Generated with Claude Code