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/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.regression_checks import (
GeometryObjectMaterialsRegressionCheck,
GeometryObjectRegressionCheck,
GeometryViewRegressionCheck,
H5RegressionCheck,
ReceiverRegressionCheck,
RegressionCheck,
SnapshotRegressionCheck,
)
@@ -38,7 +40,7 @@ class ReceiverMixin(GprMaxMixin):
)
self.regression_checks.append(regression_check)
else:
regression_check = RegressionCheck(self.output_file, reference_file)
regression_check = H5RegressionCheck(self.output_file, reference_file)
self.regression_checks.append(regression_check)
@@ -86,6 +88,61 @@ class GeometryOnlyMixin(GprMaxMixin):
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):
"""Add regression tests for geometry views.

查看文件

@@ -9,7 +9,7 @@ from reframe.utility import osext
class RegressionCheck:
"""Compare two hdf5 files using h5diff"""
"""Compare two files using diff"""
def __init__(
self, output_file: Union[str, PathLike], reference_file: Union[str, PathLike]
@@ -23,7 +23,8 @@ class RegressionCheck:
"""
self.output_file = Path(output_file)
self.reference_file = Path(reference_file)
self.h5diff_options: list[str] = []
self.cmd = "diff"
self.options: list[str] = []
@property
def error_msg(self) -> str:
@@ -57,26 +58,22 @@ class RegressionCheck:
return sn.path_isfile(self.reference_file)
def run(self) -> Literal[True]:
"""Run the regression check using h5diff.
"""Run the regression check.
Returns:
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:
reframe.core.exceptions.SanityError: If the output file does
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.h5diff_options,
self.cmd,
*self.options,
str(self.output_file.absolute()),
str(self.reference_file),
]
@@ -86,16 +83,29 @@ class RegressionCheck:
sn.path_isfile(self.output_file),
f"Expected output file '{self.output_file}' does not exist",
) and sn.assert_false(
h5diff_output.stdout,
completed_process.stdout,
(
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."
),
)
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.
This can include arbitrary receivers in each file, or two receivers
@@ -106,7 +116,7 @@ class ReceiverRegressionCheck(RegressionCheck):
self,
output_file: Union[str, PathLike],
reference_file: Union[str, PathLike],
output_receiver: Optional[str],
output_receiver: str,
reference_receiver: Optional[str] = None,
) -> None:
"""Create a new receiver regression check.
@@ -125,26 +135,42 @@ class ReceiverRegressionCheck(RegressionCheck):
self.output_receiver = output_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:
self.h5diff_options.append(f"rxs/{self.reference_receiver}")
self.options.append(f"rxs/{self.reference_receiver}")
@property
def error_msg(self) -> str:
return f"Receiver '{self.output_receiver}' failed regression check"
class SnapshotRegressionCheck(RegressionCheck):
class SnapshotRegressionCheck(H5RegressionCheck):
"""Run regression check on a gprMax Snapshot."""
@property
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."""
@property
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.mixins import (
GeometryObjectMixin,
GeometryOnlyMixin,
GeometryViewMixin,
ReceiverMixin,
@@ -17,3 +18,7 @@ class GprMaxSnapshotTest(SnapshotMixin, GprMaxBaseTest):
class GprMaxGeometryViewTest(GeometryViewMixin, GeometryOnlyMixin, GprMaxBaseTest):
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