Source code for sproclib.unit.base.ProcessModel

"""
Base classes for SPROCLIB - Standard Process Control Library

This module provides the abstract base class for all process models.

Author: Thorsten Gressling <gressling@paramus.ai>
License: MIT License
"""

import numpy as np
import logging
from typing import Optional, Tuple, Dict, Any, List, Callable
from abc import ABC, abstractmethod
from scipy.integrate import solve_ivp

logger = logging.getLogger(__name__)


[docs] class ProcessModel(ABC): """Abstract base class for process models."""
[docs] def __init__(self, name: str = "ProcessModel"): """ Initialize process model. Args: name: Model name for identification """ self.name = name self.parameters = {} self.state_variables = {} self.inputs = {} self.outputs = {}
[docs] @abstractmethod def dynamics(self, t: float, x: np.ndarray, u: np.ndarray) -> np.ndarray: """ Define the process dynamics dx/dt = f(t, x, u). Args: t: Time x: State variables u: Input variables Returns: State derivatives dx/dt """ pass
[docs] @abstractmethod def steady_state(self, u: np.ndarray) -> np.ndarray: """ Calculate steady-state values for given inputs. Args: u: Input variables Returns: Steady-state values """ pass
[docs] def simulate( self, t_span: Tuple[float, float], x0: np.ndarray, u_func: Callable[[float], np.ndarray], t_eval: Optional[np.ndarray] = None ) -> Dict[str, np.ndarray]: """ Simulate the process model. Args: t_span: Time span (t_start, t_end) x0: Initial conditions u_func: Function returning inputs as function of time t_eval: Time points for output (optional) Returns: Dictionary with 't', 'x', 'u' arrays """ def rhs(t, x): u = u_func(t) return self.dynamics(t, x, u) sol = solve_ivp(rhs, t_span, x0, t_eval=t_eval, dense_output=True) if t_eval is None: t_eval = sol.t u_values = np.array([u_func(t) for t in t_eval]) return { 't': t_eval, 'x': sol.sol(t_eval), 'u': u_values.T }
[docs] def get_info(self) -> Dict[str, Any]: """ Get model information summary. Returns: Dictionary with model information """ return { 'name': self.name, 'type': self.__class__.__name__, 'parameters': self.parameters, 'n_states': len(self.state_variables), 'n_inputs': len(self.inputs), 'n_outputs': len(self.outputs) }
[docs] def update_parameters(self, **kwargs): """ Update model parameters. Args: **kwargs: Parameter updates """ for key, value in kwargs.items(): if hasattr(self, key): setattr(self, key, value) self.parameters[key] = value else: logger.warning(f"Parameter '{key}' not found in model '{self.name}'")