Fields API
Field annotation types for Numen ECS components.
numen.fields
Field annotation types for the Numen ECS framework.
Each annotation declares how a component field maps into the flat solver arrays:
IntegratedField— state variable; solver integratesdx/dt = f(...)ParameterField— constant parameter inp; never changes during a solveContinuousField— algebraic or output variable written each RHS callDiscreteField— zero-order-hold variable; updated at a fixed rateExcitationPort— injectable forcing input for the characterization frameworkEntityGroup— slot-type declaration for multi-entity coupled systems
Usage example::
from typing import Annotated, Literal
from numen.spec.component import Component
from numen.fields import IntegratedField, ParameterField
class MassComponent(Component):
kind: Literal["mass"] = "mass"
position: Annotated[float, IntegratedField()] = 0.0
velocity: Annotated[float, IntegratedField()] = 0.0
mass: Annotated[float, ParameterField()] = 1.0
EntityGroup
Declares the slot types for one entity group in a multi-slot system.
Analogous to IntegratedField(size=N): bundles type declarations with an implicit size (= number of slots). Used as a ClassVar on System subclasses to declare coupling topology and drive compile-time validation.
Example
entity_slots: ClassVar[EntityGroup] = EntityGroup(MassComponent, SpringComponent, MassComponent)
compile_spec reads entity_slots.slot_types for validation and entity_slots.size to populate CompiledSystem.group_size, which the backend uses to pre-group entity_ids before dispatching to the dynamics function.
Source code in src/numen/fields.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
IntegratedField
dataclass
Continuous state variable; solver integrates dx/dt = f(...).
Placed in the state vector x. The ODE solver updates it every step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
int
|
Number of contiguous scalar slots. Default 1.
Use |
1
|
Example::
position: Annotated[float, IntegratedField()] = 0.0
frequencies: Annotated[list[float], IntegratedField(size=8)] = [0.0]*8
Source code in src/numen/fields.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
ParameterField
dataclass
Constant parameter that enters the parameter vector p.
Never updated during a solve. Appears in spec.param_index_map and
is accessible via spec.view(entity_id, ComponentType, x, p).field_name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
int
|
Number of contiguous scalar slots. Use |
1
|
Source code in src/numen/fields.py
112 113 114 115 116 117 118 119 120 121 122 | |
ContinuousField
dataclass
Algebraic or output variable; computed from state each RHS call.
When algebraic=False (default): output variable — the dynamics function
writes a derived quantity each RHS call (e.g. force, power, flow rate).
The differential_mask is 1 for these slots; all backends support it.
When algebraic=True: algebraic constraint — the dynamics function writes
a residual g(x)=0. The differential_mask is 0 for these slots.
Julia-only (requires an implicit solver such as Rodas5P or FBDF).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
int
|
Number of contiguous scalar slots. |
1
|
algebraic
|
bool
|
If True, marks this field as a DAE algebraic constraint
(residual form). Julia-only; raises |
False
|
Source code in src/numen/fields.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
DiscreteField
dataclass
Zero-order-hold variable updated at a fixed rate.
Occupies a slot in the state vector x. Solver is given required stop
times at multiples of dt so the controller callback fires at exact times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dt
|
float
|
Update period in seconds. Must be > 0. |
0.0
|
size
|
int
|
Number of contiguous scalar slots. |
1
|
Source code in src/numen/fields.py
97 98 99 100 101 102 103 104 105 106 107 108 109 | |
ExcitationPort
dataclass
Marks a component field as an injectable excitation input port.
Compiles like a ParameterField (goes into parameter vector p). The characterization framework reads the annotation metadata to discover available ports and uses inject_excitation() to add a time-varying forcing system post-compilation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
targets
|
str
|
Name of the IntegratedField whose derivative receives F(t). E.g. "velocity" means F(t) is added to d(velocity)/dt. |
''
|
port_type
|
str
|
Bond graph port type — "effort" (force, pressure, voltage) or "flow" (velocity, flow rate, current). Metadata only; used for axis labels and FRF naming conventions. |
'effort'
|
units
|
str
|
SI units string for axis labels, e.g. "N", "Pa", "V". |
''
|
size
|
int
|
Number of scalar values (consistent with other field types). |
1
|
Example::
class MassComponent(Component):
velocity: Annotated[float, IntegratedField()] = 0.0
force: Annotated[float, ExcitationPort(
targets = "velocity",
port_type = "effort",
units = "N",
)] = 0.0
Source code in src/numen/fields.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |