Skip to content

Commit a784f11

Browse files
removed SpeciesChangeVar
1 parent 1b3ebf7 commit a784f11

File tree

4 files changed

+103
-49
lines changed

4 files changed

+103
-49
lines changed

src/festim/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
from .reaction import Reaction
6060
from .settings import Settings
6161
from .source import HeatSource, ParticleSource, SourceBase
62-
from .species import ImplicitSpecies, Species, SpeciesChangeVar, find_species_from_name
62+
from .species import ImplicitSpecies, Species, find_species_from_name
6363
from .stepsize import Stepsize
6464
from .subdomain.interface import Interface
6565
from .subdomain.surface_subdomain import SurfaceSubdomain, find_surface_from_id

src/festim/hydrogen_transport_problem.py

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,38 +1510,8 @@ def create_formulation(self):
15101510
self.formulation += ((c - c_n) / self.dt) * v * self.dx(vol.id)
15111511

15121512
for reaction in self.reactions:
1513-
if isinstance(reaction.product, list):
1514-
products = reaction.product
1515-
else:
1516-
products = [reaction.product]
1517-
1518-
# hack enforce the concentration attribute of the species for all species
1519-
# to be used in reaction.reaction_term
1520-
1521-
for spe in self.species:
1522-
if spe.mobile:
1523-
K_S = reaction.volume.material.get_solubility_coefficient(
1524-
self.mesh.mesh, self.temperature_fenics, spe
1525-
)
1526-
assert isinstance(spe, _species.SpeciesChangeVar)
1527-
spe.concentration = spe.solution * K_S
1513+
self.add_reaction_term(reaction)
15281514

1529-
# reactant
1530-
for reactant in reaction.reactant:
1531-
if isinstance(reactant, festim.species.Species):
1532-
self.formulation += (
1533-
reaction.reaction_term(self.temperature_fenics)
1534-
* reactant.test_function
1535-
* self.dx(reaction.volume.id)
1536-
)
1537-
1538-
# product
1539-
for product in products:
1540-
self.formulation += (
1541-
-reaction.reaction_term(self.temperature_fenics)
1542-
* product.test_function
1543-
* self.dx(reaction.volume.id)
1544-
)
15451515
# add sources
15461516
for source in self.sources:
15471517
self.formulation -= (
@@ -1581,6 +1551,55 @@ def create_formulation(self):
15811551
spe.solution * spe.test_function * self.dx(vol.id)
15821552
)
15831553

1554+
def add_reaction_term(self, reaction: _reaction.Reaction):
1555+
"""Adds the reaction term to the formulation"""
1556+
1557+
products = (
1558+
reaction.product
1559+
if isinstance(reaction.product, list)
1560+
else [reaction.product]
1561+
)
1562+
1563+
# we cannot use the `concentration` attribute of the mobile species and need to use u * K_S instead
1564+
1565+
def get_concentrations(species_list) -> List:
1566+
concentrations = []
1567+
for spe in species_list:
1568+
if isinstance(spe, _species.ImplicitSpecies):
1569+
concentrations.append(None)
1570+
elif spe.mobile:
1571+
K_S = reaction.volume.material.get_solubility_coefficient(
1572+
self.mesh.mesh, self.temperature_fenics, spe
1573+
)
1574+
concentrations.append(spe.solution * K_S)
1575+
else:
1576+
concentrations.append(None)
1577+
return concentrations
1578+
1579+
reactant_concentrations = get_concentrations(reaction.reactant)
1580+
product_concentrations = get_concentrations(products)
1581+
1582+
# get the reaction term from the reaction
1583+
reaction_term = reaction.reaction_term(
1584+
temperature=self.temperature_fenics,
1585+
reactant_concentrations=reactant_concentrations,
1586+
product_concentrations=product_concentrations,
1587+
)
1588+
1589+
# add reaction term to formulation
1590+
# reactant
1591+
for reactant in reaction.reactant:
1592+
if isinstance(reactant, festim.species.Species):
1593+
self.formulation += (
1594+
reaction_term * reactant.test_function * self.dx(reaction.volume.id)
1595+
)
1596+
1597+
# product
1598+
for product in products:
1599+
self.formulation += (
1600+
-reaction_term * product.test_function * self.dx(reaction.volume.id)
1601+
)
1602+
15841603
def initialise_exports(self):
15851604
self.override_post_processing_solution()
15861605
super().initialise_exports()

