Skip to content

Loads API

Loads describe excitation independently of the structural model. Every load produces a LoadHistory containing a (n_positions, n_time) diagnostic field and, when applicable, exact point-force components. The solver owns projection onto the system coordinates.

from dynaresp import loads

load = loads.Harmonic(position=1.0, amplitude=100.0, frequency=3.0)

Use the excitation guide to choose between point, function, and moving loads.

Shared interface

Load

Bases: ABC

Base class for a reusable excitation strategy.

A load is configuration only. Calling :meth:generate evaluates it on caller-supplied axes and creates a fresh random stream from seed.

generate

generate(time, positions, *, seed=None)

Generate a load history on caller-supplied axes.

Parameters:

Name Type Description Default
time ArrayLike

Uniform time axis in seconds.

required
positions ArrayLike

Reporting positions or DOF indices.

required
seed int | None

Seed for this generation call. The same load, axes, and seed reproduce stochastic histories without using NumPy's global random state.

None

Returns:

Type Description
LoadHistory

A history whose values shape is

LoadHistory

(len(positions), len(time)).

Source code in src/dynaresp/loads/base.py
def generate(
    self,
    time: ArrayLike,
    positions: ArrayLike,
    *,
    seed: int | None = None,
) -> LoadHistory:
    """Generate a load history on caller-supplied axes.

    Args:
        time: Uniform time axis in seconds.
        positions: Reporting positions or DOF indices.
        seed: Seed for this generation call. The same load, axes, and seed
            reproduce stochastic histories without using NumPy's global
            random state.

    Returns:
        A history whose ``values`` shape is
        ``(len(positions), len(time))``.
    """
    return self._generate(
        validate_time(time),
        validate_positions(positions),
        np.random.default_rng(seed),
    )

to_config

to_config()

Return a JSON-compatible description of this load.

Source code in src/dynaresp/loads/base.py
def to_config(self) -> dict[str, object]:
    """Return a JSON-compatible description of this load."""
    if not is_dataclass(self):
        return {"type": type(self).__name__}
    config: dict[str, object] = {"type": type(self).__name__}
    for field in fields(self):
        value = getattr(self, field.name)
        if isinstance(value, np.ndarray):
            config[field.name] = value.tolist()
        elif callable(value):
            config[field.name] = getattr(value, "__qualname__", repr(value))
        else:
            config[field.name] = value
    return config

LoadHistory dataclass

LoadHistory(
    time,
    positions,
    distributed_values,
    description,
    point_forces=(),
)

Generated load data on explicit time and reporting-position axes.

Parameters:

Name Type Description Default
time FloatArray

Increasing, uniformly sampled time values in seconds, shape (n_time,).

required
positions FloatArray

Increasing reporting positions, shape (n_position,). For a beam these are physical coordinates; for an MDOF system they are integer-valued DOF indices.

required
distributed_values FloatArray

Force values genuinely distributed over the reporting grid, with shape (n_position, n_time).

required
description dict[str, object]

JSON-compatible load configuration.

required
point_forces tuple[PointForceComponent, ...]

Exact point-force components projected without snapping.

()

values is a cached reporting raster derived from distributed_values and the nearest-grid representation of every point force. The solver uses the canonical fields directly, so reporting cannot change the projection.

values cached property

values

Complete nearest-grid raster for reporting and storage.

PointForceComponent dataclass

PointForceComponent(
    positions, values, active, clip_outside=False
)

An exact point-force trajectory sampled on the simulation time axis.

Parameters:

Name Type Description Default
positions FloatArray

Physical position or discrete DOF index at every time sample, with shape (n_time,).

required
values FloatArray

Signed force values, with shape (n_time,). Units follow the system's force convention (normally newtons).

required
active NDArray[bool_]

Boolean mask selecting samples at which the force exists.

required
clip_outside bool

When true, project through :meth:~dynaresp.systems.StructuralSystem.force_vector, allowing a bounded system to return zero while a moving force is off-system. When false, invalid positions are reported by observation_vector instead of being silently ignored.

False

The arrays are copied and made read-only. positions are never snapped before the simulation projects the force into generalized coordinates.

rasterize

rasterize(axis)

Return a nearest-grid representation for reporting and storage.

