Skip to content

Repository files navigation

Mie Scattering — Verified MATLAB → Python Migration

A Python port of the Mätzler (2002) Mie-scattering routines (mie, mie_abcd) and the Jacques/Brown getMieScatter wrapper, delivered with a differential test harness that proves the Python results reproduce the original MATLAB numerically — not just "physically plausible," but matched to the original code's own numbers.

CI Python Tests License: MIT Ruff

The CI badge covers one workflow with four jobs: MATLAB-equivalent verification on GNU Octave, the pytest matrix (3.9/3.11/3.13), notebook execution, and ruff lint.


The result, up front

PASSED. The Python translation was run against the original MATLAB on 714 independent input cases (8 documented usage scenarios, seeded and reproducible). Every compared value agrees within the agreed engineering tolerances — worst relative error ~2×10⁻⁹, driven by high-order complex-argument Bessel functions and independently confirmed to ~10⁻¹² absolute. Validated live against MATLAB R2025a and GNU Octave 11.3, and cross-checked against an independent Bohren–Huffman implementation (~10⁻¹²). The only intentional differences from MATLAB are documented (suppressed console output; a NaN-vs-finite value in the physically-undefined no-scattering case) and affect no verified quantity.

reference vs python

MATLAB reference vs Python port for every numeric output and coefficient across all fixtures; points lie on the y = x line. Full interactive report: report.html (open the raw file) — see also the scenario coverage matrix and branch map.


Verify it yourself (English)

You need MATLAB or free Octave and Python 3.9+. Three steps:

  1. Open a terminal in this folder.
  2. Run one command — macOS/Linux: ./verify.sh · Windows: verify.bat
  3. Read report.html (opens automatically). A green PASSED banner means every Python result matched the original MATLAB within tolerance; a red FAILED banner names the diverging value.

The script creates a local .venv, installs the Python deps, auto-detects MATLAB (including /Applications/MATLAB_*.app) or Octave, and rebuilds the report. Three independent witnesses confirm the migration: a local MATLAB run (committed under reports/), the client's own MATLAB run via verify.sh, and a cloud Octave run in CI.

Проверьте сами (Русский)

Нужен MATLAB или бесплатный Octave и Python 3.9+. Три шага:

  1. Откройте терминал в этой папке.
  2. Одна команда — macOS/Linux: ./verify.sh · Windows: verify.bat
  3. Откройте report.html (откроется сам). Зелёный PASSED — все результаты Python совпали с исходным MATLAB в пределах допусков; красный FAILED укажет расхождение.

Скрипт сам создаёт .venv, ставит зависимости, находит MATLAB (в т.ч. /Applications/MATLAB_*.app) или Octave и пересобирает отчёт. Отчёт содержит: статусы PASS(both/rel/abs), матрицу покрытия сценариев, карту веток, худшие случаи по относительной и абсолютной погрешности отдельно и SHA-256 корпуса.


How this differs from existing Mie solvers

General-purpose Python Mie packages (e.g. miepython, PyMieScatt) implement the Bohren–Huffman algorithm independently and are a fine choice for new work. This repository does something narrower and, for a migration, more valuable: it is a provably faithful port of one specific legacy codebase — the exact mie/mie_abcd/getMieScatter MATLAB a client already has deployed, already validated against their instruments, and already embedded in downstream tooling that expects its exact numbers. The deliverable isn't "a Mie calculator that gets the physics right" — it's evidence that this Python function returns what that MATLAB function returns, case by case, with the divergence risks (rounding, special-function branch cuts, indexing) named and tested. If a generic library already meets your need, use it; this exists for the case where "close enough physically" isn't good enough and you need to keep your original code's numbers.


Quickstart (use the port)

pip install 'git+https://github.com/GrednevMSU/mie-scattering-matlab-to-python'
from mie_py import mie, mie_abcd, get_mie_scatter

u = mie(1.33 + 0j, 5.0)          # [Re(m), Im(m), x, qext, qsca, qabs, qb, g, qratio]
qsca, g = u[4], u[7]

mus, g, musp = get_mie_scatter(  # tissue-optics wrapper -> [mus, g, musp] (cm^-1)
    lambda_=0.633, dia=0.05, fv=0.05, npar=1.57 + 0j, nmed=1.33)

A runnable tour (usage + both demo scenarios + a verification teaser) is in notebooks/quickstart.ipynb. The MATLAB↔Python symbol map is in docs/NAME_MAP.md.


Repository layout

Root holds only what a first-time visitor needs; everything else is grouped by purpose so the structure reads as intentional, not sprawling.

