def simulate(self, Tend, nIntervals, gridWidth): problem = Implicit_Problem(self.rhs, self.y0, self.yd0) problem.name = 'IDA' # solver.rhs = self.right_hand_side problem.handle_result = self.handle_result problem.state_events = self.state_events problem.handle_event = self.handle_event problem.time_events = self.time_events problem.finalize = self.finalize # Create IDA object and set additional parameters simulation = IDA(problem) simulation.atol = self.atol simulation.rtol = self.rtol simulation.verbosity = self.verbosity if hasattr(simulation, 'continuous_output'): simulation.continuous_output = False # default 0, if one step approach should be used elif hasattr(simulation, 'report_continuously'): simulation.report_continuously = False # default 0, if one step approach should be used simulation.tout1 = self.tout1 simulation.lsoff = self.lsoff # Calculate nOutputIntervals: if gridWidth <> None: nOutputIntervals = int((Tend - self.t0) / gridWidth) else: nOutputIntervals = nIntervals # Check for feasible input parameters if nOutputIntervals == 0: print 'Error: gridWidth too high or nIntervals set to 0! Continue with nIntervals=1' nOutputIntervals = 1 # Perform simulation simulation.simulate(Tend, nOutputIntervals) # to get the values: t_new, y_new, yd_new = simulation.simulate
def run_example(): #initial values t0 = 0 y0 = np.array([0., -0.10344, -0.65, 0., 0. , 0., -0.628993, 0.047088]) #|phi_s| <= 0.1034 rad, |phi_b| <= 0.12 rad yd0 = np.array([0., 0., 0., 0., 0., 0., 0., 0.]) sw = [False, True, False] #problem model = Implicit_Problem(pecker, y0, yd0, t0, sw0=sw) model.state_events = state_events #from woodpecker.py model.handle_event = handle_event #from woodpecker.py model.name = 'Woodpeckermodel' sim = IDA(model) #create IDA solver tfinal = 2.0 #final time ncp = 500 #number control points sim.suppress_alg = True sim.rtol=1.e-6 sim.atol[6:8] = 1e6 sim.algvar[6:8] = 0 t, y, yd = sim.simulate(tfinal, ncp) #simulate #plot fig, ax = P.subplots() ax.plot(t, y[:, 0], label='z') legend = ax.legend(loc='upper center', shadow=True) P.grid() P.figure(1) fig2, ax2 = P.subplots() ax2.plot(t, y[:, 1], label='phi_s') ax2.plot(t, y[:, 2], label='phi_b') legend = ax2.legend(loc='upper center', shadow=True) P.grid() P.figure(2) fig3, ax3 = P.subplots() ax3.plot(t, y[:, 4], label='phi_sp') ax3.plot(t, y[:, 5], label='phi_bp') legend = ax3.legend(loc='upper center', shadow=True) P.grid() P.figure(3) fig4, ax4 = P.subplots() ax4.plot(t, y[:, 6], label='lambda_1') ax4.plot(t, y[:, 7], label='lambda_2') legend = ax4.legend(loc='upper right', shadow=True) P.grid() #event data sim.print_event_data() #show plots P.show() print("...") P.show()
def solve(self): # Setup IDA assert self._initial_time is not None problem = Implicit_Problem(self._residual_vector_eval, self.solution.vector(), self.solution_dot.vector(), self._initial_time) problem.jac = self._jacobian_matrix_eval problem.handle_result = self._monitor # Define an Assimulo IDA solver solver = IDA(problem) # Setup options assert self._time_step_size is not None solver.inith = self._time_step_size if self._absolute_tolerance is not None: solver.atol = self._absolute_tolerance if self._max_time_steps is not None: solver.maxsteps = self._max_time_steps if self._relative_tolerance is not None: solver.rtol = self._relative_tolerance if self._report: solver.verbosity = 10 solver.display_progress = True solver.report_continuously = True else: solver.display_progress = False solver.verbosity = 50 # Assert consistency of final time and time step size assert self._final_time is not None final_time_consistency = ( self._final_time - self._initial_time) / self._time_step_size assert isclose( round(final_time_consistency), final_time_consistency ), ("Final time should be occuring after an integer number of time steps" ) # Prepare monitor computation if not provided by parameters if self._monitor_initial_time is None: self._monitor_initial_time = self._initial_time assert isclose( round(self._monitor_initial_time / self._time_step_size), self._monitor_initial_time / self._time_step_size ), ("Monitor initial time should be a multiple of the time step size" ) if self._monitor_time_step_size is None: self._monitor_time_step_size = self._time_step_size assert isclose( round(self._monitor_time_step_size / self._time_step_size), self._monitor_time_step_size / self._time_step_size ), ("Monitor time step size should be a multiple of the time step size" ) monitor_t = arange( self._monitor_initial_time, self._final_time + self._monitor_time_step_size / 2., self._monitor_time_step_size) # Solve solver.simulate(self._final_time, ncp_list=monitor_t)
def run_example(with_plots=True): """ The same as example :doc:`EXAMPLE_cvode_basic` but now integrated backwards in time. on return: - :dfn:`exp_mod` problem instance - :dfn:`exp_sim` solver instance """ # Define the rhs def f(t, y, yd): res = yd[0] + y[0] * param return N.array([res]) param = 2 # Define an Assimulo problem imp_mod = Implicit_Problem( f, t0=5, y0=0.02695, yd0=-0.02695, name='IDA Example: $\dot y + y = 0$ (reverse time)') # Define an explicit solver imp_sim = IDA(imp_mod) # Create a IDA solver # Sets the parameters imp_sim.atol = [1e-8] # Default 1e-6 imp_sim.rtol = 1e-8 # Default 1e-6 imp_sim.backward = True # Simulate t, y, yd = imp_sim.simulate(0) # Simulate 5 seconds (t0=5 -> tf=0) # Basic test #nose.tools.assert_almost_equal(float(y[-1]), 4.00000000, 3) # Plot if with_plots: P.plot(t, y, color="b") P.xlabel('Time') P.ylabel('State') P.title(imp_mod.name) P.show() return imp_mod, imp_sim
def initialize_ode_solver(self, y_0, yd_0, t_0): model = Implicit_Problem(self.residual, y_0, yd_0, t_0) model.handle_result = self.handle_result solver = IDA(model) solver.rtol = self.solver_rtol solver.atol = self.solver_atol # * np.array([100, 10, 1e-4, 1e-4]) solver.inith = 0.1 # self.wind.R_g / const.C solver.maxh = self.dt * self.wind.R_g / const.C solver.report_continuously = True solver.display_progress = False solver.verbosity = 50 # 50 = quiet solver.num_threads = 3 # solver.display_progress = True return solver
def run_example(index="ind1", with_plots=True, with_test=False): my_pend_sys = pendulum() my_pend = my_pend_sys.generate_problem(index) my_pend.name = 'Index = {}'.format(index) dae_pend = IDA(my_pend) if index not in ('ovstab2', 'ovstab1') else ODASSL(my_pend) dae_pend.atol = 1.e-6 dae_pend.rtol = 1.e-6 dae_pend.suppress_alg = True t, y, yd = dae_pend.simulate(10., 100) final_residual = my_pend.res(0., dae_pend.y, dae_pend.yd) print(my_pend.name + " Residuals after the integration run\n") print(final_residual, 'Norm: ', sl.norm(final_residual)) if with_test: assert (sl.norm(final_residual) < 1.5e-1) if with_plots: dae_pend.plot(mask=[1, 1] + (len(my_pend.y0) - 2) * [0]) return my_pend, dae_pend
def buildsim(self, ): """ Setup the assimulo IDA simulator. """ # Create an Assimulo implicit solver (IDA) imp_sim = IDA(self.imp_mod) # Create a IDA solver # Sets the paramters # 1e-4 #Default 1e-6 imp_sim.atol = self.p.RunInput['TIMESTEPPING']['SOLVER_TOL'] # 1e-4 #Default 1e-6 imp_sim.rtol = self.p.RunInput['TIMESTEPPING']['SOLVER_TOL'] # Suppres the algebraic variables on the error test imp_sim.suppress_alg = True imp_sim.display_progress = False imp_sim.verbosity = 50 imp_sim.report_continuously = True imp_sim.time_limit = 10. self.imp_sim = imp_sim
def main(): y0 = [1.0, 0.0, 0.0, 0.0, 5] yd0 = [0.0, 0.0, 0.0, -9.82, 0.0] # tout = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0] tout = np.linspace(0.0, 10.0, 500) implicit_model = Implicit_Problem(res, y0, yd0, name="Example problem") # implicit_model.jac = jac implicit_model.algvar = [1.0, 1.0, 1.0, 1.0, 0.0] implicit_solver = IDA(implicit_model) implicit_solver.atol = 1E-6 implicit_solver.rtol = 1E-6 implicit_solver.suppress_alg = True implicit_solver.make_consistent("IDA_YA_YDP_INIT") t, y, yd = implicit_solver.simulate(10.0, ncp=500) plt.plot(t, y, linestyle="dashed", marker="o") plt.xlabel("Time") plt.ylabel("State") plt.title(implicit_model.name) plt.show()
def run_example(with_plots=True): r""" Example for demonstrating the use of a user supplied Jacobian ODE: .. math:: \dot y_1-y_3 &= 0 \\ \dot y_2-y_4 &= 0 \\ \dot y_3+y_5 y_1 &= 0 \\ \dot y_4+y_5 y_2+9.82&= 0 \\ y_3^2+y_4^2-y_5(y_1^2+y_2^2)-9.82 y_2&= 0 on return: - :dfn:`imp_mod` problem instance - :dfn:`imp_sim` solver instance """ #Defines the residual def f(t, y, yd): res_0 = yd[0] - y[2] res_1 = yd[1] - y[3] res_2 = yd[2] + y[4] * y[0] res_3 = yd[3] + y[4] * y[1] + 9.82 res_4 = y[2]**2 + y[3]**2 - y[4] * (y[0]**2 + y[1]**2) - y[1] * 9.82 return N.array([res_0, res_1, res_2, res_3, res_4]) #Defines the Jacobian def jac(c, t, y, yd): jacobian = N.zeros([len(y), len(y)]) #Derivative jacobian[0, 0] = 1 * c jacobian[1, 1] = 1 * c jacobian[2, 2] = 1 * c jacobian[3, 3] = 1 * c #Differentiated jacobian[0, 2] = -1 jacobian[1, 3] = -1 jacobian[2, 0] = y[4] jacobian[3, 1] = y[4] jacobian[4, 0] = y[0] * 2 * y[4] * -1 jacobian[4, 1] = y[1] * 2 * y[4] * -1 - 9.82 jacobian[4, 2] = y[2] * 2 jacobian[4, 3] = y[3] * 2 #Algebraic jacobian[2, 4] = y[0] jacobian[3, 4] = y[1] jacobian[4, 4] = -(y[0]**2 + y[1]**2) return jacobian #The initial conditons y0 = [1.0, 0.0, 0.0, 0.0, 5] #Initial conditions yd0 = [0.0, 0.0, 0.0, -9.82, 0.0] #Initial conditions #Create an Assimulo implicit problem imp_mod = Implicit_Problem(f, y0, yd0, name='Example using an analytic Jacobian') #Sets the options to the problem imp_mod.jac = jac #Sets the jacobian imp_mod.algvar = [1.0, 1.0, 1.0, 1.0, 0.0] #Set the algebraic components #Create an Assimulo implicit solver (IDA) imp_sim = IDA(imp_mod) #Create a IDA solver #Sets the paramters imp_sim.atol = 1e-6 #Default 1e-6 imp_sim.rtol = 1e-6 #Default 1e-6 imp_sim.suppress_alg = True #Suppres the algebraic variables on the error test #Let Sundials find consistent initial conditions by use of 'IDA_YA_YDP_INIT' imp_sim.make_consistent('IDA_YA_YDP_INIT') #Simulate t, y, yd = imp_sim.simulate( 5, 1000) #Simulate 5 seconds with 1000 communication points #Basic tests nose.tools.assert_almost_equal(y[-1][0], 0.9401995, places=4) nose.tools.assert_almost_equal(y[-1][1], -0.34095124, places=4) nose.tools.assert_almost_equal(yd[-1][0], -0.88198927, places=4) nose.tools.assert_almost_equal(yd[-1][1], -2.43227069, places=4) #Plot if with_plots: import pylab as P P.plot(t, y, linestyle="dashed", marker="o") #Plot the solution P.xlabel('Time') P.ylabel('State') P.title(imp_mod.name) P.show() return imp_mod, imp_sim
#ax[2].plot( imp_mod.x_m_c, z_out[-imp_mod.Nc:,:-1] ) #plt.show() #print z_out #Sets the options to the problem #imp_mod.jac = jac #Sets the jacobian imp_mod.algvar = [1.0 for i in range(N)] + [0.0 for i in range(N+Na+Nc)] #Set the algebraic components #imp_mod.algvar = [1.0 for i in range(N)] + [0.0 for i in range(N)] #Set the algebraic components #Create an Assimulo implicit solver (IDA) imp_sim = IDA(imp_mod) #Create a IDA solver #Sets the paramters imp_sim.atol = 1e-5 #Default 1e-6 imp_sim.rtol = 1e-5 #Default 1e-6 imp_sim.suppress_alg = True #Suppres the algebraic variables on the error test ### Simulate imp_mod.set_j_vec( I_app ) #res_test = imp_mod.res( 0.0, y0, yd0 ) #jac_test = imp_mod.jac( 2, 0.0, y0, yd0 ) #Let Sundials find consistent initial conditions by use of 'IDA_YA_YDP_INIT' imp_sim.make_consistent('IDA_YA_YDP_INIT') # Sim step 1 t1, y1, yd1 = imp_sim.simulate(100,100) #t1, y1, yd1 = imp_sim.simulate(1000,1000)
def main(): import numpy as np import time from matplotlib import pyplot as plt from li_ion_battery_p2d_functions import Extended_Problem from assimulo.solvers import IDA from li_ion_battery_p2d_inputs import Inputs as inp from li_ion_battery_p2d_init import anode, cathode, separator, SV_0, algvar from li_ion_battery_p2d_post_process import Label_Columns, tag_strings, plot_sims # Close any open pyplot objects: plt.close() # Start a timer: t_count = time.time() # Calculate the time span, which should be enough to charge or discharge fully # (i.e. 3600 seconds divided by the C-rate): t_0 = 0 t_f = 3600 / inp.C_rate # SV_0 = anode.SV_0 # SV_0 = np.concatenate((anode.SV_0, separator.SV_0, cathode.SV_0)) #SV_0 = np.concatenate((anode.SV_0, separator.SV_0)) SV_dot_0 = np.zeros_like(SV_0) """----------Equilibration----------""" # Equilibrate by integrating at zero current: print('\nEquilibrating...') # Create problem instance #Battery_equil = Extended_Problem(Battery_Func, SV_0, SV_dot_0, t_0) anode.i_ext = 0 cathode.i_ext = 0 Battery_equil = Extended_Problem.Battery_Func(t_0, SV_0, SV_dot_0, True) Battery_equil.external_event_detection = True # algvar = anode.algvar # algvar = np.concatenate((anode.algvar, separator.algvar, cathode.algvar)) #algvar = np.concatenate((anode.algvar, separator.algvar)) # Battery_equil.algvar = algvar # Simulation parameters equil_sim = IDA(Battery_equil) # Create simulation instance equil_sim.atol = atol1 # Solver absolute tolerance equil_sim.rtol = rtol1 # Solver relative tolerance equil_sim.verbosity = 50 equil_sim.make_consistent('IDA_YA_YDP_INIT') t_eq, SV_eq, SV_dot_eq = equil_sim.simulate(t_f) # Put solution into pandas dataframe with labeled columns SV_eq_df = Label_Columns(t_eq, SV_eq) # Obtain tag strings for dataframe columns tags = tag_strings(SV_eq_df) print('Done equilibrating\n') """---------------------------------""" """------------Charging-------------""" print('\nCharging...') # New initial conditions are the final equilibrium conditions t_0 = t_eq[-1] t_f1 = t_0 + t_f SV_0 = SV_eq[-1, :] SV_dot_0 = SV_dot_eq[-1:] # Charge the battery anode.params['i_ext'] = anode.i_ext cathode.params['i_ext'] = -cathode.i_ext # Create problem instance Battery_charge = Extended_Problem(Charge, SV_0, SV_dot_0, t_0) Battery_charge.external_event_detection = True Battery_charge.algvar = algvar # Simulation parameters charge_sim = IDA(Battery_charge) charge_sim.atol = atol2 charge_sim.rtol = rtol2 charge_sim.verbosity = 50 charge_sim.make_consistent('IDA_YA_YDP_INIT') # charge_sim.maxh = 0.5 t_charge, SV_charge, SV_dot_charge = charge_sim.simulate(t_f1) t_flag1 = anode.t_flag SV_charge_df = Label_Columns(t_charge, SV_charge) print('Done charging\n') """---------------------------------""" """------------Re_equilibrating-------------""" # New initial conditions are the final charge conditions t_0 = t_charge[-1] #anode.t_flag t_f2 = t_0 + t_f SV_0 = SV_charge[-1, :] SV_dot_0 = SV_dot_charge[-1, :] # Equilibrate again. Note - this is a specific choice to reflect # equilibration after the charging steps. We may want, at times, to # simulate a situation where the battery is not equilibrated between # charge and discharge, or is equilibrated for a shorter amount of time. print('\nRe-equilibrating...') Battery_re_equil = Extended_Problem(Re_equilibrate, SV_0, SV_dot_0, t_0) Battery_re_equil.external_event_detection = True Battery_re_equil.algvar = algvar # Simulation parameters re_equil_sim = IDA(Battery_re_equil) re_equil_sim.atol = atol3 re_equil_sim.rtol = rtol3 re_equil_sim.verbosity = 50 re_equil_sim.make_consistent('IDA_YA_YDP_INIT') t_req, SV_req, SV_dot_req = re_equil_sim.simulate(t_f2) SV_req_df = Label_Columns(t_req, SV_req) print('Done re-equilibrating\n') """---------------------------------""" """------------Discharging-------------""" print('\nDischarging...') t_0 = t_req[-1] t_f3 = t_f2 + t_f SV_0 = SV_req[-1, :] SV_dot_0 = SV_dot_req[-1, :] anode.params['i_ext'] = -anode.i_ext cathode.params['i_ext'] = cathode.i_ext Battery_discharge = Extended_Problem(Discharge, SV_0, SV_dot_0, t_0) Battery_discharge.external_event_detection = True Battery_discharge.algvar = algvar # Simulation parameters Battery_discharge = IDA(Battery_discharge) Battery_discharge.atol = atol4 Battery_discharge.rtol = rtol4 Battery_discharge.verbosity = 50 Battery_discharge.make_consistent('IDA_YA_YDP_INIT') t_discharge, SV_discharge, SV_dot_discharge = Battery_discharge.simulate( t_f3) t_flag2 = anode.t_flag SV_discharge_df = Label_Columns(t_discharge, SV_discharge) print('Done discharging\n') """---------------------------------""" SV_dict = {} SV_dict['SV_eq'] = SV_eq_df SV_dict['SV_charge'] = SV_charge_df SV_dict['SV_req'] = SV_req_df SV_dict['SV_discharge'] = SV_discharge_df # SV_charge_df = SV_charge_df.loc[SV_charge_df['Time'] <= t_flag1] # SV_discharge_df = SV_discharge_df.loc[SV_discharge_df['Time'] <= t_flag2] # dt_cap = t_flag1 - t_eq[-1] # t_80 = 0.8*dt_cap + t_eq[-1] # elyte80_charge = SV_charge_df.loc[SV_charge_df['Time'] <= t_80] # elyte75_charge = SV_charge_df.loc[SV_charge_df['X_an15'] <= 0.20] # el80 = elyte80_charge[X_elyte].iloc[0] # el80 = list(el80) # el80.append(inp.C_rate) # import openpyxl # book = openpyxl.load_workbook('Elyte_depth_profiles.xlsx') # sheet = book.active # sheet.append(el80) # book.save('Elyte_depth_profiles.xlsx') # print('Elyte Li+ at 80% SOC = ', elyte75_charge, '\n') plot_sims(tags['V_an'], tags['X_an'], tags['X_el_an'], SV_dict, t_f1, t_f3, t_flag1, t_flag2) # plot_sims(tags['V_cat'], tags['X_cat'], tags['X_el_cat'], SV_dict, t_f1, t_f3, t_flag1, t_flag2) # fig, axes = plt.subplots(sharey = "row", figsize = (18, 8), nrows=1, ncols=4) # plt.subplots_adjust(wspace=0, hspace=0.5) # # V_cell_plot = V_cell_eq.plot(ax = axes[0]) # V_cell_plot.set_title('Equilibration') # V_cell_plot.set_ylabel('Cell Voltage') # V_cell_plot.legend().set_visible(False) # # V_cell_plot = V_cell_charge.plot(ax = axes[1]) # V_cell_plot.set_title('Charging') # V_cell_plot.set_ylabel('Cell Voltage') # V_cell_plot.legend().set_visible(False) # # V_cell_plot = V_cell_req.plot(ax = axes[2]) # V_cell_plot.set_title('Re-Equilibration') # V_cell_plot.set_ylabel('Cell Voltage') # V_cell_plot.legend().set_visible(False) # # V_cell_plot = V_cell_discharge.plot(ax = axes[3]) # V_cell_plot.set_title('Discharge') # V_cell_plot.set_ylabel('Cell Voltage') # V_cell_plot.legend().set_visible(False) """---------------------------------""" # Post processing V_charge = np.array(SV_charge_df['V_dl1']) V_discharge = np.array(SV_discharge_df['V_dl1']) t_charge = np.array(SV_charge_df['Time']) t_discharge = np.array(SV_discharge_df['Time']) dt_charge = t_charge - t_charge[0] dt_discharge = t_discharge - t_discharge[0] # Plot charge-discharge curve Capacity_charge = -dt_charge * anode.i_ext / 3600 # A-h/m^2 Capacity_discharge = -dt_discharge * anode.i_ext / 3600 # A-h/m^2 fig1, ax1 = plt.subplots() ax1.plot(Capacity_charge, V_charge) ax1.plot(Capacity_discharge, V_discharge) # ax1.set_ylim((0, 1.2)) # ax1.set_xlim((-0.1, 18.5)) ax1.set_xlabel("Capacity [Ah/m^2]") ax1.set_ylabel("Voltage [V]") ax1.legend(("Charge capacity", "Discharge capacity")) # Calculate battery energy storage/recovery and calculate round-trip # efficiency. Anode voltage is referenced to its initial equilibrium # value (i.e. in the discharged state). # NOTE: This is in W-h/m^2, per unit area of battery. For the specific # capacity, you want W-h/g of anode material. # E_stored = 0 # E_recovered = 0 # for k in np.arange(1, len(t_charge)): # E_stored = (E_stored - (anode.V_cathode - 0.5*(V_charge[k] + V_charge[k-1])) # *ep.i_ext*(dt_charge[k] - dt_charge[k-1])) # # for k in np.arange(1, len(t_discharge)): # E_recovered = (E_recovered - (ep.V_cathode - # 0.5*(V_discharge[k] + V_discharge[k-1])) # *ep.i_ext*(dt_discharge[k] - dt_discharge[k-1])) # # Cap_recovered = Capacity_discharge[-1] # Eta_RT = E_recovered/E_stored # print('Cap_recovered = ', Cap_recovered, '\n') # print(E_stored, '\n') # print(E_recovered, '\n') # print('Eta_RT = ', Eta_RT, '\n') elapsed = time.time() - t_count print('t_cpu=', elapsed, '\n') plt.show() return t_req, SV_req, SV_dot_req
def DAE_integration_assimulo(self, **kwargs): """ Perform time integration for DAEs with the assimulo package """ assert self.set_time_setting == 1, 'Time discretization must be specified first' if self.tclose > 0: close = True else: close = False # Control vector self.U = interpolate(self.boundary_cntrl_space, self.Vb).vector()[self.bndr_i_b] if self.discontinous_boundary_values == 1: self.U[self.Corner_indices] = self.U[self.Corner_indices]/2 # Definition of the sparse solver for the DAE res function to # be defined next M should be invertible !! my_solver = factorized(csc_matrix(self.M)) rhs = self.my_mult(self.J, self.my_mult(self.Q,self.A0)) + self.my_mult(self.Bext,self.U* self.boundary_cntrl_time(0.,self.tclose)) self.AD0 = my_solver(rhs) # Definition of the rhs function required in assimulo def res(t,y,yd): """ Definition of the residual function required in the DAE part of assimulo """ if close: if t < self.tclose: z = self.my_mult(self.M,yd) - self.my_mult(self.J, self.my_mult(self.Q,y)) - self.my_mult(self.Bext,self.U* self.boundary_cntrl_time(t,self.tclose)) else: z = self.my_mult(self.M,yd) - self.my_mult((self.J - self.R), self.my_mult(self.Q,y)) else: z = self.my_mult(self.M,yd) - self.my_mult(self.J, self.my_mult(self.Q,y)) - self.my_mult(self.Bext,self.U* self.boundary_cntrl_time(t,self.tclose)) return z # Definition of the jacobian function required in assimulo def jac(c,t,y,yd): """ Definition of the Jacobian matrix required in the DAE part of assimulo """ Matrix = csr_matrix(self.my_mult(self.J,self.Q)) if close and t > self.tclose: Matrix = csr_matrix(self.my_mult(self.J - self.R, self.Q)) return c*csr_matrix(self.M) - Matrix # Definition of the jacobian matrix vector function required in assimulo def jacv(t,y,yd,res,v,c): """ Jacobian matrix-vector product required in the DAE part of assimulo """ w = self.my_mult(self.Q, v) z = self.my_mult(self.J, w) if close and t > self.tclose: z -= self.my_mult(self.R, w) return c*self.my_mult(self.M,v) - z print('DAE Integration using assimulo built-in functions:') model = Implicit_Problem(res,self.A0,self.AD0,self.tinit) model.jacv = jacv #sim = Radau5DAE(model,**kwargs) # # IDA method from Assimulo # sim = IDA(model,**kwargs) sim.algvar = [1 for i in range(self.M.shape[0])] sim.atol = 1.e-6 sim.rtol = 1.e-6 sim.report_continuously = True ncp = self.Nt sim.usejac = True sim.suppress_alg = True sim.inith = self.dt sim.maxord = 5 #sim.linear_solver = 'SPGMR' time_span, DAE_y, DAE_yd = sim.simulate(self.tfinal,ncp) #print(sim.get_options()) print(sim.print_statistics()) A_dae = DAE_y.transpose() # Hamiltonian self.Nt = A_dae.shape[1] self.tspan = np.array(time_span) Ham_dae = np.zeros(self.Nt) for k in range(self.Nt): #Ham_dae[k] = 1/2 * A_dae[:,k] @ self.M @ self.Q @ A_dae[:,k] Ham_dae[k] = 1/2 * self.my_mult(A_dae[:,k].T, \ self.my_mult(self.M, self.my_mult(self.Q, A_dae[:,k]))) # Get q variables Aq_dae = A_dae[:self.Nq,:] # Get p variables Ap_dae = A_dae[self.Nq:,:] # Get Deformation Rho = np.zeros(self.Np) for i in range(self.Np): Rho[i] = self.rho(self.coord_p[i]) W_dae = np.zeros((self.Np,self.Nt)) theta = .5 for k in range(self.Nt-1): W_dae[:,k+1] = W_dae[:,k] + self.dt * 1/Rho[:] * ( theta * Ap_dae[:,k+1] + (1-theta) * Ap_dae[:,k] ) self.Ham_dae = Ham_dae return Aq_dae, Ap_dae, Ham_dae, W_dae, np.array(time_span)
def main(): res_class = eval(inputs.test_type) # plt.close('all') t_count = time.time() SV_0 = sol_init.SV_0 SV_dot_0 = np.zeros_like(SV_0) t_0 = 0. t_f = 3600. / inputs.C_rate #63006.69900049 93633 algvar = sol_init.algvar atol = np.ones_like(SV_0) * 1e-6 atol[cat.ptr_vec['eps_S8']] = 1e-15 atol[cat.ptr_vec['eps_Li2S']] = 1e-15 atol[cat.ptr_vec['rho_k_el']] = 1e-16 # 1e-16 for Bessler rtol = 1e-6 sim_output = 50 rtol_ch = 1e-6 atol_ch = np.ones_like(SV_0) * 1e-6 atol_ch[cat.ptr_vec['eps_S8']] = 1e-15 atol_ch[cat.ptr_vec['eps_Li2S']] = 1e-15 atol_ch[cat.ptr_vec['rho_k_el']] = 1e-30 rate_tag = str(inputs.C_rate) + "C" # if 'cascade' in inputs.ctifile: # ncols = 2 + inputs.flag_req # else: ncols = 1 + inputs.flag_req fig, axes = plt.subplots(sharey="row", figsize=(9, 12), nrows=3, ncols=(ncols) * inputs.n_cycles, num=1) plt.subplots_adjust(wspace=0.15, hspace=0.4) fig.text(0.35, 0.85, rate_tag, fontsize=20, bbox=dict(facecolor='white', alpha=0.5)) # Set up user function to build figures based on inputs "----------Equilibration----------" print('\nEquilibrating...') # Set external current to 0 for equilibration cat.set_i_ext(0) # cat.nucleation_flag = 1 # Create problem object bat_eq = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_eq.external_event_detection = True bat_eq.algvar = algvar # Create simulation object sim_eq = IDA(bat_eq) sim_eq.atol = atol sim_eq.rtol = rtol sim_eq.verbosity = sim_output sim_eq.make_consistent('IDA_YA_YDP_INIT') t_eq, SV_eq, SV_dot_eq = sim_eq.simulate(t_f) # Put solution into pandas dataframe with labeled columns SV_eq_df = label_columns(t_eq, SV_eq, an.npoints, sep.npoints, cat.npoints) # Obtain tag strings for dataframe columns tags = tag_strings(SV_eq_df) # plot_sim(tags, SV_eq_df, 'Equilibrating', 0, fig, axes) t_equilibrate = time.time() - t_count print("Equilibration time = ", t_equilibrate, '\n') print('Done equilibrating\n') for cycle_num in np.arange(0, inputs.n_cycles): "------------Discharging-------------" print('Discharging...') # cat.np_L = inputs.np_Li2S_init cat.nucleation_flag = np.zeros((inputs.npoints_cathode, 1)) # New initial conditions from previous simulation if cycle_num == 0: # SV_0 = SV_0 SV_0 = SV_eq[-1, :] # SV_dot_0 = SV_dot_0 SV_dot_0 = SV_dot_eq[-1, :] else: SV_0 = SV_0_cycle SV_dot_0 = SV_dot_0_cycle # Set external current cat.set_i_ext(cat.i_ext_amp) # Update problem instance initial conditions bat_dch = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_dch.external_event_detection = True bat_dch.algvar = algvar # Re-initialize simulation object sim_dch = IDA(bat_dch) sim_dch.atol = atol sim_dch.rtol = rtol # sim_dch.maxh = 57 sim_dch.verbosity = sim_output sim_dch.make_consistent('IDA_YA_YDP_INIT') t_dch, SV_dch, SV_dot_dch = sim_dch.simulate(131865.32) SV_dch_df = label_columns(t_dch, SV_dch, an.npoints, sep.npoints, cat.npoints) # Obtain tag strings for dataframe columns tags = tag_strings(SV_dch_df) plot_sim(tags, SV_dch_df, 'Discharging', 0 + 2 * cycle_num, fig, axes) # plot_meanPS(SV_dch_df, tags, 'Discharging') print('Done Discharging\n') "--------Re-equilibration---------" if inputs.flag_req == 1: print('Re-equilibrating...') # New initial conditions from previous simulation SV_0 = SV_dch[-1, :] SV_dot_0 = SV_dot_dch[-1, :] # Set external current cat.set_i_ext(0) # Update problem instance initial conditions bat_req = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_req.external_event_detection = True bat_req.algvar = algvar # Re-initialize simulation object sim_req = IDA(bat_req) sim_req.atol = atol sim_req.rtol = rtol sim_req.verbosity = sim_output sim_req.make_consistent('IDA_YA_YDP_INIT') t_req, SV_req, SV_dot_req = sim_req.simulate(t_f) SV_req_df = label_columns(t_req, SV_req, an.npoints, sep.npoints, cat.npoints) # plot_sim(tags, SV_req_df, 'Re-Equilibrating', 1, fig, axes) print('Done re-equilibrating\n') else: SV_req = SV_dch SV_dot_req = SV_dot_dch "-----------Charging-----------" if 'dog' in inputs.ctifile: print('Charging...') SV_0 = SV_req[-1, :] SV_dot_0 = SV_dot_req[-1, :] SV_0[cat.ptr_vec['eps_S8']] = cat.eps_cutoff cat.set_i_ext(-cat.i_ext_amp) # Update problem instance initial conditions bat_ch = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_ch.external_event_detection = True bat_ch.algvar = algvar # Re-initialize simulation object sim_ch = IDA(bat_ch) sim_ch.atol = atol_ch sim_ch.rtol = rtol_ch if cycle_num > 0: sim_ch.maxh = 0.1 sim_ch.verbosity = sim_output sim_ch.make_consistent('IDA_YA_YDP_INIT') t_ch, SV_ch, SV_dot_ch = sim_ch.simulate(t_f) SV_ch_df = label_columns(t_ch, SV_ch, an.npoints, sep.npoints, cat.npoints) plot_sim(tags, SV_ch_df, 'Charging', 1 + inputs.flag_req + 2 * cycle_num, fig, axes) plot_meanPS(SV_ch_df, tags, 'Charging') SV_ch_df = 0 # # print('Max S_8(e) concentration = ', max(SV_ch[:, 6])) # SV_0_cycle = SV_ch[-1, :] # SV_dot_0_cycle = SV_ch[-1, :] print('Done Charging\n') exp_data_01C = pd.read_csv(r'0.1C Data.csv', header=None) exp_data_05C = pd.read_csv(r'0.5C Data.csv', header=None) exp_data_1C = pd.read_csv(r'1C Data.csv', header=None) Bessler = pd.read_csv(r'Bessler Dennis Data.csv', header=None) SV_copy = SV_dch_df.copy() SV_copy.loc[:, 'Time'] *= -cat.i_ext_amp * inputs.A_cat / 3600 / ( cat.m_S_tot_0) "Set up your figure" fig = plt.figure(3) ax = fig.add_axes([0.2, 0.2, 0.6, 0.75]) fig.set_size_inches((10., 5.0)) # ax2 = ax.twinx() "Formatting for the figure:" fs = 20 #font size for plots lw = 3.0 #line width for plots # font = plt.matplotlib.font_manager.FontProperties(family='Times New Roman',size=fs-1) for tick in ax.xaxis.get_major_ticks(): tick.label1.set_fontsize(fs) tick.label1.set_fontname('Times New Roman') for tick in ax.yaxis.get_major_ticks(): tick.label1.set_fontsize(fs) tick.label1.set_fontname('Times New Roman') color = matplotlib.cm.plasma(inputs.C_rate) p1, = plt.plot(SV_copy.loc[:, 'Time'], SV_copy.loc[:, 'Phi_ed1'], 'k-', linewidth=lw) # p2, = plt.plot(exp_data_01C.iloc[:,0], exp_data_01C.iloc[:,1], 'ro') # p3, = plt.plot(exp_data_05C.iloc[:,0], exp_data_05C.iloc[:,1], 'co') # p4, = plt.plot(exp_data_1C.iloc[:,0], exp_data_1C.iloc[:,1], 'ko') p5, = plt.plot(Bessler.iloc[:, 0], Bessler.iloc[:, 1], 'mo', ms=4) plt.xlim((0, 1700)) plt.xticks([0, 400, 800, 1200, 1600]) plt.ylim((1.8, 2.6)) plt.ylabel(r'Cell Voltage $[\mathrm{V}]$', fontstyle='normal', fontname='Times new Roman', fontsize=fs + 2, labelpad=5.0) plt.xlabel( r'Capacity $[\mathrm{Ah} \hspace{0.5} \mathrm{kg}^{-1}_{\mathrm{sulfur}}]$', fontstyle='normal', fontname='Times new Roman', fontsize=fs + 2, labelpad=5.0) # plt.legend(["Discharge", "Charge"]) file_name_dch = 'dch' + str(inputs.C_rate) + "C_" + inputs.mech + '.csv' SV_dch = SV_dch_df.copy() SV_dch.loc[:, 'Time'] *= -cat.i_ext_amp * inputs.A_cat / 3600 / (cat.m_S_0 + cat.m_S_el) SV_dch.to_csv(file_name_dch, index=False, header=True) t_elapsed = time.time() - t_count print('t_cpu=', t_elapsed, '\n') return SV_eq_df, SV_dch_df, SV_ch_df, tags
yd0 = numpy.array([-0, w0, w0,-g, 1e-12, 0, 0, 0]) #y0 = numpy.array([4.83617428e-01, -3.00000000e-02, -2.16050178e-01, 1.67315232e-16, -5.39725367e-14, -1.31300925e+01, -7.20313572e-02, -6.20545138e-02]) #yd0 = numpy.array([1.55140566e-17, -5.00453439e-15, -1.31302838e+01, 6.62087352e-13, -2.13577297e-10, 2.21484026e+02, -4.67637454e+00, -2.89824658e+00]) #startsw = [0,1, 0, 0] problem = Implicit_Problem(res, y0, yd0, t0, sw0=startsw) problem.state_events = state_events problem.handle_event = handle_event problem.name = 'Woodpecker' phipIndex = [4, 5] lambdaIndex = [6, 7] sim = IDA(problem) sim.rtol = 1e-6 sim.atol[phipIndex] = 1e8 sim.algvar[phipIndex] = 1 sim.atol[lambdaIndex] = 1e8 sim.algvar[lambdaIndex] = 1 sim.suppress_alg = True ncp = 500 tfinal = 2 t, y, yd = sim.simulate(tfinal, ncp) y = y[:,[ 0, ]] plt.plot(t, y) plt.legend(["z", "phi_s", "phi_b", "zp", "phip_s", "phip_b", "lambda_2", "lambda_2"], loc = 'lower left') print("Number of pecks", hack)
phi_ctr += 1 # Volume fraction of SEI per cell res[-1] = SV_dot[-1] return res """------------------------------------------------------------------------""" # Set up problem instance SEI_1D = Implicit_Problem(residual, SV_0, SV_dot_0, t_0) # Define simulation parameters simulation = IDA(SEI_1D) # Create simulation instance simulation.atol = 1e-6 # Solver absolute tolerance simulation.rtol = 1e-6 # Solver relative tolerance simulation.maxh = 0.1 # Solver max step size # Set simulation end time, slope flag (for anode voltage cycle), and run simulation t_f = ((phi_bounds[1] - phi_anode_0)/R)*5 #ncp_list = np.arange(0, t_f, 0.15) #ncp = 10000 # Run simulation t, SV, SV_dot = simulation.simulate(t_f) # %% Organize data and plot
elif indexNumber == 2: problem = Implicit_Problem(squeezer2, y0, yd0, t0) algvar[lambdaIndex] = 0 algvar[velocityIndex] = 1 sim = IDA(problem) sim.atol = numpy.ones(numpy.size(y0))*1e-7 sim.atol[lambdaIndex] = 1e-5 sim.atol[velocityIndex] = 1e-5 elif indexNumber == 1: problem = Explicit_Problem(squeezer1, y0[0:14], t0) sim = RungeKutta34(problem) sim.atol = numpy.ones(14)*1e-7 problem.name = 'Squeezer' sim.rtol = 1e-8 tfinal = 0.03 ncp = 5000 if indexNumber == 2 or indexNumber == 3: sim.algvar = algvar sim.suppress_alg = True t, y, yd = sim.simulate(tfinal, ncp) elif indexNumber == 1: t, y, = sim.simulate(tfinal, ncp) print(numpy.shape(y)) #sim.plot()
def DAE_integration_assimulo_lagrangian(self, **kwargs): """ Perform time integration for DAEs with the assimulo package Lagrangian variant """ assert self.set_time_setting == 1, 'Time discretization must be specified first' if self.tclose > 0: close = True else: close = False # Control vector self.U = interpolate(self.boundary_cntrl_space, self.Vl).vector()[self.bndr_i_l] if self.discontinous_boundary_values == 1: self.U[self.Corner_indices] = self.U[self.Corner_indices]/2 self.UU = np.zeros(self.Nb) for i in range(self.Nb): self.UU[i] = self.boundary_cntrl_space(self.coord_b[i]) # Definition of the sparse solver for the DAE res function to # be defined next M should be invertible !! #my_solver = factorized(csc_matrix(self.M)) #rhs = self.my_mult(self.J, self.my_mult(self.Q,self.A0)) + self.my_mult(self.Bext,self.U* self.boundary_cntrl_time(0.,self.tclose)) #self.AD0 = my_solver(rhs) # Definition of the rhs function required in assimulo def res(t,y,yd): """ Definition of the residual function required in the DAE part of assimulo """ z = np.zeros(self.Np+self.Nl) z[0:self.Np] = self.my_mult(self.M_class, yd[0:self.Np]) + self.my_mult(self.D_class, y[0:self.Np]) - self.my_mult(self.C_class, y[self.Np:]) z[self.Np:self.Np+self.Nl] = self.my_mult(self.C_class.T, y[0:self.Np]) - self.L_class * self.boundary_cntrl_time(t,self.tclose) return z # Definition of the jacobian function required in assimulo def jac(c,t,y,yd): """ Definition of the Jacobian matrix required in the DAE part of assimulo """ #Matrix = csr_matrix(self.my_mult(self.J,self.Q)) #if close and t > self.tclose: # Matrix = csr_matrix(self.my_mult(self.J - self.R, self.Q)) #return c*csr_matrix(self.M) - Matrix return None # Definition of the jacobian matrix vector function required in assimulo def jacv(t,y,yd,res,v,c): """ Jacobian matrix-vector product required in the DAE part of assimulo """ #w = self.my_mult(self.Q, v) #z = self.my_mult(self.J, w) #if close and t > self.tclose: # z -= self.my_mult(self.R, w) #return c*self.my_mult(self.M,v) - z return None print('DAE Integration using assimulo built-in functions:') #def handle_result(solver, t ,y, yd): # global order # order.append(solver.get_last_order()) # # solver.t_sol.extend([t]) # solver.y_sol.extend([y]) # solver.yd_sol.extend([yd]) # The initial conditons y0 = np.concatenate(( self.Tp0, np.zeros(self.Nl) )) yd0 = np.zeros(self.Np + self.Nl) model = Implicit_Problem(res,y0,yd0,self.tinit) #model.handle_result = handle_result #model.jacv = jacv #sim = Radau5DAE(model,**kwargs) # # IDA method from Assimulo # sim = IDA(model,**kwargs) sim.algvar = list(np.concatenate((np.ones(self.Np), np.zeros(self.Nl) )) ) sim.atol = 1.e-6 sim.rtol = 1.e-6 sim.report_continuously = True ncp = self.Nt #sim.usejac = True sim.suppress_alg = True sim.inith = self.dt sim.maxord = 5 #sim.linear_solver = 'SPGMR' sim.make_consistent('IDA_YA_YDP_INIT') #time_span, DAE_y, DAE_yd = sim.simulate(self.tfinal,ncp, self.tspan) time_span, DAE_y, DAE_yd = sim.simulate(self.tfinal, 0, self.tspan) #print(sim.get_options()) print(sim.print_statistics()) A_dae = DAE_y[:,0:self.Np].transpose() # Hamiltonian self.Nt = A_dae.shape[1] self.tspan = np.array(time_span) Ham_dae = np.zeros(self.Nt) for k in range(self.Nt): Ham_dae[k] = 1/2 * self.my_mult(A_dae[:,k].T, \ self.my_mult(self.Mp_rho_Cv, A_dae[:,k])) self.Ham_dae = Ham_dae return Ham_dae, np.array(time_span)
def run_example(with_plots=True): r""" An example for IDA with scaled preconditioned GMRES method as a special linear solver. Note, how the operation Jacobian times vector is provided. ODE: .. math:: \dot y_1 - y_2 &= 0\\ \dot y_2 -9.82 &= 0 on return: - :dfn:`imp_mod` problem instance - :dfn:`imp_sim` solver instance """ #Defines the residual def res(t, y, yd): res_0 = yd[0] - y[1] res_1 = yd[1] + 9.82 return N.array([res_0, res_1]) #Defines the Jacobian*vector product def jacv(t, y, yd, res, v, c): jy = N.array([[0, -1.], [0, 0]]) jyd = N.array([[1, 0.], [0, 1]]) j = jy + c * jyd return N.dot(j, v) #Initial conditions y0 = [1.0, 0.0] yd0 = [0.0, -9.82] #Defines an Assimulo implicit problem imp_mod = Implicit_Problem( res, y0, yd0, name='Example using the Jacobian Vector product') imp_mod.jacv = jacv #Sets the jacobian imp_sim = IDA(imp_mod) #Create an IDA solver instance #Set the parameters imp_sim.atol = 1e-5 #Default 1e-6 imp_sim.rtol = 1e-5 #Default 1e-6 imp_sim.linear_solver = 'SPGMR' #Change linear solver #imp_sim.options["usejac"] = False #Simulate t, y, yd = imp_sim.simulate( 5, 1000) #Simulate 5 seconds with 1000 communication points #Basic tests nose.tools.assert_almost_equal(y[-1][0], -121.75000000, 4) nose.tools.assert_almost_equal(y[-1][1], -49.100000000) #Plot if with_plots: P.plot(t, y) P.xlabel('Time') P.ylabel('State') P.title(imp_mod.name) P.show() return imp_mod, imp_sim
def run_example(with_plots=True): r""" Example for demonstrating the use of a user supplied Jacobian ODE: .. math:: \dot y_1-y_3 &= 0 \\ \dot y_2-y_4 &= 0 \\ \dot y_3+y_5 y_1 &= 0 \\ \dot y_4+y_5 y_2+9.82&= 0 \\ y_3^2+y_4^2-y_5(y_1^2+y_2^2)-9.82 y_2&= 0 on return: - :dfn:`imp_mod` problem instance - :dfn:`imp_sim` solver instance """ global order order = [] #Defines the residual def f(t, y, yd): res_0 = yd[0] - y[2] res_1 = yd[1] - y[3] res_2 = yd[2] + y[4] * y[0] res_3 = yd[3] + y[4] * y[1] + 9.82 res_4 = y[2]**2 + y[3]**2 - y[4] * (y[0]**2 + y[1]**2) - y[1] * 9.82 return N.array([res_0, res_1, res_2, res_3, res_4]) def handle_result(solver, t, y, yd): global order order.append(solver.get_last_order()) solver.t_sol.extend([t]) solver.y_sol.extend([y]) solver.yd_sol.extend([yd]) #The initial conditons y0 = [1.0, 0.0, 0.0, 0.0, 5] #Initial conditions yd0 = [0.0, 0.0, 0.0, -9.82, 0.0] #Initial conditions #Create an Assimulo implicit problem imp_mod = Implicit_Problem(f, y0, yd0, name='Example for plotting used order') imp_mod.handle_result = handle_result #Sets the options to the problem imp_mod.algvar = [1.0, 1.0, 1.0, 1.0, 0.0] #Set the algebraic components #Create an Assimulo implicit solver (IDA) imp_sim = IDA(imp_mod) #Create a IDA solver #Sets the paramters imp_sim.atol = 1e-6 #Default 1e-6 imp_sim.rtol = 1e-6 #Default 1e-6 imp_sim.suppress_alg = True #Suppres the algebraic variables on the error test imp_sim.report_continuously = True #Let Sundials find consistent initial conditions by use of 'IDA_YA_YDP_INIT' imp_sim.make_consistent('IDA_YA_YDP_INIT') #Simulate t, y, yd = imp_sim.simulate(5) #Simulate 5 seconds #Basic tests nose.tools.assert_almost_equal(y[-1][0], 0.9401995, places=4) nose.tools.assert_almost_equal(y[-1][1], -0.34095124, places=4) nose.tools.assert_almost_equal(yd[-1][0], -0.88198927, places=4) nose.tools.assert_almost_equal(yd[-1][1], -2.43227069, places=4) nose.tools.assert_almost_equal(order[-1], 5, places=4) #Plot if with_plots: P.figure(1) P.plot(t, y, linestyle="dashed", marker="o") #Plot the solution P.xlabel('Time') P.ylabel('State') P.title(imp_mod.name) P.figure(2) P.plot([0] + N.add.accumulate(N.diff(t)).tolist(), order) P.title("Used order during the integration") P.xlabel("Time") P.ylabel("Order") P.show() return imp_mod, imp_sim
def dae_solver(residual, y0, yd0, t0, p0=None, jac=None, name='DAE', solver='IDA', algvar=None, atol=1e-6, backward=False, display_progress=True, pbar=None, report_continuously=False, rtol=1e-6, sensmethod='STAGGERED', suppress_alg=False, suppress_sens=False, usejac=False, usesens=False, verbosity=30, tfinal=10., ncp=500): ''' DAE solver. Parameters ---------- residual: function Implicit DAE model. y0: List[float] Initial model state. yd0: List[float] Initial model state derivatives. t0: float Initial simulation time. p0: List[float] Parameters for which sensitivites are to be calculated. jac: function Model jacobian. name: string Model name. solver: string DAE solver. algvar: List[bool] A list for defining which variables are differential and which are algebraic. The value True(1.0) indicates a differential variable and the value False(0.0) indicates an algebraic variable. atol: float Absolute tolerance. backward: bool Specifies if the simulation is done in reverse time. display_progress: bool Actives output during the integration in terms of that the current integration is periodically printed to the stdout. Report_continuously needs to be activated. pbar: List[float] An array of positive floats equal to the number of parameters. Default absolute values of the parameters. Specifies the order of magnitude for the parameters. Useful if IDAS is to estimate tolerances for the sensitivity solution vectors. report_continuously: bool Specifies if the solver should report the solution continuously after steps. rtol: float Relative tolerance. sensmethod: string Specifies the sensitivity solution method. Can be either ‘SIMULTANEOUS’ or ‘STAGGERED’. Default is 'STAGGERED'. suppress_alg: bool Indicates that the error-tests are suppressed on algebraic variables. suppress_sens: bool Indicates that the error-tests are suppressed on the sensitivity variables. usejac: bool Sets the option to use the user defined jacobian. usesens: bool Aactivates or deactivates the sensitivity calculations. verbosity: int Determines the level of the output. QUIET = 50 WHISPER = 40 NORMAL = 30 LOUD = 20 SCREAM = 10 tfinal: float Simulation final time. ncp: int Number of communication points (number of return points). Returns ------- sol: solution [time, model states], List[float] ''' if usesens is True: # parameter sensitivity model = Implicit_Problem(residual, y0, yd0, t0, p0=p0) else: model = Implicit_Problem(residual, y0, yd0, t0) model.name = name if usejac is True: # jacobian model.jac = jac if algvar is not None: # differential or algebraic variables model.algvar = algvar if solver == 'IDA': # solver from assimulo.solvers import IDA sim = IDA(model) sim.atol = atol sim.rtol = rtol sim.backward = backward # backward in time sim.report_continuously = report_continuously sim.display_progress = display_progress sim.suppress_alg = suppress_alg sim.verbosity = verbosity if usesens is True: # sensitivity sim.sensmethod = sensmethod sim.pbar = np.abs(p0) sim.suppress_sens = suppress_sens # Simulation # t, y, yd = sim.simulate(tfinal, ncp=(ncp - 1)) ncp_list = np.linspace(t0, tfinal, num=ncp, endpoint=True) t, y, yd = sim.simulate(tfinal, ncp=0, ncp_list=ncp_list) # Plot # sim.plot() # plt.figure() # plt.subplot(221) # plt.plot(t, y[:, 0], 'b.-') # plt.legend([r'$\lambda$']) # plt.subplot(222) # plt.plot(t, y[:, 1], 'r.-') # plt.legend([r'$\dot{\lambda}$']) # plt.subplot(223) # plt.plot(t, y[:, 2], 'k.-') # plt.legend([r'$\eta$']) # plt.subplot(224) # plt.plot(t, y[:, 3], 'm.-') # plt.legend([r'$\dot{\eta}$']) # plt.figure() # plt.subplot(221) # plt.plot(t, yd[:, 0], 'b.-') # plt.legend([r'$\dot{\lambda}$']) # plt.subplot(222) # plt.plot(t, yd[:, 1], 'r.-') # plt.legend([r'$\ddot{\lambda}$']) # plt.subplot(223) # plt.plot(t, yd[:, 2], 'k.-') # plt.legend([r'$\dot{\eta}$']) # plt.subplot(224) # plt.plot(t, yd[:, 3], 'm.-') # plt.legend([r'$\ddot{\eta}$']) # plt.figure() # plt.subplot(121) # plt.plot(y[:, 0], y[:, 1]) # plt.xlabel(r'$\lambda$') # plt.ylabel(r'$\dot{\lambda}$') # plt.subplot(122) # plt.plot(y[:, 2], y[:, 3]) # plt.xlabel(r'$\eta$') # plt.ylabel(r'$\dot{\eta}$') # plt.figure() # plt.subplot(121) # plt.plot(yd[:, 0], yd[:, 1]) # plt.xlabel(r'$\dot{\lambda}$') # plt.ylabel(r'$\ddot{\lambda}$') # plt.subplot(122) # plt.plot(yd[:, 2], yd[:, 3]) # plt.xlabel(r'$\dot{\eta}$') # plt.ylabel(r'$\ddot{\eta}$') # plt.figure() # plt.subplot(121) # plt.plot(y[:, 0], y[:, 2]) # plt.xlabel(r'$\lambda$') # plt.ylabel(r'$\eta$') # plt.subplot(122) # plt.plot(y[:, 1], y[:, 3]) # plt.xlabel(r'$\dot{\lambda}$') # plt.ylabel(r'$\dot{\eta}$') # plt.figure() # plt.subplot(121) # plt.plot(yd[:, 0], yd[:, 2]) # plt.xlabel(r'$\dot{\lambda}$') # plt.ylabel(r'$\dot{\eta}$') # plt.subplot(122) # plt.plot(yd[:, 1], yd[:, 3]) # plt.xlabel(r'$\ddot{\lambda}$') # plt.ylabel(r'$\ddot{\eta}$') # plt.show() sol = [t, y, yd] return sol
def main(): SV_0 = solver_inputs.SV_0 SV_dot_0 = np.zeros_like(SV_0) algvar = solver_inputs.algvar # Close any open pyplot objects: plt.close('all') atol = np.ones_like(SV_0)*1e-8 rtol = 1e-4 # Start a timer: t_count = time.time() # Calculate the time span, which should be enough to charge or discharge fully # (i.e. 3600 seconds divided by the C-rate): t_0 = 0 t_f = 3600/Inputs.C_rate rate_tag = str(Inputs.C_rate)+"C" """----------Figures----------""" if Inputs.plot_profiles_flag: fig1, axes1, fig2, axes2, fig3, axes3 = setup_plots(plt, rate_tag) for cycle in np.arange(0, Inputs.n_cycles): """----------Equilibration----------""" # Equilibrate by integrating at zero current: print('\nEquilibrating...') # Create problem instance current.set_i_ext(0) battery_eq = li_ion(li_ion.res_fun, SV_0, SV_dot_0, t_0) battery_eq.external_event_detection = True battery_eq.algvar = algvar # Simulation parameters sim_eq = IDA(battery_eq) # Create simulation instance sim_eq.atol = atol # Solver absolute tolerance sim_eq.rtol = rtol # Solver relative tolerance sim_eq.verbosity = 50 sim_eq.make_consistent('IDA_YA_YDP_INIT') t_eq, SV_eq, SV_dot_eq = sim_eq.simulate(0.1*t_f) # Put solution into pandas dataframe with labeled columns SV_eq_df = Label_Columns(t_eq, SV_eq, an.npoints, sep.npoints, cat.npoints) # Obtain tag strings for dataframe columns tags = tag_strings(SV_eq_df) print('Done equilibrating\n') """------------Charging-------------""" print('\nCharging...') # New initial conditions are the final equilibrium conditions t_0 = 0 SV_0 = SV_eq[-1, :] SV_dot_0 = SV_dot_eq[-1 :] # Charge the battery current.set_i_ext(current.i_ext_set) # Create problem instance battery_ch = li_ion(li_ion.res_fun, SV_0, SV_dot_0, t_0) battery_ch.external_event_detection = True battery_ch.algvar = algvar # Simulation parameters sim_ch = IDA(battery_ch) sim_ch.atol = atol sim_ch.rtol = rtol sim_ch.verbosity = 50 sim_ch.make_consistent('IDA_YA_YDP_INIT') t_ch, SV_ch, SV_dot_ch = sim_ch.simulate(t_f) SV_ch_df = Label_Columns(t_ch, SV_ch, an.npoints, sep.npoints, cat.npoints) if Inputs.plot_potential_profiles == 1: plot_potential(tags['Phi_an'], tags['Phi_cat'], SV_ch_df, 'Charging', 0, fig1, axes1) if Inputs.plot_electrode_profiles == 1: plot_electrode(tags['X_an'], tags['X_cat'], SV_ch_df, 'Charging', 0, fig2, axes2) if Inputs.plot_elyte_profiles == 1: plot_elyte(tags['X_el_an'], tags['X_el_cat'], tags['X_el_sep'], SV_ch_df, 'Charging', 0, fig3, axes3) print('Done charging\n') """------------Re_equilibrating-------------""" if Inputs.flag_re_equil == 1: # New initial conditions are the final charge conditions SV_0 = SV_ch[-2, :] SV_dot_0 = SV_dot_ch[-2, :] # Equilibrate again. Note - this is a specific choice to reflect # equilibration after the charging steps. We may want, at times, to # simulate a situation where the battery is not equilibrated between # charge and discharge, or is equilibrated for a shorter amount of time. print('\nRe-equilibrating...') current.set_i_ext(0) battery_req = li_ion(li_ion.res_fun, SV_0, SV_dot_0, t_0) battery_req.external_event_detection = True battery_req.algvar = algvar # Simulation parameters sim_req = IDA(battery_req) sim_req.atol = atol sim_req.rtol = rtol sim_req.verbosity = 50 sim_req.make_consistent('IDA_YA_YDP_INIT') t_req, SV_req, SV_dot_req = sim_req.simulate(t_f) SV_req_df = Label_Columns(t_req, SV_req, an.npoints, sep.npoints, cat.npoints) if Inputs.plot_potential_profiles*Inputs.phi_time == 1: plot_potential(tags['Phi_an'], tags['Phi_cat'], SV_req_df, 'Re-equilibrating', 1, None, fig1, axes1) if Inputs.plot_electrode_profiles == 1: plot_electrode(tags['X_an'], tags['X_cat'], SV_req_df, 'Re-equilibrating', 1, fig2, axes2) if Inputs.plot_elyte_profiles == 1: plot_elyte(tags['X_el_an'], tags['X_el_cat'], tags['X_el_sep'], SV_req_df, 'Re-equilibrating', 1, fig3, axes3) print('Done re-equilibrating\n') else: SV_req = SV_ch SV_dot_req = SV_dot_ch SV_req_df = SV_req """------------Discharging-------------""" print('\nDischarging...') SV_0 = SV_req[-1, :] SV_dot_0 = SV_dot_req[-1, :] current.set_i_ext(-current.i_ext_set) battery_dch = li_ion(li_ion.res_fun, SV_0, SV_dot_0, t_0) battery_dch.external_event_detection = True battery_dch.algvar = algvar # Simulation parameters sim_dch = IDA(battery_dch) sim_dch.atol = atol sim_dch.rtol = rtol sim_dch.verbosity = 50 sim_dch.make_consistent('IDA_YA_YDP_INIT') t_dch, SV_dch, SV_dot_dch = sim_dch.simulate(t_f) SV_dch_df = Label_Columns(t_dch, SV_dch, an.npoints, sep.npoints, cat.npoints) if Inputs.plot_potential_profiles == 1: plot_potential(tags['Phi_an'], tags['Phi_cat'], SV_dch_df, 'Discharging', 1+(Inputs.flag_re_equil*Inputs.phi_time), fig1, axes1) if Inputs.plot_electrode_profiles == 1: plot_electrode(tags['X_an'], tags['X_cat'], SV_dch_df, 'Discharging', 1+Inputs.flag_re_equil, fig2, axes2) if Inputs.plot_elyte_profiles == 1: plot_elyte(tags['X_el_an'], tags['X_el_cat'], tags['X_el_sep'], SV_dch_df, 'Discharging', 1+Inputs.flag_re_equil, fig3, axes3) print('Done discharging\n') """---------------------------------""" SV_0 = SV_dch[-1, :] SV_dot_0 = np.zeros_like(SV_0) # %% Plot capacity if flagged plt.show('all') plot_cap(SV_ch_df, SV_dch_df, rate_tag, current.i_ext_set, Inputs.plot_cap_flag, tags) elapsed = time.time() - t_count print('t_cpu=', elapsed, '\n') plt.show() return SV_eq_df, SV_ch_df, SV_req_df, SV_dch_df
def run_example(with_plots=True): """ This example show how to use Assimulo and IDA for simulating sensitivities for initial conditions.:: 0 = dy1/dt - -(k01+k21+k31)*y1 - k12*y2 - k13*y3 - b1 0 = dy2/dt - k21*y1 + (k02+k12)*y2 0 = dy3/dt - k31*y1 + k13*y3 y1(0) = p1, y2(0) = p2, y3(0) = p3 p1=p2=p3 = 0 See http://sundials.2283335.n4.nabble.com/Forward-sensitivities-for-initial-conditions-td3239724.html on return: - :dfn:`imp_mod` problem instance - :dfn:`imp_sim` solver instance """ def f(t, y, yd, p): y1, y2, y3 = y yd1, yd2, yd3 = yd k01 = 0.0211 k02 = 0.0162 k21 = 0.0111 k12 = 0.0124 k31 = 0.0039 k13 = 0.000035 b1 = 49.3 res_0 = -yd1 - (k01 + k21 + k31) * y1 + k12 * y2 + k13 * y3 + b1 res_1 = -yd2 + k21 * y1 - (k02 + k12) * y2 res_2 = -yd3 + k31 * y1 - k13 * y3 return N.array([res_0, res_1, res_2]) #The initial conditions y0 = [0.0, 0.0, 0.0] #Initial conditions for y yd0 = [49.3, 0., 0.] p0 = [0.0, 0.0, 0.0] #Initial conditions for parameters yS0 = N.array([[1, 0, 0], [0, 1, 0], [0, 0, 1.]]) #Create an Assimulo implicit problem imp_mod = Implicit_Problem(f, y0, yd0, p0=p0, name='Example: Computing Sensitivities') #Sets the options to the problem imp_mod.yS0 = yS0 #Create an Assimulo explicit solver (IDA) imp_sim = IDA(imp_mod) #Sets the paramters imp_sim.rtol = 1e-7 imp_sim.atol = 1e-6 imp_sim.pbar = [ 1, 1, 1 ] #pbar is used to estimate the tolerances for the parameters imp_sim.report_continuously = True #Need to be able to store the result using the interpolate methods imp_sim.sensmethod = 'SIMULTANEOUS' #Defines the sensitvity method used imp_sim.suppress_sens = False #Dont suppress the sensitivity variables in the error test. #Simulate t, y, yd = imp_sim.simulate(400) #Simulate 400 seconds #Basic test nose.tools.assert_almost_equal(y[-1][0], 1577.6552477, 3) nose.tools.assert_almost_equal(y[-1][1], 611.9574565, 3) nose.tools.assert_almost_equal(y[-1][2], 2215.88563217, 3) nose.tools.assert_almost_equal(imp_sim.p_sol[0][1][0], 1.0) #Plot if with_plots: P.figure(1) P.subplot(221) P.plot(t, N.array(imp_sim.p_sol[0])[:, 0], t, N.array(imp_sim.p_sol[0])[:, 1], t, N.array(imp_sim.p_sol[0])[:, 2]) P.title("Parameter p1") P.legend(("p1/dy1", "p1/dy2", "p1/dy3")) P.subplot(222) P.plot(t, N.array(imp_sim.p_sol[1])[:, 0], t, N.array(imp_sim.p_sol[1])[:, 1], t, N.array(imp_sim.p_sol[1])[:, 2]) P.title("Parameter p2") P.legend(("p2/dy1", "p2/dy2", "p2/dy3")) P.subplot(223) P.plot(t, N.array(imp_sim.p_sol[2])[:, 0], t, N.array(imp_sim.p_sol[2])[:, 1], t, N.array(imp_sim.p_sol[2])[:, 2]) P.title("Parameter p3") P.legend(("p3/dy1", "p3/dy2", "p3/dy3")) P.subplot(224) P.title('ODE Solution') P.plot(t, y) P.suptitle(imp_mod.name) P.show() return imp_mod, imp_sim
def main(): res_class = eval(inputs.test_type) # plt.close('all') t_count = time.time() SV_0 = sol_init.SV_0 SV_dot_0 = np.zeros_like(SV_0) t_0 = 0. t_f = 3600. / inputs.C_rate algvar = sol_init.algvar atol = np.ones_like(SV_0) * 1e-5 atol[cat.ptr_vec['eps_S8']] = 1e-25 atol[cat.ptr_vec['eps_Li2S']] = 1e-25 atol[cat.ptr_vec['rho_k_el']] = 1e-25 # atol = 1e-30; rtol = 1e-4 sim_output = 50 rate_tag = str(inputs.C_rate) + "C" fig, axes = plt.subplots(sharey="row", figsize=(9, 12), nrows=3, ncols=1) plt.subplots_adjust(wspace=0.15, hspace=0.4) fig.text(0.15, 0.8, rate_tag, fontsize=20, bbox=dict(facecolor='white', alpha=0.5)) # Set up user function to build figures based on inputs "----------Equilibration----------" print('\nEquilibrating...') # Set external current to 0 for equilibration cat.set_i_ext(0) # Create problem object bat_eq = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_eq.external_event_detection = True bat_eq.algvar = algvar # Create simulation object sim_eq = IDA(bat_eq) sim_eq.atol = atol sim_eq.rtol = rtol sim_eq.verbosity = sim_output sim_eq.make_consistent('IDA_YA_YDP_INIT') t_eq, SV_eq, SV_dot_eq = sim_eq.simulate(t_f) # Put solution into pandas dataframe with labeled columns SV_eq_df = label_columns(t_eq, SV_eq, an.npoints, sep.npoints, cat.npoints) # SV_eq_df = [] # Obtain tag strings for dataframe columns tags = tag_strings(SV_eq_df) # plot_sim(tags, SV_eq_df, 'Equilibrating', 0, fig, axes) # print(SV_eq_df[tags['rho_el'][4:10]].iloc[-1]) print('Done equilibrating\n') "------------Discharging-------------" print('Discharging...') # New initial conditions from previous simulation SV_0 = SV_eq[-1, :] SV_dot_0 = SV_dot_eq[-1, :] # Set external current cat.set_i_ext(cat.i_ext_amp) # Update problem instance initial conditions bat_dch = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) bat_dch.external_event_detection = True bat_dch.algvar = algvar # Re-initialize simulation object sim_dch = IDA(bat_dch) sim_dch.atol = atol sim_dch.rtol = rtol sim_dch.maxh = 5 sim_dch.verbosity = sim_output sim_dch.make_consistent('IDA_YA_YDP_INIT') t_dch, SV_dch, SV_dot_dch = sim_dch.simulate(t_f) # if hasattr(cathode, 'get_tflag'): # t_flag_ch = cathode.get_tflag SV_dch_df = label_columns(t_dch, SV_dch, an.npoints, sep.npoints, cat.npoints) # SV_dch_df = [] # Obtain tag strings for dataframe columns # tags = tag_strings(SV_ch_df) plot_sim(tags, SV_dch_df, 'Discharging', 1, fig, axes) plot_meanPS(SV_dch_df, tags) print('Done Discharging\n') "--------Re-equilibration---------" # if inputs.flag_req == 1: # # print('Re-equilibrating...') # # # New initial conditions from previous simulation # SV_0 = SV_ch[-1, :] # SV_dot_0 = SV_dot_ch[-1, :] # # # Set external current # cat.set_i_ext(0) # # # Update problem instance initial conditions # bat_req = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) # bat_req.external_event_detection = True # bat_req.algvar = algvar # # # Re-initialize simulation object # sim_req = IDA(bat_req) # sim_req.atol = atol # sim_req.rtol = rtol # sim_req.verbosity = sim_output # sim_req.make_consistent('IDA_YA_YDP_INIT') # # t_req, SV_req, SV_dot_req = sim_req.simulate(t_f) # # SV_req_df = label_columns(t_req, SV_req, an.npoints, sep.npoints, cat.npoints) # ## plot_sim(tags, SV_req_df, 'Re-Equilibrating', 2-1, fig, axes) # # print('Done re-equilibrating\n') # else: # SV_req = SV_ch # SV_dot_req = SV_dot_ch "-----------Charging-----------" # print('Charging...') # # SV_0 = SV_req[-1, :] # SV_dot_0 = SV_dot_req[-1, :] # # cat.set_i_ext(-cat.i_ext_amp) # # # Update problem instance initial conditions # bat_dch = res_class(res_class.res_fun, SV_0, SV_dot_0, t_0) # bat_dch.external_event_detection = True # bat_dch.algvar = algvar # # # Re-initialize simulation object # sim_dch = IDA(bat_dch) # sim_dch.atol = atol # sim_dch.rtol = rtol # sim_dch.verbosity = sim_output # sim_dch.make_consistent('IDA_YA_YDP_INIT') # # t_dch, SV_dch, SV_dot_dch = sim_dch.simulate(t_f) # ## if hasattr(cathode, 'get_tflag'): ## t_flag_dch = cathode.get_tflag # # SV_dch_df = label_columns(t_dch, SV_dch, an.npoints, sep.npoints, cat.npoints) # # plot_sim(tags, SV_dch_df, 'Charging', 3, fig, axes) # # print('Done Charging\n') t_elapsed = time.time() - t_count print('t_cpu=', t_elapsed, '\n') return SV_eq_df, SV_dch_df, tags #SV_eq_df, SV_req_df #, SV_dch_df