def phis_mats(self, ): """ Solid phase parameters and j vector matrices """ p = self.p self.A_ps_a = batteqns.flux_mat_builder(p.Na, p.x_m_a, numpy.ones_like(p.vols_a), p.sig_a_eff) self.A_ps_c = batteqns.flux_mat_builder(p.Nc, p.x_m_c, numpy.ones_like(p.vols_c), p.sig_c_eff) Baps = numpy.array( [asa * p.F * dxa for asa, dxa in zip(p.as_a, p.vols_a)], dtype='d') Bcps = numpy.array( [asc * p.F * dxc for asc, dxc in zip(p.as_c, p.vols_c)], dtype='d') self.B_ps_a = numpy.diag(Baps) self.B_ps_c = numpy.diag(Bcps) self.B2_ps_a = numpy.zeros(p.Na, dtype='d') self.B2_ps_a[0] = -1. self.B2_ps_c = numpy.zeros(p.Nc, dtype='d') self.B2_ps_c[-1] = -1.
def update_cs_mats(self, csa, csc, csa_ss, csc_ss, csa_o, csc_o): """ FVM discretization of the concentration flux term for the solid particle diffusion equation. A matrix is generated for each particle that exists at each node point along the mesh in the thickness of each electrode. In general, the diffusivity is a function of concentration, and therefore these matrices are different for each particle, and change through time. If, Ds(cs) is constant, then this only needs to be initialized and then may be left constat during the simulation. """ p = self.p Acsa_list = [[] for i in range(p.Na)] Acsc_list = [[] for i in range(p.Nc)] Dsa_ss = [0. for i in range(p.Na)] Dsc_ss = [0. for i in range(p.Nc)] for ia in range(p.Na): csa_m = csa[ia * p.Nra:(ia + 1) * p.Nra] csa_e = numpy.array( [csa_o[ia]] + [0.5 * (csa_m[i + 1] + csa_m[i]) for i in range(p.Nra - 1)] + [csa_ss[ia]]) Ua_e = p.uref_a(csa_e / p.csa_max) Dsa_e = p.Dsa_intp(Ua_e) Acsa_list[ia] = batteqns.flux_mat_builder(p.Nra, p.r_m_a, p.vols_ra_m, Dsa_e * (p.r_e_a**2)) Dsa_ss[ia] = Dsa_e[-1] for ic in range(p.Nc): csc_m = csc[ic * p.Nrc:(ic + 1) * p.Nrc] csc_e = numpy.array( [csc_o[ic]] + [0.5 * (csc_m[i + 1] + csc_m[i]) for i in range(p.Nrc - 1)] + [csc_ss[ic]]) Uc_e = p.uref_c(csc_e / p.csc_max) Dsc_e = p.Dsc_intp(Uc_e) Acsc_list[ic] = batteqns.flux_mat_builder(p.Nrc, p.r_m_c, p.vols_rc_m, Dsc_e * (p.r_e_c**2)) Dsc_ss[ic] = Dsc_e[-1] self.A_cs_a = scipy.linalg.block_diag(*Acsa_list) self.A_cs_c = scipy.linalg.block_diag(*Acsc_list) self.D_cs_a = numpy.diag(-1.0 / (numpy.array(Dsa_ss) * self.c_n_a)) self.D_cs_c = numpy.diag(-1.0 / (numpy.array(Dsc_ss) * self.c_n_c))
def build_Ace_mat(self, c, T): """ FVM discretization of the concentration flux term for the elyte diffusion equation. """ p = self.p D_eff = self.Diff_ce(c, T) A = p.K_m.dot(batteqns.flux_mat_builder(p.N, p.x_m, p.vols, D_eff)) return A
def build_Ape_mat(self, c, T): """ FVM discretization of the potential flux term for the elyte potential equation. """ p = self.p k_eff = self.kapp_ce(c, T) A = batteqns.flux_mat_builder(p.N, p.x_m, p.vols, k_eff) A[-1, -1] = 2 * A[-1, -1] # BC update for phi_e = 0 return A
def build_Bpe_mat(self, c, T): """ FVM discretization of the concentration flux term for the elyte potential equation. """ p = self.p gam = 2. * (1. - p.t_plus) * p.R_gas * T / p.F k_eff = self.kapp_ce(c, T) c_edge = batteqns.mid_to_edge(c, p.x_e) B1 = batteqns.flux_mat_builder(p.N, p.x_m, p.vols, k_eff * gam / c_edge) return B1
def cs_mats(self, ): """ Intiliaze the solid phase diffusion model matrices. """ p = self.p # 1D spherical diffusion model # A_cs pre build self.A_csa_single = batteqns.flux_mat_builder(p.Nra, p.r_m_a, p.vols_ra_m, p.Dsa * (p.r_e_a**2)) self.A_csc_single = batteqns.flux_mat_builder(p.Nrc, p.r_m_c, p.vols_rc_m, p.Dsc * (p.r_e_c**2)) # A_cs build up to the stacked full cs size (Nr and Nx) b = [self.A_csa_single] * p.Na self.A_cs_a = scipy.linalg.block_diag(*b) b = [self.A_csc_single] * p.Nc self.A_cs_c = scipy.linalg.block_diag(*b) # B_cs and C_cs are constant (i.e., are not state-dependent) self.B_csa_single = numpy.array( [0. for i in range(p.Nra - 1)] + [-1. * p.r_e_a[-1]**2 / p.vols_ra_m[-1]], dtype='d') self.B_csc_single = numpy.array( [0. for i in range(p.Nrc - 1)] + [-1. * p.r_e_c[-1]**2 / p.vols_rc_m[-1]], dtype='d') b = [self.B_csa_single] * p.Na self.B_cs_a = scipy.linalg.block_diag(*b).T b = [self.B_csc_single] * p.Nc self.B_cs_c = scipy.linalg.block_diag(*b).T # Particle surface concentration h_na = p.r_e_a[-1] - p.r_m_a[-1] h_n1a = p.r_m_a[-1] - p.r_m_a[-2] h_nc = p.r_e_c[-1] - p.r_m_c[-1] h_n1c = p.r_m_c[-1] - p.r_m_c[-2] self.a_n_a, self.b_n_a, self.c_n_a = batteqns.right_side_coeffs( h_na, h_n1a) self.a_n_c, self.b_n_c, self.c_n_c = batteqns.right_side_coeffs( h_nc, h_n1c) self.C_cs_a_single = numpy.array( [0. for i in range(p.Nra - 2)] + [-self.a_n_a / self.c_n_a, -self.b_n_a / self.c_n_a], dtype='d') self.C_cs_c_single = numpy.array( [0. for i in range(p.Nrc - 2)] + [-self.a_n_c / self.c_n_c, -self.b_n_c / self.c_n_c], dtype='d') self.C_cs_a = scipy.linalg.block_diag(*[self.C_cs_a_single] * p.Na) self.C_cs_c = scipy.linalg.block_diag(*[self.C_cs_c_single] * p.Nc) self.C_cs_a_avg = scipy.linalg.block_diag( *[1. / ((1. / 3.) * p.Rp_a**3) * p.vols_ra_m] * p.Na) self.C_cs_c_avg = scipy.linalg.block_diag( *[1. / ((1. / 3.) * p.Rp_c**3) * p.vols_rc_m] * p.Nc) self.C_cs_a_mean = 1. / p.La * p.vols_a.dot(self.C_cs_a_avg) self.C_cs_c_mean = 1. / p.Lc * p.vols_c.dot(self.C_cs_c_avg) # Particle core concentration h_na = p.r_e_a[0] - p.r_m_a[0] h_n1a = p.r_m_a[1] - p.r_m_a[0] h_nc = p.r_e_c[0] - p.r_m_c[0] h_n1c = p.r_m_c[1] - p.r_m_c[0] a_n_a, b_n_a, c_n_a = batteqns.left_side_coeffs(h_na, h_n1a) a_n_c, b_n_c, c_n_c = batteqns.left_side_coeffs(h_nc, h_n1c) C_cso_a_single = numpy.array([-b_n_a / a_n_a, -c_n_a / a_n_a] + [0. for i in range(p.Nra - 2)], dtype='d') C_cso_c_single = numpy.array([-b_n_c / a_n_c, -c_n_c / a_n_c] + [0. for i in range(p.Nrc - 2)], dtype='d') self.C_cso_a = scipy.linalg.block_diag(*[C_cso_a_single] * p.Na) self.C_cso_c = scipy.linalg.block_diag(*[C_cso_c_single] * p.Nc) # D_cs prelim values, note this is Ds(cs) dependent and therefore # requires updating for state dependent Ds self.D_cs_a = -1.0 / (p.Dsa * self.c_n_a) * numpy.eye(p.Na) self.D_cs_c = -1.0 / (p.Dsc * self.c_n_c) * numpy.eye(p.Nc)