Register Custom Distributions
nemora ships with a core registry (Weibull, Gamma, Johnson SB, Birnbaum-Saunders, and the
generalized beta and generalized secant families). Generalised secant entries are available as
gsmN for N >= 2 (e.g. gsm3, gsm5) and can be extended via the same plugin hooks. The registry can be
extended at runtime. You can plug in additional probability density functions either by calling the
Python API directly, by installing a plugin that exposes an entry point, or by pointing the toolkit
at a YAML configuration file.
The helper nemora.distributions.default_parameter_bounds() exposes Nemora’s canonical parameter
constraints (e.g. enforcing positive shape/scale parameters or simplex-constrained omega weights).
CLI and fitting helpers fall back to these defaults whenever an individual Distribution does not
override the bounds field.
Python API
from typing import Mapping
import numpy as np
from nemora.distributions import Distribution, register_distribution
def truncated_normal_pdf(x: np.ndarray, params: Mapping[str, float]) -> np.ndarray:
mean = params["mu"]
sigma = params["sigma"]
scale = params.get("s", 1.0)
z = (x - mean) / sigma
return scale * np.exp(-0.5 * z**2) / (sigma * np.sqrt(2 * np.pi))
register_distribution(
Distribution(
name="truncnorm",
parameters=("mu", "sigma", "s"),
pdf=truncated_normal_pdf,
notes="Example plugin distribution.",
bounds={"sigma": (1e-6, None)},
extras={"source": "python-api"},
),
overwrite=True,
)
Once registered, the new distribution appears in nemora registry and is available to the HPS
workflow.
Entry points (recommended for plugins)
Third-party packages can expose a callable via the nemora.distributions entry-point group. The
callable should return either a single Distribution or an iterable of them. Example
pyproject.toml snippet:
[project.entry-points."nemora.distributions"]
truncnorm = "my_plugin.distributions:create_truncnorm"
Within my_plugin/distributions.py:
from nemora.distributions import Distribution
from ._pdf import truncated_normal_pdf
def create_truncnorm() -> Distribution:
return Distribution(
name="truncnorm",
parameters=("mu", "sigma", "s"),
pdf=truncated_normal_pdf,
notes="Truncated Normal distribution shipped by my_plugin.",
bounds={"sigma": (1e-6, None)},
extras={"source": "entry-point"},
)
nemora discovers the entry point at import time and registers the distribution automatically.
YAML configuration
Supply a YAML file that references callables or defines distributions inline. Point the environment
variable DBHDISTFIT_DISTRIBUTIONS at one or more files separated by the OS path separator, or copy
files into config/distributions/ inside a source checkout.
metadata:
title: "Custom additions"
version: "1.0"
distributions:
- name: truncnorm
parameters: ["mu", "sigma", "s"]
pdf: my_plugin.pdf:truncated_normal_pdf
notes: "Truncated normal PDF from my_plugin."
bounds:
sigma: [1e-6, null]
- callable: my_plugin.factory:create_mixture
overwrite: true
args: [2]
Each item either provides a callable (invoked with optional args/kwargs) or an inline
definition with name, parameters, and a pdf import path. If the callable returns multiple
Distribution instances they are all registered. The loader skips invalid entries but reports
warnings via the logger to aid debugging.
Inspecting the registry
nemora registry
The CLI lists built-in and plugin distributions in alphabetical order. Use nemora --verbose distribution-name (planned) to inspect parameters and metadata.
To inspect parameter bounds and extras for a specific entry:
nemora registry --describe weibull --json
Pass --show-metadata to print all distributions in a human-readable table.
Programmatic workflows can call nemora.distributions.list_registry_metadata() to inspect bounds
and extras without parsing CLI output:
from nemora.distributions import list_registry_metadata
for entry in list_registry_metadata():
print(entry["name"], entry["parameters"], entry["bounds"].get("a"))
CLI users can run nemora registry --describe gamma --show-metadata (or --json) to print the same
information without writing Python.
Testing custom distributions
When adding a new distribution, unit tests should exercise the PDF across representative DBH vectors
and ensure parameters remain valid for grouped tallies. The helper register_distribution accepts
overwrite=True so test suites can inject temporary definitions without polluting the global
registry.