Skip to content

Releases: scottprahl/miepython

Speed up and improved accuracy of coefficients

Choose a tag to compare

@scottprahl scottprahl released this 28 Jul 21:22

Speed up is 18x for near field calculations

Improved accuracy arises from using new stable recursion methods for calculating $a_n$, ..., $d_n$

Test coverage is now 100%

A number of errors/out-of-date documentation comments are fixed.

3.3.0 (07/28/2026)

  • fix the docstring examples in core.py, which had rotted unnoticed. The
    coefficients examples called mie_coefficients, a name that never
    existed, showed the imaginary parts with the wrong sign, and still included the
    padding element an_bn no longer returns; the efficiencies_mx examples
    used a different function's signature and printed an invented repr. The
    Returns section also described a tuple where an ndarray comes back
  • run the docstring examples as part of the test suite, so they cannot rot again.
    They are written with explicit formatting rather than bare array reprs, which
    keeps them independent of NumPy's print precision
  • keep one copy of the scattering-function normalization rules. core and
    rayleigh held the same thirty lines differing only in which efficiencies
    they consulted, so core.normalization_factor now takes an
    efficiency_source and rayleigh passes its own
  • accept an rng argument in generate_mie_costheta. It drew from the
    process-wide numpy.random, which a caller could only control by reseeding
    the whole program; passing numpy.random.default_rng(seed) now gives a
    reproducible stream and leaves the global one alone. Omitting it behaves as
    before
  • document the angular-argument convention: a scalar mu counts as one angle
    and returns a length-one array, except in phase_matrix, which squeezes it
    away. docs/01_basics.ipynb demonstrates the first half deliberately, so
    both are now stated in the docstrings and pinned by tests
  • fix make readme_images, which had never worked: .PHONY declared that name
    but the rule below it was written readme:, so the advertised command failed
    with "No rule to make target" while an undocumented make readme did the job
  • drop sync from make help. No such target exists; the one that syncs the
    environment is venv, and it was not listed at all. Also corrected
    pylint-check, described as "Same as lint above" when it runs pylint alone, and
    moved the individual check targets out of the packaging section into the lint one
    where they belong
  • check the Makefile's help text against the rules it defines, so a target cannot be
    advertised, or declared phony, without existing. These four bugs were all of the
    same kind -- the help block is a pile of @echo lines with nothing tying it to
    the rules underneath -- and nothing could have caught them
  • generate the README figures reproducibly. matplotlib stamps each SVG with the
    current time and names clip paths and glyphs from a random salt, so re-running
    make readme_images produced files differing on a hundred lines even when the
    figures were pixel-for-pixel identical. There was no way to tell "a plot changed"
    from "matplotlib rolled different ids". Fixing svg.hashsalt and passing
    metadata={"Date": None} makes repeated runs byte-identical, and the committed
    images are regenerated once against that
  • point the README license badge at blob/main rather than blob/master. There
    is no master branch; the link worked only because GitHub silently redirects
  • evaluate the near fields for every point at once instead of one point at a time.
    field.py walked the grid with np.ndindex and called into
    scipy.special separately for each point, so a 41x41 slice spent 0.4 s almost
    entirely in scipy's per-call overhead rather than on Bessel functions. The points
    are now split once into those inside the sphere and those outside -- the two sides
    need different radial functions and different media, but within a side every point
    does the same arithmetic -- and each group is evaluated as a
    (n_points, n_terms) batch. Roughly 18x faster: that slice takes 0.022 s, and
    a 101x101 slice drops from 2.4 s to 0.13 s. Every returned value is bitwise
    identical to before, which is checked point by point against evaluating the same
    coordinates individually
  • evaluate the spherical Hankel functions over orders 0..n+1 in one call rather
    than making four separate calls that recompute shared orders. xi'_n needs
    h1 at n-1, n and n+1, and the order-n value was being computed
    twice; slicing one array instead cuts that part of the work to a quarter
  • drop the three near-field per-point evaluators and the two loop drivers in favour
    of a single batched routine, 63 fewer statements for the same physics.
    _vsh_components_base now takes an explicit inside flag and arrays of
    coordinates, so it no longer re-derives from d_sphere which side it is on
  • make the submodules reachable, each in the way that suits it.
    miepython.rayleigh needs only NumPy and is now imported with the package, so
    import miepython is enough to reach it; miepython.vsh requires the
    optional scipy and is imported inside the same guard as field, staying
    absent when scipy is not installed; miepython.monte_carlo imports
    miepython itself, so importing it from the package would be circular and it
    remains a separate import miepython.monte_carlo. All three are now described
    in the package docstring, and monte_carlo's own docstring shows the full
    workflow and says why it is not imported for you
  • have vsh reach D_calc through ._backend instead of importing
    miepython for it. The old import was a cycle that worked only because the
    call is deferred to run time, and importing vsh from __init__ would have
    depended on that
  • fix the call signatures listed in vsh's module docstring. All four vector
    spherical harmonics were advertised as (n, k, d_sphere, r, theta, phi); they
    actually take a wavelength rather than a wavenumber and a refractive index
    besides, (n, lambda0, d_sphere, m_index, r, theta, phi), so anyone following
    the docstring got a TypeError. The four *_array variants went unmentioned
    altogether. Signatures written out in prose are now checked against the code
  • fix two stale references in the notebooks: mie.mie_S1_S2 in
    docs/03a_normalization.ipynb, together with the comparison values it quotes,
    and a commented-out mie._D_calc in docs/10_basic_tests.ipynb
  • fix off-by-one in n_pole for S1_S2 and everything built on it
    (i_par, i_per, i_unpolarized, phase_matrix, intensities).
    n_pole=1 returned the quadrupole instead of the dipole; it now matches
    the convention already used by efficiencies_mx
  • raise ValueError for an n_pole beyond the truncated series instead of
    returning zeros or an IndexError
  • add multipole regression tests (series sum, closed form, per-multipole
    optical theorem) and re-execute docs/12_multipoles.ipynb
  • implement the e_field argument of efficiencies_mx, which was accepted
    and documented but silently ignored. With n_pole > 0 it now selects the
    electric multipole a_n (e_field=True, the default) or the magnetic
    multipole b_n (e_field=False). Behavior change: n_pole > 0
    previously returned a_n and b_n combined; that total is now
    e_field=True plus e_field=False
  • make the two backends agree on g when n_pole > 0. The no-JIT backend
    returned None (which became nan for array input) while the JIT
    backend returned 0. Both now return 0.0, which is the exact value:
    an isolated multipole of one parity scatters symmetrically about 90 degrees
  • fix an operator-precedence bug in the perfectly-conducting guard of cn_dn.
    a and b or c made the test true for every finite index, so cn_dn(0j, x)
    raised ZeroDivisionError and an infinite index produced nan. The
    internal coefficients are now zero for a perfect conductor, as intended
  • drop fastmath from the numba _cn_dn_nb kernel. It implies LLVM's
    ninf, which folded the np.isinf guard to False and defeated the
    fix above in the JIT backend. This also improves JIT/no-JIT agreement
  • make the internal-field coefficients c_n and d_n numerically stable.
    psi_n came from the three-term upwards recurrence, which is contaminated
    by the growing chi_n solution once n exceeds |mx|. That is the normal
    case for a relative index below one, where the coefficients were wrong by up
    to 140%. psi_n now uses Miller's downwards recurrence seeded above |z|
    and normalised against whichever of psi_0 or psi_1 is larger, and
    the logarithmic derivatives take the always-stable downwards route.
    Worst error against a direct SciPy evaluation over 7320 cases drops from
    90 to 3e-9, and the JIT and no-JIT backends now agree to 5e-15 where they
    previously differed by up to a factor of 39
  • always use the downwards recurrence for the logarithmic derivative D_n.
    Wiscombe's criterion chose between the two recurrences from the refractive
    index alone, never from the number of terms, so it picked the upwards
    recurrence for small spheres where it is unstable. For a lossless sphere
    Re(a_n) must equal |a_n|**2; at m=1.05, x=0.1 the real parts of the
    quadrupole and higher coefficients came out with the wrong sign and up to 12
    orders of magnitude too large, which made ``efficiencies...
