Materials¶
materials
¶
Optical material models.
Convention (used everywhere in lightsmith): time dependence exp(-iomegat), so absorbing materials have Im(eps) > 0 and Im(n) > 0. Backends that use the opposite convention convert at their boundary.
Measured data come from the refractiveindex.info database (CC0 1.0,
https://github.com/polyanskiy/refractiveindex.info-database). A small, cited
subset ships with the package ({"kind": "library", "name": "Au",
"dataset": "Johnson-Christy"}, see :func:list_materials); any other entry
can be downloaded with :func:fetch_refractiveindex.
RII_REPOSITORY
module-attribute
¶
RII_RAW_URL
module-attribute
¶
RII_RAW_URL = 'https://raw.githubusercontent.com/polyanskiy/refractiveindex.info-database/{ref}/database/{path}'
RII_PAGE_URL
module-attribute
¶
RII_CITATION
module-attribute
¶
Material
module-attribute
¶
Material = Annotated[Union[ConstantIndex, ConstantPermittivity, Drude, DrudeLorentz, Tabulated, LibraryMaterial], Field(discriminator='kind')]
MaterialRangeError
¶
Bases: ValueError
A wavelength lies outside the range where a material's data are valid.
ConstantIndex
¶
ConstantPermittivity
¶
Bases: _Material
Wavelength-independent complex relative permittivity.
Drude
¶
LorentzPole
¶
DrudeLorentz
¶
Bases: _Material
eps(w) = eps_inf - wp^2/(w^2 + i g w) + sum_j d_j w0_j^2 / (w0_j^2 - w^2 - i G_j w).
The form FDTD needs for auxiliary-differential-equation dispersion.
Fit one to measured data with :func:lightsmith.materials_fit.fit_drude_lorentz.
Tabulated
¶
LibraryMaterial
¶
Bases: _Material
Measured n, k bundled with lightsmith, e.g. {"kind": "library", "name": "Au",
"dataset": "Johnson-Christy"}. Linear interpolation in n and k, no extrapolation.
Names and datasets accept aliases ("gold", "JC") and are stored in canonical form;
an omitted dataset is filled with the material's default so the spec stays
reproducible. See :func:list_materials.
read_refractiveindex_yaml
¶
read_refractiveindex_yaml(path_or_text: str | Path, source: str | None = None) -> Tabulated
Load one refractiveindex.info YAML entry (a file path or its text) as :class:Tabulated.
default_cache_dir
¶
User cache directory for downloaded data (LIGHTSMITH_CACHE_DIR overrides).
fetch_refractiveindex
¶
fetch_refractiveindex(shelf: str, book: str, page: str, *, cache_dir: str | Path | None = None, refresh: bool = False, ref: str = 'main', timeout: float = 30.0) -> Tabulated
Download one refractiveindex.info entry (e.g. "main", "Au", "Olmon-sc") as :class:Tabulated.
Names are those in the refractiveindex.info URL (?shelf=main&book=Au&page=Olmon-sc).
The YAML is cached under :func:default_cache_dir (or cache_dir); later calls
work offline. ref is a branch, tag or commit of the database repository.
Tabulated n/k and formula types 1-9 are supported. The database is CC0; cite the
dataset's own reference (kept in .source) and Polyanskiy, Sci. Data 11, 94 (2024).
list_materials
¶
Bundled datasets (no network needed): one dict per dataset with its name, range and citation.
Each row has material_json, ready to drop into a :class:Simulation.
materials_fit
¶
Fit measured permittivity with a passive Drude-Lorentz model.
FDTD needs a rational permittivity it can integrate with auxiliary
differential equations; measured (tabulated) data are not usable directly.
:func:fit_drude_lorentz turns any material into a :class:DrudeLorentz::
from lightsmith.materials_fit import fit_drude_lorentz, fit_quality
wl = np.linspace(450, 900, 91)
dl = fit_drude_lorentz({"kind": "library", "name": "Au"}, wl)
fit_quality(dl, "Au", wl)["rms_rel_error"] # ~0.01 (JC data)
Every parameter is constrained to be physical: eps_inf >= 1, and plasma
frequency, Drude damping, oscillator strengths, resonances and pole dampings
are all strictly positive, so Im(eps) > 0 at every positive frequency
(passive, hence stable in FDTD). The fit is a bounded nonlinear least-squares
fit (scipy least_squares) of eps in eV, started from non-negative linear
fits and continued pole by pole, so it does not depend on a user guess.
fit_drude_lorentz
¶
fit_drude_lorentz(material, wavelengths_nm, n_poles: int | None = None, *, drude: bool | None = None, weights=None, max_poles: int = DEFAULT_MAX_POLES, tol: float = DEFAULT_TOL, eps_inf_min: float = 1.0, return_info: bool = False)
Fit a passive :class:DrudeLorentz to material over the band spanned by wavelengths_nm.
material is any material object, its JSON dict, or a library name ("Au").
The fit uses wavelengths_nm (vacuum, nm) as samples, densified to at least
64 points uniform in photon energy across [min, max] when fewer are given;
outside the band the model is only constrained to stay physical.
weights (same length as wavelengths_nm) up-weights parts of the band.
The objective weights Re(eps) by 1/|eps| and Im(eps) by 1/(|Im eps| + 0.05 |eps|), so the loss of good metals (which sets plasmon linewidths) is fitted too.
n_poles is the number of Lorentz poles. With None it is chosen
automatically: the smallest number (up to max_poles) for which both
rms_rel_error and rms_imag_error are below tol, or else the best
found (stopping once a pole improves them by < 10 %). drude adds the
free-electron term; None adds it when Re(eps) < 0 somewhere in the band (metals).
Returns the :class:DrudeLorentz; with return_info=True returns
(model, DrudeLorentzFit) carrying the RMS / max errors. See also :func:fit_quality.
fit_quality
¶
Error of model (e.g. a fitted :class:DrudeLorentz) against material at wavelengths_nm.
Returns rms_rel_error and max_rel_error (of |eps_model - eps| / |eps|),
rms_imag_error and max_imag_error (of |Im eps_model - Im eps| / (|Im eps| + 0.05 |eps|),
the loss that sets resonance widths), rms_abs_error and max_abs_error
(of |eps_model - eps|), plus band_nm.