def set_state(self, state: Dict): self.x = state["x"] self.v = state["v"] Example: Simple controller (P-controller) ---------------------------------------------------------------------- class PController(XModModel): """Outputs F = Kp * (x_ref - x_measured)."""

def run(self, t_start: float, t_end: float, log_callback: Callable = None): t = t_start outputs = {name: {} for name in self.models} while t < t_end - 1e-12: # Gather all inputs for each model from previous outputs inputs_for = {name: {} for name in self.models} for fm, fp, tm, tp in self.connections: if fm in outputs and fp in outputs[fm]: inputs_for[tm][tp] = outputs[fm][fp] # Step each model new_outputs = {} for name, model in self.models.items(): step_result = model.step(t, self.dt, inputs_for[name]) new_outputs[name] = step_result.outputs outputs = new_outputs t += self.dt if log_callback: log_callback(t, outputs)

@abstractmethod def get_state(self) -> Dict: """For checkpoint/rollback.""" pass

def __init__(self, name: str): self.name = name self.input_ports: List[XModPort] = [] self.output_ports: List[XModPort] = []

def step(self, t: float, dt: float, inputs: Dict[str, np.ndarray]) -> XModStep: F_ext = inputs.get("F_ext", np.array([0.0]))[0] # Simple semi-implicit Euler a = (F_ext - self.k * self.x - self.c * self.v) / self.m self.v += a * dt self.x += self.v * dt return XModStep( outputs={"x": np.array([self.x]), "v": np.array([self.v])}, new_time=t + dt )