# Natures

`natures.h`/`natures.cpp` track Verilog-A "natures" (the physical-quantity kind behind a discipline's potential/flow, e.g. voltage, current, charge, temperature) by name across every loaded device, and turn them into the small dense integers the nonlinear solver actually uses for per-nature tolerance and convergence bookkeeping.

## Why identity is name-based

`NatureId` is just an `Id` (see [Identifiers](identifier.md)) - a nature has no numeric identity of its own; it is identified purely by name, exactly as Verilog-A's own `nature`/`discipline` declarations are. This matters because two different OSDI files (compiled independently, possibly by different Verilog-A compilations) need to agree on "is this the same physical quantity" without sharing any other context - matching on the declared name is the only thing that can work across independently compiled shared libraries. Builtin/legacy SPICE natures (`.voltage`, `.current`, `.flux`, `.charge`) and the "no nature" sentinel use a leading-`.` naming convention specifically so they can't collide with any real Verilog-A nature name, and are registered once as static identifiers ([Identifiers](identifier.md)'s `Id::createStatic`) rather than looked up per file.

## `NatureRegistry`: a global, all-static name registry

`NatureRegistry` has no instances (deleted copy/move constructors, every member `static`) - it exists purely as a namespaced collection of process-wide state. `natureId(file, name)` interns a nature name into an `Id` and records that `file` is one of the (possibly several) shared libraries where a nature by that name was found, in `natureFilesMap` - useful for diagnostics ("which loaded files declare a `voltage` nature") rather than for the tolerance pipeline itself, which only needs the `Id`.

## `NaturesSubset`: per-circuit dense indexing

Nature `Id`s are process-wide and effectively unbounded (every loaded device can introduce new ones), but the nonlinear solver wants small, dense indices to use as array subscripts for per-nature tolerance/maximum tracking - and only the natures actually *used* by one circuit's devices should take up a slot. `NaturesSubset` is that per-circuit mapping: `registerNature(id)` is idempotent (returns the existing index if `id` was already registered, otherwise assigns the next one) and every device registers the natures its own tolerances reference as the circuit's loads are processed (see `OsdiFile::tolerances()`/`natrefTolerances()` in [OSDI Files](osdifile.md), and `Instance::updatePotentialNodeSpiceTolerances()`/`updateFlowNodeSpiceTolerances()` in [Device, Instance, and Model Base Classes](devbase.md)).

`reset()` always pre-registers the "no nature" sentinel and the four legacy SPICE natures first, in a fixed order, giving them fixed indices (`noNature=0`, `spiceVoltage=1`, `spiceCurrent=2`, `spiceFlux=3`, `spiceCharge=4`) mirrored by matching static constants on both `NatureRegistry` (as `Id`s) and `NaturesSubset` (as indices) - code that only cares about the classic SPICE tolerance quantities can reference these fixed slots directly, without a lookup, while still sharing the same registration path as every other, dynamically discovered nature.

## `NatureTolerance`

A small `(NatureId, abstol)` pair - what a device returns when asked for a node or residual's tolerance (see the header's own workflow comment): the device supplies a nature identity and an absolute tolerance value; once every device's tolerances are collected, the `NatureId`s are converted to `NaturesSubset` indices, and the nonlinear solver (via `CommonData`, not detailed here) tracks per-nature maxima using those dense indices rather than the `Id`s themselves.
