Constraints¤
A constraint bounds a quantity of an equilibrium state between a lower and an
upper limit during constrained form-finding with
constrained_fdm.
Base class¤
constraints
¤
Constraint
¤
The base class for all constraints, bounds an equilibrium quantity must obey.
Attributes:
-
key(Int[Array, ...]) –The key of the element the constraint acts on; a sequence of keys (a list or a tuple) only for aggregate constraints.
-
bound_low(Float[Array, ...]) –The lower bound on the constrained quantity. If None, unbounded below.
-
bound_up(Float[Array, ...]) –The upper bound on the constrained quantity. If None, unbounded above.
Notes
A constraint is a registered JAX pytree (an equinox Module): its key,
bound_low, and bound_up are dynamic array leaves. Construction stores one
element's values unbatched, so a constraint is a single-element object; a
collection stacks same-type constraints along a new leading axis and the
optimizer vmaps the constraint over it. The key is resolved to an index
against an equilibrium structure at evaluation time. Subclasses supply the
constrained quantity via constraint. Missing bounds normalize to negative
or positive infinity rather than None.
A per-element constraint takes exactly one element key; to bound many
elements, create one constraint per element and let collections vectorize
them. Only aggregate constraints, which declare is_aggregate = True, span a
whole structure.
keys_from_structure
¤
keys_from_structure(structure: EquilibriumStructure) -> Int[ndarray, 'elements ...']
The structure's canonical keys for this constraint's vocabulary.
Parameters:
-
structure(EquilibriumStructure) –The structure whose element ordering defines the index.
Returns:
-
keys_canonical(Int[ndarray, 'elements ...']) –The node, edge, or vertex key ordering the constraint's key is resolved against, one entry per element: a node/vertex key, or an edge key pair.
Notes
The only per-subclass part of key resolution: a subclass names the
canonical ordering its key belongs to (nodes, vertices, or edge pairs)
and raises if the structure is the wrong kind. The resolution itself
lives once in index, so an author who defines a constraint on a new
vocabulary overrides this hook alone.
index
¤
index(structure: EquilibriumStructure) -> Int[Array, ...]
The constraint's element index, resolved against the structure.
Parameters:
-
structure(EquilibriumStructure) –The structure whose element ordering defines the index.
Returns:
-
index(Int[Array, ...]) –A single index for a per-element constraint, or the whole index row for an aggregate constraint, which reads its whole selection in one call.
Notes
The real work of key resolution: a subclass names its canonical keys via
keys_from_structure, and this resolves the constraint's key against them
in one indices_from_keys call, never a per-key loop. The key stays a
compile-time constant (a constraint is closed over, never a jitted
argument), so the resolution folds to a constant at trace time. The key's
own shape distinguishes a per-element constraint from an aggregate, so
there is no aggregate special case here.
__call__
¤
__call__(eqstate: EquilibriumState, structure: EquilibriumStructure) -> Float[Array, ...]
Evaluate the constraint for one element against an equilibrium state.
Parameters:
-
eqstate(EquilibriumState) –The equilibrium state to read the constrained quantity from.
-
structure(EquilibriumStructure) –The structure whose element ordering resolves the constraint's index.
Returns:
-
constraint(Float[Array, ...]) –The constrained quantity for this one element, in the raw shape its hook returns: a scalar for a per-element constraint, or the whole row for an aggregate.
Raises:
-
ValueError–If a per-element constraint's value is not a scalar, typically because the constraint was handed a list of keys where one was expected.
Notes
A constraint holds one element, so this is the linear per-element body: resolve the index, read the constrained quantity, and check its shape. A standalone call returns one element's unbatched value.
To evaluate a group of same-type constraints, stack them into one pytree
and vmap, exactly as one maps any equinox module over a batch::
stacked = tree_stack(constraints)
values = jax.vmap(lambda c: c(eqstate, structure))(stacked)
The optimizer owns that vmap; a scalar constraint lacks a goal's
prediction-vs-target shape check, so the per-element scalar guard here
keeps a stray list key from silently mis-sizing against its bounds.
evaluate
¤
Evaluate the constraint directly on a datastructure, without solving.
Parameters:
-
datastructure(FDNetwork | FDMesh) –The network or mesh to read the equilibrium state from. Its geometry is used as-is; no form-finding is run.
-
sparse(bool, default:True) –If True, assemble the equilibrium state with the sparse model.
Returns:
-
constraint(Float[Array, ...]) –The constrained quantity for this element, in its raw shape.
Notes
A convenience for prototyping a constraint on the high-level COMPAS layer. Unlike the optimizer path, it consumes the datastructure's current state directly rather than solving for equilibrium from raw parameters.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, ...]) -> Float[Array, ...]
Extract the constrained quantity for one element from an equilibrium state.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the quantity from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against, so a constraint can read whole trace-time constants (connectivity, topology) from it. Most constraints ignore it.
-
index(Int[Array, ...]) –The element index, one for a per-element constraint or the whole index row for an aggregate constraint. A constraint carrying an extra per-element array reads it off
self.
Returns:
-
constraint(Float[Array, ...]) –The value of the constrained quantity.
Edge constraints¤
EdgeLengthConstraint
¤
Bound the length of an edge between a lower and an upper value.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The length of the edge.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the length from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the edge.
Returns:
-
constraint(Float[Array, '']) –The edge's length.
EdgeForceConstraint
¤
Bound the internal force of an edge between a lower and an upper value.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The internal force in the edge.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the force from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the edge.
Returns:
-
constraint(Float[Array, '']) –The edge's internal force, signed positive in tension.
EdgeAngleConstraint
¤
EdgeAngleConstraint(key: tuple[int, int], vector: Float[Array, ...] | Sequence[float], bound_low: BoundLike = None, bound_up: BoundLike = None)
Bound the angle between an edge and a reference vector.
Parameters:
-
key(tuple[int, int]) –The key of the edge the constraint acts on.
-
vector(Float[Array, ...] | Sequence[float]) –The reference vector the edge's angle is measured against.
-
bound_low(BoundLike, default:None) –The lower bound on the angle, in radians. If None, unbounded below.
-
bound_up(BoundLike, default:None) –The upper bound on the angle, in radians. If None, unbounded above.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The angle between the edge and its reference vector.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the edge vector from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the edge.
Returns:
-
constraint(Float[Array, '']) –The angle between the edge and its reference vector, in radians.
Notes
The reference vector is read off self.vector, this element's own vector.
Node constraints¤
NodeXCoordinateConstraint
¤
Bound the X coordinate of a node between a lower and an upper value.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The X coordinate of the node.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the coordinate from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the node.
Returns:
-
constraint(Float[Array, '']) –The node's X coordinate.
NodeYCoordinateConstraint
¤
Bound the Y coordinate of a node between a lower and an upper value.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The Y coordinate of the node.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the coordinate from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the node.
Returns:
-
constraint(Float[Array, '']) –The node's Y coordinate.
NodeZCoordinateConstraint
¤
Bound the Z coordinate of a node between a lower and an upper value.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, '']
The Z coordinate of the node.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the coordinate from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The index of the node.
Returns:
-
constraint(Float[Array, '']) –The node's Z coordinate.
Vertex constraints¤
Most vertex constraints are thin counterparts of the node constraints above:
the constraint logic is inherited unchanged, while keys resolve against the
vertices of a mesh instead of the nodes of a network. Applying one to a
network raises a TypeError pointing to the Node* counterpart, and vice
versa. VertexCurvatureConstraint is mesh only and has no node counterpart:
its angle-deficit curvature needs the ordered neighbor ring that a mesh's face
winding supplies and a plain network lacks.
VertexXCoordinateConstraint
¤
Bound the X coordinate of a vertex between a lower and an upper value.
VertexYCoordinateConstraint
¤
Bound the Y coordinate of a vertex between a lower and an upper value.
VertexZCoordinateConstraint
¤
Bound the Z coordinate of a vertex between a lower and an upper value.
VertexCurvatureConstraint
¤
VertexCurvatureConstraint(key: int, polygon: Int[Array, neighbors] | Sequence[int], bound_low: BoundLike = None, bound_up: BoundLike = None)
Bound the discrete curvature at a vertex over its one-hop neighborhood.
Parameters:
-
key(int) –The key of the vertex the constraint acts on.
-
polygon(Int[Array, neighbors] | Sequence[int]) –The neighboring vertex keys forming the ordered ring around the vertex.
-
bound_low(BoundLike, default:None) –The lower bound on the curvature. If None, unbounded below.
-
bound_up(BoundLike, default:None) –The upper bound on the curvature. If None, unbounded above.
Notes
The discrete curvature is the angle deficit 2 * pi - sum(alphas), summed
over the angles between successive spokes to the neighbor ring, so it is
only meaningful when the neighbors are given in cyclic order. A mesh
supplies that order canonically through its face winding (e.g. from
compas.datastructures.Mesh.vertex_neighbors(vkey, ordered=True)); a plain
network has no faces and hence no canonical ring, which is why the
constraint is mesh only.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumMeshStructure, index: Int[Array, '']) -> Float[Array, '']
The discrete curvature at the vertex over its one-hop neighborhood.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the vertex coordinates from.
-
structure(EquilibriumMeshStructure) –The mesh structure whose vertex ordering resolves the neighbor ring.
-
index(Int[Array, '']) –The index of the vertex.
Returns:
-
constraint(Float[Array, '']) –The discrete curvature at the vertex given its neighbors' coordinates.
Notes
The neighbor ring is stored as raw vertex keys, so it is resolved to
structure indices here, inside the evaluation vmap, in a second
indices_from_keys call whose (neighbors,) query rides the map. The
canonical vertex ordering is static, so only the query search runs in
JAX.
Network constraints¤
NetworkEdgesLengthConstraint
¤
Bound the length of every edge of a network.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, edges]
The length of every edge.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the lengths from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The sentinel index, unused.
Returns:
-
constraint(Float[Array, edges]) –The length of each edge, flattened.
NetworkEdgesForceConstraint
¤
Bound the internal force of every edge of a network.
constraint
¤
constraint(eq_state: EquilibriumState, structure: EquilibriumStructure, index: Int[Array, '']) -> Float[Array, edges]
The internal force in every edge.
Parameters:
-
eq_state(EquilibriumState) –The equilibrium state to read the forces from.
-
structure(EquilibriumStructure) –The structure the constraint is evaluated against; unused.
-
index(Int[Array, '']) –The sentinel index, unused.
Returns:
-
constraint(Float[Array, edges]) –The internal force of each edge, flattened.