Merge branch 'rinside-everywhere' into 'main'

Implement RInside as singleton pattern

See merge request naaice/poet!16
This commit is contained in:
Max Lübke 2023-07-21 12:53:07 +02:00
commit e62472237d
10 changed files with 41 additions and 416 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
Time-stamp: "Last modified 2023-07-20 11:30:44 delucia" Time-stamp: "Last modified 2023-07-21 12:34:43 mluebke"
--> -->
# POET # POET
@ -69,8 +69,6 @@ following available options:
DHT usage. Defaults to _OFF_. DHT usage. Defaults to _OFF_.
- **POET_ENABLE_TESTING**=_boolean_ - enables small set of unit tests (more to - **POET_ENABLE_TESTING**=_boolean_ - enables small set of unit tests (more to
come). Defaults to _OFF_. come). Defaults to _OFF_.
- **POET_USE_PRM_BACKEND**=_bollean_ - use the PhreeqcRM parallelization instead
of POET's one. Intended for debugging purposes for modellers.
### Example: Build from scratch ### Example: Build from scratch

View File

@ -1,14 +1,7 @@
configure_file(poet.h.in poet.h) configure_file(poet.h.in poet.h)
if(POET_USE_PRM_BACKEND) add_executable(poet poet.cpp)
set(poet_SRC poet_prm.cpp)
else()
set(poet_SRC poet.cpp)
endif()
add_executable(poet ${poet_SRC})
target_include_directories(poet PUBLIC "${CMAKE_CURRENT_BINARY_DIR}") target_include_directories(poet PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
target_link_libraries(poet PUBLIC poet_lib MPI::MPI_CXX) target_link_libraries(poet PUBLIC poet_lib MPI::MPI_CXX)
#target_compile_definitions(poet PRIVATE OMPI_SKIP_MPICXX)
install(TARGETS poet DESTINATION bin) install(TARGETS poet DESTINATION bin)

View File

@ -19,12 +19,12 @@
*/ */
#include "poet/ChemistryModule.hpp" #include "poet/ChemistryModule.hpp"
#include <RInside.h>
#include <Rcpp.h> #include <Rcpp.h>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <poet/DiffusionModule.hpp> #include <poet/DiffusionModule.hpp>
#include <poet/Grid.hpp> #include <poet/Grid.hpp>
#include <poet/RInsidePOET.hpp>
#include <poet/SimParams.hpp> #include <poet/SimParams.hpp>
#include <cstring> #include <cstring>
@ -292,8 +292,7 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/* initialize R runtime */ RInsidePOET &R = RInsidePOET::getInstance();
RInside R(argc, argv);
/*Loading Dependencies*/ /*Loading Dependencies*/
// TODO: kann raus // TODO: kann raus

View File

@ -1,285 +0,0 @@
/*
** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of
** Potsdam)
**
** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam)
**
** POET is free software; you can redistribute it and/or modify it under the
** terms of the GNU General Public License as published by the Free Software
** Foundation; either version 2 of the License, or (at your option) any later
** version.
**
** POET is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
** A PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License along with
** this program; if not, write to the Free Software Foundation, Inc., 51
** Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "poet/ChemistryModule.hpp"
#include <RInside.h>
#include <Rcpp.h>
#include <cstdint>
#include <cstdlib>
#include <poet/DiffusionModule.hpp>
#include <poet/Grid.hpp>
#include <poet/SimParams.hpp>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <mpi.h>
#include <poet.h>
using namespace std;
using namespace poet;
using namespace Rcpp;
void set_chem_parameters(poet::ChemistryModule &chem, uint32_t wp_size,
const std::string &database_path) {
chem.SetErrorHandlerMode(1);
chem.SetComponentH2O(false);
chem.SetRebalanceFraction(0.5);
chem.SetRebalanceByCell(true);
chem.UseSolutionDensityVolume(false);
chem.SetPartitionUZSolids(false);
// Set concentration units
// 1, mg/L; 2, mol/L; 3, kg/kgs
chem.SetUnitsSolution(2);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsPPassemblage(1);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsExchange(1);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsSurface(1);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsGasPhase(1);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsSSassemblage(1);
// 0, mol/L cell; 1, mol/L water; 2 mol/L rock
chem.SetUnitsKinetics(1);
// Set representative volume
std::vector<double> rv;
rv.resize(wp_size, 1.0);
chem.SetRepresentativeVolume(rv);
// Set initial porosity
std::vector<double> por;
por.resize(wp_size, 1);
chem.SetPorosity(por);
// Set initial saturation
std::vector<double> sat;
sat.resize(wp_size, 1.0);
chem.SetSaturation(sat);
// Load database
chem.LoadDatabase(database_path);
}
inline double RunMasterLoop(SimParams &params, RInside &R, Grid &grid,
ChemistryParams &chem_params,
const GridParams &g_params, uint32_t nxyz_master) {
DiffusionModule diffusion(poet::DiffusionParams(R), grid);
/* Iteration Count is dynamic, retrieving value from R (is only needed by
* master for the following loop) */
uint32_t maxiter = R.parseEval("mysetup$iterations");
double sim_time = .0;
ChemistryModule chem(grid.GetTotalCellCount(), MPI_COMM_WORLD);
set_chem_parameters(chem, nxyz_master, chem_params.database_path);
chem.RunInitFile(chem_params.input_script);
chem.SetTimeStep(0);
chem.RunCells();
StateMemory *chem_state = grid.RegisterState("state_C", chem.GetPropNames());
auto &chem_field = chem_state->mem;
chem_field = chem.GetField();
/* SIMULATION LOOP */
double dStartTime = MPI_Wtime();
for (uint32_t iter = 1; iter < maxiter + 1; iter++) {
uint32_t tick = 0;
// cout << "CPP: Evaluating next time step" << endl;
// R.parseEvalQ("mysetup <- master_iteration_setup(mysetup)");
double dt = Rcpp::as<double>(
R.parseEval("mysetup$timesteps[" + std::to_string(iter) + "]"));
cout << "CPP: Next time step is " << dt << "[s]" << endl;
/* displaying iteration number, with C++ and R iterator */
cout << "CPP: Going through iteration " << iter << endl;
cout << "CPP: R's $iter: " << ((uint32_t)(R.parseEval("mysetup$iter")))
<< ". Iteration" << endl;
/* run transport */
// TODO: transport to diffusion
diffusion.simulate(dt);
grid.PreModuleFieldCopy(tick++);
cout << "CPP: Chemistry" << endl;
chem.SetTimeStep(dt);
chem.SetConcentrations(chem_field);
chem.SetTimeStep(dt);
chem.RunCells();
chem_field = chem.GetField();
grid.WriteFieldsToR(R);
grid.PreModuleFieldCopy(tick++);
R["req_dt"] = dt;
R["simtime"] = (sim_time += dt);
R.parseEval("mysetup$req_dt <- req_dt");
R.parseEval("mysetup$simtime <- simtime");
// MDL master_iteration_end just writes on disk state_T and
// state_C after every iteration if the cmdline option
// --ignore-results is not given (and thus the R variable
// store_result is TRUE)
R.parseEvalQ("mysetup <- master_iteration_end(setup=mysetup)");
cout << endl
<< "CPP: End of *coupling* iteration " << iter << "/" << maxiter
<< endl
<< endl;
// MPI_Barrier(MPI_COMM_WORLD);
} // END SIMULATION LOOP
R.parseEvalQ("profiling <- list()");
R["simtime_chemistry"] = chem.GetChemistryTime();
R.parseEvalQ("profiling$simtime_chemistry <- simtime_chemistry");
chem.MpiWorkerBreak();
diffusion.end();
return MPI_Wtime() - dStartTime;
}
int main(int argc, char *argv[]) {
double dSimTime, sim_end;
int world_size, world_rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
if (world_rank == 0) {
cout << "Running POET in version " << poet_version << endl << endl;
}
if (world_rank > 0) {
{
uint32_t nxyz;
MPI_Bcast(&nxyz, 1, MPI_UINT32_T, 0, MPI_COMM_WORLD);
ChemistryModule worker(nxyz, MPI_COMM_WORLD);
worker.MpiWorker();
}
MPI_Barrier(MPI_COMM_WORLD);
cout << "CPP: finished, cleanup of process " << world_rank << endl;
MPI_Finalize();
return EXIT_SUCCESS;
}
/* initialize R runtime */
RInside R(argc, argv);
/*Loading Dependencies*/
// TODO: kann raus
std::string r_load_dependencies = "source('../R_lib/kin_r_library.R');";
R.parseEvalQ(r_load_dependencies);
SimParams params(world_rank, world_size);
int pret = params.parseFromCmdl(argv, R);
if (pret == poet::PARSER_ERROR) {
MPI_Finalize();
return EXIT_FAILURE;
} else if (pret == poet::PARSER_HELP) {
MPI_Finalize();
return EXIT_SUCCESS;
}
cout << "CPP: R Init (RInside) on process " << world_rank << endl;
R.parseEvalQ("mysetup <- setup");
// if (world_rank == 0) { // get timestep vector from
// grid_init function ... //
std::string master_init_code = "mysetup <- master_init(setup=setup)";
R.parseEval(master_init_code);
Grid grid;
GridParams g_params(R);
grid.InitModuleFromParams(g_params);
grid.PushbackModuleFlow(poet::DIFFUSION_MODULE_NAME, CHEMISTRY_MODULE_NAME);
grid.PushbackModuleFlow(CHEMISTRY_MODULE_NAME, poet::DIFFUSION_MODULE_NAME);
params.initVectorParams(R, grid.GetSpeciesCount());
// MDL: store all parameters
if (world_rank == 0) {
cout << "CPP: Calling R Function to store calling parameters" << endl;
R.parseEvalQ("StoreSetup(setup=mysetup)");
}
if (world_rank == 0) {
cout << "CPP: Init done on process with rank " << world_rank << endl;
}
// MPI_Barrier(MPI_COMM_WORLD);
poet::ChemistryParams chem_params(R);
/* THIS IS EXECUTED BY THE MASTER */
uint32_t nxyz = grid.GetTotalCellCount();
MPI_Bcast(&nxyz, 1, MPI_UINT32_T, 0, MPI_COMM_WORLD);
uint32_t nxyz_master = grid.GetTotalCellCount();
dSimTime = RunMasterLoop(params, R, grid, chem_params, g_params, nxyz_master);
cout << "CPP: finished simulation loop" << endl;
cout << "CPP: start timing profiling" << endl;
R["simtime"] = dSimTime;
R.parseEvalQ("profiling$simtime <- simtime");
string r_vis_code;
r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));";
R.parseEval(r_vis_code);
cout << "CPP: Done! Results are stored as R objects into <"
<< params.getOutDir() << "/timings.rds>" << endl;
MPI_Barrier(MPI_COMM_WORLD);
cout << "CPP: finished, cleanup of process " << world_rank << endl;
MPI_Finalize();
if (world_rank == 0) {
cout << "CPP: done, bye!" << endl;
}
exit(0);
}

