Source code for festim.boundary_conditions.surface_reaction
import ufl
from dolfinx import fem
from festim import k_B
from festim.boundary_conditions import ParticleFluxBC
[docs]
class SurfaceReactionBCpartial(ParticleFluxBC):
"""Boundary condition representing a surface reaction A + B <-> C.
where A, B are the reactants and C is the product
the forward reaction rate is K_r = k_r0 * exp(-E_kr / (k_B * T))
and the backward reaction rate is K_d = k_d0 * exp(-E_kd / (k_B * T))
The reaction rate is:
K = K_r * C_A * C_B - K_d * P_C
with C_A, C_B the concentration of species A and B,
P_C the partial pressure of species C at the surface.
This class is used to create the flux of a single species entering the surface
Example: The flux of species A entering the surface is K.
Args:
reactant (list): list of F.Species objects representing the reactants
gas_pressure (float, callable): the partial pressure of the product species
k_r0 (float): the pre-exponential factor of the forward reaction rate
E_kr (float): the activation energy of the forward reaction rate (eV)
k_d0 (float): the pre-exponential factor of the backward reaction rate
E_kd (float): the activation energy of the backward reaction rate (eV)
subdomain (F.SurfaceSubdomain): the surface subdomain where the reaction occurs
species (F.Species): the species to which the flux is applied
"""
def __init__(
self,
reactant,
gas_pressure,
k_r0,
E_kr,
k_d0,
E_kd,
subdomain,
species,
):
self.reactant = reactant
self.gas_pressure = gas_pressure
self.k_r0 = k_r0
self.E_kr = E_kr
self.k_d0 = k_d0
self.E_kd = E_kd
super().__init__(subdomain=subdomain, value=None, species=species)
[docs]
def create_value_fenics(self, mesh, temperature, t: fem.Constant):
kr = self.k_r0 * ufl.exp(-self.E_kr / (k_B * temperature))
kd = self.k_d0 * ufl.exp(-self.E_kd / (k_B * temperature))
if callable(self.gas_pressure):
gas_pressure = self.gas_pressure(t=t)
else:
gas_pressure = self.gas_pressure
# initialise with the concentration of the first reactant
if self.reactant[0].concentration:
product_of_reactants = self.reactant[0].concentration
else: # probably used in HydrogenTransportProblemDiscontinuous
product_of_reactants = self.reactant[0].subdomain_to_solution[
self._volume_subdomain
]
# then compute the product of the concentrations of the other reactants
for reactant in self.reactant[1:]:
if reactant.concentration:
product_of_reactants *= reactant.concentration
else: # probably used in HydrogenTransportProblemDiscontinuous
product_of_reactants *= reactant.subdomain_to_solution[
self._volume_subdomain
]
self.value_fenics = kd * gas_pressure - kr * product_of_reactants
[docs]
class SurfaceReactionBC:
"""Boundary condition representing a surface reaction A + B <-> C.
where A, B are the reactants and C is the product
the forward reaction rate is K_r = k_r0 * exp(-E_kr / (k_B * T))
and the backward reaction rate is K_d = k_d0 * exp(-E_kd / (k_B * T))
The reaction rate is:
K = K_r * C_A * C_B - K_d * P_C
with C_A, C_B the concentration of species A and B,
P_C the partial pressure of species C at the surface.
The flux of species A entering the surface is K.
In the special case where A=B, then the flux of particle entering the surface is 2*K
Args:
reactant (list): list of F.Species objects representing the reactants
gas_pressure (float, callable): the partial pressure of the product species
k_r0 (float): the pre-exponential factor of the forward reaction rate
E_kr (float): the activation energy of the forward reaction rate (eV)
k_d0 (float): the pre-exponential factor of the backward reaction rate
E_kd (float): the activation energy of the backward reaction rate (eV)
subdomain (F.SurfaceSubdomain): the surface subdomain where the reaction occurs
"""
def __init__(
self,
reactant,
gas_pressure,
k_r0,
E_kr,
k_d0,
E_kd,
subdomain,
):
self.reactant = reactant
self.gas_pressure = gas_pressure
self.k_r0 = k_r0
self.E_kr = E_kr
self.k_d0 = k_d0
self.E_kd = E_kd
self.subdomain = subdomain
# create the flux boundary condition for each reactant
self.flux_bcs = [
SurfaceReactionBCpartial(
reactant=self.reactant,
gas_pressure=self.gas_pressure,
k_r0=self.k_r0,
E_kr=self.E_kr,
k_d0=self.k_d0,
E_kd=self.E_kd,
subdomain=self.subdomain,
species=species,
)
for species in self.reactant
]
@property
def time_dependent(self):
return False # no need to update if only using ufl.conditional objects