diff --git a/doc/source/modules/pydefix.rst b/doc/source/modules/pydefix.rst index d02f34fa8..6d3c1ccad 100644 --- a/doc/source/modules/pydefix.rst +++ b/doc/source/modules/pydefix.rst @@ -56,6 +56,30 @@ Your python script should define functions that will be called while Idefix is r * The signature of the ``initflow`` function should be ``(data)`` where ``data`` is a python structure matching Idefix's ``DataBlockHost`` class. * The signature of the ``output`` function should be ``(data,grid,n)`` where ``data`` is a python structure matching Idefix's ``DataBlockHost`` class, ``grid`` is Idefix's ``GridHost`` class, and ``n`` is an integer representing the current number of the output +Access to input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``pydefix`` module exposes the full set of Idefix input parameters as a global variable ``input_parameters``. This variable is a nested dictionary with the structure ``dict[str, dict[str, list[str]]]``, where: + +* The first level keys are the block names from the input file (e.g., ``Grid``, ``Hydro``, ``TimeIntegrator``, etc.) +* The second level keys are the parameter names within each block +* The values are lists of strings containing the parameter values as specified in the input file + +For example, to access the grid parameters from your Python script: + +.. code-block:: python + + from pydefix import input_parameters + + # Access Grid block parameters + grid_params = input_parameters["Grid"] + x1_grid = grid_params["X1-grid"] # Returns a list like ["1", "0.0", "256", "u", "1.0"] + + # Access TimeIntegrator parameters + cfl = input_parameters["TimeIntegrator"]["CFL"][0] # Returns "0.6" as a string + +This allows your Python functions to access and use any parameter from the input file without needing to pass them explicitly. + MPI parallelism +++++++++++++++ When Idefix runs with MPI parallelism enabled, a python interpreter and script is launched by each MPI process. Each of these script is independent diff --git a/src/arrays.hpp b/src/arrays.hpp index 6d8989bda..91be12548 100644 --- a/src/arrays.hpp +++ b/src/arrays.hpp @@ -24,6 +24,8 @@ template using IdefixArray3D = Kokkos::View; template using IdefixArray4D = Kokkos::View; +template using IdefixArray5D = + Kokkos::View; template using IdefixHostArray1D = Kokkos::View; @@ -33,6 +35,8 @@ template using IdefixHostArray3D = Kokkos::View; template using IdefixHostArray4D = Kokkos::View; +template using IdefixHostArray5D = + Kokkos::View; // Atomic arrays template using IdefixAtomicArray1D = diff --git a/src/fluid/fluid.hpp b/src/fluid/fluid.hpp index d32b074fc..54af4df9e 100644 --- a/src/fluid/fluid.hpp +++ b/src/fluid/fluid.hpp @@ -178,6 +178,10 @@ class Fluid { IdefixArray4D J; // Electrical current // (only defined when non-ideal MHD effects are enabled) + // For muli-fluid simulations, we need to store the variables of all fluids in a single array + IdefixArray5D AllVc; // All cell-centered primitive variables index + IdefixArray5D AllUc; // All face-centered varariables + // Name of the fields (used in outputs) std::vector VcName; std::vector VsName; @@ -532,11 +536,31 @@ Fluid::Fluid(Grid &grid, Input &input, DataBlock *datain, int n) { // ALLOCATION SECION /////////////////// ///////////////////////////////////////// - // We now allocate the fields required by the hydro solver - Vc = IdefixArray4D(prefix+"_Vc", Phys::nvar+nTracer, - data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); - Uc = IdefixArray4D(prefix+"_Uc", Phys::nvar+nTracer, - data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); + if(std::string(Phys::prefix).compare("Dust") == 0) { + // Ensure Vc and Vs are subviews of the a parent array (own by the primary dust fluid object) + if(instanceNumber == 0) { + // Allocate AllVc + int nSpecies = input.Get("Dust","nSpecies",0); + AllVc = IdefixArray5D("Dust_AllVc", nSpecies, Phys::nvar+nTracer, + data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); + AllUc = IdefixArray5D("Dust_AllUc", nSpecies, Phys::nvar+nTracer, + data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); + } else { + AllVc = data->dust[0]->AllVc; + AllUc = data->dust[0]->AllUc; + } + // Create subviews for this dust specie + Vc = Kokkos::subview(AllVc, instanceNumber, + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + Uc = Kokkos::subview(AllUc, instanceNumber, + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + } else { + // We now allocate the fields required by the hydro solver + Vc = IdefixArray4D(prefix+"_Vc", Phys::nvar+nTracer, + data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); + Uc = IdefixArray4D(prefix+"_Uc", Phys::nvar+nTracer, + data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); + } data->states["current"].PushArray(Uc, State::center, prefix+"_Uc"); diff --git a/src/input.cpp b/src/input.cpp index 39fd44e9a..db7c696f5 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -431,3 +431,7 @@ void Input::PrintVersion() { idfx::cout << "Compiler version: " << CompilerInfo::version << std::endl; idfx::cout << "Compiler path: " << CompilerInfo::path << std::endl; } + +const IdefixInputContainer& Input::GetInputParameters() const { + return inputParameters; +} diff --git a/src/input.hpp b/src/input.hpp index 6f6c802cf..2f0de750b 100644 --- a/src/input.hpp +++ b/src/input.hpp @@ -63,6 +63,7 @@ class Input { void PrintLogo(); void PrintOptions(); void PrintVersion(); + const IdefixInputContainer& GetInputParameters() const; bool restartRequested{false}; //< Should we restart? int restartFileNumber; //< if yes, from which file? diff --git a/src/pydefix.cpp b/src/pydefix.cpp index 241797f5a..1b1a5447d 100644 --- a/src/pydefix.cpp +++ b/src/pydefix.cpp @@ -31,6 +31,9 @@ namespace py = pybind11; int Pydefix::ninstance = 0; +// Global pointer to input parameters for Python access +static const IdefixInputContainer* globalInputParameters = nullptr; + namespace PydefixTools { // Functions provided by Idefix in Pydefix for user convenience @@ -250,6 +253,11 @@ PYBIND11_EMBEDDED_MODULE(pydefix, m) { m.attr("prank") = idfx::prank; m.attr("psize") = idfx::psize; + // Expose input parameters as a global module attribute + if (globalInputParameters != nullptr) { + m.attr("input_parameters") = py::cast(*globalInputParameters); + } + m.def("GatherIdefixArray",&PydefixTools::GatherIdefixArray, py::arg("in"), py::arg("data"), @@ -277,7 +285,10 @@ void Pydefix::CallScript(std::string scriptName, std::string funcName, Ts... arg } -Pydefix::Pydefix(Input &input) { +Pydefix::Pydefix(Input &input) : inputPtr(&input) { + // Store reference to input parameters for Python access + globalInputParameters = &(input.GetInputParameters()); + // Check that the input has a [python] block if(input.CheckBlock("Python")) { this->isActive = true; diff --git a/src/pydefix.hpp b/src/pydefix.hpp index ee292549b..b3bac0608 100644 --- a/src/pydefix.hpp +++ b/src/pydefix.hpp @@ -44,6 +44,7 @@ class Pydefix { template void CallScript(std::string, std::string, Ts...); static int ninstance; + Input* inputPtr; // Store pointer to active Input instance std::string scriptFilename; std::string outputFunctionName; std::string initflowFunctionName; diff --git a/test/IO/pydefix/pydefix_example.py b/test/IO/pydefix/pydefix_example.py index d5a90d13c..f4c0c2638 100644 --- a/test/IO/pydefix/pydefix_example.py +++ b/test/IO/pydefix/pydefix_example.py @@ -18,6 +18,34 @@ from pydefix import * +def test_input_parameters_access(): + """Test that input_parameters are accessible from Python.""" + # Access the global input_parameters dict + params = input_parameters + + # Verify it's a dict + assert isinstance(params, dict), "input_parameters should be a dict" + + # Verify we can access Grid parameters + assert "Grid" in params, "Grid block should be in input_parameters" + grid_params = params["Grid"] + assert isinstance(grid_params, dict), "Grid should be a dict" + + # Verify we can access specific parameters + assert "X1-grid" in grid_params, "X1-grid should be in Grid params" + x1_grid = grid_params["X1-grid"] + assert isinstance(x1_grid, list), "X1-grid should be a list" + assert len(x1_grid) > 0, "X1-grid should have values" + + # Verify we can read actual values from the ini file + # From idefix.ini: X1-grid is "1 0.0 256 u 1.0" + assert x1_grid[0] == "1", f"Expected '1', got {x1_grid[0]}" + assert x1_grid[1] == "0.0", f"Expected '0.0', got {x1_grid[1]}" + assert x1_grid[2] == "256", f"Expected '256', got {x1_grid[2]}" + + print("✓ input_parameters access test passed!") + + # The output function # the only argument is dataBlockHost python object, wrapping a dataBlockHost Idefix object def output(data, grid, n): @@ -44,6 +72,9 @@ def output(data, grid, n): def initflow(data): + # Test input_parameters access on first call + test_input_parameters_access() + # Field amplitude B0 = 1 / np.sqrt(4 * np.pi)