Read more

Near field cartesian fix

Choose a tag to compare

@scottprahl scottprahl released this 06 Mar 18:25

3.2.0 (03/06/2026)

  • fix error in E & H calculations in the near field when y≠0 (thanks @dorianherle)
  • add regression test

3.1.0 (02/07/2026)

  • add near-field E and H field APIs, fix boundary continuity/medium handling, and expand validation tests
  • add field calculation utilities, field module cleanup/help text improvements, and precomputed E/H reference data (via scattnlay)
  • improve performance: ~20% speedups in Mie backends and faster near-field calculations; add speed benchmarks
  • documentation updates: new/updated notebooks (boundary conditions, 2D fields, performance), clarified conventions
  • refresh docs/README visuals and assets; add custom CSS for docs images
  • jupyterlite/RTD updates: config moves, build modernizations, and avoid numba install in JupyterLite
  • packaging/CI: pyproject and requirements cleanup, improved PyPI workflow, updated citation automation/config
  • misc cleanups: remove unused files/images, minor typos, Makefile and docs config tidy-ups, CITATION.cff refresh

Now with near field calculations

Choose a tag to compare

@scottprahl scottprahl released this 08 Feb 01:03

3.1.0 (02/07/2026)

  • add near-field E and H field APIs, fix boundary continuity/medium handling, and expand validation tests
  • add field calculation utilities, field module cleanup/help text improvements, and precomputed E/H reference data (via scattnlay)
  • improve performance: ~20% speedups in Mie backends and faster near-field calculations; add speed benchmarks
  • documentation updates: new/updated notebooks (boundary conditions, 2D fields, performance), clarified conventions
  • refresh docs/README visuals and assets; add custom CSS for docs images
  • jupyterlite/RTD updates: config moves, build modernizations, and avoid numba install in JupyterLite
  • packaging/CI: pyproject and requirements cleanup, improved PyPI workflow, updated citation automation/config
  • misc cleanups: remove unused files/images, minor typos, Makefile and docs config tidy-ups, CITATION.cff refresh

