Skip to content

Commit 1b246ad

Browse files
change var function in the same file
1 parent 33dbfeb commit 1b246ad

File tree

4 files changed

+226
-236
lines changed

4 files changed

+226
-236
lines changed

src/festim/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@
4444
Value,
4545
get_interpolation_points,
4646
)
47+
from .problem import ProblemBase
4748
from .hydrogen_transport_problem import (
4849
HTransportProblemDiscontinuous,
4950
HTransportProblemPenalty,
5051
HydrogenTransportProblem,
52+
HydrogenTransportProblemDiscontinuousChangeVar,
5153
)
5254
from .initial_condition import InitialCondition, InitialTemperature
5355
from .material import Material
5456
from .mesh.mesh import Mesh
5557
from .mesh.mesh_1d import Mesh1D
5658
from .mesh.mesh_from_xdmf import MeshFromXDMF
57-
from .problem import ProblemBase
58-
from .problem_change_of_var import HydrogenTransportProblemDiscontinuousChangeVar
5959
from .reaction import Reaction
6060
from .settings import Settings
6161
from .source import HeatSource, ParticleSource, SourceBase

src/festim/coupled_heat_hydrogen_problem.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
HTransportProblemDiscontinuous,
88
HTransportProblemPenalty,
99
HydrogenTransportProblem,
10+
HydrogenTransportProblemDiscontinuousChangeVar,
1011
)
11-
from festim.problem_change_of_var import HydrogenTransportProblemDiscontinuousChangeVar
1212

1313

1414
class CoupledTransientHeatTransferHydrogenTransport:

src/festim/hydrogen_transport_problem.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import Callable
2+
from typing import List
23

34
from mpi4py import MPI
45

