Line data Source code
1 : /*
2 : * Cell_SPM.hpp
3 : *
4 : * Header file for the parent Class for all Cells.
5 : *
6 : * It also defines a number of structs:
7 : * DEG_ID settings about which degradation models should be used for the simulations
8 : * SEIparam fitting parameters of the various models for SEI growth
9 : * CSparam fitting parameters of the various models for crach growth on the surface of the electrodes
10 : * LAMparam fitting parameters of the various models for loss of active material
11 : * PLparam fitting parameters of the various models for lithium plating
12 : *
13 : * Copyright (c) 2019, The Chancellor, Masters and Scholars of the University
14 : * of Oxford, VITO nv, and the 'Slide' Developers.
15 : * See the licence file LICENCE.txt for more information.
16 : */
17 :
18 : #pragma once
19 :
20 : #include "State_SPM.hpp" //!< class that represents the state of a cell, the state is the collection of all time-varying conditions of the battery
21 : #include "Model_SPM.hpp" //!< defines a struct with the values for the matrices used in the spatial discretisation of the diffusion PDE
22 : #include "param/param_SPM.hpp"
23 : #include "../Cell.hpp"
24 : #include "../../utility/utility.hpp" // Do not remove they are required in cpp files.
25 : #include "../../settings/settings.hpp" // Do not remove they are required in cpp files.
26 : #include "../../types/OCVcurves.hpp"
27 :
28 : #include <vector>
29 : #include <array>
30 : #include <iostream>
31 : #include <memory>
32 :
33 : namespace slide {
34 :
35 : //!< State related functions
36 : void validState(State_SPM &s, State_SPM &s_ini);
37 :
38 : class Cell_SPM : public Cell
39 : {
40 : public:
41 : DEG_ID deg_id; //!< structure with the identification of which degradation model(s) to use #TODO may be protected.
42 : using sigma_type = std::array<double, settings::nch + 2>;
43 :
44 : protected: //!< protected such that child classes can access the class variables
45 : State_SPM st{}, s_ini{}; //!< the battery current/initial state, grouping all parameter which change over the battery's lifetime (see State_SPM.hpp)
46 :
47 : //!< Battery model constants
48 : double Cmaxpos{ 51385 }; //!< maximum lithium concentration in the cathode [mol m-3] value for NMC
49 : double Cmaxneg{ 30555 }; //!< maximum lithium concentration in the anode [mol m-3] value for C
50 : double C_elec{ 1000 }; //!< Li- concentration in electrolyte [mol m-3] standard concentration of 1 molar
51 :
52 : double n{ 1 }; //!< number of electrons involved in the main reaction [-] #TODO if really constant?
53 :
54 : //!< parameters of the main li-insertion reaction
55 : double kp{ 5e-11 }; //!< rate constant of main reaction at positive electrode at reference temperature
56 : double kp_T{ 58000 }; //!< activation energy for the Arrhenius relation of kp
57 : double kn{ 1.7640e-11 }; //!< rate constant of main reaction at negative electrode at reference temperature
58 : double kn_T{ 20000 }; //!< activation energy for the Arrhenius relation of kn
59 : //!< The diffusion constants at reference temperature are part of State because they can change over the battery's lifetime
60 : double Dp_T{ 29000 }; //!< activation energy for the Arrhenius relation of Dp
61 : double Dn_T{ 35000.0 / 5.0 }; //!< activation energy for the Arrhenius relation of Dn
62 :
63 : //!< Thermal model parameters
64 : double Therm_Qgen{}; //!< total heat generation since the last update [J]
65 : double Therm_Qgentot{}; //!< variable for unit testing, total heat generation since the beginning of this cell's life [J]
66 : double Therm_time{}; //!< time since the last update of the thermal model
67 : double T_env{ settings::T_ENV }; //!< environment temperature [K]
68 : double T_ref{ 25.0_degC }; //!< reference temperature [K]
69 :
70 : //!< Qch: 90 gives very good cooling, as if there is a fan pointed at the cell. values of 30-60 are representative for a cell on a shelf without forced cooling
71 : //!< 40 is representative for a cell on a shelf without forced cooling
72 : double Qch{ 45 }; //!< convective heat transfer coefficient per volume [W K-1 m-3]
73 : double rho{ 1626 }; //!< density of the battery
74 : double Cp{ 750 }; //!< thermal capacity of the battery #TODO = units missing.
75 :
76 : //!< Geometric parameters
77 : param::Geometry_SPM geo{};
78 : //!< other geometric parameters are part of State because they can change over the battery's lifetime
79 :
80 : param::StressParam sparam{ param::def::StressParam_Kokam }; //!< Stress parameters.
81 :
82 : //!< Constants and parameters for the SEI growth model //!< #TODO if we can make these static and speed gain.
83 : double rsei{ 2037.4 * 50 }; //!< specific resistance times real surface area of the SEI film [Ohm m] ? #TODO if unit is correct. aging fit.
84 : double nsei{ 1 }; //!< number of electrons involved in the SEI reaction [-]
85 : double alphasei{ 1 }; //!< charge transfer coefficient of the SEI reaction [-]
86 : double OCVsei{ 0.4 }; //!< equilibrium potential of the SEI side reaction [V]
87 : double rhosei{ 100e3 }; //!< partial molar volume of the SEI layer [m3 mol-1]
88 : double c_elec0{ 4.541e-3 }; //!< bulk concentration of the electrolyte molecule participating in the SEI growth (e.g. EC) [mol m-3]
89 : double Vmain{ 13 }; //!< partial molar volume of the main reaction, see Ashwin et al, 2016
90 : double Vsei{ 64.39 }; //!< partial molar volume of the SEI side reaction, see Ashwin et al., 2016
91 :
92 : param::SEIparam sei_p{ param::def::SEIparam_Kokam }; //!< structure with the fitting parameters of the different SEI growth models
93 :
94 : //!< surface crack parameters & constants
95 : param::CSparam csparam{}; //!< structure with the fitting parameters of the different crack growth models
96 :
97 : //!< LAM parameters & constants
98 : double OCVnmc{ 4.1 }; //!< equilibrium potential of the NMC dissolution side reaction [V]
99 : param::LAMparam lam_p{ param::def::LAMparam_Kokam }; //!< structure with the fitting parameters of the different LAM models
100 :
101 : //!< Li-plating parameters & constants //!< #TODO if we can make these static and speed gain.
102 : double npl{ 1 }; //!< number of electrons involved in the plating reaction [-]
103 : double alphapl{ 1 }; //!< charge transfer constant for the plating reaction [-]
104 : double OCVpl{ 0 }; //!< OCV of the plating reaction [V]
105 : double rhopl{ 10e6 }; //!< density of the plated lithium layer
106 : param::PLparam pl_p; //!< structure with the fitting parameters of the different plating models
107 :
108 : //!< Matrices for spatial discretisation of the solid diffusion model
109 : Model_SPM *M{ Model_SPM::makeModel() };
110 :
111 : //!< OCV curves
112 : OCVcurves OCV_curves;
113 :
114 : bool Vcell_valid{ false };
115 :
116 : //!< Functions
117 : std::pair<double, double> calcSurfaceConcentration(double jp, double jn, double Dpt, double Dnt);
118 : std::pair<double, double> calcOverPotential(double cps, double cns, double i_app); //!< Should not throw normally, except divide by zero?
119 :
120 : inline double calcArrheniusCoeff() { return (1 / T_ref - 1 / st.T()) / PhyConst::Rg; } //!< Calculates Arrhenius coefficient.
121 :
122 : std::array<double, 2> calcDiffConstant(); //!< Calculate the diffusion constant at the battery temperature using an Arrhenius relation
123 : std::array<double, 3> calcMolarFlux(); //!< Calculate molar flux
124 :
125 : //!< void setStates(State_SPM &&states); //!< set the cell's states to the states in the array
126 :
127 : //!< degradation models
128 : void SEI(double OCVnt, double etan, double *isei, double *den); //!< calculate the effect of SEI growth
129 : void CS(double OCVnt, double etan, double *isei_multiplyer, double *dCS, double *dDn); //!< calculate the effect of surface crack growth
130 : void LAM(bool critical, double zp_surf, double etap, double *dthickp, double *dthickn, double *dap, double *dan, double *dep, double *den); //!< calculate the effect of LAM
131 : double LiPlating(double OCVnt, double etan);
132 :
133 : //!< state space model
134 : void dState_diffusion(bool print, State_SPM &d_state); //!< just diffusion PDE
135 : void dState_thermal(bool print, double &dQgen); //!< calculate the heat generation
136 : void dState_degradation(bool print, State_SPM &d_state); //!< calculate the effect of lithium plating
137 : void dState_all(bool print, State_SPM &d_state); //!< individual functions are combined in one function to gain speed.
138 :
139 : //!< thermal model
140 : double thermalModel_cell();
141 : double thermalModel_coupled(int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim);
142 :
143 : //!< cell to cell variations // #TODO why do we store variations?
144 : double var_cap{ 1 }; //!< relative factor increasing the capacity of the cell
145 : double var_R{ 1 }; //!< relative factor increasing the DC resistance
146 : double var_degSEI{ 1 }; //!< relative factor to speed up or slow down the rate of SEI growth
147 : double var_degLAM{ 1 }; //!< relative factor to speed up or slow down the rate of LAM
148 :
149 : public:
150 : //!< Constructor
151 : Cell_SPM(OCVcurves OCV_curves_) : OCV_curves(OCV_curves_) {}
152 : Cell_SPM(std::string IDi, const DEG_ID °id, double capf, double resf, double degfsei, double degflam);
153 :
154 : Cell_SPM(); //!< Default constructor.
155 :
156 : Cell_SPM(Model_SPM *M_ptr) : M(M_ptr) {}
157 :
158 : //!< getters
159 8 : double T() noexcept override { return st.T(); } //!< returns the uniform battery temperature in [K]
160 : double getTenv() const noexcept { return T_env; } //!< get the environmental temperature [K]
161 :
162 : Status setCurrent(double Inew, bool checkV = true, bool print = true) override;
163 : Status setSOC(double SOCnew, bool checkV = true, bool print = true) override;
164 :
165 2 : auto &getStateObj() { return st; }
166 : auto setStateObj(State_SPM &st_new)
167 : {
168 : st = st_new;
169 : Vcell_valid = false;
170 : }
171 :
172 : std::array<double, 4> getVariations() const noexcept override { return { var_cap, var_R, var_degSEI, var_degLAM }; } // #TODO : deprecated will be deleted.
173 :
174 : void getTemperatures(double *Tenv, double *Tref) noexcept //!< get the environmental and reference temperature
175 : {
176 : /*
177 : * Function to get the environmental and reference temperatures
178 : * OUT
179 : * Tenv environmental temperature [K]
180 : * Tref reference temperature [K] at which cell parameters are measured
181 : */
182 : *Tenv = T_env;
183 : *Tref = T_ref;
184 : }
185 :
186 : //!< thermal model
187 : double getThermalSurface() override;
188 : double thermalModel(int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim) override;
189 : double thermal_getTotalHeat(); //!< function for unit testing
190 :
191 : //!< double getR() noexcept //!< get the total cell DC resistance
192 : //!< {
193 : //!< /*
194 : //!< * Return the total cell DC resistance [Ohm]
195 : //!< * The total cell resistance is the sum of the resistance of the electrodes and the SEI layer
196 : //!< * the resistance of the electrodes increases due to loss of active material (LAM)
197 : //!< * the resistance of the SEI layer increases as the layer becomes thicker
198 : //!< * it is assumed the plated lithium does not add resistance
199 : //!< */
200 : //!< return (rsei * st.delta() + st.getR(elec_surf));
201 : //!< }
202 :
203 : double getRdc() noexcept; //!< calculate the resistance from every component
204 : double getRtot() override { return getRdc(); }
205 :
206 : double getAnodeSurface() noexcept { return st.an() * st.thickn() * geo.elec_surf; } //!< get the anode pure surface area (without cracks) product of the effective surface area (an) with the electrode volume
207 :
208 44 : double I() const override { return st.I(); } //!< get the cell current [A] positive for discharging
209 : double V() override;
210 :
211 : bool getCSurf(double &cps, double &cns, bool print); //!< get the surface concentrations
212 : void getC(double cp[], double cn[]) noexcept; //!< get the concentrations at all nodes
213 : int getVoltage(bool print, double *V, double *OCVp, double *OCVn, double *etap, double *etan, double *Rdrop, double *Temp); //!< get the cell's voltage
214 : int getVoltage_ne(bool print, double *V, double *OCVp, double *OCVn, double *etap, double *etan, double *Rdrop, double *Temp); //!< get the cell's voltage noexcept
215 :
216 : void getDaiStress(double *sigma_p, double *sigma_n, sigma_type &sigma_r_p, sigma_type &sigma_r_n, sigma_type &sigma_t_p, sigma_type &sigma_t_n, sigma_type &sigma_h_p, sigma_type &sigma_h_n) noexcept; //!< get the stresses at all nodes according to Dai's stress model
217 : void updateDaiStress() noexcept; //!< updated the stored stress values for Dai's stress model
218 : void getLaresgoitiStress(bool print, double *sigma_n); //!< get the stresses at all nodes according to Laresgoiti's stress model
219 : void updateLaresgoitiStress(bool print); //!< update the stored stress values for Laresgoiti's stress model
220 :
221 : //!< setters
222 : //!< void setVlimits(double VMAX, double VMIN); //!< set the voltage limits of the cell
223 : void setT(double T) override; //!< set the cell's temperature
224 : void setTenv(double Tenv); //!< set the environmental temperature
225 : //!< void setStates(const State_SPM &si, double I); //!< set the cell's states to the states in the State object and the cell current to the given value
226 : void setC(double cp0, double cn0); //!< set the concentrations to the given (uniform) concentration
227 : //!< void setCurrent(bool critical, bool check, double I); //!< set the cell's current to the specified value -> From old slide.
228 : void peekVoltage(double I); //!< Peeks voltage for state for given I
229 :
230 : //!< State related functions
231 :
232 : //!< void validState()
233 : //!< {
234 : //!< slide::validState(st, s_ini);
235 : //!< }
236 : ThroughputData getThroughputs() override { return { st.time(), st.Ah(), st.Wh() }; }
237 :
238 : void overwriteCharacterisationStates(double Dpi, double Dni, double ri)
239 : {
240 : //!< Overwrite both current and initial states.
241 : st.overwriteCharacterisationStates(Dpi, Dni, ri);
242 : s_ini.overwriteCharacterisationStates(Dpi, Dni, ri);
243 : }
244 :
245 : void overwriteGeometricStates(double thickpi, double thickni, double epi, double eni, double api, double ani)
246 : {
247 : //!< Overwrite both current and initial states.
248 : st.overwriteGeometricStates(thickpi, thickni, epi, eni, api, ani);
249 : s_ini.overwriteGeometricStates(thickpi, thickni, epi, eni, api, ani);
250 : }
251 :
252 : //!< time integration
253 : //!< void integratorStep(bool print, double dti, bool blockDegradation); //!< step forward in time using specified numerical integrator
254 :
255 : //!< void ETI_electr(bool print, double I, double dti, bool blockDegradation, bool pos); //!< step forward with only one electrode using forward Euler time integration
256 :
257 : //!< Base integrators:
258 :
259 : //!< State_SPM::states_type Int_FWEuler(bool print, double dti, bool blockDegradation); //!< Forward euler integrator.
260 : //!< State_SPM::states_type Int_RK4(bool print, double dti, bool blockDegradation); //!< Runge-Kutta 4 integrator.
261 :
262 : //!< Calculate the time derivatives of the states at the actual cell current (state-space model)
263 : State_SPM::states_type dState(bool print, State_SPM &d_state);
264 :
265 : //!< Utility
266 : void checkModelparam(); //!< check if the inputs to the MATLAB code are the same as the ones here in the C++ code
267 :
268 : //!< --- slide-pack functions --- //
269 :
270 : void getStates(getStates_t s) override { s.insert(s.end(), st.begin(), st.end()); } //!< returns the states of the cell collectively.
271 : std::span<double> viewStates() override { return std::span<double>(st.begin(), st.end()); }
272 : double getOCV() override;
273 : Status setStates(setStates_t sSpan, bool checkV, bool print) override;
274 : bool validStates(bool print = true) override;
275 7 : inline double SOC() override { return st.SOC(); }
276 : void timeStep_CC(double dt, int steps = 1) override;
277 :
278 : Cell_SPM *copy() override { return new Cell_SPM(*this); }
279 : //!< Obsolete functions (do not use):
280 : void ETI(bool print, double dti, bool blockDegradation); //!< step forward in time using forward Eurler time integration
281 :
282 : //!< Functions for fitting:
283 : void setOCVcurve(const std::string &namepos, const std::string &nameneg); //!< sets the OCV curve of the cell to the given value
284 : void setInitialConcentration(double cmaxp, double cmaxn, double lifracp, double lifracn); //!< sets the initial concentration
285 : void setGeometricParameters(double capnom, double elec_surf, double ep, double en, double thickp, double thickn); //!< sets the geometric parameters related to the amount of active material
286 : //!< void setRamping(double Istep, double tstep); //!< sets the ramping parameters
287 :
288 : void setCharacterisationParam(double Dp, double Dn, double kp, double kn, double Rdc); //!< sets the parameters related to the characterisation of the cell
289 : };
290 : } // namespace slide
|