Imported from liamkirkpatrick/pliomio_isotopes (
AGENTS.md). Install upstream withnpx skills add liamkirkpatrick/pliomio_isotopes. Copyright stays with the author.
AGENTS.md
Repository-specific details
- Python package:
swimundersrc/swim/ - Full tests:
conda run -n mioplio python -m pytest -q - MATLAB parity tests:
conda run -n mioplio python -m pytest -q tests/parity - Lint:
conda run -n mioplio ruff check src tests scripts - Type check:
conda run -n mioplio mypy src scripts - MATLAB baseline runner:
run('tests/run_swim_allan_hills_test.m') - Frozen fixtures:
tests/fixtures/matlab/port_baseline_v1/allan_hills/ - Fixture formats: numeric MATLAB v7
.mat, CSV, and JSON provenance - Numerical tolerances: use the explicit tolerances in
tests/parity/; do not change them without documenting numerical justification - No subdirectories currently require a more specialized
AGENTS.md
Project purpose
This repository is a Python reimplementation and future extension of Simple Water Isotope Model (SWIM) an existing scientific modeling framework originally implemented in MATLAB and described in Markle, Bradley R., and Eric J. Steig. "Improving temperature reconstructions from ice-core water-isotope records." Climate of the Past 18.6 (2022): 1321-1368.
The project has two distinct goals:
- Reproduce the published / legacy MATLAB model faithfully in Python.
- Only after parity is established, improve the software design and extend the science. Here we will attempt to apply SWIM to produce a first-of-it's-kind reconstrunction of Pliocene and Miocene water isotopes.
During the porting phase, preserving scientific and numerical behavior is more important than making the implementation elegant. Note that the current script often contains multiple versions of the same function or dataset - I will want to preserve this rough form of version control (e.g. be able to select older versions), but the outdated versions should more explicitly be documented as outdated and the differences should be readily accessible.
Sources of truth
When determining intended model behavior, consult sources in this order:
- Scientific documentation derived from the paper and supplement
docs/science/
- Original MATLAB implementation
legacy_matlab/
- Recorded project decisions and known discrepancies
docs/porting/
- Current Python implementation
src/
- Tests and MATLAB reference outputs
tests/
The paper describes the intended science, while the MATLAB code represents the behavior of the legacy implementation. These may not always agree.
Never silently resolve a discrepancy between the paper, supplement, MATLAB code, documentation, and Python implementation. Identify it explicitly and document it before changing scientific behavior.
Required background before changing model behavior
Before modifying scientific calculations, read the relevant project documentation.
At minimum, consult:
docs/science/model_overview.mddocs/science/equations.mddocs/legacy/matlab_architecture.mddocs/legacy/execution_flow.mddocs/porting/traceability.md
Also inspect any topic-specific documentation relevant to the code being changed.
If one of these files does not yet exist, do not invent its contents. Use the paper, supplement, MATLAB implementation, tests, and existing documentation as appropriate, and create or update documentation when useful discoveries are made.
Core porting principles
1. Establish parity before improving the model
During the MATLAB-to-Python port:
- Preserve observable MATLAB behavior unless a deliberate deviation has been documented.
- Do not fix suspected scientific bugs, numerical quirks, unusual conventions, or awkward algorithms merely because they appear incorrect or inelegant. Do flag these for review.
- Do not combine a behavioral port with a scientific change.
- Prefer a faithful, testable implementation first; refactoring can happen after parity is established.
If the MATLAB code appears to contain a bug or conflicts with the paper:
- Identify the discrepancy.
- Determine whether it affects model output.
- Document it.
- Preserve legacy behavior during the parity phase unless the project explicitly decides otherwise.
2. Preserve scientific meaning, not MATLAB syntax
The Python implementation does not need to mimic MATLAB line-for-line.
Prefer clear Python and NumPy constructs when they preserve the same behavior.
Be especially careful with:
- MATLAB 1-based indexing versus Python 0-based indexing
- inclusive MATLAB ranges
- column-major array assumptions
- implicit array expansion / broadcasting
- matrix multiplication versus elementwise multiplication
- transpose behavior
- shape changes caused by indexing
- MATLAB logical indexing
- default floating-point behavior
NaNhandling- boundary indexing
- interpolation and extrapolation behavior
- solver tolerances and stopping criteria
- ordering of operations
- hidden state, globals, persistent variables, or script workspace variables
Do not simplify these behaviors until equivalence has been demonstrated.
3. Make units explicit
Scientific quantities must have clear units.
When adding or modifying model variables:
- Preserve the units used by the original model unless deliberately changing them.
- Document unit conversions near the relevant calculation.
- Avoid unexplained numerical conversion factors.
- Prefer descriptive variable names over ambiguous abbreviations in new Python code.
- Where practical, include units in docstrings or comments for public model variables and parameters.
If units are uncertain, investigate rather than infer silently.
4. Preserve numerical reproducibility
Scientific code should be reproducible.
When relevant:
- Use deterministic random seeds in tests.
- Record solver tolerances.
- Avoid unnecessary changes to operation ordering during the parity phase.
- Do not replace an algorithm with a mathematically equivalent one without checking whether numerical output changes materially.
- Compare intermediate states, not only final outputs, when debugging parity failures.
MATLAB reference implementation
The original MATLAB implementation lives under:
legacy_matlab/
Treat this directory as a reference implementation.
Unless a task explicitly requires changing the legacy code:
- Do not refactor the MATLAB implementation.
- Do not rename legacy files.
- Do not alter legacy calculations to make Python tests pass.
- Do not overwrite MATLAB-generated reference outputs.
If MATLAB needs to be instrumented to generate additional reference data, keep such changes minimal and clearly documented.
Python implementation
Python source code lives under:
src/
Follow the existing repository structure and conventions. Do not create new architectural layers or abstractions unless they solve a concrete problem.
General expectations:
- Prefer small, composable functions.
- Avoid global mutable state.
- Make dependencies explicit.
- Add type annotations to new public functions where practical.
- Use NumPy idiomatically, but not at the expense of numerical parity.
- Keep scientific calculations separate from plotting, file I/O, and presentation logic where practical.
- Do not optimize performance before correctness and parity are established.
When porting a MATLAB routine, preserve a clear correspondence between the legacy routine and its Python replacement until the port is mature.
Testing and validation
Tests live under:
tests/
Expected categories may include:
tests/unit/— local behavior of individual functionstests/integration/— behavior across model componentstests/parity/— comparison with MATLAB reference behaviortests/fixtures/— fixed inputs and reference outputs
MATLAB parity tests
For ported scientific calculations, prefer tests against MATLAB-generated reference values.
A useful parity test should record, when available:
- model input
- relevant parameters
- intermediate state
- expected output
- tolerance used for comparison
- provenance of the MATLAB reference result
Do not loosen tolerances simply to make a failing test pass.
If a tolerance must change, explain why the new tolerance is scientifically and numerically justified.
Debugging parity failures
When Python and MATLAB disagree:
- Reproduce the failure with the smallest practical case.
- Compare shapes, indexing, units, and boundary values.
- Compare intermediate calculations.
- Identify the earliest point of divergence.
- Determine whether the difference is caused by:
- translation error
- indexing
- shape / broadcasting behavior
- floating-point ordering
- solver behavior
- MATLAB-specific semantics
- undocumented legacy behavior
- an actual discrepancy in the original model
- Fix the cause rather than compensating for the final output.
Never alter a reference fixture merely because the Python result differs.
Scientific traceability
Maintain the mapping between the scientific description, legacy implementation, Python implementation, and validation.
The primary traceability document is:
docs/porting/traceability.md
When porting or substantially modifying scientific functionality, update the traceability documentation where appropriate.
Useful mappings include:
- scientific concept
- paper / supplement section or equation
- MATLAB file and function
- Python module and function
- parity or validation test
- known discrepancy or implementation note
Important scientific reasoning should not live only in chat history, issue comments, or commit messages.
Documentation as persistent project knowledge
This repository should become progressively easier for future humans and agents to understand.
If investigation reveals important information that is not already documented, update the appropriate file under docs/.
Examples include:
- meaning of poorly named MATLAB variables
- units
- hidden assumptions
- execution order
- important global state
- boundary conditions
- solver behavior
- unexpected indexing conventions
- undocumented parameter defaults
- differences between the publication and MATLAB implementation
- behavior that initially appears to be a bug but is required for parity
- decisions made during the Python port
Do not leave important discoveries only in the current conversation.
Do not add speculative documentation as fact. Clearly label unresolved interpretations or open questions.
Expected task workflow
For nontrivial porting or scientific tasks, follow this sequence unless the task explicitly requires something else.
Before editing
- Read the relevant documentation.
- Inspect the MATLAB implementation and its dependencies.
- Inspect the current Python implementation and tests.
- Identify relevant scientific equations, variables, units, and assumptions.
- Note any ambiguity or discrepancy that may affect the implementation.
While editing
- Make the smallest coherent change.
- Preserve legacy behavior during the parity phase.
- Add or update tests.
- Avoid unrelated refactors.
- Document important newly discovered behavior.
After editing
- Run the relevant tests.
- Run parity comparisons where available.
- Review numerical tolerances.
- Update traceability or other project documentation if needed.
- Summarize:
- what changed
- what was validated
- remaining discrepancies or uncertainties
Scope discipline
Keep changes narrowly aligned with the requested task.
Do not:
- refactor unrelated modules
- rename scientific concepts merely for stylistic preference
- change numerical algorithms without justification
- replace working scientific calculations with more sophisticated methods during the parity phase
- remove apparently unused MATLAB behavior until its role has been investigated
- introduce new dependencies unless they provide clear value
If a larger redesign would be beneficial, describe it separately rather than bundling it into a behavioral port.
Scientific changes after parity
Once a component has demonstrated adequate MATLAB parity, deliberate scientific changes may be made.
Such changes should be clearly distinguished from the legacy port.
For a scientific modification:
- State what behavior is changing.
- Identify the scientific rationale.
- Identify which equations, assumptions, or parameterizations are affected.
- Add tests for the new intended behavior.
- Preserve the ability to compare against the legacy implementation when useful.
- Update the relevant scientific and traceability documentation.
Do not describe a scientifically changed implementation as a faithful port of the MATLAB model.
Code review priorities
When reviewing changes, prioritize:
- Scientific correctness
- Agreement with intended legacy behavior
- Numerical correctness and stability
- Units and dimensional consistency
- Test coverage and reproducibility
- Traceability to the paper and MATLAB implementation
- Clarity and maintainability
- Performance
During the parity phase, elegance and optimization are secondary to correctness and traceability.
Commands
Use the Python 3.11 Conda environment and repository configuration:
conda run -n mioplio python -m pytest -q
conda run -n mioplio python -m pytest -q tests/parity
conda run -n mioplio ruff check src tests scripts
conda run -n mioplio mypy src scripts
Regenerate a local MATLAB reference run with:
run('tests/run_swim_allan_hills_test.m')
Do not assume an unavailable tool or dependency exists; inspect pyproject.toml, environment files, CI configuration, and repository documentation first.