API Reference

Class and method signatures for Molenspin 0.4.x. Generated from source docstrings; last updated 2026-05-08.

molenspin.Assembly

class Assembly(
    name: str = "assembly",
    gravity: float = 9.81,
    default_module: float = 2.0,
    backlash: float = 0.0,
    frame_origin: tuple[float, float] = (0.0, 0.0),
)

Top-level container for a kinematic model.

Assembly.add_shaft

def add_shaft(
    omega_rpm: float | None = None,
    omega_rad: float | None = None,
    name: str = "",
) -> Shaft

Add a shaft. Specify angular velocity in RPM or rad/s (not both). If neither is given, the shaft is free and its velocity is determined by constraints.

Assembly.add_gear

def add_gear(
    teeth: int,
    driven_by: Shaft | None = None,
    meshes_with: Gear | None = None,
    module: float | None = None,
    pressure_angle: float = 20.0,
    helix_angle: float = 0.0,
    name: str = "",
) -> Gear

Assembly.simulate

def simulate(
    duration: float,
    dt: float = 1e-3,
    integrator: str = "rk4",
    rtol: float = 1e-6,
    atol: float = 1e-9,
    warm_start: bool = True,
    record_contacts: bool = False,
) -> SimResult

molenspin.Shaft

class Shaft:
    name: str
    omega_rpm: float       # current angular velocity in RPM
    omega_rad: float       # current angular velocity in rad/s
    theta: float           # current angular position in radians

molenspin.Gear

class Gear:
    teeth: int
    module: float
    shaft: Shaft           # the shaft this gear sits on
    pitch_radius: float    # = module * teeth / 2  (mm)
    name: str

molenspin.SimResult

class SimResult:
    dt: float
    n_steps: int
    shafts: dict[str, ShaftHistory]

    def print_summary(self) -> None: ...
    def export_svg(self, path: str, fps: int = 30,
                   duration: float | None = None, **kwargs) -> None: ...
    def export_json(self, path: str, indent: int = 0) -> None: ...

molenspin.ShaftHistory

class ShaftHistory:
    name: str
    omega_history: np.ndarray   # shape (n_steps,), rad/s
    theta_history: np.ndarray   # shape (n_steps,), radians
    omega_rpm: float            # final value
    n_revolutions: float        # total revolutions over simulation

molenspin.BevelPair

class BevelPair:
    def __init__(
        self,
        gear_a: Gear,
        gear_b: Gear,
        shaft_angle: float = 90.0,
    ): ...

molenspin.BeltDrive

class BeltDrive:
    def __init__(
        self,
        sprocket_driver: Gear,
        sprocket_driven: Gear,
        slip: float = 0.0,
    ): ...

molenspin.Constraint (base class)

class Constraint:
    """Subclass this to add custom algebraic constraints."""
    def residual(self, state: np.ndarray) -> float: ...
    def jacobian(self, state: np.ndarray) -> np.ndarray: ...

Custom constraints are registered with asm.add_constraint(my_constraint). See the geometry engine post for an example of a fixed-pivot constraint used in the windmill model.

Exceptions

ExceptionRaised when
ms.OverdeterminedErrorThe constraint graph has more equations than degrees of freedom.
ms.UnderdeterminedErrorAt least one shaft has no constraints and is free-floating.
ms.ConvergenceErrorThe Newton solver didn't converge within the maximum iterations.
ms.TopologyErrorA gear mesh creates a cycle in the assembly graph.