The result has shape (n_position, n_time). Inactive samples and positions outside axis remain zero. This representation is a diagnostic only; the simulator projects the exact trajectory instead.

Source code in src/dynaresp/loads/base.py
def rasterize(self, axis: FloatArray) -> FloatArray:
    """Return a nearest-grid representation for reporting and storage.

    The result has shape ``(n_position, n_time)``. Inactive samples and
    positions outside ``axis`` remain zero. This representation is a
    diagnostic only; the simulator projects the exact trajectory instead.
    """
    field = np.zeros((axis.size, self.positions.size), dtype=np.float64)
    columns = np.flatnonzero(
        self.active & (self.positions >= axis[0]) & (self.positions <= axis[-1])
    )
    if columns.size:
        rows = np.argmin(
            np.abs(axis[:, None] - self.positions[columns][None, :]),
            axis=0,
        )
        field[rows, columns] += self.values[columns]
    return field

Fixed-position loads

WhiteNoise dataclass

WhiteNoise(rms, position=0.0, mean=0.0)

Bases: Load

Independent Gaussian force samples at one exact position.

Parameters:

Name Type Description Default
rms float

Standard deviation of the random force (and RMS when mean is zero), normally in newtons.

required
position float

Physical coordinate or integer DOF index of the point force.

0.0
mean float

Mean force in the same units as rms.

0.0

Pass a seed to :meth:Load.generate for a reproducible realization. The force is projected at position without snapping to the reporting grid.

Harmonic dataclass

Harmonic(
    amplitude,
    frequency,
    position=0.0,
    phase=0.0,
    start_time=0.0,
)

Bases: Load

A sinusoidal force switched on at one exact position and time.

Parameters:

Name Type Description Default
amplitude float

Signed peak force, normally in newtons.

required
frequency float

Frequency in hertz; zero is allowed.

required
position float

Physical coordinate or integer DOF index of the point force.

0.0
phase float

Phase at start_time in radians.

0.0
start_time float

Switch-on time in seconds. The force is zero before it.

0.0

Chirp dataclass

Chirp(
    amplitude,
    start_frequency,
    end_frequency,
    position=0.0,
    start_time=0.0,
    sweep_duration=None,
    method="linear",
)

Bases: Load

A finite-duration sinusoidal frequency sweep at one exact position.

Parameters:

Name Type Description Default
amplitude float

Signed peak force, normally in newtons.

required
start_frequency float

Positive initial frequency in hertz.

required
end_frequency float

Positive final frequency in hertz.

required
position float

Physical coordinate or integer DOF index of the point force.

0.0
start_time float

Sweep start in seconds; force is zero before this time.

0.0
sweep_duration float | None

Sweep duration in seconds. When omitted, the sweep ends at the final simulation time.

None
method Literal['linear', 'logarithmic']

"linear" or "logarithmic" frequency interpolation.

'linear'

Samples at and beyond start_time + sweep_duration are zero.

Impulse dataclass

Impulse(magnitude, position=0.0, time=0.0)

Bases: Load

A point impulse represented at the nearest simulation time sample.

Parameters:

Name Type Description Default
magnitude float

Signed impulse, normally in newton-seconds.

required
position float

Physical coordinate or integer DOF index of the point force.

0.0
time float

Requested impulse time in seconds; it must lie inside the simulation window.

0.0

The selected sample receives magnitude / dt, preserving the requested impulse under rectangular integration on the uniform time axis. Spatial projection still uses the exact position.

TimeSeries dataclass

TimeSeries(
    values, position=0.0, sample_times=None, scale=1.0
)

Bases: Load

A measured or prescribed force history at one exact position.

Parameters:

Name Type Description Default
values ArrayLike

Non-empty finite force samples, normally in newtons.

required
position float

Physical coordinate or integer DOF index of the point force.

0.0
sample_times ArrayLike | None

Optional increasing sample times in seconds. When given, values are linearly interpolated onto the simulation time axis and are zero outside this interval. When omitted, values must match the simulation time axis one-for-one.

None
scale float

Multiplicative factor applied after interpolation.

1.0

Input arrays are copied and made read-only during construction.

Custom force functions

ForceFunction module-attribute