View File

@ -1,4 +1,4 @@
// Time-stamp: "Last modified 2023-07-12 12:50:53 mluebke" // Time-stamp: "Last modified 2023-07-21 12:35:23 mluebke"
#ifndef CHEMISTRYMODULE_H_ #ifndef CHEMISTRYMODULE_H_
#define CHEMISTRYMODULE_H_ #define CHEMISTRYMODULE_H_
@ -24,20 +24,6 @@ namespace poet {
*/ */
class ChemistryModule : public PhreeqcRM { class ChemistryModule : public PhreeqcRM {
public: public:
#ifdef POET_USE_PRM
/**
* Creates a new instance of Chemistry module with given grid cell count and
* using MPI communicator.
*
* Constructor is just a wrapper around PhreeqcRM's constructor, so just calls
* the base class constructor.
*
* \param nxyz Count of grid cells.
* \param communicator MPI communicator where work will be distributed.
*/
ChemistryModule(uint32_t nxyz, MPI_Comm communicator)
: PhreeqcRM(nxyz, communicator), n_cells(nxyz){};
#else
/** /**
* Creates a new instance of Chemistry module with given grid cell count, work * Creates a new instance of Chemistry module with given grid cell count, work
* package size and communicator. * package size and communicator.
@ -59,7 +45,6 @@ public:
* Deconstructor, which frees DHT data structure if used. * Deconstructor, which frees DHT data structure if used.
*/ */
~ChemistryModule(); ~ChemistryModule();
#endif
/** /**
* Parses the input script and extract information needed during runtime. * Parses the input script and extract information needed during runtime.
@ -92,8 +77,6 @@ public:
*/ */
auto GetChemistryTime() const { return this->chem_t; } auto GetChemistryTime() const { return this->chem_t; }
#ifndef POET_USE_PRM
/** /**
* Create a new worker instance inside given MPI communicator. * Create a new worker instance inside given MPI communicator.
* *
@ -126,9 +109,9 @@ public:
* Enumerating DHT file options * Enumerating DHT file options
*/ */
enum { enum {
DHT_FILES_DISABLED = 0, //!< disabled file output DHT_FILES_DISABLED = 0, //!< disabled file output
DHT_FILES_SIMEND, //!< only output of snapshot after simulation DHT_FILES_SIMEND, //!< only output of snapshot after simulation
DHT_FILES_ITEREND //!< output snapshots after each iteration DHT_FILES_ITEREND //!< output snapshots after each iteration
}; };
/** /**
@ -281,11 +264,8 @@ public:
* \param enabled True if print progressbar, false if not. * \param enabled True if print progressbar, false if not.
*/ */
void setProgressBarPrintout(bool enabled); void setProgressBarPrintout(bool enabled);
#endif
protected: protected:
#ifdef POET_USE_PRM
void PrmToPoetField(std::vector<double> &field);
#else
enum { enum {
CHEM_INIT, CHEM_INIT,
CHEM_WP_SIZE, CHEM_WP_SIZE,
@ -401,8 +381,6 @@ protected:
bool print_progessbar{false}; bool print_progessbar{false};
#endif
double chem_t = 0.; double chem_t = 0.;
uint32_t n_cells = 0; uint32_t n_cells = 0;

View File

@ -0,0 +1,21 @@
#ifndef RPOET_H_
#define RPOET_H_
#include <RInside.h>
class RInsidePOET : public RInside {
public:
static RInsidePOET &getInstance() {
static RInsidePOET instance;
return instance;
}
RInsidePOET(RInsidePOET const &) = delete;
void operator=(RInsidePOET const &) = delete;
private:
RInsidePOET() : RInside(){};
};
#endif // RPOET_H_

View File

@ -1,6 +1,4 @@
add_subdirectory(DataStructures) file(GLOB_RECURSE poet_lib_SRC
file(GLOB poet_lib_SRC
CONFIGURE_DEPENDS CONFIGURE_DEPENDS
"*.cpp" "*.c") "*.cpp" "*.c")
@ -10,7 +8,15 @@ find_library(CRYPTO_LIBRARY crypto)
add_library(poet_lib ${poet_lib_SRC}) add_library(poet_lib ${poet_lib_SRC})
target_include_directories(poet_lib PUBLIC ${PROJECT_SOURCE_DIR}/include) target_include_directories(poet_lib PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(poet_lib PUBLIC target_link_libraries(poet_lib PUBLIC
MPI::MPI_CXX ${MATH_LIBRARY} RRuntime tug PhreeqcRM DataStructures ChemistryModule) MPI::MPI_CXX ${MATH_LIBRARY} RRuntime PhreeqcRM tug)
target_compile_definitions(poet_lib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) target_compile_definitions(poet_lib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX)
add_subdirectory(ChemistryModule) mark_as_advanced(PHREEQCRM_BUILD_MPI PHREEQCRM_DISABLE_OPENMP)
set(PHREEQCRM_DISABLE_OPENMP ON CACHE BOOL "" FORCE)
option(POET_DHT_DEBUG "Build with DHT debug info" OFF)
if(POET_DHT_DEBUG)
target_compile_definitions(poet_lib PRIVATE DHT_STATISTICS)
endif()

View File

@ -1,32 +0,0 @@
option(POET_USE_PRM_BACKEND "Use PhreeqcRM parallelization instead of poet's." OFF)
option(POET_DHT_DEBUG "Build with DHT debug info" OFF)
list(APPEND CHEM_MODEL_SRC "ChemistryModule.cpp" )
mark_as_advanced(PHREEQCRM_BUILD_MPI PHREEQCRM_DISABLE_OPENMP)
set(PHREEQCRM_DISABLE_OPENMP ON CACHE BOOL "" FORCE)
if(POET_USE_PRM_BACKEND)
set(PHREEQCRM_BUILD_MPI ON CACHE BOOL "" FORCE)
target_compile_definitions(poet_lib PRIVATE POET_USE_PRM)
else()
set(PHREEQCRM_BUILD_MPI OFF CACHE BOOL "" FORCE)
list(APPEND CHEM_MODEL_SRC "WorkerFunctions.cpp" "MasterFunctions.cpp" "DHT.c" "DHT_Wrapper.cpp" "HashFunctions.cpp")
endif()
add_library(ChemistryModule ${CHEM_MODEL_SRC})
target_include_directories(ChemistryModule PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(ChemistryModule
PUBLIC MPI::MPI_CXX PhreeqcRM
PRIVATE ${MATH_LIBRARY}
)
target_compile_definitions(ChemistryModule PUBLIC OMPI_SKIP_MPICXX)
if(POET_DHT_DEBUG)
target_compile_definitions(ChemistryModule PRIVATE DHT_STATISTICS)
endif()
if(POET_USE_PRM_BACKEND)
target_compile_definitions(ChemistryModule PUBLIC POET_USE_PRM)
endif()

View File

@ -12,7 +12,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#ifndef POET_USE_PRM
poet::ChemistryModule::ChemistryModule(uint32_t nxyz, uint32_t wp_size, poet::ChemistryModule::ChemistryModule(uint32_t nxyz, uint32_t wp_size,
MPI_Comm communicator) MPI_Comm communicator)
: PhreeqcRM(nxyz, 1), group_comm(communicator), wp_size(wp_size) { : PhreeqcRM(nxyz, 1), group_comm(communicator), wp_size(wp_size) {
@ -42,10 +41,7 @@ poet::ChemistryModule::createWorker(MPI_Comm communicator) {
return ChemistryModule(wp_size, wp_size, communicator); return ChemistryModule(wp_size, wp_size, communicator);
} }
#endif
void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) { void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) {
#ifndef POET_USE_PRM
if (this->is_master) { if (this->is_master) {
int f_type = CHEM_INIT; int f_type = CHEM_INIT;
PropagateFunctionType(f_type); PropagateFunctionType(f_type);
@ -54,7 +50,6 @@ void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) {
ChemBCast(&count, 1, MPI_INT); ChemBCast(&count, 1, MPI_INT);
ChemBCast(const_cast<char *>(input_script_path.data()), count, MPI_CHAR); ChemBCast(const_cast<char *>(input_script_path.data()), count, MPI_CHAR);
} }
#endif
this->RunFile(true, true, false, input_script_path); this->RunFile(true, true, false, input_script_path);
this->RunString(true, false, false, "DELETE; -all; PRINT; -warnings 0;"); this->RunString(true, false, false, "DELETE; -all; PRINT; -warnings 0;");
@ -69,7 +64,6 @@ void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) {
char equilibrium = (speciesPerModule[3] == 0 ? -1 : 1); char equilibrium = (speciesPerModule[3] == 0 ? -1 : 1);
char surface = (speciesPerModule[4] == 0 ? -1 : 1); char surface = (speciesPerModule[4] == 0 ? -1 : 1);
#ifdef POET_USE_PRM
std::vector<int> ic1; std::vector<int> ic1;
ic1.resize(this->nxyz * 7, -1); ic1.resize(this->nxyz * 7, -1);
// TODO: hardcoded reaction modules // TODO: hardcoded reaction modules
@ -84,25 +78,8 @@ void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) {
} }
this->InitialPhreeqc2Module(ic1); this->InitialPhreeqc2Module(ic1);
#else
std::vector<int> ic1;
ic1.resize(this->nxyz * 7, -1);
// TODO: hardcoded reaction modules
for (int i = 0; i < nxyz; i++) {
ic1[i] = 1; // Solution 1
ic1[nxyz + i] = equilibrium; // Equilibrium 1
ic1[2 * nxyz + i] = exchange; // Exchange none
ic1[3 * nxyz + i] = surface; // Surface none
ic1[4 * nxyz + i] = -1; // Gas phase none
ic1[5 * nxyz + i] = -1; // Solid solutions none
ic1[6 * nxyz + i] = kinetics; // Kinetics 1
}
this->InitialPhreeqc2Module(ic1);
#endif
} }
#ifndef POET_USE_PRM
void poet::ChemistryModule::initializeField(const Field &trans_field) { void poet::ChemistryModule::initializeField(const Field &trans_field) {
if (is_master) { if (is_master) {
@ -368,27 +345,3 @@ void poet::ChemistryModule::unshuffleField(const std::vector<double> &in_buffer,
} }
} }
} }
#else // POET_USE_PRM
inline void poet::ChemistryModule::PrmToPoetField(std::vector<double> &field) {
this->getDumpedField(field);
}
void poet::ChemistryModule::RunCells() {
PhreeqcRM::RunCells();
std::vector<double> tmp_field;
PrmToPoetField(tmp_field);
this->field = tmp_field;
for (uint32_t i = 0; i < field.size(); i++) {
uint32_t back_i = static_cast<uint32_t>(i / this->nxyz);
uint32_t mod_i = i % this->nxyz;
field[i] = tmp_field[back_i + (mod_i * this->prop_count)];
}
}
#endif

View File

@ -1,6 +0,0 @@
file(GLOB DataStructures_SRC
CONFIGURE_DEPENDS
"*.cpp" "*.c")
add_library(DataStructures ${DataStructures_SRC})
target_include_directories(DataStructures PUBLIC ${PROJECT_SOURCE_DIR}/include)