@@ -1471,3 +1472,225 @@ def create_formulation(self):
14711472
entity_maps=entity_maps,
14721473
)
14731474
self.J = dolfinx.fem.form(J, entity_maps=entity_maps)
1475+
1476+
1477+
class HydrogenTransportProblemDiscontinuousChangeVar(HydrogenTransportProblem):
1478+
species: List[_species.Species]
1479+
1480+
def create_formulation(self):
1481+
"""Creates the formulation of the model"""
1482+
1483+
self.formulation = 0
1484+
1485+
# add diffusion and time derivative for each species
1486+
for spe in self.species:
1487+
u = spe.solution
1488+
u_n = spe.prev_solution
1489+
v = spe.test_function
1490+
1491+
for vol in self.volume_subdomains:
1492+
D = vol.material.get_diffusion_coefficient(
1493+
self.mesh.mesh, self.temperature_fenics, spe
1494+
)
1495+
if spe.mobile:
1496+
K_S = vol.material.get_solubility_coefficient(
1497+
self.mesh.mesh, self.temperature_fenics, spe
1498+
)
1499+
c = u * K_S
1500+
c_n = u_n * K_S
1501+
else:
1502+
c = u
1503+
c_n = u_n
1504+
if spe.mobile:
1505+
self.formulation += ufl.dot(D * ufl.grad(c), ufl.grad(v)) * self.dx(
1506+
vol.id
1507+
)
1508+
1509+
if self.settings.transient:
1510+
self.formulation += ((c - c_n) / self.dt) * v * self.dx(vol.id)
1511+
1512+
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
1528+
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+
)
1545+
# add sources
1546+
for source in self.sources:
1547+
self.formulation -= (
1548+
source.value.fenics_object
1549+
* source.species.test_function
1550+
* self.dx(source.volume.id)
1551+
)
1552+
1553+
# add fluxes
1554+
for bc in self.boundary_conditions:
1555+
if isinstance(bc, boundary_conditions.ParticleFluxBC):
1556+
self.formulation -= (
1557+
bc.value_fenics
1558+
* bc.species.test_function
1559+
* self.ds(bc.subdomain.id)
1560+
)
1561+
1562+
# check if each species is defined in all volumes
1563+
if not self.settings.transient:
1564+
for spe in self.species:
1565+
# if species mobile, already defined in diffusion term
1566+
if not spe.mobile:
1567+
not_defined_in_volume = self.volume_subdomains.copy()
1568+
for vol in self.volume_subdomains:
1569+
# check reactions
1570+
for reaction in self.reactions:
1571+
if (
1572+
spe in reaction.product
1573+
): # TODO we probably need this in HydrogenTransportProblem too no?
1574+
if vol == reaction.volume:
1575+
if vol in not_defined_in_volume:
1576+
not_defined_in_volume.remove(vol)
1577+
1578+
# add c = 0 to formulation where needed
1579+
for vol in not_defined_in_volume:
1580+
self.formulation += (
1581+
spe.solution * spe.test_function * self.dx(vol.id)
1582+
)
1583+
1584+
def initialise_exports(self):
1585+
self.override_post_processing_solution()
1586+
super().initialise_exports()
1587+
1588+
def override_post_processing_solution(self):
1589+
# override the post-processing solution c = theta * K_S
1590+
Q0 = fem.functionspace(self.mesh.mesh, ("DG", 0))
1591+
Q1 = fem.functionspace(self.mesh.mesh, ("DG", 1))
1592+
1593+
for spe in self.species:
1594+
if not spe.mobile:
1595+
continue
1596+
K_S0 = fem.Function(Q0)
1597+
E_KS = fem.Function(Q0)
1598+
for subdomain in self.volume_subdomains:
1599+
entities = subdomain.locate_subdomain_entities_correct(
1600+
self.volume_meshtags
1601+
)
1602+
K_S0.x.array[entities] = subdomain.material.get_K_S_0(spe)
1603+
E_KS.x.array[entities] = subdomain.material.get_E_K_S(spe)
1604+
1605+
K_S = K_S0 * ufl.exp(-E_KS / (festim.k_B * self.temperature_fenics))
1606+
1607+
theta = spe.solution
1608+
1609+
spe.dg_expr = fem.Expression(
1610+
theta * K_S, get_interpolation_points(Q1.element)
1611+
)
1612+
spe.post_processing_solution = fem.Function(Q1)
1613+
spe.post_processing_solution.interpolate(
1614+
spe.dg_expr
1615+
) # NOTE: do we need this line since it's in initialise?
1616+
1617+
def post_processing(self):
1618+
# need to compute c = theta * K_S
1619+
# this expression is stored in species.dg_expr
1620+
for spe in self.species:
1621+
if not spe.mobile:
1622+
continue
1623+
spe.post_processing_solution.interpolate(spe.dg_expr)
1624+
1625+
super().post_processing()
1626+
1627+
def create_dirichletbc_form(self, bc: festim.FixedConcentrationBC):
1628+
"""Creates a dirichlet boundary condition form
1629+
1630+
Args:
1631+
bc (festim.DirichletBC): the boundary condition
1632+
1633+
Returns:
1634+
dolfinx.fem.bcs.DirichletBC: A representation of
1635+
the boundary condition for modifying linear systems.
1636+
"""
1637+
# create value_fenics
1638+
if not self.multispecies:
1639+
function_space_value = bc.species.sub_function_space
1640+
else:
1641+
function_space_value = bc.species.collapsed_function_space
1642+
1643+
# create K_S function
1644+
Q0 = fem.functionspace(self.mesh.mesh, ("DG", 0))
1645+
K_S0 = fem.Function(Q0)
1646+
E_KS = fem.Function(Q0)
1647+
for subdomain in self.volume_subdomains:
1648+
entities = subdomain.locate_subdomain_entities_correct(self.volume_meshtags)
1649+
K_S0.x.array[entities] = subdomain.material.get_K_S_0(bc.species)
1650+
E_KS.x.array[entities] = subdomain.material.get_E_K_S(bc.species)
1651+
1652+
K_S = K_S0 * ufl.exp(-E_KS / (festim.k_B * self.temperature_fenics))
1653+
1654+
bc.create_value(
1655+
temperature=self.temperature_fenics,
1656+
function_space=function_space_value,
1657+
t=self.t,
1658+
K_S=K_S,
1659+
)
1660+
1661+
# get dofs
1662+
if self.multispecies and isinstance(bc.value_fenics, (fem.Function)):
1663+
function_space_dofs = (
1664+
bc.species.sub_function_space,
1665+
bc.species.collapsed_function_space,
1666+
)
1667+
else:
1668+
function_space_dofs = bc.species.sub_function_space
1669+
1670+
bc_dofs = bc.define_surface_subdomain_dofs(
1671+
facet_meshtags=self.facet_meshtags,
1672+
function_space=function_space_dofs,
1673+
)
1674+
1675+
# create form
1676+
if not self.multispecies and isinstance(bc.value_fenics, (fem.Function)):
1677+
# no need to pass the functionspace since value_fenics is already a Function
1678+
function_space_form = None
1679+
else:
1680+
function_space_form = bc.species.sub_function_space
1681+
1682+
form = fem.dirichletbc(
1683+
value=bc.value_fenics,
1684+
dofs=bc_dofs,
1685+
V=function_space_form,
1686+
)
1687+
1688+
return form
1689+
1690+
def update_time_dependent_values(self):
1691+
super().update_time_dependent_values()
1692+
1693+
if self.temperature_time_dependent:
1694+
for bc in self.boundary_conditions:
1695+
if isinstance(bc, boundary_conditions.FixedConcentrationBC):
1696+
bc.update(self.t)

0 commit comments

Comments
 (0)