From 67277fd895dc94055435e6bda630cbb628987f47 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 26 Jan 2025 18:31:11 -0800 Subject: [PATCH 01/83] update rtol to make callable in problem --- src/festim/problem.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/festim/problem.py b/src/festim/problem.py index d1066ef79..fbb49d18f 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -121,7 +121,7 @@ def create_solver(self): ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) self.solver.atol = self.settings.atol - self.solver.rtol = self.settings.rtol + self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else 1e-10 self.solver.max_it = self.settings.max_iterations ksp = self.solver.krylov_solver @@ -151,6 +151,9 @@ def run(self): unit_scale=True, ) while self.t.value < self.settings.final_time: + # update rtol if it's callable + if callable(self.settings.rtol): + self.solver.rtol = self.settings.rtol(self.t.value) self.iterate() if self.show_progress_bar: self.progress_bar.refresh() # refresh progress bar to show 100% From be656dc5041ca156cf50d17a63be26bb8387c9e6 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 26 Jan 2025 18:36:35 -0800 Subject: [PATCH 02/83] adjust default rtol --- src/festim/problem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/problem.py b/src/festim/problem.py index fbb49d18f..c0143edb8 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -121,7 +121,7 @@ def create_solver(self): ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) self.solver.atol = self.settings.atol - self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else 1e-10 + self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol self.solver.max_it = self.settings.max_iterations ksp = self.solver.krylov_solver From 4e3874cca399ef3521b00243fc309088c483f03d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 26 Jan 2025 18:42:08 -0800 Subject: [PATCH 03/83] adjust default rtol --- src/festim/problem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/problem.py b/src/festim/problem.py index c0143edb8..3e9d28405 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -121,7 +121,7 @@ def create_solver(self): ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) self.solver.atol = self.settings.atol - self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol + self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol(0.0) self.solver.max_it = self.settings.max_iterations ksp = self.solver.krylov_solver From ffa890d36419ba37412f407fdaa35fface907243 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 10 Feb 2025 16:44:44 -0500 Subject: [PATCH 04/83] update atol to make callable in problem.py --- src/festim/problem.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/festim/problem.py b/src/festim/problem.py index 3e9d28405..25fe2e968 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -120,7 +120,7 @@ def create_solver(self): bcs=self.bc_forms, ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) - self.solver.atol = self.settings.atol + self.solver.atol = self.settings.atol if not callable(self.settings.rtol) else self.settings.rtol(0.0) self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol(0.0) self.solver.max_it = self.settings.max_iterations @@ -154,6 +154,9 @@ def run(self): # update rtol if it's callable if callable(self.settings.rtol): self.solver.rtol = self.settings.rtol(self.t.value) + # update rtol if it's callable + if callable(self.settings.atol): + self.solver.atol = self.settings.atol(self.t.value) self.iterate() if self.show_progress_bar: self.progress_bar.refresh() # refresh progress bar to show 100% From 9ac79df299171f12a57406755e441d8deb35c186 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 10 Feb 2025 16:58:19 -0500 Subject: [PATCH 05/83] fix bug --- src/festim/problem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/festim/problem.py b/src/festim/problem.py index 25fe2e968..4b5ee5b6f 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -120,7 +120,7 @@ def create_solver(self): bcs=self.bc_forms, ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) - self.solver.atol = self.settings.atol if not callable(self.settings.rtol) else self.settings.rtol(0.0) + self.solver.atol = self.settings.atol if not callable(self.settings.atol) else self.settings.atol(0.0) self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol(0.0) self.solver.max_it = self.settings.max_iterations @@ -154,7 +154,7 @@ def run(self): # update rtol if it's callable if callable(self.settings.rtol): self.solver.rtol = self.settings.rtol(self.t.value) - # update rtol if it's callable + # update atol if it's callable if callable(self.settings.atol): self.solver.atol = self.settings.atol(self.t.value) self.iterate() From d3fd8a756deae3067f17759ebe03125ba47ce746 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sat, 22 Feb 2025 12:10:08 -0500 Subject: [PATCH 06/83] add temp export --- src/festim/hydrogen_transport_problem.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 09e34f9a4..3033bbe74 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -366,6 +366,18 @@ def initialise_exports(self): a string, find species object in self.species""" for export in self.exports: + if isinstance(export, exports.VTXTemperatureExport): + temperature_field = self.temperature_fenics + self._vtxfiles.append( + dolfinx.io.VTXWriter( + temperature_field.function_space.mesh.comm, + export.filename, + [temperature_field], + engine="BP5", + ) + ) + continue + # if name of species is given then replace with species object if isinstance(export.field, list): for idx, field in enumerate(export.field): From eb5cdd426e7de3af313c322aecd4ac320c09c937 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 13:27:17 -0500 Subject: [PATCH 07/83] surface temperature export class --- src/festim/exports/__init__.py | 2 ++ src/festim/exports/surface_temperature.py | 42 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/festim/exports/surface_temperature.py diff --git a/src/festim/exports/__init__.py b/src/festim/exports/__init__.py index ca4eb00a7..741dc0988 100644 --- a/src/festim/exports/__init__.py +++ b/src/festim/exports/__init__.py @@ -9,12 +9,14 @@ "AverageSurface", "AverageVolume", "TotalVolume", + "SurfaceTemperature" ] from .average_surface import AverageSurface from .average_volume import AverageVolume from .surface_flux import SurfaceFlux from .surface_quantity import SurfaceQuantity +from .surface_temperature import SurfaceTemperature from .total_surface import TotalSurface from .total_volume import TotalVolume from .volume_quantity import VolumeQuantity diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py new file mode 100644 index 000000000..2b6b74baa --- /dev/null +++ b/src/festim/exports/surface_temperature.py @@ -0,0 +1,42 @@ +import ufl +from dolfinx import fem +from .surface_quantity import SurfaceQuantity + +class SurfaceTemperature(SurfaceQuantity): + """Computes the temperature on a given surface + + Args: + temperature_field (festim.Temperature): temperature field to be computed + surface (festim.SurfaceSubdomain1D): surface subdomain + filename (str, optional): name of the file to which the surface temperature is exported + + Attributes: + see `festim.SurfaceQuantity` + """ + + @property + def title(self): + return f"Temperature surface {self.surface.id}" + + def compute(self, ds): + """Computes the value of the temperature at the surface + + Args: + ds (ufl.Measure): surface measure of the model + """ + + # Obtain the temperature field + temperature_field = self.field.solution + + # Compute the average temperature on the surface + self.value = fem.assemble_scalar( + fem.form( + temperature_field * ds(self.surface.id) + ) + ) + self.data.append(self.value) + +# Example usage: +# Assuming you have a temperature field and a surface defined +# surface_temp = SurfaceTemperature(temperature_field, surface) +# surface_temp.compute(ds) \ No newline at end of file From 77da114428b1b2cd3fdb9b0fb90aef2a9a0df309 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 13:32:31 -0500 Subject: [PATCH 08/83] add surfacetemp to festim attribute --- src/festim/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/festim/__init__.py b/src/festim/__init__.py index be4cdd6ed..d6fc6939b 100644 --- a/src/festim/__init__.py +++ b/src/festim/__init__.py @@ -30,6 +30,7 @@ from .exports.minimum_volume import MinimumVolume from .exports.surface_flux import SurfaceFlux from .exports.surface_quantity import SurfaceQuantity +from .exports.surface_temperature import SurfaceTemperature from .exports.total_surface import TotalSurface from .exports.total_volume import TotalVolume from .exports.volume_quantity import VolumeQuantity From 9b20f0145c9356c0fef39979cfdfe9f35096e66d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 13:39:26 -0500 Subject: [PATCH 09/83] update surfacetemperature class --- src/festim/exports/surface_temperature.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 2b6b74baa..ad78b4643 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -1,8 +1,10 @@ import ufl from dolfinx import fem from .surface_quantity import SurfaceQuantity +import csv +import festim as F -class SurfaceTemperature(SurfaceQuantity): +class SurfaceTemperature(F.HydrogenTransportProblem): """Computes the temperature on a given surface Args: @@ -26,7 +28,7 @@ def compute(self, ds): """ # Obtain the temperature field - temperature_field = self.field.solution + temperature_field = self.temperature_fenics # Compute the average temperature on the surface self.value = fem.assemble_scalar( From aa813e5fbd673039f1cc6d5e6b63ea8f351ab4f2 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 13:41:41 -0500 Subject: [PATCH 10/83] circular import --- src/festim/exports/surface_temperature.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index ad78b4643..497deb140 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -1,10 +1,9 @@ import ufl from dolfinx import fem -from .surface_quantity import SurfaceQuantity import csv -import festim as F +from src.festim.hydrogen_transport_problem import HydrogenTransportProblem -class SurfaceTemperature(F.HydrogenTransportProblem): +class SurfaceTemperature(HydrogenTransportProblem): """Computes the temperature on a given surface Args: From b9f700a8771bb31280473551be6e2568fb6b36a9 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 13:42:45 -0500 Subject: [PATCH 11/83] fix circular import --- src/festim/exports/surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 497deb140..a22c014a6 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -1,7 +1,7 @@ import ufl from dolfinx import fem import csv -from src.festim.hydrogen_transport_problem import HydrogenTransportProblem +from festim.hydrogen_transport_problem import HydrogenTransportProblem class SurfaceTemperature(HydrogenTransportProblem): """Computes the temperature on a given surface From d4a5e9fa07126d89529435711b67144b41a070da Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 14:50:33 -0500 Subject: [PATCH 12/83] fix surface temperature export --- src/festim/exports/surface_temperature.py | 81 ++++++++++++++++++----- src/festim/hydrogen_transport_problem.py | 8 +++ 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index a22c014a6..e32be787c 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -1,43 +1,88 @@ -import ufl -from dolfinx import fem import csv -from festim.hydrogen_transport_problem import HydrogenTransportProblem +from dolfinx import fem +import ufl +import festim as F -class SurfaceTemperature(HydrogenTransportProblem): - """Computes the temperature on a given surface +class SurfaceTemperature: + """Exports the temperature on a given surface. Args: - temperature_field (festim.Temperature): temperature field to be computed - surface (festim.SurfaceSubdomain1D): surface subdomain + temperature_field (fem.Constant or fem.Function): the temperature field to be computed + surface (int or festim.SurfaceSubdomain): the surface subdomain filename (str, optional): name of the file to which the surface temperature is exported Attributes: - see `festim.SurfaceQuantity` + temperature_field (fem.Constant or fem.Function): the temperature field + surface (int or festim.SurfaceSubdomain): the surface subdomain + filename (str): name of the file to which the surface temperature is exported + t (list): list of time values + data (list): list of temperature values on the surface """ + def __init__(self, temperature_field, surface, filename: str = None) -> None: + self.temperature_field = temperature_field + self.surface = surface + self.filename = filename + + self.t = [] + self.data = [] + self._first_time_export = True + + @property + def filename(self): + return self._filename + + @filename.setter + def filename(self, value): + if value is None: + self._filename = None + elif not isinstance(value, str): + raise TypeError("filename must be of type str") + elif not value.endswith(".csv") and not value.endswith(".txt"): + raise ValueError("filename must end with .csv or .txt") + self._filename = value + + @property + def surface(self): + return self._surface + + @surface.setter + def surface(self, value): + if not isinstance(value, (int, F.SurfaceSubdomain)) or isinstance(value, bool): + raise TypeError("surface should be an int or F.SurfaceSubdomain") + self._surface = value + @property def title(self): return f"Temperature surface {self.surface.id}" def compute(self, ds): - """Computes the value of the temperature at the surface + """Computes the average temperature on the surface. Args: ds (ufl.Measure): surface measure of the model """ - - # Obtain the temperature field - temperature_field = self.temperature_fenics - # Compute the average temperature on the surface self.value = fem.assemble_scalar( fem.form( - temperature_field * ds(self.surface.id) + self.temperature_field * ds(self.surface.id) ) ) self.data.append(self.value) -# Example usage: -# Assuming you have a temperature field and a surface defined -# surface_temp = SurfaceTemperature(temperature_field, surface) -# surface_temp.compute(ds) \ No newline at end of file + def write(self, t): + """Writes the time and temperature value to the file. + + Args: + t (float): current time value + """ + if self.filename is not None: + if self._first_time_export: + header = ["t(s)", f"{self.title}"] + with open(self.filename, mode="w+", newline="") as file: + writer = csv.writer(file) + writer.writerow(header) + self._first_time_export = False + with open(self.filename, mode="a", newline="") as file: + writer = csv.writer(file) + writer.writerow([t, self.value]) \ No newline at end of file diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 3033bbe74..86bf3c78e 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -377,6 +377,14 @@ def initialise_exports(self): ) ) continue + + if isinstance(export, exports.SurfaceTemperature): + export.temperature_field = self.temperature_fenics # Assign the temperature field + export.compute(self.ds) # Compute the temperature on the surface + export.t.append(float(self.t)) # Append the current time + if export.filename is not None: + export.write(t=float(self.t)) # Write to file if filename is provided + continue # if name of species is given then replace with species object if isinstance(export.field, list): From 773b29179b2011047f62e8ab55cb0e7754843546 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 15:45:01 -0500 Subject: [PATCH 13/83] add post processing surfacetemp update --- src/festim/hydrogen_transport_problem.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 86bf3c78e..f3dca0070 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -379,11 +379,6 @@ def initialise_exports(self): continue if isinstance(export, exports.SurfaceTemperature): - export.temperature_field = self.temperature_fenics # Assign the temperature field - export.compute(self.ds) # Compute the temperature on the surface - export.t.append(float(self.t)) # Append the current time - if export.filename is not None: - export.write(t=float(self.t)) # Write to file if filename is provided continue # if name of species is given then replace with species object @@ -432,8 +427,11 @@ def initialise_exports(self): export.D = D export.D_expr = D_expr + elif isinstance(export, exports.SurfaceTemperature): + export.temperature_field = self.temperature_fenics + # reset the data and time for SurfaceQuantity and VolumeQuantity - if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity)): + if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity, exports.SurfaceTemperature)): export.t = [] export.data = [] @@ -823,6 +821,17 @@ def post_processing(self): # if filename given write export data to file if export.filename is not None: export.write(t=float(self.t)) + + elif isinstance(export, exports.SurfaceTemperature): + export.compute(self.ds) # compute surface temp + + export.t.append(float(self.t)) # update export time + export.data.append(export.value) # update export data + + # if filename given write export data to file + if export.filename is not None: + export.write(t=float(self.t)) + elif isinstance(export, exports.VolumeQuantity): if isinstance(export, (exports.TotalVolume, exports.AverageVolume)): export.compute(self.dx) From b3f44883717371243ad0888ed3169d43886d6246 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 17:50:35 -0500 Subject: [PATCH 14/83] update compute method for surface temp --- src/festim/exports/surface_temperature.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index e32be787c..98058a847 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -62,12 +62,14 @@ def compute(self, ds): Args: ds (ufl.Measure): surface measure of the model """ - # Compute the average temperature on the surface - self.value = fem.assemble_scalar( - fem.form( - self.temperature_field * ds(self.surface.id) - ) - ) + temperature_field = self.temperature_field + + surface_integral = fem.assemble_scalar(fem.form(temperature_field * ds(self.surface.id))) # integral over surface + + surface_area = fem.assemble_scalar(fem.form(1 * ds(self.surface.id))) + + self.value = surface_integral / surface_area # avg temp + self.data.append(self.value) def write(self, t): From 3e70f370f98aa4aa38e91c3271b00b6119a0f228 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 21:26:59 -0500 Subject: [PATCH 15/83] fix double count surface temp --- src/festim/hydrogen_transport_problem.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index f3dca0070..f4b51e794 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -789,6 +789,8 @@ def update_time_dependent_values(self): if source.temperature_dependent: source.update(t=t) + surface_temp_processed = False + def post_processing(self): """Post processes the model""" @@ -803,6 +805,7 @@ def post_processing(self): export.D.interpolate(export.D_expr) species_not_updated.remove(export.field) + last_time = None for export in self.exports: # TODO if export type derived quantity if isinstance(export, exports.SurfaceQuantity): @@ -823,14 +826,16 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.SurfaceTemperature): - export.compute(self.ds) # compute surface temp + if self.t != last_time: + export.compute(self.ds) # compute surface temp - export.t.append(float(self.t)) # update export time - export.data.append(export.value) # update export data + export.t.append(float(self.t)) # update export time - # if filename given write export data to file - if export.filename is not None: - export.write(t=float(self.t)) + # if filename given write export data to file + if export.filename is not None: + export.write(t=float(self.t)) + + last_time = self.t elif isinstance(export, exports.VolumeQuantity): if isinstance(export, (exports.TotalVolume, exports.AverageVolume)): From d1b71deed2d0998159b99591951493bffa1f5ca8 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 23 Feb 2025 23:16:23 -0500 Subject: [PATCH 16/83] typos --- src/festim/hydrogen_transport_problem.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index f4b51e794..120bfb992 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -805,7 +805,6 @@ def post_processing(self): export.D.interpolate(export.D_expr) species_not_updated.remove(export.field) - last_time = None for export in self.exports: # TODO if export type derived quantity if isinstance(export, exports.SurfaceQuantity): @@ -826,16 +825,14 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.SurfaceTemperature): - if self.t != last_time: - export.compute(self.ds) # compute surface temp + export.compute(self.ds) # compute surface temp - export.t.append(float(self.t)) # update export time + export.t.append(float(self.t)) # update export time - # if filename given write export data to file - if export.filename is not None: - export.write(t=float(self.t)) + # if filename given write export data to file + if export.filename is not None: + export.write(t=float(self.t)) - last_time = self.t elif isinstance(export, exports.VolumeQuantity): if isinstance(export, (exports.TotalVolume, exports.AverageVolume)): From 6a52a39d2747577b426a66eff797dbf400b33e7e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 24 Feb 2025 13:35:33 -0500 Subject: [PATCH 17/83] add surface temperature export class --- src/festim/hydrogen_transport_problem.py | 11 ----------- src/festim/problem.py | 10 ++-------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 1d9726817..3742bf2ab 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -369,17 +369,6 @@ def initialise_exports(self): a string, find species object in self.species""" for export in self.exports: - if isinstance(export, exports.VTXTemperatureExport): - temperature_field = self.temperature_fenics - self._vtxfiles.append( - dolfinx.io.VTXWriter( - temperature_field.function_space.mesh.comm, - export.filename, - [temperature_field], - engine="BP5", - ) - ) - continue if isinstance(export, exports.SurfaceTemperature): continue diff --git a/src/festim/problem.py b/src/festim/problem.py index 4b5ee5b6f..d1066ef79 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -120,8 +120,8 @@ def create_solver(self): bcs=self.bc_forms, ) self.solver = NewtonSolver(MPI.COMM_WORLD, problem) - self.solver.atol = self.settings.atol if not callable(self.settings.atol) else self.settings.atol(0.0) - self.solver.rtol = self.settings.rtol if not callable(self.settings.rtol) else self.settings.rtol(0.0) + self.solver.atol = self.settings.atol + self.solver.rtol = self.settings.rtol self.solver.max_it = self.settings.max_iterations ksp = self.solver.krylov_solver @@ -151,12 +151,6 @@ def run(self): unit_scale=True, ) while self.t.value < self.settings.final_time: - # update rtol if it's callable - if callable(self.settings.rtol): - self.solver.rtol = self.settings.rtol(self.t.value) - # update atol if it's callable - if callable(self.settings.atol): - self.solver.atol = self.settings.atol(self.t.value) self.iterate() if self.show_progress_bar: self.progress_bar.refresh() # refresh progress bar to show 100% From 4e5e68b05ac83b705c6977d4ce5144b92241dcdf Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 16:15:04 -0500 Subject: [PATCH 18/83] add surface temp to derived quantities test --- test/test_derived_quantities.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_derived_quantities.py b/test/test_derived_quantities.py index edfd6ae37..6e9fedfe0 100644 --- a/test/test_derived_quantities.py +++ b/test/test_derived_quantities.py @@ -10,6 +10,7 @@ surf_2 = F.SurfaceSubdomain(id=2) vol_1 = F.VolumeSubdomain(id=1, material="test") vol_2 = F.VolumeSubdomain(id=2, material="test") +temp = 400 results = "test.csv" surface_flux = F.SurfaceFlux(field=mobile_H, surface=surf_1, filename=results) @@ -24,6 +25,7 @@ avg_vol = F.AverageVolume(mobile_H, volume=vol_2, filename=results) surf_quant = F.SurfaceQuantity(mobile_H, surface=surf_1, filename=results) vol_quant = F.VolumeQuantity(mobile_H, volume=vol_1, filename=results) +surf_temp = F.SurfaceTemperature(temperature_field=temp, surface=surf_1, filename=results) @pytest.mark.parametrize( @@ -39,6 +41,7 @@ (max_surface, "Maximum H surface 2"), (avg_surface, "Average D surface 1"), (avg_vol, "Average H volume 2"), + (surf_temp, "Temperature surface 1") ], ) def test_title(quantity, expected_title, tmp_path): From 9a9106d9a8140de72b01d4eb0597cc6b5ca2829d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 16:45:01 -0500 Subject: [PATCH 19/83] add better doc, add surface temp test --- src/festim/exports/surface_temperature.py | 6 +-- test/test_surface_temperature.py | 53 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 test/test_surface_temperature.py diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 98058a847..6ade1458a 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -4,19 +4,19 @@ import festim as F class SurfaceTemperature: - """Exports the temperature on a given surface. + """Exports the average temperature on a given surface. Args: temperature_field (fem.Constant or fem.Function): the temperature field to be computed surface (int or festim.SurfaceSubdomain): the surface subdomain - filename (str, optional): name of the file to which the surface temperature is exported + filename (str, optional): name of the file to which the average surface temperature is exported Attributes: temperature_field (fem.Constant or fem.Function): the temperature field surface (int or festim.SurfaceSubdomain): the surface subdomain filename (str): name of the file to which the surface temperature is exported t (list): list of time values - data (list): list of temperature values on the surface + data (list): list of average temperature values on the surface """ def __init__(self, temperature_field, surface, filename: str = None) -> None: diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py new file mode 100644 index 000000000..30db1343b --- /dev/null +++ b/test/test_surface_temperature.py @@ -0,0 +1,53 @@ +import numpy as np +import ufl +from dolfinx import fem + +import festim as F + +@pytest.mark.parametrize( + "T_function, expected_values", + [ + (3, 3), + (lambda t: t, 2.5), + ], +) + +def test_average_surface_compute_1D(T_function, expected_values): + """Test that the average surface temperature export computes the correct value""" + + # BUILD + # BUILD + L = 6.0 + D = 1.5 + my_mesh = F.Mesh1D(np.linspace(0, L, 10000)) + dummy_surface = F.SurfaceSubdomain1D(id=1, x=6) + dummy_volume = F.VolumeSubdomain1D( + id=1, borders=[0, L], material=F.Material(D_0=1, E_D=1, name="dummy") + ) + facet_meshtags, temp = my_mesh.define_meshtags( + surface_subdomains=[dummy_surface], volume_subdomains=[dummy_volume] + ) + + ds = ufl.Measure("ds", domain=my_mesh.mesh, subdomain_data=facet_meshtags) + + my_model = F.HydrogenTransportProblem( + mesh=my_mesh, + ) + my_model.t = fem.Constant(my_model.mesh.mesh, 0.0) + dt = fem.Constant(my_mesh.mesh, 1.0) + + my_model.temperature = T_function + + my_model.define_temperature() + + # RUN + for i in range(3): + my_model.t.value += dt.value + my_model.update_time_dependent_values() + + my_export.compute(ds) + my_export = F.SurfaceTemperature(temperature_field=T_function, surface=dummy_surface) + + # TEST + for i in range(0,2): + assert np.isclose(my_export.value, expected_values[i]) \ No newline at end of file From f03ae7d0a3df8562f12854405fd9dcc10a8fa3fa Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:19:32 -0500 Subject: [PATCH 20/83] add pytest to import --- test/test_surface_temperature.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 30db1343b..bd05d30be 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -1,6 +1,7 @@ import numpy as np import ufl from dolfinx import fem +import pytest import festim as F From aefcdaa78f3a7c19a0ac55f7495f45d350d6b8ef Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:25:50 -0500 Subject: [PATCH 21/83] add my_export quantity --- test/test_surface_temperature.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index bd05d30be..bd72b02b5 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -13,10 +13,9 @@ ], ) -def test_average_surface_compute_1D(T_function, expected_values): +def test_average_surface_temperature_compute_1D(T_function, expected_values): """Test that the average surface temperature export computes the correct value""" - # BUILD # BUILD L = 6.0 D = 1.5 @@ -46,6 +45,7 @@ def test_average_surface_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() + my_export = F.SurfaceTemperature(temperature_field=my_model.temperature, surface=dummy_surface) my_export.compute(ds) my_export = F.SurfaceTemperature(temperature_field=T_function, surface=dummy_surface) From 806502aeae87f167662a334165a296a7c720cd28 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:34:17 -0500 Subject: [PATCH 22/83] delete extra line --- test/test_surface_temperature.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index bd72b02b5..172619bf5 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -47,8 +47,7 @@ def test_average_surface_temperature_compute_1D(T_function, expected_values): my_export = F.SurfaceTemperature(temperature_field=my_model.temperature, surface=dummy_surface) my_export.compute(ds) - my_export = F.SurfaceTemperature(temperature_field=T_function, surface=dummy_surface) # TEST for i in range(0,2): - assert np.isclose(my_export.value, expected_values[i]) \ No newline at end of file + assert np.isclose(my_export, expected_values[i]) \ No newline at end of file From 91f1d5bc13eadd09f131261ee4ae7f8206ecb7f1 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:38:11 -0500 Subject: [PATCH 23/83] fix exported value comparison --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 172619bf5..689e10172 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -50,4 +50,4 @@ def test_average_surface_temperature_compute_1D(T_function, expected_values): # TEST for i in range(0,2): - assert np.isclose(my_export, expected_values[i]) \ No newline at end of file + assert np.isclose(my_export, expected_values) \ No newline at end of file From 1e5e2b070a94ed7c3d09679a8d2de00d2ea8c16c Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:48:02 -0500 Subject: [PATCH 24/83] add temp field value to surface temp --- src/festim/exports/surface_temperature.py | 4 ++++ test/test_surface_temperature.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 6ade1458a..eedc98bfd 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -52,6 +52,10 @@ def surface(self, value): raise TypeError("surface should be an int or F.SurfaceSubdomain") self._surface = value + @property + def temperature_field(self): + return self._temperature_field + @property def title(self): return f"Temperature surface {self.surface.id}" diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 689e10172..220b21486 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -50,4 +50,4 @@ def test_average_surface_temperature_compute_1D(T_function, expected_values): # TEST for i in range(0,2): - assert np.isclose(my_export, expected_values) \ No newline at end of file + assert np.isclose(my_export.value, expected_values) \ No newline at end of file From 7b0ea6dc0826f61ca0e9a6c9f17b5016908c4970 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 17:58:08 -0500 Subject: [PATCH 25/83] add temp field setter --- src/festim/exports/surface_temperature.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index eedc98bfd..b336edeeb 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -55,6 +55,18 @@ def surface(self, value): @property def temperature_field(self): return self._temperature_field + + @temperature_field.setter + def temperature_field(self, value): + # check that temperature field is fem.Constant, fem.Function, or fem.Expression + if not isinstance(value, (fem.Constant, str)): + raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + elif not isinstance(value, (fem.Function, str)): + raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + elif not isinstance(value, (fem.Expression, str)): + raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + + self._field = value @property def title(self): From 528492c10b129746a0d0eeb729bf8e5ca9767c4d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 18:01:48 -0500 Subject: [PATCH 26/83] initialise exports --- test/test_surface_temperature.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 220b21486..4f2232b5b 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -39,6 +39,7 @@ def test_average_surface_temperature_compute_1D(T_function, expected_values): my_model.temperature = T_function my_model.define_temperature() + my_model.initialise_exports() # RUN for i in range(3): From 1971774e7458583631c440e0cc8b27001c8cd7f7 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 18:06:43 -0500 Subject: [PATCH 27/83] remove surface temp from derived quantities --- test/test_derived_quantities.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_derived_quantities.py b/test/test_derived_quantities.py index 6e9fedfe0..edfd6ae37 100644 --- a/test/test_derived_quantities.py +++ b/test/test_derived_quantities.py @@ -10,7 +10,6 @@ surf_2 = F.SurfaceSubdomain(id=2) vol_1 = F.VolumeSubdomain(id=1, material="test") vol_2 = F.VolumeSubdomain(id=2, material="test") -temp = 400 results = "test.csv" surface_flux = F.SurfaceFlux(field=mobile_H, surface=surf_1, filename=results) @@ -25,7 +24,6 @@ avg_vol = F.AverageVolume(mobile_H, volume=vol_2, filename=results) surf_quant = F.SurfaceQuantity(mobile_H, surface=surf_1, filename=results) vol_quant = F.VolumeQuantity(mobile_H, volume=vol_1, filename=results) -surf_temp = F.SurfaceTemperature(temperature_field=temp, surface=surf_1, filename=results) @pytest.mark.parametrize( @@ -41,7 +39,6 @@ (max_surface, "Maximum H surface 2"), (avg_surface, "Average D surface 1"), (avg_vol, "Average H volume 2"), - (surf_temp, "Temperature surface 1") ], ) def test_title(quantity, expected_title, tmp_path): From 7d687de4b764311f13af8c7b869ad62239558345 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:00:59 -0500 Subject: [PATCH 28/83] change func name, add float and int to temp types --- src/festim/exports/surface_temperature.py | 12 ++++++++---- test/test_surface_temperature.py | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index b336edeeb..1541343f1 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -58,13 +58,17 @@ def temperature_field(self): @temperature_field.setter def temperature_field(self, value): - # check that temperature field is fem.Constant, fem.Function, or fem.Expression + # check that temperature field is float, int, fem.Constant, fem.Function, or fem.Expression if not isinstance(value, (fem.Constant, str)): - raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") elif not isinstance(value, (fem.Function, str)): - raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") elif not isinstance(value, (fem.Expression, str)): - raise TypeError("field must be of type fem.Constant, fem.Function, or fem.Expression") + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") + elif not isinstance(value, int): + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") + elif not isinstance(value, float): + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") self._field = value diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 4f2232b5b..632671560 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -13,7 +13,7 @@ ], ) -def test_average_surface_temperature_compute_1D(T_function, expected_values): +def test_surface_temperature_compute_1D(T_function, expected_values): """Test that the average surface temperature export computes the correct value""" # BUILD From 37d59f60b4188ac0f8412e9992d39864e191e99e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:05:26 -0500 Subject: [PATCH 29/83] test if test or definition problem --- test/test_surface_temperature.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 632671560..d19f7fbce 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -5,13 +5,13 @@ import festim as F -@pytest.mark.parametrize( - "T_function, expected_values", - [ - (3, 3), - (lambda t: t, 2.5), - ], -) +# @pytest.mark.parametrize( +# "T_function, expected_values", +# [ +# (3, 3), +# (lambda t: t, 2.5), +# ], +# ) def test_surface_temperature_compute_1D(T_function, expected_values): """Test that the average surface temperature export computes the correct value""" @@ -46,9 +46,10 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature(temperature_field=my_model.temperature, surface=dummy_surface) + my_export = F.SurfaceTemperature(temperature_field=3, surface=dummy_surface) my_export.compute(ds) # TEST for i in range(0,2): - assert np.isclose(my_export.value, expected_values) \ No newline at end of file + assert np.isclose(my_export.value, 3) + # assert np.isclose(my_export.value, expected_values) \ No newline at end of file From 98167a06bad0f81ebffb3d1eb2d91540188b15e5 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:11:41 -0500 Subject: [PATCH 30/83] fix test --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index d19f7fbce..554c21894 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -36,7 +36,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t = fem.Constant(my_model.mesh.mesh, 0.0) dt = fem.Constant(my_mesh.mesh, 1.0) - my_model.temperature = T_function + my_model.temperature = 3 my_model.define_temperature() my_model.initialise_exports() From a044ecfc09753a8cb7aa54902af336c68fb32621 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:15:05 -0500 Subject: [PATCH 31/83] fix test --- test/test_surface_temperature.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 554c21894..7ea397e82 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -13,12 +13,11 @@ # ], # ) -def test_surface_temperature_compute_1D(T_function, expected_values): +def test_surface_temperature_compute_1D(): """Test that the average surface temperature export computes the correct value""" # BUILD L = 6.0 - D = 1.5 my_mesh = F.Mesh1D(np.linspace(0, L, 10000)) dummy_surface = F.SurfaceSubdomain1D(id=1, x=6) dummy_volume = F.VolumeSubdomain1D( From eb486c3bd8cb2a5ce7d224f18c0b7f338f25a494 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:39:29 -0500 Subject: [PATCH 32/83] fix temp field setter --- src/festim/exports/surface_temperature.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 1541343f1..93cedce92 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -60,15 +60,11 @@ def temperature_field(self): def temperature_field(self, value): # check that temperature field is float, int, fem.Constant, fem.Function, or fem.Expression if not isinstance(value, (fem.Constant, str)): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - elif not isinstance(value, (fem.Function, str)): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - elif not isinstance(value, (fem.Expression, str)): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - elif not isinstance(value, int): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - elif not isinstance(value, float): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") + if not isinstance(value, (fem.Function, str)): + if not isinstance(value, (fem.Expression, str)): + if not isinstance(value, int): + if not isinstance(value, float): + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") self._field = value From e0b182029f94a1fd76460dc2dacc5464456e2345 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:44:17 -0500 Subject: [PATCH 33/83] fix setter --- test/test_surface_temperature.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 7ea397e82..54de6ddb0 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -31,12 +31,11 @@ def test_surface_temperature_compute_1D(): my_model = F.HydrogenTransportProblem( mesh=my_mesh, + temperature=3, ) my_model.t = fem.Constant(my_model.mesh.mesh, 0.0) dt = fem.Constant(my_mesh.mesh, 1.0) - my_model.temperature = 3 - my_model.define_temperature() my_model.initialise_exports() @@ -51,4 +50,4 @@ def test_surface_temperature_compute_1D(): # TEST for i in range(0,2): assert np.isclose(my_export.value, 3) - # assert np.isclose(my_export.value, expected_values) \ No newline at end of file + # assert np.isclose(my_export.value, expected_values) From 9e2937e4dcb33aa3a35c942484c94d3cbd6dba75 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:48:47 -0500 Subject: [PATCH 34/83] simplify setter --- src/festim/exports/surface_temperature.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 93cedce92..3258ea87d 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -59,14 +59,10 @@ def temperature_field(self): @temperature_field.setter def temperature_field(self, value): # check that temperature field is float, int, fem.Constant, fem.Function, or fem.Expression - if not isinstance(value, (fem.Constant, str)): - if not isinstance(value, (fem.Function, str)): - if not isinstance(value, (fem.Expression, str)): - if not isinstance(value, int): - if not isinstance(value, float): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - - self._field = value + if not isinstance(value, (fem.Constant, fem.Function, fem.Expression, int, float, str)): + raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") + + self._temperature_field = value @property def title(self): From 38a6ae18582547e7706b28066e92a09f11a8abd4 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:50:38 -0500 Subject: [PATCH 35/83] testing export.value --- test/test_surface_temperature.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 54de6ddb0..b305a7961 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -46,6 +46,7 @@ def test_surface_temperature_compute_1D(): my_export = F.SurfaceTemperature(temperature_field=3, surface=dummy_surface) my_export.compute(ds) + print(my_export.value) # TEST for i in range(0,2): From 7e8d843e883da8f3687c9be3738fa8c5096f5a9e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 22:56:14 -0500 Subject: [PATCH 36/83] update test --- test/test_surface_temperature.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index b305a7961..f5f555a1f 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -5,15 +5,15 @@ import festim as F -# @pytest.mark.parametrize( -# "T_function, expected_values", -# [ -# (3, 3), -# (lambda t: t, 2.5), -# ], -# ) - -def test_surface_temperature_compute_1D(): +@pytest.mark.parametrize( + "T_function, expected_values", + [ + (3, 3), + (lambda t: t, 2.5), + ], +) + +def test_surface_temperature_compute_1D(T_function, expected_values): """Test that the average surface temperature export computes the correct value""" # BUILD @@ -31,7 +31,7 @@ def test_surface_temperature_compute_1D(): my_model = F.HydrogenTransportProblem( mesh=my_mesh, - temperature=3, + temperature=T_function, ) my_model.t = fem.Constant(my_model.mesh.mesh, 0.0) dt = fem.Constant(my_mesh.mesh, 1.0) @@ -44,11 +44,10 @@ def test_surface_temperature_compute_1D(): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature(temperature_field=3, surface=dummy_surface) + my_export = F.SurfaceTemperature(temperature_field=T_function, surface=dummy_surface) my_export.compute(ds) - print(my_export.value) # TEST for i in range(0,2): - assert np.isclose(my_export.value, 3) - # assert np.isclose(my_export.value, expected_values) + # assert np.isclose(my_export.value, 3) + assert np.isclose(my_export.value, expected_values) From f414bd1435ba6e329b19c6da501ec891ac8d3cc0 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:10:38 -0500 Subject: [PATCH 37/83] update test --- test/test_surface_temperature.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index f5f555a1f..cbdd4a710 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -48,6 +48,4 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_export.compute(ds) # TEST - for i in range(0,2): - # assert np.isclose(my_export.value, 3) - assert np.isclose(my_export.value, expected_values) + assert np.isclose(my_export.value, expected_values) From 66ad7883356294796dfd856a024f2037c21016b5 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:14:32 -0500 Subject: [PATCH 38/83] uodate test --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index cbdd4a710..faa7df33a 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -44,7 +44,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature(temperature_field=T_function, surface=dummy_surface) + my_export = F.SurfaceTemperature(temperature_field=my_model.temperature, surface=dummy_surface) my_export.compute(ds) # TEST From 60eb9e73083d18cf4d9946b2b1ea7a7db67a0739 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:19:44 -0500 Subject: [PATCH 39/83] update test --- test/test_surface_temperature.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index faa7df33a..20d4c5dfc 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -44,8 +44,9 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature(temperature_field=my_model.temperature, surface=dummy_surface) + my_export = F.SurfaceTemperature(temperature_field=my_model.temperature_fenics, surface=dummy_surface) my_export.compute(ds) + print(my_export.value) # TEST assert np.isclose(my_export.value, expected_values) From c1bac956a1a710b4c31bab93a176f35d99c65ee1 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:23:34 -0500 Subject: [PATCH 40/83] update test --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 20d4c5dfc..a6a9f82aa 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -9,7 +9,7 @@ "T_function, expected_values", [ (3, 3), - (lambda t: t, 2.5), + (lambda t: t, 3.0), ], ) From 03148d13cafc94859e6338e7410f0b1595a9c63e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:24:22 -0500 Subject: [PATCH 41/83] add test --- test/test_surface_temperature.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index a6a9f82aa..04c75e475 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -10,6 +10,7 @@ [ (3, 3), (lambda t: t, 3.0), + (lambda x, t: 1.0 + x[0] + t, 6.0), ], ) From c955d9fb1081975f9f7df169eb4bfe8b164d68d6 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:29:03 -0500 Subject: [PATCH 42/83] black formatted --- test/test_surface_temperature.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 04c75e475..31d0f5da3 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -5,17 +5,17 @@ import festim as F + @pytest.mark.parametrize( "T_function, expected_values", [ (3, 3), (lambda t: t, 3.0), - (lambda x, t: 1.0 + x[0] + t, 6.0), + (lambda x, t: 1.0 + x[0] + t, 10.0), ], ) - def test_surface_temperature_compute_1D(T_function, expected_values): - """Test that the average surface temperature export computes the correct value""" + """Test that the average surface temperature export computes the correct value.""" # BUILD L = 6.0 @@ -45,9 +45,10 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature(temperature_field=my_model.temperature_fenics, surface=dummy_surface) + my_export = F.SurfaceTemperature( + temperature_field=my_model.temperature_fenics, surface=dummy_surface + ) my_export.compute(ds) - print(my_export.value) # TEST assert np.isclose(my_export.value, expected_values) From 8c2f0bf04ba541230f125b0b25bffbf40ec2edca Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:32:52 -0500 Subject: [PATCH 43/83] add test for title --- test/test_surface_temperature.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 31d0f5da3..6dc24762e 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -2,6 +2,7 @@ import ufl from dolfinx import fem import pytest +import os import festim as F @@ -52,3 +53,18 @@ def test_surface_temperature_compute_1D(T_function, expected_values): # TEST assert np.isclose(my_export.value, expected_values) + + +def test_title(tmp_path): + surf_1 = F.SurfaceSubdomain(id=1) + results = "test.csv" + temp = 400 + surface_temp = F.SurfaceTemperature(temperature_field=temp,surface=surf_1,filename=results) + + my_model = F.HydrogenTransportProblem( + temperature=temp, + ) + surface_temp.filename = os.path.join(tmp_path, "test.csv") + surface_temp.value = 1 + + assert surface_temp.title == "Temperature surface 1" From f6b5ff6f9617a2edf1cfdf74827f660dad1fa316 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:33:14 -0500 Subject: [PATCH 44/83] black formatted --- test/test_surface_temperature.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 6dc24762e..036aa4c46 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -59,11 +59,13 @@ def test_title(tmp_path): surf_1 = F.SurfaceSubdomain(id=1) results = "test.csv" temp = 400 - surface_temp = F.SurfaceTemperature(temperature_field=temp,surface=surf_1,filename=results) + surface_temp = F.SurfaceTemperature( + temperature_field=temp, surface=surf_1, filename=results + ) my_model = F.HydrogenTransportProblem( - temperature=temp, - ) + temperature=temp, + ) surface_temp.filename = os.path.join(tmp_path, "test.csv") surface_temp.value = 1 From 339a94ac49aec0855ff8bc387583d1905c373200 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:49:16 -0500 Subject: [PATCH 45/83] additional tests --- test/test_surface_temperature.py | 137 +++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 036aa4c46..4c689a8ac 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -70,3 +70,140 @@ def test_title(tmp_path): surface_temp.value = 1 assert surface_temp.title == "Temperature surface 1" + +@pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) +def test_title_generation(tmp_path, value): + """Test that the title is made to be written to the header in a csv or txt file""" + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + + my_export = F.SurfaceTemperature( + filename=os.path.join(tmp_path, f"{value}"), + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=35, x=1), + ) + my_export.value = 2.0 + my_export.write(0) + title = np.genfromtxt(my_export.filename, delimiter=",", max_rows=1, dtype=str) + + expected_title = "Temperature surface 35" + + assert title[1] == expected_title + + +def test_write_overwrite(tmp_path): + """Test that the write method overwrites the file if it already exists""" + filename = os.path.join(tmp_path, "my_export.csv") + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + + my_export = F.SurfaceTemperature( + filename=filename, + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=35, x=1), + ) + my_export.value = 2.0 + my_export.write(0) + my_export.write(1) + + my_export2 = F.SurfaceTemperature( + filename=filename, + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=1, x=1), + ) + my_export2.value = 3.0 + my_export2.write(1) + my_export2.write(2) + my_export2.write(3) + + data = np.genfromtxt(filename, delimiter=",", names=True) + file_length = data.size + expected_length = 3 + + assert file_length == expected_length + + +def test_filename_setter_raises_TypeError(): + """Test that a TypeError is raised when the filename is not a string""" + + with pytest.raises(TypeError, match="filename must be of type str"): + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + + F.SurfaceTemperature( + filename=1, + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=1, x=1), + ) + +def test_filename_setter_raises_ValueError(tmp_path): + """Test that a ValueError is raised when the filename does not end with .csv or .txt""" + + with pytest.raises(ValueError): + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + + F.SurfaceTemperature( + filename=os.path.join(tmp_path, "my_export.xdmf"), + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=1, x=1), + ) + +def test_field_setter_raises_TypeError(): + """Test that a TypeError is raised when the field is not an int, float, fem.Constant, fem.Expression, or fem.Function""" + + with pytest.raises(TypeError): + + F.SurfaceTemperature( + field=1, + surface=F.SurfaceSubdomain1D(id=1, x=1), + ) + + +@pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) +def test_writer(tmp_path, value): + """Test that the writes values at each timestep to either a csv or txt file""" + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + + my_export = F.SurfaceTemperature( + filename=os.path.join(tmp_path, f"{value}"), + field=my_model.temperature_fenics, + surface=F.SurfaceSubdomain1D(id=1, x=0), + ) + my_export.value = 2.0 + + for i in range(10): + my_export.write(i) + file_length = len(np.genfromtxt(my_export.filename, delimiter=",")) + + expected_length = i + 2 + + assert file_length == expected_length + + +def test_surface_setter_raises_TypeError(): + """Test that a TypeError is raised when the surface is not a + F.SurfaceSubdomain""" + + with pytest.raises( + TypeError, match="surface should be an int or F.SurfaceSubdomain" + ): + my_model = F.HydrogenTransportProblem( + temperature=500 + ) + my_model.define_temperature() + F.SurfaceTemperature( + field=my_model.temperature_fenics, + surface="1", + ) \ No newline at end of file From e960b5aa04b7261da8392a12d0f5dab298c2906b Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Tue, 25 Feb 2025 23:49:36 -0500 Subject: [PATCH 46/83] black formatted --- test/test_surface_temperature.py | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 4c689a8ac..17678ff43 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -71,12 +71,11 @@ def test_title(tmp_path): assert surface_temp.title == "Temperature surface 1" + @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_title_generation(tmp_path, value): """Test that the title is made to be written to the header in a csv or txt file""" - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( @@ -96,9 +95,7 @@ def test_title_generation(tmp_path, value): def test_write_overwrite(tmp_path): """Test that the write method overwrites the file if it already exists""" filename = os.path.join(tmp_path, "my_export.csv") - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( @@ -131,9 +128,7 @@ def test_filename_setter_raises_TypeError(): """Test that a TypeError is raised when the filename is not a string""" with pytest.raises(TypeError, match="filename must be of type str"): - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() F.SurfaceTemperature( @@ -142,13 +137,12 @@ def test_filename_setter_raises_TypeError(): surface=F.SurfaceSubdomain1D(id=1, x=1), ) + def test_filename_setter_raises_ValueError(tmp_path): """Test that a ValueError is raised when the filename does not end with .csv or .txt""" with pytest.raises(ValueError): - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() F.SurfaceTemperature( @@ -157,6 +151,7 @@ def test_filename_setter_raises_ValueError(tmp_path): surface=F.SurfaceSubdomain1D(id=1, x=1), ) + def test_field_setter_raises_TypeError(): """Test that a TypeError is raised when the field is not an int, float, fem.Constant, fem.Expression, or fem.Function""" @@ -171,9 +166,7 @@ def test_field_setter_raises_TypeError(): @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_writer(tmp_path, value): """Test that the writes values at each timestep to either a csv or txt file""" - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( @@ -199,11 +192,9 @@ def test_surface_setter_raises_TypeError(): with pytest.raises( TypeError, match="surface should be an int or F.SurfaceSubdomain" ): - my_model = F.HydrogenTransportProblem( - temperature=500 - ) + my_model = F.HydrogenTransportProblem(temperature=500) my_model.define_temperature() F.SurfaceTemperature( field=my_model.temperature_fenics, surface="1", - ) \ No newline at end of file + ) From 97b3b17988e5d6651ac24f9e169873b8200d077d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Wed, 26 Feb 2025 00:08:24 -0500 Subject: [PATCH 47/83] add mesh, fix temp_field name --- test/test_surface_temperature.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 17678ff43..505953754 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -75,7 +75,7 @@ def test_title(tmp_path): @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_title_generation(tmp_path, value): """Test that the title is made to be written to the header in a csv or txt file""" - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( @@ -95,12 +95,12 @@ def test_title_generation(tmp_path, value): def test_write_overwrite(tmp_path): """Test that the write method overwrites the file if it already exists""" filename = os.path.join(tmp_path, "my_export.csv") - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( filename=filename, - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), ) my_export.value = 2.0 @@ -128,12 +128,12 @@ def test_filename_setter_raises_TypeError(): """Test that a TypeError is raised when the filename is not a string""" with pytest.raises(TypeError, match="filename must be of type str"): - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() F.SurfaceTemperature( filename=1, - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -142,12 +142,12 @@ def test_filename_setter_raises_ValueError(tmp_path): """Test that a ValueError is raised when the filename does not end with .csv or .txt""" with pytest.raises(ValueError): - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() F.SurfaceTemperature( filename=os.path.join(tmp_path, "my_export.xdmf"), - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -158,7 +158,7 @@ def test_field_setter_raises_TypeError(): with pytest.raises(TypeError): F.SurfaceTemperature( - field=1, + temperature_field=1, surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -166,12 +166,12 @@ def test_field_setter_raises_TypeError(): @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_writer(tmp_path, value): """Test that the writes values at each timestep to either a csv or txt file""" - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() my_export = F.SurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=0), ) my_export.value = 2.0 @@ -192,9 +192,9 @@ def test_surface_setter_raises_TypeError(): with pytest.raises( TypeError, match="surface should be an int or F.SurfaceSubdomain" ): - my_model = F.HydrogenTransportProblem(temperature=500) + my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() F.SurfaceTemperature( - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface="1", ) From c69e971e03bf59f54a61155cab07489a9471f9a7 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Wed, 26 Feb 2025 00:15:49 -0500 Subject: [PATCH 48/83] fix failing tests --- test/test_surface_temperature.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 505953754..5de1c9bc6 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -80,7 +80,7 @@ def test_title_generation(tmp_path, value): my_export = F.SurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), ) my_export.value = 2.0 @@ -109,7 +109,7 @@ def test_write_overwrite(tmp_path): my_export2 = F.SurfaceTemperature( filename=filename, - field=my_model.temperature_fenics, + temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) my_export2.value = 3.0 @@ -158,7 +158,7 @@ def test_field_setter_raises_TypeError(): with pytest.raises(TypeError): F.SurfaceTemperature( - temperature_field=1, + temperature_field="str", surface=F.SurfaceSubdomain1D(id=1, x=1), ) From 134a8ff86f1c69815c6f51a128a14ef9e26fc84b Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Wed, 26 Feb 2025 00:23:07 -0500 Subject: [PATCH 49/83] temperature cannot be a string --- src/festim/exports/surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 3258ea87d..e8dc9c1c9 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -59,7 +59,7 @@ def temperature_field(self): @temperature_field.setter def temperature_field(self, value): # check that temperature field is float, int, fem.Constant, fem.Function, or fem.Expression - if not isinstance(value, (fem.Constant, fem.Function, fem.Expression, int, float, str)): + if not isinstance(value, (fem.Constant, fem.Function, fem.Expression, int, float)): raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") self._temperature_field = value From e1ed3bd2a7e9654c12a43aae35a40ab7db230226 Mon Sep 17 00:00:00 2001 From: Kaelyn Dunnell <150201080+kaelyndunnell@users.noreply.github.com> Date: Sun, 2 Mar 2025 13:41:22 -0500 Subject: [PATCH 50/83] Update src/festim/exports/surface_temperature.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémi Delaporte-Mathurin <40028739+RemDelaporteMathurin@users.noreply.github.com> --- src/festim/exports/surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index e8dc9c1c9..0106138f3 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -3,7 +3,7 @@ import ufl import festim as F -class SurfaceTemperature: +class SurfaceTemperature(F.SurfaceQuantity): """Exports the average temperature on a given surface. Args: From 38d68c77b5784d2f66e7854135a226d0005993f2 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:43:35 -0500 Subject: [PATCH 51/83] delete unneeded lines when inherit from F.SurfaceQuantity --- src/festim/exports/surface_temperature.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 0106138f3..3d507c485 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -42,16 +42,6 @@ def filename(self, value): raise ValueError("filename must end with .csv or .txt") self._filename = value - @property - def surface(self): - return self._surface - - @surface.setter - def surface(self, value): - if not isinstance(value, (int, F.SurfaceSubdomain)) or isinstance(value, bool): - raise TypeError("surface should be an int or F.SurfaceSubdomain") - self._surface = value - @property def temperature_field(self): return self._temperature_field From baa374d05661ed33d4b70caf145e2aa11325cf9e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:43:55 -0500 Subject: [PATCH 52/83] also inherited now --- src/festim/exports/surface_temperature.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 3d507c485..995453bc1 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -28,20 +28,6 @@ def __init__(self, temperature_field, surface, filename: str = None) -> None: self.data = [] self._first_time_export = True - @property - def filename(self): - return self._filename - - @filename.setter - def filename(self, value): - if value is None: - self._filename = None - elif not isinstance(value, str): - raise TypeError("filename must be of type str") - elif not value.endswith(".csv") and not value.endswith(".txt"): - raise ValueError("filename must end with .csv or .txt") - self._filename = value - @property def temperature_field(self): return self._temperature_field From ecf45328bb1e7b451f2a811f19ee7d1a121b1cb8 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:44:32 -0500 Subject: [PATCH 53/83] also inherited --- src/festim/exports/surface_temperature.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 995453bc1..334e22d18 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -58,21 +58,4 @@ def compute(self, ds): self.value = surface_integral / surface_area # avg temp - self.data.append(self.value) - - def write(self, t): - """Writes the time and temperature value to the file. - - Args: - t (float): current time value - """ - if self.filename is not None: - if self._first_time_export: - header = ["t(s)", f"{self.title}"] - with open(self.filename, mode="w+", newline="") as file: - writer = csv.writer(file) - writer.writerow(header) - self._first_time_export = False - with open(self.filename, mode="a", newline="") as file: - writer = csv.writer(file) - writer.writerow([t, self.value]) \ No newline at end of file + self.data.append(self.value) \ No newline at end of file From 8ef198133fb8bac0efc9cb5da51c24b470634fcf Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:45:13 -0500 Subject: [PATCH 54/83] remove old line --- src/festim/hydrogen_transport_problem.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 3742bf2ab..624392851 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -793,8 +793,6 @@ def update_time_dependent_values(self): if source.temperature_dependent: source.update(t=t) - surface_temp_processed = False - def post_processing(self): """Post processes the model""" From dd3ed9979edfb96a0227dc9d1a096a98e85d04a7 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:49:47 -0500 Subject: [PATCH 55/83] rename to AverageSurfaceTemperature --- src/festim/exports/__init__.py | 4 ++-- src/festim/exports/surface_temperature.py | 2 +- src/festim/hydrogen_transport_problem.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/festim/exports/__init__.py b/src/festim/exports/__init__.py index 741dc0988..19386b90d 100644 --- a/src/festim/exports/__init__.py +++ b/src/festim/exports/__init__.py @@ -9,14 +9,14 @@ "AverageSurface", "AverageVolume", "TotalVolume", - "SurfaceTemperature" + "AverageSurfaceTemperature" ] from .average_surface import AverageSurface from .average_volume import AverageVolume from .surface_flux import SurfaceFlux from .surface_quantity import SurfaceQuantity -from .surface_temperature import SurfaceTemperature +from .surface_temperature import AverageSurfaceTemperature from .total_surface import TotalSurface from .total_volume import TotalVolume from .volume_quantity import VolumeQuantity diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 334e22d18..f2bbc93b5 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -3,7 +3,7 @@ import ufl import festim as F -class SurfaceTemperature(F.SurfaceQuantity): +class AverageSurfaceTemperature(F.SurfaceQuantity): """Exports the average temperature on a given surface. Args: diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 624392851..625be9413 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -370,7 +370,7 @@ def initialise_exports(self): for export in self.exports: - if isinstance(export, exports.SurfaceTemperature): + if isinstance(export, exports.AverageSurfaceTemperature): continue # if name of species is given then replace with species object @@ -419,11 +419,11 @@ def initialise_exports(self): export.D = D export.D_expr = D_expr - elif isinstance(export, exports.SurfaceTemperature): + elif isinstance(export, exports.AverageSurfaceTemperature): export.temperature_field = self.temperature_fenics # reset the data and time for SurfaceQuantity and VolumeQuantity - if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity, exports.SurfaceTemperature)): + if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity, exports.AverageSurfaceTemperature)): export.t = [] export.data = [] @@ -826,7 +826,7 @@ def post_processing(self): if export.filename is not None: export.write(t=float(self.t)) - elif isinstance(export, exports.SurfaceTemperature): + elif isinstance(export, exports.AverageSurfaceTemperature): export.compute(self.ds) # compute surface temp export.t.append(float(self.t)) # update export time From 15fe0ad63783f442e65838c915b91f2177b31cec Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 13:58:26 -0500 Subject: [PATCH 56/83] set temp field as an attribute --- src/festim/exports/surface_temperature.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index f2bbc93b5..15b6f2bee 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -7,7 +7,6 @@ class AverageSurfaceTemperature(F.SurfaceQuantity): """Exports the average temperature on a given surface. Args: - temperature_field (fem.Constant or fem.Function): the temperature field to be computed surface (int or festim.SurfaceSubdomain): the surface subdomain filename (str, optional): name of the file to which the average surface temperature is exported @@ -19,27 +18,15 @@ class AverageSurfaceTemperature(F.SurfaceQuantity): data (list): list of average temperature values on the surface """ - def __init__(self, temperature_field, surface, filename: str = None) -> None: - self.temperature_field = temperature_field + def __init__(self, surface, filename: str = None) -> None: self.surface = surface self.filename = filename + self.temperature_field = None self.t = [] self.data = [] self._first_time_export = True - @property - def temperature_field(self): - return self._temperature_field - - @temperature_field.setter - def temperature_field(self, value): - # check that temperature field is float, int, fem.Constant, fem.Function, or fem.Expression - if not isinstance(value, (fem.Constant, fem.Function, fem.Expression, int, float)): - raise TypeError("field must be of type float, int, fem.Constant, fem.Function, or fem.Expression") - - self._temperature_field = value - @property def title(self): return f"Temperature surface {self.surface.id}" From 3454d35ced77ec7566086f11ff91c4766de59a65 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:01:29 -0500 Subject: [PATCH 57/83] fix surfacequantity inheritance --- src/festim/exports/surface_temperature.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 15b6f2bee..0399ee60c 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -1,9 +1,9 @@ import csv from dolfinx import fem import ufl -import festim as F +from .surface_quantity import SurfaceQuantity -class AverageSurfaceTemperature(F.SurfaceQuantity): +class AverageSurfaceTemperature(SurfaceQuantity): """Exports the average temperature on a given surface. Args: From 96bf5dd20ecc5d7f351a98c4bcf6af44b21e0b73 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:03:39 -0500 Subject: [PATCH 58/83] truncate computation of AverageSurfaceTemperature in hydrogentransportproblem --- src/festim/hydrogen_transport_problem.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 625be9413..18f45e001 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -812,7 +812,7 @@ def post_processing(self): if isinstance(export, exports.SurfaceQuantity): if isinstance( export, - (exports.SurfaceFlux, exports.TotalSurface, exports.AverageSurface), + (exports.SurfaceFlux, exports.TotalSurface, exports.AverageSurface, exports.AverageSurfaceTemperature), ): export.compute( self.ds, @@ -826,16 +826,6 @@ def post_processing(self): if export.filename is not None: export.write(t=float(self.t)) - elif isinstance(export, exports.AverageSurfaceTemperature): - export.compute(self.ds) # compute surface temp - - export.t.append(float(self.t)) # update export time - - # if filename given write export data to file - if export.filename is not None: - export.write(t=float(self.t)) - - elif isinstance(export, exports.VolumeQuantity): if isinstance(export, (exports.TotalVolume, exports.AverageVolume)): export.compute(self.dx) From 78d34ceea7fa133fa3852992bece1cdacd837d3a Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:04:31 -0500 Subject: [PATCH 59/83] fix festim init --- src/festim/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/__init__.py b/src/festim/__init__.py index 1437c660e..3982c0e18 100644 --- a/src/festim/__init__.py +++ b/src/festim/__init__.py @@ -30,7 +30,7 @@ from .exports.minimum_volume import MinimumVolume from .exports.surface_flux import SurfaceFlux from .exports.surface_quantity import SurfaceQuantity -from .exports.surface_temperature import SurfaceTemperature +from .exports.surface_temperature import AverageSurfaceTemperature from .exports.total_surface import TotalSurface from .exports.total_volume import TotalVolume from .exports.volume_quantity import VolumeQuantity From e2b7b9a5bdacfb7368f546fff0a7b67aff913f95 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:38:33 -0500 Subject: [PATCH 60/83] renamed class --- test/test_surface_temperature.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 5de1c9bc6..dd78b5664 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -46,7 +46,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.SurfaceTemperature( + my_export = F.AverageSurfaceTemperature( temperature_field=my_model.temperature_fenics, surface=dummy_surface ) my_export.compute(ds) @@ -59,7 +59,7 @@ def test_title(tmp_path): surf_1 = F.SurfaceSubdomain(id=1) results = "test.csv" temp = 400 - surface_temp = F.SurfaceTemperature( + surface_temp = F.AverageSurfaceTemperature( temperature_field=temp, surface=surf_1, filename=results ) @@ -78,7 +78,7 @@ def test_title_generation(tmp_path, value): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - my_export = F.SurfaceTemperature( + my_export = F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), @@ -98,7 +98,7 @@ def test_write_overwrite(tmp_path): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - my_export = F.SurfaceTemperature( + my_export = F.AverageSurfaceTemperature( filename=filename, temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), @@ -107,7 +107,7 @@ def test_write_overwrite(tmp_path): my_export.write(0) my_export.write(1) - my_export2 = F.SurfaceTemperature( + my_export2 = F.AverageSurfaceTemperature( filename=filename, temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), @@ -131,7 +131,7 @@ def test_filename_setter_raises_TypeError(): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - F.SurfaceTemperature( + F.AverageSurfaceTemperature( filename=1, temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), @@ -145,7 +145,7 @@ def test_filename_setter_raises_ValueError(tmp_path): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - F.SurfaceTemperature( + F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, "my_export.xdmf"), temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), @@ -157,7 +157,7 @@ def test_field_setter_raises_TypeError(): with pytest.raises(TypeError): - F.SurfaceTemperature( + F.AverageSurfaceTemperature( temperature_field="str", surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -169,7 +169,7 @@ def test_writer(tmp_path, value): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - my_export = F.SurfaceTemperature( + my_export = F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=0), @@ -194,7 +194,7 @@ def test_surface_setter_raises_TypeError(): ): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() - F.SurfaceTemperature( + F.AverageSurfaceTemperature( temperature_field=my_model.temperature_fenics, surface="1", ) From f0123dc04d48c8dc6083674a7d3cb6d9a831e3d1 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:40:49 -0500 Subject: [PATCH 61/83] remove temp field from arguments --- test/test_surface_temperature.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index dd78b5664..8cf5b5a15 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -47,7 +47,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.update_time_dependent_values() my_export = F.AverageSurfaceTemperature( - temperature_field=my_model.temperature_fenics, surface=dummy_surface + surface=dummy_surface ) my_export.compute(ds) @@ -60,7 +60,7 @@ def test_title(tmp_path): results = "test.csv" temp = 400 surface_temp = F.AverageSurfaceTemperature( - temperature_field=temp, surface=surf_1, filename=results + surface=surf_1, filename=results ) my_model = F.HydrogenTransportProblem( @@ -80,7 +80,6 @@ def test_title_generation(tmp_path, value): my_export = F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), ) my_export.value = 2.0 @@ -100,7 +99,6 @@ def test_write_overwrite(tmp_path): my_export = F.AverageSurfaceTemperature( filename=filename, - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=35, x=1), ) my_export.value = 2.0 @@ -109,7 +107,6 @@ def test_write_overwrite(tmp_path): my_export2 = F.AverageSurfaceTemperature( filename=filename, - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) my_export2.value = 3.0 @@ -133,7 +130,6 @@ def test_filename_setter_raises_TypeError(): F.AverageSurfaceTemperature( filename=1, - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -147,7 +143,6 @@ def test_filename_setter_raises_ValueError(tmp_path): F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, "my_export.xdmf"), - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -158,7 +153,6 @@ def test_field_setter_raises_TypeError(): with pytest.raises(TypeError): F.AverageSurfaceTemperature( - temperature_field="str", surface=F.SurfaceSubdomain1D(id=1, x=1), ) @@ -171,7 +165,6 @@ def test_writer(tmp_path, value): my_export = F.AverageSurfaceTemperature( filename=os.path.join(tmp_path, f"{value}"), - temperature_field=my_model.temperature_fenics, surface=F.SurfaceSubdomain1D(id=1, x=0), ) my_export.value = 2.0 @@ -195,6 +188,5 @@ def test_surface_setter_raises_TypeError(): my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) my_model.define_temperature() F.AverageSurfaceTemperature( - temperature_field=my_model.temperature_fenics, surface="1", ) From 7ede0ec2955729f5201e5f65da832800559276fb Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:43:13 -0500 Subject: [PATCH 62/83] remove unneeded test --- test/test_surface_temperature.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 8cf5b5a15..d83a1eeec 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -147,16 +147,6 @@ def test_filename_setter_raises_ValueError(tmp_path): ) -def test_field_setter_raises_TypeError(): - """Test that a TypeError is raised when the field is not an int, float, fem.Constant, fem.Expression, or fem.Function""" - - with pytest.raises(TypeError): - - F.AverageSurfaceTemperature( - surface=F.SurfaceSubdomain1D(id=1, x=1), - ) - - @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_writer(tmp_path, value): """Test that the writes values at each timestep to either a csv or txt file""" From b542a18450af238546b3f14116c5f5313dc6cb5e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:49:02 -0500 Subject: [PATCH 63/83] fix if statement --- src/festim/hydrogen_transport_problem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 18f45e001..cd8ca031f 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -419,7 +419,7 @@ def initialise_exports(self): export.D = D export.D_expr = D_expr - elif isinstance(export, exports.AverageSurfaceTemperature): + if isinstance(export, exports.AverageSurfaceTemperature): export.temperature_field = self.temperature_fenics # reset the data and time for SurfaceQuantity and VolumeQuantity From b77407063a921aa1e1a5f5b4c42d91f8a50f5995 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 14:55:26 -0500 Subject: [PATCH 64/83] add line --- src/festim/hydrogen_transport_problem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index cd8ca031f..6ba0368f2 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -371,7 +371,7 @@ def initialise_exports(self): for export in self.exports: if isinstance(export, exports.AverageSurfaceTemperature): - continue + export.temperature_field = self.temperature_fenics # if name of species is given then replace with species object if isinstance(export.field, list): From fe8f5c66b06df6ee7070a78003b44261b2b74b92 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 15:07:40 -0500 Subject: [PATCH 65/83] add test line, simply HTP --- src/festim/hydrogen_transport_problem.py | 2 +- test/test_surface_temperature.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 6ba0368f2..f4a8cfe93 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -423,7 +423,7 @@ def initialise_exports(self): export.temperature_field = self.temperature_fenics # reset the data and time for SurfaceQuantity and VolumeQuantity - if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity, exports.AverageSurfaceTemperature)): + if isinstance(export, (exports.SurfaceQuantity, exports.VolumeQuantity)): export.t = [] export.data = [] diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index d83a1eeec..006d337b6 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -49,6 +49,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_export = F.AverageSurfaceTemperature( surface=dummy_surface ) + my_export.temperature_field = my_model.temperature_field my_export.compute(ds) # TEST From b1d7ec76d6124a947032d94929016ab0707b592f Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 15:07:57 -0500 Subject: [PATCH 66/83] fix test --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 006d337b6..730eb7319 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -49,7 +49,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_export = F.AverageSurfaceTemperature( surface=dummy_surface ) - my_export.temperature_field = my_model.temperature_field + my_export.temperature_field = my_model.temperature my_export.compute(ds) # TEST From 352fb852e38d803c77a9f0ed98baf38e814689b4 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 15:11:45 -0500 Subject: [PATCH 67/83] fix temp line --- test/test_surface_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 730eb7319..f8a4dce3d 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -49,7 +49,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_export = F.AverageSurfaceTemperature( surface=dummy_surface ) - my_export.temperature_field = my_model.temperature + my_export.temperature_field = my_model.temperature_fenics my_export.compute(ds) # TEST From 7fb1fc16b5bf0d29dab5d129aa3a5d9d5e49462d Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 15:17:23 -0500 Subject: [PATCH 68/83] simplify HTP --- src/festim/hydrogen_transport_problem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index f4a8cfe93..fe5475910 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -371,8 +371,8 @@ def initialise_exports(self): for export in self.exports: if isinstance(export, exports.AverageSurfaceTemperature): - export.temperature_field = self.temperature_fenics - + continue + # if name of species is given then replace with species object if isinstance(export.field, list): for idx, field in enumerate(export.field): From e531a88b76ca23e176f9ef9b39ec2369afdcbe9c Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Sun, 2 Mar 2025 15:19:11 -0500 Subject: [PATCH 69/83] ruff formatted --- src/festim/exports/__init__.py | 2 +- src/festim/exports/surface_temperature.py | 13 +++++---- src/festim/hydrogen_transport_problem.py | 8 ++++-- test/test_surface_temperature.py | 32 ++++++++++++++--------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/festim/exports/__init__.py b/src/festim/exports/__init__.py index 19386b90d..9fb0471b3 100644 --- a/src/festim/exports/__init__.py +++ b/src/festim/exports/__init__.py @@ -9,7 +9,7 @@ "AverageSurface", "AverageVolume", "TotalVolume", - "AverageSurfaceTemperature" + "AverageSurfaceTemperature", ] from .average_surface import AverageSurface diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 0399ee60c..422981eef 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -3,6 +3,7 @@ import ufl from .surface_quantity import SurfaceQuantity + class AverageSurfaceTemperature(SurfaceQuantity): """Exports the average temperature on a given surface. @@ -37,12 +38,14 @@ def compute(self, ds): Args: ds (ufl.Measure): surface measure of the model """ - temperature_field = self.temperature_field + temperature_field = self.temperature_field + + surface_integral = fem.assemble_scalar( + fem.form(temperature_field * ds(self.surface.id)) + ) # integral over surface - surface_integral = fem.assemble_scalar(fem.form(temperature_field * ds(self.surface.id))) # integral over surface - surface_area = fem.assemble_scalar(fem.form(1 * ds(self.surface.id))) - self.value = surface_integral / surface_area # avg temp + self.value = surface_integral / surface_area # avg temp - self.data.append(self.value) \ No newline at end of file + self.data.append(self.value) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index fe5475910..c1b0d8d27 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -369,7 +369,6 @@ def initialise_exports(self): a string, find species object in self.species""" for export in self.exports: - if isinstance(export, exports.AverageSurfaceTemperature): continue @@ -812,7 +811,12 @@ def post_processing(self): if isinstance(export, exports.SurfaceQuantity): if isinstance( export, - (exports.SurfaceFlux, exports.TotalSurface, exports.AverageSurface, exports.AverageSurfaceTemperature), + ( + exports.SurfaceFlux, + exports.TotalSurface, + exports.AverageSurface, + exports.AverageSurfaceTemperature, + ), ): export.compute( self.ds, diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index f8a4dce3d..c36cc5ced 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -46,9 +46,7 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.AverageSurfaceTemperature( - surface=dummy_surface - ) + my_export = F.AverageSurfaceTemperature(surface=dummy_surface) my_export.temperature_field = my_model.temperature_fenics my_export.compute(ds) @@ -60,9 +58,7 @@ def test_title(tmp_path): surf_1 = F.SurfaceSubdomain(id=1) results = "test.csv" temp = 400 - surface_temp = F.AverageSurfaceTemperature( - surface=surf_1, filename=results - ) + surface_temp = F.AverageSurfaceTemperature(surface=surf_1, filename=results) my_model = F.HydrogenTransportProblem( temperature=temp, @@ -76,7 +72,9 @@ def test_title(tmp_path): @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_title_generation(tmp_path, value): """Test that the title is made to be written to the header in a csv or txt file""" - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() my_export = F.AverageSurfaceTemperature( @@ -95,7 +93,9 @@ def test_title_generation(tmp_path, value): def test_write_overwrite(tmp_path): """Test that the write method overwrites the file if it already exists""" filename = os.path.join(tmp_path, "my_export.csv") - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() my_export = F.AverageSurfaceTemperature( @@ -126,7 +126,9 @@ def test_filename_setter_raises_TypeError(): """Test that a TypeError is raised when the filename is not a string""" with pytest.raises(TypeError, match="filename must be of type str"): - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() F.AverageSurfaceTemperature( @@ -139,7 +141,9 @@ def test_filename_setter_raises_ValueError(tmp_path): """Test that a ValueError is raised when the filename does not end with .csv or .txt""" with pytest.raises(ValueError): - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() F.AverageSurfaceTemperature( @@ -151,7 +155,9 @@ def test_filename_setter_raises_ValueError(tmp_path): @pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) def test_writer(tmp_path, value): """Test that the writes values at each timestep to either a csv or txt file""" - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() my_export = F.AverageSurfaceTemperature( @@ -176,7 +182,9 @@ def test_surface_setter_raises_TypeError(): with pytest.raises( TypeError, match="surface should be an int or F.SurfaceSubdomain" ): - my_model = F.HydrogenTransportProblem(mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)),temperature=500) + my_model = F.HydrogenTransportProblem( + mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 + ) my_model.define_temperature() F.AverageSurfaceTemperature( surface="1", From 2b2c38a4ad2ae19849d880b9a1d5c4d87131b311 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 10:45:58 -0400 Subject: [PATCH 70/83] remove unneeded tests --- test/test_surface_temperature.py | 101 ------------------------------- 1 file changed, 101 deletions(-) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index c36cc5ced..9255fba54 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -88,104 +88,3 @@ def test_title_generation(tmp_path, value): expected_title = "Temperature surface 35" assert title[1] == expected_title - - -def test_write_overwrite(tmp_path): - """Test that the write method overwrites the file if it already exists""" - filename = os.path.join(tmp_path, "my_export.csv") - my_model = F.HydrogenTransportProblem( - mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 - ) - my_model.define_temperature() - - my_export = F.AverageSurfaceTemperature( - filename=filename, - surface=F.SurfaceSubdomain1D(id=35, x=1), - ) - my_export.value = 2.0 - my_export.write(0) - my_export.write(1) - - my_export2 = F.AverageSurfaceTemperature( - filename=filename, - surface=F.SurfaceSubdomain1D(id=1, x=1), - ) - my_export2.value = 3.0 - my_export2.write(1) - my_export2.write(2) - my_export2.write(3) - - data = np.genfromtxt(filename, delimiter=",", names=True) - file_length = data.size - expected_length = 3 - - assert file_length == expected_length - - -def test_filename_setter_raises_TypeError(): - """Test that a TypeError is raised when the filename is not a string""" - - with pytest.raises(TypeError, match="filename must be of type str"): - my_model = F.HydrogenTransportProblem( - mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 - ) - my_model.define_temperature() - - F.AverageSurfaceTemperature( - filename=1, - surface=F.SurfaceSubdomain1D(id=1, x=1), - ) - - -def test_filename_setter_raises_ValueError(tmp_path): - """Test that a ValueError is raised when the filename does not end with .csv or .txt""" - - with pytest.raises(ValueError): - my_model = F.HydrogenTransportProblem( - mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 - ) - my_model.define_temperature() - - F.AverageSurfaceTemperature( - filename=os.path.join(tmp_path, "my_export.xdmf"), - surface=F.SurfaceSubdomain1D(id=1, x=1), - ) - - -@pytest.mark.parametrize("value", ["my_export.csv", "my_export.txt"]) -def test_writer(tmp_path, value): - """Test that the writes values at each timestep to either a csv or txt file""" - my_model = F.HydrogenTransportProblem( - mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 - ) - my_model.define_temperature() - - my_export = F.AverageSurfaceTemperature( - filename=os.path.join(tmp_path, f"{value}"), - surface=F.SurfaceSubdomain1D(id=1, x=0), - ) - my_export.value = 2.0 - - for i in range(10): - my_export.write(i) - file_length = len(np.genfromtxt(my_export.filename, delimiter=",")) - - expected_length = i + 2 - - assert file_length == expected_length - - -def test_surface_setter_raises_TypeError(): - """Test that a TypeError is raised when the surface is not a - F.SurfaceSubdomain""" - - with pytest.raises( - TypeError, match="surface should be an int or F.SurfaceSubdomain" - ): - my_model = F.HydrogenTransportProblem( - mesh=F.Mesh1D(np.linspace(0, 6.0, 10000)), temperature=500 - ) - my_model.define_temperature() - F.AverageSurfaceTemperature( - surface="1", - ) From a7222533b9295c6e609d9b5e0995de1c7c77aa38 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 11:01:08 -0400 Subject: [PATCH 71/83] add averagesurfacetemperature to export init --- src/festim/exports/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/festim/exports/__init__.py b/src/festim/exports/__init__.py index c4cfe35af..513ad2b92 100644 --- a/src/festim/exports/__init__.py +++ b/src/festim/exports/__init__.py @@ -31,4 +31,5 @@ "VTXTemperatureExport", "VolumeQuantity", "XDMFExport", + "AverageSurfaceTemperature", ] From b9795ba1b0c7fd313311f12b96b5711f64350601 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 11:04:03 -0400 Subject: [PATCH 72/83] updates/rebase --- src/festim/hydrogen_transport_problem.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 0b046330d..7e9ecdffa 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1017,7 +1017,8 @@ def post_processing(self): if isinstance(export, exports.SurfaceQuantity): if isinstance( export, - exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, exports.AverageSurfaceTemperature, + exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, + exports.AverageSurfaceTemperature, ): if len(self.advection_terms) > 0: warnings.warn( @@ -1592,13 +1593,17 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_0 += ( 2 * gamma @@ -1822,9 +1827,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert export.subdomain, ( - "Profile1DExport requires a subdomain to be set" - ) + assert ( + export.subdomain + ), "Profile1DExport requires a subdomain to be set" u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( From c568c2129ab44cddeb8d34691412c7ff7bda8432 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 11:04:09 -0400 Subject: [PATCH 73/83] full integration test --- test/test_surface_temperature.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 9255fba54..3f1513496 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -50,6 +50,10 @@ def test_surface_temperature_compute_1D(T_function, expected_values): my_export.temperature_field = my_model.temperature_fenics my_export.compute(ds) + my_model.exports = [my_export] + my_model.initialise() + my_model.run() + # TEST assert np.isclose(my_export.value, expected_values) From d1eeb8b722dad4aa2a49ac5d4062fde2fd3024b6 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 11:57:32 -0400 Subject: [PATCH 74/83] fix integration tests and test --- src/festim/hydrogen_transport_problem.py | 5 +++- test/test_surface_temperature.py | 31 +++++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 7e9ecdffa..d68fae684 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -480,6 +480,8 @@ def initialise_exports(self): for export in self.exports: if isinstance(export, exports.SurfaceQuantity): + if isinstance(export, exports.AverageSurfaceTemperature): + continue if export.field in spe_to_D_global: # if already computed then use the same D D = spe_to_D_global[export.field] @@ -1018,7 +1020,6 @@ def post_processing(self): if isinstance( export, exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, - exports.AverageSurfaceTemperature, ): if len(self.advection_terms) > 0: warnings.warn( @@ -1026,6 +1027,8 @@ def post_processing(self): "evaluation of surface flux values" ) export.compute(export.field.solution, self.ds) + elif isinstance(export, exports.AverageSurfaceTemperature): + export.compute(self.ds) else: export.compute() # update export data diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 3f1513496..19a38032e 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -21,36 +21,43 @@ def test_surface_temperature_compute_1D(T_function, expected_values): # BUILD L = 6.0 my_mesh = F.Mesh1D(np.linspace(0, L, 10000)) - dummy_surface = F.SurfaceSubdomain1D(id=1, x=6) + dummy_surface = F.SurfaceSubdomain1D(id=1, x=L) dummy_volume = F.VolumeSubdomain1D( - id=1, borders=[0, L], material=F.Material(D_0=1, E_D=1, name="dummy") + id=1, borders=(0.0, L), material=F.Material(D_0=1, E_D=1, name="dummy") ) + facet_meshtags, temp = my_mesh.define_meshtags( surface_subdomains=[dummy_surface], volume_subdomains=[dummy_volume] ) - ds = ufl.Measure("ds", domain=my_mesh.mesh, subdomain_data=facet_meshtags) + dt = F.Stepsize(initial_value=1) + settings = F.Settings(atol=1e05, rtol=1e-10, stepsize=dt, final_time=10) my_model = F.HydrogenTransportProblem( - mesh=my_mesh, - temperature=T_function, + mesh=my_mesh, temperature=T_function, settings=settings ) - my_model.t = fem.Constant(my_model.mesh.mesh, 0.0) + + my_model.species = [F.Species("H")] + my_model.subdomains = [ + dummy_surface, + dummy_volume, + ] + + my_model.t = fem.Constant(my_mesh.mesh, 0.0) dt = fem.Constant(my_mesh.mesh, 1.0) my_model.define_temperature() my_model.initialise_exports() + my_export = F.AverageSurfaceTemperature(surface=dummy_surface) + my_export.temperature_field = my_model.temperature_fenics + my_model.exports = [my_export] + # RUN - for i in range(3): + for _ in range(3): my_model.t.value += dt.value my_model.update_time_dependent_values() - my_export = F.AverageSurfaceTemperature(surface=dummy_surface) - my_export.temperature_field = my_model.temperature_fenics - my_export.compute(ds) - - my_model.exports = [my_export] my_model.initialise() my_model.run() From 5b36778d45f6ac0d9bdad7a9fe78b8ce60f7ebff Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 12:02:20 -0400 Subject: [PATCH 75/83] ruff --- src/festim/hydrogen_transport_problem.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index d68fae684..ca1882414 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1596,17 +1596,13 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_0 += ( 2 * gamma @@ -1830,9 +1826,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert ( - export.subdomain - ), "Profile1DExport requires a subdomain to be set" + assert export.subdomain, ( + "Profile1DExport requires a subdomain to be set" + ) u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( From dc51fb66963af3729e8585a3e4eb5ddf902f207e Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 12:20:50 -0400 Subject: [PATCH 76/83] add not implemented error for discontinuous problem --- src/festim/hydrogen_transport_problem.py | 24 ++++++++++++++++---- test/test_surface_temperature.py | 29 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index ca1882414..6acff76ca 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1596,13 +1596,17 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_0 += ( 2 * gamma @@ -1709,6 +1713,11 @@ def initialise_exports(self): for export in self.exports: if isinstance(export, exports.SurfaceQuantity): + if isinstance(export, exports.AverageSurfaceTemperature): + raise NotImplementedError( + f"Export type {type(export)} not implemented for " + f"mixed-domain approach" + ) if export.field in spe_to_D_global: # if already computed then use the same D D = spe_to_D_global[export.field] @@ -1765,6 +1774,11 @@ def post_processing(self): # handle derived quantities if isinstance(export, exports.SurfaceQuantity): + if isinstance(export, exports.AverageSurfaceTemperature): + raise NotImplementedError( + f"Export type {type(export)} not implemented for " + f"mixed-domain approach" + ) if isinstance( export, exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, @@ -1826,9 +1840,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert export.subdomain, ( - "Profile1DExport requires a subdomain to be set" - ) + assert ( + export.subdomain + ), "Profile1DExport requires a subdomain to be set" u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index 19a38032e..fbe2d9365 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -99,3 +99,32 @@ def test_title_generation(tmp_path, value): expected_title = "Temperature surface 35" assert title[1] == expected_title + + +def test_not_implemented_error_raised_with_multiple_volume_domains(): + """Test that NotImplementedError is raised for problems with multiple volume domains.""" + + # BUILD + L = 1.0 + test_mesh = F.Mesh1D(vertices=np.linspace(0, L, num=101)) + + my_mat = F.Material(D_0=1, E_D=1) + dummy_surface = F.SurfaceSubdomain1D(id=1, x=L) + vol_1 = F.VolumeSubdomain1D(id=1, borders=[0, 0.5], material=my_mat) + vol_2 = F.VolumeSubdomain1D(id=1, borders=[0.5, L], material=my_mat) + + H = F.Species("H") + my_model = F.HydrogenTransportProblemDiscontinuous( + mesh=test_mesh, + temperature=10, + subdomains=[vol_1, vol_2], + species=[F.Species("H")], + ) + + my_model.initialise_exports() + + my_model.exports = [F.AverageSurfaceTemperature(surface=dummy_surface)] + + # TEST + with pytest.raises(NotImplementedError): + my_model.initialise_exports() From 0bcd616d4ca128ff8ece96fe14ac247f83b87bcd Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 12:21:32 -0400 Subject: [PATCH 77/83] ruff --- src/festim/hydrogen_transport_problem.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 6acff76ca..9170a3f34 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1596,17 +1596,13 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_0 += ( 2 * gamma @@ -1840,9 +1836,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert ( - export.subdomain - ), "Profile1DExport requires a subdomain to be set" + assert export.subdomain, ( + "Profile1DExport requires a subdomain to be set" + ) u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( From b331392e4327f2513e313c6becec068d5e942117 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 12:37:03 -0400 Subject: [PATCH 78/83] update testing coverage --- src/festim/hydrogen_transport_problem.py | 19 +++++++++---------- test/test_surface_temperature.py | 7 ++----- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 9170a3f34..bfde776d2 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1596,13 +1596,17 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_0 += ( 2 * gamma @@ -1770,11 +1774,6 @@ def post_processing(self): # handle derived quantities if isinstance(export, exports.SurfaceQuantity): - if isinstance(export, exports.AverageSurfaceTemperature): - raise NotImplementedError( - f"Export type {type(export)} not implemented for " - f"mixed-domain approach" - ) if isinstance( export, exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, @@ -1836,9 +1835,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert export.subdomain, ( - "Profile1DExport requires a subdomain to be set" - ) + assert ( + export.subdomain + ), "Profile1DExport requires a subdomain to be set" u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( diff --git a/test/test_surface_temperature.py b/test/test_surface_temperature.py index fbe2d9365..373ea91d3 100644 --- a/test/test_surface_temperature.py +++ b/test/test_surface_temperature.py @@ -47,7 +47,6 @@ def test_surface_temperature_compute_1D(T_function, expected_values): dt = fem.Constant(my_mesh.mesh, 1.0) my_model.define_temperature() - my_model.initialise_exports() my_export = F.AverageSurfaceTemperature(surface=dummy_surface) my_export.temperature_field = my_model.temperature_fenics @@ -101,7 +100,7 @@ def test_title_generation(tmp_path, value): assert title[1] == expected_title -def test_not_implemented_error_raised_with_multiple_volume_domains(): +def test_not_implemented_error_raised_with_initialise_exports_multiple_subdomains(): """Test that NotImplementedError is raised for problems with multiple volume domains.""" # BUILD @@ -117,12 +116,10 @@ def test_not_implemented_error_raised_with_multiple_volume_domains(): my_model = F.HydrogenTransportProblemDiscontinuous( mesh=test_mesh, temperature=10, - subdomains=[vol_1, vol_2], + subdomains=[dummy_surface, vol_1, vol_2], species=[F.Species("H")], ) - my_model.initialise_exports() - my_model.exports = [F.AverageSurfaceTemperature(surface=dummy_surface)] # TEST From d2682894b8d530731ee01d8b76034c04f514f863 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Fri, 24 Oct 2025 12:38:13 -0400 Subject: [PATCH 79/83] ruff --- src/festim/hydrogen_transport_problem.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index bfde776d2..193859ff4 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1596,17 +1596,13 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_0 += ( 2 * gamma @@ -1835,9 +1831,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert ( - export.subdomain - ), "Profile1DExport requires a subdomain to be set" + assert export.subdomain, ( + "Profile1DExport requires a subdomain to be set" + ) u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( From a9e9e202c210a8fae2348f176d86daf1f08f2f3d Mon Sep 17 00:00:00 2001 From: Kaelyn Dunnell <150201080+kaelyndunnell@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:43:11 -0400 Subject: [PATCH 80/83] Update src/festim/exports/surface_temperature.py Co-authored-by: James Dark <65899899+jhdark@users.noreply.github.com> --- src/festim/exports/surface_temperature.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 422981eef..273e984d5 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -8,16 +8,22 @@ class AverageSurfaceTemperature(SurfaceQuantity): """Exports the average temperature on a given surface. Args: - surface (int or festim.SurfaceSubdomain): the surface subdomain - filename (str, optional): name of the file to which the average surface temperature is exported + surface: the surface subdomain + filename: name of the file to which the average surface temperature is exported Attributes: - temperature_field (fem.Constant or fem.Function): the temperature field + temperature_field: the temperature field surface (int or festim.SurfaceSubdomain): the surface subdomain filename (str): name of the file to which the surface temperature is exported t (list): list of time values data (list): list of average temperature values on the surface """ + + surface: int | SurfaceSubdomain + filename: str | None + + temperature_field: fem.Constant | fem.Function + def __init__(self, surface, filename: str = None) -> None: self.surface = surface From 262a912d7dada9a9d45710b6625049b100700893 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 27 Oct 2025 10:14:11 -0400 Subject: [PATCH 81/83] simplify --- src/festim/exports/surface_temperature.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/festim/exports/surface_temperature.py b/src/festim/exports/surface_temperature.py index 273e984d5..e15de834c 100644 --- a/src/festim/exports/surface_temperature.py +++ b/src/festim/exports/surface_temperature.py @@ -2,6 +2,7 @@ from dolfinx import fem import ufl from .surface_quantity import SurfaceQuantity +from festim.subdomain.surface_subdomain import SurfaceSubdomain class AverageSurfaceTemperature(SurfaceQuantity): @@ -18,12 +19,11 @@ class AverageSurfaceTemperature(SurfaceQuantity): t (list): list of time values data (list): list of average temperature values on the surface """ - + surface: int | SurfaceSubdomain filename: str | None - - temperature_field: fem.Constant | fem.Function + temperature_field: fem.Constant | fem.Function def __init__(self, surface, filename: str = None) -> None: self.surface = surface @@ -46,12 +46,10 @@ def compute(self, ds): """ temperature_field = self.temperature_field - surface_integral = fem.assemble_scalar( + self.value = fem.assemble_scalar( fem.form(temperature_field * ds(self.surface.id)) - ) # integral over surface - - surface_area = fem.assemble_scalar(fem.form(1 * ds(self.surface.id))) - - self.value = surface_integral / surface_area # avg temp + ) / fem.assemble_scalar( + fem.form(1 * ds(self.surface.id)) + ) # integral over surface / surface area self.data.append(self.value) From 0e2fa61337e61497ed046e4340d1ce07c707479a Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 27 Oct 2025 10:25:25 -0400 Subject: [PATCH 82/83] add changes erased in resolve conflicts --- src/festim/hydrogen_transport_problem.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index b6d0fb237..8d1b879eb 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1608,13 +1608,17 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface(interface.id) + ) * dInterface( + interface.id + ) F_0 += ( 2 * gamma @@ -1719,6 +1723,11 @@ def initialise_exports(self): # HydrogenTransportProblem for export in self.exports: if isinstance(export, exports.SurfaceQuantity): + if isinstance(export, exports.AverageSurfaceTemperature): + raise NotImplementedError( + f"Export type {type(export)} not implemented for " + f"mixed-domain approach" + ) volume = self.surface_to_volume[export.surface] D = volume.material.get_diffusion_coefficient( self.mesh.mesh, self.temperature_fenics, export.field @@ -1830,9 +1839,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert export.subdomain, ( - "Profile1DExport requires a subdomain to be set" - ) + assert ( + export.subdomain + ), "Profile1DExport requires a subdomain to be set" u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index( From c7b5464f248e97ea020e7cd6ffbfb18d6cde81f5 Mon Sep 17 00:00:00 2001 From: kaelyndunnell Date: Mon, 27 Oct 2025 10:26:59 -0400 Subject: [PATCH 83/83] ruff --- src/festim/hydrogen_transport_problem.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 8d1b879eb..0727d8e33 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -1608,17 +1608,13 @@ def mixed_term(u, v, n): interface.id ) - 0.5 * mixed_term( v_b, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( interface.id ) - 0.5 * mixed_term( v_t, (u_b / K_b - u_t / K_t), n_0 - ) * dInterface( - interface.id - ) + ) * dInterface(interface.id) F_0 += ( 2 * gamma @@ -1839,9 +1835,9 @@ def post_processing(self): export.write(t=float(self.t)) elif isinstance(export, exports.Profile1DExport): - assert ( - export.subdomain - ), "Profile1DExport requires a subdomain to be set" + assert export.subdomain, ( + "Profile1DExport requires a subdomain to be set" + ) u = export.subdomain.u if export._dofs is None: index = self.subdomain_to_species[export.subdomain].index(