Source code for goflow.models.base

# @Author: Felix Kramer <felix>
# @Date:   2022-06-28T16:24:41+02:00
# @Email:  felixuwekramer@proton.me
# @Filename: base.py
# @Last modified by:   felix
# @Last modified time: 2022-07-02T14:16:48+02:00

import numpy as np
from dataclasses import dataclass, field


[docs]@dataclass class model(): """ The basic model class, acting as a center piece for 'morph' simulations, as it defines the individual dynamic system. This class defines the ODE sytem, metabolic cost model and a diverse set of functionalities for effective evaluation of any simulation's proceeding. Based on scipy.integrate.solve_ivp (1.7.3) it defines specific event handlers for stiff systems and utility functions. Attributes: ivp_options (dict):\n Information to generate the internal solver_options. Providing t0,t1 number of evaluation and x0.\n model_args (list):\n Model specific paramerets need to evaluate the update rules of the DS \n solver_options (dict):\n Specifying runtime and evaluation marks. \n events (dict):\n Events to consier, here in gernal flatlining events which allow for early termination of stiff simulations. \n null_decimals (in):\n description \n Methods: init() The model post_init function. update_event_func() Update the event function and ensures that solver_options are set. flatlining_default(t, x_0, *args) The default flatlining function for determining the terminal event of the dynamical system. flatlining_dynamic(t, x_0, *args) The dynamic flatlining function for determining the terminal event of the dynamical system. set_model_parameters(model_pars) Set internal model arguments array. set_solver_options(solv_opt) Set internal solver_options and update event function. calc_update_stimuli(t, x_0, *args) The dynamic system's temporal update rule, computing the gradient -dF for dx/dt. calc_cost_stimuli(t, x_0, *args) Computes the dynamic system's Lyapunov function and its gradient. """ defVals = dict(init=False, repr=False) ivp_options: dict = field(default_factory=dict, **defVals) model_args: list = field(default_factory=list, **defVals) solver_options: dict = field(default_factory=dict, init=False, repr=True) events: dict = field(default_factory=dict, **defVals) null_decimal: int = field(default=6, **defVals) # jac: bool = field(default=False, **defVals) def __post_init__(self): self.init()
[docs] def init(self): """ The model post_init function. Setting proxy values for internal variables. """ self.ivp_options = { 't0': 0., 't1': 1., 'x0': 1, 'num': 100, } self.model_args = [] self.solver_options = { 't_eval': np.linspace( self.ivp_options['t0'], self.ivp_options['t1'], num=self.ivp_options['num'] ) } self.events = { 'default': self.flatlining_default, 'dynamic': self.flatlining_dynamic, }
[docs] def update_event_func(self): """ Update the event function and ensures that solver_options are set. Raises: Exception: \\n Warning: Event handling got inadequadt event function, falling back to default """ try: kw = self.solver_options['events'] self.solver_options['events'] = self.events[kw] except Exception: print( """ Warning: Event handling got inadequadt event function, falling back to default """ ) self.solver_options['events'] = self.events['default']
[docs] def flatlining_default(self, t, x_0, *args): """ The default flatlining function for determining the terminal event of the dynamical system. Based on the event handling schemes of scipy.integrate.solve_ivp (1.7.3), has the same call signature as calc_update_stimuli(). The method checks whether the system's Lyapunov function has decreased beneath a certain threshold. Args: t (float):\n Current time step in numeric ODE evaluation \n x_0 (array):\n Current state vector of the DS. \n args (iterable):\n Model specific tuple of parameters, same signature as needed for calc_update_stimuli. \n Returns: float: \n z, the signature of sign change, signaling the internal threshold being passed. """ F, dF = self.calc_cost_stimuli(t, x_0, *args) dF_abs = np.linalg.norm(dF) quality = np.round(np.divide(dF_abs, F), self.null_decimal) z = quality - np.power(10., -(self.null_decimal-1)) # print(f'ref: {z}') # print(f't: {t}') return z
[docs] def flatlining_dynamic(self, t, x_0, *args): """ The dynamic flatlining function for determining the terminal event of the dynamical system. Based on the event handling schemes of scipy.integrate.solve_ivp (1.7.3), has the same call signature as calc_update_stimuli(). The method checks whether the magnitude of relative change of the state vector x_0 has decreased beneath a certain threshold. Args: t (float):\n Current time step in numeric ODE evaluation \n x_0 (array):\n Current state vector of the DS. \n args (iterable):\n Model specific tuple of parameters, same signature as needed for calc_update_stimuli. \n Returns: float: \n z, the signature of sign change, signaling the internal threshold being passed. """ dx = self.calc_update_stimuli(t, x_0, *args) dx_abs = np.absolute(dx) rel_r = np.divide(dx_abs, x_0) quality = np.round(np.linalg.norm(rel_r), self.null_decimal) z = quality-np.power(10., -(self.null_decimal-1)) return z
for f in [flatlining_default, flatlining_dynamic]: f.terminal = True f.direction = 1.
[docs] def set_model_parameters(self, model_pars): """ Set internal model arguments array. Args: model_pars (dict):\n Model argument dictionary generated on program initilization. \n """ for k, v in model_pars.items(): self.model_args.append(v)
[docs] def set_solver_options(self, solv_opt): """ Set internal solver_options and update event function. Args: solv_opt (dict):\n Solver argument dictionary generated on program initilization. \n """ for k, v in solv_opt.items(): self.solver_options[k] = v self.update_event_func()
[docs] def calc_update_stimuli(self, t, x_0, *args): """ The dynamic system's temporal update rule, computing the gradient -dF for dx/dt. Args: t (float):\n Current time step in numeric ODE evaluation \n x_0 (array):\n Current state vector of the DS. \n args (iterable):\n Model specific tuple of parameters, needed to evaluate stimulus functions \n Returns: array: \n The computed change dx to the state vector x_0. """ dx = np.array() return dx
[docs] def calc_cost_stimuli(self, t, x_0, *args): """ Computes the dynamic system's Lyapunov function and its gradient. Args: t (float):\n Current time step in numeric ODE evaluation \n x_0 (array):\n Current state vector of the DS. \n args (iterable):\n Model specific tuple of parameters, needed to evaluate stimulus ] functions \n Returns: iterable: \n The computed gradient dF to the current cost function F, as well as F itself. """ F = np.array() dF = np.array() return F, dF