Source code for cideMOD.models.particle_models.SGM_basic.outputs

#
# Copyright (c) 2023 CIDETEC Energy Storage.
#
# This file is part of cideMOD.
#
# cideMOD is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import dolfinx as dfx

from cideMOD.cell.warehouse import Warehouse
from cideMOD.cell.variables import ProblemVariables
from cideMOD.cell.components import BatteryCell
from cideMOD.cell.dimensional_analysis import DimensionalAnalysis
from cideMOD.mesh.base_mesher import BaseMesher
from cideMOD.models.PXD.base_model import BasePXDModelOutputs


[docs] class ParticleModelSGMOutputs(BasePXDModelOutputs): """ A class that contains the mandatory methods to be overrided related to the outputs of :class:`cideMOD.models.ParticlelModel`. """
[docs] def get_outputs_info(self, warehouse: Warehouse) -> None: """ This method modifies a dictionary containing the information of both the global and internal variables that can be outputed by the particle model. Parameters ---------- warehouse: Warehouse Object that postprocess, store and write the outputs. """ # Global variables warehouse.add_global_variable_info('cathode_SOC', fnc=self.get_soc_c, default=True, header="Cathode AM {i} SOC [-]", dtype='list_of_scalar') warehouse.add_global_variable_info('total_lithium', fnc=self.calculate_total_lithium, header="Total_lithium [mol]") # Internal variables for component in warehouse.problem.cell_parser._components_.values(): if not component.name == 'electrode': continue label = component.label tag = component.tag warehouse.add_internal_variable_info(f'c_s_{label}_surf', subdomains=tag, dtype='list_of_scalar') warehouse.add_internal_variable_info(f'c_s_{label}_avg', subdomains=tag, dtype='list_of_scalar') warehouse.add_internal_variable_info(f'x_{label}_surf', subdomains=tag, dtype='list_of_scalar') warehouse.add_internal_variable_info(f'x_{label}_avg', subdomains=tag, dtype='list_of_scalar', default=True)
[docs] def prepare_outputs(self, warehouse: Warehouse, var: ProblemVariables, cell: BatteryCell, mesher: BaseMesher, DA: DimensionalAnalysis, problem) -> None: """ This method computes the expression of the requested internal variables to be ready for being evaluated and stored. Parameters ---------- warehouse: Warehouse Object that postprocess, store and write the outputs. var: ProblemVariables Object containing the problem variables. cell: BatteryCell Object where cell parameters are preprocessed and stored. mesher: BaseMesher Object that store the mesh information. DA: DimensionalAnalysis Object where the dimensional analysis is performed. problem: Problem Object that handles the battery cell simulation. """ # Prepare global variables self.problem = problem self.mesher = mesher self.cell = cell self.var = var self._SoC_forms = [dfx.fem.form(x * mesher.dx_c) for x in var.x_c_avg] # Prepare internal variables for component in cell._components_.values(): if not component.name == 'electrode': continue label = component.label n_mat = component.n_mat warehouse.setup_internal_variable( f'c_s_{label}_surf', var(f'c_s_{label}_surf'), length=n_mat) warehouse.setup_internal_variable( f'c_s_{label}_avg', var(f'c_s_{label}_avg'), length=n_mat) warehouse.setup_internal_variable( f'x_{label}_surf', var(f'x_{label}_surf'), length=n_mat) warehouse.setup_internal_variable( f'x_{label}_avg', var(f'x_{label}_avg'), length=n_mat)
[docs] def get_soc_c(self): dx = self.mesher.dx_c return [self.problem.get_avg(form, dx) for form in self._SoC_forms]
def _get_electrode_lithium(self, electrode, dx): c_s_avg = getattr(self.var, f'c_s_{electrode.label}_avg') li_total = 0 for k, material in enumerate(electrode.active_materials): li_total += c_s_avg[k] * material.eps_s return self.problem.get_avg(li_total, dx)
[docs] def calculate_total_lithium(self): # TODO: Make this more efficient compiling the form within self.prepare_outputs d = self.mesher.get_measures() internal_li = self.cell.anode.L * self._get_electrode_lithium(self.cell.anode, d.x_a) internal_li += self.cell.cathode.L * self._get_electrode_lithium(self.cell.cathode, d.x_c) disolved_li = self.problem.get_avg( self.cell.anode.eps_e * self.cell.anode.L * self.var.c_e, d.x_a) disolved_li += self.problem.get_avg( self.cell.separator.eps_e * self.cell.separator.L * self.var.c_e * d.x_s) disolved_li += self.problem.get_avg( self.cell.cathode.eps_e * self.cell.cathode.L * self.var.c_e * d.x_c) total_li = (internal_li + disolved_li) * self.cell.area return total_li