SLIDE  3.0.0
A simulator for lithium-ion battery pack degradation
Loading...
Searching...
No Matches
slide::Cell_SPM Class Reference

#include <Cell_SPM.hpp>

Inheritance diagram for slide::Cell_SPM:
[legend]
Collaboration diagram for slide::Cell_SPM:
[legend]

Public Types

using sigma_type = std::array< double, settings::nch+2 >
 

Public Member Functions

 Cell_SPM (OCVcurves OCV_curves_)
 < Constructor More...
 
 Cell_SPM (std::string IDi, const DEG_ID &degid, double capf, double resf, double degfsei, double degflam)
 
 Cell_SPM ()
 Default constructor. More...
 
 Cell_SPM (Model_SPM *M_ptr)
 getters More...
 
double T () noexcept override
 returns the uniform battery temperature in [K] More...
 
double getTenv () const noexcept
 get the environmental temperature [K] More...
 
Status setCurrent (double Inew, bool checkV=true, bool print=true) override
 
Status setSOC (double SOCnew, bool checkV=true, bool print=true) override
 
auto & getStateObj ()
 
auto setStateObj (State_SPM &st_new)
 
std::array< double, 4 > getVariations () const noexcept override
 
void getTemperatures (double *Tenv, double *Tref) noexcept
 < get the environmental and reference temperature More...
 
double getThermalSurface () override
 return the 'A' for the thermal model of this SU (Q = hA*dT) More...
 
double thermalModel (int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim) override
 
double thermal_getTotalHeat ()
 function for unit testing More...
 
double getRdc () noexcept
 calculate the resistance from every component More...
 
double getRtot () override
 
double getAnodeSurface () noexcept
 get the anode pure surface area (without cracks) product of the effective surface area (an) with the electrode volume More...
 
double I () const override
 get the cell current [A] positive for discharging More...
 
double V () override
 print is an optional argument More...
 
bool getCSurf (double &cps, double &cns, bool print)
 get the surface concentrations More...
 
void getC (double cp[], double cn[]) noexcept
 get the concentrations at all nodes More...
 
int getVoltage (bool print, double *V, double *OCVp, double *OCVn, double *etap, double *etan, double *Rdrop, double *Temp)
 get the cell's voltage More...
 
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 More...
 
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 More...
 
void updateDaiStress () noexcept
 updated the stored stress values for Dai's stress model More...
 
void getLaresgoitiStress (bool print, double *sigma_n)
 get the stresses at all nodes according to Laresgoiti's stress model More...
 
void updateLaresgoitiStress (bool print)
 update the stored stress values for Laresgoiti's stress model More...
 
void setT (double T) override
 set the cell's temperature More...
 
void setTenv (double Tenv)
 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 More...
 
void setC (double cp0, double cn0)
 void setCurrent(bool critical, bool check, double I); //!< set the cell's current to the specified value -> From old slide. More...
 
void peekVoltage (double I)
 Peeks voltage for state for given I. More...
 
ThroughputData getThroughputs () override
 
void overwriteCharacterisationStates (double Dpi, double Dni, double ri)
 
void overwriteGeometricStates (double thickpi, double thickni, double epi, double eni, double api, double ani)
 void ETI_electr(bool print, double I, double dti, bool blockDegradation, bool pos); //!< step forward with only one electrode using forward Euler time integration More...
 
State_SPM::states_type dState (bool print, State_SPM &d_state)
 Utility. More...
 
void checkModelparam ()
 check if the inputs to the MATLAB code are the same as the ones here in the C++ code More...
 
void getStates (getStates_t s) override
 returns the states of the cell collectively. More...
 
std::span< double > viewStates () override
 Only for cells to see individual states. More...
 
double getOCV () override
 
Status setStates (setStates_t sSpan, bool checkV, bool print) override
 opposite of getStates, check the states are valid? More...
 
bool validStates (bool print=true) override
 checks if a state array is valid More...
 
double SOC () override
 
void timeStep_CC (double dt, int steps=1) override
 setStates(std::move(states)); //!< store new states, checks if they are illegal (throws an error in that case) More...
 
Cell_SPMcopy () override
 Obsolete functions (do not use): More...
 
void ETI (bool print, double dti, bool blockDegradation)
 step forward in time using forward Eurler time integration More...
 
void setOCVcurve (const std::string &namepos, const std::string &nameneg)
 sets the OCV curve of the cell to the given value More...
 
void setInitialConcentration (double cmaxp, double cmaxn, double lifracp, double lifracn)
 sets the initial concentration More...
 
void setGeometricParameters (double capnom, double elec_surf, double ep, double en, double thickp, double thickn)
 void setRamping(double Istep, double tstep); //!< sets the ramping parameters More...
 
void setCharacterisationParam (double Dp, double Dn, double kp, double kn, double Rdc)
 sets the parameters related to the characterisation of the cell More...
 
- Public Member Functions inherited from slide::Cell
 Cell ()
 
 Cell (const std::string &ID_)
 
virtual ~Cell ()=default
 
double Cap () const final override
 
void setCapacity (double capacity)
 
constexpr double Vmin () const override
 lower voltage limit of the cell More...
 
constexpr double VMIN () const override
 safety cut off More...
 
constexpr double VMAX () const override
 safety cut off More...
 
constexpr double Vmax () const override
 upper voltage limit of the cell More...
 
constexpr double Tmax ()
 
constexpr double Tmin ()
 
double getVhigh () final
 return the voltage of the cell with the highest voltage More...
 
double getVlow () final
 return the voltage of the cell with the lowest voltage More...
 
virtual Status setSOC (double SOCnew, bool checkV=true, bool print=true)=0
 
virtual double SOC ()=0
 
virtual double getThotSpot () override
 the T of the hottest element in the SU More...
 
size_t getNcells () override final
 this is a single cell More...
 
virtual Status checkCurrent (bool checkV, bool print) noexcept
 
virtual Status checkVoltage (double &v, bool print) noexcept override
 Check the voltage status of the cell. More...
 
virtual double thermalModel (int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim) override
 Calculate the thermal model of the cell. More...
 
virtual void storeData () override
 Add another data point in the array. More...
 
virtual void writeData (const std::string &prefix) override
 
virtual ThroughputData getThroughputs ()
 
virtual std::array< double, 4 > getVariations () const noexcept
 
- Public Member Functions inherited from slide::StorageUnit
 StorageUnit ()=default
 < basic getters and setters More...
 
 StorageUnit (std::string_view ID_)
 
 StorageUnit (std::string_view ID_, StorageUnit *parent_, bool blockDegAndTherm_)
 
virtual ~StorageUnit ()=default
 
const std::string & getID ()
 
void setID (std::string IDi)
 Return the full ID string, including the ID of the parent module. More...
 
virtual std::string getFullID ()
 
virtual double Cap () const =0
 
auto * getParent ()
 
virtual double I () const =0
 
virtual double getRtot ()=0
 
virtual size_t getNcells ()=0
 return the number of single cells connected to this SU More...
 
bool isCharging ()
 negative means charge. More...
 
bool isDischarging ()
 positive means discharge. More...
 
virtual void getStates (getStates_t s)=0
 returns one long array with the states More...
 
virtual viewStates_t viewStates ()
 Only for cells to see individual states. More...
 
void setBlockDegAndTherm (bool block)
 
virtual void setParent (StorageUnit *p)
 set the parent More...
 
virtual Status setCurrent (double Inew, bool checkV=true, bool print=true)=0
 
virtual Status setVoltage (double Vnew, bool checkI=true, bool print=true)
 
virtual Status setStates (setStates_t s, bool checkStates=true, bool print=true)=0
 opposite of getStates, check the states are valid? More...
 
virtual void backupStates ()
 Back-up states. More...
 
virtual void restoreStates ()
 restore backed-up states. More...
 
virtual double getOCV ()=0
 
virtual double V ()=0
 print is an optional argument More...
 
virtual Status checkVoltage (double &v, bool print) noexcept=0
 get the voltage and check if it is valid More...
 
virtual double getVhigh ()=0
 return the voltage of the cell with the highest voltage More...
 
virtual double getVlow ()=0
 return the voltage of the cell with the lowest voltage More...
 
virtual double Vmin () const =0
 lower voltage limit of the cell More...
 
virtual double VMIN () const =0
 safety cut off More...
 
virtual double Vmax () const =0
 upper voltage limit of the cell More...
 
virtual double VMAX () const =0
 safety cut off More...
 
virtual double T ()=0
 
virtual double getThotSpot ()=0
 the T of the hottest element in the SU More...
 
virtual double getThermalSurface ()=0
 return the 'A' for the thermal model of this SU (Q = hA*dT) More...
 
virtual double thermalModel (int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim)=0
 calculate the thermal model of this SU More...
 
virtual void setT (double Tnew)=0
 functionality More...
 
virtual bool validStates (bool print=true)=0
 checks if a state array is valid More...
 
virtual StorageUnitcopy ()=0
 copy this SU to a new object More...
 
virtual void timeStep_CC (double dt, int steps=1)=0
 take a number of time steps More...
 
virtual void storeData ()=0
 
virtual void writeData (const std::string &prefix)=0
 

Public Attributes

DEG_ID deg_id
 structure with the identification of which degradation model(s) to use #TODO may be protected. More...
 

Protected Member Functions

std::pair< double, double > calcSurfaceConcentration (double jp, double jn, double Dpt, double Dnt)
 
std::pair< double, double > calcOverPotential (double cps, double cns, double i_app)
 Should not throw normally, except divide by zero? More...
 
double calcArrheniusCoeff ()
 Calculates Arrhenius coefficient. More...
 
std::array< double, 2 > calcDiffConstant ()
 Calculate the diffusion constant at the battery temperature using an Arrhenius relation. More...
 
std::array< double, 3 > calcMolarFlux ()
 Calculate molar flux. More...
 
void SEI (double OCVnt, double etan, double *isei, double *den)
 calculate the effect of SEI growth More...
 
