Source code for festim.concentration.theta

from festim import Mobile, k_B
import fenics as f


[docs] class Theta(Mobile): """Class representing the "chemical potential" c/S where S is the solubility of the metal """ def __init__(self): """Inits Theta""" super().__init__() self.S = None self.F = None
[docs] def initialise(self, V, value, label=None, time_step=None): """Assign a value to self.previous_solution Args: V (fenics.FunctionSpace): the function space value (sp.Add, float, int, str): the value of the initialisation. label (str, optional): the label in the XDMF file. Defaults to None. time_step (int, optional): the time step to read in the XDMF file. Defaults to None. """ comp = self.get_comp(V, value, label=label, time_step=time_step) prev_sol = f.Function(V) v = f.TestFunction(V) dx = f.Measure("dx", subdomain_data=self.volume_markers) F = 0 for mat in self.materials: S = mat.S_0 * f.exp(-mat.E_S / k_B / self.T.T) F += -prev_sol * v * dx(mat.id) if mat.solubility_law == "sievert": F += comp / S * v * dx(mat.id) elif mat.solubility_law == "henry": F += (comp / S) ** 0.5 * v * dx(mat.id) f.solve(F == 0, prev_sol, bcs=[]) f.assign(self.previous_solution, prev_sol)
[docs] def get_concentration_for_a_given_material(self, material, T): """Returns the concentration (and previous concentration) for a given material Args: material (festim.Material): the material with attributes S_0 and E_S T (festim.Temperature): the temperature with attributest T and T_n Returns: fenics.Product, fenics.Product: the current concentration and previous concentration """ E_S = material.E_S S_0 = material.S_0 S = S_0 * f.exp(-E_S / k_B / T.T) S_n = S_0 * f.exp(-E_S / k_B / T.T_n) if material.solubility_law == "sievert": c_0 = self.solution * S c_0_n = self.previous_solution * S_n elif material.solubility_law == "henry": c_0 = (self.solution) ** 2 * S c_0_n = self.previous_solution**2 * S_n return c_0, c_0_n
[docs] def mobile_concentration(self): """Returns the hydrogen concentration as c=theta*K_S or c=theta**2*K_H This is needed when adding robin BCs (eg RecombinationFlux). Returns: ufl.algebra.Sum: the hydrogen mobile concentration """ henry_to_concentration = self.solution**2 * self.S sieverts_to_concentration = self.solution * self.S # henry_marker is equal to 1 in Henry materials and 0 elsewhere return ( self.materials.henry_marker * henry_to_concentration + self.materials.sievert_marker * sieverts_to_concentration )
[docs] def post_processing_solution_to_concentration(self): """Converts the post_processing_solution from theta to mobile concentration. c = theta * S. The attribute post_processing_solution is fenics.Product (if self.S is festim.ArheniusCoeff) """ problem = f.LinearVariationalProblem( a=f.lhs(self.form_post_processing), L=f.rhs(self.form_post_processing), u=self.post_processing_solution, bcs=[], ) solver = f.LinearVariationalSolver(problem) solver.solve()
[docs] def create_form_post_processing(self, V, materials, dx): """Creates a variational formulation for c = theta * S or theta**2 * S Args: V (fenics.FunctionSpace): the DG1 function space of the concentration field materials (festim.Materials): the materials dx (fenics.Measurement): the dx measure of the problem """ F = 0 v = f.TestFunction(V) c = f.TrialFunction(V) F += -c * v * dx for mat in materials: if mat.solubility_law == "sievert": # for sievert materials c = theta * S F += self.solution * self.S * v * dx(mat.id) elif mat.solubility_law == "henry": # for henry materials c = theta**2 * S F += self.solution**2 * self.S * v * dx(mat.id) self.form_post_processing = F self.post_processing_solution = f.Function(V)