limits¶
Limit sets: the regulatory tables a material is measured against.
limits
¶
Limit sets: the regulatory tables a material is measured against.
Every limit set is data, loaded from JSON in data/limits. Adding a
jurisdiction means adding a file and a build script, never an elif in the
calculation. Only two things in these regulations cannot be expressed as a
table, and both are named explicitly rather than worked around:
- limits given per gram of material (the NRC's nCi/g transuranic entries), which need the material's density before they can be compared against Ci/m3, and
- limits that depend on the material's own nuclides (the NRC Class A rule that
anything with a half-life under five years takes a 700 Ci/m3 limit), held in
DYNAMIC_RULES.
Classes:
-
LimitSet–A named table of per-nuclide activity limits.
Functions:
-
limit_sets–Names of the available limit sets, sorted.
-
get_limit_set–Look up a limit set by name.
-
register_limit_set–Add a limit set at runtime, for a site-specific or draft table.
LimitSet
dataclass
¶
LimitSet(name: str, label: str, units: str, limits: dict[str, float], jurisdiction: str = '', default_limit: float | None = None, unlimited: tuple[str, ...] = (), secular_equilibrium: dict[str, tuple[str, ...]] = dict(), secular_equilibrium_sec: dict[str, tuple[str, ...]] = dict(), limits_secular_equilibrium: dict[str, float] = dict(), metal_overrides: dict[str, float] = dict(), limits_per_gram: dict[str, float] = dict(), limits_upper: dict[str, float] = dict(), dynamic_rule: str | None = None, min_half_life_scope: float | None = None, threshold: float = 1.0, source: str = '', url: str = '', retrieved: str = '', notes: str = '')
A named table of per-nuclide activity limits.
Attributes:
-
name(str) –Stable identifier, such as
UK_EPR16_out_of_scope. -
label(str) –Human readable description for reports.
-
jurisdiction(str) –Issuing authority, such as
UKorGermany. -
units(str) –Activity units the limits are in:
Bq/g,Ci/m3, orBqfor a total activity limit, which needs the material's mass. -
limits(dict[str, float]) –Limit per canonical nuclide name.
-
default_limit(float | None) –Limit applied to a nuclide absent from
limits, orNonewhere the regulation has no catch-all. Three UK sets define one: 0.01 Bq/g forUK_EPR16_out_of_scopeandUK_IRR17_notification, and 0.1 Bq/g forUK_IRR17_registration. The other UK sets, and every German, US, EU and IAEA set, have none. -
unlimited(tuple[str, ...]) –Nuclides the source explicitly places no limit on. They are covered, and contribute nothing, which is different from being absent.
-
secular_equilibrium(dict[str, tuple[str, ...]]) –Parent to the daughters whose contribution the parent's limit already includes, straight from the regulation's own table. These are the "+" rows.
-
secular_equilibrium_sec(dict[str, tuple[str, ...]]) –Parent to the daughters covered by its whole chain "sec" value, which is a different and usually much longer list carrying a different and much stricter limit. UK EPR 2016 gives U-238 three progeny at 1 Bq/g under "U-238+" and fourteen at 0.01 Bq/g under "U-238sec". The stricter value is stored in
limitsunder a_seckey. -
limits_secular_equilibrium(dict[str, float]) –The limit to use for a parent that the source lists twice, once plain and once marked "+", when its daughters are actually present. StrlSchV gives Th-232 as 10 Bq/g plain and 0.01 Bq/g marked, and which one applies depends on the material, not on the table.
-
metal_overrides(dict[str, float]) –Limits replacing or adding to
limitswhen the material is activated metal. -
limits_per_gram(dict[str, float]) –Limits in nCi/g, converted using the material density.
-
limits_upper(dict[str, float]) –Upper end of a limit given as a range in the source, kept for reference.
limitsholds the conservative lower end. -
dynamic_rule(str | None) –Key into
DYNAMIC_RULESfor a rule that depends on the material's own nuclides. -
min_half_life_scope(float | None) –Half-life in seconds below which, if every radionuclide present falls under it, the material is outside the regulation altogether. A whole-material test, not a per-nuclide filter.
-
threshold(float) –Index value at or above which the material fails, normally 1.
-
source,((url, retrieved, notes)) –Provenance.
Methods:
-
__post_init__–Canonicalise and validate, so a hand-built set behaves like a loaded one.
-
__hash__–Hash by name and units.
-
daughters_of–Daughters whose activity this set's limit for
parentalready covers. -
__len__–The number of nuclides limited, not counting whole chain variants.
covered_nuclides
property
¶
Every nuclide this set names, whether limited or explicitly unlimited.
The _sec keys are whole chain variants of a nuclide already counted,
not nuclides of their own, so they are not included.
__post_init__
¶
Canonicalise and validate, so a hand-built set behaves like a loaded one.
A set built in Python went through none of the normalisation the JSON
loader applies, so {"Co-60": 0.1} silently matched nothing. Doing the
work here means both paths cannot diverge.
Limits are also required to be positive. A limit of zero means "no activity of this is permitted", the strictest possible value, but the sum of fractions cannot express that, and the evaluation used to skip it as though the nuclide had no limit at all, which is the opposite. Rejecting it here keeps that contradiction out of the data.
__hash__
¶
__hash__() -> int
Hash by name and units.
The generated hash would cover every field, and five of them are dicts, so it raises TypeError even though the class presents as immutable. A set is identified by its name, which the registry already treats as a key, so that is what it hashes by. Equality still compares every field.
daughters_of
¶
Daughters whose activity this set's limit for parent already covers.
limit_sets
¶
limit_sets(jurisdiction: str | None = None) -> tuple[str, ...]
get_limit_set
¶
register_limit_set
¶
Add a limit set at runtime, for a site-specific or draft table.
Parameters: