Skip to content

hybrid_system

Hybrid system core types.

FlowFunction

Bases: Protocol

Continuous dynamics callback.

EventSurfaceFunction

Bases: Protocol

Scalar event-surface callback.

ResetFunction

Bases: Protocol

State reset callback.

CrossingDirection

Bases: IntEnum

Direction in which an event surface must cross zero.

ContinuousDynamics(flow, label=None) dataclass

Reusable continuous dynamics definition.

Parameters:

Name Type Description Default
flow Callable[..., Derivative]

Dynamics function returning the state derivative. Scalar derivative returns are accepted only for single-state systems, both during solver evaluation and when derivatives are captured on the returned trace grid.

required
label str | None

Optional display label.

None

Location(dynamics, *, label=None, parameters=None) dataclass

Location(
    dynamics: ContinuousDynamics,
    *,
    label: str | None = None,
    parameters: Parameters | None = None,
)
Location(
    dynamics: Callable[..., Derivative],
    *,
    label: str | None = None,
    parameters: Parameters | None = None,
)

Discrete hybrid-automaton location.

Parameters:

Name Type Description Default
dynamics ContinuousDynamics | Callable[..., Derivative]

Continuous dynamics or bare flow callback active here.

required
label str | None

Optional display label.

None
parameters Parameters | None

Location-local parameter map.

None
Source code in src/flowcean/ode/hybrid_system.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def __init__(
    self,
    dynamics: ContinuousDynamics | Callable[..., Derivative],
    *,
    label: str | None = None,
    parameters: Parameters | None = None,
) -> None:
    if isinstance(dynamics, ContinuousDynamics):
        continuous_dynamics = dynamics
    elif callable(dynamics):
        continuous_dynamics = ContinuousDynamics(dynamics)
    else:
        message = (
            "Location requires ContinuousDynamics or a flow callback."
        )
        raise TypeError(message)
    if parameters is not None and not isinstance(parameters, Mapping):
        message = "parameters must be a mapping."
        raise TypeError(message)
    object.__setattr__(self, "dynamics", continuous_dynamics)
    object.__setattr__(self, "label", label)
    object.__setattr__(self, "parameters", dict(parameters or {}))

EventSurface(fn, direction=CrossingDirection.EITHER, label=None) dataclass

Scalar event surface defining a simulated transition event.

Flowcean transitions fire when fn reaches zero in direction. This is event-surface semantics, not Boolean guard-region semantics.

Parameters:

Name Type Description Default
fn Callable[..., float]

Root function; transitions when it crosses zero.

required
direction CrossingDirection

Crossing direction. Defaults to either direction.

EITHER
label str | None

Optional display label.

None

Reset(fn, label=None) dataclass

State reset applied on a transition.

Parameters:

Name Type Description Default
fn Callable[..., State]

Reset function applied at the event time.

required
label str | None

Optional display label.

None

Transition(source, target, event, reset=None) dataclass

Discrete event-triggered transition between locations.

event is a scalar zero-crossing surface.

Parameters:

Name Type Description Default
source Location

Source location.

required
target Location

Target location.

required
event EventSurface | Callable[..., float]

Event surface that triggers the transition.

required
reset Reset | Callable[..., State] | None

Optional reset applied upon transition.

None
Source code in src/flowcean/ode/hybrid_system.py
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def __init__(
    self,
    source: Location,
    target: Location,
    event: EventSurface | Callable[..., float],
    reset: Reset | Callable[..., State] | None = None,
) -> None:
    if not isinstance(source, Location):
        message = "source must be a Location."
        raise TypeError(message)
    if not isinstance(target, Location):
        message = "target must be a Location."
        raise TypeError(message)
    if isinstance(event, EventSurface):
        event_surface = event
    elif callable(event):
        event_surface = EventSurface(event)
    else:
        message = "event must be an EventSurface or callable."
        raise TypeError(message)
    if isinstance(reset, Reset) or reset is None:
        transition_reset = reset
    elif callable(reset):
        transition_reset = Reset(reset)
    else:
        message = "reset must be a Reset, callable, or None."
        raise TypeError(message)
    object.__setattr__(self, "source", source)
    object.__setattr__(self, "target", target)
    object.__setattr__(self, "event", event_surface)
    object.__setattr__(self, "reset", transition_reset)

HybridSystem(locations, transitions, initial_location, initial_state, parameters=dict()) dataclass

Hybrid system with locations and transitions.

Parameters:

Name Type Description Default
locations Sequence[Location]

Location objects in this system.

required
transitions Sequence[Transition]

Transition list defining event surfaces and resets.

required
initial_location Location

Starting location object.

required
initial_state State

Initial state vector.

required
parameters Parameters

Global parameter map passed to callbacks.

dict()

transitions_from(location)

Return transitions leaving the given location.

Source code in src/flowcean/ode/hybrid_system.py
292
293
294
295
296
297
298
def transitions_from(self, location: Location) -> list[Transition]:
    """Return transitions leaving the given location."""
    return [
        transition
        for transition in self.transitions
        if transition.source is location
    ]

Event(time, source_location, target_location, event_surface, reset, state) dataclass

Transition event information for a trace.

Trace(t, x, location, events, u=None, dx=None) dataclass

Simulation trace with time, state, and location labels.

as_dict()

Return a dictionary view of the trace.

Source code in src/flowcean/ode/hybrid_system.py
365
366
367
368
369
370
371
372
373
374
def as_dict(self) -> dict[str, object]:
    """Return a dictionary view of the trace."""
    return {
        "t": self.t,
        "x": self.x,
        "location": self.location,
        "events": self.events,
        "u": self.u,
        "dx": self.dx,
    }

display_label(obj)

Return the human-readable label for a hybrid-system object.

Source code in src/flowcean/ode/hybrid_system.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
def display_label(obj: object) -> str:
    """Return the human-readable label for a hybrid-system object."""
    if isinstance(obj, Location):
        return (
            obj.label
            or obj.dynamics.label
            or _callback_label(obj.dynamics.flow)
            or repr(obj)
        )
    if isinstance(obj, ContinuousDynamics):
        return obj.label or _callback_label(obj.flow) or repr(obj)
    if isinstance(obj, EventSurface):
        return obj.label or _callback_label(obj.fn) or repr(obj)
    if isinstance(obj, Reset):
        return obj.label or _callback_label(obj.fn) or repr(obj)
    return repr(obj)