Skip to content

trusty.subspace

Subspace (reduced-order) runtime + offline precompute.

The offline tooling at :mod:trusty.subspace.precompute produces a .basis file (modal eigenmodes packed against a hex mesh). At runtime, attach a subspace body to the world with :func:add_hex_body / :func:add_tet_body; the composer scans the world for SubspaceBody components and wires the subspace module automatically. Contact for any subspace body (subspace floor, FEM floor, cross-block subspace<->FEM) is governed by the single trusty.contact.enable knob shared by every module in the simulator.

Basis

actuation

actuation(world: World, muscle: int) -> float

Current actuation (alpha) of body's muscle.

add_hex_body

add_hex_body(
    world: World,
    rest_mesh: HexMesh,
    material: StableNeoHookean
    | Corotational
    | StableFung
    | NeohookeanBW
    | ARAP
    | QuadraticVolume,
    density: float,
    basis: Basis,
    *,
    project_positive_definite: bool = True,
    friction_mu: float = 0.0,
) -> int

Add a Q1 hex subspace body carrying basis (from subspace.load). The composer activates the subspace module automatically when any world body has this tag.

add_muscle

add_muscle(
    world: World,
    body: int,
    directions: ndarray[float64, (N, 3)],
    stiffness: float,
) -> int

Attach a muscle fiber field to body. directions is the rest-frame fiber, (num_elements, 3) for curved fibers or (1, 3) to broadcast one direction; stiffness is the fixed gain. Returns the muscle's index (its handle for set_actuation / actuation). The live actuation starts at 0.

Call before building the body's basis -- the basis precompute reads the world's muscles to build the operator it decomposes.

add_tet_body

add_tet_body(
    world: World,
    rest_mesh: TetMesh,
    material: StableNeoHookean
    | Corotational
    | StableFung
    | NeohookeanBW
    | ARAP
    | QuadraticVolume,
    density: float,
    basis: Basis,
    *,
    project_positive_definite: bool = True,
    friction_mu: float = 0.0,
) -> int

Tet counterpart of add_hex_body.

deformed_positions

deformed_positions(
    world: World, body: int
) -> ndarray[float64, (N, 3)]

Current deformed node positions of subspace body as an (N, 3) numpy array. The rest mesh before the first step.

fem_rest_operator

fem_rest_operator(
    world: World,
) -> scipy.sparse.csc_matrix[float]

Full-space rest stiffness operator (3N, 3N) of the world's single FEM solid: the elastic K plus every muscle (add_muscle) the world declares, at the gain it is simulated with. This is the operator the basis is decomposed from, so declaring a muscle on the precompute world is all it takes for the basis to account for it. Attachments are deliberately excluded -- a bond is a both-sided coupled term whose stiffness on the follower depends on how freely its anchor moves, so folding a grounded k I3 would delete the follower motion a movable anchor exists to permit.

fem_elastic_stiffness_matrix

fem_elastic_stiffness_matrix(
    world: World,
) -> scipy.sparse.csc_matrix[float]

Elastic stiffness (3N, 3N) at the rest configuration of the world's single FEM solid -- the elastic block of fem_rest_operator.

fem_muscle_stiffness_matrix

fem_muscle_stiffness_matrix(
    world: World,
) -> scipy.sparse.csc_matrix[float]

Muscle stiffness (3N, 3N) at rest: sum_muscles A_musc, without the elastic block. Only the activation-mode solve needs this alone (its rest contraction force is -A_musc x0); the eigenproblem wants fem_rest_operator.

fem_mass_matrix

fem_mass_matrix(world: World) -> ndarray[float64, (N,)]

Lumped nodal mass of the world's single FEM solid as a length-3N diagonal, each node's mass repeated 3 times (scalar-DOF indexable).

fem_pinned_dofs

fem_pinned_dofs(world: World) -> list[int]

Sorted scalar DOF indices the world pinned via fem.pin_face. Slice these out before a generalised eigensolve.

load

load(path: str) -> Basis

Parse a .basis file into an opaque Basis handle. Pass the result to add_hex_body / add_tet_body. Cache the handle to share one basis across multiple bodies without re-parsing.

num_bodies

num_bodies(world: World) -> int

Number of subspace bodies in the world.

num_muscles

num_muscles(world: World, body: int) -> int

Number of muscles attached to subspace body.

read_state

read_state(
    world: World, body: int
) -> ndarray[float64, (N,)]

Reduced state z of subspace body after the last accepted step. Returns a length-r numpy array, zero before the first step.

set_actuation

set_actuation(
    world: World, muscle: int, value: float
) -> None

Set the actuation (alpha) of body's muscle. Scales the precomputed muscle force/stiffness; takes effect on the next step.