Jupyter Lite support

Choose a tag to compare

@scottprahl scottprahl released this 03 Jan 00:15

3.0.5 (1/2/2026)

  • fix versioning

3.0.4 (1/2/2026)

  • Host jupyterlite instance of github
  • improve citation guidelines
  • add test for unpolarized intensity methods
  • begin work on local electrical and magnetic fields
  • using black now with longer lines
  • improved packaging
  • improve readme

3.0.3

  • skipped

3.0.2 (5/25/2025)

  • fix version number

3.0.1 (5/25/2025)

  • fix JIT regression (thanks @avgeiss)
  • clarify polarization in docstrings
  • improve README.rst
  • fix git branches
  • rename mie.mie_scalar to mie.single_sphere
  • rename small_mie_sphere to small_sphere
  • rename small_conducting_mie to small_conducting_sphere
  • rationalize importing of jit and non-jit code
  • add test_jit_speed.py and test_nojit_speed.py

3.0.2

Choose a tag to compare

@scottprahl scottprahl released this 25 May 22:10

3.0.2 5/25/2025)

  • update version in both __init__.py and pyproject.toml

3.0.1 (5/25/2025)

  • fix JIT regression (thanks @avgeiss)
  • clarify polarization in docstrings
  • improve README.rst
  • fix git branches
  • rename mie.mie_scalar to mie.single_sphere
  • rename small_mie_sphere to small_sphere
  • rename small_conducting_mie to small_conducting_sphere
  • rationalize importing of jit and non-jit code
  • add test_jit_speed.py and test_nojit_speed.py

Restored JIT functionality

Choose a tag to compare

@scottprahl scottprahl released this 25 May 21:41

3.0.1 (5/25/2025)

  • fix JIT regression (thanks @avgeiss)
  • clarify polarization in docstrings
  • improve README.rst
  • fix git branches
  • rename mie.mie_scalar to mie.single_sphere
  • rename small_mie_sphere to small_sphere
  • rename small_conducting_mie to small_conducting_sphere
  • rationalize importing of jit and non-jit code
  • add test_jit_speed.py and test_nojit_speed.py

New, saner, api

Choose a tag to compare

@scottprahl scottprahl released this 16 Mar 16:33

This version improves the api: mie.efficiencies() instead of mie.ez_mie() to find the Mie efficiencies. The source code has been refactored so there is less redundancy between jitted and non-jitted code. Other changes include

  • breaking api changes
  • use core.py to cleanly separate jit and non-jit code
  • new function to calculate mie coefficients inside sphere
  • new function to calculate E-fields near and far from sphere (only validated in far-field)
  • new rayleigh.py
  • new vsh.py to calculate vector spherical harmonics
  • new util.py for printing complex numbers
  • new bessel.py for complete spherical bessel function support
  • new monte_carlo.py to isolate Monte Carlo routines
  • use black for python formatting
  • update all notebooks to use new api
  • add more tests

Add ability to get multipole information

Choose a tag to compare

@scottprahl scottprahl released this 02 Dec 03:08

2.5.5 (12/1/2024)

  • add ability to get individual multipole intensities
  • add 12_multipoles.ipynb as documentation
  • improve github workflows

Better documentation for normalization options

Choose a tag to compare

@scottprahl scottprahl released this 07 May 23:39

Spring cleaning. Fixed a bunch of packaging details and improved the README.rst page.

Info about normalization options is available. For example, help(miepython.i_per) will now tell you

i_per(m, x, mu, norm='albedo')
    Return the scattered intensity in a plane normal to the incident light.

    This is the scattered intensity in a plane that is perpendicular to the
    field of the incident plane wave. The intensity is normalized such
    that the integral of the unpolarized intensity over 4π steradians
    is equal to the single scattering albedo.

    The normalization is controlled by `norm` and should be one of
    ['albedo', 'one', '4pi', 'qext', 'qsca', 'bohren', or 'wiscombe']
    The normalization describes the integral of the scattering phase
    function over all 4𝜋 steradians.

    Args:
        m: the complex index of refraction of the sphere
        x: the size parameter of the sphere
        mu: the angles, cos(theta), to calculate intensities
        norm: (optional) string describing scattering function normalization

    Returns:
        The intensity at each angle in the array mu.  Units [1/sr]

2.5.4 (5/7/2024)

  • document normalization in docstrings
  • add version and year to CITATION.cff
  • remove 'v' from version numbers
  • add github script and workflow to auto-update CITATION.cff
  • add conda badge to readme
  • clean up README.rst
  • use svg images
  • use a single tests/test_mie for jit and non-jit tests
  • support ruff
  • test python versions 3.7 to 3.12
  • fix badges
  • remove unused functions
  • fix zenodo link

Full Changelog: v2.5.3...2.5.4

More conda packaging nonsense

Choose a tag to compare

@scottprahl scottprahl released this 05 Aug 21:34

v2.5.3 (8/5/2023)

  • conda-forge fails because test files are not included

v2.5.0 (8/4/2023)

  • fix scattering function for very small spheres

v2.4.0 (6/10/2023)

  • add mie_phase_matrix() to calculate scattering (Mueller) matrix