Repository navigation
Releases: multilayerapp/PyStratify
Release list
PyStratify 0.11.0
Thin-film ellipsometry: dispersion models, measurement files and fits. Two new modules; nothing already computed changes.
pystratify.dispersion: parametric dielectric functions, wavelengths in nm and oscillator parameters in eV, composed with+: Cauchy (with an Urbach tail), Sellmeier, poles, Lorentz, Gaussian, Tauc-Lorentz, Cody-Lorentz (with an Urbach tail; ε₁ by a numerical Kramers–Kronig transform), Drude in energy and resistivity form, Bruggeman (alsobruggeman_epsilonon bare permittivities) and Maxwell Garnett mixtures, tables (Table.from_refractiveindexreads a refractiveindex.info page), andkramers_kronig_real.pystratify.ellipsometry: Ψ, Δ and N, C, S of a film stack in the instrument (Nebraska) convention that Woollam, SENTECH and pyElli report (Δ = 180° − Δ ofplanar.ellips); incoherent backside reflection from a finite substrate and the depolarisation it causes; readers for J.A. Woollam (CompleteEASE, WVASE) and SENTECH SpectraRay files;fit, a bounded least-squares fit reporting the instruments' MSE, 90 % confidence limits and parameter correlations, with a grid search for the start; andfit_nk, point-by-point optical constants.- Checked against pyElli (
benchmarks/DISPERSION_CODES.md,benchmarks/ELLIPSOMETRY_CODES.md): every dispersion model to 5e-15; Ψ, Δ of four dispersive stacks to 4e-12° with both of its solvers; both file readers exactly; and a fit of a real TiO₂ measurement where the parameters agree with pyElli + lmfit to 4e-7 and the standard errors and MSE to all printed digits. (pyElli's two Drude models return ε₁ with the wrong sign; its Cody-Lorentz ε₁ is a coarse 1000-point sum.) examples/ellipsometry_fit.pyfits two real measurements published with pyElli: a Woollam RC2 wafer (native oxide 2.25 nm) and a SENTECH TiO₂ film.
The oscillator forms are multilayer.app's, parameter for parameter; the site's API now evaluates its oscillator models with this module.
PyStratify 0.10.6
Documentation and packaging; no change to any computed number.
- The README is a front page: figures, a quick start for every geometry and source, and the comparison with sixteen independent references. Its former detail moved to CHANGELOG.md, docs/GUIDE.md, docs/NUMERICS.md, benchmarks/README.md and tests/README.md.
- PyPI now lists authors, keywords, classifiers and links to the site, the guide, the issues and the DOI.
- The test that the committed docs manifest is current compares check values to a tolerance (it failed on Linux on a 2e-16 rounding residual).
PyStratify 0.10.5
Cylinder emitters at a mode's cutoff. Next to a light line the reflected spectral density of a cylinder source lost digits (its m = ±1 TE/TM-coupled terms carry 1/q factors that cancel), so a guided mode just above cutoff made the quadrature chase noise until its evaluation budget ran out — an error instead of a result; with scipy 1.18 even a plain fibre did so at tolerance 1e-7. Within 1e-3 of the host's and the source medium's light lines the real part now comes from the exact power balance at that axial wavenumber (escape + absorbed − direct), which equals the reflected density to ~1e-14 wherever that is accurate. Over 60 random lossless cylinders the budget errors fall from 12 to 2; converged results are unchanged.
PyStratify 0.10.4
Every guided mode of a cylinder. A point source beside or inside a lossless cylinder could lose the power it couples into some of the cylinder's guided modes: the mode search dropped real roots (Brent's minimiser stalled just above a fixed |det| bar) while the solve reported convergence. Over 60 random lossless cylinders the totals moved by more than 1e-3 in 28 of 97 comparable cases (up to 9.5%), and 11 cases that raised an error now solve. For a step-index fibre the modes found now equal those of its closed-form dispersion relation.
Found by a new 3D FDTD benchmark against MIT Meep (benchmarks/fdtd_meep.py → FDTD_MEEP.md): Meep converges toward PyStratify to 0.74% at 60 px/µm for every orientation, through a mode cutoff.
Also: near_field is exact at a sphere's centre (Bohren & Huffman's d₁, m c₁), and sphere near fields are benchmarked against scattnlay (≤ 8.2e-13) and treams (≤ 6.6e-14) in benchmarks/mie_codes.py.
PyStratify 0.10.3
A point source in an exterior half-space of a film stack (above or below it) lost the power it couples into the stack's guided modes, so total rates near lossless guides were low (by 20%, 30 nm above 200 nm of TiO2 on glass) while the solve reported convergence. Lossy stacks and sources inside a finite layer were unaffected.
Found by the new public benchmark benchmarks/emitter_references.py against smuthi; see benchmarks/EMITTER_REFERENCES.md.
PyStratify 0.10.2
The first release on PyPI (pip install pystratify) and the first archived on Zenodo.
No change to the physics or numerics since 0.10.1. Added:
docs/API.md: the draft 1.0 API contract. Every exported name is frozen, legacy or internal, andtests/test_api_contract.pykeeps the list and__all__in step.- A release workflow: a published GitHub release uploads to PyPI by Trusted Publishing.
- README: the headline now covers films, cylinders and spheres.
PyStratify 0.8.0
PyStratify 0.8.0 evaluates every quantity that sums the high-order tail of the multipole series at a source through the normalized formulation. Each term is an explicit factor that can only underflow, multiplied by quantities that neither overflow nor underflow. The results are accurate to about 1e-14 at any distance from metal shells and lossless interfaces, with up to tens of thousands of multipoles.
What's new
Normalized formulation by default
decay_ratesandemission_ratestake their total and radiative rates from the normalized formulation (route="auto").route="log"keeps the logarithmic recursion of 0.7 for cross-checks. Within about 1 nm of a lossless interface it loses ~1e-8 in the total rate; the normalized route does not.- Results carry a
routefield. On the logarithmic route,converged=Falseflags a failed energy balance. - Absorption per layer is computed in closed form (Lommel integrals, O(L)).
Frequency shift
- The Lamb shift is available as
DecayRates.shift,EmissionRates.shiftandNormalizedRates.shift. - It needs the reactive high-order tail even next to lossless surfaces (10⁴ orders where the total rate needs ten), so the truncation is automatic and tests the complex series.
New near-field quantities, normalized from the start
green_dyadic: the two-point Green's dyadic between any two points in lossless shells, in the same shell or across shells. It gives energy transfer, coherent dipole–dipole coupling and collective decay, with reciprocity and envelope truncation.spectral_density: J(ω) and the shift over wavelength, for Wigner–Weisskopf dynamics and pseudomode strong coupling.shell_average: emitters spread through a shell, with volume- and orientation-averaged rates and quantum yield, and a cutoff next to absorbing layers.casimir_polder: the Casimir–Polder potential at any distance, from the normalized series at imaginary frequency.normalized_terms: the per-order Green's forms and radiated amplitudes for many emitter radii at once.
Interface responses in the normalized maps
- 2D sheets (
Sheet,graphene_conductivity) enter as additive terms of the Möbius maps, with cancellation-free mismatches and the surface absorption as a flux jump. - Feibelman d-parameters,
Feibelman(d_perp, d_par, metal="inner"|"outer"), are new. They reproduce the mesoscopic Mie theory of Gonçalves et al., Nat. Commun. 11, 366 (2020), to 1e-15. - Chiral (Pasteur) layers use 2×2 maps in the (TM, TE) basis, with a closed-form contrast matrix, so the small TE parts keep full precision.
Sources
- Magnetic quadrupoles are obtained by duality.
- General p + m sources are routed in the TE/TM basis with real covariance weights.
References
references.layered_green_formsandreferences.layered_green_sumsgive mpmath transfer-matrix references for the per-order forms, the shift and sheets.references.classical_decay_rates(..., with_shift=True)gives the unnormalized shift.
Known limitations
These are documented in the README and in the docstrings of decay_rates and emission_rates.
- Absorption next to metal. Absorption is still computed from the amplitudes of the logarithmic solver. Its accuracy is ~1e-13 at 1 nm, ~1e-12 at 0.1 nm and ~1e-11 at 0.05 nm from gold. Total rate, radiative rate and shift are not affected.
- Quadrupoles deep in a subwavelength lossless core. They are accurate to ~1e-13.
- Chiral layers. Sources inside a chiral layer take the logarithmic route. Absorption in absorbing chiral structures uses O(L²) quadrature, which is slow within ~0.5 nm.
- d-parameters. The conditions are linearized from the metal side: exact for d∥ = 0, and second-order differences for d⊥d∥ ≠ 0.
Tests
472 tests (one skipped locally) cover:
- the new quantities against mpmath transfer matrices (shift, two-point dyadic, sheets, d-parameters, chiral layers, Casimir–Polder);
- the Gonçalves Mie theory;
- energy balance with sheets, d-parameters and chiral layers;
- reciprocity of the two-point dyadic;
- the agreement of the two routes.
CI runs on Python 3.10 and 3.12.
Compatibility
decay_ratesandemission_ratesreturn the same fields as in 0.7, plusshiftandroute.- Their numbers agree with 0.7.1 to ~1e-14, except within about a nanometre of lossless interfaces, where 0.8.0 is the more accurate.
- For plane-wave scattering, near fields and far fields, nothing changes.
PyStratify 0.7.1
The normalized formulation through real zeros of ψ_l
normalized_decay_rates (the formulation of the accompanying paper) built ψ_l ξ_l and the normalized j̄_l as products of consecutive ratios. At a real zero of ψ_{l-1}, which occurs for lossless shells and at the emitter, each of these products is a 0·∞ form whose small and large factors were rounded independently. Within a relative distance δ of such a zero, about log10(1/δ) digits were lost. A round parameter choice can hit a zero exactly: an emitter at r = 200 nm in water at 532 nm has k r = π, and its radiative rate came out 42 % too small. decay_rates, emission_rates and the plane-wave routines were not affected.
Fix (normalized.auxiliary)
- ξ'/ξ is computed by its own upward recurrence, and P_l = ψ_l ξ_l = i/(B_l − A_l) is formed one order at a time from the Wronskian. No product runs through a zero, the cancellation of l/z − A_{l−1} for l ≫ |z| is gone, and for real z the small real part ψ_l² is a ratio of positive quantities (relative error 1e-15 instead of up to 4e-9).
- The ratios of j̄ reuse the sums A_l + l/z that are rounded in the recurrence for A, and ψ_0 = s_1 ψ_1 is used near a zero of sin z. At a zero, j̄_l and P_l therefore carry the same rounding, and P/j̄ stays exact.
- For strongly amplifying media (Im z ≤ −1), where the forward recurrence of ξ'/ξ is unstable and ψ has no zero within distance 1, P is still obtained from a cancellation-free product recurrence.
Accuracy against extended-precision transfer matrices
| 0.7.0 | 0.7.1 | |
|---|---|---|
| emitters and interfaces at or near real zeros | up to O(1) | ≤ 6e-14 |
| 20 benchmark cases (total / radiative), up to 22 620 multipoles | 8.0e-13 / 6.2e-13 | 1.5e-14 / 1.2e-14 |
| emitters 0.05–0.1 nm from gold | 7.7e-11 | 1.5e-14 |
758 random multilayers agree with 0.7.0 to a median of 4e-15. In the five cases where the two versions differed by more than 1e-11, the extended-precision reference sides with 0.7.1.
Tests: 22 new tests cover real zeros, the small real part of ψξ, gain media and rates at zeros; 17 of them fail on 0.7.0. The full suite gives 320 passed.