Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
36ed2a6
accept temperature as callable
jhdark Oct 30, 2023
7064952
temperature needs to be given
jhdark Oct 30, 2023
39a09cc
added tests
jhdark Oct 30, 2023
83d87fc
typo
jhdark Oct 30, 2023
c686eb1
new attribute fenics_value
jhdark Oct 30, 2023
64fe46c
fix tests
jhdark Oct 30, 2023
10bdcc0
updates from comments
jhdark Oct 30, 2023
c427b84
constant not callable
jhdark Oct 30, 2023
1a43f4a
modified tests from comments
jhdark Oct 30, 2023
2750537
typo
jhdark Oct 30, 2023
fd5ee95
improve coverage
jhdark Oct 30, 2023
9a547e5
update doc strings
jhdark Oct 30, 2023
bead7e3
add test for temperture as None
jhdark Oct 30, 2023
22de6a6
additional test for coverage
jhdark Oct 30, 2023
6830c37
Merge branch 'temperature_as_callable' into fenicsx
jhdark Oct 31, 2023
470305a
Merge pull request #17 from jhdark/fenicsx
jhdark Oct 31, 2023
dc3290e
add update time dependent values
jhdark Oct 31, 2023
a8d0e6f
model integration test simpler
jhdark Oct 31, 2023
7227150
expected values as arguement
jhdark Oct 31, 2023
068efb5
use temperature function space in temperature expr
jhdark Oct 31, 2023
67d30cc
Apply suggestions from code review
jhdark Oct 31, 2023
f69ec67
moved temperature tests to h-transport-problem tests
jhdark Oct 31, 2023
0f63f92
use float(self.t)
jhdark Oct 31, 2023
2a254b8
updated doc strings
jhdark Oct 31, 2023
535e56f
remove logic from tests
jhdark Oct 31, 2023
ce9a411
added raise value error, degree argument
jhdark Oct 31, 2023
9f39d51
update docs
jhdark Oct 31, 2023
363caf4
typo
jhdark Nov 1, 2023
b92b827
is, not == in test
jhdark Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 122 additions & 13 deletions festim/hydrogen_transport_problem.py
Comment thread
jhdark marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class HydrogenTransportProblem:
mesh (festim.Mesh): the mesh of the model
subdomains (list of festim.Subdomain): the subdomains of the model
species (list of festim.Species): the species of the model
temperature (float or fem.Constant): the temperature of the model
temperature (float, int, fem.Constant, fem.Function or callable): the
temperature of the model (K)
sources (list of festim.Source): the hydrogen sources of the model
boundary_conditions (list of festim.BoundaryCondition): the boundary
conditions of the model
Expand All @@ -33,7 +34,8 @@ class HydrogenTransportProblem:
mesh (festim.Mesh): the mesh of the model
subdomains (list of festim.Subdomain): the subdomains of the model
species (list of festim.Species): the species of the model
temperature (fem.Constant): the temperature of the model
temperature (float, int, fem.Constant, fem.Function or callable): the
temperature of the model (K)
boundary_conditions (list of festim.BoundaryCondition): the boundary
conditions of the model
solver_parameters (dict): the solver parameters of the model
Expand All @@ -47,7 +49,15 @@ class HydrogenTransportProblem:
model
formulation (ufl.form.Form): the formulation of the model
solver (dolfinx.nls.newton.NewtonSolver): the solver of the model
multispecies (bool): True if the model has more than one species
multispecies (bool): True if the model has more than one species.
temperature_fenics (fem.Constant or fem.Function): the
temperature of the model as a fenics object (fem.Constant or
fem.Function).
temperature_expr (fem.Expression): the expression of the temperature
that is used to update the temperature_fenics
temperature_time_dependent (bool): True if the temperature is time
dependent


