你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 15:10:13 +08:00
177 行
5.6 KiB
Python
177 行
5.6 KiB
Python
from os import PathLike
|
|
from pathlib import Path
|
|
from shutil import copyfile
|
|
from typing import Literal, Optional, Union
|
|
|
|
import reframe.utility.sanity as sn
|
|
from reframe.core.runtime import runtime
|
|
from reframe.utility import osext
|
|
|
|
|
|
class RegressionCheck:
|
|
"""Compare two files using diff"""
|
|
|
|
def __init__(
|
|
self, output_file: Union[str, PathLike], reference_file: Union[str, PathLike]
|
|
) -> None:
|
|
"""Create a new regression check.
|
|
|
|
Args:
|
|
output_file: Path to output file generate by the test.
|
|
reference_file: Path to reference file to run the regression
|
|
check against.
|
|
"""
|
|
self.output_file = Path(output_file)
|
|
self.reference_file = Path(reference_file)
|
|
self.cmd = "diff"
|
|
self.options: list[str] = []
|
|
|
|
@property
|
|
def error_msg(self) -> str:
|
|
"""Message to display if the regression check fails"""
|
|
return "Failed regression check"
|
|
|
|
def create_reference_file(self) -> bool:
|
|
"""Create reference file if it does not already exist.
|
|
|
|
The reference file is created as a copy of the current output
|
|
file.
|
|
|
|
Returns:
|
|
file_created: Returns True if a new file was created, False
|
|
if the path already exists.
|
|
"""
|
|
if not sn.path_exists(self.reference_file):
|
|
self.reference_file.parent.mkdir(parents=True, exist_ok=True)
|
|
copyfile(self.output_file, self.reference_file)
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def reference_file_exists(self) -> bool:
|
|
"""Check if the reference file exists.
|
|
|
|
Returns:
|
|
file_exists: Returns true if the reference filepath is a
|
|
regular file, False otherwise.
|
|
"""
|
|
return sn.path_isfile(self.reference_file)
|
|
|
|
def run(self) -> Literal[True]:
|
|
"""Run the regression check.
|
|
|
|
Returns:
|
|
check_passed: Returns True if the output file matches the
|
|
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.
|
|
"""
|
|
|
|
completed_process = osext.run_command(
|
|
[
|
|
self.cmd,
|
|
*self.options,
|
|
str(self.output_file.absolute()),
|
|
str(self.reference_file),
|
|
]
|
|
)
|
|
|
|
return sn.assert_true(
|
|
sn.path_isfile(self.output_file),
|
|
f"Expected output file '{self.output_file}' does not exist",
|
|
) and sn.assert_false(
|
|
completed_process.stdout,
|
|
(
|
|
f"{self.error_msg}\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 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
|
|
in the same file.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
output_file: Union[str, PathLike],
|
|
reference_file: Union[str, PathLike],
|
|
output_receiver: str,
|
|
reference_receiver: Optional[str] = None,
|
|
) -> None:
|
|
"""Create a new receiver regression check.
|
|
|
|
Args:
|
|
output_file: Path to output file generate by the test.
|
|
reference_file: Path to reference file to run the regression
|
|
check against.
|
|
output_receiver: Output receiver to check.
|
|
reference_receiver: Optional receiver to check against in
|
|
the reference file. If None, this will be the same as
|
|
the output receiver.
|
|
"""
|
|
super().__init__(output_file, reference_file)
|
|
|
|
self.output_receiver = output_receiver
|
|
self.reference_receiver = reference_receiver
|
|
|
|
self.options.append(f"rxs/{self.output_receiver}")
|
|
if self.reference_receiver is not None:
|
|
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(H5RegressionCheck):
|
|
"""Run regression check on a gprMax Snapshot."""
|
|
|
|
@property
|
|
def error_msg(self) -> str:
|
|
return f"Snapshot '{self.output_file.name}' failed regression check"
|
|
|
|
|
|
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"
|