Releases: scottprahl/miepython
Releases · scottprahl/miepython
Release list
Speed up and improved accuracy of coefficients
Speed up is 18x for near field calculations
Improved accuracy arises from using new stable recursion methods for calculating
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
coefficientsexamples calledmie_coefficients, a name that never
existed, showed the imaginary parts with the wrong sign, and still included the
padding elementan_bnno longer returns; theefficiencies_mxexamples
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.
coreand
rayleighheld the same thirty lines differing only in which efficiencies
they consulted, socore.normalization_factornow takes an
efficiency_sourceandrayleighpasses its own - accept an
rngargument ingenerate_mie_costheta. It drew from the
process-widenumpy.random, which a caller could only control by reseeding
the whole program; passingnumpy.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
mucounts as one angle
and returns a length-one array, except inphase_matrix, which squeezes it
away.docs/01_basics.ipynbdemonstrates the first half deliberately, so
both are now stated in the docstrings and pinned by tests - fix
make readme_images, which had never worked:.PHONYdeclared that name
but the rule below it was writtenreadme:, so the advertised command failed
with "No rule to make target" while an undocumentedmake readmedid the job - drop
syncfrommake help. No such target exists; the one that syncs the
environment isvenv, 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@echolines 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_imagesproduced 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". Fixingsvg.hashsaltand 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/mainrather thanblob/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.pywalked the grid withnp.ndindexand called into
scipy.specialseparately 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+1in one call rather
than making four separate calls that recompute shared orders.xi'_nneeds
h1atn-1,nandn+1, and the order-nvalue 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_basenow takes an explicitinsideflag and arrays of
coordinates, so it no longer re-derives fromd_spherewhich side it is on - make the submodules reachable, each in the way that suits it.
miepython.rayleighneeds only NumPy and is now imported with the package, so
import miepythonis enough to reach it;miepython.vshrequires the
optionalscipyand is imported inside the same guard asfield, staying
absent when scipy is not installed;miepython.monte_carloimports
miepythonitself, so importing it from the package would be circular and it
remains a separateimport miepython.monte_carlo. All three are now described
in the package docstring, andmonte_carlo's own docstring shows the full
workflow and says why it is not imported for you - have
vshreachD_calcthrough._backendinstead of importing
miepythonfor it. The old import was a cycle that worked only because the
call is deferred to run time, and importingvshfrom__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 aTypeError. The four*_arrayvariants went unmentioned
altogether. Signatures written out in prose are now checked against the code - fix two stale references in the notebooks:
mie.mie_S1_S2in
docs/03a_normalization.ipynb, together with the comparison values it quotes,
and a commented-outmie._D_calcindocs/10_basic_tests.ipynb - fix off-by-one in
n_poleforS1_S2and everything built on it
(i_par,i_per,i_unpolarized,phase_matrix,intensities).
n_pole=1returned the quadrupole instead of the dipole; it now matches
the convention already used byefficiencies_mx - raise
ValueErrorfor ann_polebeyond the truncated series instead of
returning zeros or anIndexError - add multipole regression tests (series sum, closed form, per-multipole
optical theorem) and re-executedocs/12_multipoles.ipynb - implement the
e_fieldargument ofefficiencies_mx, which was accepted
and documented but silently ignored. Withn_pole > 0it 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=Truepluse_field=False - make the two backends agree on
gwhenn_pole > 0. The no-JIT backend
returnedNone(which becamenanfor array input) while the JIT
backend returned0. Both now return0.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 cmade the test true for every finite index, socn_dn(0j, x)
raisedZeroDivisionErrorand an infinite index producednan. The
internal coefficients are now zero for a perfect conductor, as intended - drop
fastmathfrom the numba_cn_dn_nbkernel. It implies LLVM's
ninf, which folded thenp.isinfguard toFalseand defeated the
fix above in the JIT backend. This also improves JIT/no-JIT agreement - make the internal-field coefficients
c_nandd_nnumerically stable.
psi_ncame from the three-term upwards recurrence, which is contaminated
by the growingchi_nsolution 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_nnow uses Miller's downwards recurrence seeded above|z|
and normalised against whichever ofpsi_0orpsi_1is 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...
Near field cartesian fix
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
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
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
3.0.2 5/25/2025)
- update version in both
__init__.pyandpyproject.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
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
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
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
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
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