Skip to content

Core library: catalogue

The framework every application builds on: the network, the layers, the model, the set-up helpers, and the general-purpose constitutive laws and drives. Every application is set up the same way; see Using noodl.

Import from noodl.topology and the modules named in each table. The full reference, with every parameter, is in the API reference.

Set-up

Build the model and its starting state and inputs.

Name What it does How to call it
drivers_from
noodl.refs
A drivers dictionary from {key: {label: value}} and/or {key: tensor}. drivers_from(model, values, *, base=None)
state_from
noodl.refs
A state dictionary, as drivers_from builds drivers. state_from(model, values, *, base=None)
initial_drivers
noodl.refs
A copy of the model's driver template (model.driver_template, which an application's build_model records), then values (see drivers_from). initial_drivers(model, *, values=None)
check_setup
noodl.validation
Check model and, when given, state and drivers; return a SetupReport. check_setup(model, state=None, drivers=None, *, dt=None, probe=False, steady=False, names=None)

Layers and model

The conservation layers and the model that steps them.

Name What it does How to call it
Network
noodl.topology
Directed multigraph with typed edges and tensor-valued topology operators. Network(dtype=torch.float32)
Ports
noodl.model
What a coupled or external model may prescribe and read. Ports(boundary_nodes, prescribed_keys, boundary_flows, flow_keys=<factory>)
Model
noodl.model
Layers on one Network, stepped together. See the module docstring for the keys. Model(net, layers, closures=(), reactions=(), coupling='pingpong', iterate_tol=None, iterate_max=20, substeps=None, adjoint_rtol=1e-10, iterate_relaxation=0.5, reaction_order='after_transport', iterate_acceleration=None, iterate_memory=5, iterate_flow_tol=None, iterate_on_limit='raise')
AllocatedFlowLayer
noodl.layers
Flows allocated by rule, not by a potential: each edge's requested flow is clipped to the arc's capacity and the receiving node's free storage, one explicit step at a time, conserving storage exactly (WSIMOD's push/pull semantics). quantity, unit and flow_unit are reported by model.refs, never used numerically. AllocatedFlowLayer(net, name, kind, *, s_max, c_arc, preference=None, mode='hard', tau=None, n_passes=5, quantity='storage', unit='', flow_unit='')
KirchhoffLayer
noodl.layers
Flows driven by a potential (pressure, head): solves nodal conservation A_I g(A^T phi) = s_I for the interior potentials by Newton's method, with the constitutive laws on its edge kinds, drives added to the potential differences, and prescribed potentials at its boundary nodes; differentiable through the converged solution. flow_unit is reported by model.refs, never used numerically. KirchhoffLayer(net, name, laws, drives=(), boundary=(), linear_solver='auto', *, node_sources=(), quantity='potential', unit='', flow_unit='', phasor=False, analytic_primal=False, newton_defaults=None)
TransportLayer
noodl.layers
dx/dt = M x + N x_b + sources / capacity on this layer's ACTIVE interior nodes. TransportLayer(net, name, *, capacity, flow_kind, boundary, n_species=1, carrier=1.0, transmission=None, kinetics=None, removal=None, conduction_kind=None, conductance=None, dilution=None, dilution_mode='signed', storage_free=(), scheme='exact', linear_solver='auto', quantity='scalar', unit='', species_names=None, source_unit='', capacity_unit='', flow_unit='')
CoupledModel
noodl.couple
Returned by union. .step takes and returns {model_tag: State} / {model_tag: Drivers} -- each model keeps its own dicts; nothing is merged. CoupledModel(models, links, aliases, substeps, *, relaxation=0.5, iterate_rtol=1e-08, iterate_atol=0.0, iterate_max=50, adjoint_rtol=1e-10)

Constitutive laws

The relation between the flow through an edge and the potential difference across it.