void CS (double OCVnt, double etan, double *isei_multiplyer, double *dCS, double *dDn)
 calculate the effect of surface crack growth More...
 
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 More...
 
double LiPlating (double OCVnt, double etan)
 state space model More...
 
void dState_diffusion (bool print, State_SPM &d_state)
 just diffusion PDE More...
 
void dState_thermal (bool print, double &dQgen)
 calculate the heat generation More...
 
void dState_degradation (bool print, State_SPM &d_state)
 calculate the effect of lithium plating More...
 
void dState_all (bool print, State_SPM &d_state)
 individual functions are combined in one function to gain speed. More...
 
double thermalModel_cell ()
 
double thermalModel_coupled (int Nneighb, double Tneighb[], double Kneighb[], double Aneighb[], double tim)
 cell to cell variations // #TODO why do we store variations? More...
 
- Protected Member Functions inherited from slide::StorageUnit
virtual size_t calculateNcells ()
 

Protected Attributes

State_SPM st {}
 < protected such that child classes can access the class variables More...
 
State_SPM s_ini {}
 the battery current/initial state, grouping all parameter which change over the battery's lifetime (see State_SPM.hpp) More...
 
double Cmaxpos { 51385 }
 maximum lithium concentration in the cathode [mol m-3] value for NMC More...
 
double Cmaxneg { 30555 }
 maximum lithium concentration in the anode [mol m-3] value for C More...
 
double C_elec { 1000 }
 Li- concentration in electrolyte [mol m-3] standard concentration of 1 molar. More...
 
double n { 1 }
 number of electrons involved in the main reaction [-] #TODO if really constant? More...
 
double kp { 5e-11 }
 rate constant of main reaction at positive electrode at reference temperature More...
 
double kp_T { 58000 }
 activation energy for the Arrhenius relation of kp More...
 
double kn { 1.7640e-11 }
 rate constant of main reaction at negative electrode at reference temperature More...
 
double kn_T { 20000 }
 The diffusion constants at reference temperature are part of State because they can change over the battery's lifetime. More...
 
double Dp_T { 29000 }
 activation energy for the Arrhenius relation of Dp More...
 
double Dn_T { 35000.0 / 5.0 }
 activation energy for the Arrhenius relation of Dn More...
 
double Therm_Qgen {}
 total heat generation since the last update [J] More...
 
double Therm_Qgentot {}
 variable for unit testing, total heat generation since the beginning of this cell's life [J] More...
 
double Therm_time {}
 time since the last update of the thermal model More...
 
double T_env { settings::T_ENV }
 environment temperature [K] More...
 
double T_ref { 25.0_degC }
 reference temperature [K] More...
 
double Qch { 45 }
 convective heat transfer coefficient per volume [W K-1 m-3] More...
 
double rho { 1626 }
 density of the battery More...
 
double Cp { 750 }
 thermal capacity of the battery #TODO = units missing. More...
 
param::Geometry_SPM geo {}
 other geometric parameters are part of State because they can change over the battery's lifetime More...
 
param::StressParam sparam { param::def::StressParam_Kokam }
 Stress parameters. More...
 
double rsei { 2037.4 * 50 }
 specific resistance times real surface area of the SEI film [Ohm m] ? #TODO if unit is correct. aging fit. More...
 
double nsei { 1 }
 number of electrons involved in the SEI reaction [-] More...
 
double alphasei { 1 }
 charge transfer coefficient of the SEI reaction [-] More...
 
double OCVsei { 0.4 }
 equilibrium potential of the SEI side reaction [V] More...
 
double rhosei { 100e3 }
 partial molar volume of the SEI layer [m3 mol-1] More...
 
double c_elec0 { 4.541e-3 }
 bulk concentration of the electrolyte molecule participating in the SEI growth (e.g. EC) [mol m-3] More...
 
double Vmain { 13 }
 partial molar volume of the main reaction, see Ashwin et al, 2016 More...
 
double Vsei { 64.39 }
 partial molar volume of the SEI side reaction, see Ashwin et al., 2016 More...
 
param::SEIparam sei_p { param::def::SEIparam_Kokam }
 structure with the fitting parameters of the different SEI growth models More...
 
param::CSparam csparam {}
 structure with the fitting parameters of the different crack growth models More...
 
double OCVnmc { 4.1 }
 equilibrium potential of the NMC dissolution side reaction [V] More...
 
param::LAMparam lam_p { param::def::LAMparam_Kokam }
 structure with the fitting parameters of the different LAM models More...
 
double npl { 1 }
 number of electrons involved in the plating reaction [-] More...
 
double alphapl { 1 }
 charge transfer constant for the plating reaction [-] More...
 
double OCVpl { 0 }
 OCV of the plating reaction [V]. More...
 
double rhopl { 10e6 }
 density of the plated lithium layer More...
 
param::PLparam pl_p
 structure with the fitting parameters of the different plating models More...
 
Model_SPMM { Model_SPM::makeModel() }
 OCV curves. More...
 
OCVcurves OCV_curves
 
bool Vcell_valid { false }
 Functions. More...
 
double var_cap { 1 }
 relative factor increasing the capacity of the cell More...
 
double var_R { 1 }
 relative factor increasing the DC resistance More...
 
double var_degSEI { 1 }
 relative factor to speed up or slow down the rate of SEI growth More...
 
double var_degLAM { 1 }
 relative factor to speed up or slow down the rate of LAM More...
 
- Protected Attributes inherited from slide::Cell
double capNom { 16 }
 capacity [Ah]. More...
 
CellData< settings::DATASTORE_CELLcellData
 Cell data storage. More...
 
- Protected Attributes inherited from slide::StorageUnit
std::string ID { "StorageUnit" }
 identification string More...
 
StorageUnitparent { nullptr }
 pointer to the SU 'above' this one [e.g. the module to which a cell is connected] More...
 
bool blockDegAndTherm { false }
 if true, degradation and the thermal ODE are ignored More...
 

Additional Inherited Members

- Static Public Attributes inherited from slide::Cell
static constexpr CellLimits limits { defaultCellLimits }
 
- Protected Types inherited from slide::StorageUnit
using setStates_t = std::span< double > &
 To pass states to read, non-expandable container. More...
 
using getStates_t = std::vector< double > &
 To pass states to save, expandable container. More...
 
using viewStates_t = std::span< double >
 

Member Typedef Documentation

◆ sigma_type

using slide::Cell_SPM::sigma_type = std::array<double, settings::nch + 2>

Constructor & Destructor Documentation

◆ Cell_SPM() [1/4]

slide::Cell_SPM::Cell_SPM ( OCVcurves  OCV_curves_)
inline

< Constructor

◆ Cell_SPM() [2/4]

slide::Cell_SPM::Cell_SPM ( std::string  IDi,
const DEG_ID degid,
double  capf,
double  resf,
double  degfsei,
double  degflam 
)

< Set the resistance

< current collector

< cathode

< anode #TODO if you memoize Rdc then getRdc here.

< set the capacity

< nominal capacity

< surface area of the electrodes (current to current density)

< set the degradation factor

< set the degradation ID and related settings

< Check if we will have to calculate the stress according to Dai's stress model

< check if we need to calculate the stress according to Laresgoiti's stress model

◆ Cell_SPM() [3/4]

slide::Cell_SPM::Cell_SPM ( )

Default constructor.

< ID string

< Parameters are given for 16 Ah high-power, prismatic KokamNMC cell. (SLPB78205130H)

< Set initial state:

< SEI thickness. Start with a fresh cell, which has undergone some formation cycles so it has an initial SEI layer. never start with a value of 0, because some equations have a term 1/delta, which would give nan or inf so this will give errors in the code

< lost lithium. Start with 0 so we can keep track of how much li we lose while cycling the cell

< diffusion constant of the cathode at reference temperature

< diffusion constant of the anode at reference temperature

< thickness of the positive electrode

< thickness of the negative electrode

< volume fraction of active material in the cathode

< volume fraction of active material in the anode

< effective surface area of the cathode, the 'real' surface area is the product of the effective surface area (a) with the electrode volume (elec_surf * thick)

< effective surface area of the anode

< initial crack surface. Start with 1% of the real surface area

< R = Rdc * (thickp * ap * elec_surf + thickn * an * elec_surf) / 2; //!< specific resistance of the combined electrodes, see State::iniStates

< note: this is divided by geometric surface (elec_surf) instead of effective surf (a*thick*elec_surf)

< thickness of the plated lithium layer. You can start with 0 here

< 0.689332 lithium fraction in the cathode at 50% soc (3.68136 V) [-]

< 0.479283 lithium fraction in the anode at 50% soc (3.68136 V) [-]

< Since fp and fn are set at 50%.

< set the states, with a random value for the concentration

< Default values for not defined other param:

< assume the maximum crack surface is 5 times the initial anode surface

Here is the call graph for this function:

◆ Cell_SPM() [4/4]

slide::Cell_SPM::Cell_SPM ( Model_SPM M_ptr)
inline

getters

Member Function Documentation

◆ calcArrheniusCoeff()

double slide::Cell_SPM::calcArrheniusCoeff ( )
inlineprotected

Calculates Arrhenius coefficient.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcDiffConstant()

std::array< double, 2 > slide::Cell_SPM::calcDiffConstant ( )
protected

Calculate the diffusion constant at the battery temperature using an Arrhenius relation.

< Calculate the diffusion constant at the battery temperature using an Arrhenius relation

< diffusion constant of the positive particle [m s-1]

< diffusion constant of the negative particle [m s-1]

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcMolarFlux()

std::array< double, 3 > slide::Cell_SPM::calcMolarFlux ( )
protected

Calculate molar flux.

void setStates(State_SPM &&states); //!< set the cell's states to the states in the array degradation models

< current density on the electrode [A m-2]

< molar flux on the positive particle [mol m-2 s-1]

< molar flux on the negative particle [mol m-2 s-1]

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcOverPotential()

std::pair< double, double > slide::Cell_SPM::calcOverPotential ( double  cps,
double  cns,
double  i_app 
)
protected

