示例#1
0
    def compute_SSM(self, normalize=False, **kwargs):
        """
        Returns the sensitivity coefficients 
        S_j for each parameter p_j. 
        The sensitivity coefficients are written 
        in a sensitivity matrix SSM of size 
        len(timepoints) x len(params) x n
        If normalize argument is true, 
        the coefficients are normalized by 
        the nominal value of each paramneter.
        Use mode = 'accurate' for this object attribute 
        to use accurate computations using numdifftools.
        """
        if 'mode' in kwargs:
            if kwargs.get('mode') == 'accurate_SSM':
                return self.solve_extended_ode(**kwargs)

        def sens_func(t, x, J, Z):
            # forms ODE to solve for sensitivity coefficient S
            dsdt = J @ x + Z
            return dsdt

        P = self.params_values
        S0 = np.zeros(self.n)  # Initial value for S_i
        SSM = np.zeros((len(self.timepoints), len(P), self.n))
        # solve for all x's in timeframe set by timepoints
        system_obj = self.get_system()
        sol = utils.get_ODE(system_obj, self.timepoints).solve_system().T
        xs = sol
        xs = np.reshape(xs, (len(self.timepoints), self.n))
        self.xs = xs
        # Solve for SSM at each time point
        for k in range(len(self.timepoints)):
            # print('for timepoint',self.timepoints[k])
            timepoints = self.timepoints[0:k + 1]
            if len(timepoints) == 1:
                continue
            # get the jacobian matrix
            J = self.compute_J(xs[k, :], **kwargs)
            #Solve for S = dx/dp for all x and all P (or theta, the parameters) at time point k
            for j in range(len(P)):
                utils.printProgressBar(int(j + k * len(P)),
                                       len(self.timepoints) * len(P) - 1,
                                       prefix='SSM Progress:',
                                       suffix='Complete',
                                       length=50)
                # print('for parameter',P[j])
                # get the pmatrix
                Zj = self.compute_Zj(xs[k, :], j, **kwargs)
                # solve for S
                sens_func_ode = lambda t, x: sens_func(t, x, J, Zj)
                sol = odeint(sens_func_ode, S0, timepoints, tfirst=True)
                S = sol
                S = np.reshape(S, (len(timepoints), self.n))
                SSM[k, j, :] = S[k, :]
        self.SSM = SSM
        if normalize:
            SSM = self.normalize_SSM(
            )  #Identifiablity was estimated using an normalized SSM
        return SSM
 def get_robustness_metric(self, reduced_sys):
     # Create an option so the default way this is
     # done is given two systems compute robustness metric.
     # Implementing Theorem 2
     timepoints_ssm = self.timepoints_ssm
     _, x_sols, full_ssm = self.get_solutions()
     S = full_ssm.compute_SSM()
     self.S = S
     reduced_ssm = utils.get_SSM(reduced_sys, timepoints_ssm)
     x_sols_hat = utils.get_ODE(reduced_sys,
                                timepoints_ssm).solve_system().T
     x_sols = np.reshape(x_sols, (len(timepoints_ssm), self.n))
     x_sols_hat = np.reshape(x_sols_hat,
                             (len(timepoints_ssm), reduced_sys.n))
     Se = np.zeros(len(self.params_values))
     S_hat = reduced_ssm.compute_SSM()
     reduced_sys.S = S_hat
     S_bar = np.concatenate((S, S_hat), axis=2)
     S_bar = np.reshape(S_bar, (len(timepoints_ssm), self.n + reduced_sys.n,
                                len(self.params_values)))
     for j in range(len(self.params_values)):
         S_metric_max = 0
         for k in range(len(self.timepoints_ssm)):
             J = full_ssm.compute_J(x_sols[k, :])
             J_hat = reduced_ssm.compute_J(x_sols_hat[k, :])
             J_bar = block_diag(J, J_hat)
             # print(J)
             # print(J_bar)
             C_bar = np.concatenate((self.C, -1 * reduced_sys.C), axis=1)
             C_bar = np.reshape(C_bar, (np.shape(self.C)[0],
                                        (self.n + reduced_sys.n)))
             # if np.isnan(J).any() or np.isnan(J_hat).any()
             # or np.isfinite(J).all() or np.isfinite(J_hat).all():
             #     warnings.warn('NaN or inf found in Jacobians, continuing')
             #     continue
             P = solve_lyapunov(J_bar, -1 * C_bar.T @ C_bar)
             if k == 0:
                 max_eig_P = max(eigvals(P))
             Z = full_ssm.compute_Zj(x_sols[k, :], j)
             Z_hat = reduced_ssm.compute_Zj(x_sols_hat[k, :], j)
             Z_bar = np.concatenate((Z, Z_hat), axis=0)
             Z_bar = np.reshape(Z_bar, ((self.n + reduced_sys.n), 1))
             S_metric = norm(Z_bar.T @ P @ S_bar[k, :, j])
             if S_metric > S_metric_max:
                 S_metric_max = S_metric
         Se[j] = max_eig_P + 2 * len(reduced_ssm.timepoints) * S_metric_max
         utils.printProgressBar(
             int(j + k * len(self.params_values)),
             len(timepoints_ssm) * len(self.params_values) - 1,
             prefix='Robustness Metric Progress:',
             suffix='Complete',
             length=50)
     reduced_sys.Se = Se
     return Se
示例#3
0
 def test_ode_objects(self):
     import numpy as np
     timepoints = np.linspace(0, 10, 100)
     ode_object = ODE(self.x,
                      self.f,
                      self.params,
                      self.C,
                      self.g,
                      self.h,
                      self.u,
                      params_values=[2, 4, 6],
                      x_init=np.ones(4),
                      input_values=self.input_values,
                      timepoints=timepoints)
     ode_object_same = get_ODE(self.system, timepoints=timepoints)
     self.assertIsInstance(ode_object, ODE)
     self.assertIsInstance(ode_object, System)
     self.assertEqual(ode_object.f, ode_object_same.f)
     self.assertIsInstance(ode_object.get_system(), System)
     test_sys = TestSystem()
     test_sys.test_system_equality(ode_object.get_system(), self.system)
     test_sys.test_system_equality(ode_object.get_system(), self.system)
 def get_error_metric(self, reduced_sys):
     # Give option for get_error_metric(sys1, sys2)
     """
     Returns the error defined as the 2-norm of y - y_hat.
     y = Cx and y_hat = C_hat x_hat OR
     y = h(x, P), y_hat = h_hat(x_hat, P) 
     """
     reduced_ode = utils.get_ODE(reduced_sys, self.timepoints_ode)
     x_sol, _, _ = self.get_solutions()
     y = self.C @ x_sol
     x_sols_hat = reduced_ode.solve_system().T
     reduced_sys.x_sol = x_sols_hat
     y_hat = np.array(reduced_sys.C) @ np.array(x_sols_hat)
     if np.shape(y) == np.shape(y_hat):
         e = np.linalg.norm(y - y_hat)
     else:
         raise ValueError(
             'The output dimensions must be the same for' +
             'reduced and full model. Choose C and C_hat accordingly')
     if np.isnan(e):
         print('The error is NaN, something wrong...continuing.')
     return e