Multilayer Optics Calculator Documentation
Learn how to calculate reflectance, transmittance and absorptance of multilayer thin films using the online transfer matrix method calculator. This documentation covers physical conventions, material models, layer-stack controls, exports, limitations and numerical verification of the calculation engine.
Overview
The Multilayer Optics Calculator computes the reflectance, transmittance, and absorptance of a planar multilayer (thin-film) stack using the Transfer Matrix Method (TMM) — the same formalism used to design anti-reflection coatings, dielectric mirrors, and distributed Bragg reflectors.
You describe a stack of layers between an incident medium and a substrate, assign each layer a material with its own optical dispersion model, then compute R(λ), T(λ), and A(λ) over a wavelength range at a chosen incidence angle and polarization. This page documents both how to operate the app and the physical conventions, assumptions, and numerical behavior behind the numbers it reports — read Physics and conventions and Assumptions and limitations before relying on results for anything beyond a qualitative check.
Calculations run entirely on the backend on a single verified numerical kernel — your browser never does the physics. The public site runs a server-side PHP implementation of that kernel; it was checked to agree with the original Python/NumPy reference kernel to within numerical round-off (see Numerical verification for what "verified" means concretely here).
Quick start
- Add or pick materials. Search the built-in library on the right of the Materials panel — over 3,500 materials sourced from RefractiveIndex.INFO (see References) — and click + Add on a result, or create your own with + New material.
- Build the layer stack. In Layer stack, set the incident medium and substrate, then add single layers or repeating periods (e.g. a Bragg mirror's H/L pairs) with a thickness in nanometers and a material for each.
- Set the spectrum. Choose a wavelength range and point count, an incidence angle, and which polarization result to display. TE and TM are computed together, while Unpolarized is their power average.
- Compute. Click Compute spectrum. The chart updates with R, T, or A — toggle between them, and between TE / TM / Unpolarized, without recomputing.
- Export or iterate. Export the spectrum as CSV or the chart as a PNG, print the results page, or save the whole project as a JSON file to reopen later.
Prefer to start from a working configuration instead of an empty stack? The Examples page has four worked configurations — an idealized quarter-wave AR coating, a real-material Bragg mirror, a silver mirror, and a Fabry-Pérot resonance — each one loads directly into the app with a single click.
Physics and conventions
These conventions apply throughout the app — they determine how to interpret every number it reports.
Wavelength and angle
The wavelength λ entered everywhere in the app is the vacuum (free-space) wavelength, in nanometers; the in-medium wavelength and wavevector are derived from it internally. The incidence angle is measured inside the incident medium, relative to the surface normal, at 0° = normal incidence. Snell's law is enforced as the usual invariant β = n₀sinθ₀ across the whole stack, so a non-unity incident-medium index does not need to be corrected for separately. Input validation restricts the angle to 0° ≤ θ < 90° (exact grazing incidence is excluded).
Complex refractive index and time convention
Every material's optical constants are combined into a single complex refractive index N = n + iκ for use in the transfer matrix. The app assumes harmonic time dependence e−iωt; under that convention, κ > 0 corresponds to a lossy (absorbing) medium and κ = 0 is lossless — this is the same sign convention used consistently by every material model (Constant, Cauchy, Sellmeier, Tabulated).
TE and TM polarization
TE (s-polarization) has its electric field perpendicular to the plane of incidence; TM (p-polarization) has its electric field lying in the plane of incidence. Both are always computed together. The Unpolarized chart toggle is the incoherent average of the two power quantities, not an average of field amplitudes:
Reflectance, transmittance and absorptance
For each polarization, R and T are computed from the stack's overall reflection and transmission amplitudes r, t via R = |r|² and a power-flux-corrected T = (Re(qsub)/Re(qinc)) · |t|², and
See Results and definitions for exactly what T and A represent when the substrate itself absorbs — this is a common source of confusion and worth reading before interpreting A on an absorbing substrate.
Mathematical formulation (for readers who want the actual transfer matrix)
For each layer j with complex index Nj, at Snell invariant β = N₀sinθ₀:
choosing the branch with Im(γj) ≥ 0, and — when γj is (numerically) real, i.e. |Im(γj)| below a small tolerance — Re(γj) ≥ 0, so that the field always decays (never grows) with propagation depth in an absorbing medium, as implemented in compute_tmm_fast.py. The polarization-dependent optical admittance is
and each finite layer's phase thickness, with vacuum wavenumber k₀ = 2π/λ and physical thickness dj, is
Each finite layer contributes a 2×2 characteristic (Abelès) matrix relating the tangential field components at its two boundaries:
The stack's total matrix is the ordered product M = M₁M₂⋯MN over the finite layers (incident medium and substrate are not included in the product, but enter via q₀ and qsub at the boundary conditions); r and t are then obtained from M together with q₀ and qsub in the standard way, and R, T, A follow as in Reflectance, transmittance, absorptance above. This is the same Abelès-matrix formalism described in, e.g., Byrnes (arXiv:1603.02720) and Macleod — see References and data sources.
Assumptions and limitations
The Transfer Matrix Method, as implemented here, is exact within a specific physical model. The current calculator assumes:
- Flat, parallel interfaces — no surface roughness, waviness, or interface grading.
- Homogeneous layers — each layer's index is a single complex value per wavelength, uniform across the layer (no in-plane variation, no depth-graded index).
- Isotropic materials — no birefringence or other optical anisotropy; a layer cannot have different indices along different axes.
- Coherent, monochromatic plane-wave illumination — full interference between all internal reflections is included in every finite layer, at every wavelength independently.
- No diffuse scattering — only specular reflection and transmission are modeled.
- Semi-infinite incident medium and substrate — neither has a back surface; nothing reflects back from "behind" the substrate or "in front of" the source.
- No optical nonlinearity — the refractive index does not depend on field intensity.
Layer stack
The stack is read top-to-bottom as light travels through it: the incident medium is where the light originates (usually air), followed by any number of finite-thickness layers, and finally the substrate — a semi-infinite medium the light is transmitted into. Both media are non-absorbing by default (e.g. air, n=1) but can use any material model (see the incident-medium caveat under Assumptions and limitations).
Single layers vs. periods
A single layer has one thickness and one material. A period groups several layers together and repeats the whole group a given number of times — this is the natural way to build a distributed Bragg reflector or any other periodic stack without adding each pair of layers by hand. The period card shows the expansion, e.g. "2 layers × 6 = 12", so you can confirm the total layer count before computing.
Use the ↑ / ↓ controls on a layer or period card to reorder it within the stack, and ✕ to remove it. Each layer's thickness is entered in nanometers and its material is chosen from a dropdown populated by whatever is currently listed under In this simulation in the Materials panel.
Stack visualization
The panel to the right of the results chart renders the stack to scale: each layer's height is proportional to its thickness, colored to match its material's swatch, with a light bulb marking the incident side and hatched caps marking the semi-infinite incident/substrate media. Renaming a layer or changing its thickness or material updates this panel immediately. This is a schematic aid only — it plays no role in the calculation.
Materials and optical data
The Materials panel has two columns: In this simulation — the materials actually available to assign to layers — and the built-in library, a searchable catalog of reference materials you can add from with a single click. Materials in the simulation can be edited (✎), duplicated (⧉ — the copy is automatically renamed with a "- copy" suffix so it never collides with an existing name), or removed (✕).
If you edit a material and save it under a name that already matches a different material in the simulation, you'll be asked to confirm before it overwrites that other material — every layer that referenced either material ends up pointing at the single, merged result. Use Save as copy instead when you want to keep both versions independent. Editing a material that's already assigned to more than one layer shows a notice that changes will affect every layer using it.
Built-in library materials are read-only. Opening the editor (✎) on a material added from the built-in library shows its wavelength range, point count, n and κ range, the n(λ)/κ(λ) preview charts, dataset/author, sample type, reference, and material name — all for inspection only, none of it editable. Only the display color can be changed. Save as copy is still available but produces another equally read-only duplicate under a new name (useful for assigning the same underlying data two different display colors), not an independently editable material — there is currently no way to turn a built-in material's data into a starting point for your own edits from inside the app.
Dispersion models
Constant n, κ
Wavelength-independent index. N = n + iκ (see Physics and conventions for the time-convention sign of κ).
Cauchy dispersion
n(λ) = A + B/λ² + C/λ⁴ + D/λ⁶
Good for normal-dispersion transparent materials (most glasses and polymers) away from absorption bands. κ can be set to zero, a constant, or sourced from tabulated data. λ is evaluated in whichever Wavelength unit (nm or µm) is selected for that material — the coefficients must be consistent with that unit.
Sellmeier dispersion
n²(λ) = 1 + Σᵢ Bᵢ·λ² / (λ² − Cᵢ)
The standard form for optical glass and crystal data sheets; add as many (Bᵢ, Cᵢ) term pairs as the reference source provides.
Tabulated n, κ
Import measured or literature n/κ data directly (e.g. a CSV export from RefractiveIndex.INFO). Values between data points are obtained by linear interpolation (not a spline or PCHIP fit).
Every model form includes a live preview of n(λ) and κ(λ) as you type or import data, so you can sanity-check a material before assigning it to a layer.
Wavelength range
Every tabulated (or imported) material has a valid wavelength range, shown once imported. Calculations outside that range are always blocked — the request fails with an explicit error rather than silently substituting or extrapolating a value. There is no way to override this from the app: narrow the spectrum to fit within the material's data range, or choose a material whose range already covers what you need.
If an uploaded file provides no valid third (κ) column for a row, that row is rejected outright rather than defaulted to κ = 0 — check the column mapping (wavelength / n / κ) if an upload fails or looks wrong. Two different literature records for what is nominally "the same" material (e.g. two different SiO₂ datasets) can disagree meaningfully, especially outside the visible range — always check which specific dataset and wavelength range a library entry actually covers.
Data handling and privacy
Uploaded files are stored temporarily for the current session and automatically deleted within 24 hours.
Specifically: an uploaded n/κ file is saved server-side under a randomly generated identifier that is bound to an anonymous, opaque session cookie issued to your browser — only that same session can read, list, or compute with the file; it is never listed publicly or accessible to a different session. It is subject to a 5 MB size limit, and both the file and its association with your session expire and become inaccessible 24 hours after upload, regardless of whether you're still using the app; expired files are also actively deleted from server storage the next time any upload/listing request is handled. There is currently no user-facing button to delete a file before that 24-hour window elapses. The application does not add its own logging of computation inputs, spectra, or results beyond the web server's standard access log (request method, path, and status — not file contents). If you're working with sensitive or proprietary n/κ data, keep this in mind, or use the built-in library / manually entered coefficients (Constant, Cauchy, Sellmeier) instead of uploading a file.
Spectrum settings
| Setting | Description |
|---|---|
| Wavelength start / stop | Range of the computed spectrum, in nanometers (each bounded to 0–107 nm by input validation). |
| Points | Number of wavelength samples across that range (2 to 20,000). |
| Incidence angle | Angle of incidence in degrees, measured in the incident medium from the surface normal (0° ≤ θ < 90°). |
| Polarization | TE and TM are always computed together; the chart's Polarization toggle (TE / TM / Unpolarized) switches which is displayed. |
A stack may have up to 200 layers (including the incident medium and substrate). Click Compute spectrum to run the calculation, which is performed server-side and returned to your browser for plotting (see Numerical verification for how the calculation kernel is checked).
Results and definitions
The Results panel plots the computed spectrum. Use the Reflectance / Transmittance / Absorptance toggle to switch quantity, and TE / TM / Unpolarized to switch polarization — both are instant, no recomputation needed. Click and drag on the chart to zoom into a wavelength range; a Reset zoom button appears once you've zoomed in. As you zoom in, the x-axis tick labels gain decimal precision to match the narrower range — matching the y-axis, which already behaves this way — so a deep zoom resolves fractions of a nanometre instead of rounding to whole numbers, and resetting the zoom returns the labels to whole numbers. Moving the cursor over the plot shows a dashed crosshair and, in the top-right of the plot area, a live readout of the wavelength and the currently plotted quantity at that point; the readout's precision also adapts to the zoom level (enough decimals to resolve one on-screen pixel). The crosshair and readout are on-screen aids only — they are never included in an exported PNG or in the PDF report.
What T and A actually mean for an absorbing substrate
Transmittance T is the optical power flux crossing the final interface and entering the semi-infinite substrate. If the substrate is absorbing, that power may subsequently be absorbed as it propagates deeper into the substrate — but the calculator has no "deeper into the substrate" to compute, since the substrate is modeled as semi-infinite. That power is reported as transmitted, full stop, regardless of what would eventually happen to it inside a real, finite piece of that substrate material.
Consequently, A = 1 − R − T represents absorption within the finite layers of the stack only — it is not, and cannot be interpreted as, the total eventual absorption in a real absorbing substrate of finite thickness. If you need the latter, you would need to model the substrate as an additional finite layer (with its own thickness) followed by a different, non-absorbing terminating medium, and interpret the results accordingly.
Layer-resolved absorptance is not currently calculated — the app reports a single whole-stack A per polarization, not a breakdown of how much is absorbed in each individual layer.
Appearance preview
The Appearance preview renders what the stack would perceptually look like under specular, idealized viewing conditions, at 1° steps from 0° to 85° incidence, interpolated between those precomputed angles as you drag the angle slider or play the rotation animation — the underlying spectra are computed once per generation, not per frame.
Color pipeline
Each angle's reflectance or transmittance spectrum Q(λ) is converted to a color as:
using CIE Standard Illuminant D65 and the CIE 1931 2° standard observer color matching functions (trapezoidal numerical integration), followed by the standard D65-referenced XYZ→linear-sRGB matrix and IEC 61966-2-1 gamma encoding. The color computation always independently covers the full, standard 380–780 nm visible range — it does not depend on, and is not narrowed by, whatever wavelength range is configured for the main spectrum chart. If any material in the stack does not have valid data across the full 380–780 nm range, the preview is blocked (the request fails, the same way an out-of-range main-spectrum computation does) rather than silently computing a color from a partial range; choose a material with full visible-range coverage to proceed.
Gamut
The computed sRGB value itself is not clamped — the true chromaticity is preserved through the calculation. However, an sRGB display physically cannot reproduce a color outside its gamut: when the color is rendered on screen as a swatch, it is clipped to the displayable [0,1] range at that final step. In practice this means a highly saturated spectral color (e.g. from narrow-band interference) may be shown slightly less saturated than the true computed value. The unclipped CIE XYZ and linear-sRGB values are retained internally, while the displayed swatch is clipped to the reproducible sRGB gamut. The final appearance also depends on monitor calibration and viewing conditions — treat the swatch as indicative, not a colorimetric reference.
Angle sampling
The angle step is 1° (0° to 85°), matching the backend's finest supported resolution. Even a structure with a narrow spectral resonance is unlikely to shift color meaningfully within a single 1° step, but the displayed color between sampled angles is still a smooth interpolation, not an independent recomputation. Treat rapid color changes with angle as a signal to check the underlying numeric spectrum at nearby angles individually, rather than trusting the interpolated animation.
The accompanying ray diagram shows the light source and eye on a line through the sample that tilts with the incidence angle — collinear through the sample in Transmission mode, mirror-symmetric in Reflection mode; it is a schematic aid and does not affect the calculation.
Export and reports
- Export CSV — the full per-wavelength table (R, T, A for both TE and TM) for the most recently computed spectrum.
- Export PNG — a high-resolution (2×) raster image of the chart exactly as currently displayed, including whatever quantity/polarization toggle is active.
- Generate PDF report (as of 1.8) — assembles a structured, one-click PDF: an optional title you're prompted for when you click the button (leave it blank for no title), the currently displayed chart (exactly as shown — same quantity/polarization toggle and zoom as Export PNG), the incidence angle, wavelength range and point count the result was actually computed with, a table of the full layer stack (incident medium, every finite layer with its thickness, periods expanded into individual rows, and the substrate) with each layer's material and where its optical data came from (e.g.
RefractiveIndex.INFO — book (page)for a built-in library material, orUser-defined (...)for a constant/Cauchy/Sellmeier material you defined yourself), and a footer with attribution and the generation date (no time). A table row is never split across a page break — if the stack is long enough to need a second page, the whole row moves down together with the repeated table header.
Requires a computed result — if you click Generate PDF report before clicking Compute spectrum, you'll be asked to compute first. For a complete, reproducible record you can re-load and keep editing, use Save project (see below) instead or alongside the PDF report — the report is a human-readable snapshot, not a re-loadable project file.
Save and load projects
Save project downloads a JSON file containing the wavelength range and point count, incidence angle, every material definition (including its swatch color), the full layer stack (every layer's material, thickness, and name), and the currently displayed result view (which of Reflectance/Transmittance/Absorptance, and which polarizations, are shown on the chart). Load project reads that file back and restores the app to exactly that state, including any custom materials you'd defined. It does not save the computed spectrum itself or the chart's zoom level — click Compute spectrum again after loading.
A project file saved by an earlier version of the app may still contain an extrapolation setting from before that feature was removed (see Version history) — loading such a file is safe, but that setting is ignored: extrapolation can no longer be enabled from this app, regardless of what an older project file says.
Project files are downloaded directly to your machine — there is no server-side storage of projects (unlike uploaded material data files, see Materials and optical data). A project file is the only way to persist or share a configuration, so keep it if you want to come back to a particular design later.
Numerical verification
The physics kernel used by every calculation path (spectrum, appearance preview, and export) is covered by an automated regression test suite. Specifically, it is checked against:
- ✓Fresnel reflectance at a single non-absorbing air–glass interface (n = 1.0 → 1.5) at normal incidence, against the closed-form R = ((n₁−n₂)/(n₁+n₂))² = 0.04, and R + T = 1, both to within 10⁻¹².
- ✓Energy conservation (R + T = 1) for a lossless multilayer stack (SiO₂/TiO₂/SiO₂ on glass) at 0°, 30°, 60°, and 85° incidence, to within 10⁻¹⁰.
- ✓A quarter-wave antireflection coating (film index nf = √(n₀·ns), thickness λ₀/4nf) reducing reflectance to zero at its design wavelength, compared against the ≈14.8% reflectance of the bare interface without the coating. Test parameters: n₀ = 1.0 (incident), ns = 2.25 (substrate), nf = √(1.0·2.25) = 1.5 (film), λ₀ = 550 nm, thickness = λ₀/(4·nf) ≈ 91.67 nm, 0° incidence.
- ✓Positive absorption (A > 0) and full energy balance (R + T + A = 1, to within 10⁻¹²) for a stack containing an absorbing layer.
- ✓Agreement between the production server-side (PHP) kernel and the reference Python/NumPy kernel across a suite of stacks — including a five-layer absorbing stack with a lossy metal layer at 0°, 25°, 55°, and 80° incidence — with a maximum absolute difference on the order of 10⁻¹⁵ on every reported quantity. (The reference Python kernel is itself cross-checked between its plain-NumPy and optionally JIT-compiled code paths to the same tolerance.)
This does not prove correctness for every conceivable stack, but it anchors the kernel against known closed-form results and cross-validates the independent implementations against each other — "verified kernel" in this documentation always refers specifically to these checks.
Numerical behavior to be aware of
- A = 1 − R − T has no floor applied. A lossless stack can display a tiny negative absorption (on the order of 10⁻¹² to 10⁻¹⁰, i.e. floating-point round-off) instead of exactly zero — this is not clamped or zeroed for presentation.
- If the Sellmeier expression produces a pole, a non-finite value, or n²≤0, the calculation is stopped. The selected wavelength is outside the valid domain of the model or the coefficient units may be incorrect. The app does not floor n² at zero or otherwise fabricate a value — keep your wavelength range away from a material's Cᵢ values, and check that the coefficient units match the selected Wavelength unit.
- Incidence angle is restricted to θ < 90° by input validation; there is no special handling as θ approaches that bound beyond ordinary floating-point behavior.
- Limits: up to 200 layers per stack (incident and substrate included), up to 20,000 wavelength points per spectrum request.
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
| "Requested spectrum range exceeds material data range" error | A tabulated material's valid wavelength range is narrower than your configured spectrum. Narrow the spectrum to fit within the material's data range, or use a material whose range already covers what you need — there is no extrapolation override. |
| Chart is empty | Click Compute spectrum first — toggling quantity/polarization afterwards doesn't require recomputation, but nothing is plotted until a first computation completes. |
| Compute spectrum fails with a network / "backend unreachable" error | The compute request couldn't reach the backend API. Retry in a moment; if it persists the server may be temporarily unavailable. |
| Appearance preview is blocked with an "outside data range" error | A material in the stack doesn't have valid data across the full 380–780 nm visible range, which the appearance preview always uses regardless of the main chart's configured range. Use a material with full visible-range coverage — there is no extrapolation override. |
| A material upload is rejected or looks wrong | Check that the wavelength / n / κ column indices match the file, and that the file actually contains a valid third (κ) column for every row you expect to use. |
| Saving a material prompts "already exists — overwrite?" | Another material in the simulation already has that name. Confirm to merge the two (every layer referencing either now points at the result), or use Save as copy to keep both. |
References and data sources
Method
- S. J. Byrnes, "Multilayer optical calculations," arXiv:1603.02720 (2016).
- H. A. Macleod, Thin-Film Optical Filters, 4th ed., CRC Press (2010).
- M. Born and E. Wolf, Principles of Optics, 7th ed., Cambridge University Press (1999).
Colorimetry (Appearance preview)
- CIE 15:2004, Colorimetry, 3rd edition, CIE Central Bureau, Vienna.
- ISO/CIE 11664-1 (CIE S 014-1), Colorimetry — Part 1: CIE standard colorimetric observers (defines the CIE 1931 2° standard observer).
- ISO/CIE 11664-2 (CIE S 014-2), Colorimetry — Part 2: CIE standard illuminants (defines D65).
Optical constants database
- M. N. Polyanskiy, "Refractive index database," https://refractiveindex.info. Accessed on 2026-07-17.
- M. N. Polyanskiy, "Refractiveindex.info database of optical constants," Scientific Data 11, 94 (2024).
Built-in material library
The built-in library contains 3,542 materials imported from the RefractiveIndex.INFO database (see citation above), spanning all of its catalog shelves — MAIN (simple inorganic materials), ORGANIC, GLASS, OTHER, manufacturer SPEC SHEETS, 3D-printing materials, and popular optical glasses. Each entry's original dispersion formula was evaluated, or its tabulated data parsed, once and offline into a plain wavelength-vs-(n,κ) table; every one of the database's nine dispersion-formula types was independently checked against RefractiveIndex.INFO's own reference implementation before import. From this point on, a library material is handled by the calculation engine exactly like an uploaded tabulated file (see Materials and optical data) — the same linear interpolation, and the same hard block on any calculation outside its valid range. Unlike an uploaded file, a library material's data and metadata cannot be edited from the app — see Materials and optical data for what remains adjustable (only the display color).
34 of the source database's 3,576 catalog pages (about 1%) could not be imported and are not in the library: a few had no usable optical (n, κ) data at all, a few had n and κ data covering non-overlapping wavelength ranges, and a small number (including one genuine negative-index metamaterial, outside the sign convention this app's calculation engine is verified for) had tabulated refractive-index values that were zero or negative and could not be trusted as real data. No entry in the library was ever floored, clamped, or otherwise patched to hide invalid values — an affected page was left out entirely rather than shown with silently altered numbers. Search the library by material name or chemical formula (a case-insensitive match against the compound/book-level name only — not the author, dataset year, or shelf); each result lists its valid wavelength range, and the full reference/comments text is shown once added to your simulation.
Version history
This is version 1.8. The backend reports this version string at GET /api/health. This page documents the application's behavior as verified against its source and automated test suite at the time of writing; if something here stops matching what you observe in the app, the app has changed since and this page is due for an update.
| 1.8 | Replaced Print results (a plain browser print dialog) with Generate PDF report — a structured, one-click PDF with an optional title, the currently displayed chart, the incidence angle/wavelength range/point count, a table of the full layer stack with each layer's material and data source, and a generated-on date. See Export and reports for details. Later refinements within 1.8: the chart's x-axis tick labels now gain decimal precision as you zoom in (matching the y-axis), and moving the cursor over the plot shows a crosshair with a live wavelength / value readout whose precision adapts to the zoom level — both are on-screen aids and never appear in an exported PNG or the PDF report. |
|---|---|
| 1.7 | The incident-medium k notice (see 1.4/1.5) now appears as soon as an absorbing material is assigned as the incident medium — you no longer need to click Compute spectrum first to see it. Added the Examples page: four worked, individually verified configurations that load directly into the app with one click. |
| 1.6 | Built-in library materials are now read-only in the editor — only the display color can be changed; everything else (name, definition, upload fields, wavelength range, points, n/κ range, charts, dataset/author, sample type, reference) is shown for inspection only. The editor's wavelength-range/points/n-range/κ-range stats and "first rows" preview table, previously static mockup placeholder text for every material regardless of what was actually loaded, now show real data for both uploaded and built-in materials. Interpolation is now always linear for every tabulated material — the previously offered "PCHIP" option never did anything and has been removed. The "Allow extrapolation" checkbox has been removed entirely; it never actually worked from the UI in any released version (a DOM/selector mismatch meant it was never wired to anything), and calculations outside a material's valid range are now unconditionally blocked with no override, matching what the checkbox was supposed to do but never did. Built-in-material captions that previously read "Tabulated n,k" now read "RefractiveIndex.INFO" throughout, since that phrasing was misleading for library data (it isn't something you tabulated or uploaded). |
| 1.5 | The incident-medium k notice (see 1.4) now appears for any nonzero k, however small — previously a tolerance of 1e-6 silently ignored genuine but tiny absorption in some built-in library materials (e.g. N-BK7 in the visible range, k ≈ 1e-8), showing no notice even though that k was in fact being dropped. |
| 1.4 | An absorbing incident medium (k > 0) is no longer rejected — its k is now silently treated as 0 (n is left untouched) and a notice appears under "Compute spectrum" whenever this happens, instead of the request failing with an error. |
| 1.3 | An absorbing incident medium (k > 0) was rejected with a clear error (422) instead of silently producing physically meaningless results, including negative transmittance — see the warning under Assumptions and limitations. (Superseded by 1.4: now clamped instead of rejected.) |
| 1.2 | The stack visualization's incident-medium and substrate end caps now tint their hatched pattern from that medium's own material color, matching the material swatch shown everywhere else (previously they were a fixed neutral gray regardless of the medium's color). Save project now also includes the displayed result view (quantity + polarizations). |
| 1.1 | Added the built-in material library: 3,542 searchable, directly computable materials imported from RefractiveIndex.INFO (see References and data sources). Fixed incorrect default Sellmeier coefficients in the "New material" form. |
| 1.0 | Initial version. |
Multilayer Optics Calculator — back to the app.