diff --git a/.github/workflows/idefix-ci-jobs.yml b/.github/workflows/idefix-ci-jobs.yml index 275ea1ce2..734390db2 100644 --- a/.github/workflows/idefix-ci-jobs.yml +++ b/.github/workflows/idefix-ci-jobs.yml @@ -21,6 +21,7 @@ env: PYTHONPATH: ${{ github.workspace }} IDEFIX_DIR: ${{ github.workspace }} + jobs: ShocksHydro: runs-on: self-hosted @@ -35,6 +36,8 @@ jobs: run: scripts/ci/run-tests $IDEFIX_DIR/test/HD/sod-iso -all $TESTME_OPTIONS - name: Mach reflection test run: scripts/ci/run-tests $IDEFIX_DIR/test/HD//MachReflection -all $TESTME_OPTIONS + - name: Sedov blast wave + run: scripts/ci/run-tests $IDEFIX_DIR/test/HD/SedovBlastWave -all $TESTME_OPTIONS ParabolicHydro: runs-on: self-hosted @@ -63,8 +66,10 @@ jobs: run: scripts/ci/run-tests $IDEFIX_DIR/test/MHD/sod-iso -all $TESTME_OPTIONS - name: Orszag Tang run: scripts/ci/run-tests $IDEFIX_DIR/test/MHD/OrszagTang -all $TESTME_OPTIONS - - name: Orszag Tang 3D+restart tests + - name: Orszag Tang 3D run: scripts/ci/run-tests $IDEFIX_DIR/test/MHD/OrszagTang3D -all $TESTME_OPTIONS + - name: Linear wave test + run: scripts/ci/run-tests $IDEFIX_DIR/test/MHD/LinearWaveTest -all $TESTME_OPTIONS - name: Axis Flux tube run: scripts/ci/run-tests $IDEFIX_DIR/test/MHD/AxisFluxTube -all $TESTME_OPTIONS @@ -207,3 +212,23 @@ jobs: run: scripts/ci/run-tests $IDEFIX_DIR/test/utils/dumpImage -all $TESTME_OPTIONS - name: Column density run: scripts/ci/run-tests $IDEFIX_DIR/test/utils/columnDensity -all $TESTME_OPTIONS + + IOs: + needs: [Fargo, Dust, Planet, ShearingBox, SelfGravity] + runs-on: self-hosted + steps: + - name: Check out repo + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Restart dumps + run: scripts/ci/run-tests $IDEFIX_DIR/test/IO/dump -all $TESTME_OPTIONS + - name: Pydefix + run: | + python3 -m venv $IDEFIX_DIR/test/IO/pydefix/env + source $IDEFIX_DIR/test/IO/pydefix/env/bin/activate + python3 -m pip install -r $IDEFIX_DIR/test/IO/pydefix/python_requirements.txt + scripts/ci/run-tests $IDEFIX_DIR/test/IO/pydefix -all $TESTME_OPTIONS + + - name: xdmf + run: scripts/ci/run-tests $IDEFIX_DIR/test/IO/xdmf -all $TESTME_OPTIONS diff --git a/CMakeLists.txt b/CMakeLists.txt index f4a647fe8..ea4a71537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,13 @@ if(Idefix_HDF5) ) find_package(HDF5 REQUIRED) target_link_libraries(idefix "${HDF5_LIBRARIES}") - target_include_directories(idefix "${HDF5_INCLUDE_DIRS}") + message(STATUS "Found HDF5 include directories: ${HDF5_INCLUDE_DIRS}") + target_include_directories(idefix PUBLIC "${HDF5_INCLUDE_DIRS}") + if(Idefix_MPI) + if(NOT HDF5_IS_PARALLEL) + message(FATAL_ERROR "Parallel HDF5 required for Idefix_MPI but the found HDF5 library does not support it") + endif() + endif() message(STATUS "XDMF (hdf5+xmf) dumps enabled") else() set(Idefix_HDF5 OFF) @@ -123,6 +129,16 @@ endif() if(Idefix_PYTHON) add_compile_definitions("WITH_PYTHON") + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) + + execute_process( + COMMAND "${Python3_EXECUTABLE}" -m pybind11 --cmakedir + OUTPUT_VARIABLE PYBIND11_CMAKE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + + list(APPEND CMAKE_PREFIX_PATH "${PYBIND11_CMAKE_DIR}") if (NOT DEFINED Python_FIND_FRAMEWORK) set(Python_FIND_FRAMEWORK "LAST") # Use Apple's python only at last resort on Macos endif () diff --git a/reference b/reference index 1028989b3..32499c14c 160000 --- a/reference +++ b/reference @@ -1 +1 @@ -Subproject commit 1028989b3847200da9b54ed74df0d5c0b0d13045 +Subproject commit 32499c14cfacd05e1c9499bd23198a53c416c3c2 diff --git a/src/output/xdmf.cpp b/src/output/xdmf.cpp index 23ddaa03a..4e7ff6843 100644 --- a/src/output/xdmf.cpp +++ b/src/output/xdmf.cpp @@ -286,18 +286,18 @@ int Xdmf::Write() { idfx::pushRegion("Xdmf::Write"); fs::path filename; fs::path filename_xmf; - hid_t err; + [[maybe_unused]] hid_t err; idfx::cout << "Xdmf: Write file n " << xdmfFileNumber << "..." << std::flush; timer.reset(); // Create a copy of the dataBlock on Host, and sync it. #if DIMENSIONS == 1 - int tot_dim = 1; + [[maybe_unused]] int tot_dim = 1; #elif DIMENSIONS == 2 int tot_dim = 2; #elif DIMENSIONS == 3 - int tot_dim = 3; + [[maybe_unused]] int tot_dim = 3; #endif std::stringstream ssfileName, ssfileNameXmf, ssxdmfFileNum; @@ -344,7 +344,8 @@ int Xdmf::Write() { #endif // Layout of the field data in memory - hsize_t field_data_size[3], field_data_start[3], field_data_subsize[3], stride[3]; + [[maybe_unused]] hsize_t field_data_size[3], field_data_start[3]; + [[maybe_unused]] hsize_t field_data_subsize[3], stride[3]; #ifdef WITH_MPI for(int dir = 0; dir < 3 ; dir++) { field_data_size[dir] = static_cast(this->mpi_data_size[dir]); @@ -454,11 +455,10 @@ void Xdmf::WriteHeader( hid_t tspace, tattr; hid_t unit_info, unit_attr; hid_t group; - hid_t file_access = 0; #ifdef WITH_MPI hid_t plist_id_mpiio = 0; /* for collective MPI I/O */ #endif - hid_t err; + [[maybe_unused]] hid_t err; hsize_t dimstr; @@ -814,7 +814,7 @@ void Xdmf::WriteScalar( dataset_name = var_name.c_str(); std::string dataset_label = dataset_name.c_str(); std::transform(dataset_label.begin(), dataset_label.end(), dataset_label.begin(), ::tolower); - hid_t err, dataset; + [[maybe_unused]] hid_t err, dataset; // We define the dataset that contain the fields. diff --git a/src/pydefix.cpp b/src/pydefix.cpp index 1f156185d..1b8168088 100644 --- a/src/pydefix.cpp +++ b/src/pydefix.cpp @@ -68,7 +68,7 @@ py::array_t GatherIdefixArray(IdefixHostArray3D // np_int: size that should be copied into global // beg: offset in the incoming array where copy should begin // gbeg: offset in the global array where copy should be begin - std::array np_int,np_tot, beg, gbeg; + [[maybe_unused]] std::array np_int,np_tot, beg, gbeg; IdefixHostArray3D buf; if(rank==0) { @@ -127,7 +127,7 @@ py::array_t GatherIdefixArray(IdefixHostArray3D }// End loop on target rank for root process } else { // MPI prank >0 std::array np_int = dataHost.np_int; - std::array np_tot = dataHost.np_tot; + [[maybe_unused]] std::array np_tot = dataHost.np_tot; std::array gbeg = dataHost.gbeg; std::array beg = dataHost.beg; @@ -278,6 +278,9 @@ Pydefix::Pydefix(Input &input) { idfx::cout << "Pydefix: start Python interpreter." << std::endl; py::initialize_interpreter(); + py::exec("import sys; print(f'Pydefix: Python Version: {sys.version}')"); + py::exec("print(f'Pydefix: Executable Path: {sys.executable}')"); + py::exec("print(f'Pydefix: Sys Path: {sys.path}')"); } this->scriptFilename = input.Get("Python","script",0); if(scriptFilename.substr(scriptFilename.length() - 3, 3).compare(".py")==0) { diff --git a/src/setup.cpp b/src/setup.cpp index 8c64f4447..b82f118f8 100644 --- a/src/setup.cpp +++ b/src/setup.cpp @@ -12,7 +12,9 @@ // own implementation of the constructor, initflow and destructor __attribute__((weak)) Setup::Setup(Input &input, Grid &grid, DataBlock &data, Output &output) { - IDEFIX_WARNING("Caution, this is the default Setup constructor and it does nothing!"); + #ifndef WITH_PYTHON + IDEFIX_WARNING("Caution, this is the default Setup constructor and it does nothing!"); + #endif } __attribute__((weak)) void Setup::InitFlow(DataBlock &data) { diff --git a/test/HD/SedovBlastWave/idefix.ini b/test/HD/SedovBlastWave/idefix.ini index 51122521c..107b719cd 100644 --- a/test/HD/SedovBlastWave/idefix.ini +++ b/test/HD/SedovBlastWave/idefix.ini @@ -25,6 +25,5 @@ X3-beg periodic X3-end periodic [Output] -vtk 0.1 -xdmf 0.1 -dmp 0.1 +vtk 0.1 +dmp 0.1 diff --git a/test/IO/dump/CMakeLists.txt b/test/IO/dump/CMakeLists.txt new file mode 100644 index 000000000..629aed2d1 --- /dev/null +++ b/test/IO/dump/CMakeLists.txt @@ -0,0 +1 @@ +enable_idefix_property(Idefix_MHD) diff --git a/test/IO/dump/definitions.hpp b/test/IO/dump/definitions.hpp new file mode 100644 index 000000000..a854ad9e3 --- /dev/null +++ b/test/IO/dump/definitions.hpp @@ -0,0 +1,5 @@ +#define COMPONENTS 3 +#define DIMENSIONS 3 +//#define DEBUG + +#define GEOMETRY CARTESIAN diff --git a/test/MHD/OrszagTang3D/idefix-checkrestart.ini b/test/IO/dump/idefix.ini similarity index 100% rename from test/MHD/OrszagTang3D/idefix-checkrestart.ini rename to test/IO/dump/idefix.ini diff --git a/test/IO/dump/setup.cpp b/test/IO/dump/setup.cpp new file mode 100644 index 000000000..1db56f5b0 --- /dev/null +++ b/test/IO/dump/setup.cpp @@ -0,0 +1,277 @@ +#include "idefix.hpp" +#include "setup.hpp" + +/*********************************************/ +/** +Customized random number generator +Allow one to have consistent random numbers +generators on different architectures. +**/ +/*********************************************/ + +Output* myOutput; +int outnum; +// Analysis function +// This analysis checks that the restart routines are performing as they should +void Analysis(DataBlock& data) { + + + idfx::cout << "Analysis: Checking restart routines" << std::endl; + + // Trigger dump creation + // data.SetBoundaries(); + myOutput->ForceWriteDump(data); + + // Mirror data on Host + DataBlockHost d(data); + + // Sync it + d.SyncFromDevice(); + + // Create local arrays to store the current physical state + IdefixHostArray4D myVc = IdefixHostArray4D("myVc", d.Vc.extent(0), data.np_tot[KDIR], data.np_tot[JDIR],data.np_tot[IDIR]); + IdefixHostArray4D myVs = IdefixHostArray4D("myVs", DIMENSIONS, data.np_tot[KDIR]+KOFFSET, data.np_tot[JDIR]+JOFFSET,data.np_tot[IDIR]+IOFFSET); + #ifdef EVOLVE_VECTOR_POTENTIAL + IdefixHostArray4D myVe = IdefixHostArray4D("myVe", AX3e+1, data.np_tot[KDIR]+KOFFSET, data.np_tot[JDIR]+JOFFSET,data.np_tot[IDIR]+IOFFSET); + #endif + // Transfer the datablock to myVc and myVs + for(int n = 0; n < d.Vc.extent(0) ; n++) { + for(int k = 0; k < d.np_tot[KDIR] ; k++) { + for(int j = 0; j < d.np_tot[JDIR] ; j++) { + for(int i = 0; i < d.np_tot[IDIR] ; i++) { + myVc(n,k,j,i) = d.Vc(n,k,j,i); + d.Vc(n,k,j,i) = 0.0; + + } + } + } + } + + for(int n = 0; n < DIMENSIONS ; n++) { + for(int k = 0; k < d.np_tot[KDIR] + KOFFSET; k++) { + for(int j = 0; j < d.np_tot[JDIR] + JOFFSET; j++) { + for(int i = 0; i < d.np_tot[IDIR] + IOFFSET; i++) { + myVs(n,k,j,i) = d.Vs(n,k,j,i); + d.Vs(n,k,j,i) = 0.0; + } + } + } + } + #ifdef EVOLVE_VECTOR_POTENTIAL + for(int n = 0; n < AX3e+1 ; n++) { + for(int k = 0; k < d.np_tot[KDIR] + KOFFSET; k++) { + for(int j = 0; j < d.np_tot[JDIR] + JOFFSET; j++) { + for(int i = 0; i < d.np_tot[IDIR] + IOFFSET; i++) { + myVe(n,k,j,i) = d.Ve(n,k,j,i); + d.Ve(n,k,j,i) = 0.0; + } + } + } + } + #endif + + // Push our datablockHost to erase everything + d.SyncToDevice(); + // From this point, the dataBlock is full of zeros + + // Load back the restart dump + myOutput->RestartFromDump(data, outnum); + data.SetBoundaries(); + #ifdef EVOLVE_VECTOR_POTENTIAL + data.hydro->emf->ComputeMagFieldFromA(data.hydro->Ve, data.hydro->Vs); + #endif + d.SyncFromDevice(); + + // increment outnum + outnum++; + int errornum; + + errornum = 0; + idfx::cout << "Analysis: checking consistency" << std::endl; + // Check that the save/load routines have left everything unchanged. + for(int n = 0; n < d.Vc.extent(0) ; n++) { + for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { + if(myVc(n,k,j,i) != d.Vc(n,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Vc at (i,j,k,n) = ( " << i << ", " << j << ", " << k << ", " << n << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl + << "Original= " << myVc(n,k,j,i) << " New=" << d.Vc(n,k,j,i) << " diff=" << myVc(n,k,j,i)-d.Vc(n,k,j,i) << std::endl; + } + + } + } + } + } + + for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { + if(myVs(BX1s,k,j,i) != d.Vs(BX1s,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Vs(BX1s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl + << "Original= " << myVs(BX1s,k,j,i) << " New=" << d.Vs(BX1s,k,j,i) << " diff=" << myVs(BX1s,k,j,i)-d.Vs(BX1s,k,j,i) << std::endl; + + } + + } + } + } + for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { + if(myVs(BX2s,k,j,i) != d.Vs(BX2s,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Vs(BX2s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; + } + + } + } + } + for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { + if(myVs(BX3s,k,j,i) != d.Vs(BX3s,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Vs(BX3s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl + << "Original= " << myVs(BX3s,k,j,i) << " New=" << d.Vs(BX3s,k,j,i) << " diff=" << myVs(BX3s,k,j,i)-d.Vs(BX3s,k,j,i) << std::endl; + } + + } + } + } +#ifdef EVOLVE_VECTOR_POTENTIAL + for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { + if(myVe(AX1e,k,j,i) != d.Ve(AX1e,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Ve(AX1e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; + + } + + } + } + } + for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { + if(myVe(AX2e,k,j,i) != d.Ve(AX2e,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Ve(AX2e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; + } + + } + } + } + for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { + for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { + for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { + if(myVe(AX3e,k,j,i) != d.Ve(AX3e,k,j,i)) { + errornum++; + idfx::cout << "-----------------------------------------" << std::endl + << " Error in Ve(AX3e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl + << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl + << "Original= " << myVs(BX3s,k,j,i) << " New=" << d.Vs(BX3s,k,j,i) << " diff=" << myVs(BX3s,k,j,i)-d.Vs(BX3s,k,j,i) << std::endl; + } + + } + } + } +#endif + + idfx::cout << "Analysis: consistency check done with " << errornum << " errors " << std::endl; + if(errornum>0) { + IDEFIX_ERROR("Restart from dump failed validation"); + } +} + +// Initialisation routine. Can be used to allocate +// Arrays or variables which are used later on +Setup::Setup(Input &input, Grid &grid, DataBlock &data, Output &output) { + if(input.CheckEntry("Output","analysis")>0) { + output.EnrollAnalysis(&Analysis); + myOutput = &output; + outnum=0; + } +} + +// This routine initialize the flow +// Note that data is on the device. +// One can therefore define locally +// a datahost and sync it, if needed +void Setup::InitFlow(DataBlock &data) { + // Create a host copy + DataBlockHost d(data); + real x,y,z; + IdefixHostArray4D Ve; + + #ifndef EVOLVE_VECTOR_POTENTIAL + Ve = IdefixHostArray4D("Potential vector",3, d.np_tot[KDIR]+1, d.np_tot[JDIR]+1, d.np_tot[IDIR]+1); + #else + Ve = d.Ve; + #endif + + bool haveTracer = data.hydro->haveTracer; + + real B0=1.0/sqrt(4.0*M_PI); + + for(int k = 0; k < d.np_tot[KDIR] ; k++) { + for(int j = 0; j < d.np_tot[JDIR] ; j++) { + for(int i = 0; i < d.np_tot[IDIR] ; i++) { + x=d.x[IDIR](i); + y=d.x[JDIR](j); + z=d.x[KDIR](k); + + d.Vc(RHO,k,j,i) = 25.0/(36.0*M_PI); + d.Vc(PRS,k,j,i) = 5.0/(12.0*M_PI); + d.Vc(VX1,k,j,i) = -sin(2.0*M_PI*y); + d.Vc(VX2,k,j,i) = sin(2.0*M_PI*x)+cos(2.0*M_PI*z); + d.Vc(VX3,k,j,i) = cos(2.0*M_PI*x); + + real xl=d.xl[IDIR](i); + real yl=d.xl[JDIR](j); + real zl=d.xl[KDIR](k); + Ve(IDIR,k,j,i) = B0/(2.0*M_PI)*(cos(2.0*M_PI*yl)); + Ve(JDIR,k,j,i) = B0/(2.0*M_PI)*sin(2.0*M_PI*xl); + Ve(KDIR,k,j,i) = B0/(2.0*M_PI)*( + cos(2.0*M_PI*yl) + cos(4.0*M_PI*xl)/2.0); + + if(haveTracer) { + d.Vc(TRG ,k,j,i) = x>0.5? 1.0:0.0; + d.Vc(TRG+1,k,j,i) = z>0.5? 1.0:0.0; + } + } + } + } + + #ifndef EVOLVE_VECTOR_POTENTIAL + d.MakeVsFromAmag(Ve); + #endif + // Send it all, if needed + d.SyncToDevice(); +} + +// Analyse data to produce an output +void MakeAnalysis(DataBlock & data) { + +} + + + +// Do a specifically designed user step in the middle of the integration +void ComputeUserStep(DataBlock &data, real t, real dt) { + +} diff --git a/test/IO/dump/testme.py b/test/IO/dump/testme.py new file mode 100755 index 000000000..35affdba2 --- /dev/null +++ b/test/IO/dump/testme.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +""" + +@author: glesur +""" +import os +import sys +sys.path.append(os.getenv("IDEFIX_DIR")) + +import pytools.idfx_test as tst + +# Whether we should reset our reference run (only do that on purpose!) + +tolerance=1e-13 + +def testMe(test): + test.configure() + test.compile() + + # Check restarts + test.run("idefix.ini") + + +test=tst.idfxTest() + +# if no decomposition is specified, use that one +if not test.dec: + test.dec=["2","2","2"] + +if not test.all: + testMe(test) +else: + test.vectPot=False + test.reconstruction=2 + test.mpi=False + testMe(test) + # test in MPI mode + test.mpi=True + testMe(test) + + + # test with vector potential + test.mpi=False + test.vectPot=True + test.reconstruction=2 + testMe(test) + + test.mpi=True + testMe(test) + + # test with other precision + test.single=True + test.vectPot=False + test.reconstruction=2 + test.mpi=False + testMe(test) + # test in MPI mode + test.mpi=True + testMe(test) diff --git a/test/IO/pydefix/idefix.ini b/test/IO/pydefix/idefix.ini index 57fdcfc4a..3ee42ae3e 100644 --- a/test/IO/pydefix/idefix.ini +++ b/test/IO/pydefix/idefix.ini @@ -26,5 +26,6 @@ X3-beg outflow X3-end outflow [Output] -log 10 +log 100 python 0.02 +dmp 0.5 diff --git a/test/IO/pydefix/python_requirements.txt b/test/IO/pydefix/python_requirements.txt index 6afd3019b..9489d0889 100644 --- a/test/IO/pydefix/python_requirements.txt +++ b/test/IO/pydefix/python_requirements.txt @@ -1,6 +1,7 @@ # note: version requirements are indicative and tests # should be able to run with # older versions of our dependencies, though it is not guaranteed. +# minimally require last versions available for Python 2.7 numpy>=1.16.6 matplotlib>=2.2.5 -pybind11>=2.12.0 +pybind11>=2.10.0 diff --git a/test/IO/pydefix/testme.py b/test/IO/pydefix/testme.py new file mode 100755 index 000000000..0a3ad0432 --- /dev/null +++ b/test/IO/pydefix/testme.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +""" + +@author: glesur +""" +import os +import sys +sys.path.append(os.getenv("IDEFIX_DIR")) + +import pytools.idfx_test as tst +tolerance=1e-12 +def testMe(test): + test.configure() + test.compile() + + test.run(inputFile="idefix.ini") + if test.init and not test.mpi: + test.makeReference(filename="dump.0001.dmp") + + test.nonRegressionTest(filename="dump.0001.dmp",tolerance=tolerance) + + +test=tst.idfxTest() +if not test.dec: + test.dec=['2','2'] + +if not test.all: + if(test.check): + test.checkOnly(filename="dump.0001.dmp",tolerance=tolerance) + else: + testMe(test) +else: + test.noplot = True + test.vectPot = False + test.single=False + test.reconstruction=2 + test.mpi=False + testMe(test) + test.mpi=True + testMe(test) diff --git a/test/HD/SedovBlastWave/CMakeLists.txt b/test/IO/xdmf/CMakeLists.txt similarity index 50% rename from test/HD/SedovBlastWave/CMakeLists.txt rename to test/IO/xdmf/CMakeLists.txt index c4ae088b8..8ce9e0f4d 100644 --- a/test/HD/SedovBlastWave/CMakeLists.txt +++ b/test/IO/xdmf/CMakeLists.txt @@ -1 +1,2 @@ +enable_idefix_property(Idefix_MHD) enable_idefix_property(Idefix_HDF5) diff --git a/test/IO/xdmf/definitions.hpp b/test/IO/xdmf/definitions.hpp new file mode 100644 index 000000000..a854ad9e3 --- /dev/null +++ b/test/IO/xdmf/definitions.hpp @@ -0,0 +1,5 @@ +#define COMPONENTS 3 +#define DIMENSIONS 3 +//#define DEBUG + +#define GEOMETRY CARTESIAN diff --git a/test/IO/xdmf/idefix.ini b/test/IO/xdmf/idefix.ini new file mode 100644 index 000000000..250a24054 --- /dev/null +++ b/test/IO/xdmf/idefix.ini @@ -0,0 +1,26 @@ +[Grid] +X1-grid 1 0.0 32 u 1.0 +X2-grid 1 0.0 64 u 1.0 +X3-grid 1 0.0 32 u 1.0 + +[TimeIntegrator] +CFL 0.9 +tstop 0.2 +first_dt 1.e-4 +nstages 2 + +[Hydro] +solver hlld + +[Boundary] +X1-beg periodic +X1-end periodic +X2-beg periodic +X2-end periodic +X3-beg periodic +X3-end periodic + +[Output] +xdmf 0.2 +dmp 0.2 +log 10 diff --git a/test/IO/xdmf/setup.cpp b/test/IO/xdmf/setup.cpp new file mode 100644 index 000000000..8cc40857f --- /dev/null +++ b/test/IO/xdmf/setup.cpp @@ -0,0 +1,75 @@ +#include "idefix.hpp" +#include "setup.hpp" + +// Initialisation routine. Can be used to allocate +// Arrays or variables which are used later on +Setup::Setup(Input &input, Grid &grid, DataBlock &data, Output &output) { +} + +// This routine initialize the flow +// Note that data is on the device. +// One can therefore define locally +// a datahost and sync it, if needed +void Setup::InitFlow(DataBlock &data) { + // Create a host copy + DataBlockHost d(data); + real x,y,z; + IdefixHostArray4D Ve; + + #ifndef EVOLVE_VECTOR_POTENTIAL + Ve = IdefixHostArray4D("Potential vector",3, d.np_tot[KDIR]+1, d.np_tot[JDIR]+1, d.np_tot[IDIR]+1); + #else + Ve = d.Ve; + #endif + + bool haveTracer = data.hydro->haveTracer; + + real B0=1.0/sqrt(4.0*M_PI); + + for(int k = 0; k < d.np_tot[KDIR] ; k++) { + for(int j = 0; j < d.np_tot[JDIR] ; j++) { + for(int i = 0; i < d.np_tot[IDIR] ; i++) { + x=d.x[IDIR](i); + y=d.x[JDIR](j); + z=d.x[KDIR](k); + + d.Vc(RHO,k,j,i) = 25.0/(36.0*M_PI); + d.Vc(PRS,k,j,i) = 5.0/(12.0*M_PI); + d.Vc(VX1,k,j,i) = -sin(2.0*M_PI*y); + d.Vc(VX2,k,j,i) = sin(2.0*M_PI*x)+cos(2.0*M_PI*z); + d.Vc(VX3,k,j,i) = cos(2.0*M_PI*x); + + real xl=d.xl[IDIR](i); + real yl=d.xl[JDIR](j); + real zl=d.xl[KDIR](k); + Ve(IDIR,k,j,i) = B0/(2.0*M_PI)*(cos(2.0*M_PI*yl)); + Ve(JDIR,k,j,i) = B0/(2.0*M_PI)*sin(2.0*M_PI*xl); + Ve(KDIR,k,j,i) = B0/(2.0*M_PI)*( + cos(2.0*M_PI*yl) + cos(4.0*M_PI*xl)/2.0); + + if(haveTracer) { + d.Vc(TRG ,k,j,i) = x>0.5? 1.0:0.0; + d.Vc(TRG+1,k,j,i) = z>0.5? 1.0:0.0; + } + } + } + } + + #ifndef EVOLVE_VECTOR_POTENTIAL + d.MakeVsFromAmag(Ve); + #endif + // Send it all, if needed + d.SyncToDevice(); +} + +// Analyse data to produce an output +void MakeAnalysis(DataBlock & data) { + +} + + + +// Do a specifically designed user step in the middle of the integration +void ComputeUserStep(DataBlock &data, real t, real dt) { + +} diff --git a/test/IO/xdmf/testme.py b/test/IO/xdmf/testme.py new file mode 100755 index 000000000..a1e333430 --- /dev/null +++ b/test/IO/xdmf/testme.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +""" + +@author: glesur +""" +import os +import sys +sys.path.append(os.getenv("IDEFIX_DIR")) + +import pytools.idfx_test as tst + +name="dump.0001.dmp" + +test=tst.idfxTest() + +def check_xdmf_exists(): + # verify that the expected XDMF sidecar and data file exist. + xdmf_file = "data.0001.flt.xmf" + h5_file = "data.0001.flt.h5" + + + if not os.path.exists(xdmf_file): + print("Missing expected XDMF output file: {}".format(xdmf_file)) + sys.exit(1) + if not os.path.exists(h5_file): + print("Missing expected XDMF data file: {}".format(h5_file)) + sys.exit(1) + +if not test.dec: + test.dec=['2','2','2'] + +if test.check: + check_xdmf_exists() + +else: + test.vectPot=False + test.single=False + test.reconstruction=2 + test.mpi=False + # Only check that the test runs. + test.configure(definitionFile="definitions.hpp") + test.compile() + test.run(inputFile="idefix.ini") + check_xdmf_exists diff --git a/test/MHD/LinearWaveTest/idefix-entropy.ini b/test/MHD/LinearWaveTest/idefix-entropy.ini index 5a54d274b..805819477 100644 --- a/test/MHD/LinearWaveTest/idefix-entropy.ini +++ b/test/MHD/LinearWaveTest/idefix-entropy.ini @@ -29,4 +29,4 @@ epsilon 1.0e-6 [Output] dmp 1.0 vtk 1.0 -log 1 +log 10 diff --git a/test/MHD/LinearWaveTest/testme.py b/test/MHD/LinearWaveTest/testme.py index 8c9282862..390a5759b 100755 --- a/test/MHD/LinearWaveTest/testme.py +++ b/test/MHD/LinearWaveTest/testme.py @@ -9,7 +9,7 @@ sys.path.append(os.getenv("IDEFIX_DIR")) import pytools.idfx_test as tst -tolerance=1e-14 +tolerance=2e-13 def testMe(test): test.configure() test.compile() diff --git a/test/MHD/OrszagTang3D/setup.cpp b/test/MHD/OrszagTang3D/setup.cpp index 86766c8ee..a6927a132 100644 --- a/test/MHD/OrszagTang3D/setup.cpp +++ b/test/MHD/OrszagTang3D/setup.cpp @@ -12,200 +12,10 @@ generators on different architectures. Output* myOutput; int outnum; // Analysis function -// This analysis checks that the restart routines are performing as they should -void Analysis(DataBlock& data) { - - - idfx::cout << "Analysis: Checking restart routines" << std::endl; - - // Trigger dump creation - // data.SetBoundaries(); - myOutput->ForceWriteDump(data); - - // Mirror data on Host - DataBlockHost d(data); - - // Sync it - d.SyncFromDevice(); - - // Create local arrays to store the current physical state - IdefixHostArray4D myVc = IdefixHostArray4D("myVc", d.Vc.extent(0), data.np_tot[KDIR], data.np_tot[JDIR],data.np_tot[IDIR]); - IdefixHostArray4D myVs = IdefixHostArray4D("myVs", DIMENSIONS, data.np_tot[KDIR]+KOFFSET, data.np_tot[JDIR]+JOFFSET,data.np_tot[IDIR]+IOFFSET); - #ifdef EVOLVE_VECTOR_POTENTIAL - IdefixHostArray4D myVe = IdefixHostArray4D("myVe", AX3e+1, data.np_tot[KDIR]+KOFFSET, data.np_tot[JDIR]+JOFFSET,data.np_tot[IDIR]+IOFFSET); - #endif - // Transfer the datablock to myVc and myVs - for(int n = 0; n < d.Vc.extent(0) ; n++) { - for(int k = 0; k < d.np_tot[KDIR] ; k++) { - for(int j = 0; j < d.np_tot[JDIR] ; j++) { - for(int i = 0; i < d.np_tot[IDIR] ; i++) { - myVc(n,k,j,i) = d.Vc(n,k,j,i); - d.Vc(n,k,j,i) = 0.0; - - } - } - } - } - - for(int n = 0; n < DIMENSIONS ; n++) { - for(int k = 0; k < d.np_tot[KDIR] + KOFFSET; k++) { - for(int j = 0; j < d.np_tot[JDIR] + JOFFSET; j++) { - for(int i = 0; i < d.np_tot[IDIR] + IOFFSET; i++) { - myVs(n,k,j,i) = d.Vs(n,k,j,i); - d.Vs(n,k,j,i) = 0.0; - } - } - } - } - #ifdef EVOLVE_VECTOR_POTENTIAL - for(int n = 0; n < AX3e+1 ; n++) { - for(int k = 0; k < d.np_tot[KDIR] + KOFFSET; k++) { - for(int j = 0; j < d.np_tot[JDIR] + JOFFSET; j++) { - for(int i = 0; i < d.np_tot[IDIR] + IOFFSET; i++) { - myVe(n,k,j,i) = d.Ve(n,k,j,i); - d.Ve(n,k,j,i) = 0.0; - } - } - } - } - #endif - - // Push our datablockHost to erase everything - d.SyncToDevice(); - // From this point, the dataBlock is full of zeros - - // Load back the restart dump - myOutput->RestartFromDump(data, outnum); - data.SetBoundaries(); - #ifdef EVOLVE_VECTOR_POTENTIAL - data.hydro->emf->ComputeMagFieldFromA(data.hydro->Ve, data.hydro->Vs); - #endif - d.SyncFromDevice(); - - // increment outnum - outnum++; - int errornum; - - errornum = 0; - idfx::cout << "Analysis: checking consistency" << std::endl; - // Check that the save/load routines have left everything unchanged. - for(int n = 0; n < d.Vc.extent(0) ; n++) { - for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { - if(myVc(n,k,j,i) != d.Vc(n,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Vc at (i,j,k,n) = ( " << i << ", " << j << ", " << k << ", " << n << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl - << "Original= " << myVc(n,k,j,i) << " New=" << d.Vc(n,k,j,i) << " diff=" << myVc(n,k,j,i)-d.Vc(n,k,j,i) << std::endl; - } - - } - } - } - } - - for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { - if(myVs(BX1s,k,j,i) != d.Vs(BX1s,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Vs(BX1s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl - << "Original= " << myVs(BX1s,k,j,i) << " New=" << d.Vs(BX1s,k,j,i) << " diff=" << myVs(BX1s,k,j,i)-d.Vs(BX1s,k,j,i) << std::endl; - - } - - } - } - } - for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { - if(myVs(BX2s,k,j,i) != d.Vs(BX2s,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Vs(BX2s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; - } - - } - } - } - for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { - if(myVs(BX3s,k,j,i) != d.Vs(BX3s,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Vs(BX3s) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl - << "Original= " << myVs(BX3s,k,j,i) << " New=" << d.Vs(BX3s,k,j,i) << " diff=" << myVs(BX3s,k,j,i)-d.Vs(BX3s,k,j,i) << std::endl; - } - - } - } - } -#ifdef EVOLVE_VECTOR_POTENTIAL - for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR] ; i++) { - if(myVe(AX1e,k,j,i) != d.Ve(AX1e,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Ve(AX1e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; - - } - - } - } - } - for(int k = d.beg[KDIR]; k < d.end[KDIR]+KOFFSET ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR] ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { - if(myVe(AX2e,k,j,i) != d.Ve(AX2e,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Ve(AX2e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl; - } - - } - } - } - for(int k = d.beg[KDIR]; k < d.end[KDIR] ; k++) { - for(int j = d.beg[JDIR]; j < d.end[JDIR]+JOFFSET ; j++) { - for(int i = d.beg[IDIR]; i < d.end[IDIR]+IOFFSET ; i++) { - if(myVe(AX3e,k,j,i) != d.Ve(AX3e,k,j,i)) { - errornum++; - idfx::cout << "-----------------------------------------" << std::endl - << " Error in Ve(AX3e) at (i,j,k) = ( " << i << ", " << j << ", " << k << ")" << std::endl - << " Coordinates (x1,x2,x3) = ( " << d.x[IDIR](i) << ", " << d.x[JDIR](j) << ", " << d.x[KDIR](k) << ")" << std::endl - << "Original= " << myVs(BX3s,k,j,i) << " New=" << d.Vs(BX3s,k,j,i) << " diff=" << myVs(BX3s,k,j,i)-d.Vs(BX3s,k,j,i) << std::endl; - } - - } - } - } -#endif - - idfx::cout << "Analysis: consistency check done with " << errornum << " errors " << std::endl; - if(errornum>0) { - IDEFIX_ERROR("Restart from dump failed validation"); - } -} // Initialisation routine. Can be used to allocate // Arrays or variables which are used later on Setup::Setup(Input &input, Grid &grid, DataBlock &data, Output &output) { - if(input.CheckEntry("Output","analysis")>0) { - output.EnrollAnalysis(&Analysis); - myOutput = &output; - outnum=0; - } } // This routine initialize the flow diff --git a/test/MHD/OrszagTang3D/testme.py b/test/MHD/OrszagTang3D/testme.py index 600a5ef5f..b9626f9cc 100755 --- a/test/MHD/OrszagTang3D/testme.py +++ b/test/MHD/OrszagTang3D/testme.py @@ -27,12 +27,6 @@ def testMe(test): test.makeReference(filename="dump.0001.dmp") test.nonRegressionTest(filename="dump.0001.dmp",tolerance=tol) - # Check restarts - test.run("idefix-checkrestart.ini") - #force override the inputfile since the result should be identical - test.inifile="idefix.ini" - test.nonRegressionTest(filename="dump.0002.dmp",tolerance=tol) - test=tst.idfxTest()