Name What it does How to call it
AffinityFan
noodl.elements
A fan curve run at another speed and air density, by the fan laws (ContamX's performance-curve fan, measured against ContamX 3.4.1.7). AffinityFan(curve, *, src, tgt, rho_ref, speed_key=None, off=0.0, multiplier=1.0, shutoff=None, rho_key='rho', kind=None)
AirDuct
noodl.elements
A duct segment, F (kg/s) from dp (Pa): Darcy-Weisbach with ContamX's friction factor. AirDuct(length, diameter, roughness, loss=0.0, *, area=None, src, tgt, rho_key='rho', temperature_key=None, kind='duct', learnable=False)
Conductance
noodl.elements
q = g dp, the linear branch law used for thermal conduction and passive exchange; g is in the flow unit per unit of potential (W/K for heat, kg/s per Pa for air). Conductance(g, *, kind='conduction', learnable=False)
CubicSplineFlow
noodl.elements
An airflow element given by measured points, fitted as ContamX fits them (SplineCurve): CONTAM's cubic-spline elements. CubicSplineFlow(x, y, *, independent='pressure', volume=False, multiplier=1.0, src, tgt, rho_key='rho', kind='airpath')
Damper
noodl.elements
Separate power-law coefficient and exponent for each flow direction: C_pos/n_pos for dp > 0 and C_neg/n_neg for dp < 0, each as in PowerLaw (C in the flow unit per Pa^n, n dimensionless). Damper(C_pos, n_pos, C_neg, n_neg, *, dp_transition=0.001, src=None, tgt=None, m=0.0, rho_ref=1.2041, rho_key='rho', kind='damper', learnable=False)
DoorCompartment
also MBLDoorCompartment
noodl.elements
One compartment of Buildings.Airflow.Multizone.DoorDiscretizedOpen per edge. DoorCompartment(*, src, tgt, medium, dA, CD=0.65, m=0.5, dp_turbulent=0.01, vZer=0.001, T_key='T', Xw_key='X_w', p_key='p_abs', kind='door', learnable=False)
DoorPortStream
also MBLDoorPortStream
noodl.elements
One of the two port streams of a whole discretised door, as ONE edge from side A to side B: direction="ab" returns port_a1.m_flow = mAB_flow, "ba" returns port_b2.m_flow = -port_a2.m_flow = -mBA_flow (kg/s, both positive from A to B), from the compartment law comp (:class:DoorCompartment or :class:OperableDoorCompartment, one door) at the compartment pressure differences dp + head(drivers) (:class:DoorCompartmentHead). The edge's own dp is the zones' potential difference phi_A - phi_B. DoorPortStream(comp, head, direction, kind)
Duct
noodl.elements
Colebrook duct: F(dp) with friction from the Colebrook equation, laminar below Re_t. Length L, diameter D and roughness eps (m); sum_C the dimensionless sum of dynamic loss coefficients; A (m2) defaults to the circular area; rho (kg/m3) and mu (Pa s); the flow is a mass flow in kg/s. Duct(L, D, eps, sum_C=0.0, *, A=None, Re_t=2000.0, rho=1.2041, mu=1.81625e-05, n_iter=4, kind='duct', learnable=False)
DuctTerminal
noodl.elements
A duct terminal, the zero-length duct between a junction and its zone, F (kg/s) from dp (Pa), as ContamX 3.4.1.7 computes it (measured). DuctTerminal(area, loss, *, src, tgt, rho_key='rho', temperature_key=None, opening_key=None, kind='duct_terminal', learnable=False)
FanCurve
noodl.elements
Cubic pressure-flow curve inverted for q given dp on [0, q_max]: coeffs are (a0, a1, a2, a3) of P(q) = a0 + a1 q + a2 q^2 + a3 q^3 in Pa for q in the flow unit, and q_max is the largest flow the curve covers, in that unit. FanCurve(coeffs, q_max, *, kind='airpath', learnable=False)
FixedFlow
noodl.elements
q = q0 regardless of dp (q0 in the flow unit); dflow = 0; linear_init = (q0, 0). FixedFlow(q0, *, kind='airpath', learnable=False)
FixedVolumeFlow
noodl.elements
F = Q rho_up whatever dp: a constant volume flow volume_flow Q (m3/s, one per edge) delivered as mass flow at the density of the node it draws from (src when Q >= 0, tgt otherwise), read from drivers[rho_key] (full node order). ContamX's constant-volume fan in a duct (measured). FixedVolumeFlow(volume_flow, *, src, tgt, rho_key='rho', kind='fan', learnable=False)
OpenDoor
also MBLDoorOpen
noodl.elements
Buildings.Airflow.Multizone.DoorOpen: one direction of the always-open door. OpenDoor(*, direction, src, tgt, medium, wOpe=0.9, hOpe=2.1, CD=0.65, m=0.5, dp_turbulent=0.01, T_key='T', kind='door', learnable=False)
OperableDoor
also MBLDoorOperable
noodl.elements
Buildings.Airflow.Multizone.DoorOperable: the door blended between open and closed by the opening signal y read from drivers[y_key]. OperableDoor(*, direction, src, tgt, medium, y_key, LClo, wOpe=0.9, hOpe=2.1, CDOpe=0.65, mOpe=0.5, mClo=0.65, dpCloRat=4.0, CDCloRat=1.0, dp_turbulent=0.01, T_key='T', kind='door', learnable=False)
OperableDoorCompartment
also MBLDoorCompartmentOperable
noodl.elements
One compartment of Buildings.Airflow.Multizone.DoorDiscretizedOperable per edge, blended between the open door and the closed crack by y = drivers[y_key]. OperableDoorCompartment(*, src, tgt, medium, y_key, AOpe, LClo, nCom, CDOpe=0.65, CDClo=0.65, CDCloRat=1.0, dpCloRat=4.0, mOpe=0.5, mClo=0.65, dp_turbulent=0.01, vZer=0.001, T_key='T', Xw_key='X_w', p_key='p_abs', kind='door', learnable=False)
PowerLaw
noodl.elements
q = C sign(dp) |dp|^n, laminar-blended or smoothly regularised near dp = 0. dp is in Pa; C is in the flow unit per Pa^n (kg/s for a mass-flow coefficient, m3/s for a volume-flow one), so the flow comes out in whatever unit C carries; n is dimensionless (0.5 for an orifice, towards 1 for a laminar crack). PowerLaw(C, n, *, dp_transition=0.001, regularised=None, kind='airpath', learnable=False)
PrescribedFlow
noodl.elements
F = drivers[key] whatever dp: a flow (kg/s, one value per edge of the kind) that a closure or an input prescribes every step, e.g. an air handler's supply flows. dtype is the layer's: linear_init, which has no dp to take it from, returns it. PrescribedFlow(key, *, kind, dtype=torch.float64)
Quadratic
noodl.elements
q = sign(dp) * 2|dp| / (sqrt(a^2 + 4 b |dp|) + a): the inverse of dp = a q + b |q| q, with dp in Pa, a in Pa per flow unit and b in Pa per flow unit squared. Quadratic(a, b, *, kind='airpath', learnable=False)
RegularizedPowerLaw
also MBLPowerLaw
noodl.elements
MBL's regularised power law, q = C sign(dp) \|dp\|^m, volume or mass form. RegularizedPowerLaw(C, m, *, dp_turbulent=0.1, form, rho_default, kind='airpath', learnable=False)
Scaled
noodl.elements
F = s F_law: law's flow times the dimensionless multiplier drivers[key]. Scaled(law, key)
SplineFlowTable
also MBLTable
noodl.elements
MBL's tabulated flow law: a monotone cubic Hermite spline through (dp, flow) knots, linearly extrapolated outside them; flow(dp) always returns MASS flow in kg/s. SplineFlowTable(dp_points, flow_points, *, form, rho_default=None, kind='airpath')
UpstreamDensityPowerLaw
noodl.elements
PowerLaw with C scaled by (rho_upstream / rho_ref) ** m, upstream by sign(dp). UpstreamDensityPowerLaw(C, n, *, src, tgt, m, rho_ref=1.2041, rho_key='rho', dp_transition=0.001, regularised=None, kind='airpath', learnable=False)

Drives

Terms added to an edge's potential difference (stack, wind, fans).

Name What it does How to call it
DoorCompartmentHead
noodl.elements
The hydrostatic part of DoorDiscretized.mo:64-66, as a noodl drive: rho_A hAg[i] - rho_B hBg[i] per compartment edge, shape (..., n_edges). DoorCompartmentHead(kind, *, src, tgt, hAg, hBg, medium, T_key='T', Xw_key='X_w', p_key='p_abs')
ConstantDrive
noodl.drives
A drive that reads a pre-computed, already batched value from drivers. ConstantDrive(kind, key)
Stack
noodl.drives
Hydrostatic stack term (CONTAM TN 1887r1 eq. 17 with eq. 64-65 at the path elevation). Stack(kind, *, src, tgt, z_path, z_ref, rho_key='rho', g=9.80665)
DuctStack
noodl.drives
Hydrostatic term of a duct segment between two junctions: the air column at the density of the junctions' MEAN TEMPERATURE (ContamX 3.4.1.7, measured), which at one pressure is the harmonic mean of the two node densities. DuctStack(kind, *, src, tgt, z_ref, rho_key='rho', g=9.80665)
WindProfile
noodl.drives
CONTAM wind pressure profile: Cp versus relative wind angle, periodic in the angle. WindProfile(angles_deg, cp, *, curve='linear')
Wind
noodl.drives
Wind pressure on envelope paths (CONTAM TN 1887r1 section 3.15). Drivers: rho_amb in kg/m3, V_met in m/s and theta_w in the unit the azimuth edge attribute uses (degrees for networks read from CONTAM). Wind(kind, *, sign, envelope, azimuth, ch, cp_const, profile_index, profiles=(), rho_key='rho_amb', speed_key='V_met', direction_key='theta_w')

Closures

Functions of the state that compute drivers each step (densities, flows, levels).

Name What it does How to call it
AlgebraicClosure
noodl.contracts
A closure that only computes drivers from the state and the drivers: called as closure(state, drivers), it returns the driver entries it adds or replaces. AlgebraicClosure(...)
IntegratingClosure
noodl.contracts
A closure that advances state of its own over the step (integrates = True). IntegratingClosure(...)
ClosureSpec
noodl.contracts
A closure and its declarations, read once by closure_spec. ClosureSpec(closure, label, integrates, declares_integrates, state_keys, key_labels, reads, writes, edge_kinds, requires_coupling, reads_flows_of, species_columns, output_units=<factory>, owner='Model')

Reactions

Transformations applied to transported species each step.

Name What it does How to call it
FirstOrderDecay
noodl.layers
x <- x * exp(-rate * dt); rate broadcasts against x. FirstOrderDecay(rate)

Files

Readers and writers of other tools' file formats.

Name What it does How to call it
write_at
noodl.layout
target with value written (add=True: ADDED) at node position, in the caller's own layout (reduced (..., n) or stacked (..., n, 1)) but not necessarily its own shape: a batched value written into an unbatched target broadcasts the target up to the value's batch. Never writes into target itself. where prefixes the layout error. write_at(target, n, position, value, *, add=False, where='layout.write_at')

Other classes

Supporting types.

Name What it does How to call it
StepContext
noodl.contracts
What a state transition needs from the model: the interval it must integrate over (None under steady(), which an integrating closure refuses) and, when the caller tracks it, the time at the start of the step. StepContext(dt, t=None)
ClosureAttribute
noodl.contracts
One optional attribute of a closure: its name, the type it must have, what it defaults to when absent, what it means and which code consumes it. ClosureAttribute(name, type, default, meaning, consumer)
Field
noodl.refs
A state or driver key that also knows the layout of the tensor stored under it. Field(key, *, role, layer, axis, labels, ordering, settable=None, n_species=1, species=None, quantity='', unit='', required='optional', default=0.0, description='', dtype=torch.float64, device='cpu', aliases=None, column=False, scalar=False)
LayerRef
noodl.refs
One registered layer of a model, with its keys as discoverable Field attributes. LayerRef(name, layer, kind, *, flow_owner=None)
KeyOwnership
noodl.refs
Who writes and who reads one key of a model: writers and readers are tuples of "layer <name>", "closure <label>" or "caller" (the dictionary the caller gives). field is the key's Field when the model knows its layout. Closure entries come from the closure's DECLARATIONS (inputs, outputs, state_keys), so a closure that declares nothing is absent. KeyOwnership(key, field, writers, readers)
LayerRefs
noodl.refs
Registered layer name -> LayerRef, plus the model's closure-carried keys. LayerRefs(model)
Issue
noodl.validation
One finding: level is "error", "warning" or "info"; key the key concerned, if any. Issue(level, code, message, key=None)
InputRow
noodl.validation
One known key: what is expected and what was given. InputRow(key, role, layer, required, ordering, expected, unit, given, status)
SetupReport
noodl.validation
The result of check_setup. ok is true when there are no errors. SetupReport(issues=<factory>, rows=<factory>, probed=False, driver_reads=frozenset(), state_reads=frozenset(), closure_outputs=frozenset())
UndefinedSteadyState
noodl.layers
A steady transport solve has no answer: a stored node keeps everything that enters it (nothing leaves it, or it belongs to a closed group whose contents never reach a boundary outflow, a removal or a filter loss). A ValueError, raised before the solve and naming the nodes; layer is the layer's name and nodes the nodes refused. UndefinedSteadyState(message, *, layer, nodes)
AirMedium
also MBLMedium
noodl.elements
An air medium's default state and the two densities its flow elements need. AirMedium(name, p_default, T_default, X_default, rho_default, has_moisture, _buoyancy, _density=None, _cp=None)
LawContext
noodl.elements
What a dynamic or implicit constitutive law needs besides its own edge values. LawContext(mode, dt=None, t=None, integration='trapezoidal', dp_prev=None, q_prev=None, omega=None)
SplineCurve
noodl.elements
A measured curve y(x) fitted as ContamX fits it (see the module docstring). SplineCurve(x, y, *, name='')
Conversion
noodl.couple
One registered conversion and the UNITS it maps between, (from_unit, to_unit, fn). Conversion(from_unit, to_unit, fn)
ValueLink
noodl.couple
One shared-node value relationship. ValueLink(from_model, from_key, from_index, to_model, to_key, to_index=0, convert=None, two_way=False, convert_back=None, sources_key=None)
DriverAlias
noodl.couple
One driver value shared across models: source is authoritative; every target is overwritten from it through that target's own registered conversion (or none). DriverAlias(source, targets)

Functions

Calculations and helpers.

Name What it does How to call it
closure_spec
noodl.contracts
Read closure's declarations into a ClosureSpec: the only reader of the closure attributes (CLOSURE_ATTRIBUTES). index is the closure's position, for the message about a non-callable; owner prefixes every message. closure_spec(closure, *, index, owner='Model')
call_closure
noodl.contracts
Call a closure (or its ClosureSpec) by the one dispatch rule: three arguments for an integrating closure, two otherwise. For callers outside Model that run a closure themselves; a bare closure is read with closure_spec first. call_closure(closure_or_spec, state, drivers, ctx=None)
reaction_species_columns
noodl.contracts
A Reaction's optional species_columns (the same member as a closure's), {} when it declares none. TypeError if malformed. reaction_species_columns(reaction)
check_species_columns
noodl.contracts
Raise ValueError unless every {layer: {name: column}} in declared names a transport layer of transport, has column < n_species, and, when the layer has species_names, species_names[column] == name. A layer without species_names cannot verify names, so it accepts only declarations that give distinct columns. label names the closure or reaction in the message. check_species_columns(label, declared, transport)
batch_shape
noodl.layout
The batch shape of x: its shape without its last n_trailing physical dimensions. ValueError if x has fewer dimensions than that. batch_shape(x, n_trailing)
broadcast_batch
noodl.layout
Broadcast the batch shapes of items, each (tensor, number of trailing physical dims). Returns the common batch shape and every tensor .expand()-ed to that batch plus its own trailing shape (views, no copies). The batch is aligned on the LEFT of the physical axes, never against them, so a batch of size n cannot be mistaken for a node axis. RuntimeError naming the shapes if the batches do not broadcast. broadcast_batch(*items)
per_instance
noodl.layout
A float, or a tensor with one value per instance (B...), as (B..., 1, ...) with n_trailing trailing singleton axes, in like's dtype and device. It then broadcasts against like (B..., physical...) over the batch only, never against a physical axis (a batch of size n is not a node axis). RuntimeError if its batch does not broadcast with like's. per_instance(value, like, n_trailing)
is_stacked
noodl.layout
True when x is in STACKED layout (..., n, K): at least min_dim dimensions (never fewer than 2) and trailing shape (n, K). With K == 1 this is the (..., n, 1) column, as opposed to the reduced (..., n). is_stacked(x, n, K=1, *, min_dim=2)
as_stacked
noodl.layout
(x as (..., n, K), reduced?) by the one rule: stacked (..., n, K) first; for K == 1 also reduced (..., n), returned with a trailing axis and reduced=True. min_dim is the fewest dimensions of the stacked form (the reduced form needs one fewer): 3 where the leading axis is time. ValueError("{where}: {name!r} must be ...") otherwise. as_stacked(x, n, K, *, name, where, min_dim=2)
as_layout
noodl.layout
x_stacked (..., n, 1) back in the caller's layout: (..., n) if reduced, unchanged otherwise (the inverse of as_stacked for one species). as_layout(x_stacked, reduced)
reduced_single
noodl.layout
A single-species tensor in REDUCED layout (..., n), whether it came stacked (..., n, 1) or reduced. A batched (1, 1) is both and holds one number, so the ambiguity at n == 1 is harmless. ValueError("{where}: ...") if its last axis is not n entries. reduced_single(x, n, *, where)
species_columns
noodl.layout
The column of each wanted species name in the declared order (a layer's species_names). order="any" allows a subset in any order; order="exact" requires wanted == declared. Unknown and repeated names raise ValueError, naming them, with where as prefix. With declared=None (the layer names no species) the names cannot be resolved: the identity [0, 1, ...] is returned, only when len(wanted) == n_species. species_columns(declared, wanted, *, where, n_species=None, order='any')
normalize_unit
noodl.refs
A unit string in one canonical spelling, for comparison only (this is not a units library: nothing is converted, and two different units never compare equal). normalize_unit(unit)
units_agree
noodl.refs
Whether two unit strings are the same unit up to normalize_unit's spellings. units_agree(a, b)
input_field
noodl.refs
A Field for an input a closure, reaction, law or drive reads itself (a wind speed, an inflow), as a closure's input_specs or a builder's model.input_specs declares it. input_field(model, key, *, description, unit='', over=None, required=True, ordering=None)
input_unit_declarations
noodl.refs
(origin, key, unit) for every input a model, closure or reaction declares in input_specs, in declaration order; unit is "" when the spec gives none. origin names the declarer ("model", a closure's or reaction's repr). input_unit_declarations(model)
required_state_keys
noodl.refs
The state keys Model.step reads from the step-start state. required_state_keys(model)
active_interior
noodl.layers
Split the non-boundary nodes of net into the ones kinds touch and the ones it does not: (interior_idx, inactive_idx), both in NODE order, both excluding boundary. active_interior(net, kinds, boundary)
Orifice
noodl.elements
PowerLaw(C = Cd * A * sqrt(2 / rho), n = 0.5): the sharp-edged orifice equation, as a VOLUME flow in m3/s from Cd (dimensionless discharge coefficient), A (m2) and rho (kg/m3). Orifice(Cd, A, *, rho=1.2, dp_transition=0.001, regularised=None, kind='airpath', learnable=False)
air_viscosity
noodl.elements
Dynamic viscosity of air (Pa s) at temperature T (K): ContamX's linear law, 1.81625e-5 + 4.92859e-8 (T - 293.15), measured between 253 and 333 K. air_viscosity(T)
discretized_door
also mbl_discretized_door
noodl.elements
One DoorDiscretizedOpen as nCom edges of kind: the compartment element and its head drive. Defaults are MBL's (DoorDiscretized.mo:6-11, TwoWayFlowElementBuoyancy.mo:6-14, DoorDiscretizedOpen.mo:6, TwoWayFlowElement.mo:19). dA = wOpe hOpe / nCom on every edge (DoorDiscretizedOpen.mo:23, DoorDiscretized.mo:60). discretized_door(*, src, tgt, medium, nCom=10, wOpe=0.9, hOpe=2.1, hA=1.35, hB=1.35, CD=0.65, m=0.5, dp_turbulent=0.01, vZer=0.001, kind='door', T_key='T', Xw_key='X_w', p_key='p_abs')
discretized_operable_door
also mbl_discretized_operable_door
noodl.elements
One DoorDiscretizedOperable as nCom edges of kind; see :func:discretized_door. AOpe = wOpe hOpe (DoorDiscretizedOperable.mo:35); LClo has no MBL default. discretized_operable_door(*, src, tgt, medium, y_key, LClo, nCom=10, wOpe=0.9, hOpe=2.1, hA=1.35, hB=1.35, CDOpe=0.65, CDClo=0.65, CDCloRat=1.0, dpCloRat=4.0, mOpe=0.5, mClo=0.65, dp_turbulent=0.01, vZer=0.001, kind='door', T_key='T', Xw_key='X_w', p_key='p_abs')
effective_leakage_area
also mbl_ela
noodl.elements
EffectiveAirLeakageArea.mo:3-5,7-14,16: C = L * CDRat * sqrt(2 / rho_default) * dpRat ** (0.5 - m), m = 0.65 by default (:4), dpRat = 4 Pa (:7-9), CDRat = 1 (:11-14). effective_leakage_area(L, dpRat=4.0, CDRat=1.0, m=0.65, dp_turbulent=0.1, *, rho_default, kind='airpath', learnable=False)
medium
noodl.elements
Look up one of the three air media, by physical name or by Modelica class path. medium(name)
open_door_pair
also mbl_door_pair
noodl.elements
Both edges of one DoorOpen (or of several, with per-door src/tgt): the "ab" edge (path 1) with kind f"{kind}_ab" and the "ba" edge (path 2) with kind f"{kind}_ba", sharing every keyword argument of :class:OpenDoor. open_door_pair(*, kind='door', **kwargs)
operable_door_pair
also mbl_operable_door_pair
noodl.elements
Both edges of one DoorOperable; see :func:open_door_pair. operable_door_pair(*, kind='door', **kwargs)
power_law_coefficient
also mbl_coefficient
noodl.elements
Coefficient_V_flow.mo/Coefficient_m_flow.mo: C/k and m given directly, with no further formula -- a direct pass-through to :class:RegularizedPowerLaw. power_law_coefficient(C, m, form, dp_turbulent=0.1, *, rho_default, kind='airpath', learnable=False)
power_law_from_point
also mbl_point
noodl.elements
Point_m_flow.mo:4-5: k = mMea_flow_nominal / dpMea_nominal ** m, fit from one measured (dp, m_flow) pair; m stays a free parameter (default 0.5, inherited from Coefficient_m_flow's PowerLawResistanceParameters(m=0.5), Coefficient_m_flow.mo:27-28). power_law_from_point(dpMea, mMea_flow, m=0.5, dp_turbulent=0.1, *, rho_default, kind='airpath', learnable=False)
power_law_from_points
also mbl_points
noodl.elements
Points_m_flow.mo:4-6,15-16: the flow exponent itself is derived from two measured (dp, m_flow) pairs, m = (ln(mMea[0]) - ln(mMea[1])) / (ln(dpMea[0]) - ln(dpMea[1])), then k = mMea[0] / dpMea[0] ** m. dpMea/mMea_flow are each a 2-element sequence. power_law_from_points(dpMea, mMea_flow, dp_turbulent=0.1, *, rho_default, kind='airpath', learnable=False)
regularized_orifice
also mbl_orifice
noodl.elements
Orifice.mo:3-5,9: C = CD * A * sqrt(2 / rho_default), m = 0.5 by default (overridable, per Orifice.mo:3's non-final m=0.5 modifier); C itself is final in MBL (does not depend on m). CD defaults to 0.65 (Orifice.mo:9, the sharp-edged-orifice discharge coefficient). regularized_orifice(A, CD=0.65, m=0.5, dp_turbulent=0.1, *, rho_default, kind='airpath', learnable=False)
check_drive_signature
noodl.drives
Raise TypeError unless drive is callable as drive(drivers). check_drive_signature(drive, *, where)
apply_conversion
noodl.couple
value unchanged if name is None; the registered conversion otherwise. apply_conversion(name, value, drivers)
transport_boundary_inflow
noodl.couple
Net mass INFLOW, (...,), at the boundary node boundary_idx[node_position], in a transport layer's own units, for a SINGLE-SPECIES layer (x_interior/x_boundary are (..., n_i)/(..., n_b), never (..., n_i, K)). transport_boundary_inflow(net, q, flow_kinds, x_interior, x_boundary, interior_idx, boundary_idx, node_position)
union
noodl.couple
Couple models by exchanging the driver/state values shared names, WITHOUT merging any model's Network, layers, or closures. Never modifies the Model/State/Drivers objects passed in -- returns fresh dict copies. union(models, shared, *, substeps=None, relaxation=0.5, iterate_rtol=1e-08, iterate_atol=0.0, iterate_max=50, adjoint_rtol=1e-10)

Constants and tables

Named values and option tables.

Name Value
CLOSURE_ATTRIBUTES tuple

Base classes (for extending)

Subclass these to add a constitutive law, drive, closure, reaction or node source; see Extending noodl.

Name What it does How to call it
Reaction
noodl.layers
A local, per-node nonlinear map applied to the state after a transport step (or before it, under Model(reaction_order="before_transport")). Reaction(...)
ConstitutiveLaw
noodl.elements
Abstract branch law: flow as a function of potential difference. ConstitutiveLaw(kind)
ImplicitLaw
noodl.elements
A constitutive law written as a relation residual(dp, q, drivers, ctx) = 0. ImplicitLaw(kind)
Drive
noodl.drives
A drive must read every differentiable quantity from drivers, never own one. Drive(...)
NodeSource
noodl.nodesources
Base class: a potential-dependent withdrawal at a fixed set of nodes. NodeSource(nodes)