README.md · LICENSE · THIRD_PARTY_NOTICES.md      first-minute essentials
verify.sh · verify.bat                            one-command entry point
report.html                                       the golden, pre-generated report
mie_py/                                            the Python port (numpy/scipy)

harness/            generate_fixtures.m, run_reference.m, matlab_src/
                    (ORIGINAL MATLAB, untouched), compare.py, report.py,
                    plots.py, tolerances.yaml — the whole verification engine
fixtures/           the seeded input corpus + manifest.json (SHA-256)
reference_outputs/  golden MATLAB outputs, committed for MATLAB-free reruns
reports/            live verification_report.md, figures/, archived report versions
docs/               methodology notes, findings, name map, changelogs, whitepaper
tests/              pytest suite against committed MATLAB golden (no MATLAB needed)
bench/              MATLAB-vs-Python timing scripts + committed results
notebooks/          quickstart.ipynb
.github/workflows/  CI: Octave verify + pytest matrix + notebook + lint

Architecture, in one picture:

   harness/matlab_src/  (ORIGINAL MATLAB — never modified)
        │  harness/generate_fixtures.m ──► fixtures/ + manifest.json (seeded corpus, SHA-256)
        │  harness/run_reference.m     ──► reference_outputs/         (golden outputs)
        ▼
   ┌──────────────────┐     same inputs      ┌────────────────────┐
   │  MATLAB / Octave  │◄────────────────────►│   mie_py/  (PORT)  │
   └──────────────────┘                      └────────────────────┘
                     \                        /
                      \  harness/compare.py  /   (tolerances.yaml)
                       ▼                      ▼
              report.html  +  reports/verification_report.md  (+ figures)

Reproduce the report without MATLAB (uses the committed golden):

docker build -t mie-verify .
docker run --rm -v "$PWD/out:/out" mie-verify   # writes out/report.html

Benchmark

Single-machine mie() timing (MATLAB R2025a vs Python on this hardware); see docs/BENCHMARK.md for methodology and caveats.

x nmax Python [µs] MATLAB [µs] ratio
1 7 55.9 318.9 0.18×
50 67 335.1 593.8 0.56×
150 173 1743 1761 0.99×

The port is ~2× faster on short series and reaches parity on long ones. Speed is not a project goal; timing is shown for transparency. Numbers vary with hardware and BLAS.


Methodology & scope

  • docs/VERIFICATION_NOTES.md — function inventory, the risk table of every MATLAB↔Python divergence hazard (nmax rounding, half-integer Bessel functions, conjugate transpose, non-scattering singularities…), tolerance justifications, corpus design.
  • docs/ORIGINAL_CODE_FINDINGS.md — documented deviations (F1–F6) and the two review claims that were not defects.
  • THIRD_PARTY_NOTICES.md — provenance and license status of the original MATLAB.
  • docs/whitepaper.md — methodology write-up (placeholder / outline).
  • docs/CORPUS_CHANGELOG.md — audit trail for the fixture corpus itself, independent of the repo's own release history.

Verified envelope: tissue-optics refractive indices (real 1.0–1.6), absorbing particles up to Im(npar)=0.1, non-absorbing (real) medium, size parameter x ≤ 150 (dia ≤ 10 µm). Out of domain: x < 0 (matches original by erroring) and complex nmed (finding F4).


Services — verified numerical migration

I port legacy MATLAB/Fortran/C numerical code to Python and deliver the proof it still computes the same answers: a reproducible equivalence harness and a report a non-specialist can audit. Engagements come in three tiers (scope below; contact for a quote).

Basic Standard Enterprise
Port to NumPy/SciPy
Bug-for-bug fidelity + documented deviations
Seeded fixture corpus + reference runner
Per-output tolerances with written justification
Single-file HTML pass/fail report
pytest suite + packaging (pip install)
Convergence figures + benchmark
CI (cloud second-engine witness) + Docker
Extended envelope / edge-case hardening
Multi-engine cross-validation (MATLAB + Octave)
Whitepaper + methodology write-up
Handover, training, maintenance window

This repository is a worked Basic→Standard example end to end. Prices depend on code size, algorithm complexity, and required envelope — contact for a quote.

Contact: grednevnv@my.msu.ru · github.com/GrednevMSU


License: MIT for the port and harness; harness/matlab_src/ is third-party — see THIRD_PARTY_NOTICES.md.

About

Verified MATLAB->Python migration of Mie scattering code (Matzler 2002 / Jacques-Brown), with numerical-equivalence harness

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages