added musrview png ref test via ctest
All checks were successful
Build and Deploy Documentation / build-and-deploy (push) Successful in 27s
@@ -1,2 +1,3 @@
|
||||
#--- musrfit integration tests ------------------------------------------------
|
||||
add_subdirectory(maxLH_check)
|
||||
add_subdirectory(musrview_check)
|
||||
|
||||
124
tests/musrview_check/CMakeLists.txt
Normal file
@@ -0,0 +1,124 @@
|
||||
#--- musrview PNG integration tests -------------------------------------------
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
#--- helper macro -------------------------------------------------------------
|
||||
# add_musrview_test(test_name msr_file [extra_musrview_args...])
|
||||
# msr_file is relative to ${CMAKE_SOURCE_DIR}/doc/examples.
|
||||
# extra args (e.g. -f, -a) are forwarded directly to musrview.
|
||||
macro(add_musrview_test test_name msr_file)
|
||||
add_test(
|
||||
NAME ${test_name}
|
||||
COMMAND Python3::Interpreter
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/musrview_check.py
|
||||
$<TARGET_FILE:musrview>
|
||||
${CMAKE_SOURCE_DIR}/doc/examples/${msr_file}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ref
|
||||
${test_name}
|
||||
--tol 0.01
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/doc/examples
|
||||
)
|
||||
endmacro()
|
||||
|
||||
#--- doc/examples tests -------------------------------------------------------
|
||||
|
||||
# single histogram fits
|
||||
add_musrview_test(musrview-histo-MusrRoot test-histo-MusrRoot.msr)
|
||||
add_musrview_test(musrview-histo-MusrRoot-fourier test-histo-MusrRoot.msr -f)
|
||||
add_musrview_test(musrview-histo-MusrRoot-fourier-avg test-histo-MusrRoot.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN test-histo-PSI-BIN.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-fourier test-histo-PSI-BIN.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-fourier-avg test-histo-PSI-BIN.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-ROOT-NPP test-histo-ROOT-NPP.msr)
|
||||
add_musrview_test(musrview-histo-ROOT-NPP-fourier test-histo-ROOT-NPP.msr -f)
|
||||
add_musrview_test(musrview-histo-ROOT-NPP-fourier-avg test-histo-ROOT-NPP.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-HAL9500 test-histo-HAL9500.msr)
|
||||
add_musrview_test(musrview-histo-HAL9500-fourier test-histo-HAL9500.msr -f)
|
||||
add_musrview_test(musrview-histo-HAL9500-fourier-avg test-histo-HAL9500.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-HAL9500-RRF test-histo-HAL9500-RRF.msr)
|
||||
add_musrview_test(musrview-histo-HAL9500-RRF-fourier test-histo-HAL9500-RRF.msr -f)
|
||||
add_musrview_test(musrview-histo-HAL9500-RRF-fourier-avg test-histo-HAL9500-RRF.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-muMinus test-histo-muMinus.msr)
|
||||
add_musrview_test(musrview-histo-muMinus-fourier test-histo-muMinus.msr -f)
|
||||
add_musrview_test(musrview-histo-muMinus-fourier-avg test-histo-muMinus.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-NeXus test-histo-NeXus.msr)
|
||||
add_musrview_test(musrview-histo-NeXus-fourier test-histo-NeXus.msr -f)
|
||||
add_musrview_test(musrview-histo-NeXus-fourier-avg test-histo-NeXus.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-NeXus2 test-histo-NeXus2.msr)
|
||||
add_musrview_test(musrview-histo-NeXus2-fourier test-histo-NeXus2.msr -f)
|
||||
add_musrview_test(musrview-histo-NeXus2-fourier-avg test-histo-NeXus2.msr -f -a)
|
||||
|
||||
# asymmetry fits
|
||||
add_musrview_test(musrview-asy-PSI-BIN test-asy-PSI-BIN.msr)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-fourier test-asy-PSI-BIN.msr -f)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-fourier-avg test-asy-PSI-BIN.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-asy-MUD test-asy-MUD.msr)
|
||||
add_musrview_test(musrview-asy-MUD-fourier test-asy-MUD.msr -f)
|
||||
add_musrview_test(musrview-asy-MUD-fourier-avg test-asy-MUD.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-asy-NeXus2 test-asy-NeXus2.msr)
|
||||
add_musrview_test(musrview-asy-NeXus2-fourier test-asy-NeXus2.msr -f)
|
||||
add_musrview_test(musrview-asy-NeXus2-fourier-avg test-asy-NeXus2.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-asy-HAL9500-RRF test-asy-HAL9500-RRF.msr)
|
||||
add_musrview_test(musrview-asy-HAL9500-RRF-fourier test-asy-HAL9500-RRF.msr -f)
|
||||
add_musrview_test(musrview-asy-HAL9500-RRF-fourier-avg test-asy-HAL9500-RRF.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-asy-LF-BaB6 test-asy-LF-BaB6.msr)
|
||||
add_musrview_test(musrview-asy-LF-BaB6-fourier test-asy-LF-BaB6.msr -f)
|
||||
add_musrview_test(musrview-asy-LF-BaB6-fourier-avg test-asy-LF-BaB6.msr -f -a)
|
||||
|
||||
#--- doc/examples/ViewOpts tests ----------------------------------------------
|
||||
|
||||
add_musrview_test(musrview-asy-PSI-BIN-range ViewOpts/test-asy-PSI-BIN-range.msr)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-range-fourier ViewOpts/test-asy-PSI-BIN-range.msr -f)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-range-fourier-avg ViewOpts/test-asy-PSI-BIN-range.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-asy-PSI-BIN-use_fit_ranges ViewOpts/test-asy-PSI-BIN-use_fit_ranges.msr)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-use_fit_ranges-fourier ViewOpts/test-asy-PSI-BIN-use_fit_ranges.msr -f)
|
||||
add_musrview_test(musrview-asy-PSI-BIN-use_fit_ranges-fourier-avg ViewOpts/test-asy-PSI-BIN-use_fit_ranges.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-lc ViewOpts/test-histo-PSI-BIN-no-scale-range-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-lc-fourier ViewOpts/test-histo-PSI-BIN-no-scale-range-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-no-scale-range-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-no-lc ViewOpts/test-histo-PSI-BIN-no-scale-range-no-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-no-lc-fourier ViewOpts/test-histo-PSI-BIN-no-scale-range-no-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-no-scale-range-no-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-no-scale-range-no-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-range-lc ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-range-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-range-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-range-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-range-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-range-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-ufr-lc ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-use_fit_ranges-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-ufr-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-use_fit_ranges-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-fitRangeBin-ufr-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-fitRangeBin-use_fit_ranges-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-lc ViewOpts/test-histo-PSI-BIN-scale-range-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-range-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-range-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-no-lc ViewOpts/test-histo-PSI-BIN-scale-range-no-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-no-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-range-no-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-range-no-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-range-no-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-sub_ranges-lc ViewOpts/test-histo-PSI-BIN-scale-sub_ranges-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-sub_ranges-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-sub_ranges-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-sub_ranges-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-sub_ranges-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-lc ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-lifetimecorrection.msr -f -a)
|
||||
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-no-lc ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-no-lifetimecorrection.msr)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-no-lc-fourier ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-no-lifetimecorrection.msr -f)
|
||||
add_musrview_test(musrview-histo-PSI-BIN-scale-ufr-no-lc-fourier-avg ViewOpts/test-histo-PSI-BIN-scale-use_fit_ranges-no-lifetimecorrection.msr -f -a)
|
||||
144
tests/musrview_check/musrview_check.py
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Runs musrview --png on a given msr-file, then compares the generated PNGs
|
||||
against reference images using pixel-level comparison (Pillow).
|
||||
|
||||
Usage:
|
||||
musrview_check.py <musrview> <msr-file> <ref-dir> <test-name>
|
||||
[--tol T] [--generate] [musrview-opts...]
|
||||
|
||||
Modes:
|
||||
default Compare generated PNGs against references in <ref-dir>/<test-name>/
|
||||
--generate Generate reference PNGs into <ref-dir>/<test-name>/ (no comparison)
|
||||
|
||||
Tolerance metric: mean absolute pixel difference normalised to [0, 1].
|
||||
0.0 = identical, 1.0 = maximally different. Default tolerance: 0.01 (~1%).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
def pixel_diff(img_a_path, img_b_path):
|
||||
"""Return the mean absolute pixel difference normalised to [0, 1]."""
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
a = np.asarray(Image.open(img_a_path).convert("RGBA"), dtype=np.float64)
|
||||
b = np.asarray(Image.open(img_b_path).convert("RGBA"), dtype=np.float64)
|
||||
|
||||
if a.shape != b.shape:
|
||||
return 1.0 # completely different dimensions
|
||||
|
||||
return np.mean(np.abs(a - b)) / 255.0
|
||||
|
||||
|
||||
def main():
|
||||
# ---- argument parsing ----------------------------------------------------
|
||||
parser = argparse.ArgumentParser(description="musrview PNG integration test")
|
||||
parser.add_argument("musrview", help="path to musrview executable")
|
||||
parser.add_argument("msr_file", help="path to msr input file")
|
||||
parser.add_argument("ref_dir", help="root reference directory")
|
||||
parser.add_argument("test_name", help="test name (subdirectory in ref_dir)")
|
||||
parser.add_argument("--tol", type=float, default=0.01,
|
||||
help="tolerance for pixel comparison (default 0.01)")
|
||||
parser.add_argument("--generate", action="store_true",
|
||||
help="generate reference PNGs instead of comparing")
|
||||
|
||||
# everything after the known args is forwarded to musrview
|
||||
args, musrview_opts = parser.parse_known_args()
|
||||
|
||||
msr_basename = os.path.splitext(os.path.basename(args.msr_file))[0]
|
||||
ref_subdir = os.path.join(args.ref_dir, args.test_name)
|
||||
|
||||
# ---- run musrview in a temporary directory -------------------------------
|
||||
work_dir = os.path.dirname(os.path.abspath(args.msr_file))
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
# snapshot existing PNGs so we only pick up newly created ones
|
||||
pre_existing = set(glob.glob(os.path.join(work_dir, f"{msr_basename}_*.png")))
|
||||
|
||||
cmd = [args.musrview, args.msr_file, "--png"] + musrview_opts
|
||||
print(f"running: {' '.join(cmd)}")
|
||||
result = subprocess.run(cmd, capture_output=True, text=True,
|
||||
cwd=work_dir,
|
||||
env={**os.environ, "MUSRVIEW_PNG_DIR": tmp_dir})
|
||||
if result.returncode != 0:
|
||||
print(f"**ERROR** musrview returned exit code {result.returncode}")
|
||||
print(result.stdout + result.stderr)
|
||||
return 1
|
||||
|
||||
# collect only newly created PNGs (exclude pre-existing ones)
|
||||
generated = sorted(
|
||||
p for p in glob.glob(os.path.join(work_dir, f"{msr_basename}_*.png"))
|
||||
if p not in pre_existing
|
||||
)
|
||||
if not generated:
|
||||
generated = sorted(glob.glob(os.path.join(tmp_dir, f"{msr_basename}_*.png")))
|
||||
if not generated:
|
||||
print(f"**ERROR** no PNGs matching '{msr_basename}_*.png' found")
|
||||
print(f" checked: {work_dir}")
|
||||
if result.stdout:
|
||||
print(result.stdout)
|
||||
return 1
|
||||
|
||||
# ---- generate mode ---------------------------------------------------
|
||||
if args.generate:
|
||||
os.makedirs(ref_subdir, exist_ok=True)
|
||||
for png in generated:
|
||||
dst = os.path.join(ref_subdir, os.path.basename(png))
|
||||
shutil.copy2(png, dst)
|
||||
print(f" saved reference: {dst}")
|
||||
# clean up generated PNGs from work_dir
|
||||
for png in generated:
|
||||
if os.path.dirname(os.path.abspath(png)) == os.path.abspath(work_dir):
|
||||
os.remove(png)
|
||||
print(f"GENERATE: {len(generated)} reference PNG(s) written to {ref_subdir}")
|
||||
return 0
|
||||
|
||||
# ---- compare mode ----------------------------------------------------
|
||||
if not os.path.isdir(ref_subdir):
|
||||
print(f"**ERROR** reference directory not found: {ref_subdir}")
|
||||
return 1
|
||||
|
||||
failures = 0
|
||||
compared = 0
|
||||
for png_path in generated:
|
||||
name = os.path.basename(png_path)
|
||||
ref_path = os.path.join(ref_subdir, name)
|
||||
if not os.path.isfile(ref_path):
|
||||
print(f"FAIL: no reference PNG for {name}")
|
||||
failures += 1
|
||||
continue
|
||||
|
||||
diff = pixel_diff(png_path, ref_path)
|
||||
compared += 1
|
||||
if diff > args.tol:
|
||||
print(f"FAIL: {name} diff={diff:.6f} > tol={args.tol:.6f}")
|
||||
failures += 1
|
||||
else:
|
||||
print(f"PASS: {name} diff={diff:.6f} <= tol={args.tol:.6f}")
|
||||
|
||||
# clean up generated PNGs from work_dir
|
||||
for png in generated:
|
||||
if os.path.dirname(os.path.abspath(png)) == os.path.abspath(work_dir):
|
||||
os.remove(png)
|
||||
|
||||
if compared == 0:
|
||||
print("**ERROR** no PNGs were compared")
|
||||
return 1
|
||||
|
||||
if failures:
|
||||
print(f"\n{failures} of {len(generated)} PNG(s) FAILED")
|
||||
return 1
|
||||
|
||||
print(f"\nAll {compared} PNG(s) PASSED (tol={args.tol})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
BIN
tests/musrview_check/ref/musrview-asy-MUD/test-asy-MUD_0.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 28 KiB |