Skip to content

Commit

Permalink
Merge pull request #694 from KulaginVladimir/main
Browse files Browse the repository at this point in the history
F.Materials -> subclass of list
  • Loading branch information
RemDelaporteMathurin authored Feb 1, 2024
2 parents 0353514 + e85cf4a commit ff6daff
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 33 deletions.
2 changes: 1 addition & 1 deletion festim/concentration/mobile.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def create_diffusion_form(
raise ValueError(msg)

F = 0
for material in materials.materials:
for material in materials:
D_0 = material.D_0
E_D = material.E_D
c_0, c_0_n = self.get_concentration_for_a_given_material(material, T)
Expand Down
4 changes: 2 additions & 2 deletions festim/concentration/theta.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def initialise(self, V, value, label=None, time_step=None):
v = f.TestFunction(V)
dx = f.Measure("dx", subdomain_data=self.volume_markers)
F = 0
for mat in self.materials.materials:
for mat in self.materials:
S = mat.S_0 * f.exp(-mat.E_S / k_B / self.T.T)
F += -prev_sol * v * dx(mat.id)
if mat.solubility_law == "sievert":
Expand Down Expand Up @@ -110,7 +110,7 @@ def create_form_post_processing(self, V, materials, dx):
c = f.TrialFunction(V)

F += -c * v * dx
for mat in materials.materials:
for mat in materials:
if mat.solubility_law == "sievert":
# for sievert materials c = theta * S
F += self.solution * self.S * v * dx(mat.id)
Expand Down
2 changes: 1 addition & 1 deletion festim/concentration/traps/trap.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def create_trapping_form(self, mobile, materials, T, dx, dt=None):
# if the sim is steady state and
# if a trap is not defined in one subdomain
# add c_t = 0 to the form in this subdomain
for mat in materials.materials:
for mat in materials:
if mat not in self.materials:
F_trapping += solution * test_function * dx(mat.id)

Expand Down
6 changes: 3 additions & 3 deletions festim/generic_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,12 @@ def materials(self):

@materials.setter
def materials(self, value):
if isinstance(value, list):
if isinstance(value, festim.Materials):
self._materials = value
elif isinstance(value, list):
self._materials = festim.Materials(value)
elif isinstance(value, festim.Material):
self._materials = festim.Materials([value])
elif isinstance(value, festim.Materials):
self._materials = value
elif value is None:
self._materials = value
else:
Expand Down
46 changes: 22 additions & 24 deletions festim/materials/materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
from typing import Union


class Materials:
class Materials(list):
"""
Args:
materials (list, optional): contains festim.Material objects.
Defaults to [].
A list of festim.Material objects
"""

def __init__(self, materials=[]):
self.materials = materials
def __init__(self, *args):
super().__init__(*args)
self.D = None
self.S = None
self.thermal_cond = None
Expand All @@ -38,7 +36,7 @@ def check_borders(self, size):
bool -- True if everything's alright
"""
all_borders = []
for m in self.materials:
for m in self:
if isinstance(m.borders[0], list):
for border in m.borders:
all_borders.append(border)
Expand All @@ -63,7 +61,7 @@ def check_materials(self, T: festim.Temperature, derived_quantities: list = []):
objects the derived quantities. Defaults to [].
"""

if len(self.materials) > 0: # TODO: get rid of this...
if len(self) > 0: # TODO: get rid of this...
self.check_consistency()

self.check_for_unused_properties(T, derived_quantities)
Expand All @@ -75,7 +73,7 @@ def check_materials(self, T: festim.Temperature, derived_quantities: list = []):
def check_unique_ids(self):
# check that ids are different
mat_ids = []
for mat in self.materials:
for mat in self:
if type(mat.id) is list:
mat_ids += mat.id
else:
Expand All @@ -98,12 +96,12 @@ def check_for_unused_properties(
# warn about unused keys
transient_properties = ["rho", "heat_capacity"]
if not isinstance(T, HeatTransferProblem):
for mat in self.materials:
for mat in self:
for key in transient_properties:
if getattr(mat, key) is not None:
warnings.warn(key + " key will be ignored", UserWarning)

for mat in self.materials:
for mat in self:
if getattr(mat, "thermal_cond") is not None:
warn = True
if isinstance(T, HeatTransferProblem):
Expand Down Expand Up @@ -135,9 +133,9 @@ def check_consistency(self):
}

for attr, value in attributes.items():
for mat in self.materials:
for mat in self:
value.append(getattr(mat, attr))
if value.count(None) not in [0, len(self.materials)]:
if value.count(None) not in [0, len(self)]:
raise ValueError("{} is not defined for all materials".format(attr))

def check_missing_properties(self, T: festim.Temperature, derived_quantities: list):
Expand All @@ -151,12 +149,12 @@ def check_missing_properties(self, T: festim.Temperature, derived_quantities: li
ValueError: if thermal_cond, heat_capacity or rho is None when needed
"""
if isinstance(T, HeatTransferProblem):
if self.materials[0].thermal_cond is None:
if self[0].thermal_cond is None:
raise ValueError("Missing thermal_cond in materials")
if T.transient:
if self.materials[0].heat_capacity is None:
if self[0].heat_capacity is None:
raise ValueError("Missing heat_capacity in materials")
if self.materials[0].rho is None:
if self[0].rho is None:
raise ValueError("Missing rho in materials")
# TODO: add check for thermal cond for thermal flux computation

Expand All @@ -172,7 +170,7 @@ def find_material_from_id(self, mat_id):
Returns:
festim.Material: the material that has the id mat_id
"""
for material in self.materials:
for material in self:
mat_ids = material.id
if type(mat_ids) is not list:
mat_ids = [mat_ids]
Expand All @@ -192,7 +190,7 @@ def find_material_from_name(self, name):
Returns:
festim.Material: the material object
"""
for material in self.materials:
for material in self:
if material.name == name:
return material

Expand Down Expand Up @@ -225,7 +223,7 @@ def find_subdomain_from_x_coordinate(self, x):
Returns:
int: the corresponding subdomain id
"""
for material in self.materials:
for material in self:
# if no borders are provided, assume only one subdomain
if material.borders is None:
return material.id
Expand Down Expand Up @@ -255,13 +253,13 @@ def create_properties(self, vm, T):
"""
self.D = ArheniusCoeff(self, vm, T, "D_0", "E_D", degree=2)
# all materials have the same properties so only checking the first is enough
if self.materials[0].S_0 is not None:
if self[0].S_0 is not None:
self.S = ArheniusCoeff(self, vm, T, "S_0", "E_S", degree=2)
if self.materials[0].thermal_cond is not None:
if self[0].thermal_cond is not None:
self.thermal_cond = ThermalProp(self, vm, T, "thermal_cond", degree=2)
self.heat_capacity = ThermalProp(self, vm, T, "heat_capacity", degree=2)
self.density = ThermalProp(self, vm, T, "rho", degree=2)
if self.materials[0].Q is not None:
if self[0].Q is not None:
self.Q = ThermalProp(self, vm, T, "Q", degree=2)

def solubility_as_function(self, mesh, T):
Expand All @@ -273,7 +271,7 @@ def solubility_as_function(self, mesh, T):
vS = f.TestFunction(V)
dx = mesh.dx
F = 0
for mat in self.materials:
for mat in self:
F += -S * vS * dx(mat.id)
F += mat.S_0 * f.exp(-mat.E_S / k_B / T) * vS * dx(mat.id)
f.solve(F == 0, S, bcs=[])
Expand All @@ -300,7 +298,7 @@ def create_solubility_law_markers(self, mesh: festim.Mesh):
F_sievert = -sievert * test_function_sievert * mesh.dx

# build the formulation depending on the
for mat in self.materials:
for mat in self:
# make sure mat_ids is a list
mat_ids = mat.id
if not isinstance(mat.id, list):
Expand Down
2 changes: 1 addition & 1 deletion festim/meshing/mesh_1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def define_volume_markers(self, materials):

def define_measures(self, materials):
"""Creates the fenics.Measure objects for self.dx and self.ds"""
if materials.materials[0].borders is not None:
if materials[0].borders is not None:
materials.check_borders(self.size)
self.define_markers(materials)
super().define_measures()
2 changes: 1 addition & 1 deletion festim/temperature/temperature_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def define_variational_problem(self, materials, mesh, dt=None):
v_T = self.v_T

self.F = 0
for mat in materials.materials:
for mat in materials:
thermal_cond = mat.thermal_cond
if callable(thermal_cond): # if thermal_cond is a function
thermal_cond = thermal_cond(T)
Expand Down
11 changes: 11 additions & 0 deletions test/system/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,14 @@ def test_small_timesteps_final_time_bug():
my_model.run()

assert np.isclose(my_model.t, my_model.settings.final_time, atol=0.0)


def test_materials_setter():
"""
Checks that @materials.setter properly assigns F.Materials to F.Simulation.materials
see #694 for the details
"""
my_model = F.Simulation()
test_materials = F.Materials([])
my_model.materials = test_materials
assert my_model.materials is test_materials
10 changes: 10 additions & 0 deletions test/unit/test_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,13 @@ def test_error_wrong_solubility_law_string():
match="Acceptable values for solubility_law are 'henry' and 'sievert'",
):
F.Material(1, 1, 1, solubility_law="foo")


def test_equality_identity_two_empty_materials():
"""
Tests equality and two of two empty F.Materials objects, i.e. checks
that these F.Materials are equal but refer to different objects
"""
my_materials1 = F.Materials([])
my_materials2 = F.Materials([])
assert (my_materials1 == my_materials2) and (my_materials1 is not my_materials2)

0 comments on commit ff6daff

Please sign in to comment.