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 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 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 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 run_example(with_plots=True): r""" Example of the use of IDA for an implicit differential equation with a discontinuity (state event) and the need for an event iteration. on return: - :dfn:`imp_mod` problem instance - :dfn:`imp_sim` solver instance """ #Create an instance of the problem imp_mod = Extended_Problem() #Create the problem imp_sim = IDA(imp_mod) #Create the solver imp_sim.verbosity = 0 imp_sim.report_continuously = True #Simulate t, y, yd = imp_sim.simulate(10.0,1000) #Simulate 10 seconds with 1000 communications points #Plot if with_plots: import pylab as P P.plot(t,y) P.title(imp_mod.name) P.ylabel('States') P.xlabel('Time') P.show() #Basic test nose.tools.assert_almost_equal(y[-1][0],8.0) nose.tools.assert_almost_equal(y[-1][1],3.0) nose.tools.assert_almost_equal(y[-1][2],2.0) 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(): 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 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
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
### Simulate #imp_mod.set_iapp( I_app/10. ) #imp_sim.make_consistent('IDA_YA_YDP_INIT') #ta, ya, yda = imp_sim.simulate(0.1,5) ## #imp_mod.set_iapp( I_app/2. ) #imp_sim.make_consistent('IDA_YA_YDP_INIT') #tb, yb, ydb = imp_sim.simulate(0.2,5) #imp_mod.set_iapp( I_app ) #imp_sim.make_consistent('IDA_YA_YDP_INIT') ## Sim step 1 #t1, y1, yd1 = imp_sim.simulate(1./Crate*3600.*0.2,100) imp_sim.display_progress = False imp_sim.verbosity = 50 imp_sim.report_continuously = True imp_sim.time_limit = 10. ### Simulate t01, t02 = 0.1, 0.2 imp_mod.set_iapp(I_app / 10.) imp_sim.make_consistent('IDA_YA_YDP_INIT') ta, ya, yda = imp_sim.simulate(t01, 2) imp_mod.set_iapp(I_app / 2.) imp_sim.make_consistent('IDA_YA_YDP_INIT') tb, yb, ydb = imp_sim.simulate(t02, 2) print 'yb shape', yb.shape
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