From 0b2f3c7bf23bb06745b5719398f03729b909b96b Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Fri, 14 Aug 2026 15:53:33 +0200 Subject: [PATCH 1/8] test: Fix missing protagation of return status when calling pytest in ./test.py --- pytools/idfx_test_run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytools/idfx_test_run.py b/pytools/idfx_test_run.py index 25071612..03a3cef6 100644 --- a/pytools/idfx_test_run.py +++ b/pytools/idfx_test_run.py @@ -365,7 +365,7 @@ def main(self, all: bool = False): os.environ["IDEFIX_TEST_FILTER_SUBDIR"] = idefixTest.filterSubdir if idefixTest.all: - pytest.main( + status = pytest.main( [ "-v", "--no-header", @@ -375,6 +375,7 @@ def main(self, all: bool = False): + idefixTest.remainingArgs + [self.parentScritFile] ) + sys.exit(status) else: raise NotImplementedError("Not yet supported !") # elif self.check: From b24f5e29521f038ae29b6f23bdc4f3d2ced80a90 Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Fri, 14 Aug 2026 13:53:47 +0200 Subject: [PATCH 2/8] fix: fix an issue coming from the previous refactoring about accessing a GPU buffer on CPU --- src/fluid/boundary/axis.cpp | 8 ++++---- src/mpi/buffer.hpp | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/fluid/boundary/axis.cpp b/src/fluid/boundary/axis.cpp index 45ea49ea..d95cf484 100644 --- a/src/fluid/boundary/axis.cpp +++ b/src/fluid/boundary/axis.cpp @@ -491,12 +491,12 @@ void Axis::ExchangeMPI(int side) { //unpack Vs face-centered BoundingBox recvBoxVsIdir = baseBox; recvBoxVsIdir[IDIR][1] += 1; - bufferRecv.UnpackJDirSymetric(Vs, IDIR, sVs(IDIR), recvBoxVsIdir); + bufferRecv.UnpackJDirSymetric(Vs, IDIR, sVs, recvBoxVsIdir); //unpack Vs face-centered BoundingBox recvBoxVsKdir = baseBox; recvBoxVsKdir[KDIR][1] += 1; - bufferRecv.UnpackJDirSymetric(Vs, KDIR, sVs(KDIR), recvBoxVsKdir); + bufferRecv.UnpackJDirSymetric(Vs, KDIR, sVs, recvBoxVsKdir); } } else if(side==right) { //unpack Vc on right part @@ -514,14 +514,14 @@ void Axis::ExchangeMPI(int side) { recvBoxVsIdir[IDIR][1] += 1; recvBoxVsIdir[JDIR][0] += offset; recvBoxVsIdir[JDIR][1] += offset; - bufferRecv.UnpackJDirSymetric(Vs, IDIR, sVs(IDIR), recvBoxVsIdir); + bufferRecv.UnpackJDirSymetric(Vs, IDIR, sVs, recvBoxVsIdir); //unpack Vs face-centered on right part BoundingBox recvBoxVsKdir = baseBox; recvBoxVsKdir[KDIR][1] += 1; recvBoxVsKdir[JDIR][0] += offset; recvBoxVsKdir[JDIR][1] += offset; - bufferRecv.UnpackJDirSymetric(Vs, KDIR, sVs(KDIR), recvBoxVsKdir); + bufferRecv.UnpackJDirSymetric(Vs, KDIR, sVs, recvBoxVsKdir); } // MHD } diff --git a/src/mpi/buffer.hpp b/src/mpi/buffer.hpp index 35164355..b045b86e 100644 --- a/src/mpi/buffer.hpp +++ b/src/mpi/buffer.hpp @@ -165,7 +165,7 @@ class Buffer { void UnpackJDirSymetric(IdefixArray4D& out, const int var, - const int symMultiplier, + IdefixArray1D& SymMap, BoundingBox box) { const int ni = box[IDIR][1]-box[IDIR][0]; const int ninj = (box[JDIR][1]-box[JDIR][0])*ni; @@ -183,6 +183,7 @@ class Buffer { KOKKOS_LAMBDA (int k, int j, int i) { const int jinverted = jend-(j-jbeg)-1; const int arrIndex = i-ibeg + (j-jbeg)*ni + (k-kbeg)*ninj + offset; + const int symMultiplier = SymMap(var); out(var,k,jinverted,i) = symMultiplier * arr(arrIndex); }); From a2421e6c9b659fc26dcd1f9e8573c7a4416af025 Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Fri, 14 Aug 2026 17:18:50 +0200 Subject: [PATCH 3/8] fix: Fix some warnings about unused variabled blocking the test suite --- src/fluid/RiemannSolver/MHDsolvers/storeFlux.hpp | 4 ++-- src/fluid/boundary/axis.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fluid/RiemannSolver/MHDsolvers/storeFlux.hpp b/src/fluid/RiemannSolver/MHDsolvers/storeFlux.hpp index b376befe..e4152dcd 100644 --- a/src/fluid/RiemannSolver/MHDsolvers/storeFlux.hpp +++ b/src/fluid/RiemannSolver/MHDsolvers/storeFlux.hpp @@ -55,8 +55,8 @@ KOKKOS_FORCEINLINE_FUNCTION void K_StoreHLL( const int i, const int j, const int const IdefixArray3D &dL, const IdefixArray3D &dR) { EXPAND( , - constexpr int Xt = (DIR == IDIR ? MX2 : MX1); , - constexpr int Xb = (DIR == KDIR ? MX2 : MX3); ) + [[maybe_unused]] constexpr int Xt = (DIR == IDIR ? MX2 : MX1); , + [[maybe_unused]] constexpr int Xb = (DIR == KDIR ? MX2 : MX3); ) real ar = std::fmax(ZERO_F, sr); real al = std::fmin(ZERO_F, sl); diff --git a/src/fluid/boundary/axis.cpp b/src/fluid/boundary/axis.cpp index d95cf484..a5153d36 100644 --- a/src/fluid/boundary/axis.cpp +++ b/src/fluid/boundary/axis.cpp @@ -392,7 +392,8 @@ void Axis::ExchangeMPI(int side) { idfx::pushRegion("Axis::ExchangeMPI"); #ifdef WITH_MPI // Load the buffers with data - int ibeg,iend,jbeg,jend,kbeg,kend,offset; + [[maybe_unused]] int ibeg,iend,jbeg,jend,kbeg,kend; + int offset; int ny; Buffer bufferSend = this->bufferSend; IdefixArray1D map = this->mapVars; From 118bd3def9763ea94d9459f2a4b11837dc30e6f4 Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Mon, 17 Aug 2026 12:02:26 +0200 Subject: [PATCH 4/8] test: fix utils/lookupTable test by adding possibility to call a python function from testme.json --- doc/source/testing/testLauncher.rst | 33 +++++++++++++++ pytools/idfx_test_run.py | 62 +++++++++++++++++++++++++++++ test/utils/lookupTable/testme.json | 3 +- test/utils/lookupTable/testme.py | 25 ++---------- 4 files changed, 100 insertions(+), 23 deletions(-) diff --git a/doc/source/testing/testLauncher.rst b/doc/source/testing/testLauncher.rst index ffb80ef9..febc0cb8 100644 --- a/doc/source/testing/testLauncher.rst +++ b/doc/source/testing/testLauncher.rst @@ -191,6 +191,12 @@ In addition there is some extra keys which are dedicated to the json interpretat * - ``multirun`` - ``{}`` - See the multi-run section below. + * - ``callPyFunctionBefore`` + - + - Call a python function before executing the test (see dedicated section at the end of this file). + * - ``callPyFunctionAfter`` + - + - Call a python function after executing the test (see dedicated section at the end of this file). Looping over parameters ----------------------- @@ -374,6 +380,33 @@ They are described like : }, } +Calling a Python function +------------------------- + +In some cases (example in ``test/utils/lookupTable``) you might need to call a custom +python function before running the test to prepare the data or after the test to perform +some extra check. + +You can simply implement the functions you want to call in the python file in the test +directory (ideally named ``testmelib.py``) : + +.. code-block:: python + + def callMeAtStart(): + print("This is called at test start !") + + def callMeAtEnd(): + print("This is called at test end !") + +And add the keys in ``testme.json``: + +.. code-block:: json + + "default": { + "callPyFunctionBefore": "testmelib.py:callMeAtStart", + "callPyFunctionAfter": "testmelib.py:callMeAtEnd" + } + Using the idfxTest options -------------------------- diff --git a/pytools/idfx_test_run.py b/pytools/idfx_test_run.py index 03a3cef6..726dc8b6 100644 --- a/pytools/idfx_test_run.py +++ b/pytools/idfx_test_run.py @@ -7,6 +7,7 @@ import copy import glob +import importlib import json import os import sys @@ -135,6 +136,58 @@ def genTests(self) -> list: # ok return result + def buildPyHooks(self, config: dict) -> dict: + # init + result = {} + key: str + + # extract and build dict + for key, value in config.items(): + if key.startswith("callPyFunction"): + when = key.replace("callPyFunction", "") + result[when] = value + + # ok + return result + + # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly + def importFromPath(self, moduleName: str, filePath: str): + spec = importlib.util.spec_from_file_location(moduleName, filePath) + module = importlib.util.module_from_spec(spec) + # sys.modules[moduleName] = module + spec.loader.exec_module(module) + return module + + def callPyHook(self, dir: str, hooks: dict, name: str) -> None: + # nothing to do + if name not in hooks: + return + + # split file:funcName + params = hooks[name].split(":", 1) + filePath = params[0] + funcName = params[1] + + # complete + fileFullPath = os.path.join(dir, filePath) + + # log + print("************** CALLING PY FUNCTION ****************") + print(f"Hook: {name}") + print(f"HookValue: {hooks[name]}") + print(f"Import {fileFullPath}") + print(f"Call: {funcName}") + print("***************************************************") + + # import the module + module = self.importFromPath("idefix_test_py_hooks", fileFullPath) + + # get function + function = getattr(module, funcName) + + # call it + function() + def run(self, config: dict) -> None: # clone before modify to not modity for caller config = copy.deepcopy(config) @@ -155,6 +208,7 @@ def run(self, config: dict) -> None: nonRegressionTestIni = config.get("nonRegressionTestIni", None) check_file_produced = config.get("check_file_produced", []) problemDir = os.path.dirname(testfile) + pyHooks = self.buildPyHooks(config) # cleanup some keyword not handled at the # level of idx_test so we don't perturbate it @@ -169,6 +223,11 @@ def run(self, config: dict) -> None: del config["nonRegressionTest"] if "nonRegressionTestIni" in config: del config["nonRegressionTestIni"] + for hook in pyHooks: + del config[f"callPyFunction{hook}"] + + # call hook before + self.callPyHook(problemDir, pyHooks, "Before") # if switch from test, rebuild the runner (a runner make for one dir) if self.currentTestFile != testfile: @@ -195,6 +254,9 @@ def run(self, config: dict) -> None: f"Don't find expected file to be produced by the run : {file} !" ) + # call hook after + self.callPyHook(problemDir, pyHooks, "After") + def _runNonRegression( self, dumpname, diff --git a/test/utils/lookupTable/testme.json b/test/utils/lookupTable/testme.json index 100e561d..d012528b 100644 --- a/test/utils/lookupTable/testme.json +++ b/test/utils/lookupTable/testme.json @@ -4,6 +4,7 @@ "ini": "idefix.ini", "nonRegressionTest": false, "standardTest": false, - "tolerance": 0 + "tolerance": 0, + "callPyFunctionBefore": "testmelib.py:MakeNumpyFile" } } diff --git a/test/utils/lookupTable/testme.py b/test/utils/lookupTable/testme.py index c02f2b1c..133ea61b 100755 --- a/test/utils/lookupTable/testme.py +++ b/test/utils/lookupTable/testme.py @@ -9,32 +9,13 @@ import sys sys.path.append(os.getenv("IDEFIX_DIR")) -import numpy as np - # from scipy.interpolate import RegularGridInterpolator -import pytools.idfx_test as tst - - -def MakeNumpyFile(): - x = np.arange(1, 10, 1.0) - y = np.arange(5, 10, 1.0) - z = np.arange(2, 5, 1.0) - - xp, yp, zp = np.meshgrid(x, y, z, indexing="ij") - - data = xp + 2 * yp - zp - - np.save("x.npy", x) - np.save("y.npy", y) - np.save("z.npy", z) - np.save("data.npy", data) - # show the expected result - # f=RegularGridInterpolator((x, y, z), data) - # print(f([2.7,7.4,3.9])) +import testmelib +import pytools.idfx_test as tst test = tst.idfxTest(__file__) -MakeNumpyFile() +testmelib.MakeNumpyFile() test.configure() test.compile() From be0a7a1a76163468b5431302512edc711fe0b214 Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Mon, 17 Aug 2026 13:40:00 +0200 Subject: [PATCH 5/8] fix: communication issue introduced during the comm refactoring in recent commit of PR #385. --- src/fluid/constrainedTransport/EMFexchange.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fluid/constrainedTransport/EMFexchange.hpp b/src/fluid/constrainedTransport/EMFexchange.hpp index aad12334..17978380 100644 --- a/src/fluid/constrainedTransport/EMFexchange.hpp +++ b/src/fluid/constrainedTransport/EMFexchange.hpp @@ -75,7 +75,7 @@ void ConstrainedTransport::ExchangeX1(IdefixArray3D ey, IdefixArray3 sendBoxEy[KDIR][1] += 1; sendBoxEy[IDIR][0] = iright; sendBoxEy[IDIR][1] = iright + 1; - BufferRight.Pack(ez, sendBoxEy); + BufferRight.Pack(ey, sendBoxEy); #endif // Wait for completion before sending out everything @@ -239,11 +239,11 @@ void ConstrainedTransport::ExchangeX3(IdefixArray3D ex, IdefixArray3 baseBox[KDIR][1] = data->end[KDIR]; //extend by one the end on jdir && take the ghost on k - BoundingBox sendBoxEz = baseBox; - sendBoxEz[JDIR][1] += 1; - sendBoxEz[KDIR][0] = kright; - sendBoxEz[KDIR][1] = kright + 1; - BufferRight.Pack(ez, sendBoxEz); + BoundingBox sendBoxEx = baseBox; + sendBoxEx[JDIR][1] += 1; + sendBoxEx[KDIR][0] = kright; + sendBoxEx[KDIR][1] = kright + 1; + BufferRight.Pack(ex, sendBoxEx); //extend by one the end on idir && take the ghost on k BoundingBox sendBoxEy = baseBox; From 9ac76feba6366ceda7288ca23135dd0991dd6c9f Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Mon, 17 Aug 2026 13:48:35 +0200 Subject: [PATCH 6/8] fix: add missing new file testmelib.py in test/utils/lookupTable --- test/utils/lookupTable/testmelib.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/utils/lookupTable/testmelib.py diff --git a/test/utils/lookupTable/testmelib.py b/test/utils/lookupTable/testmelib.py new file mode 100644 index 00000000..b4126614 --- /dev/null +++ b/test/utils/lookupTable/testmelib.py @@ -0,0 +1,19 @@ +import numpy as np + + +def MakeNumpyFile(): + x = np.arange(1, 10, 1.0) + y = np.arange(5, 10, 1.0) + z = np.arange(2, 5, 1.0) + + xp, yp, zp = np.meshgrid(x, y, z, indexing="ij") + + data = xp + 2 * yp - zp + + np.save("x.npy", x) + np.save("y.npy", y) + np.save("z.npy", z) + np.save("data.npy", data) + # show the expected result + # f=RegularGridInterpolator((x, y, z), data) + # print(f([2.7,7.4,3.9])) From 11d6cfe9cebaaa02a55b931edc371a92a89890af Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Tue, 18 Aug 2026 11:48:15 +0200 Subject: [PATCH 7/8] fix: need to call the python function after having jumped into the test case dir --- pytools/idfx_test_run.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pytools/idfx_test_run.py b/pytools/idfx_test_run.py index 726dc8b6..fc0bba2f 100644 --- a/pytools/idfx_test_run.py +++ b/pytools/idfx_test_run.py @@ -227,7 +227,8 @@ def run(self, config: dict) -> None: del config[f"callPyFunction{hook}"] # call hook before - self.callPyHook(problemDir, pyHooks, "Before") + with moveInDir(problemDir): + self.callPyHook(problemDir, pyHooks, "Before") # if switch from test, rebuild the runner (a runner make for one dir) if self.currentTestFile != testfile: @@ -255,7 +256,8 @@ def run(self, config: dict) -> None: ) # call hook after - self.callPyHook(problemDir, pyHooks, "After") + with moveInDir(problemDir): + self.callPyHook(problemDir, pyHooks, "After") def _runNonRegression( self, From 444b71e39df1aeb1378e6cbe03ce5d12c361d6b8 Mon Sep 17 00:00:00 2001 From: Sebastien Valat Date: Tue, 18 Aug 2026 12:05:17 +0200 Subject: [PATCH 8/8] fix: same issue about current working dir for the XDMF test --- pytools/idfx_test_run.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pytools/idfx_test_run.py b/pytools/idfx_test_run.py index fc0bba2f..be2e2bb5 100644 --- a/pytools/idfx_test_run.py +++ b/pytools/idfx_test_run.py @@ -249,11 +249,12 @@ def run(self, config: dict) -> None: ) # check produced - for file in check_file_produced: - if not os.path.exists(file) and not self.currentTestRunner.fake: - raise Exception( - f"Don't find expected file to be produced by the run : {file} !" - ) + with moveInDir(problemDir): + for file in check_file_produced: + if not os.path.exists(file) and not self.currentTestRunner.fake: + raise Exception( + f"Don't find expected file to be produced by the run : {file} !" + ) # call hook after with moveInDir(problemDir):