Usage:
>>> import festim as F
Expand Down Expand Up @@ -99,6 +109,7 @@ def __init__(
self.formulation = None
self.volume_subdomains = []
self.bc_forms = []
self.temperature_fenics = None

@property
def temperature(self):
Expand All @@ -108,8 +119,39 @@ def temperature(self):
def temperature(self, value):
if value is None:
self._temperature = value
elif isinstance(value, (float, int, fem.Constant, fem.Function)):
self._temperature = value
elif callable(value):
self._temperature = value
else:
raise TypeError(
f"Value must be a float, int, fem.Constant, fem.Function, or callable"
)

@property
def temperature_fenics(self):
return self._temperature_fenics

@temperature_fenics.setter
def temperature_fenics(self, value):
if value is None:
self._temperature_fenics = value
return
elif not isinstance(value, (fem.Constant, fem.Function)):
raise TypeError(f"Value must be a fem.Constant or fem.Function")
self._temperature_fenics = value

@property
def temperature_time_dependent(self):
if self.temperature is None:
return False
if isinstance(self.temperature, fem.Constant):
return False
if callable(self.temperature):
arguments = self.temperature.__code__.co_varnames
return "t" in arguments
else:
self._temperature = F.as_fenics_constant(value, self.mesh.mesh)
return False

@property
def multispecies(self):
Expand All @@ -123,11 +165,68 @@ def initialise(self):
self.t = fem.Constant(self.mesh.mesh, 0.0)
self.dt = self.settings.stepsize.get_dt(self.mesh.mesh)

self.define_temperature()
self.define_boundary_conditions()
self.create_formulation()
self.create_solver()
self.defing_export_writers()

def define_temperature(self):
Comment thread
jhdark marked this conversation as resolved.
"""Sets the value of temperature_fenics_value. The type depends on
self.temperature. If self.temperature is a function on t only, create
a fem.Constant. Else, create an dolfinx.fem.Expression (stored in
self.temperature_expr) to be updated, a dolfinx.fem.Function object
is created from the Expression (stored in self.temperature_fenics_value).
Raise a ValueError if temperature is None.
"""
# check if temperature is None
if self.temperature is None:
raise ValueError("the temperature attribute needs to be defined")

# if temperature is a float or int, create a fem.Constant
elif isinstance(self.temperature, (float, int)):
self.temperature_fenics = F.as_fenics_constant(
self.temperature, self.mesh.mesh
)
# if temperature is a fem.Constant or function, pass it to temperature_fenics
elif isinstance(self.temperature, (fem.Constant, fem.Function)):
self.temperature_fenics = self.temperature

# if temperature is callable, process accordingly
elif callable(self.temperature):
arguments = self.temperature.__code__.co_varnames
if "t" in arguments and "x" not in arguments and "T" not in arguments:
# only t is an argument
self.temperature_fenics = F.as_fenics_constant(
mesh=self.mesh.mesh, value=self.temperature(t=float(self.t))
)
else:
x = ufl.SpatialCoordinate(self.mesh.mesh)
degree = 1
element_temperature = basix.ufl.element(
basix.ElementFamily.P,
self.mesh.mesh.basix_cell(),
degree,
basix.LagrangeVariant.equispaced,
)
function_space_temperature = fem.FunctionSpace(
self.mesh.mesh, element_temperature
)
self.temperature_fenics = fem.Function(function_space_temperature)
kwargs = {}
if "t" in arguments:
kwargs["t"] = self.t
if "x" in arguments:
kwargs["x"] = x

# store the expression of the temperature
# to update the temperature_fenics later
self.temperature_expr = fem.Expression(
Comment thread
jhdark marked this conversation as resolved.
self.temperature(**kwargs),
function_space_temperature.element.interpolation_points(),
Comment thread
RemDelaporteMathurin marked this conversation as resolved.
)
self.temperature_fenics.interpolate(self.temperature_expr)

def defing_export_writers(self):
"""Defines the export writers of the model, if field is given as
a string, find species object in self.species"""
Expand All @@ -146,10 +245,11 @@ def define_function_space(self):
"""Creates the function space of the model, creates a mixed element if
model is multispecies. Creates the main solution and previous solution
function u and u_n."""
degree = 1
element_CG = basix.ufl.element(
basix.ElementFamily.P,
self.mesh.mesh.basix_cell(),
1,
degree,
basix.LagrangeVariant.equispaced,
)
if not self.multispecies:
Expand Down Expand Up @@ -276,7 +376,7 @@ def create_dirichletbc_form(self, bc):

bc.create_value(
mesh=self.mesh.mesh,
temperature=self.temperature,
temperature=self.temperature_fenics,
function_space=function_space_value,
t=self.t,
)
Expand Down Expand Up @@ -325,7 +425,7 @@ def create_formulation(self):

for vol in self.volume_subdomains:
D = vol.material.get_diffusion_coefficient(
self.mesh.mesh, self.temperature, spe
self.mesh.mesh, self.temperature_fenics, spe
)

self.formulation += dot(D * grad(u), grad(v)) * self.dx(vol.id)
Expand Down Expand Up @@ -386,9 +486,7 @@ def iterate(
self.progress.update(self.dt.value)
self.t.value += self.dt.value

# update boundary conditions
for bc in self.boundary_conditions:
bc.update(float(self.t))
self.update_time_dependent_values()

self.solver.solve(self.u)

Expand All @@ -397,7 +495,7 @@ def iterate(
if not skip_post_processing:
if not self.multispecies:
D_D = self.subdomains[0].material.get_diffusion_coefficient(
self.mesh.mesh, self.temperature, self.species[0]
self.mesh.mesh, self.temperature_fenics, self.species[0]
)
cm = self.u
self.species[0].post_processing_solution = self.u
Expand All @@ -412,10 +510,10 @@ def iterate(

cm_1, cm_2 = self.u.split()
D_1 = self.subdomains[0].material.get_diffusion_coefficient(
self.mesh.mesh, self.temperature, self.species[0]
self.mesh.mesh, self.temperature_fenics, self.species[0]
)
D_2 = self.subdomains[0].material.get_diffusion_coefficient(
self.mesh.mesh, self.temperature, self.species[1]
self.mesh.mesh, self.temperature_fenics, self.species[1]
)
surface_flux_1 = form(D_1 * dot(grad(cm_1), self.mesh.n) * self.ds(2))
surface_flux_2 = form(D_2 * dot(grad(cm_2), self.mesh.n) * self.ds(2))
Expand All @@ -431,3 +529,14 @@ def iterate(

# update previous solution
self.u_n.x.array[:] = self.u.x.array[:]

def update_time_dependent_values(self):
t = float(self.t)
if self.temperature_time_dependent:
if isinstance(self.temperature_fenics, fem.Constant):
self.temperature_fenics.value = self.temperature(t=t)
else:
self.temperature_fenics.interpolate(self.temperature_expr)

for bc in self.boundary_conditions:
bc.update(t)
1 change: 1 addition & 0 deletions test/test_dirichlet_bc.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ def test_species_predefined():
my_model.species = [F.Species("H")]
my_bc = F.DirichletBC(subdomain, 1.0, "J")
my_model.boundary_conditions = [my_bc]
my_model.temperature = 1
my_model.settings = F.Settings(atol=1, rtol=0.1)
my_model.settings.stepsize = 1

Expand Down
Loading