hmf.core.model

The Model base class and the per-kind model registry (issue #388).

A model is one interchangeable implementation of a piece of physics: a fitting function, a transfer function, a filter, a mass definition, … Models are frozen, keyword-only attrs classes whose fields are the model’s parameters. They have no cosmology of their own: their methods take every physical input as an explicit argument (issue #389).

Kinds and registration

A kind is an abstract base class declared with kind=True. It owns a registry of its models:

@attrs.frozen(kw_only=True)
class FittingFunction(Model, kind=True):
    @abc.abstractmethod
    def fsigma(self, sigma): ...

@attrs.frozen(kw_only=True)
class Tinker08(FittingFunction, alias="Tinker08"):
    A: float = field(default=0.186, doc="Amplitude.")

    def fsigma(self, sigma): ...

Every concrete subclass of a kind is registered in that kind (and in any enclosing kind) under its qualified name, package.module:Class, and, if it gives one, under a short alias. An alias is unique within a kind: registering a second class under the same alias is an error, unless the new class passes override=True. A class defined in user code therefore never silently replaces a built-in model. Intermediate base classes that should not be registered pass abstract=True.

Re-defining a class with the same qualified name (re-running a notebook cell, or importlib.reload()) replaces the old registration.

Lookup

Lookup is per kind only; there is no global lookup by name. FittingFunction.get(name) accepts an alias, a qualified name, an import path ("pkg.mod:Cls" or "pkg.mod.Cls") of a class not yet imported, or a class. If that fails, it loads the plugins advertised in the hmf.models entry-point group (once each) and tries again, and finally raises ModelNotFoundError with suggestions. A plugin package advertises its models in its pyproject.toml:

[project.entry-points."hmf.models"]
my_models = "my_package.models"

The entry point may name a module (whose import registers its models) or a class.

Subclasses must be decorated with @attrs.frozen(kw_only=True)

Slotted attrs classes are built twice: once by the class statement, and again by the decorator, which calls __init_subclass__ a second time without the class keywords. Model handles this (it stores its own class keywords on the class, and re-registers the final class), and generates the “Parameters” section of the class docstring from the fields at that point. Mixins with their own __init_subclass__ should likewise tolerate being called a second time without their keywords.

Classes

Model()

Base class of every v4 model.

Functions

qualified_name(cls)

Return the qualified name of a class: package.module:Class.

Exceptions

DuplicateAliasError

A model was registered under an alias already taken within its kind.

ModelNotFoundError

No model of the requested kind is registered or importable under a name.