src/festim/reaction.py

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from typing import Optional, Union
1+
from typing import Optional, Union, List
22

33
from ufl import exp
4+
from ufl.core.expr import Expr
45

56
from festim import k_B as _k_B
67
from festim.species import ImplicitSpecies as _ImplicitSpecies
@@ -102,11 +103,27 @@ def __str__(self) -> str:
102103
products = self.product
103104
return f"{reactants} <--> {products}"
104105

105-
def reaction_term(self, temperature):
106+
def reaction_term(
107+
self,
108+
temperature,
109+
reactant_concentrations: List = None,
110+
product_concentrations: List = None,
111+
) -> Expr:
106112
"""Compute the reaction term at a given temperature.
107113
108114
Arguments:
109-
temperature (): The temperature at which the reaction term is computed.
115+
temperature: The temperature at which the reaction term is computed.
116+
reactant_concentrations: The concentrations of the reactants. Must
117+
be the same length as the reactants. If None, the ``concentration``
118+
attribute of each reactant is used. If an element is None, the
119+
``concentration`` attribute of the reactant is used.
120+
product_concentrations: The concentrations of the products. Must
121+
be the same length as the products. If None, the ``concentration``
122+
attribute of each product is used. If an element is None, the
123+
``concentration`` attribute of the product is used.
124+
125+
Returns:
126+
The reaction term to be used in a formulation.
110127
"""
111128

112129
if self.product == []:
@@ -130,6 +147,9 @@ def reaction_term(self, temperature):
130147
"E_p cannot be None when reaction products are present."
131148
)
132149

150+
products = self.product if isinstance(self.product, list) else [self.product]
151+
152+
# reaction rates
133153
k = self.k_0 * exp(-self.E_k / (_k_B * temperature))
134154

135155
if self.p_0 and self.E_p:
@@ -139,20 +159,35 @@ def reaction_term(self, temperature):
139159
else:
140160
p = 0
141161

162+
# if reactant_concentrations is provided, use these concentrations
142163
reactants = self.reactant
143-
product_of_reactants = reactants[0].concentration
144-
for reactant in reactants[1:]:
145-
product_of_reactants *= reactant.concentration
146-
147-
if isinstance(self.product, list):
148-
products = self.product
164+
if reactant_concentrations is not None:
165+
assert len(reactant_concentrations) == len(reactants)
166+
for i, reactant in enumerate(reactants):
167+
if reactant_concentrations[i] is None:
168+
reactant_concentrations[i] = reactant.concentration
169+
else:
170+
reactant_concentrations = [reactant.concentration for reactant in reactants]
171+
172+
# if product_concentrations is provided, use these concentrations
173+
if product_concentrations is not None:
174+
assert len(product_concentrations) == len(products)
175+
for i, product in enumerate(products):
176+
if product_concentrations[i] is None:
177+
product_concentrations[i] = product.concentration
149178
else:
150-
products = [self.product]
179+
product_concentrations = [product.concentration for product in products]
151180

152-
if len(products) > 0:
153-
product_of_products = products[0].concentration
154-
for product in products[1:]:
155-
product_of_products *= product.concentration
181+
# multiply all concentrations to be used in the term
182+
product_of_reactants = reactant_concentrations[0]
183+
for reactant_conc in reactant_concentrations[1:]:
184+
product_of_reactants *= reactant_conc
185+
186+
if products:
187+
product_of_products = product_concentrations[0]
188+
for product_conc in product_concentrations[1:]:
189+
product_of_products *= product_conc
156190
else:
157191
product_of_products = 0
192+
158193
return k * product_of_reactants - (p * product_of_products)

test/system_tests/test_multi_material_change_of_var.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ def test_run():
103103
right_surface,
104104
]
105105

106-
H = F.SpeciesChangeVar("H", mobile=True)
107-
trapped_H = F.SpeciesChangeVar("H_trapped", mobile=False)
106+
H = F.Species("H", mobile=True)
107+
trapped_H = F.Species("H_trapped", mobile=False)
108108
empty_trap = F.ImplicitSpecies(n=0.5, others=[trapped_H])
109109

110110
my_model.species = [H, trapped_H]
@@ -193,7 +193,7 @@ def c_exact_bot_np(x):
193193
bottom_surface,
194194
]
195195

196-
H = F.SpeciesChangeVar("H", mobile=True)
196+
H = F.Species("H", mobile=True)
197197

198198
my_model.species = [H]
199199

0 commit comments

Comments
 (0)