Skip to content

Commit

Permalink
Merge pull request festim-dev#774 from festim-dev/IC-heat-transfer
Browse files Browse the repository at this point in the history
IC improvements for Heat Transfer
  • Loading branch information
RemDelaporteMathurin authored Jun 4, 2024
2 parents 217dc15 + 82509da commit fb2c99f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
11 changes: 11 additions & 0 deletions docs/source/userguide/temperature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ For a steady-state problem:
:ref:`Boundary conditions<boundary conditions>` and :ref:`heat sources<sources>` can then be applied to this heat transfer problem.

For transient problems, an initial condition is required:

.. code-block:: python
model.T = HeatTransferProblem(
transient=True,
initial_condition=300,
)
Initial conditions can be given as float, sympy expressions or a :class:`festim.InitialCondition` instance in order to read from a XDMF file (see :ref:`Initial Conditions<Initial Conditions>` for more details).

----------------
From a XDMF file
----------------
Expand Down
18 changes: 16 additions & 2 deletions festim/temperature/temperature_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class HeatTransferProblem(festim.Temperature):
Args:
transient (bool, optional): If True, a transient simulation will
be run. Defaults to True.
initial_condition (festim.InitialCondition, optional): The initial condition.
initial_condition (int, float, sp.Expr, festim.InitialCondition, optional): The initial condition.
Only needed if transient is True.
absolute_tolerance (float, optional): the absolute tolerance of the newton
solver. Defaults to 1e-03
Expand Down Expand Up @@ -56,6 +56,17 @@ def __init__(
self.boundary_conditions = []
self.sub_expressions = []

@property
def initial_condition(self):
return self._initial_condition

@initial_condition.setter
def initial_condition(self, value):
if isinstance(value, (int, float, sp.Expr)):
self._initial_condition = festim.InitialCondition(field="T", value=value)
else:
self._initial_condition = value

# TODO rename initialise?
def create_functions(self, materials, mesh, dt=None):
"""Creates functions self.T, self.T_n and test function self.v_T.
Expand All @@ -73,7 +84,10 @@ def create_functions(self, materials, mesh, dt=None):
self.T = f.Function(V, name="T")
self.T_n = f.Function(V, name="T_n")
self.v_T = f.TestFunction(V)

if self.transient and self.initial_condition is None:
raise AttributeError(
"Initial condition is required for transient heat transfer simulations"
)
if self.transient and self.initial_condition:
if isinstance(self.initial_condition.value, str):
if self.initial_condition.value.endswith(".xdmf"):
Expand Down
20 changes: 20 additions & 0 deletions test/system/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,23 @@ def test_materials_setter():
test_materials = F.Materials([])
my_model.materials = test_materials
assert my_model.materials is test_materials


def test_error_raised_when_no_IC_heat_transfer():
"""
Checks that an error is raised when no initial condition is provided for
transient heat transfer simulations
"""
my_model = F.Simulation()

my_model.T = F.HeatTransferProblem(transient=True, initial_condition=None)
my_model.mesh = F.MeshFromVertices(np.linspace(0, 1, 10))
my_model.materials = F.Material(1, 1, 0.1)
my_model.settings = F.Settings(1e-10, 1e-10, final_time=1e-7)
my_model.dt = F.Stepsize(1e-9)

with pytest.raises(
AttributeError,
match="Initial condition is required for transient heat transfer simulations",
):
my_model.initialise()
28 changes: 25 additions & 3 deletions test/unit/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ def thermal_cond(a):
bc1 = festim.DirichletBC(surfaces=[1], value=u, field="T")
bc2 = festim.FluxBC(surfaces=[2], value=2, field="T")

my_temp = festim.HeatTransferProblem(
transient=True, initial_condition=festim.InitialCondition(field="T", value=0)
)
my_temp = festim.HeatTransferProblem(transient=True, initial_condition=0)
my_temp.boundary_conditions = [bc1, bc2]
my_temp.sources = [festim.Source(-4, volume=[1], field="T")]
my_temp.create_functions(my_mats, my_mesh, dt=dt)
Expand Down Expand Up @@ -133,6 +131,30 @@ class is created from this file and the error norm between the written and
assert error_L2 < 1e-9


def test_temperature_with_expr():
"""
Test for the InitialCondition.create_functions() with a sympy expression
and checks that the error norm between the expected and computed
functions is below a certain threshold.
"""
# create function to be comapared
mesh = fenics.UnitSquareMesh(10, 10)
# TempFromXDMF needs a festim mesh
my_mesh = festim.Mesh()
my_mesh.dx = fenics.dx
my_mesh.ds = fenics.ds
my_mesh.mesh = mesh
my_mats = festim.Materials(
[festim.Material(id=1, D_0=1, E_D=0, thermal_cond=1, heat_capacity=1, rho=1)]
)
my_T = festim.HeatTransferProblem(transient=True, initial_condition=300 + festim.x)
my_T.create_functions(mesh=my_mesh, materials=my_mats, dt=festim.Stepsize(2))

expected_expr = fenics.Expression("300 + x[0]", degree=2)
error_L2 = fenics.errornorm(expected_expr, my_T.T_n, "L2")
assert error_L2 < 1e-9


def test_temperature_from_xdmf_create_functions(tmpdir):
"""Test for the TemperatureFromXDMF.create_functions().
Creates a function, writes it to an XDMF file, then a TemperatureFromXDMF
Expand Down

0 comments on commit fb2c99f

Please sign in to comment.