| Badge | Status |
|---|---|
| Python versions | |
| Documentation | |
| Scientific article | |
| Continuous integration | |
| Test coverage | |
| Google Colab | |
| PyPI package | |
| PyPI downloads | |
| Anaconda package | |
| Anaconda downloads | |
| Latest Anaconda release |
PyMieSim is an open-source Python package for fast and flexible Mie scattering simulations. It supports spherical, cylindrical and core--shell particles and provides helper classes for custom sources and detectors. The project targets both quick single-scatterer studies and large parametric experiments.
Try the live web GUI: PyMieSim Parameter Sweep Lab.
- Solvers for spheres, cylinders and core--shell geometries.
- Built-in models for plane wave and Gaussian sources.
- Multiple detector types including photodiodes and coherent modes.
- Simple data analysis with pandas DataFrame outputs.
PyMieSim is available on PyPI and Anaconda. Install it with:
pip install PyMieSim
conda install PyMieSim --channels MartinPdeSThis installs a pre-built wheel when one is available for your operating system, architecture, and Python version. Wheels are the recommended option for using PyMieSim because they include the compiled C++ and Fortran extensions.
Verify the installation with the same Python interpreter that you will use for your simulations:
python -c "import PyMieSim; print(PyMieSim.__version__)"Named optical materials use PyOptik's provenance-preserving
RefractiveIndex.INFO catalog. Initialize its local snapshot once before using
constructors such as SellmeierMaterial("BK7") or
TabulatedMaterial("silver"):
python -m PyOptik setupBuilding from source is intended for development or platforms without a matching wheel. It requires a C++20 compiler, Fortran, CMake, pybind11, and OpenMP; see troubleshooting if the compiled extension cannot be imported.
Create a source, a scatterer, and a Simulation. Physical quantities use
the built-in ureg unit registry, while refractive indices are
dimensionless real or complex values.
from PyMieSim import (
Gaussian,
PolarizationState,
Simulation,
Sphere,
ureg,
)
source = Gaussian(
wavelength=633 * ureg.nanometer,
polarization=PolarizationState(angle=0 * ureg.degree),
optical_power=1e-3 * ureg.watt,
numerical_aperture=0.2,
)
scatterer = Sphere(
diameter=200 * ureg.nanometer,
material=1.5 + 0.01j,
medium=1.0,
)
simulation = Simulation(scatterer=scatterer, source=source)
qsca = simulation.run("Qsca")
print(qsca)This prints a dimensionless scattering efficiency, approximately:
0.2080989068292113 dimensionless
Inspect the measures supported by the configured simulation with:
print(simulation.available_measures)For explicit measure and unit metadata, request a typed result:
result = simulation.run("Qsca", as_result=True)
print(result.measure, result.quantity, result.units)Always attach units to wavelengths, lengths, powers, and angles:
633 * ureg.nanometer
200 * ureg.nanometer
1e-3 * ureg.watt
0 * ureg.degreeRefractive indices are dimensionless. A complex index such as
1.5 + 0.01j represents an absorbing material under PyMieSim's optical
convention. Built-in and tabulated materials have supported wavelength
ranges; use load_material and validate_wavelength when working with
real material data.
Use Experiment when you want to evaluate several wavelengths, particle
sizes, or material parameters. Results retain named dimensions and
coordinates, and can be converted to NumPy or pandas explicitly.
import numpy as np
from PyMieSim import (
Experiment,
GaussianSet,
PolarizationSet,
SphereSet,
ureg,
)
source = GaussianSet(
wavelength=np.linspace(500, 700, 5) * ureg.nanometer,
polarization=PolarizationSet(angles=0 * ureg.degree),
optical_power=1e-3 * ureg.watt,
numerical_aperture=0.2,
)
scatterer = SphereSet(
diameter=np.linspace(100, 500, 9) * ureg.nanometer,
material=1.5,
medium=1.0,
)
experiment = Experiment(scatterer_set=scatterer, source_set=source)
result = experiment.get("Qsca")
values = result.as_numpy()
dataframe = result.as_dataframe()The experiment grid has five wavelength values and nine diameter values, so
values.shape is (5, 9). See the
parameter sweep guide
for multiple measures and plotting.
Add a detector when you need collected or coupled power rather than only a scatterer property:
from PyMieSim import (
Gaussian,
Photodiode,
PolarizationState,
Simulation,
Sphere,
ureg,
)
single_source = Gaussian(
wavelength=633 * ureg.nanometer,
polarization=PolarizationState(angle=0 * ureg.degree),
optical_power=1e-3 * ureg.watt,
numerical_aperture=0.2,
)
single_scatterer = Sphere(
diameter=200 * ureg.nanometer,
material=1.5 + 0.01j,
medium=1.0,
)
detector = Photodiode(
sampling=500,
numerical_aperture=0.2,
phi_offset=0 * ureg.degree,
gamma_offset=0 * ureg.degree,
medium=1.0,
)
simulation = Simulation(
scatterer=single_scatterer,
source=single_source,
detector=detector,
)
coupling = simulation.run("coupling")
print(coupling)coupling requires a detector. Other available detector types include
CoherentMode and IntegratingSphere; see the
detector coupling guide.
- If
import PyMieSimfails, runpython -m pip show PyMieSimand check that it uses the same Python executable as your script. - If a constructor reports a unit error, check that every dimensional input
has units and convert it with
.to(...)when necessary. - If
couplingis unavailable, add a detector and inspectsimulation.available_measures. - For slow or memory-heavy sweeps, print
experiment.array_shapeandexperiment.total_iterationsbefore requesting a result. - On servers or in CI, select a non-interactive Matplotlib backend such as
Aggbefore importing plotting code.
See the online documentation for theory, performance guidance, runnable examples, and advanced near-field and far-field workflows.
Here is the architecture for a standard workflow using PyMieSim:
Clone the repository, select the Python interpreter you want to use, install the development and testing dependencies, and build an editable installation:
git clone https://github.com/MartinPdeS/PyMieSim.git
cd PyMieSim
python -m pip install ".[testing,documentation,dev]"
python -m PyOptik setup --no-progress
make PYTHON=python editablemake editable builds the native extensions in the local build
directory and installs them into the same environment. Always run tests with
that same interpreter:
python -c "import PyMieSim; print(PyMieSim.__version__)"
python -m pytest --config-file=pytest.iniIf the import reports missing native extensions, the build was not completed
for this interpreter. Re-run make editable after checking that CMake,
Fortran, pybind11, and OpenMP are installed. Do not mix build artifacts from
different Python versions or architectures.
The equivalent lower-level workflow is:
python -m pip install --no-build-isolation -Cbuild-dir=build -e .The editable workflow is preferred because it keeps the Python sources and compiled extensions aligned. A released wheel does not require a compiler or the native build toolchain.
After the developer setup, run the unit tests with:
python -m pytest --config-file=pytest.iniIf you use PyMieSim in academic work, please cite:
@article{PoinsinetdeSivry-Houle:23,
author = {Martin Poinsinet de Sivry-Houle and Nicolas Godbout and Caroline Boudoux},
journal = {Opt. Continuum},
title = {PyMieSim: an open-source library for fast and flexible far-field Mie scattering simulations},
volume = {2},
number = {3},
pages = {520--534},
year = {2023},
doi = {10.1364/OPTCON.473102},
}
For questions or contributions, contact martin.poinsinet.de.sivry@gmail.com.


