Repository navigation
Modernize issue integration - #87
Merged
Merged
Conversation
Initialize IFL before the environmental-CAPE call (matching pcmin.m) instead of after it, so a flag tripped by that calculation is no longer overwritten by the default. No output change for converging profiles (regression pins pass unchanged at rtol=1e-13). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
For marginal near-neutral soundings the BE02 fixed-point pressure iteration can lock into a period-2 cycle whose amplitude exceeds the 0.5 hPa tolerance; pcmin.m (and previously tcpyPI) runs to the iteration cap and returns missing (IFL=2). Detect the cycle (iterate returns to within 1e-5 hPa of the two-back state while the step exceeds tolerance, checked after NP>=10) and collapse it to the cycle midpoint, letting the loop exit through the normal convergence path (IFL=1). Converging profiles are unchanged bit-for-bit: every column of the pinned sample exits within 9 iterations so the gated branch is unreachable; enforced by the 13-digit doctests, the rtol=1e-13 gridded regression, and a new bit-identity test on the 1995 control profile. Adds rescue + seeded fuzz stress tests and updates the instability notebook narrative. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The sample pipeline previously fed ERA5 specific humidity directly as pi()'s mixing-ratio input (documented legacy convention, ~1-2% low in boundary-layer vapor). The builder now converts r = q/(1-q) and stores it as 'r' (Water Vapor Mixing Ratio, g/kg); ERA5 relative humidity is renamed 'r' -> 'rh' to free the name. Month coordinate attrs are now CF-defensible (units '1' + long_name) instead of the non-udunits 'Month Number'. Regenerates sample_data.nc and the run_sample output artifacts (regression re-pinned); updates run_sample.py, reference_calculations.m (MATLAB reference must be regenerated from the new sample), and the six notebooks that read the gridded sample. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quantified on the ERA5 September-2024 North Atlantic sample: switching to the physical CL=4190 raises VMAX by ~+1.2 m/s (+1.8%) on average and deepens PMIN by ~5-6 hPa. The modified CL=2500 is retained deliberately for BE02/pcmin consistency; documented in the constants.py docstring, a note in Lv() (pseudoadiabat-tuned, not Kirchhoff), and an aside in efficiency_demo.ipynb (per checkCL branch triage). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pi_field() wraps the same compiled per-column core as pi() in a Numba generalized ufunc (target='parallel', cache=True), processing the entire field inside compiled multithreaded code. This removes the per-column Python-loop overhead of xarray.apply_ufunc(..., vectorize=True): the 12-month sample (11,232 columns) drops from ~3.7 s to ~0.04 s (~100x) with results exactly equal to pi() for identical inputs. Implemented natively - no new dependencies - so only tcpyPI code executes (cf. the Skyborn benchmark that motivated issue #86). Adds a per-cell NaN-MSL early return to the compiled core (unreachable for valid MSL), a pure-Python fallback when Numba is disabled, exact-equality/NaN/ordering/broadcast tests, a three-way benchmark in clock_pypi.ipynb (legacy vs pi_field vs optional Skyborn, with unit conversion and graceful skip), a 'bench' pixi env providing skyborn, and switches run_sample.py to the whole-field path (artifacts regenerated on the float64 path; regression re-pinned). Verified on the numba 0.59 floor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ruff (lint+format) and lenient mypy configured in pyproject with a pixi 'lint' environment and a CI lint job; .pre-commit-config.yaml for contributors. tcpyPI now degrades gracefully when numba is not installed: it imports with a RuntimeWarning and runs the pure-Python kernels (pi_field falls back to a per-column loop), tested via a subprocess with the numba import blocked (roadmap #75). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ruff format + ruff check --fix across src/, tests/, run_sample.py, and data/ scripts (whitespace/import-order/pyupgrade); per-file ignores for the package __init__ re-export pattern and run_sample's deliberate sys.path shim; remove two dead NCMAX assignments and a dead diseq assignment; simplify a ==True comparison; two targeted type-ignores for numpy's nditer stub limitation. No behavior change: full suite and the rtol=1e-13 regression pass unchanged; mypy and ruff now run clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nda-forge docs - hatch-fancy-pypi-readme rewrites the README's relative links/images to absolute GitHub URLs for PyPI (readme now dynamic; verified zero relative links in the built wheel's long-description). - Bump requires-python to >=3.11 (roadmap #75), propagated through classifiers, the pixi min-versions CI env (verified: py3.11.15/numpy1.26.4/numba0.59.1, 66 tests pass), ruff/mypy targets, and the README. - CI workflows trigger on [main, master] to survive the default-branch rename (drop master afterwards); URLs written against main. - README: conda-forge badge and install instructions (feedstock already exists). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eld flags, refresh AGENTS.md From the branch review panel (reuse + conventions angles): extract shared _outflow_source_flag() and _sort_profile_descending() helpers so pi() and pi_field() cannot drift; make the compiled core's CHECK 0 the single owner of the NaN-MSL policy (wrapper keeps only the shared-P guard); make pi_field's option flags keyword-only (new API surface; prevents silent positional transposition); refresh AGENTS.md (3.11 floor, lint/bench commands, module map incl. pi_field and the r-mixing-ratio sample convention, drop brittle test counts); bump ruff-pre-commit to v0.15.21 to match the CI lint env. All gates green: ruff, mypy, 66 basic + 2 regression tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…it fixes From the Opus review panel: fix the broken xarray quickstart (ds.q -> ds.r after the mixing-ratio rename; verified it runs); replace the sdist exclude list with an explicit only-include allowlist (hatchling treats .gitignore !-negations as force-includes that overrode the exclude, silently shipping ~12 MB of sample netCDF - sdist now 50 KB with zero .nc, wheel still builds from it); fix the stale pyPI/issues URL; list matlab_pi_reference_2024.nc in the README data inventory; use the current ruff-check pre-commit hook id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ersisted env-CAPE flags From the adversarial science review (200k-profile fuzz + full-sample sweep, all items CONFIRMED-SAFE): document that the period-2 rescue covers cycle amplitudes up to ~1 hPa (larger cycles fail safe to IFL=2), and that a flag tripped by the environmental-CAPE calculation persists (#78) so IFL=0/3 can accompany finite outputs on converged degenerate-parcel columns - IFL==1 remains the trustworthy-output gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… inputs Two math-identical optimizations, certified byte-for-byte equal to the previous kernel (d4aa131) over the full 12-month sample x 7 option combinations through both entry points, the doctest and both 1995 marginal profiles x the same combos, and a 50,000-profile seeded fuzz corpus with NaN injections - all 58 output arrays byte-identical: 1. Replace list-form min([a, b])/max([a, b]) with scalar min(a, b)/max(a, b) at 14 hot-loop sites. This is a selection (comparison), not arithmetic - identical comparisons in identical argument order returning one of the original bit patterns (NaN first-argument bias preserved) - but the list form heap-allocated a reflected list on every call inside the compiled kernels. Also matches the meaning of pcmin.m's min([a b]) MATLAB idiom. 2. ascontiguousarray for the profile arrays in the pi_field wrapper (memory layout only; xarray.apply_ufunc hands over strided transposed views). Measured: full-field pi_field 21.5 ms -> 13.0 ms (1.65x; ~285x vs the legacy per-column workflow) on the 11,232-column sample. All gates green: ruff/mypy clean, 66 basic + 2 regression tests (the rtol=1e-13 pins and pi_field==pi exact-equality tests are permanent tripwires for the bit-identity guarantee). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-identical) Class 2 of the certified kernel optimizations: the environment (T, R, P) is identical across all ~20 CAPE evaluations of a pi() column, so the missing-value scan, ptop slicing, ordering check, and per-level environmental density temperature now compute once per column (_cape_env_setup) instead of once per call; cape() becomes a thin setup+core wrapper (_cape_core holds the parcel-dependent math line-for-line) and _pi_numba calls the hoisted path directly. Certified byte-identical vs 848a85d over 59 output arrays: full sample x 7 option combos through pi_field AND scalar pi(), doctest + both 1995 profiles x combos, 100 direct cape() calls (degenerate parcels, NaN-injected environments, both miss_handle paths), and 50k fuzz. Re-certified on the post-format final bytes. Honest measurement: negligible speed change (pi_field 12.2 -> 12.0 ms full-field; the Newton entropy solver dominates per-column cost, so the deduplicated environmental terms barely register). Kept for the clean environment/parcel separation; trivially revertable if the structural change is judged not worth it. All gates green incl. the numba-0.59 floor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record the durable kernel-change policy (math-by-math/bit-for-bit identicality, certified via the byte-equality harness; never reassociate arithmetic), the cape() setup/core hoisting structure and its rationale, the IFL==1 trustworthy-output gate and rescue amplitude coverage, and the bench-kernel Jupyter registration. Also gitignore the local .ai/ handoff directory. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lls (bit-identical)" This reverts commit 2e7a2de. The hoist was certified byte-identical but measured ~0 speed gain (the Newton entropy solver dominates per-column cost), so the structural drift from the pcmin.m/MATLAB reference is not worth it. pi.py is restored byte-for-byte to the certified 848a85d state (git diff empty), so no new certification run is required. AGENTS.md updated to match the restored cape() structure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-run of matlab_scripts/reference_calculations.m (MATLAB Online) against data/sample_data.nc with humidity as true mixing ratio r. verify_pi.ipynb max abs diffs vs pyPI: VMAX 0.110 m/s, PMIN 0.300 hPa, T0 0.180 K, LNB 1.074 hPa. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… benchmark The old cell pre-converted units by hand, but xarray arithmetic keeps the stale units attrs and Skyborn's xarray wrapper converts by attribute, so every input was silently double-converted (PI solved on ~576 K SSTs, VMAX RMSE 63 m/s). The cell now converts outside the timed region with corrected attrs, warms both paths, times best-of-5 through the same xarray-level API, and prints a definitive verdict plus a value check. Fresh outputs on the bench kernel: legacy apply_ufunc 0.69 s vs pi_field 26 ms (warm, ~27x); pi_field 25.5 ms vs Skyborn 24.4 ms (comparable); VMAX agreement max |diff| 1.9e-2 m/s over 7093 cells (Skyborn float32). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nelspecs Full Run-All of every notebook after the Class-2 revert: nine on the default-env kernel (tcpypi-pixi), clock_pypi on the bench kernel. verify_pi reproduces the certified MATLAB comparison exactly. All notebooks previously carried the kernelspec of an unrelated local environment, which Jupyter silently binds to on open; kernelspec metadata is now pinned to the repo's own kernels (tcpypi-pixi / tcpypi-bench). pixi.lock: editable-install version stamp from the env re-solve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
No description provided.