Add geometry object reframe tests

这个提交包含在:
nmannall
2024-12-05 12:14:55 +00:00
父节点 8b038f09c3
当前提交 98507608e5
共有 10 个文件被更改,包括 174 次插入23 次删除

2
.gitattributes vendored
查看文件

@@ -2,3 +2,5 @@ tools/Jupyter_notebooks/* linguist-vendored
reframe_tests/regression_checks/TestGeometryView_5176823e/partial_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text reframe_tests/regression_checks/TestGeometryView_5176823e/partial_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
reframe_tests/regression_checks/TestGeometryView_5176823e/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text reframe_tests/regression_checks/TestGeometryView_5176823e/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
reframe_tests/regression_checks/TestGeometryView_77980202/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text reframe_tests/regression_checks/TestGeometryView_77980202/full_volume.vtkhdf filter=lfs diff=lfs merge=lfs -text
reframe_tests/regression_checks/TestGeometryObject_a6a096cb/full_volume.h5 filter=lfs diff=lfs merge=lfs -text
reframe_tests/regression_checks/TestGeometryObject_a6a096cb/partial_volume.h5 filter=lfs diff=lfs merge=lfs -text

查看文件

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ac30e1b942acb3e17bec7d2a16167429ed3b1590642d9c403ee5d0adb6be27c8
size 75462640

查看文件

@@ -0,0 +1,9 @@
#material: 1 inf 1 0 pec
#material: 1 0 1 0 free_space
#material: 4.9 0 1 0 myWater
#material: 3 0 2 0 boxMaterial
#material: 1.5 0 1.25 0 boxMaterial+free_space+free_space+free_space
#material: 2 0 1.5 0 boxMaterial+free_space+free_space+boxMaterial
#material: 1.975 0 1 0 myWater+free_space+free_space+free_space
#material: 2.95 0 1 0 myWater+free_space+free_space+myWater
#material: 3.925 0 1 0 myWater+myWater+free_space+myWater

查看文件

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:224975ddea1c1a4cd3f99aaa9e7ce1fb1ec31de07b0352424f66be73a5645a4f
size 4980400

查看文件

@@ -0,0 +1,9 @@
#material: 1 inf 1 0 pec
#material: 1 0 1 0 free_space
#material: 4.9 0 1 0 myWater
#material: 3 0 2 0 boxMaterial
#material: 1.5 0 1.25 0 boxMaterial+free_space+free_space+free_space
#material: 2 0 1.5 0 boxMaterial+free_space+free_space+boxMaterial
#material: 1.975 0 1 0 myWater+free_space+free_space+free_space
#material: 2.95 0 1 0 myWater+free_space+free_space+myWater
#material: 3.925 0 1 0 myWater+myWater+free_space+myWater

查看文件

@@ -9,9 +9,11 @@ from typing_extensions import TYPE_CHECKING
from reframe_tests.tests.base_tests import GprMaxBaseTest from reframe_tests.tests.base_tests import GprMaxBaseTest
from reframe_tests.tests.regression_checks import ( from reframe_tests.tests.regression_checks import (
GeometryObjectMaterialsRegressionCheck,
GeometryObjectRegressionCheck,
GeometryViewRegressionCheck, GeometryViewRegressionCheck,
H5RegressionCheck,
ReceiverRegressionCheck, ReceiverRegressionCheck,
RegressionCheck,
SnapshotRegressionCheck, SnapshotRegressionCheck,
) )
@@ -38,7 +40,7 @@ class ReceiverMixin(GprMaxMixin):
) )
self.regression_checks.append(regression_check) self.regression_checks.append(regression_check)
else: else:
regression_check = RegressionCheck(self.output_file, reference_file) regression_check = H5RegressionCheck(self.output_file, reference_file)
self.regression_checks.append(regression_check) self.regression_checks.append(regression_check)
@@ -86,6 +88,61 @@ class GeometryOnlyMixin(GprMaxMixin):
self.executable_opts += ["--geometry-only"] self.executable_opts += ["--geometry-only"]
class GeometryObjectMixin(GprMaxMixin):
"""Add regression tests for geometry objects.
Attributes:
geometry_objects (list[str]): List of geometry objects to run
regression checks on.
"""
geometry_objects = variable(typ.List[str], value=[])
def build_geometry_object_filepath(self, geometry_object: str) -> Path:
"""Build filepath to the specified geometry object.
Args:
geometry_object: Name of the geometry object.
"""
return Path(geometry_object).with_suffix(".h5")
def build_materials_filepath(self, geometry_object: str) -> Path:
"""Build filepath to the materials output by the geometry object.
Args:
geometry_object: Name of the geometry object.
"""
return Path(f"{geometry_object}_materials").with_suffix(".txt")
@run_after("setup")
def add_geometry_object_regression_checks(self):
"""Add a regression check for each geometry object.
The test will be skipped if no geometry objects have been specified.
"""
self.skip_if(
len(self.geometry_objects) < 0,
f"Must provide a list of geometry objects.",
)
for geometry_object in self.geometry_objects:
# Add materials regression check first as if this fails,
# checking the .h5 file will almost definitely fail.
materials_file = self.build_materials_filepath(geometry_object)
materials_reference_file = self.build_reference_filepath(
materials_file.name, suffix=materials_file.suffix
)
materials_regression_check = GeometryObjectMaterialsRegressionCheck(
materials_file, materials_reference_file
)
self.regression_checks.append(materials_regression_check)
geometry_object_file = self.build_geometry_object_filepath(geometry_object)
reference_file = self.build_reference_filepath(geometry_object)
regression_check = GeometryObjectRegressionCheck(geometry_object_file, reference_file)
self.regression_checks.append(regression_check)
class GeometryViewMixin(GprMaxMixin): class GeometryViewMixin(GprMaxMixin):
"""Add regression tests for geometry views. """Add regression tests for geometry views.

查看文件

@@ -9,7 +9,7 @@ from reframe.utility import osext
class RegressionCheck: class RegressionCheck:
"""Compare two hdf5 files using h5diff""" """Compare two files using diff"""
def __init__( def __init__(
self, output_file: Union[str, PathLike], reference_file: Union[str, PathLike] self, output_file: Union[str, PathLike], reference_file: Union[str, PathLike]
@@ -23,7 +23,8 @@ class RegressionCheck:
""" """
self.output_file = Path(output_file) self.output_file = Path(output_file)
self.reference_file = Path(reference_file) self.reference_file = Path(reference_file)
self.h5diff_options: list[str] = [] self.cmd = "diff"
self.options: list[str] = []
@property @property
def error_msg(self) -> str: def error_msg(self) -> str:
@@ -57,26 +58,22 @@ class RegressionCheck:
return sn.path_isfile(self.reference_file) return sn.path_isfile(self.reference_file)
def run(self) -> Literal[True]: def run(self) -> Literal[True]:
"""Run the regression check using h5diff. """Run the regression check.
Returns: Returns:
check_passed: Returns True if the output file matches the check_passed: Returns True if the output file matches the
reference file (i.e. no output from h5diff). Otherwise, reference file (i.e. no output from diff). Otherwise,
raises a SanityError. raises a SanityError.
Raises: Raises:
reframe.core.exceptions.SanityError: If the output file does reframe.core.exceptions.SanityError: If the output file does
not exist, or the regression check fails. not exist, or the regression check fails.
""" """
if runtime().system.name == "archer2":
h5diff = "/opt/cray/pe/hdf5/default/bin/h5diff"
else:
h5diff = "h5diff"
h5diff_output = osext.run_command( completed_process = osext.run_command(
[ [
h5diff, self.cmd,
*self.h5diff_options, *self.options,
str(self.output_file.absolute()), str(self.output_file.absolute()),
str(self.reference_file), str(self.reference_file),
] ]
@@ -86,16 +83,29 @@ class RegressionCheck:
sn.path_isfile(self.output_file), sn.path_isfile(self.output_file),
f"Expected output file '{self.output_file}' does not exist", f"Expected output file '{self.output_file}' does not exist",
) and sn.assert_false( ) and sn.assert_false(
h5diff_output.stdout, completed_process.stdout,
( (
f"{self.error_msg}\n" f"{self.error_msg}\n"
f"For more details run: '{' '.join(h5diff_output.args)}'\n" f"For more details run: '{' '.join(completed_process.args)}'\n"
f"To re-create regression file, delete '{self.reference_file}' and rerun the test." f"To re-create regression file, delete '{self.reference_file}' and rerun the test."
), ),
) )
class ReceiverRegressionCheck(RegressionCheck): class H5RegressionCheck(RegressionCheck):
"""Compare two hdf5 files using h5diff"""
def __init__(
self, output_file: Union[str, PathLike], reference_file: Union[str, PathLike]
) -> None:
super().__init__(output_file, reference_file)
if runtime().system.name == "archer2":
self.cmd = "/opt/cray/pe/hdf5/default/bin/h5diff"
else:
self.cmd = "h5diff"
class ReceiverRegressionCheck(H5RegressionCheck):
"""Run regression check on individual reveivers in output files. """Run regression check on individual reveivers in output files.
This can include arbitrary receivers in each file, or two receivers This can include arbitrary receivers in each file, or two receivers
@@ -106,7 +116,7 @@ class ReceiverRegressionCheck(RegressionCheck):
self, self,
output_file: Union[str, PathLike], output_file: Union[str, PathLike],
reference_file: Union[str, PathLike], reference_file: Union[str, PathLike],
output_receiver: Optional[str], output_receiver: str,
reference_receiver: Optional[str] = None, reference_receiver: Optional[str] = None,
) -> None: ) -> None:
"""Create a new receiver regression check. """Create a new receiver regression check.
@@ -125,26 +135,42 @@ class ReceiverRegressionCheck(RegressionCheck):
self.output_receiver = output_receiver self.output_receiver = output_receiver
self.reference_receiver = reference_receiver self.reference_receiver = reference_receiver
self.h5diff_options.append(f"rxs/{self.output_receiver}") self.options.append(f"rxs/{self.output_receiver}")
if self.reference_receiver is not None: if self.reference_receiver is not None:
self.h5diff_options.append(f"rxs/{self.reference_receiver}") self.options.append(f"rxs/{self.reference_receiver}")
@property @property
def error_msg(self) -> str: def error_msg(self) -> str:
return f"Receiver '{self.output_receiver}' failed regression check" return f"Receiver '{self.output_receiver}' failed regression check"
class SnapshotRegressionCheck(RegressionCheck): class SnapshotRegressionCheck(H5RegressionCheck):
"""Run regression check on a gprMax Snapshot.""" """Run regression check on a gprMax Snapshot."""
@property @property
def error_msg(self) -> str: def error_msg(self) -> str:
return f"Snapshot '{self.output_file.name}' failed regression check " return f"Snapshot '{self.output_file.name}' failed regression check"
class GeometryViewRegressionCheck(RegressionCheck): class GeometryObjectRegressionCheck(H5RegressionCheck):
"""Run regression check on a GprMax GeometryObject."""
@property
def error_msg(self) -> str:
return f"GeometryObject '{self.output_file.name}' failed regression check"
class GeometryObjectMaterialsRegressionCheck(RegressionCheck):
"""Run regression check on materials output by a GeometryObject."""
@property
def error_msg(self) -> str:
return f"GeometryObject materials file '{self.output_file}' failed regression check"
class GeometryViewRegressionCheck(H5RegressionCheck):
"""Run regression check on a GprMax GeometryView.""" """Run regression check on a GprMax GeometryView."""
@property @property
def error_msg(self) -> str: def error_msg(self) -> str:
return f"GeometryView '{self.output_file.name}' failed regression check " return f"GeometryView '{self.output_file.name}' failed regression check"

查看文件

@@ -0,0 +1,17 @@
#title: Hertzian dipole in free-space
#domain: 0.100 0.100 0.100
#dx_dy_dz: 0.001 0.001 0.001
#time_window: 3e-9
#waveform: gaussiandot 1 1e9 myWave
#hertzian_dipole: z 0.050 0.050 0.050 myWave
#material: 4.9 0 1 0 myWater
#material: 2 0 1.4 0 unusedMaterial
#material: 3 0 2 0 boxMaterial
#sphere: 0.05 0.05 0.05 0.03 myWater y
#box: 0.01 0.01 0.01 0.09 0.025 0.025 boxMaterial y
#geometry_objects_write: 0.02 0.02 0.02 0.06 0.06 0.06 partial_volume
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume

查看文件

@@ -1,5 +1,6 @@
from reframe_tests.tests.base_tests import GprMaxBaseTest from reframe_tests.tests.base_tests import GprMaxBaseTest
from reframe_tests.tests.mixins import ( from reframe_tests.tests.mixins import (
GeometryObjectMixin,
GeometryOnlyMixin, GeometryOnlyMixin,
GeometryViewMixin, GeometryViewMixin,
ReceiverMixin, ReceiverMixin,
@@ -17,3 +18,7 @@ class GprMaxSnapshotTest(SnapshotMixin, GprMaxBaseTest):
class GprMaxGeometryViewTest(GeometryViewMixin, GeometryOnlyMixin, GprMaxBaseTest): class GprMaxGeometryViewTest(GeometryViewMixin, GeometryOnlyMixin, GprMaxBaseTest):
pass pass
class GprMaxGeometryObjectTest(GeometryObjectMixin, GeometryOnlyMixin, GprMaxBaseTest):
pass

查看文件

@@ -0,0 +1,20 @@
import reframe as rfm
from reframe.core.builtins import parameter
from reframe_tests.tests.mixins import MpiMixin
from reframe_tests.tests.standard_tests import GprMaxGeometryObjectTest
@rfm.simple_test
class TestGeometryObject(GprMaxGeometryObjectTest):
tags = {"test", "serial", "geometry only", "geometry object"}
sourcesdir = "src/geometry_object_tests"
model = parameter(["geometry_object_write"])
geometry_objects = ["partial_volume", "full_volume"]
@rfm.simple_test
class TestGeometryObjectMPI(MpiMixin, TestGeometryObject):
tags = {"test", "mpi", "geometry only", "geometry object"}
mpi_layout = parameter([[2, 2, 2], [4, 4, 1]])
test_dependency = TestGeometryObject