ForceFunction = Callable[[ForceInput], ArrayLike]

ForceInput dataclass

ForceInput(time, positions, rng)

Validated inputs supplied to a custom force callback.

Parameters:

Name Type Description Default
time FloatArray

Uniform time axis in seconds, shape (n_time,).

required
positions FloatArray

Reporting coordinates or DOF indices, shape (n_position,).

required
rng Generator

Generator dedicated to this load evaluation. A callback must use this generator, rather than NumPy's global RNG, for reproducible stochastic fields.

required

FunctionLoad dataclass

FunctionLoad(function)

Bases: Load

A distributed force field generated by a user callback.

function receives :class:ForceInput and must return finite values with shape (n_position, n_time). The result is projected as a raster field. Use :class:~dynaresp.loads.PointForceComponent in a custom :class:~dynaresp.loads.Load when exact off-grid point coordinates matter.

function_name property

function_name

Stable registry name used in serialized configurations.

to_config

to_config()

Return the callback's module-qualified name for provenance.

Source code in src/dynaresp/loads/function.py
def to_config(self) -> dict[str, object]:
    """Return the callback's module-qualified name for provenance."""
    return {
        "type": type(self).__name__,
        "function": self.function_name,
    }

Moving loads

MovingLoad dataclass

MovingLoad(
    value, speed, start_position=0.0, start_time=0.0
)

Bases: Load

A point force following a constant-speed trajectory.

Parameters:

Name Type Description Default
value float

Signed force, normally in newtons.

required
speed float

Non-zero travel speed in position units per second. Its sign selects the travel direction.

required
start_position float

Exact force position at start_time.

0.0
start_time float

Time in seconds at which the force becomes active.

0.0

The exact position is start_position + speed * (time - start_time). LoadHistory.values snaps it to the nearest reporting position only for inspection; simulation projects the exact position. On bounded systems such as beams, the force is zero after it moves outside the structure.

TwoWheelLoad dataclass

TwoWheelLoad(
    front_load,
    rear_load,
    speed,
    wheel_spacing,
    start_position=0.0,
    start_time=0.0,
)

Bases: Load

Two constant-speed point forces separated by a fixed spacing.

Parameters:

Name Type Description Default
front_load float

Signed force carried by the front wheel, normally newtons.

required
rear_load float

Signed force carried by the rear wheel, normally newtons.

required
speed float

Non-zero speed in position units per second; sign gives travel direction.

required
wheel_spacing float

Positive distance between the exact wheel coordinates.

required
start_position float

Front-wheel position at start_time.

0.0
start_time float

Time in seconds at which both wheel forces become active.

0.0

Both trajectories retain exact coordinates for simulation. Their nearest-grid raster in LoadHistory.values is diagnostic.

RunnerLoad dataclass

RunnerLoad(
    mass,
    speed,
    step_frequency,
    contact_duration,
    start_position=0.0,
    start_time=0.0,
    gravity=9.81,
)

Bases: Load

Successive half-sine foot-contact forces along a travel path.

Parameters:

Name Type Description Default
mass float

Runner mass in kilograms.

required
speed float

Non-zero travel speed in position units per second; sign gives direction.

required
step_frequency float

Contact frequency in hertz.

required
contact_duration float

Duration of each contact in seconds. It cannot exceed one step period.

required
start_position float

Origin of the contact path.

0.0
start_time float

Origin time of the step sequence, in seconds.

0.0
gravity float

Gravitational acceleration in position units per second squared; defaults to 9.81.

9.81

Each contact is stationary at its exact landing position and has impulse mass * gravity / step_frequency. Exact contacts drive the simulation; the position-by-time raster is for reporting.

Composition

SumLoad dataclass

SumLoad(loads)

Bases: Load

Superposition of two or more loads evaluated on the same axes.

A generation seed deterministically creates one independent child stream per load. Distributed fields and exact point-force components retain their separate projection semantics when combined.

to_config

to_config()

Return child load descriptions in their evaluation order.

Source code in src/dynaresp/loads/base.py
def to_config(self) -> dict[str, object]:
    """Return child load descriptions in their evaluation order."""
    return {
        "type": type(self).__name__,
        "loads": [load.to_config() for load in self.loads],
    }