def test_state_transition_operator_2d(self): # two-dimensional case C_0, C_1 = symbols('C_0 C_1') state_vector = [C_0, C_1] time_symbol = Symbol('t') input_fluxes = {} output_fluxes = {0: C_0, 1: C_1} internal_fluxes = {} srm = SmoothReservoirModel(state_vector, time_symbol, input_fluxes, output_fluxes, internal_fluxes) start_values = np.array([5, 3]) times = np.linspace(0, 1, 11) smr = SmoothModelRun(srm, {}, start_values, times) x = np.array([1, 3]) Phix = smr._state_transition_operator(1, 0, x) self.assertEqual(Phix.shape, (2, )) # test t < t_0 with self.assertRaises(Exception): Phix = smr._state_transition_operator(0, 1, x) # test if operator works correctly also late in time C = Symbol('C') state_vector = [C] time_symbol = Symbol('t') # are inputs really ignored in the computation of Phi? input_fluxes = {0: 1} output_fluxes = {0: C} internal_fluxes = {} srm = SmoothReservoirModel(state_vector, time_symbol, input_fluxes, output_fluxes, internal_fluxes) start_values = np.array([5]) times = np.linspace(0, 100, 101) smr = SmoothModelRun(srm, {}, start_values, times) x = np.array([1]) Phix = smr._state_transition_operator(91, 89, x) self.assertTrue(abs(Phix - np.exp(-2)) < 1e-03)
def test_phi_2d_linear(self): C_0, C_1 = symbols('C_0 C_1') state_vector = [C_0, C_1] time_symbol = Symbol('t') input_fluxes = {} output_fluxes = {0: C_0, 1: C_1} internal_fluxes = {} srm = SmoothReservoirModel(state_vector, time_symbol, input_fluxes, output_fluxes, internal_fluxes) start_values = np.array([1, 2]) t_0 = 0 t_max = 4 nt = 200 times = np.linspace(t_0, t_max, nt) smr = SmoothModelRun(srm, {}, start_values, times) smr.initialize_state_transition_operator_cache(lru_maxsize=None, size=2) nr_pools = srm.nr_pools def baseVector(i): e_i = np.zeros((nr_pools, 1)) e_i[i] = 1 return e_i bvs = [baseVector(i) for i in range(nr_pools)] for s in np.linspace(t_0, t_max, 5): for t in np.linspace(s, t_max, 5): phi_ref = np.eye(2) * np.exp(-(t - s)) # test the matrix valued results with self.subTest(): self.assertTrue( np.allclose(smr.Phi(t, s), phi_ref, rtol=1e-2)) # test the vectored valued results for x in bvs: for phi_x in [ smr._state_transition_operator(t, s, x), smr._state_transition_operator_for_linear_systems( t, s, x) ]: with self.subTest(): self.assertTrue( np.allclose(phi_x, np.matmul(phi_ref, x).reshape(nr_pools, ), rtol=1e-2))
def test_state_transition_operator_1d(self): # one-dimensional case C = Symbol('C') state_vector = [C] time_symbol = Symbol('t') # are inputs really ignored in the computation of Phi? input_fluxes = {0: 1} output_fluxes = {0: C} internal_fluxes = {} srm = SmoothReservoirModel(state_vector, time_symbol, input_fluxes, output_fluxes, internal_fluxes) start_values = np.array([5]) times = np.linspace(0, 1, 11) smr = SmoothModelRun(srm, {}, start_values, times) x = np.array([1]) Phix = smr._state_transition_operator(1, 0, x) self.assertEqual(Phix.shape, (1, )) self.assertTrue(abs(Phix - np.exp(-1)) < 1e-03)
def test_stateTransitionOperator_by_different_methods(): # The state transition operator Phi can be used to reproduce the solution k_0_val = 1 k_1_val = 2 x0_0 = np.float(0.5) x0_1 = np.float(1.5) delta_t = np.float(1. / 4.) # var(["x_0", "x_1", "k_0", "k_1", "t", "u"]) # inputs = {0: u, 1: u * t} outputs = {0: k_0 * x_0**2, 1: k_1 * x_1} internal_fluxes = {} svec = Matrix([x_0, x_1]) srm = SmoothReservoirModel(state_vector=svec, time_symbol=t, input_fluxes=inputs, output_fluxes=outputs, internal_fluxes=internal_fluxes) t_0 = 0 t_max = 4 nt = 5 times = np.linspace(t_0, t_max, nt) double_times = np.linspace(t_0, t_max, 2 * (nt - 1) + 1) quad_times = np.linspace(t_0, t_max, 4 * (nt - 1) + 1) parameter_dict = {k_0: k_0_val, k_1: k_1_val, u: 1} func_dict = {} start_x = np.array([x0_0, x0_1]) #make it a column vector for later use #create the model run smr = SmoothModelRun(model=srm, parameter_dict=parameter_dict, start_values=start_x, times=times, func_set=func_dict) smr.build_state_transition_operator_cache(size=4) nr_pools = smr.nr_pools # to be able to compare the results we have to compute them for a # set of n linear independent vectors def baseVector(i): e_i = np.zeros((nr_pools, 1)) e_i[i] = 1 return e_i bvs = [baseVector(i) for i in range(nr_pools)] #pe('Phi_skew(2,1,bvs[0])',locals()) #raise test_times = np.linspace(t_0, t_max, 11) # We now rebuild the solution by means of phi and plot it along with the original solution original_sol, sol_func = smr.solve() u_sym = srm.external_inputs u_num = numerical_function_from_expression(u_sym, (t, ), parameter_dict, {}) def vectorlist2array(l): return np.stack([vec.flatten() for vec in l], 1) # def lists_dict2array_dict(d): # return {key:vectorlist2array(val) for key,val in d.items()} # def continiuous_integral_values(integrator, times): start = time.time() res = vectorlist2array([ integrator( lambda tau: smr._state_transition_operator(t, tau, u_num(tau)), t_0, t) for t in times ]) stop = time.time() exec_time = stop - start #pe('exec_time',locals()) return (times, res, exec_time) def discrete_integral_values(integrator, times): start = time.time() res = vectorlist2array([ integrator( lambda tau: smr._state_transition_operator(t, tau, u_num(tau)), taus=+times[0:i + 1]) for i, t in enumerate(times) ]) stop = time.time() exec_time = stop - start #pe('exec_time',locals()) return (times, res, exec_time) ## reconstruct the solution with Phi and the integrand # x_t=Phi(t,t0)*x_0+int_t0^t Phi(tau,t0)*u(tau) dtau # x_t=a(t)+b(t) et = bvs[0] + bvs[1] phi_arrays = { 'skew': (times, vectorlist2array([ smr._state_transition_operator(t, t_0, et).reshape(srm.nr_pools, 1) for t in times ])) } a_arrays = { 'skew': (times, vectorlist2array([ smr._state_transition_operator(t, t_0, start_x).reshape(srm.nr_pools, 1) for t in times ])), 'trapez1': (times, vectorlist2array([ smr._state_transition_operator(t, t_0, start_x).reshape(srm.nr_pools, 1) for t in times ])), 'trapez2': (double_times, vectorlist2array([ smr._state_transition_operator(t, t_0, start_x).reshape(srm.nr_pools, 1) for t in double_times ])), 'trapez4': (quad_times, vectorlist2array([ smr._state_transition_operator(t, t_0, start_x).reshape(srm.nr_pools, 1) for t in quad_times ])) } nested_boundary_tuples = [(0, t) for t in reversed(times)] b_arrays_trapez = {} b_arrays = { 'skew': continiuous_integral_values(array_integration_by_ode, times), 'trapez1': discrete_integral_values(array_integration_by_values, times), 'trapez2': discrete_integral_values(array_integration_by_values, double_times), 'trapez4': discrete_integral_values(array_integration_by_values, quad_times) } b_arrays_quad = { 'skew': continiuous_integral_values(array_quad_result, times) } x_arrays = { key: (a_arrays[key][0], a_arrays[key][1] + b_arrays[key][1]) for key in a_arrays.keys() } #x_arrays['trapez']=(times,a_arrays['skew'][1]+b_arrays['trapez'][1]) styleDict = OrderedDict({ 'skew': ('green', 6), 'trapez1': ('black', 4), 'trapez2': ('blue', 4), 'trapez4': ('brown', 2) }) def plot_comparison(axl, axr, d): for key in styleDict.keys(): if key in d.keys(): val = d[key] if len(val) == 3: time = "{:7.1e}".format(val[2]) else: time = "" axl.plot(val[0], val[1][0, :], '+', color=styleDict[key][0], markersize=styleDict[key][1], label=key + "[0]" + time) axr.plot(val[0], val[1][1, :], 'x', color=styleDict[key][0], markersize=styleDict[key][1], label=key + "[1]" + time) fig = plt.figure(figsize=(17, 27)) rpn = 5 cpn = 2 r = 1 axl = fig.add_subplot(rpn, cpn, r) plt.title("""phi components, nonlinear part of the system (x[0]) """) axr = fig.add_subplot(rpn, cpn, r + 1) plt.title("""phi components, linear part of the system (x[1]) """) plot_comparison(axl, axr, phi_arrays) axl.legend() r += cpn axl = fig.add_subplot(rpn, cpn, r) plt.title(''' original solution and reconstruction via phi, imprecise for trapez_rule and wrong for the old method ''') axr = fig.add_subplot(rpn, cpn, r + 1) axl.plot(times, original_sol[:, 0], 'o', color='blue', label="original_sol[:,0]") axr.plot(times, original_sol[:, 1], 'o', color='blue', label="original_sol[:,1]") plot_comparison(axl, axr, x_arrays) axl.legend() axr.legend() r += cpn axl = fig.add_subplot(rpn, cpn, r) plt.title('phi(t,ti-0) x0 ') axr = fig.add_subplot(rpn, cpn, r + 1) ax = fig.add_subplot(rpn, cpn, r) plot_comparison(axl, axr, a_arrays) axl.legend() axr.legend() r += cpn axl = fig.add_subplot(rpn, cpn, r) plt.title('\int_{t0}^t phi(tau,t) u(tau) d tau') axr = fig.add_subplot(rpn, cpn, r + 1) plot_comparison(axl, axr, b_arrays) axl.legend() axr.legend() #r+=cpn r += cpn axl = fig.add_subplot(rpn, cpn, r) plt.title('\int_{t0}^t phi(tau,t) u(tau) d tau by quad') axr = fig.add_subplot(rpn, cpn, r + 1) plot_comparison(axl, axr, b_arrays_quad) axl.legend() axr.legend() fig.savefig("solutions.pdf")
def test_phi_2d_non_linear(self): k_0_val = 1 k_1_val = 2 x0_0 = np.float(0.5) x0_1 = np.float(1.5) x_0, x_1, k_0, k_1, t, u = symbols("x_0 x_1 k_0 k_1 t u") inputs = {0: u, 1: u * t} outputs = {0: k_0 * x_0**2, 1: k_1 * x_1} internal_fluxes = {} svec = Matrix([x_0, x_1]) srm = SmoothReservoirModel(state_vector=svec, time_symbol=t, input_fluxes=inputs, output_fluxes=outputs, internal_fluxes=internal_fluxes) t_0 = 0 t_max = 4 nt = 20000 times = np.linspace(t_0, t_max, nt) parameter_dict = {k_0: k_0_val, k_1: k_1_val, u: 1} func_dict = {} # make it a column vector for later use start_x = np.array([x0_0, x0_1]) # create the model run smr = SmoothModelRun( model=srm, parameter_dict=parameter_dict, start_values=start_x, times=times, func_set=func_dict, ) smr.initialize_state_transition_operator_cache(lru_maxsize=None, size=4) nr_pools = srm.nr_pools def baseVector(i): e_i = np.zeros((nr_pools, 1)) e_i[i] = 1 return e_i bvs = [baseVector(i) for i in range(nr_pools)] smrl = smr.linearize_old() for s in np.linspace(t_0, t_max, 5): for t in np.linspace(s, t_max, 5): for x in bvs: with self.subTest(): self.assertTrue( np.allclose( smr._state_transition_operator(t, s, x), smrl. _state_transition_operator_for_linear_systems( t, s, x), # noqa: E501 rtol=1.5 * 1e-2)) for t in np.linspace(t_0, t_max, 6): for phi_mat in [smr.Phi(t, t_0), smrl.Phi(t, t_0)]: for x in bvs: with self.subTest(): self.assertTrue( np.allclose(np.matmul(phi_mat, x).reshape(nr_pools, ), smr._state_transition_operator( t, t_0, x), rtol=1.5 * 1e-2))