Should not throw normally, except divide by zero?

< Calculate the rate constants at the cell's temperature using an Arrhenius relation

< Rate constant at the positive electrode at the cell's temperature [m s-1]

< Rate constant at the negative electrode at the cell's temperature [m s-1]

< Calculate the overpotential using the Bulter-Volmer equation if alpha is 0.5, the Bulter-Volmer relation can be inverted to eta = 2RT / (nF) asinh(x) and asinh(x) = ln(x + sqrt(1+x^2) -> to asinh(x) function.

< exchange current density of the positive electrode

< exchange current density of the negative electrode

< x for the cathode

< x for the anode

< cathode overpotential [V], < 0 on discharge

< anode overpotential [V], > 0 on discharge

Parameters
i_appShould not throw normally, except divide by zero?
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcSurfaceConcentration()

std::pair< double, double > slide::Cell_SPM::calcSurfaceConcentration ( double  jp,
double  jn,
double  Dpt,
double  Dnt 
)
protected

< Calculate the surface concentration at the positive particle cp_surf = M->Cp[0][:] * zp[:] + M->Dp*jp/Dpt

< Calculate the surface concentration at the negative particle cn_surf = M->Cn[0][:] * zn[:] + M->Dn*jn/Dnt

Parameters
DntShould not throw normally, except divide by zero?
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkModelparam()

void slide::Cell_SPM::checkModelparam ( )

check if the inputs to the MATLAB code are the same as the ones here in the C++ code

— slide-pack functions — //

< check if the inputs to the MATLAB code are the same as the ones here in the C++ code input: M->Input[0] has to be the same as nch (defined in State.hpp) M->Input[1] has to be the same as Rp (defined earlier in this constructor) M->Input[2] has to be the same as Rn (defined earlier in this constructor) M->input[3] has to give the location of the 0 eigenvalue

< allow a relative difference of e-10 due to numerical errors

< allow a relative difference of e-10 due to numerical errors

< allow a relative difference of e-10 due to numerical errors

< allow a relative difference of e-10 due to numerical errors

Here is the caller graph for this function:

◆ copy()

Cell_SPM * slide::Cell_SPM::copy ( )
inlineoverridevirtual

Obsolete functions (do not use):

Implements slide::StorageUnit.

◆ CS()

void slide::Cell_SPM::CS ( double  OCVnt,
double  etan,
double *  isei_multiplyer,
double *  dCS,
double *  dDn 
)
protected

calculate the effect of surface crack growth

< output parameters

< isei multiplier from all models to be considered

< increase in surface area from all models to be considered

< active surface area of the anode [m2] this active area is used to translate absolute values (such as currents) to relative values (such as current densities)

< Loop for each model we want to use

< a switch to calculate the effect according to model i

< no surface cracks

< Laresgoiti's stress and crack growth model (Laresgoiti, Kablitz, Ecker, Sauer, Journal of Power Sources 300, 2015) this model calculates crack growth due to temporal variations in the li-concentration

< check the calculated stress values are up to date

< if you see this error, you have to call Cell_SPM::updateLaresgoitiStress(), which calculates the stress and stores the values, before you call this function

< equations (22)+ (27) from the paper current density on particle = I /(elec_surf * thick * a) isei also acts on this scale since it is an extra boundary condition ( itot = (jn + isei) = (surface gradient)/nF ) crack growth -> increase isei_on_particle -> (jn + isei*(initial+crack_surface)/initial)*nF such that if the crack surface area is the same as the initial electrode surface area, we double isei

< increase SEI growth proportionally the crack surface

< Laresgoiti's crack growth model (Laresgoiti, Kablitz, Ecker, Sauer, Journal of Power Sources 300, 2015) but with stress model from Dai, Cai, White, Journal of Power sources 247, 2014 instead of Laresgoiti's stress from figure 5 this model calculates crack growth due to spatial (Dai) and temporal (Laresgoiti) variations in the li-concentration

< ensure the stress values are up to date

< if you see this error, you have to call Cell_SPM::updateDaiStress(), which calculates the stress and stores the values before you call this function

< equations (22)+ (27) from the paper but with Dai's stress

< increase SEI growth proportionally the crack surface

< model by Deshpande & Bernardi,Journal of the Electrochemical Society 164 (2), 2017 this model is adapted to calculate crack growth due to spatial variations in the li-concentration

< get concentrations

< Add the effects of this model

< equations (8) + (21) Note that eqn (8) refers to the change with respect to time while here we use the spatial variation This makes the model capture more of the spatial variation in stress Laresgoiti's model already accounted for temporal variation, so simply use that if you are interested in temporal rather than spatial variation

< increase SEI growth proportionally the crack surface

< model from Barai, Smith, Chen, Kim, Mukherjee, Journal of the Electrochemical Society 162 (9), 2015 equation (1a): CS = Amax(1 - exp(-m * Ah)) with m a fitting parameter and Ah the charge throughput up to now dCS/dAh = m Amax exp(-m Ah) = m Amax - m Amax + m Amax exp(-m Ah) = m Amax - m CS = m(Amax - CS) dCS/dt = dCS/dAh * dAh/dt = dCS/dAh * abs(I) = m(Amax - CS)*abs(I) where we use the absolute value of I because 'Ah' is the total charge throughput, i.e. int ( abs(I) dt )

< 'maximum crack surface area', a fitting parameters avoid negative crack growth if the crack surface becomes slightly larger than Amax this is possible due to discrete time steps: CS(t) is just smaller, but CS (t+1) = CS(t) + dCS*dt is just larger

< Add the effects of this model

< see above, with m = csparam.CS4

< increase SEI growth proportionally the crack surface

< model from Ekstrom and Lindbergh, Journal of the Electrochemical Society 162 (6), 2015 overpotential for the crack-side-reaction = overpotential for the SEI reaction

< overpotential [V], equation (6)

< get surface concentration

< get the surface lithium concentration //!< #TODO only cns is used.

< rate constant for the side reaction

< Calculate the rate constant, equation (11) with an Arrhenius relation for the temperature (which wasn't considered by Ekstrom)

< Add the effects of this model

< equation (9)

< increase SEI growth proportionally the crack surface

< unknown degradation model

< Decrease the negative diffusion constant if needed

< don't decrease the negative diffusion constant

< decrease it according to Barai, Smith, Chen, Kim, Mukherjee, Journal of the Electrochemical Society 162 (9), 2015

< equation (2) D(t) = D0 (1 - CS)^gamma but this can become negative is CS is larger than 1, we assume there should be a term /Amax in eqn (2): D(t) = D0 (1 - (CS/Amax))^gamma, which becomes 0 if CS = Amax so dD/dt = - gamma D0 (1-CS/Amax)^(gamma-1) 1/Amax dCS/dt

< 'maximum crack surface area', a fitting parameters avoid increasing diffusion coefficient if the crack surface becomes larger than Amax this is possible if the user chooses a different CS growth model, which does give larger crack surfaces (i.e. not CS4 which is Barai's crack growth model)

< cap the decrease rate at a maximum value of 2e-7 (2e-5% = kill the battery in about 1000h)

< unknown degradation model

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dState()

State_SPM::states_type slide::Cell_SPM::dState ( bool  print,
State_SPM d_state 
)

Utility.

◆ dState_all()

void slide::Cell_SPM::dState_all ( bool  print,
State_SPM d_state 
)
protected

individual functions are combined in one function to gain speed.

thermal model

◆ dState_degradation()

void slide::Cell_SPM::dState_degradation ( bool  print,
State_SPM d_state 
)
protected

calculate the effect of lithium plating

< Calculcate the lithium fractions at the surface of the particles

< current density, molar flux on the pos/neg particle

< check if the surface concentration is within the allowed range 0 < cp < Cmaxpos 0 < cn < Cmaxneg

< Do not delete if you cannot ensure zp/zn between 0-1

< lithium fraction (0 to 1)

< Calculate the overpotentials if needed

< calculate the anode potential (needed for various degradation models)

< entropic coefficient of the anode potential [V K-1]

< anode potential [V]

< anode potential at the cell's temperature [V]

< SEI growth

< current density of the SEI growth side reaction [A m-2]

< decrease in volume fraction due to SEI growth [s-1]

< additional diffusion in the anode due to isei

< Throws but not wrapped in try-catch since only appears here.

< Subtract Li from negative electrode (like an extra current density -> add it in the boundary conditions: dCn/dx = jn + isei/nF)

< crack growth leading to additional exposed surface area

< relative increase in isei due to additional SEI growth on the extra exposed surface area [-]

< increase in crack surface area [m2 s-1]

< change in negative diffusion constant [m s-1 s-1]

< additional diffusion in the anode due to extra SEI growth on the crack surface

< Throws but not wrapped in try-catch since only appears here.

< crack surface leads to extra SEI growth because the exposed surface area increases. (like an extra current density -> add it in the boundary conditions: dCn/dx = jn + isei/nF + isei_CS/nF)

< extra SEI side reaction current density due to the crack surface area [A m-2]

< loss of active material LAM

< change in geometric parameters describing the amount of active material

< Throws but not wrapped in try-catch since only appears here.

< lithium plating

< current density of the plating side reaction [A m-2]

< additional diffusion in the anode due to ipl

< Subtract Li from negative electrode (like an extra current density -> add it in the boundary conditions: dCn/dx = jn + ipl/nF)

< #TODO (npl * F) division is unnecessary it is already multiple in the function.

< output

< dzp += 0 //!< dzp should be added from diffusion function

< dzn jtot = jn + isei/nF + isei_CS/nF + ipl/nF

< ddelta SEI thickness

< dLLI lost lithium

< dthickp electrode thickness

< dthickn

< dep volume fraction of active material

< den

< dap effective surface are, a = 3 e/R

< dan

< dCS surface area of the cracks

< dDp diffusion constant

< dDn

< drdc_p cathode resistance

< drdc_n anode resistance

< drdc_cc current collector resistance

< ddelta_pl thickness of the plated lithium

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dState_diffusion()

void slide::Cell_SPM::dState_diffusion ( bool  print,
State_SPM d_state 
)
protected

just diffusion PDE

< current density, molar flux on the pos/neg particle

< Calculate the effect of the main li-reaction on the (transformed) concentration

< dz/dt = D * A * z + B * j

< loop for each row of the matrix-vector product A * z

< A is diagonal, so the array M->A has only the diagonal elements

< dz/dt = D * A * z + B * j

< dSOC state of charge

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dState_thermal()

void slide::Cell_SPM::dState_thermal ( bool  print,
double &  dQgen 
)
protected

calculate the heat generation

< Calculcate the lithium fractions at the surface of the particles

< current density, molar flux on the pos/neg particle

< check if the surface concentration is within the allowed range 0 < cp < Cmaxpos 0 < cn < Cmaxneg

< Do not delete if you cannot ensure zp/zn between 0-1

< lithium fraction (0 to 1)

< const double zn_surf = (cns / Cmaxneg);

< Calculate the overpotentials if needed

< #TODO why don't we use in the new one?

< only consider negative electrode, ignore the positive electrode

< only consider positive electrode, ignore the negative electrode

< in linear interpolation, throw an error if you are outside of the allowed range of the data

< entropic coefficient of the entire cell OCV [V K-1]

< temperature model Calculate the thermal sources/sinks/transfers per unit of volume of the battery The battery volume is given by the product of the cell thickness and the electrode surface

< reversible heat due to entropy changes [W]

< reaction heat due to the kinetics [W]

< Ohmic heat due to electrode resistance [W]

< const double Qc = -Qch * SAV * (st.T() - T_env); //!< cooling with the environment [W m-2]

< total heat generation and cooling in W

< dQcool = (Qc) * (L*elec_surf);

< dT = 1/(rho*Cp)*(Qrev+Qrea+Qohm+Qc); //!< dT cell temperature

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ETI()

void slide::Cell_SPM::ETI ( bool  print,
double  dti,
bool  blockDegradation 
)

step forward in time using forward Eurler time integration

Functions for fitting:

◆ getAnodeSurface()

double slide::Cell_SPM::getAnodeSurface ( )
inlinenoexcept

get the anode pure surface area (without cracks) product of the effective surface area (an) with the electrode volume

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getC()

void slide::Cell_SPM::getC ( double  cp[],
double  cn[] 
)
noexcept

get the concentrations at all nodes

< Calculate the diffusion constant at the battery temperature using an Arrhenius relation

< Calculate the molar flux on the surfaces

< current density, molar flux on the pos/neg particle

< Calculate concentration at the surface and inner nodes using the matrices from the spatial discretisation of the solid diffusion PDE cp = M->Cp[:][:] * zp[:] + M->Dp*jp/Dpt cn = M->Cn[:][:] * zn[:] + M->Dn*jn/Dnt

< Problem here!!!!!!! #TODO

< loop to calculate at each surface + inner node

Here is the caller graph for this function:

◆ getCSurf()

bool slide::Cell_SPM::getCSurf ( double &  cps,
double &  cns,
bool  print 
)

get the surface concentrations

< current density, molar flux on the pos/neg particle

< check if the surface concentration is within the allowed range 0 < cp < Cmaxpos && 0 < cn < Cmaxneg

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getDaiStress()

void slide::Cell_SPM::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

< Get the locations of the Chebyshev nodes

< location (x-value) of the positive Chebyshev nodes

< location (x-value) of the positive and negative Chebyshev nodes [-surface .. centre .. +surface]

< centre node

< negative nodes

< positive nodes

< positive and negative nodes, [+surface .. inner .. centre]

< concentrations at all nodes, [-surface .. inner .. centre .. inner .. +surface]

< cathode centre node

< anode centre node

< cathode negative points

< anode negative points

< cathode positive points

< anode positive points

< Calculate the matrix-vector product of the required functions as given in the paper by Dai et al. (concentration * radius^2) we need to remember the transformation of variables from x (-1<x<1) to r (-R<r<R) int( c * r^2 dr) = int(c * (x*R)^2 * d(R*x)) = int(c x^2 R^3 dx) so the matrix-vector product we need is F = Q * (concentration * x^2 * R^3)

< Note: since Fp (Fn) is multiplied by Rp^3 (Rn^3) then divided by them they are eliminated to remove numerical problems.

< arrays with the product for the positive and negative electrode

< loop for each row (one row = one node)

< calculate the matrix-vector product for row i as you would do it by hand: F(i) = sum(Q(i,j)*C(j)*x(j)^2*R^3, j=0..2*nch+2)

< loop through the columns to calculate the sum

< Q(i,j)*C(j)*x(j)^2

< int( cp*r^2, r=0..Rp ) // Note r^3 is eliminated!

< int( cn*r^2, r=0..Rn )

< Reset the stress values.

< loop for the positive nodes

< r(i) = R * x(i) radius of positive node i in the positive particle radius of positive node i in the negative particle

< integral from the centre to positive node i int(cp*zp^2, zp=0..rp(i)) = F[nch+1+i] - F[nch+1]

< integral from the centre to positive node i int(cn*zn^2, zn=0..rn(i))

< Implement the equations from Dai et al. Flip all arrays to get the opposite order (now it is [centre .. +surface] and we want [+surface .. centre] and store in the output arrays

< centre node -> special formula (31 & 33) in Dai, Cai, White

< other nodes -> equation 13 in Dai, Cai, White

< ap = int (c x^2, x=0..R), bp = int (c x^2 , x=0..r)

< calculate hydrostatic stress

< find the maximum (in absolute value) of the stresses

< node with the maximum hydrostatic stress in the positive/negative particle

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getLaresgoitiStress()

void slide::Cell_SPM::getLaresgoitiStress ( bool  print,
double *  sigma_n 
)

get the stresses at all nodes according to Laresgoiti's stress model

< Arrays with the stress from Laresgoiti, Kablitz, Ecker, Sauer, Journal of Power Sources 300, 2015 (figure 5)

< li-fraction in the graphite

< stress [MPa]

< Change this if xx is not fixed time step.

< Get the surface concentration

< get the surface lithium concentration [mol m-3]

< lithium fraction on negative surface [0, 1]

< check if the surface concentration is within the allowed range 0 < cp < Cmaxpos 0 < cn < Cmaxneg

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getOCV()

double slide::Cell_SPM::getOCV ( )
overridevirtual

< print if the (global) verbose-setting is above the threshold

< Get the surface concentrations

< Calculate the li-fraction (instead of the li-concentration)

< in linear interpolation, throw an error if you are out of the allowed range

< entropic coefficient of the total cell voltage [V/K]

< anode potential [V]

< cathode potential [V]

Implements slide::StorageUnit.

Here is the call graph for this function:

◆ getRdc()

double slide::Cell_SPM::getRdc ( )
noexcept

calculate the resistance from every component

< real surface area of the sei-layer

< real surface area of the positive electrode

< real surface area of the negative electrode

< calculate the resistance from every component

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getRtot()

double slide::Cell_SPM::getRtot ( )
inlineoverridevirtual

Implements slide::StorageUnit.

Here is the call graph for this function:

◆ getStateObj()

auto & slide::Cell_SPM::getStateObj ( )
inline
Here is the caller graph for this function:

◆ getStates()

void slide::Cell_SPM::getStates ( getStates_t  s)
inlineoverridevirtual

returns the states of the cell collectively.

Implements slide::StorageUnit.

Here is the caller graph for this function:

◆ getTemperatures()

void slide::Cell_SPM::getTemperatures ( double *  Tenv,
double *  Tref 
)
inlinenoexcept

< get the environmental and reference temperature

thermal model

◆ getTenv()

double slide::Cell_SPM::getTenv ( ) const
inlinenoexcept

get the environmental temperature [K]

◆ getThermalSurface()

double slide::Cell_SPM::getThermalSurface ( )
overridevirtual

return the 'A' for the thermal model of this SU (Q = hA*dT)

Implements slide::StorageUnit.

Here is the caller graph for this function:

◆ getThroughputs()

ThroughputData slide::Cell_SPM::getThroughputs ( )
inlineoverridevirtual

Reimplemented from slide::Cell.

Here is the call graph for this function:

◆ getVariations()

std::array< double, 4 > slide::Cell_SPM::getVariations ( ) const
inlineoverridevirtualnoexcept

Reimplemented from slide::Cell.

◆ getVoltage()

int slide::Cell_SPM::getVoltage ( bool  print,
double *  V,
double *  OCVp,
double *  OCVn,
double *  etap,
double *  etan,
double *  Rdrop,
double *  Temp 
)

get the cell's voltage

◆ getVoltage_ne()

int slide::Cell_SPM::getVoltage_ne ( bool  print,
double *  V,
double *  OCVp,
double *  OCVn,
double *  etap,
double *  etan,
double *  Rdrop,
double *  Temp 
)

get the cell's voltage noexcept

◆ I()

double slide::Cell_SPM::I ( ) const
inlineoverridevirtual

get the cell current [A] positive for discharging

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ LAM()

void slide::Cell_SPM::LAM ( bool  critical,
double  zp_surf,
double  etap,
double *  dthickp,
double *  dthickn,
double *  dap,
double *  dan,
double *  dep,
double *  den 
)
protected

calculate the effect of LAM

< output parameters

< loop for each model to use

< calculate the effect of this model

< no LAM

< Stress model from Dai, Cai, White, Journal of Power sources 247, 2014 LAM equation similar to CS equation from Laresgoiti (Laresgoiti, Kablitz, Ecker, Sauer, Journal of Power Sources 300, 2015)

< ensure the stress values are up to date

< if you see this error, you have to call Cell_SPM::updateDaiStress(), which calculates the stress and stores the values before calling this function

< with Dai's stress model (values stored in s_dai_p)

< #TODO sparam.s_dt was 2.0 in slide, why?

< ageing fit you need to divide by the time step to counter the effect of the time step larger dt has double effect: increase the stress difference, and time integrate by larger time period assuming stress changes are constant at ds per second, it would be ds (time_now - time_prev), or ds * dt and to cover a period of T (so we need T/dt steps of dt each), the total effect of stress is (ds*dt) * dt * T/dt = ds*dt*T so the effect of stress increases linearly with the size of the time setp so divide by total time (dt*nstep) to cancel this out, i.e. ds is per second (and not per total time period) assume the other effects are 0

< Model by Delacourt & Safari, Journal of the Electrochemical Society 159 (8), 2012

< Get the molar flux on each particle

< current density, molar flux on the pos/neg particle

< Use Arrhenius relations to update the fitting parameters for the cell temperature

< Add the effects of this model

< equation (5) from the paper

< assume the other effects are 0

< Model by Kindermann, Keil, Frank, Jossen, Journal of the Electrochemical Society 164 (12), 2017

< cathode potential

< get OCV of positive electrode, throw error if out of bounds this should be updated for the cell's temperature using the entropic coefficient of the cathode but I couldn't find any data on this, so I have ignored the effect

< std::cout << "Throw test: " << 40 << '
';

< equation (9) from the paper

< temperature dependent rate constant

< Arrhenius law

< current density of the NMC dissolution reaction

< equation (8) from the paper

< cap the effect at 5e-6 to avoid a very fast drop of capacity (which could cause an error) a value of 5e-6 gives dap = -3.5. The initial value is about 17000, so the cell is dead in 5,000 seconds so this cap is quite high

< Add the effects of this model

< assume the other effects are 0

< Model by Narayanrao, Joglekar, Inguva, Journal of the Electrochemical Society 160 (1), 2012

< Add the effects of this model

< equation (7) from the paper

< assume the other effects are 0

< unknown degradation model

Here is the call graph for this function:
Here is the caller graph for this function:

◆ LiPlating()

double slide::Cell_SPM::LiPlating ( double  OCVnt,
double  etan 
)
protected

state space model

< Arrhenius relation for temperature-dependent plating parameters

< Rate constant

< Yang, Leng, Zhang, Ge, Wang, Journal of Power Sources 360, 2017

Here is the call graph for this function:
Here is the caller graph for this function:

◆ overwriteCharacterisationStates()

void slide::Cell_SPM::overwriteCharacterisationStates ( double  Dpi,
double  Dni,
double  ri 
)
inline

< Overwrite both current and initial states.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ overwriteGeometricStates()

void slide::Cell_SPM::overwriteGeometricStates ( double  thickpi,
double  thickni,
double  epi,
double  eni,
double  api,
double  ani 
)
inline

void ETI_electr(bool print, double I, double dti, bool blockDegradation, bool pos); //!< step forward with only one electrode using forward Euler time integration

time integration void integratorStep(bool print, double dti, bool blockDegradation); //!< step forward in time using specified numerical integrator Base integrators: State_SPM::states_type Int_FWEuler(bool print, double dti, bool blockDegradation); //!< Forward euler integrator. State_SPM::states_type Int_RK4(bool print, double dti, bool blockDegradation); //!< Runge-Kutta 4 integrator. Calculate the time derivatives of the states at the actual cell current (state-space model)

< Overwrite both current and initial states.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ peekVoltage()

void slide::Cell_SPM::peekVoltage ( double  I)

Peeks voltage for state for given I.

State related functions void validState() { slide::validState(st, s_ini); }

◆ SEI()

void slide::Cell_SPM::SEI ( double  OCVnt,
double  etan,
double *  isei,
double *  den 
)
protected

calculate the effect of SEI growth

< variables

< SEI side reaction current density of all models combined

< Loop for each model to use

< Use a switch to calculate the magnitude of the SEI growth according to this degradation model

< no SEI growth

< kinetics and diffusion according to Pinson & Bazant, Journal of the Electrochemical society 160 (2), 2013

< Arrhenius relation for the rate parameter at the cell temperature

< Add the effect of this model eta_sei = OCVneg + etaneg - OCVsei + rsei*I isei = nFk exp(-nF/RT alpha eta_sei) on charge, I < 0 and etan < 0. so higher charging current -> more negative term in exponential -> larger isei

< Kinetic model according to Ning & Popov, Journal of the Electrochemical Society 151 (10), 2004 #TODO -> In slidepack case1 paper and case2 paper are swapped.

< Arrhenius relation for the rate parameter at the cell temperature

< Arrhenius relation for the diffusion constant at the cell temperature

< derivation of the formula: start equations (use the symbols from Yang, Leng, Zhang, Ge, Wang, Journal of Power Sources 360, 2017 but with opposite sign for j j = nFk c exp(..) j/nF = - D/delta (c - c0) j/nF = D/delta (- j/(nFk exp(..)) + c0) j * ( 1/(nFk exp(..)) + delta/DnF ) = c0 j = c0 / ( 1/(nFk exp(..)) + delta/DnF )

< Add the effects of this model

< model from Christensen & Newmann, Journal of the Electrochemical Society 152 (4), 2005

< Arrhenius relation for the rate parameter at the cell temperature

< Arrhenius relation for the diffusion constant at the cell temperature

< Use equation [22] from the paper

< the parameter a_L_K is set to 0.134461 but this constant can be lumped into the rate- and diffusion constants

< Add the effects of this model

< model from the optimisation in the paper

< Arrhenius relation for the rate parameter at the cell temperature

< Arrhenius relation for the diffusion constant at the cell temperature

< Use equation [22] from the paper

< the parameter a_L_K is set to 0.134461 but this constant can be lumped into the rate- and diffusion constants

< note: model used in optimisation had kpt/knt or vice versa, here a fixed value

< Add the effects of this model

< unknown degradation model

< Make the output for the SEI side reaction current density

< Calculate how much we decrease the volume fraction due to SEI growth

< don't decrease volume fraction

< decrease volume fraction according to Ashwin, Chung, Wang, Journal of Power Sources 328, 2016

< molar flux on the negative particle

< note: they use J = volumetric current [A/m3] -> they multiply with 'an' but we already have density [A/m2]

  • because they use the porosity while we use the volume fraction

< unknown degradation model

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setC()

void slide::Cell_SPM::setC ( double  cp0,
double  cn0 
)

void setCurrent(bool critical, bool check, double I); //!< set the cell's current to the specified value -> From old slide.

set the concentrations to the given (uniform) concentration

< #NOTHOTFUNCTION

< The second transformation is to the eigenspace: z = V * u with V the inverse of the matrix with the eigenvectors. As explained, we know that there is one eigenvector corresponding to a uniform concentration So we need to calculate only this one nonzero value for the (twice) transformed concentration The location of the uniform eigenvector (which has a 0 eigenvalue) is written in M->Input[3]

< (twice) transformed negative uniform concentration

< (twice) transformed positive uniform concentration

< Do the first transformation, to u(i) = radius(i) * concentration = x(i) * R * concentration(i)

< ------------------------------------------------------------------------— loop to calculate the row of V * u corresponding to the uniform concentration

< Make the arrays for the (twice) transformed concentration with all zero

< except the ind which will be set soon.

< Set the cell current to 0 to reflect the boundary condition for a fully uniform concentration

< #TODO we do not do this.

< the stress values stored in the class variables for stress are no longer valid because the state has changed

Here is the caller graph for this function:

◆ setCharacterisationParam()

void slide::Cell_SPM::setCharacterisationParam ( double  Dp,
double  Dn,
double  kpi,
double  kni,
double  Rdc 
)

sets the parameters related to the characterisation of the cell

void Cell_SPM::setRamping(double Istep, double tstep) { /*

  • Function to set the ramping parameters of the cell.
  • This allows to decrease them if you are trying weird things (e.g. very small diffusion constants) with the cell
  • IN
  • Istep maximum change in current per tstep [A], > 0
  • tstep time step by which you change the current, [s], > 0 *‍/ dIcell = Istep; dt_I = tstep; }

< store the rate constants in the cell

< calculate the specific electrode resistance from the total DC resistance

< overwrite the cycling related parameters

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setCurrent()

Status slide::Cell_SPM::setCurrent ( double  Inew,
bool  checkV = true,
bool  print = true 
)
overridevirtual

< #TODO in future make it into states.

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setGeometricParameters()

void slide::Cell_SPM::setGeometricParameters ( double  capnom,
double  elec_surf,
double  ep,
double  en,
double  thickp,
double  thickn 
)

void setRamping(double Istep, double tstep); //!< sets the ramping parameters

sets the geometric parameters related to the amount of active material

< If you change the volume fraction, you also have to change the effective surface area

< overwrite the original geometric parameters, use cell version

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setInitialConcentration()

void slide::Cell_SPM::setInitialConcentration ( double  cmaxp,
double  cmaxn,
double  lifracp,
double  lifracn 
)

sets the initial concentration

< Store the maximum concentrations

< set the concentration

< std::cout << "Throw test: " << 33 << '
';

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setOCVcurve()

void slide::Cell_SPM::setOCVcurve ( const std::string &  namepos,
const std::string &  nameneg 
)

sets the OCV curve of the cell to the given value

< verbose = verbosei;

< Cell_Fit::Cell_Fit(const slide::Model_SPM &MM, int verbosei) #TODO important for ageing to set no ageing. : Cell(settings::path::Kokam::namepos, settings::path::Kokam::nameneg, settings::path::Kokam::nameentropicC, settings::path::Kokam::nameentropicCell) { /*

  • Standard constructor to initialise the battery parameters.
  • Nothing should be changed in this constructor unless the user changes the radius of the particles.
  • The values used for fitting can be changed using the functions defined in this class
  • IN
  • M structure of the type Model, with the matrices of spatial discretisation for solid diffusion
  • verbosei integer indicating how verbose the simulation has to be.
  • The higher the number, the more output there is.
  • Recommended value is 1, only use higher values for debugging
  • From 4 (and above) there will be too much info printed to follow what is going on, but this might be useful for debugging to find where the error is and why it is happening
  • 0 almost no messages are printed, only in case of critical errors related to illegal parameters
  • 1 error messages are printed in case of critical errors which might crash the simulation
  • 2 all error messages are printed, whether the simulation can recover from the errors or not
  • 3 on top of the output from 2, a message is printed every time a function in the Cycler and BasicCycler is started and terminated
  • 4 on top of the output from 3, the high-level flow of the program in the Cycler is printed (e.g. 'we are going to discharge the cell')
  • 5 on top of the output from 4, the low-level flow of the program in the BasicCycler is printed (e.g. 'in time step 101, the voltage is 3.65V')
  • 6 on top of the output from 5, we also print details of the nonlinear search for the current needed to do a CV phase
  • 7 on top of the output from 6, a message is printed every time a function in the Cell is started and terminated
  • THROWS
  • 110 the matrices for the solid diffusion discretisation, produced by MATLAB, are wrong
  • 111 the OCV curves are too long *‍/ < //!< maximum concentrations Cmaxpos = 51385; Cmaxneg = 30555; C_elec = 1000; //!< standard concentration of 1 molar < //!< constants n = 1; < //!< Cell parameters nomCapacity = 2.7; //!< 2.7 Ah capacity Vmax = 4.2; //!< value for an NMC/C cell Vmin = 2.7; //!< value for an NMC/C cell Icell = 0; //!< initial cell current is 0A dIcell = 0.1; //!< ramp at 0.1A dt_I = 1e-3; //!< ramp at 1ms so changing the current goes fast //!< now changing the current takes 0.01 second per A < //!< thermal parameters T_ref = PhyConst::Kelvin + 25; T_env = PhyConst::Kelvin + 25; Qch = 90; //!< 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 rho = 1626; Cp = 750; < //!< geometry L = 1.6850e-4; Rp = 8.5e-6; //!< do NOT CHANGE this value, if you do change it, you have to recalculate the spatial discretisation with the supplied MATLAB scripts. See the word document '2 overview of the code', section 'MATLAB setup before running the C++ code' Rn = 1.25e-5; //!< do NOT CHANGE this value, if you do change it, you have to recalculate the spatial discretisation with the supplied MATLAB scripts. See the word document '2 overview of the code', section 'MATLAB setup before running the C++ code' SAV = 252.9915; elec_surf = 0.0982; //!< OCV fitting parameter < //!< Stress parameters sparam = param::def::StressParam_Fit; < //!< main Li reaction kp = 5e-11; //!< characterisation fitting parameter (at Tref) kp_T = 58000; kn = 1.7640e-11; //!< characterisation fitting parameter (at Tref) kn_T = 20000; //!< The diffusion coefficients at reference temperature are part of 'State'. //!< The values are set in the block of code below ('Initialise state variables') Dp_T = 29000; Dn_T = 35000; < //!< spatial discretisation of the solid diffusion PDE M = MM; checkModelparam(); //!< check if the inputs to the MATLAB code are the same as the ones here in the C++ code < //!< Initialise state variables slide::State_SPM::z_type up, un; double fp, fn, T, delta, LLI, thickp, thickn, ep, en, ap, an, CS, Dp, Dn, R, delta_pl; double Rdc = 0.0102; //!< DC resistance of the total cell in Ohm, characterisation fitting parameter fp = 0.689332; //!< lithium fraction in the cathode at 50% soc [-], OCV fitting parameter fn = 0.479283; //!< lithium fraction in the anode at 50% soc [-], OCV fitting parameter T = PhyConst::Kelvin + 25; //!< cell temperature delta = 1e-9; //!< SEI thickness. Start with a fresh cell, which has undergone some formation cycles so it has an initial SEI layer. //!< never start with a value of 0, because some equations have a term 1/delta, which would give nan or inf //!< so this will give errors in the code LLI = 0; //!< lost lithium. Start with 0 so we can keep track of how much li we lose while cycling the cell thickp = 70e-6; //!< thickness of the positive electrode, OCV fitting parameter thickn = 73.5e-6; //!< thickness of the negative electrode, OCV fitting parameter ep = 0.5; //!< volume fraction of active material in the cathode, OCV fitting parameter en = 0.5; //!< volume fraction of active material in the anode, OCV fitting parameter ap = 3 * ep / Rp; //!< effective surface area of the cathode, the 'real' surface area is the product of the effective surface area (a) with the electrode volume (elec_surf * thick) an = 3 * en / Rn; //!< effective surface area of the anode CS = 0.01 * an * elec_surf * thickn; //!< initial crack surface. Start with 1% of the real surface area Dp = 8e-14; //!< diffusion constant of the cathode at reference temperature, characterisation fitting parameter Dn = 7e-14; //!< diffusion constant of the anode at reference temperature, characterisation fitting parameter R = Rdc * ((thickp * ap * elec_surf + thickn * an * elec_surf) / 2); //!< specific resistance of the combined electrodes, see State::iniStates delta_pl = 0; //!< thickness of the plated lithium layer. You can start with 0 here s_ini.initialise(up, un, T, delta, LLI, thickp, thickn, ep, en, ap, an, CS, Dp, Dn, R, delta_pl); //!< set the states, with a random value for the concentration s = s_ini; //!< set the states, with a random value for the concentration < //!< Check if this was a valid state try { validState(); } catch (int e) { std::cout << "Error in State::initialise, one of the states has an illegal value, throwing an error\n"; < throw 12; } < setC(fp, fn); //!< set the lithium concentration < //!< SEI parameters nsei = 1; alphasei = 1; OCVsei = 0.4; rhosei = 100e3; rsei = 2037.4; Vmain = 13.0; Vsei = 64.39; c_elec0 = 4.541 / 1000; //!< fitting parameters of the models sei_p.sei1k = 0; sei_p.sei1k_T = 0; sei_p.sei2k = 0; sei_p.sei2k_T = 0; sei_p.sei2D = 0; sei_p.sei2D_T = 0; sei_p.sei3k = 0; sei_p.sei3k_T = 0; sei_p.sei3D = 0; sei_p.sei3D_T = 0; sei_p.sei_porosity = 0; < //!< surface cracking //!< fitting parameters of the models csparam.CS1alpha = 0; csparam.CS2alpha = 0; csparam.CS3alpha = 0; csparam.CS4alpha = 0; csparam.CS4Amax = 0; csparam.CS5k = 0; csparam.CS5k_T = 0; csparam.CS_diffusion = 0; < //!< LAM OCVnmc = 4.1; //!< fitting parameters lam_p.lam1p = 0; lam_p.lam1n = 0; lam_p.lam2ap = 0; lam_p.lam2bp = 0; lam_p.lam2an = 0; lam_p.lam2bn = 0; lam_p.lam2t = 0; lam_p.lam3k = 0; lam_p.lam3k_T = 0; lam_p.lam4p = 0; lam_p.lam4n = 0; < //!< li-plating parameters npl = 1; alphapl = 1; OCVpl = 0; rhopl = 10000e3; //!< fitting parameters pl_p.pl1k = 0; pl_p.pl1k_T = 0; < //!< degradation identifiers: no degradation deg.SEI_id.add_model(0); //!< no SEI growth, there is 1 SEI model (namely '0') deg.SEI_porosity = 0; //!< don't decrease the volume fraction < deg.CS_id.add_model(0); //!< no surface cracks //!< there is 1 model (that there are no cracks) deg.CS_diffusion = 0; //!< don't decrease the diffusion coefficient < deg.LAM_id.add_model(0); //!< no LAM //!< there is 1 LAM model deg.pl_id = 0; //!< no lithium plating //!< Check if we will have to calculate the stress sparam.s_dai = false; //!< according to Dai's stress model sparam.s_lares = false; //!< according to Laresgoiti's stress model }

< Store the OCV curves

< the OCV curve of the anode, the first column gives the lithium fractions (increasing), the 2nd column gives the OCV vs li/li+

< std::cout << "Throw test: " << 32 << '
';

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setSOC()

Status slide::Cell_SPM::setSOC ( double  SOCnew,
bool  checkV = true,
bool  print = true 
)
overridevirtual

< get the voltage Does not throw anymore!

< Restore states here.

Parameters
printAlso not used except test functions.

Implements slide::Cell.

Here is the call graph for this function:

◆ setStateObj()

auto slide::Cell_SPM::setStateObj ( State_SPM st_new)
inline

◆ setStates()

Status slide::Cell_SPM::setStates ( setStates_t  s,
bool  checkStates,
bool  print 
)
overridevirtual

opposite of getStates, check the states are valid?

< Back-up values.

< Copy states.

< Remove first Nstates elements from span.

< Restore states here.

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setT()

void slide::Cell_SPM::setT ( double  T)
overridevirtual

set the cell's temperature

< #TODO if we need to check if we are in limits. if T is in limits.

< the stress values stored in the class variables for stress are no longer valid because the state has changed

Implements slide::StorageUnit.

Here is the caller graph for this function:

◆ setTenv()

void slide::Cell_SPM::setTenv ( double  Tenv)

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

set the environmental temperature

void Cell_SPM::setVlimits(double VMAX, double VMIN) { /*

  • sets the voltage limits of this cell to the given values.
  • IN
  • VMAX maximum voltage of this cell, [V]
  • VMIN minimum voltage of this cell, [V]
  • THROWS
  • 103 illegal value of the voltage limits
  • Both values have to be between the maximum and minimum of the OCV curve of the cell
  • We are not checking the full OCV curve because that would take too long.
  • Instead, we check that the values are positive and that VMAX is below the maximum of the cathode OCV. *‍/ bool vmax = VMAX < 0 || VMAX > OCV_curves.OCV_pos.y[0]; if (vmax) std::cerr << "ERROR in Cell_SPM::setVlimits. The value of the maximum voltage is " << VMAX << "V but it has to be positive and lower than the maximum value of the OCV curve of the cathode, which is " << OCV_curves.OCV_pos.y.back() << ".\n"; bool vmin = VMIN < 0; if (vmin) std::cerr << "ERROR in Cell_SPM::setVlimits. The value of the minimum voltage is " << VMIN << "V but it has to be positive.\n"; if (vmax || vmin) throw 103; Vmax = VMAX; Vmin = VMIN; }

< check if the environmental temperature is in the allowed limits

< the temperature limits are defined in State.hpp

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SOC()

double slide::Cell_SPM::SOC ( )
inlineoverridevirtual

Implements slide::Cell.

Here is the caller graph for this function:

◆ T()

double slide::Cell_SPM::T ( )
inlineoverridevirtualnoexcept

returns the uniform battery temperature in [K]

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ thermal_getTotalHeat()

double slide::Cell_SPM::thermal_getTotalHeat ( )

function for unit testing

double getR() noexcept //!< get the total cell DC resistance { /*

  • Return the total cell DC resistance [Ohm]
  • The total cell resistance is the sum of the resistance of the electrodes and the SEI layer
  • the resistance of the electrodes increases due to loss of active material (LAM)
  • the resistance of the SEI layer increases as the layer becomes thicker
  • it is assumed the plated lithium does not add resistance *‍/ return (rsei * st.delta() + st.getR(elec_surf)); }
Here is the caller graph for this function:

◆ thermalModel()

double slide::Cell_SPM::thermalModel ( int  Nneighbours,
double  Tneighbours[],
double  Kneighbours[],
double  Aneighb[],
double  tim 
)
overridevirtual

Calculate the thermal model for this cell and update its cell temperature. The heat exchange in [W] with element i is given by Qc = Kneighbours[i]*A*(Tneighbours[i] - getT()); We assume all temperatures were constant for the past period, such that the thermal energy in [J] is given by Ec = Qc * Therm_time This is added up with the internal heath generated, and the cell's temperature is returned

IN Nneigtbours the number of neighbouring cells / cooling systems etc. Tneighbours array with the temperature of the neighbouring elements [K] Kneighbours array with the heat transfer constants of the neighbouring elements, k or h Aneighb array with the surface area of the neigbouring cell the heat transfer happens over the smaller one of Aneighb[i] and the area of this cell tim the time since the last thermal model calculation [for verification]

throws 8 invalid time keeping 9 invalid module temperature

< #TODO thermal model implementation should be outside.

< indicate we have ran the thermal model

Reimplemented from slide::Cell.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ thermalModel_cell()

double slide::Cell_SPM::thermalModel_cell ( )
protected

< total heat generation since last time the temperature was updated

< cooling with the environment

< cooling with the environment [W m-3]

< Calculate the new temperature rho * cp * dT/dt = Qtot / V where Qtot is total power in W V is the cell's volume L * elec_surf so integrated over time this is rho * cp * (Tnew - Told) = Etot / V

< Check the new temperature is valid, and if so, set it

< Reset the cumulative thermal variables

Here is the call graph for this function:
Here is the caller graph for this function:

◆ thermalModel_coupled()

double slide::Cell_SPM::thermalModel_coupled ( int  Nneighb,
double  Tneighb[],
double  Kneighb[],
double  Aneighb[],
double  tim 
)
protected

cell to cell variations // #TODO why do we store variations?

total heat generation [J] since start of cell's life

< check the time since the last checkup is not too large. if the parent has not called the thermal model for a while, the equation becomes unstable cause E = time * kA dT, so even a small dT will cause a huge E, and therefore a very large temperature swint

< #TODO magic number.

< Check the new temperature is valid, and if so, set it

< Reset the cumulative thermal variables

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timeStep_CC()

void slide::Cell_SPM::timeStep_CC ( double  dt,
int  nstep = 1 
)
overridevirtual

setStates(std::move(states)); //!< store new states, checks if they are illegal (throws an error in that case)

void Cell_SPM::ETI(bool print, double dti, bool blockDegradation) { /*

  • Performs forward Euler time integration over one time step of dti seconds
  • s(t+1) = s(t) + ds/dt * dti
  • IN
  • print boolean indicating if we want to print error messages or not
  • if true, error messages are printed
  • if false no error messages are printed (but the error will still be thrown)
  • we need this input from higher level functions because at this point we cannot know if this will be a critical error or not
  • dti time step over which time integradation should be done [s]
  • it should be small enough to ensure numerical stability and accuracy
  • 1-5 seconds in usually ok (depending on the magnitude of the current, the temperature, etc.)
  • blockDegradation if true, degradation is not accounted for in this time step *‍/ //!< Calculate the time derivatives auto states = st; //!< calculate time derivatives, electr = 0 to account for both electrodes (i.e. cycle the full cell) const slide::states_type dstates = dState(print, blockDegradation, 0); //!< arrays with the state and dstate/dt //!< forward Euler time integration: s(t+1) = s(t) + ds/dt * dt for (int i = 0; i < settings::ns; i++) //!< loop for all states states[i] += dti * dstates[i]; } void Cell_SPM::ETI_electr(bool print, double I, double dti, bool blockDegradation, bool pos) { /*
  • Performs forward Euler time integration over one time step of dti seconds
  • Considers only one electrode, i.e. you can do half-cell cycling with only one electrode
  • This allows to calculate the half-cell OCV curves (versus a reference electrode of metallic lithium)
  • USE THIS FUNCTION WITH CARE:
  • It doesn't check the input current
  • It might get the cell to an illegal situation
  • You can't undo the effects of this function, unless you had stored the states before calling this function
  • IN
  • print boolean indicating if we want to print error messages or not
  • if true, error messages are printed
  • if false no error messages are printed (but the error will still be thrown)
  • we need this input from higher level functions because at this point we cannot know if this will be a critical error or not
  • I current applied during this time step [A]
  • > 0 for discharge
  • < 0 for charge
  • dti time step [s]
  • blockDegradation if true, degradation is not accounted for in this time step. Must be true
  • pos if true, the positive electrode is considered (half-cell cycling with the positive electrode)
  • if false, the negative electrode is considered (half-cell cycling with the negative electrode)
  • THROWS
  • 109 illegal input parameters *‍/ if (!blockDegradation) { std::cerr << "ERROR in Cell_SPM::ETI_electr, you are cycling only one electrode but want to account for degradation. This is not allowed.\n"; //!< half-cell cycling is only allowed if blockDegradation is true (i.e. you ignore degradation) //!< this is because some of the degradation mechanisms could give NaN or Inf due to a divide by 0 //!< So you can only call this function with 'true' for blockDegradation throw 109; } //!< Set the specified current Icell = I; //!< don't call setCurrent because that function ramps the current on both electrodes //!< so here 'cheat it' and directly set the current //!< this means you avoid the checks done in setCurrent, so you don't know if the current is feasible or not //!< Calculate the time derivatives auto states = st; //!< calculate time derivatives of the positive or negative electrode const slide::states_type dstates = pos ? dState(print, blockDegradation, 1) : dState(print, blockDegradation, 2); //!< arrays with the state and dstate/dt //!< forward Euler time integration: s(t+1) = s(t) + ds/dt * dt for (int i = 0; i < settings::ns; i++) //!< loop for all states states[i] += dti * dstates[i]; setStates(std::move(states)); //!< store new states } void Cell_SPM::integratorStep(bool print, double dti, bool blockDegradation) { /*
  • Performs integration with specified solver over one time step of dti seconds
  • IN
  • print boolean indicating if we want to print error messages or not
  • if true, error messages are printed
  • if false no error messages are printed (but the error will still be thrown)
  • we need this input from higher level functions because at this point we cannot know if this will be a critical error or not
  • dti time step over which time integradation should be done [s]
  • it should be small enough to ensure numerical stability and accuracy
  • 1-5 seconds in usually ok (depending on the magnitude of the current, the temperature, etc.)
  • blockDegradation if true, degradation is not accounted for in this time step *‍/ State_SPM new_states{Int_FWEuler(print, dti, blockDegradation)}; setStates(std::move(new_states)); //!< store new states, checks if they are illegal (throws an error in that case) } Base integrators: Be careful since they change the state values! slide::states_type Cell_SPM::Int_FWEuler(bool print, double dti, bool blockDegradation) { //!< Get current states: auto states = st; //!< calculate time derivatives, electr = 0 to account for both electrodes (i.e. cycle the full cell) const auto dstates = dState(print, blockDegradation, 0); //!< arrays with the state and dstate/dt //!< forward Euler time integration: s(t+1) = s(t) + ds/dt * dt for (int i = 0; i < settings::ns; i++) //!< loop for all states states[i] += dti * dstates[i]; return states; } slide::states_type Cell_SPM::Int_RK4(bool print, double dti, bool blockDegradation) { const auto Iprev = I(); //!< Runge kutta 4 auto y1 = st; const auto k1 = dState(settings::printBool::printCrit, blockDegradation, 0); const auto y2 = arrSum(y1, k1, 1.0, 0.5 * dti); setStates(State_SPM{y2}, Iprev); const auto k2 = dState(settings::printBool::printCrit, blockDegradation, 0); const auto y3 = arrSum(y1, k2, 1.0, 0.5 * dti); setStates(State_SPM{y3}, Iprev); const auto k3 = dState(settings::printBool::printCrit, blockDegradation, 0); const auto y4 = arrSum(y1, k3, 1.0, dti); setStates(State_SPM{y4}, Iprev); //!< #TODO: eliminate temporary objects State_SPM{} const auto k4 = dState(settings::printBool::printCrit, blockDegradation, 0); for (size_t i = 0; i < y1.size(); i++) y1[i] += (1.0 / 6.0) * dti * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]); return y1; }

< check the time step is positive

< Update the stress values stored in the attributes with the stress of the previous time step

< Dai's stress in the positive particle in the previous time step

< Dai's stress in the negative particle in the previous time step

< Laresgoiti's stress in the negative particle in the previous time step

< ********************************************* Resolve the diffusion model for every dt time step ****************************************************************************************

< Calculate the time derivatives

< forward Euler time integration: s(t+1) = s(t) + ds/dt * dt

< increase the cumulative variables of this cell

< Calculate the internal heat generation of the cell

< If this cell has a parent module, this parent will call the thermal model with the correct parameters which will include heat exchange with the cell's neighbours and cooling from the cooling system of the module.

< if there is no parent, this cell is a stand-alone cell. We assume convective cooling with an environment If there is no parent, assume we update T every nstep*dt. So update the temperature now

< else it is the responsibility of the parent to call the thermal model function with the correct settings

< so cooling Qc = Qch * SAV * dT / (rho*cp) = Qch * A * dT / (rho*cp)

< calculate the surface of this cell

< #TODO in slide-pack it does not check the temperature.

< Calculate the stress values stored in the attributes for the stress in this time step

< only a few degradation models actually need the stress according to Dai, so only calculate it if needed

< only a few degradation models need the stress according to Laresgoiti

< Calculate the time derivatives

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateDaiStress()

void slide::Cell_SPM::updateDaiStress ( )
noexcept

updated the stored stress values for Dai's stress model

< Make variables to store the stress

< Get the stress // #TODO these variables are not used.

< indicate that the values in the class variables are updated

Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateLaresgoitiStress()

void slide::Cell_SPM::updateLaresgoitiStress ( bool  print)

update the stored stress values for Laresgoiti's stress model

setters void setVlimits(double VMAX, double VMIN); //!< set the voltage limits of the cell

< Update the stored value

< indicate that the values in the class variables are updated

Here is the call graph for this function:
Here is the caller graph for this function:

◆ V()

double slide::Cell_SPM::V ( )
overridevirtual

print is an optional argument

< If the stored value is the most up to date one, then simply return this value

< print if the (global) verbose-setting is above the threshold

< Get the surface concentrations

< check if the surface concentration is within the allowed range 0 < cp < Cmaxpos 0 < cn < Cmaxneg don't allow 0 or Cmax because in that case, i0 will be 0, and the overpotentials will have 1/0 = inf or nan

< print error message unless you want to suppress the output

< Surface concentration is out of bounds.

< Calculate the li-fraction (instead of the li-concentration)

< Calculate the electrode potentials

< in linear interpolation, throw an error if you are out of the allowed range

< entropic coefficient of the total cell voltage [V/K]

< anode potential [V]

< cathode potential [V]

< current density on the electrodes [I m-2]

< Calculate the cell voltage the cell OCV at the reference temperature is OCV_p - OCV_n this OCV is adapted to the actual cell temperature using the entropic coefficient dOCV * (T - Tref) then the overpotentials and the resistive voltage drop are added

< we now have the most up to date value stored

Implements slide::StorageUnit.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validStates()

bool slide::Cell_SPM::validStates ( bool  print = true)
overridevirtual

checks if a state array is valid

< print if the (global) verbose-setting is above the threshold

< Check if all fields are present & extract their values

< check whether SoC in the allowed range

< there is no range on the current

Implements slide::StorageUnit.

Here is the call graph for this function:

◆ viewStates()

std::span< double > slide::Cell_SPM::viewStates ( )
inlineoverridevirtual

Only for cells to see individual states.

Reimplemented from slide::StorageUnit.

Member Data Documentation

◆ alphapl

double slide::Cell_SPM::alphapl { 1 }
protected

charge transfer constant for the plating reaction [-]

◆ alphasei

double slide::Cell_SPM::alphasei { 1 }
protected

charge transfer coefficient of the SEI reaction [-]

◆ C_elec

double slide::Cell_SPM::C_elec { 1000 }
protected

Li- concentration in electrolyte [mol m-3] standard concentration of 1 molar.

◆ c_elec0

double slide::Cell_SPM::c_elec0 { 4.541e-3 }
protected

bulk concentration of the electrolyte molecule participating in the SEI growth (e.g. EC) [mol m-3]

◆ Cmaxneg

double slide::Cell_SPM::Cmaxneg { 30555 }
protected

maximum lithium concentration in the anode [mol m-3] value for C

◆ Cmaxpos

double slide::Cell_SPM::Cmaxpos { 51385 }
protected

maximum lithium concentration in the cathode [mol m-3] value for NMC

◆ Cp

double slide::Cell_SPM::Cp { 750 }
protected

thermal capacity of the battery #TODO = units missing.

Geometric parameters

◆ csparam

param::CSparam slide::Cell_SPM::csparam {}
protected

structure with the fitting parameters of the different crack growth models

LAM parameters & constants

◆ deg_id

DEG_ID slide::Cell_SPM::deg_id

structure with the identification of which degradation model(s) to use #TODO may be protected.

◆ Dn_T

double slide::Cell_SPM::Dn_T { 35000.0 / 5.0 }
protected

activation energy for the Arrhenius relation of Dn

Thermal model parameters

◆ Dp_T

double slide::Cell_SPM::Dp_T { 29000 }
protected

activation energy for the Arrhenius relation of Dp

◆ geo

param::Geometry_SPM slide::Cell_SPM::geo {}
protected

other geometric parameters are part of State because they can change over the battery's lifetime

◆ kn

double slide::Cell_SPM::kn { 1.7640e-11 }
protected

rate constant of main reaction at negative electrode at reference temperature

◆ kn_T

double slide::Cell_SPM::kn_T { 20000 }
protected

The diffusion constants at reference temperature are part of State because they can change over the battery's lifetime.

activation energy for the Arrhenius relation of kn

◆ kp

double slide::Cell_SPM::kp { 5e-11 }
protected

rate constant of main reaction at positive electrode at reference temperature

◆ kp_T

double slide::Cell_SPM::kp_T { 58000 }
protected

activation energy for the Arrhenius relation of kp

◆ lam_p

param::LAMparam slide::Cell_SPM::lam_p { param::def::LAMparam_Kokam }
protected

structure with the fitting parameters of the different LAM models

Li-plating parameters & constants //!< #TODO if we can make these static and speed gain.

◆ M

Model_SPM* slide::Cell_SPM::M { Model_SPM::makeModel() }
protected

OCV curves.

◆ n

double slide::Cell_SPM::n { 1 }
protected

number of electrons involved in the main reaction [-] #TODO if really constant?

parameters of the main li-insertion reaction

◆ npl

double slide::Cell_SPM::npl { 1 }
protected

number of electrons involved in the plating reaction [-]

◆ nsei

double slide::Cell_SPM::nsei { 1 }
protected

number of electrons involved in the SEI reaction [-]

◆ OCV_curves

OCVcurves slide::Cell_SPM::OCV_curves
protected

◆ OCVnmc

double slide::Cell_SPM::OCVnmc { 4.1 }
protected

equilibrium potential of the NMC dissolution side reaction [V]

◆ OCVpl

double slide::Cell_SPM::OCVpl { 0 }
protected

OCV of the plating reaction [V].

◆ OCVsei

double slide::Cell_SPM::OCVsei { 0.4 }
protected

equilibrium potential of the SEI side reaction [V]

◆ pl_p

param::PLparam slide::Cell_SPM::pl_p
protected

structure with the fitting parameters of the different plating models

Matrices for spatial discretisation of the solid diffusion model

◆ Qch

double slide::Cell_SPM::Qch { 45 }
protected

convective heat transfer coefficient per volume [W K-1 m-3]

◆ rho

double slide::Cell_SPM::rho { 1626 }
protected

density of the battery

◆ rhopl

double slide::Cell_SPM::rhopl { 10e6 }
protected

density of the plated lithium layer

◆ rhosei

double slide::Cell_SPM::rhosei { 100e3 }
protected

partial molar volume of the SEI layer [m3 mol-1]

◆ rsei

double slide::Cell_SPM::rsei { 2037.4 * 50 }
protected

specific resistance times real surface area of the SEI film [Ohm m] ? #TODO if unit is correct. aging fit.

◆ s_ini

State_SPM slide::Cell_SPM::s_ini {}
protected

the battery current/initial state, grouping all parameter which change over the battery's lifetime (see State_SPM.hpp)

Battery model constants

◆ sei_p

param::SEIparam slide::Cell_SPM::sei_p { param::def::SEIparam_Kokam }
protected

structure with the fitting parameters of the different SEI growth models

surface crack parameters & constants

◆ sparam

param::StressParam slide::Cell_SPM::sparam { param::def::StressParam_Kokam }
protected

Stress parameters.

Constants and parameters for the SEI growth model //!< #TODO if we can make these static and speed gain.

◆ st

State_SPM slide::Cell_SPM::st {}
protected

< protected such that child classes can access the class variables

◆ T_env

double slide::Cell_SPM::T_env { settings::T_ENV }
protected

environment temperature [K]

◆ T_ref

double slide::Cell_SPM::T_ref { 25.0_degC }
protected

reference temperature [K]

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 40 is representative for a cell on a shelf without forced cooling

◆ Therm_Qgen

double slide::Cell_SPM::Therm_Qgen {}
protected

total heat generation since the last update [J]

◆ Therm_Qgentot

double slide::Cell_SPM::Therm_Qgentot {}
protected

variable for unit testing, total heat generation since the beginning of this cell's life [J]

◆ Therm_time

double slide::Cell_SPM::Therm_time {}
protected

time since the last update of the thermal model

◆ var_cap

double slide::Cell_SPM::var_cap { 1 }
protected

relative factor increasing the capacity of the cell

◆ var_degLAM

double slide::Cell_SPM::var_degLAM { 1 }
protected

relative factor to speed up or slow down the rate of LAM

◆ var_degSEI

double slide::Cell_SPM::var_degSEI { 1 }
protected

relative factor to speed up or slow down the rate of SEI growth

◆ var_R

double slide::Cell_SPM::var_R { 1 }
protected

relative factor increasing the DC resistance

◆ Vcell_valid

bool slide::Cell_SPM::Vcell_valid { false }
protected

Functions.

◆ Vmain

double slide::Cell_SPM::Vmain { 13 }
protected

partial molar volume of the main reaction, see Ashwin et al, 2016

◆ Vsei

double slide::Cell_SPM::Vsei { 64.39 }
protected

partial molar volume of the SEI side reaction, see Ashwin et al., 2016


The documentation for this class was generated from the following files: