Source code for festim.species

from festim.subdomain.volume_subdomain import (
    VolumeSubdomain as _VolumeSubdomain,
)
from festim.helpers import as_fenics_constant

from typing import List, Union
import ufl
from dolfinx import fem


[docs] class Species: """ Hydrogen species class for H transport simulation. Args: name (str, optional): a name given to the species. Defaults to None. mobile (bool, optional): whether the species is mobile or not. Defaults to True. subdomain (F.VolumeSubdomain, optional): the volume subdomain where the species is. Defaults to None. Attributes: name (str): a name given to the species. mobile (bool): whether the species is mobile or not. solution (dolfinx.fem.Function): the solution for the current timestep prev_solution (dolfinx.fem.Function): the solution for the previous timestep test_function (ufl.Argument): the testfunction associated with this species sub_function_space (dolfinx.fem.function.FunctionSpaceBase): the subspace of the function space collapsed_function_space (dolfinx.fem.function.FunctionSpaceBase): the collapsed function space for a species in the function space. In case single species case, this is None. post_processing_solution (dolfinx.fem.Function): the solution for post processing concentration (dolfinx.fem.Function): the concentration of the species subdomains (F.VolumeSubdomain): the volume subdomains where the species is subdomain_to_solution (dict): a dictionary mapping subdomains to solutions subdomain_to_prev_solution (dict): a dictionary mapping subdomains to previous solutions subdomain_to_test_function (dict): a dictionary mapping subdomains to test functions subdomain_to_post_processing_solution (dict): a dictionary mapping subdomains to post processing solutions subdomain_to_collapsed_function_space (dict): a dictionary mapping subdomains to collapsed function spaces subdomain_to_function_space (dict): a dictionary mapping subdomains to function spaces Examples: :: testsetup:: Species from festim import Species :: testcode:: Species Species(name="H") Species(name="Trap", mobile=False) """ subdomains: list[_VolumeSubdomain] | _VolumeSubdomain subdomain_to_solution: dict subdomain_to_prev_solution: dict subdomain_to_test_function: dict subdomain_to_post_processing_solution: dict subdomain_to_collapsed_function_space: dict subdomain_to_function_space: dict def __init__(self, name: str = None, mobile=True, subdomains=None) -> None: self.name = name self.mobile = mobile self.solution = None self.prev_solution = None self.test_function = None self.sub_function_space = None self.post_processing_solution = None self.collapsed_function_space = None self.sub_function = None self.subdomains = subdomains self.subdomain_to_solution = {} self.subdomain_to_prev_solution = {} self.subdomain_to_test_function = {} self.subdomain_to_post_processing_solution = {} self.subdomain_to_collapsed_function_space = {} self.subdomain_to_function_space = {} def __repr__(self) -> str: return f"Species({self.name})" def __str__(self) -> str: return f"{self.name}" @property def concentration(self): return self.solution @property def legacy(self) -> bool: """ Check if we are using FESTIM 1.0 implementation or FESTIM 2.0 """ if not self.subdomain_to_solution: return True else: return False
[docs] class ImplicitSpecies: """Implicit species class for H transport simulation. c = n - others Args: n (Union[float, callable]): the total concentration of the species others (list[Species]): the list of species from which the implicit species concentration is computed (c = n - others) name (str, optional): a name given to the species. Defaults to None. Attributes: name (str): a name given to the species. n (float): the total concentration of the species others (list[Species]): the list of species from which the implicit species concentration is computed (c = n - others) concentration (form): the concentration of the species value_fenics: the total concentration as a fenics object """ def __init__( self, n: Union[float, callable], others: List[Species] = None, name: str = None, ) -> None: self.name = name self.n = n self.others = others def __repr__(self) -> str: return f"ImplicitSpecies({self.name}, {self.n}, {self.others})" def __str__(self) -> str: return f"{self.name}" @property def concentration(self): if len(self.others) > 0: for other in self.others: if other.solution is None: raise ValueError( f"Cannot compute concentration of {self.name} " + f"because {other.name} has no solution." ) return self.value_fenics - sum([other.solution for other in self.others])
[docs] def create_value_fenics(self, mesh, t: fem.Constant): """Creates the value of the density as a fenics object and sets it to self.value_fenics. If the value is a constant, it is converted to a fenics.Constant. If the value is a function of t, it is converted to a fenics.Constant. Otherwise, it is converted to a ufl Expression Args: mesh (dolfinx.mesh.Mesh) : the mesh t (dolfinx.fem.Constant): the time """ x = ufl.SpatialCoordinate(mesh) if isinstance(self.n, (int, float)): self.value_fenics = as_fenics_constant(mesh=mesh, value=self.n) elif isinstance(self.n, (fem.Function, ufl.core.expr.Expr)): self.value_fenics = self.n elif callable(self.n): arguments = self.n.__code__.co_varnames if "t" in arguments and "x" not in arguments and "T" not in arguments: # only t is an argument if not isinstance(self.n(t=float(t)), (float, int)): raise ValueError( f"self.value should return a float or an int, not {type(self.n(t=float(t)))} " ) self.value_fenics = as_fenics_constant( mesh=mesh, value=self.n(t=float(t)) ) else: kwargs = {} if "t" in arguments: kwargs["t"] = t if "x" in arguments: kwargs["x"] = x self.value_fenics = self.n(**kwargs)
[docs] def update_density(self, t): """Updates the density value (only if the density is a function of time only) Args: t (float): the time """ if isinstance(self.n, (fem.Function, ufl.core.expr.Expr)): return if callable(self.n): arguments = self.n.__code__.co_varnames if isinstance(self.value_fenics, fem.Constant) and "t" in arguments: self.value_fenics.value = self.n(t=t)
[docs] def find_species_from_name(name: str, species: list): """Returns the correct species object from a list of species based on a string Args: name (str): the name of the species species (list): the list of species Returns: species (festim.Species): the species object with the correct name Raises: ValueError: if the species name is not found in the list of species """ for spe in species: if spe.name == name: return spe raise ValueError(f"Species {name} not found in list of species")