Source code for optmat.solid.models.registry
# SPDX-FileCopyrightText: 2026 John C. Travers and contributors
#
# SPDX-License-Identifier: MIT
"""Every model of a solid's dielectric function, and the recommended one.
Models come from the fits (:mod:`optmat.solid.models.fitted`), the published
formulas of the source records (:mod:`optmat.solid.models.formulas`) and the stitched
tables of curated optical constants (:mod:`optmat.solid.models.tabulated`). The
recommended model of each material is chosen, with its reason, in
``data/solid/defaults.toml``.
"""
import functools
from collections.abc import Callable, Mapping
from typing import Final
from optmat.exceptions import OptmatError
from optmat.materials import as_material
from optmat.solid.models._defaults import DEFAULTS_FILE
from optmat.solid.models._defaults import defaults as _defaults
from optmat.solid.models.base import Model
from optmat.solid.models.fitted import fitted_models
from optmat.solid.models.formulas import published_model, published_models
from optmat.solid.models.tabulated import tabulated_models
__all__ = ["DEFAULTS_FILE", "default_model", "default_reason", "model", "models"]
_REGISTRIES: Final[dict[str, Callable[[], Mapping[str, Model]]]] = {
"fit": fitted_models,
"table": tabulated_models,
}
"""The registry that holds each prefix of a name; any other name is a published
formula's (``<source>/<formula>``)."""
@functools.cache
def _all_models() -> dict[str, Model]:
"""Return every model by name.
Returns
-------
dict of str to Model
The fitted, published and tabulated models.
"""
return {**fitted_models(), **published_models(), **tabulated_models()}
[docs]
def models(material: str) -> dict[str, Model]:
"""Return every model of a solid, by name.
Parameters
----------
material : str
The material's id or an alias.
Returns
-------
dict of str to Model
The models, named ``<source>/<formula>``.
"""
wanted = as_material(material)
return {name: m for name, m in _all_models().items() if m.material == wanted}
[docs]
def model(name: str) -> Model:
"""Return a model by name.
Parameters
----------
name : str
``<source>/<formula>``.
Returns
-------
Model
The model.
Raises
------
OptmatError
If no model has that name.
"""
# Only the registry that holds the name is built (as for the gases, TC-810), and
# a published formula reads only its own source's record.
registry = _REGISTRIES.get(name.split("/", 1)[0])
try:
return registry()[name] if registry else published_model(name)
except KeyError as exc:
msg = f"no solid model named {name!r}"
raise OptmatError(msg) from exc
[docs]
def default_model(material: str, axis: str | None = None) -> Model:
"""Return the recommended model of a solid.
Parameters
----------
material : str
The material's id or an alias.
axis : str, optional
For an anisotropic crystal, the axis (``o`` or ``e`` for a uniaxial one);
required when the recommendation is per axis.
Returns
-------
Model
The model ``data/solid/defaults.toml`` names for it.
Raises
------
OptmatError
If no model is recommended for the material (or the axis) yet, or an axis is
needed and not given.
"""
wanted = as_material(material)
choice = _defaults().get(wanted)
if choice is None:
msg = f"no dispersion model is recommended for {wanted} yet"
raise OptmatError(msg)
names = choice[0]
if "" in names:
return model(names[""])
if axis is None:
msg = f"{wanted} is anisotropic: give the axis ({', '.join(sorted(names))})"
raise OptmatError(msg)
if axis not in names:
msg = f"no dispersion model is recommended for {wanted} axis {axis!r} yet"
raise OptmatError(msg)
return model(names[axis])
[docs]
def default_reason(material: str) -> str:
"""Return why the recommended model of a solid was chosen.
Parameters
----------
material : str
The material's id or an alias.
Returns
-------
str
The reason ``data/solid/defaults.toml`` gives.
Raises
------
OptmatError
If no model is recommended for the material yet.
"""
wanted = as_material(material)
choice = _defaults().get(wanted)
if choice is None:
msg = f"no dispersion model is recommended for {wanted} yet"
raise OptmatError(msg)
return choice[1]