From c05061361460006493b8781e11bceda90389e5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Thu, 7 Mar 2024 13:54:53 +0000 Subject: [PATCH 01/77] Add apps directory and initializer application --- CMakeLists.txt | 2 ++ apps/CMakeLists.txt | 4 ++++ apps/initializer/main.cpp | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 apps/CMakeLists.txt create mode 100644 apps/initializer/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8faf514e6..e6701b564 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,3 +41,5 @@ endif() option(BUILD_DOC "Build documentation with doxygen" OFF) add_subdirectory(docs) + +add_subdirectory(apps) \ No newline at end of file diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt new file mode 100644 index 000000000..928a20444 --- /dev/null +++ b/apps/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB INIT_SRCS CONFIGURE_DEPENDS "initializer/*.cpp") + +add_executable(poet_initializer ${INIT_SRCS}) +target_link_libraries(poet_initializer RRuntime tug) \ No newline at end of file diff --git a/apps/initializer/main.cpp b/apps/initializer/main.cpp new file mode 100644 index 000000000..5297158c5 --- /dev/null +++ b/apps/initializer/main.cpp @@ -0,0 +1,3 @@ +#include + +int main(int argc, char **argv) {} \ No newline at end of file From a1e771f7ed76f06e13c2e27251595120dde1d0de Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 16:57:44 +0100 Subject: [PATCH 02/77] Add iphreeqc and init_r_lib submodules, and make necessary changes to CMakeLists.txt and src/initializer.cpp --- .gitmodules | 9 ++-- CMakeLists.txt | 9 ++-- R_lib/init_r_lib.R | 37 ++++++++++++++ ext/iphreeqc | 1 + ext/phreeqcrm | 1 - src/CMakeLists.txt | 32 ++++++++++-- src/Init/GridInit.cpp | 108 +++++++++++++++++++++++++++++++++++++++ src/Init/InitialList.cpp | 7 +++ src/Init/InitialList.hpp | 44 ++++++++++++++++ src/initializer.cpp | 35 +++++++++++++ src/poet.hpp.in | 2 + 11 files changed, 273 insertions(+), 12 deletions(-) create mode 100644 R_lib/init_r_lib.R create mode 160000 ext/iphreeqc delete mode 160000 ext/phreeqcrm create mode 100644 src/Init/GridInit.cpp create mode 100644 src/Init/InitialList.cpp create mode 100644 src/Init/InitialList.hpp create mode 100644 src/initializer.cpp diff --git a/.gitmodules b/.gitmodules index 744dfdb41..645e48d00 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,9 +2,12 @@ path = ext/tug url = ../tug.git -[submodule "ext/phreeqcrm"] - path = ext/phreeqcrm - url = ../phreeqcrm-gfz.git [submodule "ext/doctest"] path = ext/doctest url = https://github.com/doctest/doctest.git +[submodule "ext/phreeqc"] + path = ext/phreeqc + url = git@git.gfz-potsdam.de:naaice/phreeqcpoet.git +[submodule "ext/iphreeqc"] + path = ext/iphreeqc + url = git@git.gfz-potsdam.de:naaice/iphreeqc.git diff --git a/CMakeLists.txt b/CMakeLists.txt index e6701b564..cef0776ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,9 @@ find_package(MPI REQUIRED) find_package(RRuntime REQUIRED) +add_compile_options(-fsanitize=address -fno-omit-frame-pointer) +add_link_options(-fsanitize=address) + add_subdirectory(src) add_subdirectory(bench) @@ -29,7 +32,7 @@ add_subdirectory(bench) set(TUG_ENABLE_TESTING OFF CACHE BOOL "" FORCE) add_subdirectory(ext/tug EXCLUDE_FROM_ALL) -add_subdirectory(ext/phreeqcrm EXCLUDE_FROM_ALL) +add_subdirectory(ext/iphreeqc EXCLUDE_FROM_ALL) option(POET_ENABLE_TESTING "Build test suite for POET" OFF) @@ -40,6 +43,4 @@ endif() option(BUILD_DOC "Build documentation with doxygen" OFF) -add_subdirectory(docs) - -add_subdirectory(apps) \ No newline at end of file +add_subdirectory(docs) \ No newline at end of file diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R new file mode 100644 index 000000000..f2dfbb71c --- /dev/null +++ b/R_lib/init_r_lib.R @@ -0,0 +1,37 @@ +input <- readRDS("/home/max/Storage/poet/build/apps/out.rds") + +grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) + +library(data.table) + +pqc_to_grid <- function(pqc_in, grid) { + # Convert the input DataFrame to a data.table + dt <- data.table(pqc_in) + + # Flatten the matrix into a vector + id_vector <- as.vector(t(grid)) + + # Initialize an empty data.table to store the results + result_dt <- data.table() + + # Iterate over each ID in the vector + for (id_mat in id_vector) { + # Find the matching row in the data.table + matching_dt <- dt[id == id_mat] + + # Append the matching data.table row to the result data.table + result_dt <- rbind(result_dt, matching_dt) + } + + # Remove all columns which only contain NaN + # result_dt <- result_dt[, colSums(is.na(result_dt)) != nrow(result_dt)] + + res_df <- as.data.frame(result_dt) + + return(res_df[, colSums(is.na(res_df)) != nrow(res_df)]) +} + +pqc_init <- pqc_to_grid(input, grid_def) +test <- pqc_init + +# remove column with all NA diff --git a/ext/iphreeqc b/ext/iphreeqc new file mode 160000 index 000000000..f3f86bb4a --- /dev/null +++ b/ext/iphreeqc @@ -0,0 +1 @@ +Subproject commit f3f86bb4ac1d3b70aec7437781875072f2896ae3 diff --git a/ext/phreeqcrm b/ext/phreeqcrm deleted file mode 160000 index 6ed14c353..000000000 --- a/ext/phreeqcrm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ed14c35322a245e3a9776ef262c0ac0eba3b301 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1494c0849..3f6d4f05c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,20 @@ +add_library(poetinitlib + Init/InitialList.cpp + Init/GridInit.cpp +) + +target_link_libraries(poetinitlib PUBLIC + RRuntime + IPhreeqcPOET + tug +) + +target_include_directories(poetinitlib PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/Init" +) + +target_compile_definitions(poetinitlib PUBLIC STRICT_R_HEADERS) + add_library(poetlib Base/Grid.cpp Base/SimParams.cpp @@ -17,8 +34,9 @@ target_link_libraries(poetlib PUBLIC MPI::MPI_C ${MATH_LIBRARY} RRuntime - PhreeqcRM + PhreeqcRM tug + poetinitlib ) target_compile_definitions(poetlib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) @@ -39,11 +57,17 @@ if (POET_PHT_ADDITIONAL_INFO) endif() file(READ "${PROJECT_SOURCE_DIR}/R_lib/kin_r_library.R" R_KIN_LIB ) +file(READ "${PROJECT_SOURCE_DIR}/R_lib/init_r_lib.R" R_INIT_LIB) configure_file(poet.hpp.in poet.hpp @ONLY) -add_executable(poet poet.cpp) -target_link_libraries(poet PRIVATE poetlib MPI::MPI_C RRuntime) -target_include_directories(poet PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") +# add_executable(poet poet.cpp) +# target_link_libraries(poet PRIVATE poetlib MPI::MPI_C RRuntime) +# target_include_directories(poet PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + +add_executable(poet_init initializer.cpp) +target_link_libraries(poet_init PRIVATE poetinitlib RRuntime) +target_include_directories(poet_init PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") install(TARGETS poet DESTINATION bin) + diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp new file mode 100644 index 000000000..c3cc0b379 --- /dev/null +++ b/src/Init/GridInit.cpp @@ -0,0 +1,108 @@ +#include "InitialList.hpp" + +#include +#include +#include + +namespace poet { +static Rcpp::NumericMatrix +pqcScriptToGrid(RInside &R, const std::string &script, const std::string &db, + std::map &raw_dumps) { + IPhreeqcPOET phreeqc(db, script); + + const auto solution_ids = phreeqc.getSolutionIds(); + auto col_names = phreeqc.getInitNames(); + const auto concentrations = phreeqc.getInitValues(); + + // add "id" to the front of the column names + + const std::size_t ncols = col_names.size(); + const std::size_t nrows = solution_ids.size(); + + col_names.insert(col_names.begin(), "id"); + + Rcpp::NumericMatrix mat(nrows, ncols + 1); + + for (std::size_t i = 0; i < nrows; i++) { + mat(i, 0) = solution_ids[i]; + for (std::size_t j = 0; j < ncols; ++j) { + mat(i, j + 1) = concentrations[i][j]; + } + } + + Rcpp::colnames(mat) = Rcpp::wrap(col_names); + + raw_dumps = phreeqc.raw_dumps(); + + return mat; +} + +static inline Rcpp::List matToGrid(RInside &R, const Rcpp::NumericMatrix &mat, + const Rcpp::NumericMatrix &grid) { + // Rcpp::List res; + // res["init_mat"] = mat; + // res["grid_mat"] = grid; + + Rcpp::Function pqc_to_grid("pqc_to_grid"); + + // R.parseEvalQ("res_df <- pqc_to_grid(init_mat, grid_mat)"); + + return pqc_to_grid(mat, grid); +} + +void InitialList::initGrid(const Rcpp::List &grid_input) { + // parse input values + const std::string script = Rcpp::as(grid_input["pqc_in"]); + const std::string database = Rcpp::as(grid_input["pqc_db"]); + + std::string script_rp(PATH_MAX, '\0'); + std::string database_rp(PATH_MAX, '\0'); + + if (realpath(script.c_str(), script_rp.data()) == nullptr) { + throw std::runtime_error("Failed to resolve the path of the Phreeqc input" + + script); + } + + if (realpath(database.c_str(), database_rp.data()) == nullptr) { + throw std::runtime_error("Failed to resolve the path of the database" + + database); + } + + Rcpp::NumericMatrix grid_def = grid_input["grid_def"]; + Rcpp::NumericVector grid_size = grid_input["grid_size"]; + // Rcpp::NumericVector constant_cells = grid["constant_cells"].; + + this->n_rows = grid_def.nrow(); + this->n_cols = grid_def.ncol(); + + this->s_rows = grid_size[0]; + this->s_cols = grid_size[1]; + + this->dim = n_cols == 1 ? 1 : 2; + + if (this->n_cols > 1 && this->n_rows == 1) { + throw std::runtime_error( + "Dimensions of grid definition does not match the expected format " + "(n_rows > 1, n_cols >= 1)."); + } + + if (this->dim != grid_size.size()) { + throw std::runtime_error( + "Dimensions of grid does not match the dimension of grid definition."); + } + + if (this->s_rows <= 0 || this->s_cols <= 0) { + throw std::runtime_error("Grid size must be positive."); + } + + this->phreeqc_mat = + pqcScriptToGrid(R, script_rp, database_rp, this->pqc_raw_dumps); + this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); + + // R["pqc_mat"] = this->phreeqc_mat; + // R["grid_def"] = initial_grid; + + // R.parseEval("print(pqc_mat)"); + // R.parseEval("print(grid_def)"); +} +} // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp new file mode 100644 index 000000000..d12c6e314 --- /dev/null +++ b/src/Init/InitialList.cpp @@ -0,0 +1,7 @@ +#include "InitialList.hpp" + +namespace poet { +void InitialList::initializeFromList(const Rcpp::List &setup) { + initGrid(setup["grid"]); +} +} // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp new file mode 100644 index 000000000..e3f86ebf6 --- /dev/null +++ b/src/Init/InitialList.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../DataStructures/Field.hpp" + +#include +#include +#include +#include + +namespace poet { + +class InitialList { +public: + InitialList(RInside &R) : R(R){}; + + void initializeFromList(const Rcpp::List &setup); + + void importList(const std::string &file_name); + Rcpp::List exportList(const std::string &file_name); + +private: + RInside &R; + + // Grid members + void initGrid(const Rcpp::List &grid_input); + std::uint8_t dim; + + std::uint32_t n_cols; + std::uint32_t n_rows; + + double s_cols; + double s_rows; + + std::vector constant_cells; + + Rcpp::List initial_grid; + + // No export + Rcpp::NumericMatrix phreeqc_mat; + + // Initialized by grid, modified by chemistry + std::map pqc_raw_dumps; +}; +} // namespace poet \ No newline at end of file diff --git a/src/initializer.cpp b/src/initializer.cpp new file mode 100644 index 000000000..8d1c0221e --- /dev/null +++ b/src/initializer.cpp @@ -0,0 +1,35 @@ +#include "Init/InitialList.hpp" +#include "poet.hpp" + +#include +#include + +#include +#include + +int main(int argc, char **argv) { + if (argc < 2 || argc > 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + RInside R(argc, argv); + + R.parseEvalQ(init_r_library); + + const std::string script = argv[1]; + R.parseEvalQ("source('" + script + "')"); + + Rcpp::List setup = R["setup"]; + + // Rcpp::List grid = R.parseEval("setup$grid"); + + // Rcpp::List results; + + poet::InitialList init(R); + + init.initializeFromList(setup); + + // parseGrid(R, grid, results); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/poet.hpp.in b/src/poet.hpp.in index 666fbaa08..115ac7dd7 100644 --- a/src/poet.hpp.in +++ b/src/poet.hpp.in @@ -7,4 +7,6 @@ static const char *poet_version = "@POET_VERSION@"; // using the Raw string literal to avoid escaping the quotes static inline std::string kin_r_library = R"(@R_KIN_LIB@)"; +static inline std::string init_r_library = R"(@R_INIT_LIB@)"; + #endif // POET_H From 3d203f307fc83305e4f12f9844a60d46955d8f70 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 16:58:37 +0100 Subject: [PATCH 03/77] Remove installation of poet binary --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3f6d4f05c..d53484cd1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,5 +69,5 @@ add_executable(poet_init initializer.cpp) target_link_libraries(poet_init PRIVATE poetinitlib RRuntime) target_include_directories(poet_init PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") -install(TARGETS poet DESTINATION bin) +# install(TARGETS poet DESTINATION bin) From 9b144f8ec58b1f9a543a7a780ca946f196b92510 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 17:11:53 +0100 Subject: [PATCH 04/77] Update CMakeLists.txt and add new files for barite_het simulation --- CMakeLists.txt | 4 +- bench/barite/het/barite_het.pqi | 79 +++++++++++++++++++++++++++++++++ bench/barite/het/test.R | 15 +++++++ src/Init/GridInit.cpp | 8 ++-- 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 bench/barite/het/barite_het.pqi create mode 100644 bench/barite/het/test.R diff --git a/CMakeLists.txt b/CMakeLists.txt index cef0776ed..a57f557df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,8 @@ find_package(MPI REQUIRED) find_package(RRuntime REQUIRED) -add_compile_options(-fsanitize=address -fno-omit-frame-pointer) -add_link_options(-fsanitize=address) +# add_compile_options(-fsanitize=address -fno-omit-frame-pointer) +# add_link_options(-fsanitize=address) add_subdirectory(src) add_subdirectory(bench) diff --git a/bench/barite/het/barite_het.pqi b/bench/barite/het/barite_het.pqi new file mode 100644 index 000000000..b13bcd1c0 --- /dev/null +++ b/bench/barite/het/barite_het.pqi @@ -0,0 +1,79 @@ +## Initial: everywhere equilibrium with Celestite NB: The aqueous +## solution *resulting* from this calculation is to be used as initial +## state everywhere in the domain +SOLUTION 1 +units mol/kgw +water 1 +temperature 25 +pH 7 +pe 4 +S(6) 1e-12 +Sr 1e-12 +Ba 1e-12 +Cl 1e-12 +PURE 1 +Celestite 0.0 1 + +SAVE SOLUTION 2 # <- phreeqc keyword to store and later reuse these results +END + +RUN_CELLS + -cells 1 + +COPY solution 1 2-3 + +## Here a 5x2 domain: + + |---+---+---+---+---| + -> | 2 | 2 | 2 | 2 | 2 | + 4 |---+---+---+---+---| + -> | 3 | 3 | 3 | 3 | 3 | + |---+---+---+---+---| + +## East boundary: "injection" of solution 4. North, W, S boundaries: closed + +## Here the two distinct zones: nr 2 with kinetics Celestite (initial +## amount is 0, is then allowed to precipitate) and nr 3 with kinetic +## Celestite and Barite (both initially > 0) where the actual +## replacement takes place + +#USE SOLUTION 2 <- PHREEQC keyword to reuse the results from previous calculation +KINETICS 2 +Celestite +-m 0 # Allowed to precipitate +-parms 10.0 +-tol 1e-9 + +END + +#USE SOLUTION 2 <- PHREEQC keyword to reuse the results from previous calculation +KINETICS 3 +Barite +-m 0.001 +-parms 50. +-tol 1e-9 +Celestite +-m 1 +-parms 10.0 +-tol 1e-9 +END + +## A BaCl2 solution (nr 4) is "injected" from the left boundary: +SOLUTION 4 +pH 7 +water 1 +temp 25 +Ba 0.1 +Cl 0.2 +END +## NB: again, the *result* of the SOLUTION 4 script defines the +## concentration of all elements (+charge, tot H, tot O) + +## Ideally, in the initial state SOLUTION 1 we should not have to +## define the 4 elemental concentrations (S(6), Sr, Ba and Cl) but +## obtain them having run once the scripts with the aqueous solution +## resulting from SOLUTION 1 once with KINETICS 2 and once with +## KINETICS 3. + +RUN_CELLS + -cells 2-4 \ No newline at end of file diff --git a/bench/barite/het/test.R b/bench/barite/het/test.R new file mode 100644 index 000000000..97c642b51 --- /dev/null +++ b/bench/barite/het/test.R @@ -0,0 +1,15 @@ +grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) + +# Define grid configuration for POET model +grid_setup <- list( + pqc_in = "./barite_het.pqi", + pqc_db = "./db_barite.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(ncol(grid_def), nrow(grid_def)), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) + +# Define a setup list for simulation configuration +setup <- list( + grid = grid_setup # Parameters related to the grid structure +) diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index c3cc0b379..f392ad6f3 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -99,10 +99,10 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { pqcScriptToGrid(R, script_rp, database_rp, this->pqc_raw_dumps); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); - // R["pqc_mat"] = this->phreeqc_mat; - // R["grid_def"] = initial_grid; + R["pqc_mat"] = this->phreeqc_mat; + R["grid_def"] = initial_grid; - // R.parseEval("print(pqc_mat)"); - // R.parseEval("print(grid_def)"); + R.parseEval("print(pqc_mat)"); + R.parseEval("print(grid_def)"); } } // namespace poet \ No newline at end of file From d012936c6d8ee12f974bb1eeb911cf4bfd0abe0f Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 22:05:06 +0100 Subject: [PATCH 05/77] Update RAW Keywords to always refer to ID 1 --- src/Init/GridInit.cpp | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index f392ad6f3..3576e3352 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -3,12 +3,12 @@ #include #include #include +#include +#include +#include namespace poet { -static Rcpp::NumericMatrix -pqcScriptToGrid(RInside &R, const std::string &script, const std::string &db, - std::map &raw_dumps) { - IPhreeqcPOET phreeqc(db, script); +static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { const auto solution_ids = phreeqc.getSolutionIds(); auto col_names = phreeqc.getInitNames(); @@ -32,24 +32,29 @@ pqcScriptToGrid(RInside &R, const std::string &script, const std::string &db, Rcpp::colnames(mat) = Rcpp::wrap(col_names); - raw_dumps = phreeqc.raw_dumps(); - return mat; } static inline Rcpp::List matToGrid(RInside &R, const Rcpp::NumericMatrix &mat, const Rcpp::NumericMatrix &grid) { - // Rcpp::List res; - // res["init_mat"] = mat; - // res["grid_mat"] = grid; - Rcpp::Function pqc_to_grid("pqc_to_grid"); - // R.parseEvalQ("res_df <- pqc_to_grid(init_mat, grid_mat)"); - return pqc_to_grid(mat, grid); } +static inline std::map +replaceRawSolutionsIDs(std::map raws) { + for (auto &raw : raws) { + std::string &s = raw.second; + // find at beginning of line '*_RAW' followed by a number and change this + // number to 1 + std::regex re(R"((RAW\s+)(\d+))"); + s = std::regex_replace(s, re, "RAW 1"); + } + + return raws; +} + void InitialList::initGrid(const Rcpp::List &grid_input) { // parse input values const std::string script = Rcpp::as(grid_input["pqc_in"]); @@ -95,10 +100,13 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { throw std::runtime_error("Grid size must be positive."); } - this->phreeqc_mat = - pqcScriptToGrid(R, script_rp, database_rp, this->pqc_raw_dumps); + IPhreeqcPOET phreeqc(database_rp, script_rp); + + this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); + this->pqc_raw_dumps = replaceRawSolutionsIDs(phreeqc.raw_dumps()); + R["pqc_mat"] = this->phreeqc_mat; R["grid_def"] = initial_grid; From 8f698149dad9b06ff3562967fda6b92dcafc511e Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 22:06:07 +0100 Subject: [PATCH 06/77] Update function name to replaceRawKeywordIDs in GridInit.cpp --- src/Init/GridInit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 3576e3352..a45c1f428 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -43,7 +43,7 @@ static inline Rcpp::List matToGrid(RInside &R, const Rcpp::NumericMatrix &mat, } static inline std::map -replaceRawSolutionsIDs(std::map raws) { +replaceRawKeywordIDs(std::map raws) { for (auto &raw : raws) { std::string &s = raw.second; // find at beginning of line '*_RAW' followed by a number and change this @@ -105,7 +105,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); - this->pqc_raw_dumps = replaceRawSolutionsIDs(phreeqc.raw_dumps()); + this->pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); R["pqc_mat"] = this->phreeqc_mat; R["grid_def"] = initial_grid; From 371eb1367a76ff37ce3e01c184b604e84f438d3d Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 13 Mar 2024 23:50:13 +0100 Subject: [PATCH 07/77] Add modify_module_sizes function and modify module_sizes in InitialList class --- R_lib/init_r_lib.R | 44 ++++++++++++++++++++++++++++++++++++++++ ext/iphreeqc | 2 +- src/Init/GridInit.cpp | 26 ++++++++++++++++++++++++ src/Init/InitialList.hpp | 7 +++++-- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index f2dfbb71c..83eaa7293 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -34,4 +34,48 @@ pqc_to_grid <- function(pqc_in, grid) { pqc_init <- pqc_to_grid(input, grid_def) test <- pqc_init +modify_module_sizes <- function(mod_sizes, pqc_mat, init_grid) { + # Find all unique IDs in init_grid + unique_ids <- unique(as.vector(init_grid$id)) + + # remove rows from pqc_mat that are not in init_grid + pqc_mat <- as.data.frame(pqc_mat) + pqc_mat <- pqc_mat[pqc_mat$id %in% unique_ids, ] + + # Find the column indices where all rows are NA + na_cols <- which(colSums(is.na(pqc_mat)) == nrow(pqc_mat)) + + # Build cumsum over mod_sizes + cum_mod_sizes <- cumsum(mod_sizes) + + # Find the indices where the value of na_cols is equal to the value of cum_mod_sizes + idx <- which(cum_mod_sizes %in% na_cols) + + # Set the value of mod_sizes to 0 at the indices found in the previous step + mod_sizes[idx] <- 0 + + return(mod_sizes) +} + +# mod_sizes <- c(7, 0, 4, 2, 0) + +# unique_ids <- unique(as.vector(pqc_init$id)) + +# tmp <- as.data.frame(input) +# pqc_test <- tmp[tmp$id %in% unique_ids, ] +# na_cols <- which(colSums(is.na(pqc_test)) == nrow(pqc_test)) +# cum_mod_sizes <- cumsum(mod_sizes) + +# # Get the indices of the columns of cum_mod_sizes where the value of the column is equal to the value of na_cols +# idx <- which(cum_mod_sizes %in% na_cols) +# mod_sizes[idx] <- 0 + +# idx <- which(na_cols == cum_mod_sizes) + + + +# idx <- which(na_cols[1] >= cum_mod_sizes) + +# mod_sizes <- modify_module_sizes(mod_sizes, pqc_init, pqc_init) + # remove column with all NA diff --git a/ext/iphreeqc b/ext/iphreeqc index f3f86bb4a..54136c8e0 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit f3f86bb4ac1d3b70aec7437781875072f2896ae3 +Subproject commit 54136c8e0c638d0dc47e85cef1428822b6c1512d diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index a45c1f428..bb29615b2 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -3,9 +3,12 @@ #include #include #include +#include +#include #include #include #include +#include namespace poet { static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { @@ -55,6 +58,21 @@ replaceRawKeywordIDs(std::map raws) { return raws; } +static inline IPhreeqcPOET::ModulesArray +modifyModuleSizes(IPhreeqcPOET::ModulesArray sizes, + const Rcpp::NumericMatrix &phreeqc_mat, + const Rcpp::List &initial_grid) { + std::vector sizes_vec(sizes.begin(), sizes.end()); + + Rcpp::Function modify_sizes("modify_module_sizes"); + sizes_vec = Rcpp::as>( + modify_sizes(sizes_vec, phreeqc_mat, initial_grid)); + + std::copy(sizes_vec.begin(), sizes_vec.end(), sizes.begin()); + + return sizes; +} + void InitialList::initGrid(const Rcpp::List &grid_input) { // parse input values const std::string script = Rcpp::as(grid_input["pqc_in"]); @@ -105,6 +123,14 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); + this->module_sizes = modifyModuleSizes(phreeqc.getModuleSizes(), + this->phreeqc_mat, this->initial_grid); + + // print module sizes + for (std::size_t i = 0; i < this->module_sizes.size(); i++) { + std::cout << this->module_sizes[i] << std::endl; + } + this->pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); R["pqc_mat"] = this->phreeqc_mat; diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index e3f86ebf6..d236d19be 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -1,12 +1,12 @@ #pragma once -#include "../DataStructures/Field.hpp" - #include #include #include #include +#include + namespace poet { class InitialList { @@ -40,5 +40,8 @@ private: // Initialized by grid, modified by chemistry std::map pqc_raw_dumps; + + // Chemistry members + IPhreeqcPOET::ModulesArray module_sizes; }; } // namespace poet \ No newline at end of file From 2b74fca74042551d8dd01de2e9bf9414c42acdbb Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 18 Mar 2024 23:06:52 +0100 Subject: [PATCH 08/77] Save latest changes, boundaries still missing or incomplete --- R_lib/init_r_lib.R | 9 +- ext/iphreeqc | 2 +- src/CMakeLists.txt | 1 + src/Init/DiffusionInit.cpp | 166 ++++++++++++++++ src/Init/InitialList.cpp | 1 + src/Init/InitialList.hpp | 11 ++ src/poet.hpp | 396 +++++++++++++++++++++++++++++++++++++ 7 files changed, 581 insertions(+), 5 deletions(-) create mode 100644 src/Init/DiffusionInit.cpp create mode 100644 src/poet.hpp diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index 83eaa7293..8879ac703 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -17,7 +17,7 @@ pqc_to_grid <- function(pqc_in, grid) { # Iterate over each ID in the vector for (id_mat in id_vector) { # Find the matching row in the data.table - matching_dt <- dt[id == id_mat] + matching_dt <- dt[dt$id == id_mat] # Append the matching data.table row to the result data.table result_dt <- rbind(result_dt, matching_dt) @@ -36,14 +36,15 @@ test <- pqc_init modify_module_sizes <- function(mod_sizes, pqc_mat, init_grid) { # Find all unique IDs in init_grid - unique_ids <- unique(as.vector(init_grid$id)) + unique_ids <- unique(init_grid$id) # remove rows from pqc_mat that are not in init_grid pqc_mat <- as.data.frame(pqc_mat) pqc_mat <- pqc_mat[pqc_mat$id %in% unique_ids, ] - # Find the column indices where all rows are NA - na_cols <- which(colSums(is.na(pqc_mat)) == nrow(pqc_mat)) + # Find the column indices where all rows are NaN + na_cols <- which(sapply(pqc_mat, function(x) all(is.na(x)))) + # na_cols <- which(colSums(is.nan(pqc_mat)) == nrow(pqc_mat)) # Build cumsum over mod_sizes cum_mod_sizes <- cumsum(mod_sizes) diff --git a/ext/iphreeqc b/ext/iphreeqc index 54136c8e0..d92ab3176 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit 54136c8e0c638d0dc47e85cef1428822b6c1512d +Subproject commit d92ab31765d3850beb0b9e980b7b82696e56e4fc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d53484cd1..e0dcb8a55 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(poetinitlib Init/InitialList.cpp Init/GridInit.cpp + Init/DiffusionInit.cpp ) target_link_libraries(poetinitlib PUBLIC diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp new file mode 100644 index 000000000..becaaa977 --- /dev/null +++ b/src/Init/DiffusionInit.cpp @@ -0,0 +1,166 @@ +#include +// leave above Rcpp includes, as eigen seem to have problems with a preceding +// Rcpp include + +#include +#include + +#include "InitialList.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace poet { + +enum SEXP_TYPE { SEXP_IS_LIST, SEXP_IS_MAT, SEXP_IS_NUM }; + +const std::map tug_side_mapping = { + {tug::BC_SIDE_RIGHT, "E"}, + {tug::BC_SIDE_LEFT, "W"}, + {tug::BC_SIDE_TOP, "N"}, + {tug::BC_SIDE_BOTTOM, "S"}}; + +static Rcpp::List parseBoundaries2D(const Rcpp::List &boundaries_list, + std::uint32_t n_cols, + std::uint32_t n_rows) { + Rcpp::List out_list; + + for (const auto &side : tug_side_mapping) { + Rcpp::NumericVector type = + (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) + ? Rcpp::NumericVector(n_rows, tug::BC_TYPE_CLOSED) + : Rcpp::NumericVector(n_cols, tug::BC_TYPE_CLOSED); + + Rcpp::NumericVector value = + (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) + ? Rcpp::NumericVector(n_rows, 0) + : Rcpp::NumericVector(n_cols, 0); + + if (boundaries_list.containsElementNamed(side.second.c_str())) { + const Rcpp::List mapping = boundaries_list[side.second]; + + const Rcpp::NumericVector cells = mapping["cells"]; + const Rcpp::NumericVector values = mapping["sol_id"]; + + if (cells.size() != values.size()) { + throw std::runtime_error("Boundary [" + side.second + + "] cells and values are not the same length"); + } + } + + out_list[side.second] = Rcpp::List::create(Rcpp::Named("type") = type, + Rcpp::Named("value") = value); + } +} + +static inline SEXP_TYPE get_datatype(const SEXP &input) { + Rcpp::Function check_list("is.list"); + Rcpp::Function check_mat("is.matrix"); + + if (Rcpp::as(check_list(input))) { + return SEXP_IS_LIST; + } else if (Rcpp::as(check_mat(input))) { + return SEXP_IS_MAT; + } else { + return SEXP_IS_NUM; + } +} + +static Rcpp::List parseAlphas2D(const SEXP &input, + const std::vector &transport_names, + std::uint32_t n_cols, std::uint32_t n_rows) { + Rcpp::List out_list; + + SEXP_TYPE input_type = get_datatype(input); + + switch (input_type) { + case SEXP_IS_LIST: { + const Rcpp::List input_list(input); + + if (input_list.size() != transport_names.size()) { + throw std::runtime_error( + "Length of alphas list does not match number of transport names"); + } + + for (const auto &name : transport_names) { + if (!input_list.containsElementNamed(name.c_str())) { + throw std::runtime_error("Alphas list does not contain transport name"); + } + + const Rcpp::NumericMatrix alpha_mat(input_list[name]); + + if (alpha_mat.size() == 1) { + Rcpp::NumericVector alpha(n_cols * n_rows, alpha_mat(0, 0)); + out_list[name] = Rcpp::wrap(alpha); + } else { + if (alpha_mat.nrow() != n_rows || alpha_mat.ncol() != n_cols) { + throw std::runtime_error( + "Alpha matrix does not match grid dimensions"); + } + + out_list[name] = alpha_mat; + } + } + break; + } + case SEXP_IS_MAT: { + Rcpp::NumericMatrix input_mat(input); + + Rcpp::NumericVector alpha(n_cols * n_rows, input_mat(0, 0)); + + if (input_mat.size() != 1) { + if (input_mat.nrow() != n_rows || input_mat.ncol() != n_cols) { + throw std::runtime_error("Alpha matrix does not match grid dimensions"); + } + + for (std::size_t i = 0; i < n_rows; i++) { + for (std::size_t j = 0; j < n_cols; j++) { + alpha[i * n_cols + j] = input_mat(i, j); + } + } + } + + for (const auto &name : transport_names) { + out_list[name] = alpha; + } + + break; + } + case SEXP_IS_NUM: { + Rcpp::NumericVector alpha(n_cols * n_rows, Rcpp::as(input)); + for (const auto &name : transport_names) { + out_list[name] = alpha; + } + break; + } + default: + throw std::runtime_error("Unknown data type"); + } + + return out_list; +} +void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { + const Rcpp::List &boundaries = diffusion_input["boundaries"]; + const SEXP &alpha_x = diffusion_input["alpha_x"]; + const SEXP &alpha_y = diffusion_input["alpha_y"]; + + std::vector colnames = + Rcpp::as>(this->initial_grid.names()); + + std::vector transport_names(colnames.begin() + 1, + colnames.begin() + 1 + + this->module_sizes[POET_SOL]); + + this->alpha_x = + parseAlphas2D(alpha_x, transport_names, this->n_cols, this->n_rows); + + this->alpha_y = + parseAlphas2D(alpha_y, transport_names, this->n_cols, this->n_rows); +} +} // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index d12c6e314..d37fee1fc 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -3,5 +3,6 @@ namespace poet { void InitialList::initializeFromList(const Rcpp::List &setup) { initGrid(setup["grid"]); + initDiffusion(setup["diffusion"]); } } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index d236d19be..30289c252 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -6,9 +6,13 @@ #include #include +#include +#include namespace poet { +using TugType = double; + class InitialList { public: InitialList(RInside &R) : R(R){}; @@ -43,5 +47,12 @@ private: // Chemistry members IPhreeqcPOET::ModulesArray module_sizes; + + // Diffusion members + void initDiffusion(const Rcpp::List &diffusion_input); + Rcpp::List boundaries; + + Rcpp::List alpha_x; + Rcpp::List alpha_y; }; } // namespace poet \ No newline at end of file diff --git a/src/poet.hpp b/src/poet.hpp new file mode 100644 index 000000000..3bee0eba6 --- /dev/null +++ b/src/poet.hpp @@ -0,0 +1,396 @@ +#ifndef POET_H +#define POET_H + +#include +static const char *poet_version = "tmp/ml/v0.2-107-g9990c12"; + +// using the Raw string literal to avoid escaping the quotes +static inline std::string kin_r_library = R"(## Time-stamp: "Last modified 2023-08-15 11:58:23 delucia" + +### Copyright (C) 2018-2023 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. + + +## Simple function to check file extension. It is needed to check if +## the GridFile is SUM (MUFITS format) or rds/RData +FileExt <- function(x) { + pos <- regexpr("\\.([[:alnum:]]+)$", x) + ifelse(pos > -1L, substring(x, pos + 1L), "") +} + +master_init <- function(setup) { + msgm("Process with rank 0 reading GRID properties") + + ## Setup the directory where we will store the results + verb <- FALSE + if (local_rank == 0) { + verb <- TRUE ## verbosity loading MUFITS results + if (!dir.exists(fileout)) { + dir.create(fileout) + msgm("created directory ", fileout) + } else { + msgm("dir ", fileout, " already exists, I will overwrite!") + } + if (!exists("store_result")) { + msgm("store_result doesn't exist!") + } else { + msgm("store_result is ", store_result) + } + } else { + + } + + setup$iter <- 1 + setup$maxiter <- setup$iterations + setup$timesteps <- setup$timesteps + setup$simulation_time <- 0 + + if (is.null(setup[["store_result"]])) { + setup$store_result <- TRUE + } + + if (setup$store_result) { + if (is.null(setup[["out_save"]])) { + setup$out_save <- seq(1, setup$iterations) + } + } + + return(setup) +} + +## This function, called only by master, stores on disk the last +## calculated time step if store_result is TRUE and increments the +## iteration counter +master_iteration_end <- function(setup) { + iter <- setup$iter + ## max digits for iterations + dgts <- as.integer(ceiling(log10(setup$iterations + 1))) + ## string format to use in sprintf + fmt <- paste0("%0", dgts, "d") + + ## Write on disk state_T and state_C after every iteration + ## comprised in setup$out_save + if (setup$store_result) { + if (iter %in% setup$out_save) { + nameout <- paste0(fileout, "/iter_", sprintf(fmt=fmt, iter), ".rds") + info <- list( + tr_req_dt = as.integer(setup$req_dt) + ## tr_allow_dt = setup$allowed_dt, + ## tr_inniter = as.integer(setup$inniter) + ) + saveRDS(list( + T = setup$state_T, C = setup$state_C, + simtime = as.integer(setup$simtime), + tr_info = info + ), file = nameout) + msgm("results stored in <", nameout, ">") + } + } + msgm("done iteration", iter, "/", setup$maxiter) + setup$iter <- setup$iter + 1 + return(setup) +} + +## function for the workers to compute chemistry through PHREEQC +slave_chemistry <- function(setup, data) { + base <- setup$base + first <- setup$first + prop <- setup$prop + immobile <- setup$immobile + kin <- setup$kin + ann <- setup$ann + + iter <- setup$iter + timesteps <- setup$timesteps + dt <- timesteps[iter] + + state_T <- data ## not the global field, but the work-package + + ## treat special H+/pH, e-/pe cases + state_T <- RedModRphree::Act2pH(state_T) + + ## reduction of the problem + if (setup$reduce) { + reduced <- ReduceStateOmit(state_T, omit = setup$ann) + } else { + reduced <- state_T + } + + ## form the PHREEQC input script for the current work package + inplist <- SplitMultiKin( + data = reduced, procs = 1, base = base, first = first, + ann = ann, prop = prop, minerals = immobile, kin = kin, dt = dt + ) + + ## if (local_rank==1 & iter==1) + ## RPhreeWriteInp("FirstInp", inplist) + + tmpC <- RunPQC(inplist, procs = 1, second = TRUE) + + ## recompose after the reduction + if (setup$reduce) { + state_C <- RecomposeState(tmpC, reduced) + } else { + state_C <- tmpC + } + + ## the next line is needed since we don't need all columns of + ## PHREEQC output + return(state_C[, prop]) +} + +## This function, called by master +master_chemistry <- function(setup, data) { + state_T <- setup$state_T + + msgm(" chemistry iteration", setup$iter) + + ## treat special H+/pH, e-/pe cases + state_T <- RedModRphree::Act2pH(state_T) + + ## reduction of the problem + if (setup$reduce) { + reduced <- ReduceStateOmit(state_T, omit = setup$ann) + } else { + reduced <- state_T + } + + ## inject data from workers + res_C <- data + + rownames(res_C) <- NULL + + ## print(res_C) + + if (nrow(res_C) > nrow(reduced)) { + res_C <- res_C[seq(2, nrow(res_C), by = 2), ] + } + + ## recompose after the reduction + if (setup$reduce) { + state_C <- RecomposeState(res_C, reduced) + } else { + state_C <- res_C + } + + setup$state_C <- state_C + setup$reduced <- reduced + + return(setup) +} + + +## Adapted version for "reduction" +ReduceStateOmit <- function(data, omit = NULL, sign = 6) { + require(mgcv) + + rem <- colnames(data) + if (is.list(omit)) { + indomi <- match(names(omit), colnames(data)) + datao <- data[, -indomi] + } else { + datao <- data + } + + datao <- signif(datao, sign) + red <- mgcv::uniquecombs(datao) + inds <- attr(red, "index") + now <- ncol(red) + + + ## reattach the omitted column(s) + ## FIXME: control if more than one ann is present + if (is.list(omit)) { + red <- cbind(red, rep(data[1, indomi], nrow(red))) + + colnames(red)[now + 1] <- names(omit) + + ret <- red[, colnames(data)] + } else { + ret <- red + } + rownames(ret) <- NULL + attr(ret, "index") <- inds + return(ret) +} + + + +## Attach the name of the calling function to the message displayed on +## R's stdout +msgm <- function(...) { + if (local_rank == 0) { + fname <- as.list(sys.call(-1))[[1]] + prefix <- paste0("R: ", fname, " ::") + cat(paste(prefix, ..., "\n")) + } + invisible() +} + + +## Function called by master R process to store on disk all relevant +## parameters for the simulation +StoreSetup <- function(setup) { + + to_store <- vector(mode = "list", length = 4) + ## names(to_store) <- c("Sim", "Flow", "Transport", "Chemistry", "DHT") + names(to_store) <- c("Sim", "Transport", "DHT", "Cmdline") + + ## read the setup R file, which is sourced in kin.cpp + tmpbuff <- file(filesim, "r") + setupfile <- readLines(tmpbuff) + close.connection(tmpbuff) + + to_store$Sim <- setupfile + + ## to_store$Flow <- list( + ## snapshots = setup$snapshots, + ## gridfile = setup$gridfile, + ## phase = setup$phase, + ## density = setup$density, + ## dt_differ = setup$dt_differ, + ## prolong = setup$prolong, + ## maxiter = setup$maxiter, + ## saved_iter = setup$iter_output, + ## out_save = setup$out_save ) + + to_store$Transport <- setup$diffusion + + ## to_store$Chemistry <- list( + ## nprocs = n_procs, + ## wp_size = work_package_size, + ## base = setup$base, + ## first = setup$first, + ## init = setup$initsim, + ## db = db, + ## kin = setup$kin, + ## ann = setup$ann) + + if (dht_enabled) { + to_store$DHT <- list( + enabled = dht_enabled, + log = dht_log + ## signif = dht_final_signif, + ## proptype = dht_final_proptype + ) + } else { + to_store$DHT <- FALSE + } + + if (dht_enabled) { + to_store$DHT <- list( + enabled = dht_enabled, + log = dht_log + #signif = dht_final_signif, + #proptype = dht_final_proptype + ) + } else { + to_store$DHT <- FALSE + } + + saveRDS(to_store, file = paste0(fileout, "/setup.rds")) + msgm("initialization stored in ", paste0(fileout, "/setup.rds")) +} + +GetWorkPackageSizesVector <- function(n_packages, package_size, len) { + ids <- rep(1:n_packages, times=package_size, each = 1)[1:len] + return(as.integer(table(ids))) +} +)"; + +static inline std::string init_r_library = R"(input <- readRDS("/home/max/Storage/poet/build/apps/out.rds") + +grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) + +library(data.table) + +pqc_to_grid <- function(pqc_in, grid) { + # Convert the input DataFrame to a data.table + dt <- data.table(pqc_in) + + # Flatten the matrix into a vector + id_vector <- as.vector(t(grid)) + + # Initialize an empty data.table to store the results + result_dt <- data.table() + + # Iterate over each ID in the vector + for (id_mat in id_vector) { + # Find the matching row in the data.table + matching_dt <- dt[id == id_mat] + + # Append the matching data.table row to the result data.table + result_dt <- rbind(result_dt, matching_dt) + } + + # Remove all columns which only contain NaN + # result_dt <- result_dt[, colSums(is.na(result_dt)) != nrow(result_dt)] + + res_df <- as.data.frame(result_dt) + + return(res_df[, colSums(is.na(res_df)) != nrow(res_df)]) +} + +pqc_init <- pqc_to_grid(input, grid_def) +test <- pqc_init + +modify_module_sizes <- function(mod_sizes, pqc_mat, init_grid) { + # Find all unique IDs in init_grid + unique_ids <- unique(as.vector(init_grid$id)) + + # remove rows from pqc_mat that are not in init_grid + pqc_mat <- as.data.frame(pqc_mat) + pqc_mat <- pqc_mat[pqc_mat$id %in% unique_ids, ] + + # Find the column indices where all rows are NA + na_cols <- which(colSums(is.na(pqc_mat)) == nrow(pqc_mat)) + + # Build cumsum over mod_sizes + cum_mod_sizes <- cumsum(mod_sizes) + + # Find the indices where the value of na_cols is equal to the value of cum_mod_sizes + idx <- which(cum_mod_sizes %in% na_cols) + + # Set the value of mod_sizes to 0 at the indices found in the previous step + mod_sizes[idx] <- 0 + + return(mod_sizes) +} + +# mod_sizes <- c(7, 0, 4, 2, 0) + +# unique_ids <- unique(as.vector(pqc_init$id)) + +# tmp <- as.data.frame(input) +# pqc_test <- tmp[tmp$id %in% unique_ids, ] +# na_cols <- which(colSums(is.na(pqc_test)) == nrow(pqc_test)) +# cum_mod_sizes <- cumsum(mod_sizes) + +# # Get the indices of the columns of cum_mod_sizes where the value of the column is equal to the value of na_cols +# idx <- which(cum_mod_sizes %in% na_cols) +# mod_sizes[idx] <- 0 + +# idx <- which(na_cols == cum_mod_sizes) + + + +# idx <- which(na_cols[1] >= cum_mod_sizes) + +# mod_sizes <- modify_module_sizes(mod_sizes, pqc_init, pqc_init) + +# remove column with all NA +)"; + +#endif // POET_H From 9fdda3115106eed2f0bdc750a944d51dc3874ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 09:47:40 +0000 Subject: [PATCH 09/77] Refactor pqc_to_grid function to use matrix instead of data.table --- R_lib/init_r_lib.R | 82 +++++++++------------------------------------- 1 file changed, 15 insertions(+), 67 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index 8879ac703..672e372cc 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -1,82 +1,30 @@ -input <- readRDS("/home/max/Storage/poet/build/apps/out.rds") - -grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) - -library(data.table) - pqc_to_grid <- function(pqc_in, grid) { - # Convert the input DataFrame to a data.table - dt <- data.table(pqc_in) + # Convert the input DataFrame to a matrix + dt <- as.matrix(pqc_in) # Flatten the matrix into a vector id_vector <- as.vector(t(grid)) - # Initialize an empty data.table to store the results - result_dt <- data.table() + # Initialize an empty matrix to store the results + result_mat <- matrix(nrow = 0, ncol = ncol(dt)) # Iterate over each ID in the vector for (id_mat in id_vector) { - # Find the matching row in the data.table - matching_dt <- dt[dt$id == id_mat] + # Find the matching row in the matrix + matching_row <- dt[dt[, "ID"] == id_mat, ] - # Append the matching data.table row to the result data.table - result_dt <- rbind(result_dt, matching_dt) + # Append the matching row to the result matrix + result_mat <- rbind(result_mat, matching_row) } + # Convert the result matrix to a data frame + res_df <- as.data.frame(result_mat) + # Remove all columns which only contain NaN - # result_dt <- result_dt[, colSums(is.na(result_dt)) != nrow(result_dt)] + res_df <- res_df[, colSums(is.na(res_df)) != nrow(res_df)] - res_df <- as.data.frame(result_dt) + # Remove row names + rownames(res_df) <- NULL - return(res_df[, colSums(is.na(res_df)) != nrow(res_df)]) + return(res_df) } - -pqc_init <- pqc_to_grid(input, grid_def) -test <- pqc_init - -modify_module_sizes <- function(mod_sizes, pqc_mat, init_grid) { - # Find all unique IDs in init_grid - unique_ids <- unique(init_grid$id) - - # remove rows from pqc_mat that are not in init_grid - pqc_mat <- as.data.frame(pqc_mat) - pqc_mat <- pqc_mat[pqc_mat$id %in% unique_ids, ] - - # Find the column indices where all rows are NaN - na_cols <- which(sapply(pqc_mat, function(x) all(is.na(x)))) - # na_cols <- which(colSums(is.nan(pqc_mat)) == nrow(pqc_mat)) - - # Build cumsum over mod_sizes - cum_mod_sizes <- cumsum(mod_sizes) - - # Find the indices where the value of na_cols is equal to the value of cum_mod_sizes - idx <- which(cum_mod_sizes %in% na_cols) - - # Set the value of mod_sizes to 0 at the indices found in the previous step - mod_sizes[idx] <- 0 - - return(mod_sizes) -} - -# mod_sizes <- c(7, 0, 4, 2, 0) - -# unique_ids <- unique(as.vector(pqc_init$id)) - -# tmp <- as.data.frame(input) -# pqc_test <- tmp[tmp$id %in% unique_ids, ] -# na_cols <- which(colSums(is.na(pqc_test)) == nrow(pqc_test)) -# cum_mod_sizes <- cumsum(mod_sizes) - -# # Get the indices of the columns of cum_mod_sizes where the value of the column is equal to the value of na_cols -# idx <- which(cum_mod_sizes %in% na_cols) -# mod_sizes[idx] <- 0 - -# idx <- which(na_cols == cum_mod_sizes) - - - -# idx <- which(na_cols[1] >= cum_mod_sizes) - -# mod_sizes <- modify_module_sizes(mod_sizes, pqc_init, pqc_init) - -# remove column with all NA From ab7efbc3a890b9b94abca75b1e45d69941d025c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 09:48:31 +0000 Subject: [PATCH 10/77] Update getModuleSizes function to use new API --- ext/iphreeqc | 2 +- src/Init/GridInit.cpp | 43 ++--- src/poet.hpp | 396 ------------------------------------------ 3 files changed, 23 insertions(+), 418 deletions(-) delete mode 100644 src/poet.hpp diff --git a/ext/iphreeqc b/ext/iphreeqc index d92ab3176..b34c32737 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit d92ab31765d3850beb0b9e980b7b82696e56e4fc +Subproject commit b34c327377e2e06fb1d79b546996b9b401e850bc diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index bb29615b2..65d788eea 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -1,6 +1,7 @@ #include "InitialList.hpp" #include +#include #include #include #include @@ -12,28 +13,25 @@ namespace poet { static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { - - const auto solution_ids = phreeqc.getSolutionIds(); - auto col_names = phreeqc.getInitNames(); - const auto concentrations = phreeqc.getInitValues(); + IPhreeqcPOET::PhreeqcMat phreeqc_mat = phreeqc.getPhreeqcMat(); // add "id" to the front of the column names - const std::size_t ncols = col_names.size(); - const std::size_t nrows = solution_ids.size(); + const std::size_t ncols = phreeqc_mat.names.size(); + const std::size_t nrows = phreeqc_mat.values.size(); - col_names.insert(col_names.begin(), "id"); + phreeqc_mat.names.insert(phreeqc_mat.names.begin(), "ID"); Rcpp::NumericMatrix mat(nrows, ncols + 1); for (std::size_t i = 0; i < nrows; i++) { - mat(i, 0) = solution_ids[i]; + mat(i, 0) = phreeqc_mat.ids[i]; for (std::size_t j = 0; j < ncols; ++j) { - mat(i, j + 1) = concentrations[i][j]; + mat(i, j + 1) = phreeqc_mat.values[i][j]; } } - Rcpp::colnames(mat) = Rcpp::wrap(col_names); + Rcpp::colnames(mat) = Rcpp::wrap(phreeqc_mat.names); return mat; } @@ -59,18 +57,22 @@ replaceRawKeywordIDs(std::map raws) { } static inline IPhreeqcPOET::ModulesArray -modifyModuleSizes(IPhreeqcPOET::ModulesArray sizes, - const Rcpp::NumericMatrix &phreeqc_mat, - const Rcpp::List &initial_grid) { - std::vector sizes_vec(sizes.begin(), sizes.end()); +getModuleSizes(IPhreeqcPOET &phreeqc, const Rcpp::List &initial_grid) { + IPhreeqcPOET::ModulesArray mod_array; + Rcpp::Function unique("unique"); - Rcpp::Function modify_sizes("modify_module_sizes"); - sizes_vec = Rcpp::as>( - modify_sizes(sizes_vec, phreeqc_mat, initial_grid)); + std::vector row_ids = + Rcpp::as>(unique(initial_grid["ID"])); - std::copy(sizes_vec.begin(), sizes_vec.end(), sizes.begin()); + // std::vector sizes_vec(sizes.begin(), sizes.end()); - return sizes; + // Rcpp::Function modify_sizes("modify_module_sizes"); + // sizes_vec = Rcpp::as>( + // modify_sizes(sizes_vec, phreeqc_mat, initial_grid)); + + // std::copy(sizes_vec.begin(), sizes_vec.end(), sizes.begin()); + + return phreeqc.getModuleSizes(row_ids); } void InitialList::initGrid(const Rcpp::List &grid_input) { @@ -123,8 +125,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); - this->module_sizes = modifyModuleSizes(phreeqc.getModuleSizes(), - this->phreeqc_mat, this->initial_grid); + this->module_sizes = getModuleSizes(phreeqc, this->initial_grid); // print module sizes for (std::size_t i = 0; i < this->module_sizes.size(); i++) { diff --git a/src/poet.hpp b/src/poet.hpp deleted file mode 100644 index 3bee0eba6..000000000 --- a/src/poet.hpp +++ /dev/null @@ -1,396 +0,0 @@ -#ifndef POET_H -#define POET_H - -#include -static const char *poet_version = "tmp/ml/v0.2-107-g9990c12"; - -// using the Raw string literal to avoid escaping the quotes -static inline std::string kin_r_library = R"(## Time-stamp: "Last modified 2023-08-15 11:58:23 delucia" - -### Copyright (C) 2018-2023 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. - - -## Simple function to check file extension. It is needed to check if -## the GridFile is SUM (MUFITS format) or rds/RData -FileExt <- function(x) { - pos <- regexpr("\\.([[:alnum:]]+)$", x) - ifelse(pos > -1L, substring(x, pos + 1L), "") -} - -master_init <- function(setup) { - msgm("Process with rank 0 reading GRID properties") - - ## Setup the directory where we will store the results - verb <- FALSE - if (local_rank == 0) { - verb <- TRUE ## verbosity loading MUFITS results - if (!dir.exists(fileout)) { - dir.create(fileout) - msgm("created directory ", fileout) - } else { - msgm("dir ", fileout, " already exists, I will overwrite!") - } - if (!exists("store_result")) { - msgm("store_result doesn't exist!") - } else { - msgm("store_result is ", store_result) - } - } else { - - } - - setup$iter <- 1 - setup$maxiter <- setup$iterations - setup$timesteps <- setup$timesteps - setup$simulation_time <- 0 - - if (is.null(setup[["store_result"]])) { - setup$store_result <- TRUE - } - - if (setup$store_result) { - if (is.null(setup[["out_save"]])) { - setup$out_save <- seq(1, setup$iterations) - } - } - - return(setup) -} - -## This function, called only by master, stores on disk the last -## calculated time step if store_result is TRUE and increments the -## iteration counter -master_iteration_end <- function(setup) { - iter <- setup$iter - ## max digits for iterations - dgts <- as.integer(ceiling(log10(setup$iterations + 1))) - ## string format to use in sprintf - fmt <- paste0("%0", dgts, "d") - - ## Write on disk state_T and state_C after every iteration - ## comprised in setup$out_save - if (setup$store_result) { - if (iter %in% setup$out_save) { - nameout <- paste0(fileout, "/iter_", sprintf(fmt=fmt, iter), ".rds") - info <- list( - tr_req_dt = as.integer(setup$req_dt) - ## tr_allow_dt = setup$allowed_dt, - ## tr_inniter = as.integer(setup$inniter) - ) - saveRDS(list( - T = setup$state_T, C = setup$state_C, - simtime = as.integer(setup$simtime), - tr_info = info - ), file = nameout) - msgm("results stored in <", nameout, ">") - } - } - msgm("done iteration", iter, "/", setup$maxiter) - setup$iter <- setup$iter + 1 - return(setup) -} - -## function for the workers to compute chemistry through PHREEQC -slave_chemistry <- function(setup, data) { - base <- setup$base - first <- setup$first - prop <- setup$prop - immobile <- setup$immobile - kin <- setup$kin - ann <- setup$ann - - iter <- setup$iter - timesteps <- setup$timesteps - dt <- timesteps[iter] - - state_T <- data ## not the global field, but the work-package - - ## treat special H+/pH, e-/pe cases - state_T <- RedModRphree::Act2pH(state_T) - - ## reduction of the problem - if (setup$reduce) { - reduced <- ReduceStateOmit(state_T, omit = setup$ann) - } else { - reduced <- state_T - } - - ## form the PHREEQC input script for the current work package - inplist <- SplitMultiKin( - data = reduced, procs = 1, base = base, first = first, - ann = ann, prop = prop, minerals = immobile, kin = kin, dt = dt - ) - - ## if (local_rank==1 & iter==1) - ## RPhreeWriteInp("FirstInp", inplist) - - tmpC <- RunPQC(inplist, procs = 1, second = TRUE) - - ## recompose after the reduction - if (setup$reduce) { - state_C <- RecomposeState(tmpC, reduced) - } else { - state_C <- tmpC - } - - ## the next line is needed since we don't need all columns of - ## PHREEQC output - return(state_C[, prop]) -} - -## This function, called by master -master_chemistry <- function(setup, data) { - state_T <- setup$state_T - - msgm(" chemistry iteration", setup$iter) - - ## treat special H+/pH, e-/pe cases - state_T <- RedModRphree::Act2pH(state_T) - - ## reduction of the problem - if (setup$reduce) { - reduced <- ReduceStateOmit(state_T, omit = setup$ann) - } else { - reduced <- state_T - } - - ## inject data from workers - res_C <- data - - rownames(res_C) <- NULL - - ## print(res_C) - - if (nrow(res_C) > nrow(reduced)) { - res_C <- res_C[seq(2, nrow(res_C), by = 2), ] - } - - ## recompose after the reduction - if (setup$reduce) { - state_C <- RecomposeState(res_C, reduced) - } else { - state_C <- res_C - } - - setup$state_C <- state_C - setup$reduced <- reduced - - return(setup) -} - - -## Adapted version for "reduction" -ReduceStateOmit <- function(data, omit = NULL, sign = 6) { - require(mgcv) - - rem <- colnames(data) - if (is.list(omit)) { - indomi <- match(names(omit), colnames(data)) - datao <- data[, -indomi] - } else { - datao <- data - } - - datao <- signif(datao, sign) - red <- mgcv::uniquecombs(datao) - inds <- attr(red, "index") - now <- ncol(red) - - - ## reattach the omitted column(s) - ## FIXME: control if more than one ann is present - if (is.list(omit)) { - red <- cbind(red, rep(data[1, indomi], nrow(red))) - - colnames(red)[now + 1] <- names(omit) - - ret <- red[, colnames(data)] - } else { - ret <- red - } - rownames(ret) <- NULL - attr(ret, "index") <- inds - return(ret) -} - - - -## Attach the name of the calling function to the message displayed on -## R's stdout -msgm <- function(...) { - if (local_rank == 0) { - fname <- as.list(sys.call(-1))[[1]] - prefix <- paste0("R: ", fname, " ::") - cat(paste(prefix, ..., "\n")) - } - invisible() -} - - -## Function called by master R process to store on disk all relevant -## parameters for the simulation -StoreSetup <- function(setup) { - - to_store <- vector(mode = "list", length = 4) - ## names(to_store) <- c("Sim", "Flow", "Transport", "Chemistry", "DHT") - names(to_store) <- c("Sim", "Transport", "DHT", "Cmdline") - - ## read the setup R file, which is sourced in kin.cpp - tmpbuff <- file(filesim, "r") - setupfile <- readLines(tmpbuff) - close.connection(tmpbuff) - - to_store$Sim <- setupfile - - ## to_store$Flow <- list( - ## snapshots = setup$snapshots, - ## gridfile = setup$gridfile, - ## phase = setup$phase, - ## density = setup$density, - ## dt_differ = setup$dt_differ, - ## prolong = setup$prolong, - ## maxiter = setup$maxiter, - ## saved_iter = setup$iter_output, - ## out_save = setup$out_save ) - - to_store$Transport <- setup$diffusion - - ## to_store$Chemistry <- list( - ## nprocs = n_procs, - ## wp_size = work_package_size, - ## base = setup$base, - ## first = setup$first, - ## init = setup$initsim, - ## db = db, - ## kin = setup$kin, - ## ann = setup$ann) - - if (dht_enabled) { - to_store$DHT <- list( - enabled = dht_enabled, - log = dht_log - ## signif = dht_final_signif, - ## proptype = dht_final_proptype - ) - } else { - to_store$DHT <- FALSE - } - - if (dht_enabled) { - to_store$DHT <- list( - enabled = dht_enabled, - log = dht_log - #signif = dht_final_signif, - #proptype = dht_final_proptype - ) - } else { - to_store$DHT <- FALSE - } - - saveRDS(to_store, file = paste0(fileout, "/setup.rds")) - msgm("initialization stored in ", paste0(fileout, "/setup.rds")) -} - -GetWorkPackageSizesVector <- function(n_packages, package_size, len) { - ids <- rep(1:n_packages, times=package_size, each = 1)[1:len] - return(as.integer(table(ids))) -} -)"; - -static inline std::string init_r_library = R"(input <- readRDS("/home/max/Storage/poet/build/apps/out.rds") - -grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) - -library(data.table) - -pqc_to_grid <- function(pqc_in, grid) { - # Convert the input DataFrame to a data.table - dt <- data.table(pqc_in) - - # Flatten the matrix into a vector - id_vector <- as.vector(t(grid)) - - # Initialize an empty data.table to store the results - result_dt <- data.table() - - # Iterate over each ID in the vector - for (id_mat in id_vector) { - # Find the matching row in the data.table - matching_dt <- dt[id == id_mat] - - # Append the matching data.table row to the result data.table - result_dt <- rbind(result_dt, matching_dt) - } - - # Remove all columns which only contain NaN - # result_dt <- result_dt[, colSums(is.na(result_dt)) != nrow(result_dt)] - - res_df <- as.data.frame(result_dt) - - return(res_df[, colSums(is.na(res_df)) != nrow(res_df)]) -} - -pqc_init <- pqc_to_grid(input, grid_def) -test <- pqc_init - -modify_module_sizes <- function(mod_sizes, pqc_mat, init_grid) { - # Find all unique IDs in init_grid - unique_ids <- unique(as.vector(init_grid$id)) - - # remove rows from pqc_mat that are not in init_grid - pqc_mat <- as.data.frame(pqc_mat) - pqc_mat <- pqc_mat[pqc_mat$id %in% unique_ids, ] - - # Find the column indices where all rows are NA - na_cols <- which(colSums(is.na(pqc_mat)) == nrow(pqc_mat)) - - # Build cumsum over mod_sizes - cum_mod_sizes <- cumsum(mod_sizes) - - # Find the indices where the value of na_cols is equal to the value of cum_mod_sizes - idx <- which(cum_mod_sizes %in% na_cols) - - # Set the value of mod_sizes to 0 at the indices found in the previous step - mod_sizes[idx] <- 0 - - return(mod_sizes) -} - -# mod_sizes <- c(7, 0, 4, 2, 0) - -# unique_ids <- unique(as.vector(pqc_init$id)) - -# tmp <- as.data.frame(input) -# pqc_test <- tmp[tmp$id %in% unique_ids, ] -# na_cols <- which(colSums(is.na(pqc_test)) == nrow(pqc_test)) -# cum_mod_sizes <- cumsum(mod_sizes) - -# # Get the indices of the columns of cum_mod_sizes where the value of the column is equal to the value of na_cols -# idx <- which(cum_mod_sizes %in% na_cols) -# mod_sizes[idx] <- 0 - -# idx <- which(na_cols == cum_mod_sizes) - - - -# idx <- which(na_cols[1] >= cum_mod_sizes) - -# mod_sizes <- modify_module_sizes(mod_sizes, pqc_init, pqc_init) - -# remove column with all NA -)"; - -#endif // POET_H From feb8efa73d5891519ffa4b5c840de519bcfb093b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 12:32:16 +0000 Subject: [PATCH 11/77] Refactor grid initialization and update member access in InitialList --- src/Init/GridInit.cpp | 14 ++++++++------ src/Init/InitialList.cpp | 4 ++-- src/Init/InitialList.hpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 65d788eea..dcd28db75 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include #include @@ -77,8 +75,10 @@ getModuleSizes(IPhreeqcPOET &phreeqc, const Rcpp::List &initial_grid) { void InitialList::initGrid(const Rcpp::List &grid_input) { // parse input values - const std::string script = Rcpp::as(grid_input["pqc_in"]); - const std::string database = Rcpp::as(grid_input["pqc_db"]); + const std::string script = Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_FILE)]); + const std::string database = Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_DB_FILE)]); std::string script_rp(PATH_MAX, '\0'); std::string database_rp(PATH_MAX, '\0'); @@ -93,8 +93,10 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { database); } - Rcpp::NumericMatrix grid_def = grid_input["grid_def"]; - Rcpp::NumericVector grid_size = grid_input["grid_size"]; + Rcpp::NumericMatrix grid_def = + grid_input[getGridMemberString(GridMembers::GRID_DEF)]; + Rcpp::NumericVector grid_size = + grid_input[getGridMemberString(GridMembers::GRID_SIZE)]; // Rcpp::NumericVector constant_cells = grid["constant_cells"].; this->n_rows = grid_def.nrow(); diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index d37fee1fc..a433097a2 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -2,7 +2,7 @@ namespace poet { void InitialList::initializeFromList(const Rcpp::List &setup) { - initGrid(setup["grid"]); - initDiffusion(setup["diffusion"]); + initGrid(setup[grid_key]); + initDiffusion(setup[diffusion_key]); } } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 30289c252..b75a9b2d8 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -3,9 +3,12 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -26,6 +29,32 @@ private: RInside &R; // Grid members + static constexpr const char *grid_key = "Grid"; + + enum class GridMembers { + PQC_SCRIPT_STRING, + PQC_SCRIPT_FILE, + PQC_DB_STRING, + PQC_DB_FILE, + GRID_DEF, + GRID_SIZE, + CONSTANT_CELLS, + POROSITY, + ENUM_SIZE + }; + + static constexpr std::size_t size_GridMembers = + static_cast(InitialList::GridMembers::ENUM_SIZE); + + static constexpr std::array + GridMembersString = {"pqc_in_string", "pqc_in_file", "pqc_db_string", + "pqc_db_file", "grid_def", "grid_size", + "constant_cells", "porosity"}; + + constexpr const char *getGridMemberString(GridMembers member) const { + return GridMembersString[static_cast(member)]; + } + void initGrid(const Rcpp::List &grid_input); std::uint8_t dim; @@ -49,6 +78,9 @@ private: IPhreeqcPOET::ModulesArray module_sizes; // Diffusion members + + static constexpr const char *diffusion_key = "Diffusion"; + void initDiffusion(const Rcpp::List &diffusion_input); Rcpp::List boundaries; From b0c65ddbda58ea376bf061393ffafebcf40eaa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 13:11:42 +0000 Subject: [PATCH 12/77] Add file reading functionality and update script and database handling --- ext/iphreeqc | 2 +- src/Init/GridInit.cpp | 58 +++++++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/ext/iphreeqc b/ext/iphreeqc index b34c32737..d6e713074 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit b34c327377e2e06fb1d79b546996b9b401e850bc +Subproject commit d6e7130746f9823e0bc5f711179e676e27ba3737 diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index dcd28db75..eead62881 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -73,24 +74,49 @@ getModuleSizes(IPhreeqcPOET &phreeqc, const Rcpp::List &initial_grid) { return phreeqc.getModuleSizes(row_ids); } -void InitialList::initGrid(const Rcpp::List &grid_input) { - // parse input values - const std::string script = Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_FILE)]); - const std::string database = Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_DB_FILE)]); +static std::string readFile(const std::string &path) { + std::string string_rpath(PATH_MAX, '\0'); - std::string script_rp(PATH_MAX, '\0'); - std::string database_rp(PATH_MAX, '\0'); - - if (realpath(script.c_str(), script_rp.data()) == nullptr) { - throw std::runtime_error("Failed to resolve the path of the Phreeqc input" + - script); + if (realpath(path.c_str(), string_rpath.data()) == nullptr) { + throw std::runtime_error("Failed to resolve the realpath to file " + path); } - if (realpath(database.c_str(), database_rp.data()) == nullptr) { - throw std::runtime_error("Failed to resolve the path of the database" + - database); + std::ifstream file(string_rpath); + + if (!file.is_open()) { + throw std::runtime_error("Failed to open file: " + path); + } + + std::stringstream buffer; + buffer << file.rdbuf(); + + return buffer.str(); +} + +void InitialList::initGrid(const Rcpp::List &grid_input) { + // parse input values + + std::string script; + std::string database; + + if (grid_input.containsElementNamed( + getGridMemberString(GridMembers::PQC_SCRIPT_FILE))) { + + script = readFile(Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_FILE)])); + } else { + script = Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_STRING)]); + } + + if (grid_input.containsElementNamed( + getGridMemberString(GridMembers::PQC_DB_FILE))) { + + database = readFile(Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_DB_FILE)])); + } else { + database = Rcpp::as( + grid_input[getGridMemberString(GridMembers::PQC_DB_STRING)]); } Rcpp::NumericMatrix grid_def = @@ -122,7 +148,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { throw std::runtime_error("Grid size must be positive."); } - IPhreeqcPOET phreeqc(database_rp, script_rp); + IPhreeqcPOET phreeqc(database, script); this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); From e3f002de4957e313c9442ce0b46fc9571a318b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 13:39:59 +0000 Subject: [PATCH 13/77] Refactor initialization code for diffusion and grid --- src/Init/DiffusionInit.cpp | 9 ++++++--- src/Init/GridInit.cpp | 25 +++++++++++++++++-------- src/Init/InitialList.hpp | 30 +++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index becaaa977..c740091a5 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -146,9 +146,12 @@ static Rcpp::List parseAlphas2D(const SEXP &input, return out_list; } void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { - const Rcpp::List &boundaries = diffusion_input["boundaries"]; - const SEXP &alpha_x = diffusion_input["alpha_x"]; - const SEXP &alpha_y = diffusion_input["alpha_y"]; + const Rcpp::List &boundaries = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; + const Rcpp::NumericVector &alpha_x = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_X)]; + const Rcpp::NumericVector &alpha_y = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_Y)]; std::vector colnames = Rcpp::as>(this->initial_grid.names()); diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index eead62881..8e5061c76 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -100,29 +100,31 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { std::string database; if (grid_input.containsElementNamed( - getGridMemberString(GridMembers::PQC_SCRIPT_FILE))) { + GRID_MEMBER_STR(GridMembers::PQC_SCRIPT_FILE))) { script = readFile(Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_FILE)])); + grid_input[GRID_MEMBER_STR(GridMembers::PQC_SCRIPT_FILE)])); } else { script = Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_SCRIPT_STRING)]); + grid_input[GRID_MEMBER_STR(GridMembers::PQC_SCRIPT_STRING)]); } if (grid_input.containsElementNamed( - getGridMemberString(GridMembers::PQC_DB_FILE))) { + GRID_MEMBER_STR(GridMembers::PQC_DB_FILE))) { database = readFile(Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_DB_FILE)])); + grid_input[GRID_MEMBER_STR(GridMembers::PQC_DB_FILE)])); } else { database = Rcpp::as( - grid_input[getGridMemberString(GridMembers::PQC_DB_STRING)]); + grid_input[GRID_MEMBER_STR(GridMembers::PQC_DB_STRING)]); } + this->database = database; + Rcpp::NumericMatrix grid_def = - grid_input[getGridMemberString(GridMembers::GRID_DEF)]; + grid_input[GRID_MEMBER_STR(GridMembers::GRID_DEF)]; Rcpp::NumericVector grid_size = - grid_input[getGridMemberString(GridMembers::GRID_SIZE)]; + grid_input[GRID_MEMBER_STR(GridMembers::GRID_SIZE)]; // Rcpp::NumericVector constant_cells = grid["constant_cells"].; this->n_rows = grid_def.nrow(); @@ -155,6 +157,13 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->module_sizes = getModuleSizes(phreeqc, this->initial_grid); + std::vector colnames = + Rcpp::as>(this->initial_grid.names()); + + this->to_transport = this->pqc_sol_order = std::vector( + colnames.begin() + 1, + colnames.begin() + 1 + this->module_sizes[POET_SOL]); + // print module sizes for (std::size_t i = 0; i < this->module_sizes.size(); i++) { std::cout << this->module_sizes[i] << std::endl; diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index b75a9b2d8..bc4a4dafd 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -51,7 +51,7 @@ private: "pqc_db_file", "grid_def", "grid_size", "constant_cells", "porosity"}; - constexpr const char *getGridMemberString(GridMembers member) const { + constexpr const char *GRID_MEMBER_STR(GridMembers member) const { return GridMembersString[static_cast(member)]; } @@ -71,20 +71,44 @@ private: // No export Rcpp::NumericMatrix phreeqc_mat; - // Initialized by grid, modified by chemistry + // Initialized by grid std::map pqc_raw_dumps; // Chemistry members IPhreeqcPOET::ModulesArray module_sizes; // Diffusion members - static constexpr const char *diffusion_key = "Diffusion"; + enum class DiffusionMembers { BOUNDARIES, ALPHA_X, ALPHA_Y, ENUM_SIZE }; + + static constexpr std::size_t size_DiffusionMembers = + static_cast(InitialList::DiffusionMembers::ENUM_SIZE); + + static constexpr std::array + DiffusionMembersString = {"boundaries", "alpha_x", "alpha_y"}; + + constexpr const char *DIFFU_MEMBER_STR(DiffusionMembers member) const { + return DiffusionMembersString[static_cast(member)]; + } + void initDiffusion(const Rcpp::List &diffusion_input); Rcpp::List boundaries; Rcpp::List alpha_x; Rcpp::List alpha_y; + + std::vector to_transport; + + // Chemistry Members + static constexpr const char *chemistry_key = "Chemistry"; + + void initChemistry(); + + std::string database; + std::vector pqc_scripts; + std::vector pqc_ids; + + std::vector pqc_sol_order; }; } // namespace poet \ No newline at end of file From 6ec98077d7a00a4537dcb457ea756b4121679994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 14:07:25 +0000 Subject: [PATCH 14/77] Update alpha matrix parsing --- src/Init/DiffusionInit.cpp | 103 ++++++++++++++++--------------------- src/Init/GridInit.cpp | 10 ++-- src/Init/InitialList.hpp | 2 +- 3 files changed, 50 insertions(+), 65 deletions(-) diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index c740091a5..a30b66ec6 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -18,7 +18,7 @@ namespace poet { -enum SEXP_TYPE { SEXP_IS_LIST, SEXP_IS_MAT, SEXP_IS_NUM }; +enum SEXP_TYPE { SEXP_IS_LIST, SEXP_IS_VEC }; const std::map tug_side_mapping = { {tug::BC_SIDE_RIGHT, "E"}, @@ -61,20 +61,38 @@ static Rcpp::List parseBoundaries2D(const Rcpp::List &boundaries_list, static inline SEXP_TYPE get_datatype(const SEXP &input) { Rcpp::Function check_list("is.list"); - Rcpp::Function check_mat("is.matrix"); if (Rcpp::as(check_list(input))) { return SEXP_IS_LIST; - } else if (Rcpp::as(check_mat(input))) { - return SEXP_IS_MAT; } else { - return SEXP_IS_NUM; + return SEXP_IS_VEC; } } -static Rcpp::List parseAlphas2D(const SEXP &input, - const std::vector &transport_names, - std::uint32_t n_cols, std::uint32_t n_rows) { +static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, + std::uint32_t n_cols, + std::uint32_t n_rows) { + if (vec.size() == 1) { + return std::vector(n_cols * n_rows, vec[0]); + } else { + if (vec.size() != n_cols * n_rows) { + throw std::runtime_error("Alpha matrix does not match grid dimensions"); + } + + std::vector alpha(n_cols * n_rows); + + for (std::uint32_t i = 0; i < n_cols; i++) { + for (std::uint32_t j = 0; j < n_rows; j++) { + alpha[i * n_rows + j] = vec[j * n_cols + i]; + } + } + return alpha; + } +} + +static Rcpp::List parseAlphas(const SEXP &input, + const std::vector &transport_names, + std::uint32_t n_cols, std::uint32_t n_rows) { Rcpp::List out_list; SEXP_TYPE input_type = get_datatype(input); @@ -93,49 +111,17 @@ static Rcpp::List parseAlphas2D(const SEXP &input, throw std::runtime_error("Alphas list does not contain transport name"); } - const Rcpp::NumericMatrix alpha_mat(input_list[name]); + const Rcpp::NumericVector &alpha_col_order_vec = input_list[name]; - if (alpha_mat.size() == 1) { - Rcpp::NumericVector alpha(n_cols * n_rows, alpha_mat(0, 0)); - out_list[name] = Rcpp::wrap(alpha); - } else { - if (alpha_mat.nrow() != n_rows || alpha_mat.ncol() != n_cols) { - throw std::runtime_error( - "Alpha matrix does not match grid dimensions"); - } - - out_list[name] = alpha_mat; - } + out_list[name] = + Rcpp::wrap(colMajToRowMaj(alpha_col_order_vec, n_cols, n_rows)); } break; } - case SEXP_IS_MAT: { - Rcpp::NumericMatrix input_mat(input); - - Rcpp::NumericVector alpha(n_cols * n_rows, input_mat(0, 0)); - - if (input_mat.size() != 1) { - if (input_mat.nrow() != n_rows || input_mat.ncol() != n_cols) { - throw std::runtime_error("Alpha matrix does not match grid dimensions"); - } - - for (std::size_t i = 0; i < n_rows; i++) { - for (std::size_t j = 0; j < n_cols; j++) { - alpha[i * n_cols + j] = input_mat(i, j); - } - } - } - + case SEXP_IS_VEC: { + const Rcpp::NumericVector alpha(input); for (const auto &name : transport_names) { - out_list[name] = alpha; - } - - break; - } - case SEXP_IS_NUM: { - Rcpp::NumericVector alpha(n_cols * n_rows, Rcpp::as(input)); - for (const auto &name : transport_names) { - out_list[name] = alpha; + out_list[name] = Rcpp::wrap(colMajToRowMaj(alpha, n_cols, n_rows)); } break; } @@ -146,24 +132,23 @@ static Rcpp::List parseAlphas2D(const SEXP &input, return out_list; } void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { - const Rcpp::List &boundaries = - diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; - const Rcpp::NumericVector &alpha_x = + // const Rcpp::List &boundaries = + // diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; + const SEXP &alpha_x = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_X)]; - const Rcpp::NumericVector &alpha_y = + const SEXP &alpha_y = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_Y)]; - std::vector colnames = - Rcpp::as>(this->initial_grid.names()); - - std::vector transport_names(colnames.begin() + 1, - colnames.begin() + 1 + - this->module_sizes[POET_SOL]); - this->alpha_x = - parseAlphas2D(alpha_x, transport_names, this->n_cols, this->n_rows); + parseAlphas(alpha_x, this->transport_names, this->n_cols, this->n_rows); this->alpha_y = - parseAlphas2D(alpha_y, transport_names, this->n_cols, this->n_rows); + parseAlphas(alpha_y, this->transport_names, this->n_cols, this->n_rows); + + R["alpha_x"] = this->alpha_x; + R["alpha_y"] = this->alpha_y; + + R.parseEval("print(alpha_x)"); + R.parseEval("print(alpha_y)"); } } // namespace poet \ No newline at end of file diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 8e5061c76..7e77a65d4 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -160,7 +160,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { std::vector colnames = Rcpp::as>(this->initial_grid.names()); - this->to_transport = this->pqc_sol_order = std::vector( + this->transport_names = this->pqc_sol_order = std::vector( colnames.begin() + 1, colnames.begin() + 1 + this->module_sizes[POET_SOL]); @@ -171,10 +171,10 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); - R["pqc_mat"] = this->phreeqc_mat; - R["grid_def"] = initial_grid; + // R["pqc_mat"] = this->phreeqc_mat; + // R["grid_def"] = initial_grid; - R.parseEval("print(pqc_mat)"); - R.parseEval("print(grid_def)"); + // R.parseEval("print(pqc_mat)"); + // R.parseEval("print(grid_def)"); } } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index bc4a4dafd..3c37f84ee 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -98,7 +98,7 @@ private: Rcpp::List alpha_x; Rcpp::List alpha_y; - std::vector to_transport; + std::vector transport_names; // Chemistry Members static constexpr const char *chemistry_key = "Chemistry"; From bc923b75e6262de61e5d296d94a859dd4833051d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 19 Mar 2024 15:37:29 +0000 Subject: [PATCH 15/77] Add resolvePqcBound function and refactor parseBoundaries2D function --- R_lib/init_r_lib.R | 11 ++++ src/Init/DiffusionInit.cpp | 121 ++++++++++++++++++++++--------------- src/Init/InitialList.hpp | 2 + 3 files changed, 85 insertions(+), 49 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index 672e372cc..c9b096057 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -28,3 +28,14 @@ pqc_to_grid <- function(pqc_in, grid) { return(res_df) } + +resolvePqcBound <- function(pqc_mat, transport_spec, id) { + df <- as.data.frame(pqc_mat, check.names = FALSE) + value <- df[df$ID == id, transport_spec] + + if (is.nan(value)) { + value <- 0 + } + + return(value) +} diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index a30b66ec6..93046575d 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -26,49 +26,6 @@ const std::map tug_side_mapping = { {tug::BC_SIDE_TOP, "N"}, {tug::BC_SIDE_BOTTOM, "S"}}; -static Rcpp::List parseBoundaries2D(const Rcpp::List &boundaries_list, - std::uint32_t n_cols, - std::uint32_t n_rows) { - Rcpp::List out_list; - - for (const auto &side : tug_side_mapping) { - Rcpp::NumericVector type = - (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) - ? Rcpp::NumericVector(n_rows, tug::BC_TYPE_CLOSED) - : Rcpp::NumericVector(n_cols, tug::BC_TYPE_CLOSED); - - Rcpp::NumericVector value = - (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) - ? Rcpp::NumericVector(n_rows, 0) - : Rcpp::NumericVector(n_cols, 0); - - if (boundaries_list.containsElementNamed(side.second.c_str())) { - const Rcpp::List mapping = boundaries_list[side.second]; - - const Rcpp::NumericVector cells = mapping["cells"]; - const Rcpp::NumericVector values = mapping["sol_id"]; - - if (cells.size() != values.size()) { - throw std::runtime_error("Boundary [" + side.second + - "] cells and values are not the same length"); - } - } - - out_list[side.second] = Rcpp::List::create(Rcpp::Named("type") = type, - Rcpp::Named("value") = value); - } -} - -static inline SEXP_TYPE get_datatype(const SEXP &input) { - Rcpp::Function check_list("is.list"); - - if (Rcpp::as(check_list(input))) { - return SEXP_IS_LIST; - } else { - return SEXP_IS_VEC; - } -} - static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, std::uint32_t n_cols, std::uint32_t n_rows) { @@ -90,6 +47,70 @@ static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, } } +Rcpp::List InitialList::resolveBoundaries(const Rcpp::List &boundaries_list) { + Rcpp::List bound_list; + Rcpp::Function resolve_R("resolvePqcBound"); + + for (const auto &species : this->transport_names) { + Rcpp::List spec_list; + + for (const auto &side : tug_side_mapping) { + Rcpp::NumericVector c_type = + (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) + ? Rcpp::NumericVector(n_rows, tug::BC_TYPE_CLOSED) + : Rcpp::NumericVector(n_cols, tug::BC_TYPE_CLOSED); + + Rcpp::NumericVector c_value = + (side.first == tug::BC_SIDE_RIGHT || side.first == tug::BC_SIDE_LEFT) + ? Rcpp::NumericVector(n_rows, 0) + : Rcpp::NumericVector(n_cols, 0); + + if (boundaries_list.containsElementNamed(side.second.c_str())) { + const Rcpp::List mapping = boundaries_list[side.second]; + + const Rcpp::NumericVector cells = mapping["cell"]; + const Rcpp::NumericVector values = mapping["sol_id"]; + const Rcpp::CharacterVector type_str = mapping["type"]; + + if (cells.size() != values.size()) { + throw std::runtime_error( + "Boundary [" + side.second + + "] cells and values are not the same length"); + } + + for (std::size_t i = 0; i < cells.size(); i++) { + if (type_str[i] == "closed") { + c_type[cells[i] - 1] = tug::BC_TYPE_CLOSED; + } else if (type_str[i] == "constant") { + c_type[cells[i] - 1] = tug::BC_TYPE_CONSTANT; + c_value[cells[i] - 1] = Rcpp::as( + resolve_R(this->phreeqc_mat, Rcpp::wrap(species), values[i])); + } else { + throw std::runtime_error("Unknown boundary type"); + } + } + } + + spec_list[side.second] = Rcpp::List::create( + Rcpp::Named("type") = c_type, Rcpp::Named("value") = c_value); + } + + bound_list[species] = spec_list; + } + + return bound_list; +} + +static inline SEXP_TYPE get_datatype(const SEXP &input) { + Rcpp::Function check_list("is.list"); + + if (Rcpp::as(check_list(input))) { + return SEXP_IS_LIST; + } else { + return SEXP_IS_VEC; + } +} + static Rcpp::List parseAlphas(const SEXP &input, const std::vector &transport_names, std::uint32_t n_cols, std::uint32_t n_rows) { @@ -132,23 +153,25 @@ static Rcpp::List parseAlphas(const SEXP &input, return out_list; } void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { - // const Rcpp::List &boundaries = - // diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; + const Rcpp::List &boundaries = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; const SEXP &alpha_x = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_X)]; const SEXP &alpha_y = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_Y)]; + this->boundaries = resolveBoundaries(boundaries); + this->alpha_x = parseAlphas(alpha_x, this->transport_names, this->n_cols, this->n_rows); this->alpha_y = parseAlphas(alpha_y, this->transport_names, this->n_cols, this->n_rows); - R["alpha_x"] = this->alpha_x; - R["alpha_y"] = this->alpha_y; + // R["alpha_x"] = this->alpha_x; + // R["alpha_y"] = this->alpha_y; - R.parseEval("print(alpha_x)"); - R.parseEval("print(alpha_y)"); + // R.parseEval("print(alpha_x)"); + // R.parseEval("print(alpha_y)"); } } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 3c37f84ee..fe1afcc59 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -93,6 +93,8 @@ private: } void initDiffusion(const Rcpp::List &diffusion_input); + Rcpp::List resolveBoundaries(const Rcpp::List &boundaries_list); + Rcpp::List boundaries; Rcpp::List alpha_x; From 8969fea7e2fc2b1f87f18b7c7705a7bf6d59badb Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 19 Mar 2024 22:03:22 +0000 Subject: [PATCH 16/77] Update grid and diffusion setup in test.R --- bench/barite/het/test.R | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/bench/barite/het/test.R b/bench/barite/het/test.R index 97c642b51..f7269e3f7 100644 --- a/bench/barite/het/test.R +++ b/bench/barite/het/test.R @@ -2,14 +2,30 @@ grid_def <- matrix(c(2, 3), nrow = 2, ncol = 5) # Define grid configuration for POET model grid_setup <- list( - pqc_in = "./barite_het.pqi", - pqc_db = "./db_barite.dat", # Path to the database file for Phreeqc + pqc_in_file = "./barite_het.pqi", + pqc_db_file = "./db_barite.dat", # Path to the database file for Phreeqc grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script grid_size = c(ncol(grid_def), nrow(grid_def)), # Size of the grid in meters constant_cells = c() # IDs of cells with constant concentration ) +diffusion_setup <- list( + boundaries = list( + "E" = list( + "type" = rep("constant", nrow(grid_def)), + "sol_id" = rep(4, nrow(grid_def)), + "cell" = seq_len(nrow(grid_def)) + ) + ), + alpha_x = 1e-6, + alpha_y = matrix(runif(10, 1e-8, 1e-7), + nrow = nrow(grid_def), + ncol = ncol(grid_def) + ) +) + # Define a setup list for simulation configuration setup <- list( - grid = grid_setup # Parameters related to the grid structure + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup # Parameters related to the diffusion process ) From 265638ab17a42bba185281b071326759077550a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 20 Mar 2024 22:33:23 +0000 Subject: [PATCH 17/77] Update include statement and add CMakeLists.txt for DataStructures --- src/CMakeLists.txt | 5 ++- src/Chemistry/WorkerFunctions.cpp | 14 +++++++ src/DataStructures/CMakeLists.txt | 11 +++++ src/DataStructures/Field.cpp | 2 +- .../{DataStructures.hpp => Field.hpp} | 40 ------------------- src/DataStructures/NamedVector.hpp | 25 ++++++++++++ 6 files changed, 55 insertions(+), 42 deletions(-) create mode 100644 src/DataStructures/CMakeLists.txt rename src/DataStructures/{DataStructures.hpp => Field.hpp} (84%) create mode 100644 src/DataStructures/NamedVector.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e0dcb8a55..c924723ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(DataStructures) + add_library(poetinitlib Init/InitialList.cpp Init/GridInit.cpp @@ -5,6 +7,7 @@ add_library(poetinitlib ) target_link_libraries(poetinitlib PUBLIC + DataStructures RRuntime IPhreeqcPOET tug @@ -27,11 +30,11 @@ add_library(poetlib Chemistry/SurrogateModels/HashFunctions.cpp Chemistry/SurrogateModels/InterpolationModule.cpp Chemistry/SurrogateModels/ProximityHashTable.cpp - DataStructures/Field.cpp Transport/DiffusionModule.cpp ) target_link_libraries(poetlib PUBLIC + DataStructures MPI::MPI_C ${MATH_LIBRARY} RRuntime diff --git a/src/Chemistry/WorkerFunctions.cpp b/src/Chemistry/WorkerFunctions.cpp index 4e67e33d5..8cec96d62 100644 --- a/src/Chemistry/WorkerFunctions.cpp +++ b/src/Chemistry/WorkerFunctions.cpp @@ -17,6 +17,20 @@ #include namespace poet { + +struct WorkPackage { + std::size_t size; + std::vector> input; + std::vector> output; + std::vector mapping; + + WorkPackage(size_t _size) : size(_size) { + input.resize(size); + output.resize(size); + mapping.resize(size, CHEM_PQC); + } +}; + inline std::string get_string(int root, MPI_Comm communicator) { int count; MPI_Bcast(&count, 1, MPI_INT, root, communicator); diff --git a/src/DataStructures/CMakeLists.txt b/src/DataStructures/CMakeLists.txt new file mode 100644 index 000000000..025671340 --- /dev/null +++ b/src/DataStructures/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(DataStructures OBJECT + Field.cpp +) + +target_link_libraries(DataStructures + PUBLIC RRuntime +) + +target_include_directories(DataStructures + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/DataStructures/Field.cpp b/src/DataStructures/Field.cpp index 71d51dea4..69ab648de 100644 --- a/src/DataStructures/Field.cpp +++ b/src/DataStructures/Field.cpp @@ -1,4 +1,4 @@ -#include "DataStructures.hpp" +#include "Field.hpp" #include #include diff --git a/src/DataStructures/DataStructures.hpp b/src/DataStructures/Field.hpp similarity index 84% rename from src/DataStructures/DataStructures.hpp rename to src/DataStructures/Field.hpp index 30f69e5dd..2f2269653 100644 --- a/src/DataStructures/DataStructures.hpp +++ b/src/DataStructures/Field.hpp @@ -1,54 +1,14 @@ #ifndef DATASTRUCTURES_H_ #define DATASTRUCTURES_H_ -#include "../Chemistry/enums.hpp" - #include -#include -#include #include -#include -#include #include -#include #include namespace poet { -struct WorkPackage { - std::size_t size; - std::vector> input; - std::vector> output; - std::vector mapping; - - WorkPackage(size_t _size) : size(_size) { - input.resize(size); - output.resize(size); - mapping.resize(size, CHEM_PQC); - } -}; - -template class NamedVector : public Rcpp::NumericVector { -public: - NamedVector() : Rcpp::NumericVector(){}; - - NamedVector(const std::vector &in_names, - const std::vector &in_values) - : Rcpp::NumericVector(Rcpp::wrap(in_values)) { - this->names() = Rcpp::CharacterVector(Rcpp::wrap(in_names)); - } - - NamedVector(const SEXP &s) : Rcpp::NumericVector(s){}; - - bool empty() const { return (this->size() == 0); } - - std::vector getNames() const { - return Rcpp::as>(this->names()); - } - std::vector getValues() const { return Rcpp::as>(*this); } -}; - using FieldColumn = std::vector; /** diff --git a/src/DataStructures/NamedVector.hpp b/src/DataStructures/NamedVector.hpp new file mode 100644 index 000000000..f120b0e48 --- /dev/null +++ b/src/DataStructures/NamedVector.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace poet { +template class NamedVector : public Rcpp::NumericVector { +public: + NamedVector() : Rcpp::NumericVector(){}; + + NamedVector(const std::vector &in_names, + const std::vector &in_values) + : Rcpp::NumericVector(Rcpp::wrap(in_values)) { + this->names() = Rcpp::CharacterVector(Rcpp::wrap(in_names)); + } + + NamedVector(const SEXP &s) : Rcpp::NumericVector(s){}; + + bool empty() const { return (this->size() == 0); } + + std::vector getNames() const { + return Rcpp::as>(this->names()); + } + std::vector getValues() const { return Rcpp::as>(*this); } +}; +} // namespace poet \ No newline at end of file From 5d4a05fe9bf7653856196c89ef76deaf99525ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 20 Mar 2024 23:46:57 +0000 Subject: [PATCH 18/77] Add Init/CMakeLists.txt and ChemistryInit.cpp files, and update initializer.cpp and InitialList.hpp --- src/CMakeLists.txt | 98 +++++++++++++++---------------- src/DataStructures/CMakeLists.txt | 10 +--- src/Init/CMakeLists.txt | 6 ++ src/Init/ChemistryInit.cpp | 17 ++++++ src/Init/GridInit.cpp | 58 ++++++++++++------ src/Init/InitialList.cpp | 72 +++++++++++++++++++++++ src/Init/InitialList.hpp | 62 ++++++++++++++++--- src/initializer.cpp | 4 ++ 8 files changed, 243 insertions(+), 84 deletions(-) create mode 100644 src/Init/CMakeLists.txt create mode 100644 src/Init/ChemistryInit.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c924723ea..f593d6b63 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,64 +1,64 @@ -add_subdirectory(DataStructures) +add_library(POETLib OBJECT) -add_library(poetinitlib - Init/InitialList.cpp - Init/GridInit.cpp +target_sources( + POETLib + PRIVATE + Init/InitialList.cpp + Init/GridInit.cpp Init/DiffusionInit.cpp + Init/ChemistryInit.cpp + PRIVATE + DataStructures/Field.cpp ) -target_link_libraries(poetinitlib PUBLIC - DataStructures - RRuntime - IPhreeqcPOET - tug +target_include_directories(POETLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries( + POETLib + PUBLIC RRuntime + PUBLIC IPhreeqcPOET + PRIVATE tug ) -target_include_directories(poetinitlib PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/Init" -) +# add_library(poetlib +# Base/Grid.cpp +# Base/SimParams.cpp +# Chemistry/ChemistryModule.cpp +# Chemistry/MasterFunctions.cpp +# Chemistry/WorkerFunctions.cpp +# Chemistry/SurrogateModels/DHT_Wrapper.cpp +# Chemistry/SurrogateModels/DHT.c +# Chemistry/SurrogateModels/HashFunctions.cpp +# Chemistry/SurrogateModels/InterpolationModule.cpp +# Chemistry/SurrogateModels/ProximityHashTable.cpp +# Transport/DiffusionModule.cpp +# ) -target_compile_definitions(poetinitlib PUBLIC STRICT_R_HEADERS) +# target_link_libraries(poetlib PUBLIC +# DataStructures +# Init +# MPI::MPI_C +# ${MATH_LIBRARY} +# RRuntime +# PhreeqcRM +# tug +# ) -add_library(poetlib - Base/Grid.cpp - Base/SimParams.cpp - Chemistry/ChemistryModule.cpp - Chemistry/MasterFunctions.cpp - Chemistry/WorkerFunctions.cpp - Chemistry/SurrogateModels/DHT_Wrapper.cpp - Chemistry/SurrogateModels/DHT.c - Chemistry/SurrogateModels/HashFunctions.cpp - Chemistry/SurrogateModels/InterpolationModule.cpp - Chemistry/SurrogateModels/ProximityHashTable.cpp - Transport/DiffusionModule.cpp -) +# target_compile_definitions(poetlib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) -target_link_libraries(poetlib PUBLIC - DataStructures - MPI::MPI_C - ${MATH_LIBRARY} - RRuntime - PhreeqcRM - tug - poetinitlib -) +# mark_as_advanced(PHREEQCRM_BUILD_MPI PHREEQCRM_DISABLE_OPENMP) +# set(PHREEQCRM_DISABLE_OPENMP ON CACHE BOOL "" FORCE) -target_compile_definitions(poetlib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) +# option(POET_DHT_DEBUG "Build with DHT debug info" OFF) -mark_as_advanced(PHREEQCRM_BUILD_MPI PHREEQCRM_DISABLE_OPENMP) -set(PHREEQCRM_DISABLE_OPENMP ON CACHE BOOL "" FORCE) +# if(POET_DHT_DEBUG) +# target_compile_definitions(poetlib PRIVATE DHT_STATISTICS) +# endif() -option(POET_DHT_DEBUG "Build with DHT debug info" OFF) +# option(POET_PHT_ADDITIONAL_INFO "Enables additional information in the PHT" OFF) -if(POET_DHT_DEBUG) - target_compile_definitions(poetlib PRIVATE DHT_STATISTICS) -endif() - -option(POET_PHT_ADDITIONAL_INFO "Enables additional information in the PHT" OFF) - -if (POET_PHT_ADDITIONAL_INFO) - target_compile_definitions(poetlib PRIVATE POET_PHT_ADD) -endif() +# if (POET_PHT_ADDITIONAL_INFO) +# target_compile_definitions(poetlib PRIVATE POET_PHT_ADD) +# endif() file(READ "${PROJECT_SOURCE_DIR}/R_lib/kin_r_library.R" R_KIN_LIB ) file(READ "${PROJECT_SOURCE_DIR}/R_lib/init_r_lib.R" R_INIT_LIB) @@ -70,7 +70,7 @@ configure_file(poet.hpp.in poet.hpp @ONLY) # target_include_directories(poet PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") add_executable(poet_init initializer.cpp) -target_link_libraries(poet_init PRIVATE poetinitlib RRuntime) +target_link_libraries(poet_init PRIVATE POETLib RRuntime) target_include_directories(poet_init PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") # install(TARGETS poet DESTINATION bin) diff --git a/src/DataStructures/CMakeLists.txt b/src/DataStructures/CMakeLists.txt index 025671340..bbc0263a8 100644 --- a/src/DataStructures/CMakeLists.txt +++ b/src/DataStructures/CMakeLists.txt @@ -1,11 +1,3 @@ -add_library(DataStructures OBJECT +target_sources(POETLib PRIVATE Field.cpp -) - -target_link_libraries(DataStructures - PUBLIC RRuntime -) - -target_include_directories(DataStructures - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) \ No newline at end of file diff --git a/src/Init/CMakeLists.txt b/src/Init/CMakeLists.txt new file mode 100644 index 000000000..47ce9eb3e --- /dev/null +++ b/src/Init/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(POETLib PRIVATE + InitialList.cpp + GridInit.cpp + DiffusionInit.cpp + ChemistryInit.cpp +) \ No newline at end of file diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp new file mode 100644 index 000000000..962fc3b73 --- /dev/null +++ b/src/Init/ChemistryInit.cpp @@ -0,0 +1,17 @@ +#include "InitialList.hpp" + +namespace poet { +InitialList::ChemistryInit InitialList::getChemistryInit() const { + ChemistryInit chem_init; + + chem_init.initial_grid = Field(initial_grid); + + chem_init.database = database; + chem_init.pqc_scripts = pqc_scripts; + chem_init.pqc_ids = pqc_ids; + + chem_init.pqc_sol_order = pqc_sol_order; + + return chem_init; +} +} // namespace poet \ No newline at end of file diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 7e77a65d4..ba7e1716a 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,7 @@ #include namespace poet { + static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { IPhreeqcPOET::PhreeqcMat phreeqc_mat = phreeqc.getPhreeqcMat(); @@ -55,13 +57,13 @@ replaceRawKeywordIDs(std::map raws) { return raws; } -static inline IPhreeqcPOET::ModulesArray -getModuleSizes(IPhreeqcPOET &phreeqc, const Rcpp::List &initial_grid) { +static inline uint32_t getSolutionCount(IPhreeqcPOET &phreeqc, + const Rcpp::List &initial_grid) { IPhreeqcPOET::ModulesArray mod_array; - Rcpp::Function unique("unique"); + Rcpp::Function unique_R("unique"); std::vector row_ids = - Rcpp::as>(unique(initial_grid["ID"])); + Rcpp::as>(unique_R(initial_grid["ID"])); // std::vector sizes_vec(sizes.begin(), sizes.end()); @@ -71,7 +73,7 @@ getModuleSizes(IPhreeqcPOET &phreeqc, const Rcpp::List &initial_grid) { // std::copy(sizes_vec.begin(), sizes_vec.end(), sizes.begin()); - return phreeqc.getModuleSizes(row_ids); + return phreeqc.getModuleSizes(row_ids)[POET_SOL]; } static std::string readFile(const std::string &path) { @@ -95,6 +97,7 @@ static std::string readFile(const std::string &path) { void InitialList::initGrid(const Rcpp::List &grid_input) { // parse input values + Rcpp::Function unique_R("unique"); std::string script; std::string database; @@ -155,26 +158,45 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); - this->module_sizes = getModuleSizes(phreeqc, this->initial_grid); + const uint32_t solution_count = getSolutionCount(phreeqc, this->initial_grid); std::vector colnames = Rcpp::as>(this->initial_grid.names()); this->transport_names = this->pqc_sol_order = std::vector( colnames.begin() + 1, - colnames.begin() + 1 + this->module_sizes[POET_SOL]); + colnames.begin() + 1 + solution_count); // skip ID - // print module sizes - for (std::size_t i = 0; i < this->module_sizes.size(); i++) { - std::cout << this->module_sizes[i] << std::endl; + std::map pqc_raw_dumps; + + pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); + + this->pqc_ids = + Rcpp::as>(unique_R(this->initial_grid["ID"])); + + for (const auto &id : this->pqc_ids) { + this->pqc_scripts.push_back(pqc_raw_dumps[id]); } - - this->pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); - - // R["pqc_mat"] = this->phreeqc_mat; - // R["grid_def"] = initial_grid; - - // R.parseEval("print(pqc_mat)"); - // R.parseEval("print(grid_def)"); } + +InitialList::DiffusionInit InitialList::getDiffusionInit() const { + DiffusionInit diff_init; + + diff_init.n_cols = this->n_cols; + diff_init.n_rows = this->n_rows; + + diff_init.s_cols = this->s_cols; + diff_init.s_rows = this->s_rows; + + diff_init.constant_cells = this->constant_cells; + diff_init.transport_names = this->transport_names; + + diff_init.initial_grid = Field(this->initial_grid); + diff_init.boundaries = Field(this->boundaries); + diff_init.alpha_x = Field(this->alpha_x); + diff_init.alpha_y = Field(this->alpha_y); + + return diff_init; +} + } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index a433097a2..aa66f71a6 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -1,8 +1,80 @@ #include "InitialList.hpp" +#include +#include +#include +#include +#include +#include namespace poet { void InitialList::initializeFromList(const Rcpp::List &setup) { initGrid(setup[grid_key]); initDiffusion(setup[diffusion_key]); } + +void InitialList::importList(const Rcpp::List &setup) { + this->dim = Rcpp::as(setup[static_cast(ExportList::GRID_DIM)]); + + Rcpp::NumericVector grid_specs = + setup[static_cast(ExportList::GRID_SPECS)]; + this->n_rows = grid_specs[0]; + this->n_cols = grid_specs[1]; + + Rcpp::NumericVector spatial = + setup[static_cast(ExportList::GRID_SPATIAL)]; + this->s_rows = spatial[0]; + this->s_cols = spatial[1]; + + this->constant_cells = Rcpp::as>( + setup[static_cast(ExportList::GRID_CONSTANT)]); + + this->porosity = Rcpp::as>( + setup[static_cast(ExportList::GRID_POROSITY)]); + + this->transport_names = Rcpp::as>( + setup[static_cast(ExportList::DIFFU_TRANSPORT)]); + this->boundaries = + Rcpp::List(setup[static_cast(ExportList::DIFFU_BOUNDARIES)]); + this->alpha_x = Rcpp::as>( + setup[static_cast(ExportList::DIFFU_ALPHA_X)]); + this->alpha_y = Rcpp::as>( + setup[static_cast(ExportList::DIFFU_ALPHA_Y)]); + + this->database = + Rcpp::as(setup[static_cast(ExportList::CHEM_DATABASE)]); + this->pqc_scripts = Rcpp::as>( + setup[static_cast(ExportList::CHEM_PQC_SCRIPTS)]); + this->pqc_ids = Rcpp::as>( + setup[static_cast(ExportList::CHEM_PQC_IDS)]); + this->pqc_sol_order = Rcpp::as>( + setup[static_cast(ExportList::CHEM_PQC_SOL_ORDER)]); +} + +Rcpp::List InitialList::exportList() { + Rcpp::List out(static_cast(ExportList::ENUM_SIZE)); + + out[static_cast(ExportList::GRID_DIM)] = this->dim; + out[static_cast(ExportList::GRID_SPECS)] = + Rcpp::NumericVector::create(this->n_rows, this->n_cols); + out[static_cast(ExportList::GRID_SPATIAL)] = + Rcpp::NumericVector::create(this->s_rows, this->s_cols); + out[static_cast(ExportList::GRID_CONSTANT)] = + Rcpp::wrap(this->constant_cells); + out[static_cast(ExportList::GRID_POROSITY)] = Rcpp::wrap(this->porosity); + + out[static_cast(ExportList::DIFFU_TRANSPORT)] = + Rcpp::wrap(this->transport_names); + out[static_cast(ExportList::DIFFU_BOUNDARIES)] = this->boundaries; + out[static_cast(ExportList::DIFFU_ALPHA_X)] = this->alpha_x; + out[static_cast(ExportList::DIFFU_ALPHA_Y)] = this->alpha_y; + + out[static_cast(ExportList::CHEM_DATABASE)] = Rcpp::wrap(this->database); + out[static_cast(ExportList::CHEM_PQC_SCRIPTS)] = + Rcpp::wrap(this->pqc_scripts); + out[static_cast(ExportList::CHEM_PQC_IDS)] = Rcpp::wrap(this->pqc_ids); + out[static_cast(ExportList::CHEM_PQC_SOL_ORDER)] = + Rcpp::wrap(this->pqc_sol_order); + + return out; +} } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index fe1afcc59..060fc19a0 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -8,10 +8,11 @@ #include #include -#include -#include +#include #include +#include + namespace poet { using TugType = double; @@ -22,12 +23,29 @@ public: void initializeFromList(const Rcpp::List &setup); - void importList(const std::string &file_name); - Rcpp::List exportList(const std::string &file_name); + void importList(const Rcpp::List &setup); + Rcpp::List exportList(); private: RInside &R; + enum class ExportList { + GRID_DIM, + GRID_SPECS, + GRID_SPATIAL, + GRID_CONSTANT, + GRID_POROSITY, + DIFFU_TRANSPORT, + DIFFU_BOUNDARIES, + DIFFU_ALPHA_X, + DIFFU_ALPHA_Y, + CHEM_DATABASE, + CHEM_PQC_SCRIPTS, + CHEM_PQC_IDS, + CHEM_PQC_SOL_ORDER, + ENUM_SIZE + }; + // Grid members static constexpr const char *grid_key = "Grid"; @@ -65,18 +83,34 @@ private: double s_rows; std::vector constant_cells; + std::vector porosity; Rcpp::List initial_grid; // No export Rcpp::NumericMatrix phreeqc_mat; - // Initialized by grid - std::map pqc_raw_dumps; +public: + struct DiffusionInit { + std::uint32_t n_cols; + std::uint32_t n_rows; - // Chemistry members - IPhreeqcPOET::ModulesArray module_sizes; + double s_cols; + double s_rows; + std::vector constant_cells; + + std::vector transport_names; + + Field initial_grid; + Field boundaries; + Field alpha_x; + Field alpha_y; + }; + + DiffusionInit getDiffusionInit() const; + +private: // Diffusion members static constexpr const char *diffusion_key = "Diffusion"; @@ -112,5 +146,17 @@ private: std::vector pqc_ids; std::vector pqc_sol_order; + +public: + struct ChemistryInit { + Field initial_grid; + + std::string database; + std::vector pqc_scripts; + std::vector pqc_ids; + std::vector pqc_sol_order; + }; + + ChemistryInit getChemistryInit() const; }; } // namespace poet \ No newline at end of file diff --git a/src/initializer.cpp b/src/initializer.cpp index 8d1c0221e..1f95babed 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -30,6 +30,10 @@ int main(int argc, char **argv) { init.initializeFromList(setup); + Rcpp::Function save("saveRDS"); + + save(init.exportList(), "init.rds"); + // parseGrid(R, grid, results); return EXIT_SUCCESS; } \ No newline at end of file From d8dddf14f204b50d8ab491f345061da373e574c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Thu, 21 Mar 2024 21:36:09 +0000 Subject: [PATCH 19/77] Add support for importing and exporting initial grid in InitialList class --- src/Init/InitialList.cpp | 4 ++++ src/Init/InitialList.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index aa66f71a6..0931c34f3 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -31,6 +31,9 @@ void InitialList::importList(const Rcpp::List &setup) { this->porosity = Rcpp::as>( setup[static_cast(ExportList::GRID_POROSITY)]); + this->initial_grid = + Rcpp::List(setup[static_cast(ExportList::GRID_INITIAL)]); + this->transport_names = Rcpp::as>( setup[static_cast(ExportList::DIFFU_TRANSPORT)]); this->boundaries = @@ -61,6 +64,7 @@ Rcpp::List InitialList::exportList() { out[static_cast(ExportList::GRID_CONSTANT)] = Rcpp::wrap(this->constant_cells); out[static_cast(ExportList::GRID_POROSITY)] = Rcpp::wrap(this->porosity); + out[static_cast(ExportList::GRID_INITIAL)] = this->initial_grid; out[static_cast(ExportList::DIFFU_TRANSPORT)] = Rcpp::wrap(this->transport_names); diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 060fc19a0..7a97bbead 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -35,6 +35,7 @@ private: GRID_SPATIAL, GRID_CONSTANT, GRID_POROSITY, + GRID_INITIAL, DIFFU_TRANSPORT, DIFFU_BOUNDARIES, DIFFU_ALPHA_X, From cb56f4aa10aabf63b3955b94d46cfabb28921ed6 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Thu, 21 Mar 2024 22:33:40 +0000 Subject: [PATCH 20/77] Add total_grid_cells to ChemistryInit struct --- src/Init/ChemistryInit.cpp | 2 ++ src/Init/DiffusionInit.cpp | 23 +++++++++++++++++++++++ src/Init/GridInit.cpp | 20 -------------------- src/Init/InitialList.hpp | 3 +++ 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index 962fc3b73..2975eec2c 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -6,6 +6,8 @@ InitialList::ChemistryInit InitialList::getChemistryInit() const { chem_init.initial_grid = Field(initial_grid); + chem_init.total_grid_cells = this->n_cols * this->n_rows; + chem_init.database = database; chem_init.pqc_scripts = pqc_scripts; chem_init.pqc_ids = pqc_ids; diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index 93046575d..2d83d1091 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -174,4 +174,27 @@ void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { // R.parseEval("print(alpha_x)"); // R.parseEval("print(alpha_y)"); } + +InitialList::DiffusionInit InitialList::getDiffusionInit() const { + DiffusionInit diff_init; + + diff_init.dim = this->dim; + + diff_init.n_cols = this->n_cols; + diff_init.n_rows = this->n_rows; + + diff_init.s_cols = this->s_cols; + diff_init.s_rows = this->s_rows; + + diff_init.constant_cells = this->constant_cells; + diff_init.transport_names = this->transport_names; + + diff_init.initial_grid = Field(this->initial_grid); + diff_init.boundaries = Field(this->boundaries); + diff_init.alpha_x = Field(this->alpha_x); + diff_init.alpha_y = Field(this->alpha_y); + + return diff_init; +} + } // namespace poet \ No newline at end of file diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index ba7e1716a..2b9d030ab 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -179,24 +179,4 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { } } -InitialList::DiffusionInit InitialList::getDiffusionInit() const { - DiffusionInit diff_init; - - diff_init.n_cols = this->n_cols; - diff_init.n_rows = this->n_rows; - - diff_init.s_cols = this->s_cols; - diff_init.s_rows = this->s_rows; - - diff_init.constant_cells = this->constant_cells; - diff_init.transport_names = this->transport_names; - - diff_init.initial_grid = Field(this->initial_grid); - diff_init.boundaries = Field(this->boundaries); - diff_init.alpha_x = Field(this->alpha_x); - diff_init.alpha_y = Field(this->alpha_y); - - return diff_init; -} - } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 7a97bbead..0f3b631b1 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -93,6 +93,7 @@ private: public: struct DiffusionInit { + uint8_t dim; std::uint32_t n_cols; std::uint32_t n_rows; @@ -152,6 +153,8 @@ public: struct ChemistryInit { Field initial_grid; + uint32_t total_grid_cells; + std::string database; std::vector pqc_scripts; std::vector pqc_ids; From 7a31858aafa6a5052bec07929c4484724160ca24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 27 Mar 2024 15:35:53 +0000 Subject: [PATCH 21/77] Add Basic heterogeneous diffusion functionality --- R_lib/kin_r_library.R | 148 ++++----- bench/barite/het/runtime.R | 4 + ext/tug | 2 +- src/Base/Grid.cpp | 274 ---------------- src/Base/Grid.hpp | 117 ------- src/Base/SimParams.cpp | 163 +++++---- src/Base/SimParams.hpp | 299 ++++++++--------- src/CMakeLists.txt | 17 +- src/Init/CMakeLists.txt | 6 - src/Init/DiffusionInit.cpp | 42 ++- src/Init/InitialList.cpp | 8 +- src/Init/InitialList.hpp | 13 +- src/Transport/DiffusionModule.cpp | 226 +++++-------- src/Transport/DiffusionModule.hpp | 49 +-- src/poet.cpp | 527 ++++++++++++++++++++---------- src/poet.hpp.in | 77 ++++- 16 files changed, 889 insertions(+), 1083 deletions(-) create mode 100644 bench/barite/het/runtime.R delete mode 100644 src/Base/Grid.cpp delete mode 100644 src/Base/Grid.hpp delete mode 100644 src/Init/CMakeLists.txt diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index 1e7f803ed..d4d04f9e2 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -28,7 +28,7 @@ master_init <- function(setup) { ## Setup the directory where we will store the results verb <- FALSE - if (local_rank == 0) { + # if (local_rank == 0) { verb <- TRUE ## verbosity loading MUFITS results if (!dir.exists(fileout)) { dir.create(fileout) @@ -41,25 +41,26 @@ master_init <- function(setup) { } else { msgm("store_result is ", store_result) } - } else { - - } + # } else { + + # } setup$iter <- 1 - setup$maxiter <- setup$iterations setup$timesteps <- setup$timesteps + setup$maxiter <- length(setup$timesteps) + setup$iterations <- setup$maxiter setup$simulation_time <- 0 if (is.null(setup[["store_result"]])) { setup$store_result <- TRUE } - + if (setup$store_result) { if (is.null(setup[["out_save"]])) { setup$out_save <- seq(1, setup$iterations) } } - + return(setup) } @@ -67,31 +68,33 @@ master_init <- function(setup) { ## calculated time step if store_result is TRUE and increments the ## iteration counter master_iteration_end <- function(setup) { - iter <- setup$iter + # iter <- setup$iter + # print(iter) ## max digits for iterations - dgts <- as.integer(ceiling(log10(setup$iterations + 1))) - ## string format to use in sprintf + iter <- 1 + dgts <- as.integer(ceiling(log10(1))) + ## string format to use in sprintf fmt <- paste0("%0", dgts, "d") - + ## Write on disk state_T and state_C after every iteration ## comprised in setup$out_save - if (setup$store_result) { - if (iter %in% setup$out_save) { - nameout <- paste0(fileout, "/iter_", sprintf(fmt=fmt, iter), ".rds") - info <- list( - tr_req_dt = as.integer(setup$req_dt) - ## tr_allow_dt = setup$allowed_dt, - ## tr_inniter = as.integer(setup$inniter) - ) - saveRDS(list( - T = setup$state_T, C = setup$state_C, - simtime = as.integer(setup$simtime), - tr_info = info - ), file = nameout) - msgm("results stored in <", nameout, ">") - } - } - msgm("done iteration", iter, "/", setup$maxiter) + # if (setup$store_result) { + # if (iter %in% setup$out_save) { + nameout <- paste0(fileout, "/iter_", sprintf(fmt = fmt, iter), ".rds") + info <- list( + tr_req_dt = as.integer(1) + ## tr_allow_dt = setup$allowed_dt, + ## tr_inniter = as.integer(setup$inniter) + ) + saveRDS(list( + T = setup$state_T, C = setup$state_C, + simtime = as.integer(0), + tr_info = info + ), file = nameout) + msgm("results stored in <", nameout, ">") + # } + # } + msgm("done iteration", iter, "/", 1) setup$iter <- setup$iter + 1 return(setup) } @@ -104,41 +107,41 @@ slave_chemistry <- function(setup, data) { immobile <- setup$immobile kin <- setup$kin ann <- setup$ann - + iter <- setup$iter timesteps <- setup$timesteps dt <- timesteps[iter] - + state_T <- data ## not the global field, but the work-package - + ## treat special H+/pH, e-/pe cases state_T <- RedModRphree::Act2pH(state_T) - + ## reduction of the problem if (setup$reduce) { reduced <- ReduceStateOmit(state_T, omit = setup$ann) } else { reduced <- state_T } - + ## form the PHREEQC input script for the current work package inplist <- SplitMultiKin( data = reduced, procs = 1, base = base, first = first, ann = ann, prop = prop, minerals = immobile, kin = kin, dt = dt ) - + ## if (local_rank==1 & iter==1) ## RPhreeWriteInp("FirstInp", inplist) - + tmpC <- RunPQC(inplist, procs = 1, second = TRUE) - + ## recompose after the reduction if (setup$reduce) { state_C <- RecomposeState(tmpC, reduced) } else { state_C <- tmpC } - + ## the next line is needed since we don't need all columns of ## PHREEQC output return(state_C[, prop]) @@ -147,40 +150,40 @@ slave_chemistry <- function(setup, data) { ## This function, called by master master_chemistry <- function(setup, data) { state_T <- setup$state_T - + msgm(" chemistry iteration", setup$iter) - + ## treat special H+/pH, e-/pe cases state_T <- RedModRphree::Act2pH(state_T) - + ## reduction of the problem if (setup$reduce) { reduced <- ReduceStateOmit(state_T, omit = setup$ann) } else { reduced <- state_T } - + ## inject data from workers res_C <- data - + rownames(res_C) <- NULL - + ## print(res_C) - + if (nrow(res_C) > nrow(reduced)) { res_C <- res_C[seq(2, nrow(res_C), by = 2), ] } - + ## recompose after the reduction if (setup$reduce) { state_C <- RecomposeState(res_C, reduced) } else { state_C <- res_C } - + setup$state_C <- state_C setup$reduced <- reduced - + return(setup) } @@ -188,7 +191,7 @@ master_chemistry <- function(setup, data) { ## Adapted version for "reduction" ReduceStateOmit <- function(data, omit = NULL, sign = 6) { require(mgcv) - + rem <- colnames(data) if (is.list(omit)) { indomi <- match(names(omit), colnames(data)) @@ -196,13 +199,13 @@ ReduceStateOmit <- function(data, omit = NULL, sign = 6) { } else { datao <- data } - + datao <- signif(datao, sign) red <- mgcv::uniquecombs(datao) inds <- attr(red, "index") now <- ncol(red) - - + + ## reattach the omitted column(s) ## FIXME: control if more than one ann is present if (is.list(omit)) { @@ -224,11 +227,11 @@ ReduceStateOmit <- function(data, omit = NULL, sign = 6) { ## Attach the name of the calling function to the message displayed on ## R's stdout msgm <- function(...) { - if (local_rank == 0) { - fname <- as.list(sys.call(-1))[[1]] - prefix <- paste0("R: ", fname, " ::") - cat(paste(prefix, ..., "\n")) - } + # if (local_rank == 0) { + fname <- as.list(sys.call(-1))[[1]] + prefix <- paste0("R: ", fname, " ::") + cat(paste(prefix, ..., "\n")) + # } invisible() } @@ -236,18 +239,17 @@ msgm <- function(...) { ## Function called by master R process to store on disk all relevant ## parameters for the simulation StoreSetup <- function(setup) { - to_store <- vector(mode = "list", length = 4) ## names(to_store) <- c("Sim", "Flow", "Transport", "Chemistry", "DHT") names(to_store) <- c("Sim", "Transport", "DHT", "Cmdline") - + ## read the setup R file, which is sourced in kin.cpp tmpbuff <- file(filesim, "r") setupfile <- readLines(tmpbuff) close.connection(tmpbuff) - + to_store$Sim <- setupfile - + ## to_store$Flow <- list( ## snapshots = setup$snapshots, ## gridfile = setup$gridfile, @@ -282,22 +284,22 @@ StoreSetup <- function(setup) { to_store$DHT <- FALSE } - if (dht_enabled) { - to_store$DHT <- list( - enabled = dht_enabled, - log = dht_log - #signif = dht_final_signif, - #proptype = dht_final_proptype - ) - } else { - to_store$DHT <- FALSE - } + if (dht_enabled) { + to_store$DHT <- list( + enabled = dht_enabled, + log = dht_log + # signif = dht_final_signif, + # proptype = dht_final_proptype + ) + } else { + to_store$DHT <- FALSE + } - saveRDS(to_store, file = paste0(fileout, "/setup.rds")) - msgm("initialization stored in ", paste0(fileout, "/setup.rds")) + saveRDS(to_store, file = paste0(fileout, "/setup.rds")) + msgm("initialization stored in ", paste0(fileout, "/setup.rds")) } GetWorkPackageSizesVector <- function(n_packages, package_size, len) { - ids <- rep(1:n_packages, times=package_size, each = 1)[1:len] + ids <- rep(1:n_packages, times = package_size, each = 1)[1:len] return(as.integer(table(ids))) } diff --git a/bench/barite/het/runtime.R b/bench/barite/het/runtime.R new file mode 100644 index 000000000..4dea41fdf --- /dev/null +++ b/bench/barite/het/runtime.R @@ -0,0 +1,4 @@ +list( + timesteps = c(1), + store_result = TRUE +) \ No newline at end of file diff --git a/ext/tug b/ext/tug index 25855da6b..8c0687a6c 160000 --- a/ext/tug +++ b/ext/tug @@ -1 +1 @@ -Subproject commit 25855da6b2930559b542bbadb16299932332d6a3 +Subproject commit 8c0687a6cd4a10a79c7a554083a35eda11cc55f0 diff --git a/src/Base/Grid.cpp b/src/Base/Grid.cpp deleted file mode 100644 index e51b114ba..000000000 --- a/src/Base/Grid.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* -** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of -** Potsdam) -** -** Copyright (C) 2018-2023 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 "Grid.hpp" -#include "SimParams.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace poet; -using namespace Rcpp; - -enum { INIT_SCRATCH, INIT_PHREEQC, INIT_RDS }; - -static inline int8_t get_type_id(std::string type) { - if (type == "scratch") { - return INIT_SCRATCH; - } - if (type == "phreeqc") { - return INIT_PHREEQC; - } - if (type == "rds") { - return INIT_RDS; - } - return -1; -} - -void poet::Grid::InitModuleFromParams(const poet::GridParams &grid_args) { - assert(grid_args.n_cells.size() == grid_args.s_cells.size()); - - this->SetGridDimension(grid_args.n_cells.size()); - - std::copy(grid_args.n_cells.begin(), grid_args.n_cells.end(), - this->n_cells.begin()); - std::copy(grid_args.s_cells.begin(), grid_args.s_cells.end(), - this->grid_size.begin()); - - auto init_type = get_type_id(grid_args.type); - assert(init_type >= 0); - - switch (init_type) { - case INIT_SCRATCH: - this->SetPropNames(grid_args.props); - this->InitGridFromScratch(grid_args.init_df); - break; - case INIT_RDS: - this->SetPropNames(grid_args.props); - this->InitGridFromRDS(); - break; - case INIT_PHREEQC: - this->InitGridFromPhreeqc(); - } -} - -void poet::Grid::SetGridDimension(uint8_t dim) { - assert(dim < MAX_DIM + 1); - - this->dim = dim; -} - -void poet::Grid::SetGridCellCount(uint32_t n_x, uint32_t n_y, uint32_t n_z) { - assert(this->dim < MAX_DIM + 1); - - this->n_cells[0] = n_x; - this->n_cells[1] = n_y; - // this->n_cells[2] = n_z; -} - -void poet::Grid::SetGridSize(double s_x, double s_y, double s_z) { - assert(this->dim < MAX_DIM + 1); - - this->grid_size[0] = s_x; - this->grid_size[1] = s_y; - // this->grid_size[2] = s_z; -} - -void poet::Grid::SetPropNames(const std::vector &prop_names) { - this->prop_names = prop_names; -} - -void poet::Grid::PushbackModuleFlow(const std::string &input, - const std::string &output) { - FlowInputOutputInfo element = {input, output}; - this->flow_vec.push_back(element); -} - -void poet::Grid::PreModuleFieldCopy(uint32_t tick) { - FlowInputOutputInfo curr_element = this->flow_vec.at(tick); - - const std::string input_module_name = curr_element.input_field; - StateMemory *out_state = this->GetStatePointer(curr_element.output_field); - - std::vector &mod_props = out_state->props; - std::vector &mod_field = out_state->mem; - - // copy output of another module as input for another module - for (uint32_t i = 0; i < mod_props.size(); i++) { - try { - std::vector t_prop_vec = - this->GetSpeciesByName(mod_props[i], input_module_name); - - std::copy(t_prop_vec.begin(), t_prop_vec.end(), - mod_field.begin() + (i * this->GetTotalCellCount())); - } catch (...) { - // TODO: there might be something wrong ... - continue; - } - } -} - -Grid::Grid() { - this->n_cells.fill(0); - this->grid_size.fill(0); -}; - -Grid::~Grid() { - for (auto &[key, val] : this->state_register) { - delete val; - } -} - -void poet::Grid::InitGridFromScratch(const Rcpp::DataFrame &init_cell) { - const uint32_t vec_size = this->GetTotalCellCount(); - - StateMemory *curr_state = - this->RegisterState(poet::GRID_MODULE_NAME, this->prop_names); - curr_state->props = this->prop_names; - - std::vector &curr_field = curr_state->mem; - - for (auto const &prop : this->prop_names) { - // size of the vector shall be 1 - double prop_val = ((Rcpp::NumericVector)init_cell[prop.c_str()])[0]; - std::vector prop_vec(vec_size, prop_val); - - curr_field.insert(curr_field.end(), prop_vec.begin(), prop_vec.end()); - } - - this->grid_init = curr_state; -} -void poet::Grid::InitGridFromRDS() { - // TODO -} -void poet::Grid::InitGridFromPhreeqc() { - // TODO -} - -poet::StateMemory *Grid::RegisterState(std::string module_name, - std::vector props) { - poet::StateMemory *mem = new poet::StateMemory; - - mem->props = props; - - const auto [it, success] = this->state_register.insert({module_name, mem}); - - if (!success) { - delete mem; - throw std::bad_alloc(); - } - - return mem; -} - -poet::StateMemory *Grid::GetStatePointer(std::string module_name) { - const auto it = this->state_register.find(module_name); - - if (it == this->state_register.end()) { - throw std::range_error( - std::string("Requested module " + module_name + " was not found")); - } - - return it->second; -} - -auto Grid::GetGridSize(uint8_t direction) const -> uint32_t { - return this->grid_size.at(direction); -} - -auto Grid::GetGridDimension() const -> uint8_t { return this->dim; } - -auto Grid::GetTotalCellCount() const -> uint32_t { - uint32_t sum = 1; - for (auto const &dim : this->n_cells) { - sum *= (dim != 0 ? dim : 1); - } - - return sum; -} - -auto Grid::GetGridCellsCount(uint8_t direction) const -> uint32_t { - return this->n_cells.at(direction); -} - -auto poet::Grid::GetInitialGrid() const -> StateMemory * { - return this->grid_init; -} - -auto Grid::GetSpeciesCount() const -> uint32_t { - return this->prop_names.size(); -} - -auto Grid::GetPropNames() const -> std::vector { - return this->prop_names; -} - -auto poet::Grid::GetSpeciesByName(std::string name, - std::string module_name) const - -> std::vector { - - auto const it = this->state_register.find(module_name); - - if (it == this->state_register.end()) { - throw std::range_error( - std::string("Requested module " + module_name + " was not found")); - } - - poet::StateMemory const *module_memory = it->second; - - auto const &prop_vector = module_memory->props; - auto const find_res = std::find(prop_vector.begin(), prop_vector.end(), name); - if (find_res == prop_vector.end()) { - throw std::range_error(std::string( - "Species " + name + " was not found for module " + module_name)); - } - uint32_t prop_index = find_res - prop_vector.begin(); - - uint32_t begin_vec = prop_index * this->GetTotalCellCount(), - end_vec = ((prop_index + 1) * this->GetTotalCellCount()); - - return std::vector(module_memory->mem.begin() + begin_vec, - module_memory->mem.begin() + end_vec); -} - -// HACK: Helper function -void poet::Grid::WriteFieldsToR(RInside &R) { - - for (auto const &elem : this->state_register) { - std::string field_name = elem.first; - StateMemory *field = elem.second; - - const uint32_t n_cells_per_prop = field->mem.size() / field->props.size(); - - R["TMP"] = Rcpp::wrap(field->mem); - R["TMP_PROPS"] = Rcpp::wrap(field->props); - R.parseEval(std::string( - "mysetup$" + field_name + " <- setNames(data.frame(matrix(TMP, nrow=" + - std::to_string(n_cells_per_prop) + ")), TMP_PROPS)")); - } -} diff --git a/src/Base/Grid.hpp b/src/Base/Grid.hpp deleted file mode 100644 index deec5c04a..000000000 --- a/src/Base/Grid.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of -** Potsdam) -** -** Copyright (C) 2018-2023 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. -*/ - -#ifndef GRID_H -#define GRID_H - -#include "SimParams.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_DIM 2 - -namespace poet { - -enum { GRID_X_DIR, GRID_Y_DIR, GRID_Z_DIR }; - -using StateMemory = struct s_StateMemory { - std::vector mem; - std::vector props; -}; - -using FlowInputOutputInfo = struct inOut_info { - std::string input_field; - std::string output_field; -}; - -constexpr const char *GRID_MODULE_NAME = "grid_init"; - -/** - * @brief Class describing the grid - * - * Providing methods to shuffle and unshuffle grid (for the master) as also to - * import and export a work package (for worker). - * - * @todo find better abstraction - * - */ -class Grid { - -public: - Grid(); - - ~Grid(); - - void InitModuleFromParams(const poet::GridParams &grid_args); - - void SetGridDimension(uint8_t dim); - void SetGridCellCount(uint32_t n_x, uint32_t n_y = 0, uint32_t n_z = 0); - void SetGridSize(double s_x, double s_y = 0., double s_z = 0.); - void SetPropNames(const std::vector &prop_names); - - void PushbackModuleFlow(const std::string &input, const std::string &output); - void PreModuleFieldCopy(uint32_t tick); - - void InitGridFromScratch(const Rcpp::DataFrame &init_cell); - void InitGridFromRDS(); - void InitGridFromPhreeqc(); - - auto GetGridDimension() const -> uint8_t; - auto GetTotalCellCount() const -> uint32_t; - auto GetGridCellsCount(uint8_t direction) const -> uint32_t; - auto GetGridSize(uint8_t direction) const -> uint32_t; - - auto RegisterState(std::string module_name, std::vector props) - -> StateMemory *; - auto GetStatePointer(std::string module_name) -> StateMemory *; - - auto GetInitialGrid() const -> StateMemory *; - - auto GetSpeciesCount() const -> uint32_t; - auto GetPropNames() const -> std::vector; - - auto GetSpeciesByName(std::string name, - std::string module_name = poet::GRID_MODULE_NAME) const - -> std::vector; - - void WriteFieldsToR(RInside &R); - -private: - std::vector flow_vec; - - std::uint8_t dim = 0; - std::array grid_size; - std::array n_cells; - - std::map state_register; - StateMemory *grid_init = std::nullptr_t(); - - std::vector prop_names; -}; -} // namespace poet -#endif // GRID_H diff --git a/src/Base/SimParams.cpp b/src/Base/SimParams.cpp index f711e796a..3ae76dd65 100644 --- a/src/Base/SimParams.cpp +++ b/src/Base/SimParams.cpp @@ -1,10 +1,11 @@ -// Time-stamp: "Last modified 2023-08-15 12:12:36 delucia" - /* ** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of ** Potsdam) ** -** Copyright (C) 2018-2023 Marco De Lucia, Max Luebke (GFZ Potsdam) +** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) +** +** Copyright (C) 2018-2022 Marco De Lucia (GFZ Potsdam), Max Luebke (University +** of 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 @@ -22,104 +23,33 @@ #include "SimParams.hpp" -#include "../Chemistry/enums.hpp" +#include "Base/Macros.hpp" -#include -#include #include -#include -#include -#include -#include #include -#include #include -#include #include +#include "Base/RInsidePOET.hpp" +#include "argh.hpp" // Argument handler https://github.com/adishavit/argh + using namespace poet; -using namespace std; -using namespace Rcpp; -poet::GridParams::s_GridParams(RInside &R) { - auto tmp_n_cells = - Rcpp::as>(R.parseEval("mysetup$grid$n_cells")); - assert(tmp_n_cells.size() < 3); +RuntimeParameters::RuntimeParameters(RInsidePOET &R, char *argv[], + int world_rank_) + : world_rank(world_rank_) { - this->dim = tmp_n_cells.size(); - - std::copy(tmp_n_cells.begin(), tmp_n_cells.end(), this->n_cells.begin()); - - auto tmp_s_cells = - Rcpp::as>(R.parseEval("mysetup$grid$s_cells")); - - assert(tmp_s_cells.size() == this->dim); - - std::copy(tmp_s_cells.begin(), tmp_s_cells.end(), this->s_cells.begin()); - - this->total_n = - (dim == 1 ? this->n_cells[0] : this->n_cells[0] * this->n_cells[1]); - - this->type = Rcpp::as(R.parseEval("mysetup$grid$type")); -} - -poet::DiffusionParams::s_DiffusionParams(RInside &R) { - this->initial_t = - Rcpp::as(R.parseEval("mysetup$diffusion$init")); - this->alpha = - Rcpp::as(R.parseEval("mysetup$diffusion$alpha")); - if (Rcpp::as( - R.parseEval("'vecinj_inner' %in% names(mysetup$diffusion)"))) { - this->vecinj_inner = - Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_inner")); - } - this->vecinj = - Rcpp::as(R.parseEval("mysetup$diffusion$vecinj")); - this->vecinj_index = - Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_index")); -} - -void poet::ChemistryParams::initFromR(RInsidePOET &R) { - this->database_path = - Rcpp::as(R.parseEval("mysetup$chemistry$database")); - this->input_script = - Rcpp::as(R.parseEval("mysetup$chemistry$input_script")); - - if (R.checkIfExists("dht_species", "mysetup$chemistry")) { - this->dht_signifs = Rcpp::as>( - R.parseEval(("mysetup$chemistry$dht_species"))); - } - - if (R.checkIfExists("pht_species", "mysetup$chemistry")) { - this->pht_signifs = Rcpp::as>( - R.parseEval(("mysetup$chemistry$pht_species"))); - } - this->hooks.dht_fill = - RHookFunction(R, "mysetup$chemistry$hooks$dht_fill"); - this->hooks.dht_fuzz = - RHookFunction>(R, "mysetup$chemistry$hooks$dht_fuzz"); - this->hooks.interp_pre = RHookFunction>( - R, "mysetup$chemistry$hooks$interp_pre_func"); - this->hooks.interp_post = - RHookFunction(R, "mysetup$chemistry$hooks$interp_post_func"); -} - -SimParams::SimParams(int world_rank_, int world_size_) { - this->simparams.world_rank = world_rank_; - this->simparams.world_size = world_size_; -} - -int SimParams::parseFromCmdl(char *argv[], RInsidePOET &R) { // initialize argh object argh::parser cmdl(argv); // if user asked for help if (cmdl[{"help", "h"}]) { - if (simparams.world_rank == 0) { + if (this->world_rank == 0) { MSG("Todo"); MSG("See README.md for further information."); } + return poet::PARSER_HELP; } // if positional arguments are missing @@ -242,11 +172,74 @@ int SimParams::parseFromCmdl(char *argv[], RInsidePOET &R) { this->chem_params.initFromR(R); return poet::PARSER_OK; +}; + +// poet::GridParams::s_GridParams(RInside &R) { +// auto tmp_n_cells = +// Rcpp::as>(R.parseEval("mysetup$grid$n_cells")); +// assert(tmp_n_cells.size() < 3); + +// this->dim = tmp_n_cells.size(); + +// std::copy(tmp_n_cells.begin(), tmp_n_cells.end(), this->n_cells.begin()); + +// auto tmp_s_cells = +// Rcpp::as>(R.parseEval("mysetup$grid$s_cells")); + +// assert(tmp_s_cells.size() == this->dim); + +// std::copy(tmp_s_cells.begin(), tmp_s_cells.end(), this->s_cells.begin()); + +// this->total_n = +// (dim == 1 ? this->n_cells[0] : this->n_cells[0] * this->n_cells[1]); + +// this->type = Rcpp::as(R.parseEval("mysetup$grid$type")); +// } + +// poet::DiffusionParams::s_DiffusionParams(RInside &R) { +// this->initial_t = +// Rcpp::as(R.parseEval("mysetup$diffusion$init")); +// this->alpha = +// Rcpp::as(R.parseEval("mysetup$diffusion$alpha")); +// if (Rcpp::as( +// R.parseEval("'vecinj_inner' %in% names(mysetup$diffusion)"))) { +// this->vecinj_inner = +// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_inner")); +// } +// this->vecinj = +// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj")); +// this->vecinj_index = +// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_index")); +// } + +void poet::ChemistryParams::initFromR(RInsidePOET &R) { + // this->database_path = + // Rcpp::as(R.parseEval("mysetup$chemistry$database")); + // this->input_script = + // Rcpp::as(R.parseEval("mysetup$chemistry$input_script")); + + if (R.checkIfExists("dht_species", "mysetup$chemistry")) { + this->dht_signifs = Rcpp::as>( + R.parseEval(("mysetup$chemistry$dht_species"))); + } + + if (R.checkIfExists("pht_species", "mysetup$chemistry")) { + this->pht_signifs = Rcpp::as>( + R.parseEval(("mysetup$chemistry$pht_species"))); + } + this->hooks.dht_fill = + RHookFunction(R, "mysetup$chemistry$hooks$dht_fill"); + this->hooks.dht_fuzz = + RHookFunction>(R, "mysetup$chemistry$hooks$dht_fuzz"); + this->hooks.interp_pre = RHookFunction>( + R, "mysetup$chemistry$hooks$interp_pre_func"); + this->hooks.interp_post = + RHookFunction(R, "mysetup$chemistry$hooks$interp_post_func"); } -void SimParams::initVectorParams(RInside &R) {} +void RuntimeParameters::initVectorParams(RInside &R) {} -std::list SimParams::validateOptions(argh::parser cmdl) { +std::list RuntimeParameters::validateOptions(argh::parser cmdl) { /* store all unknown parameters here */ std::list retList; diff --git a/src/Base/SimParams.hpp b/src/Base/SimParams.hpp index 523b5b105..b4e20f262 100644 --- a/src/Base/SimParams.hpp +++ b/src/Base/SimParams.hpp @@ -4,6 +4,9 @@ ** ** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) ** +** Copyright (C) 2018-2022 Marco De Lucia (GFZ Potsdam), Max Luebke (University +** of 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 @@ -18,20 +21,13 @@ ** Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef PARSER_H -#define PARSER_H +#pragma once -#include "../DataStructures/DataStructures.hpp" -#include "Macros.hpp" +#include "DataStructures/NamedVector.hpp" #include "RInsidePOET.hpp" -#include "argh.hpp" // Argument handler https://github.com/adishavit/argh - #include -#include #include -#include -#include #include #include @@ -51,7 +47,8 @@ enum { PARSER_OK, PARSER_ERROR, PARSER_HELP }; * @brief Defining all simulation parameters * */ -typedef struct { +struct RuntimeParameters { + /** Count of processes in MPI_COMM_WORLD */ int world_size; /** rank of proces in MPI_COMM_WORLD */ @@ -79,40 +76,40 @@ typedef struct { bool print_progressbar; bool interp_enabled; -} t_simparams; - -using GridParams = struct s_GridParams { - std::array n_cells; - std::array s_cells; - std::uint8_t dim; - std::uint32_t total_n; - - std::string type; - - Rcpp::DataFrame init_df; - std::string input_script; - std::string database_path; - - std::vector props; - - s_GridParams(RInside &R); }; -using DiffusionParams = struct s_DiffusionParams { - Rcpp::DataFrame initial_t; +// using GridParams = struct s_GridParams { +// std::array n_cells; +// std::array s_cells; +// std::uint8_t dim; +// std::uint32_t total_n; - Rcpp::NumericVector alpha; - Rcpp::List vecinj_inner; +// std::string type; - Rcpp::DataFrame vecinj; - Rcpp::DataFrame vecinj_index; +// Rcpp::DataFrame init_df; +// std::string input_script; +// std::string database_path; - s_DiffusionParams(RInside &R); -}; +// std::vector props; + +// s_GridParams(RInside &R); +// }; + +// using DiffusionParams = struct s_DiffusionParams { +// Rcpp::DataFrame initial_t; + +// Rcpp::NumericVector alpha; +// Rcpp::List vecinj_inner; + +// Rcpp::DataFrame vecinj; +// Rcpp::DataFrame vecinj_index; + +// s_DiffusionParams(RInside &R); +// }; struct ChemistryParams { - std::string database_path; - std::string input_script; + // std::string database_path; + // std::string input_script; bool use_dht; std::uint64_t dht_size; @@ -137,6 +134,7 @@ struct ChemistryParams { void initFromR(RInsidePOET &R); }; +} // namespace poet /** * @brief Reads information from program arguments and R runtime * @@ -147,129 +145,136 @@ struct ChemistryParams { * Stores and distribute current simulation parameters at any time. * */ -class SimParams { -public: - /** - * @brief Construct a new SimParams object - * - * With all given parameters a new instance of this class will be created. - * - * @param world_rank Rank of process inside MPI_COMM_WORLD - * @param world_size Size of communicator MPI_COMM_WORLD - */ - SimParams(int world_rank, int world_size); +// class SimParams { +// public: +// /** +// * @brief Construct a new SimParams object +// * +// * With all given parameters a new instance of this class will be created. +// * +// * @param world_rank Rank of process inside MPI_COMM_WORLD +// * @param world_size Size of communicator MPI_COMM_WORLD +// */ +// SimParams(int world_rank); - /** - * @brief Parse program arguments - * - * This is done by the argh.h library. - * - * First, the function will check if there is a flag 'help' or 'h'. If this is - * the case a help message is printed and the function will return with - * PARSER_HELP. - * - * Second, if there are not 2 positional arguments an error will be printed to - * stderr and the function returns with PARSER_ERROR. - * - * Then all given program parameters and flags will be read and checked, if - * there are known by validateOptions. A list of all unknown options might be - * returned, printed out and the function will return with PARSER_ERROR. - * Oterhwise the function continuos. - * - * Now all program arguments will be stored inside t_simparams struct, printed - * out and the function returns with PARSER_OK. - * - * Also, all parsed agruments are distributed to the R runtime. - * - * @param argv Argument value of the program - * @param R Instantiated R runtime - * @return int Returns with 0 if no error occured, otherwise value less than 0 - * is returned. - */ - int parseFromCmdl(char *argv[], RInsidePOET &R); +// /** +// * @brief Parse program arguments +// * +// * This is done by the argh.h library. +// * +// * First, the function will check if there is a flag 'help' or 'h'. If this +// is +// * the case a help message is printed and the function will return with +// * PARSER_HELP. +// * +// * Second, if there are not 2 positional arguments an error will be printed +// to +// * stderr and the function returns with PARSER_ERROR. +// * +// * Then all given program parameters and flags will be read and checked, if +// * there are known by validateOptions. A list of all unknown options might +// be +// * returned, printed out and the function will return with PARSER_ERROR. +// * Oterhwise the function continuos. +// * +// * Now all program arguments will be stored inside t_simparams struct, +// printed +// * out and the function returns with PARSER_OK. +// * +// * Also, all parsed agruments are distributed to the R runtime. +// * +// * @param argv Argument value of the program +// * @param R Instantiated R runtime +// * @return int Returns with 0 if no error occured, otherwise value less +// than 0 +// * is returned. +// */ +// int parseFromCmdl(char *argv[], RInsidePOET &R); - /** - * @brief Init std::vector values - * - * This will initialize dht_signif_vector and dht_prop_type_vector internally - * depending on whether vectors are defined by R-Simulation file or not. - * 'init_chemistry' must be run beforehand. - * - * @param R R runtime - */ - void initVectorParams(RInside &R); +// /** +// * @brief Init std::vector values +// * +// * This will initialize dht_signif_vector and dht_prop_type_vector +// internally +// * depending on whether vectors are defined by R-Simulation file or not. +// * 'init_chemistry' must be run beforehand. +// * +// * @param R R runtime +// */ +// void initVectorParams(RInside &R); - /** - * @brief Get the numerical params struct - * - * Returns a struct which contains all numerical or boolean simulation - * parameters. - * - * @return t_simparams Parameter struct - */ - auto getNumParams() const { return this->simparams; }; +// /** +// * @brief Get the numerical params struct +// * +// * Returns a struct which contains all numerical or boolean simulation +// * parameters. +// * +// * @return t_simparams Parameter struct +// */ +// auto getNumParams() const { return this->simparams; }; - /** - * @brief Get the DHT_Signif_Vector - * - * Returns a vector indicating which significant values are used for each - * variable of a grid cell. - * - * @return std::vector Vector of integers containing information about - * significant digits - */ - auto getDHTSignifVector() const { return this->dht_signif_vector; }; +// /** +// * @brief Get the DHT_Signif_Vector +// * +// * Returns a vector indicating which significant values are used for each +// * variable of a grid cell. +// * +// * @return std::vector Vector of integers containing information about +// * significant digits +// */ +// auto getDHTSignifVector() const { return this->dht_signif_vector; }; - auto getPHTSignifVector() const { return this->pht_signif_vector; }; +// auto getPHTSignifVector() const { return this->pht_signif_vector; }; - auto getPHTBucketSize() const { return this->pht_bucket_size; }; - auto getPHTMinEntriesNeeded() const { return this->pht_min_entries_needed; }; +// auto getPHTBucketSize() const { return this->pht_bucket_size; }; +// auto getPHTMinEntriesNeeded() const { return this->pht_min_entries_needed; +// }; - /** - * @brief Get the filesim name - * - * Returns a string containing the absolute path to a R file defining the - * simulation. - * - * @return std::string Absolute path to R file - */ - auto getFilesim() const { return this->filesim; }; +// /** +// * @brief Get the filesim name +// * +// * Returns a string containing the absolute path to a R file defining the +// * simulation. +// * +// * @return std::string Absolute path to R file +// */ +// auto getFilesim() const { return this->filesim; }; - /** - * @brief Get the output directory - * - * Returns the name of an absolute path where all output files should be - * stored. - * - * @return std::string Absolute path to output path - */ - auto getOutDir() const { return this->out_dir; }; +// /** +// * @brief Get the output directory +// * +// * Returns the name of an absolute path where all output files should be +// * stored. +// * +// * @return std::string Absolute path to output path +// */ +// auto getOutDir() const { return this->out_dir; }; - const auto &getChemParams() const { return chem_params; } +// const auto &getChemParams() const { return chem_params; } -private: - std::list validateOptions(argh::parser cmdl); +// private: +// std::list validateOptions(argh::parser cmdl); - const std::set flaglist{"ignore-result", "dht", "P", "progress", - "interp"}; - const std::set paramlist{ - "work-package-size", "dht-strategy", - "dht-size", "dht-snaps", - "dht-file", "interp-size", - "interp-min", "interp-bucket-entries"}; +// const std::set flaglist{"ignore-result", "dht", "P", +// "progress", +// "interp"}; +// const std::set paramlist{ +// "work-package-size", "dht-strategy", +// "dht-size", "dht-snaps", +// "dht-file", "interp-size", +// "interp-min", "interp-bucket-entries"}; - t_simparams simparams; +// t_simparams simparams; - std::vector dht_signif_vector; - std::vector pht_signif_vector; +// std::vector dht_signif_vector; +// std::vector pht_signif_vector; - uint32_t pht_bucket_size; - uint32_t pht_min_entries_needed; +// uint32_t pht_bucket_size; +// uint32_t pht_min_entries_needed; - std::string filesim; - std::string out_dir; +// std::string filesim; +// std::string out_dir; - ChemistryParams chem_params; -}; -} // namespace poet -#endif // PARSER_H +// ChemistryParams chem_params; +// }; +// } // namespace poet diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f593d6b63..2e4430848 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,13 @@ -add_library(POETLib OBJECT) +add_library(POETLib) -target_sources( - POETLib +target_sources(POETLib PRIVATE Init/InitialList.cpp Init/GridInit.cpp Init/DiffusionInit.cpp Init/ChemistryInit.cpp - PRIVATE DataStructures/Field.cpp + Transport/DiffusionModule.cpp ) target_include_directories(POETLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") @@ -16,7 +15,7 @@ target_link_libraries( POETLib PUBLIC RRuntime PUBLIC IPhreeqcPOET - PRIVATE tug + PUBLIC tug ) # add_library(poetlib @@ -43,7 +42,7 @@ target_link_libraries( # tug # ) -# target_compile_definitions(poetlib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) +target_compile_definitions(POETLib PUBLIC STRICT_R_HEADERS OMPI_SKIP_MPICXX) # mark_as_advanced(PHREEQCRM_BUILD_MPI PHREEQCRM_DISABLE_OPENMP) # set(PHREEQCRM_DISABLE_OPENMP ON CACHE BOOL "" FORCE) @@ -65,9 +64,9 @@ file(READ "${PROJECT_SOURCE_DIR}/R_lib/init_r_lib.R" R_INIT_LIB) configure_file(poet.hpp.in poet.hpp @ONLY) -# add_executable(poet poet.cpp) -# target_link_libraries(poet PRIVATE poetlib MPI::MPI_C RRuntime) -# target_include_directories(poet PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") +add_executable(poet poet.cpp) +target_link_libraries(poet PRIVATE POETLib MPI::MPI_C RRuntime) +target_include_directories(poet PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") add_executable(poet_init initializer.cpp) target_link_libraries(poet_init PRIVATE POETLib RRuntime) diff --git a/src/Init/CMakeLists.txt b/src/Init/CMakeLists.txt deleted file mode 100644 index 47ce9eb3e..000000000 --- a/src/Init/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -target_sources(POETLib PRIVATE - InitialList.cpp - GridInit.cpp - DiffusionInit.cpp - ChemistryInit.cpp -) \ No newline at end of file diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index 2d83d1091..c85c9c8d7 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -5,6 +5,7 @@ #include #include +#include "DataStructures/Field.hpp" #include "InitialList.hpp" #include @@ -14,6 +15,7 @@ #include #include #include +#include #include namespace poet { @@ -175,6 +177,42 @@ void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { // R.parseEval("print(alpha_y)"); } +InitialList::DiffusionInit::BoundaryMap +RcppListToBoundaryMap(const std::vector &trans_names, + const Rcpp::List &bound_list, uint32_t n_cols, + uint32_t n_rows) { + InitialList::DiffusionInit::BoundaryMap map; + + for (const auto &name : trans_names) { + const Rcpp::List &conc_list = bound_list[name]; + + tug::Boundary bc(n_rows, n_cols); + + for (const auto &[tug_index, r_init_name] : tug_side_mapping) { + const Rcpp::List &side_list = conc_list[tug_index]; + + const Rcpp::NumericVector &type = side_list["type"]; + const Rcpp::NumericVector &value = side_list["value"]; + + if (type.size() != value.size()) { + throw std::runtime_error( + "Boundary type and value are not the same length"); + } + + for (std::size_t i = 0; i < type.size(); i++) { + if (type[i] == tug::BC_TYPE_CONSTANT) { + bc.setBoundaryElementConstant(static_cast(tug_index), i, + value[i]); + } + } + } + + map[name] = bc.serialize(); + } + + return map; +} + InitialList::DiffusionInit InitialList::getDiffusionInit() const { DiffusionInit diff_init; @@ -189,8 +227,8 @@ InitialList::DiffusionInit InitialList::getDiffusionInit() const { diff_init.constant_cells = this->constant_cells; diff_init.transport_names = this->transport_names; - diff_init.initial_grid = Field(this->initial_grid); - diff_init.boundaries = Field(this->boundaries); + diff_init.boundaries = RcppListToBoundaryMap( + this->transport_names, this->boundaries, this->n_cols, this->n_rows); diff_init.alpha_x = Field(this->alpha_x); diff_init.alpha_y = Field(this->alpha_y); diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 0931c34f3..63e3e2742 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -38,10 +38,10 @@ void InitialList::importList(const Rcpp::List &setup) { setup[static_cast(ExportList::DIFFU_TRANSPORT)]); this->boundaries = Rcpp::List(setup[static_cast(ExportList::DIFFU_BOUNDARIES)]); - this->alpha_x = Rcpp::as>( - setup[static_cast(ExportList::DIFFU_ALPHA_X)]); - this->alpha_y = Rcpp::as>( - setup[static_cast(ExportList::DIFFU_ALPHA_Y)]); + this->alpha_x = + Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_X)]); + this->alpha_y = + Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_Y)]); this->database = Rcpp::as(setup[static_cast(ExportList::CHEM_DATABASE)]); diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 0f3b631b1..86c4ded77 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -8,7 +10,9 @@ #include #include +#include #include +#include #include #include @@ -26,6 +30,8 @@ public: void importList(const Rcpp::List &setup); Rcpp::List exportList(); + Field getInitialGrid() const { return Field(this->initial_grid); } + private: RInside &R; @@ -93,6 +99,9 @@ private: public: struct DiffusionInit { + using BoundaryMap = + std::map>>; + uint8_t dim; std::uint32_t n_cols; std::uint32_t n_rows; @@ -104,8 +113,8 @@ public: std::vector transport_names; - Field initial_grid; - Field boundaries; + BoundaryMap boundaries; + Field alpha_x; Field alpha_y; }; diff --git a/src/Transport/DiffusionModule.cpp b/src/Transport/DiffusionModule.cpp index abbecce95..17f761b57 100644 --- a/src/Transport/DiffusionModule.cpp +++ b/src/Transport/DiffusionModule.cpp @@ -4,6 +4,9 @@ ** ** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) ** +** Copyright (C) 2023-2024 Marco De Lucia (GFZ Potsdam), Max Luebke (University +** of 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 @@ -19,174 +22,101 @@ */ #include "DiffusionModule.hpp" -#include "../Base/Macros.hpp" -#include -#include +#include "Base/Macros.hpp" +#include "Init/InitialList.hpp" -#include -#include -#include +#include +#include +#include +#include -#include -#include -#include +#include "tug/Boundary.hpp" +#include "tug/Grid.hpp" +#include "tug/Simulation.hpp" + +#include +#include #include #include using namespace poet; -static constexpr double ZERO_MULTIPLICATOR = 10E-14; +static inline std::vector +MatrixToVec(const Eigen::MatrixX &mat) { + std::vector vec(mat.rows() * mat.cols()); -constexpr std::array borders = { - tug::bc::BC_SIDE_LEFT, tug::bc::BC_SIDE_RIGHT, tug::bc::BC_SIDE_TOP, - tug::bc::BC_SIDE_BOTTOM}; - -inline const char *convert_bc_to_config_file(uint8_t in) { - switch (in) { - case tug::bc::BC_SIDE_TOP: - return "N"; - case tug::bc::BC_SIDE_RIGHT: - return "E"; - case tug::bc::BC_SIDE_BOTTOM: - return "S"; - case tug::bc::BC_SIDE_LEFT: - return "W"; - } - return ""; -} - -DiffusionModule::DiffusionModule(const poet::DiffusionParams &diffu_args, - const poet::GridParams &grid_params) - : n_cells_per_prop(grid_params.total_n) { - this->diff_input.setGridCellN(grid_params.n_cells[0], grid_params.n_cells[1]); - this->diff_input.setDomainSize(grid_params.s_cells[0], - grid_params.s_cells[1]); - - this->dim = grid_params.dim; - - this->initialize(diffu_args, grid_params.total_n); -} - -void DiffusionModule::initialize(const poet::DiffusionParams &args, - std::uint32_t n_grid_cells) { - // const poet::DiffusionParams args(this->R); - - // name of props - // - this->prop_names = Rcpp::as>(args.initial_t.names()); - this->prop_count = this->prop_names.size(); - - // initialize field and alphas - this->alpha.reserve(this->prop_count); - - std::vector> initial_values; - - for (uint32_t i = 0; i < this->prop_count; i++) { - // get alphas - we cannot assume alphas are provided in same order as - // initial input - this->alpha.push_back(args.alpha[this->prop_names[i]]); - - const double val = args.initial_t[prop_names[i]]; - std::vector init_val(n_grid_cells, val); - initial_values.push_back(std::move(init_val)); - - if (this->dim == this->DIM_2D) { - tug::bc::BoundaryCondition bc(diff_input.grid.grid_cells[0], - diff_input.grid.grid_cells[1]); - this->bc_vec.push_back(bc); - } else { - tug::bc::BoundaryCondition bc(diff_input.grid.grid_cells[0]); - this->bc_vec.push_back(bc); + for (std::uint32_t i = 0; i < mat.cols(); i++) { + for (std::uint32_t j = 0; j < mat.rows(); j++) { + vec[j * mat.cols() + i] = mat(j, i); } } - this->t_field = Field(n_grid_cells, initial_values, prop_names); - - // apply boundary conditions to each ghost node - uint8_t bc_size = (this->dim == this->DIM_1D ? 2 : 4); - for (uint8_t i = 0; i < bc_size; i++) { - const auto &side = borders[i]; - std::vector vecinj_i = Rcpp::as>( - args.vecinj_index[convert_bc_to_config_file(side)]); - for (int i = 0; i < this->prop_count; i++) { - std::vector bc_vec = args.vecinj[this->prop_names[i]]; - tug::bc::BoundaryCondition &curr_bc = *(this->bc_vec.begin() + i); - for (int j = 0; j < vecinj_i.size(); j++) { - if (vecinj_i[j] == 0) { - continue; - } - if (this->dim == this->DIM_2D) { - curr_bc(side, j) = {tug::bc::BC_TYPE_CONSTANT, - bc_vec[vecinj_i[j] - 1]}; - } - if (this->dim == this->DIM_1D) { - curr_bc(side) = {tug::bc::BC_TYPE_CONSTANT, bc_vec[vecinj_i[j] - 1]}; - } - } - } - } - - // apply inner grid constant cells - // NOTE: opening a scope here for distinguish variable names - if (args.vecinj_inner.size() != 0) { - // apply inner constant cells for every concentration - for (int i = 0; i < this->prop_count; i++) { - std::vector bc_vec = args.vecinj[this->prop_names[i]]; - tug::bc::BoundaryCondition &curr_bc = *(this->bc_vec.begin() + i); - for (int j = 0; j < args.vecinj_inner.size(); j++) { - std::vector inner_tuple = - Rcpp::as>(args.vecinj_inner[j]); - tug::bc::boundary_condition bc = {tug::bc::BC_TYPE_CONSTANT, - bc_vec[inner_tuple[0] - 1]}; - - this->index_constant_cells.push_back(inner_tuple[1]); - uint32_t x = inner_tuple[1]; - uint32_t y = (this->dim == this->DIM_1D ? 0 : inner_tuple[2]); - - curr_bc.setInnerBC(bc, x, y); - } - } - } + return vec; } -void DiffusionModule::simulate(double dt) { - double sim_a_transport, sim_b_transport; +static inline Eigen::MatrixX +VecToMatrix(const std::vector &vec, std::uint32_t n_rows, + std::uint32_t n_cols) { + Eigen::MatrixX mat(n_rows, n_cols); - sim_b_transport = MPI_Wtime(); - - MSG_NOENDL("DiffusionModule::simulate(): Starting diffusion ..."); - std::cout << std::flush; - - std::vector> field_2d = t_field.As2DVector(); - - this->diff_input.setTimestep(dt); - - for (int i = 0; i < field_2d.size(); i++) { - std::vector in_alpha(this->n_cells_per_prop, this->alpha[i]); - this->diff_input.setBoundaryCondition(this->bc_vec[i]); - - if (this->dim == this->DIM_1D) { - tug::diffusion::BTCS_1D(this->diff_input, field_2d[i].data(), - in_alpha.data()); - } else { - tug::diffusion::ADI_2D(this->diff_input, field_2d[i].data(), - in_alpha.data()); + for (std::uint32_t i = 0; i < n_cols; i++) { + for (std::uint32_t j = 0; j < n_rows; j++) { + mat(j, i) = vec[j * n_cols + i]; } } - t_field = field_2d; - - sim_a_transport = MPI_Wtime(); - - transport_t += sim_a_transport - sim_b_transport; - std::cout << " done in " << sim_a_transport - sim_b_transport << "sec" - << std::endl; + return mat; } -void DiffusionModule::end() { - // R["simtime_transport"] = transport_t; - // R.parseEvalQ("profiling$simtime_transport <- simtime_transport"); +// static constexpr double ZERO_MULTIPLICATOR = 10E-14; + +void DiffusionModule::simulate(double requested_dt) { + MSG("Starting diffusion ..."); + const auto start_diffusion_t = std::chrono::high_resolution_clock::now(); + + const auto &n_rows = this->param_list.n_rows; + const auto &n_cols = this->param_list.n_cols; + + tug::Grid grid(param_list.n_rows, param_list.n_cols); + tug::Boundary boundary(grid); + + grid.setDomain(param_list.s_rows, param_list.s_cols); + + tug::Simulation sim(grid, boundary); + sim.setIterations(1); + + for (const auto &sol_name : this->param_list.transport_names) { + auto &species_conc = this->transport_field[sol_name]; + + Eigen::MatrixX conc = VecToMatrix(species_conc, n_rows, n_cols); + Eigen::MatrixX alpha_x = + VecToMatrix(this->param_list.alpha_x[sol_name], n_rows, n_cols); + Eigen::MatrixX alpha_y = + VecToMatrix(this->param_list.alpha_y[sol_name], n_rows, n_cols); + + boundary.deserialize(this->param_list.boundaries[sol_name]); + + grid.setAlpha(alpha_x, alpha_y); + grid.setConcentrations(conc); + + sim.setTimestep(requested_dt); + + sim.run(); + + species_conc = MatrixToVec(grid.getConcentrations()); + } + + const auto end_diffusion_t = std::chrono::high_resolution_clock::now(); + + const auto consumed_time_seconds = + std::chrono::duration_cast>( + end_diffusion_t - start_diffusion_t); + + MSG("Diffusion done in " + std::to_string(consumed_time_seconds.count()) + + " [s]"); + + transport_t += consumed_time_seconds.count(); } double DiffusionModule::getTransportTime() { return this->transport_t; } diff --git a/src/Transport/DiffusionModule.hpp b/src/Transport/DiffusionModule.hpp index a31bc0738..f19ee2064 100644 --- a/src/Transport/DiffusionModule.hpp +++ b/src/Transport/DiffusionModule.hpp @@ -21,20 +21,13 @@ #ifndef DIFFUSION_MODULE_H #define DIFFUSION_MODULE_H -#include "../Base/Grid.hpp" -#include "../Base/SimParams.hpp" -#include "../DataStructures/DataStructures.hpp" +#include "DataStructures/Field.hpp" +#include "Init/InitialList.hpp" -#include -#include - -#include -#include -#include -#include -#include +#include namespace poet { + /** * @brief Class describing transport simulation * @@ -53,8 +46,8 @@ public: * * @param R RRuntime object */ - DiffusionModule(const poet::DiffusionParams &diffu_args, - const poet::GridParams &grid_params); + DiffusionModule(const InitialList::DiffusionInit &init_list, Field field) + : param_list(init_list), transport_field(field){}; /** * @brief Run simulation for one iteration @@ -64,14 +57,6 @@ public: */ void simulate(double dt); - /** - * @brief End simulation - * - * All measured timings are distributed to the R runtime - * - */ - void end(); - /** * @brief Get the transport time * @@ -84,33 +69,17 @@ public: * * \return Reference to the diffusion field. */ - Field &getField() { return this->t_field; } + Field &getField() { return this->transport_field; } private: /** * @brief Instance of RRuntime * */ - // RRuntime &R; - enum { DIM_1D = 1, DIM_2D }; + InitialList::DiffusionInit param_list; - void initialize(const poet::DiffusionParams &args, - std::uint32_t n_grid_cells); - - uint8_t dim; - - uint32_t prop_count; - - tug::diffusion::TugInput diff_input; - std::vector alpha; - std::vector index_constant_cells; - std::vector prop_names; - - std::vector bc_vec; - Field t_field; - - uint32_t n_cells_per_prop; + Field transport_field; /** * @brief time spent for transport diff --git a/src/poet.cpp b/src/poet.cpp index 10c706a0d..fa7819460 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -4,6 +4,8 @@ ** ** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) ** +** Copyright (C) 2023-2024 Max Luebke (University of 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 @@ -18,125 +20,308 @@ ** Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "Base/Grid.hpp" #include "Base/Macros.hpp" #include "Base/RInsidePOET.hpp" -#include "Base/SimParams.hpp" -#include "Chemistry/ChemistryModule.hpp" +// #include "Chemistry/ChemistryModule.hpp" +#include "DataStructures/Field.hpp" +#include "Init/InitialList.hpp" #include "Transport/DiffusionModule.hpp" +#include +#include +#include +#include #include #include -#include #include -#include -#include #include -#include #include +#include "Base/argh.hpp" + using namespace std; using namespace poet; using namespace Rcpp; -poet::ChemistryModule::SingleCMap DFToHashMap(const Rcpp::DataFrame &df) { - std::unordered_map out_map; - vector col_names = Rcpp::as>(df.names()); +static int MY_RANK = 0; - for (const auto &name : col_names) { - double val = df[name.c_str()]; - out_map.insert({name, val}); - } +// poet::ChemistryModule::SingleCMap DFToHashMap(const Rcpp::DataFrame &df) { +// std::unordered_map out_map; +// vector col_names = Rcpp::as>(df.names()); - return out_map; -} +// for (const auto &name : col_names) { +// double val = df[name.c_str()]; +// out_map.insert({name, val}); +// } + +// return out_map; +// } // HACK: this is a step back as the order and also the count of fields is // predefined, but it will change in the future -void writeFieldsToR(RInside &R, const Field &trans, const Field &chem) { - R["TMP"] = Rcpp::wrap(trans.AsVector()); - R["TMP_PROPS"] = Rcpp::wrap(trans.GetProps()); - R.parseEval(std::string( - "mysetup$state_T <- setNames(data.frame(matrix(TMP, nrow=" + - std::to_string(trans.GetRequestedVecSize()) + ")), TMP_PROPS)")); +void writeFieldsToR(RInside &R, const Field &trans) { + // , const Field &chem) { - R["TMP"] = Rcpp::wrap(chem.AsVector()); - R["TMP_PROPS"] = Rcpp::wrap(chem.GetProps()); - R.parseEval(std::string( - "mysetup$state_C <- setNames(data.frame(matrix(TMP, nrow=" + - std::to_string(chem.GetRequestedVecSize()) + ")), TMP_PROPS)")); + Rcpp::DataFrame t_field(trans.asSEXP()); + + R["TMP"] = t_field; + + R.parseEval("mysetup$state_T <- TMP"); + R.parseEval("mysetup$state_C <- TMP"); + + // R["TMP"] = Rcpp::wrap(trans.AsVector()); + // R["TMP_PROPS"] = Rcpp::wrap(trans.GetProps()); + // R.parseEval(std::string( + // "mysetup$state_T <- setNames(data.frame(matrix(TMP, nrow=" + + // std::to_string(trans.GetRequestedVecSize()) + ")), TMP_PROPS)")); + + // R["TMP"] = Rcpp::wrap(chem.AsVector()); + // R["TMP_PROPS"] = Rcpp::wrap(chem.GetProps()); + // R.parseEval(std::string( + // "mysetup$state_C <- setNames(data.frame(matrix(TMP, nrow=" + + // std::to_string(chem.GetRequestedVecSize()) + ")), TMP_PROPS)")); } -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); +enum ParseRet { PARSER_OK, PARSER_ERROR, PARSER_HELP }; - // 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); +ParseRet parseInitValues(char **argv, RInsidePOET &R, + RuntimeParameters ¶ms) { + // initialize argh object + argh::parser cmdl(argv); - // Set representative volume - std::vector rv; - rv.resize(wp_size, 1.0); - chem.SetRepresentativeVolume(rv); + // if user asked for help + if (cmdl[{"help", "h"}]) { + if (MY_RANK == 0) { + MSG("Todo"); + MSG("See README.md for further information."); + } - // Set initial porosity - std::vector por; - por.resize(wp_size, 1); - chem.SetPorosity(por); + return ParseRet::PARSER_HELP; + } + // if positional arguments are missing + else if (!cmdl(2)) { + if (MY_RANK == 0) { + ERRMSG("POET needs 2 positional arguments: "); + ERRMSG("1) the R script defining your simulation and"); + ERRMSG("2) the directory prefix where to save results and profiling"); + } + return ParseRet::PARSER_ERROR; + } - // Set initial saturation - std::vector sat; - sat.resize(wp_size, 1.0); - chem.SetSaturation(sat); + // parse flags and check for unknown + for (const auto &option : cmdl.flags()) { + if (!(flaglist.find(option) != flaglist.end())) { + if (MY_RANK == 0) { + ERRMSG("Unrecognized option: " + option); + ERRMSG("Make sure to use available options. Exiting!"); + } + return ParseRet::PARSER_ERROR; + } + } - // Load database - chem.LoadDatabase(database_path); + // parse parameters and check for unknown + for (const auto &option : cmdl.params()) { + if (!(paramlist.find(option.first) != paramlist.end())) { + if (MY_RANK == 0) { + ERRMSG("Unrecognized option: " + option.first); + ERRMSG("Make sure to use available options. Exiting!"); + } + return ParseRet::PARSER_ERROR; + } + } + + // simparams.print_progressbar = cmdl[{"P", "progress"}]; + + // // simparams.print_progressbar = cmdl[{"P", "progress"}]; + + // /* Parse DHT arguments */ + // chem_params.use_dht = cmdl["dht"]; + // chem_params.use_interp = cmdl["interp"]; + // // cout << "CPP: DHT is " << ( dht_enabled ? "ON" : "OFF" ) << '\n'; + + // cmdl("dht-size", DHT_SIZE_PER_PROCESS_MB) >> chem_params.dht_size; + // // cout << "CPP: DHT size per process (Byte) = " << dht_size_per_process << + // // endl; + + // cmdl("dht-snaps", 0) >> chem_params.dht_snaps; + + // cmdl("dht-file") >> chem_params.dht_file; + // /*Parse work package size*/ + // cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; + + // cmdl("interp-size", 100) >> chem_params.pht_size; + // cmdl("interp-min", 5) >> chem_params.interp_min_entries; + // cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; + + // /*Parse output options*/ + // simparams.store_result = !cmdl["ignore-result"]; + + // /*Parse work package size*/ + // cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; + + // chem_params.use_interp = cmdl["interp"]; + // cmdl("interp-size", 100) >> chem_params.pht_size; + // cmdl("interp-min", 5) >> chem_params.interp_min_entries; + // cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; + + // /*Parse output options*/ + // simparams.store_result = !cmdl["ignore-result"]; + + // if (simparams.world_rank == 0) { + // MSG("Complete results storage is " + BOOL_PRINT(simparams.store_result)); + // MSG("Work Package Size: " + std::to_string(simparams.wp_size)); + // MSG("DHT is " + BOOL_PRINT(chem_params.use_dht)); + + // if (chem_params.use_dht) { + // MSG("DHT strategy is " + std::to_string(simparams.dht_strategy)); + // // MDL: these should be outdated (?) + // // MSG("DHT key default digits (ignored if 'signif_vector' is " + // // "defined) = " + // // << simparams.dht_significant_digits); + // // MSG("DHT logarithm before rounding: " + // // << (simparams.dht_log ? "ON" : "OFF")); + // MSG("DHT size per process (Megabyte) = " + + // std::to_string(chem_params.dht_size)); + // MSG("DHT save snapshots is " + BOOL_PRINT(chem_params.dht_snaps)); + // MSG("DHT load file is " + chem_params.dht_file); + // } + + // if (chem_params.use_interp) { + // MSG("PHT interpolation enabled: " + + // BOOL_PRINT(chem_params.use_interp)); MSG("PHT interp-size = " + + // std::to_string(chem_params.pht_size)); MSG("PHT interp-min = " + + // std::to_string(chem_params.interp_min_entries)); + // MSG("PHT interp-bucket-entries = " + + // std::to_string(chem_params.pht_max_entries)); + // } + // } + + std::string init_file; + std::string runtime_file; + std::string out_dir; + + cmdl(1) >> init_file; + cmdl(2) >> runtime_file; + cmdl(3) >> out_dir; + + // chem_params.dht_outdir = out_dir; + + /* distribute information to R runtime */ + // if local_rank == 0 then master else worker + R["local_rank"] = MY_RANK; + // assign a char* (string) to 'filesim' + R["filesim"] = wrap(runtime_file); + // assign a char* (string) to 'fileout' + R["fileout"] = wrap(out_dir); + // pass the boolean "store_result" to the R process + // R["store_result"] = simparams.store_result; + // // worker count + // R["n_procs"] = simparams.world_size - 1; + // // work package size + // R["work_package_size"] = simparams.wp_size; + // // dht enabled? + // R["dht_enabled"] = chem_params.use_dht; + // // log before rounding? + // R["dht_log"] = simparams.dht_log; + + try { + Rcpp::Function source("source"); + Rcpp::Function readRDS("readRDS"); + + Rcpp::List init_params_ = readRDS(init_file); + params.init_params = init_params_; + + Rcpp::List runtime_params = + source(runtime_file, Rcpp::Named("local", true)); + runtime_params = runtime_params["value"]; + R[r_runtime_parameters] = runtime_params; + + params.timesteps = + Rcpp::as>(runtime_params["timesteps"]); + + } catch (const std::exception &e) { + ERRMSG("Error while parsing R scripts: " + std::string(e.what())); + return ParseRet::PARSER_ERROR; + } + // eval the init string, ignoring any returns + // R.parseEvalQ("source(filesim)"); + // R.parseEvalQ("mysetup <- setup"); + + // this->chem_params.initFromR(R); + + return ParseRet::PARSER_OK; } -inline double RunMasterLoop(SimParams ¶ms, RInside &R, - const GridParams &g_params, uint32_t nxyz_master) { +// 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 rv; +// rv.resize(wp_size, 1.0); +// chem.SetRepresentativeVolume(rv); + +// // Set initial porosity +// std::vector por; +// por.resize(wp_size, 1); +// chem.SetPorosity(por); + +// // Set initial saturation +// std::vector sat; +// sat.resize(wp_size, 1.0); +// chem.SetSaturation(sat); + +// // Load database +// chem.LoadDatabase(database_path); +// } + +static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, + DiffusionModule &diffusion) { - DiffusionParams d_params{R}; - DiffusionModule diffusion(d_params, g_params); /* Iteration Count is dynamic, retrieving value from R (is only needed by * master for the following loop) */ - uint32_t maxiter = R.parseEval("mysetup$iterations"); + uint32_t maxiter = params.timesteps.size(); double sim_time = .0; - ChemistryModule chem(nxyz_master, params.getNumParams().wp_size, maxiter, - params.getChemParams(), MPI_COMM_WORLD); + // ChemistryModule chem(nxyz_master, params.getNumParams().wp_size, maxiter, + // params.getChemParams(), MPI_COMM_WORLD); - set_chem_parameters(chem, nxyz_master, params.getChemParams().database_path); - chem.RunInitFile(params.getChemParams().input_script); + // set_chem_parameters(chem, nxyz_master, + // params.getChemParams().database_path); + // chem.RunInitFile(params.getChemParams().input_script); - poet::ChemistryModule::SingleCMap init_df = DFToHashMap(d_params.initial_t); - chem.initializeField(diffusion.getField()); + // poet::ChemistryModule::SingleCMap init_df = + // DFToHashMap(d_params.initial_t); + // chem.initializeField(diffusion.getField()); - if (params.getNumParams().print_progressbar) { - chem.setProgressBarPrintout(true); - } + // if (params.getNumParams().print_progressbar) { + // chem.setProgressBarPrintout(true); + // } /* SIMULATION LOOP */ @@ -147,31 +332,30 @@ inline double RunMasterLoop(SimParams ¶ms, RInside &R, // cout << "CPP: Evaluating next time step" << endl; // R.parseEvalQ("mysetup <- master_iteration_setup(mysetup)"); - double dt = Rcpp::as( - R.parseEval("mysetup$timesteps[" + std::to_string(iter) + "]")); + double dt = params.timesteps[iter - 1]; // cout << "CPP: Next time step is " << dt << "[s]" << endl; MSG("Next time step is " + std::to_string(dt) + " [s]"); /* displaying iteration number, with C++ and R iterator */ MSG("Going through iteration " + std::to_string(iter)); - MSG("R's $iter: " + - std::to_string((uint32_t)(R.parseEval("mysetup$iter"))) + - ". Iteration"); + // MSG("R's $iter: " + + // std::to_string((uint32_t)(R.parseEval("mysetup$iter"))) + + // ". Iteration"); /* run transport */ // TODO: transport to diffusion diffusion.simulate(dt); - chem.getField().update(diffusion.getField()); + // chem.getField().update(diffusion.getField()); MSG("Chemistry step"); - chem.SetTimeStep(dt); - chem.RunCells(); + // chem.SetTimeStep(dt); + // chem.RunCells(); - writeFieldsToR(R, diffusion.getField(), chem.GetField()); - diffusion.getField().update(chem.GetField()); + writeFieldsToR(R, diffusion.getField()); + // diffusion.getField().update(chem.GetField()); R["req_dt"] = dt; R["simtime"] = (sim_time += dt); @@ -183,7 +367,7 @@ inline double RunMasterLoop(SimParams ¶ms, RInside &R, // 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)"); + R.parseEval("mysetup <- master_iteration_end(setup=mysetup)"); MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + std::to_string(maxiter)); @@ -194,60 +378,60 @@ inline double RunMasterLoop(SimParams ¶ms, RInside &R, dSimTime += end_t - start_t; } // END SIMULATION LOOP - R.parseEvalQ("profiling <- list()"); + // R.parseEvalQ("profiling <- list()"); - R["simtime_chemistry"] = chem.GetChemistryTime(); - R.parseEvalQ("profiling$simtime_chemistry <- simtime_chemistry"); + // R["simtime_chemistry"] = chem.GetChemistryTime(); + // R.parseEvalQ("profiling$simtime_chemistry <- simtime_chemistry"); - R["chemistry_loop"] = chem.GetMasterLoopTime(); - R.parseEvalQ("profiling$chemistry_loop <- chemistry_loop"); + // R["chemistry_loop"] = chem.GetMasterLoopTime(); + // R.parseEvalQ("profiling$chemistry_loop <- chemistry_loop"); - R["chemistry_sequential"] = chem.GetMasterSequentialTime(); - R.parseEvalQ("profiling$simtime_sequential <- chemistry_sequential"); + // R["chemistry_sequential"] = chem.GetMasterSequentialTime(); + // R.parseEvalQ("profiling$simtime_sequential <- chemistry_sequential"); - R["idle_master"] = chem.GetMasterIdleTime(); - R.parseEvalQ("profiling$idle_master <- idle_master"); + // R["idle_master"] = chem.GetMasterIdleTime(); + // R.parseEvalQ("profiling$idle_master <- idle_master"); - R["idle_worker"] = Rcpp::wrap(chem.GetWorkerIdleTimings()); - R.parseEvalQ("profiling$idle_worker <- idle_worker"); + // R["idle_worker"] = Rcpp::wrap(chem.GetWorkerIdleTimings()); + // R.parseEvalQ("profiling$idle_worker <- idle_worker"); - R["phreeqc_time"] = Rcpp::wrap(chem.GetWorkerPhreeqcTimings()); - R.parseEvalQ("profiling$phreeqc <- phreeqc_time"); + // R["phreeqc_time"] = Rcpp::wrap(chem.GetWorkerPhreeqcTimings()); + // R.parseEvalQ("profiling$phreeqc <- phreeqc_time"); - R["simtime_transport"] = diffusion.getTransportTime(); - R.parseEvalQ("profiling$simtime_transport <- simtime_transport"); + // R["simtime_transport"] = diffusion.getTransportTime(); + // R.parseEvalQ("profiling$simtime_transport <- simtime_transport"); // R["phreeqc_count"] = phreeqc_counts; // R.parseEvalQ("profiling$phreeqc_count <- phreeqc_count"); - if (params.getChemParams().use_dht) { - R["dht_hits"] = Rcpp::wrap(chem.GetWorkerDHTHits()); - R.parseEvalQ("profiling$dht_hits <- dht_hits"); - R["dht_evictions"] = Rcpp::wrap(chem.GetWorkerDHTEvictions()); - R.parseEvalQ("profiling$dht_evictions <- dht_evictions"); - R["dht_get_time"] = Rcpp::wrap(chem.GetWorkerDHTGetTimings()); - R.parseEvalQ("profiling$dht_get_time <- dht_get_time"); - R["dht_fill_time"] = Rcpp::wrap(chem.GetWorkerDHTFillTimings()); - R.parseEvalQ("profiling$dht_fill_time <- dht_fill_time"); - } - if (params.getChemParams().use_interp) { - R["interp_w"] = Rcpp::wrap(chem.GetWorkerInterpolationWriteTimings()); - R.parseEvalQ("profiling$interp_write <- interp_w"); - R["interp_r"] = Rcpp::wrap(chem.GetWorkerInterpolationReadTimings()); - R.parseEvalQ("profiling$interp_read <- interp_r"); - R["interp_g"] = Rcpp::wrap(chem.GetWorkerInterpolationGatherTimings()); - R.parseEvalQ("profiling$interp_gather <- interp_g"); - R["interp_fc"] = - Rcpp::wrap(chem.GetWorkerInterpolationFunctionCallTimings()); - R.parseEvalQ("profiling$interp_function_calls <- interp_fc"); - R["interp_calls"] = Rcpp::wrap(chem.GetWorkerInterpolationCalls()); - R.parseEvalQ("profiling$interp_calls <- interp_calls"); - R["interp_cached"] = Rcpp::wrap(chem.GetWorkerPHTCacheHits()); - R.parseEvalQ("profiling$interp_cached <- interp_cached"); - } + // if (params.getChemParams().use_dht) { + // R["dht_hits"] = Rcpp::wrap(chem.GetWorkerDHTHits()); + // R.parseEvalQ("profiling$dht_hits <- dht_hits"); + // R["dht_evictions"] = Rcpp::wrap(chem.GetWorkerDHTEvictions()); + // R.parseEvalQ("profiling$dht_evictions <- dht_evictions"); + // R["dht_get_time"] = Rcpp::wrap(chem.GetWorkerDHTGetTimings()); + // R.parseEvalQ("profiling$dht_get_time <- dht_get_time"); + // R["dht_fill_time"] = Rcpp::wrap(chem.GetWorkerDHTFillTimings()); + // R.parseEvalQ("profiling$dht_fill_time <- dht_fill_time"); + // } + // if (params.getChemParams().use_interp) { + // R["interp_w"] = Rcpp::wrap(chem.GetWorkerInterpolationWriteTimings()); + // R.parseEvalQ("profiling$interp_write <- interp_w"); + // R["interp_r"] = Rcpp::wrap(chem.GetWorkerInterpolationReadTimings()); + // R.parseEvalQ("profiling$interp_read <- interp_r"); + // R["interp_g"] = + // Rcpp::wrap(chem.GetWorkerInterpolationGatherTimings()); + // R.parseEvalQ("profiling$interp_gather <- interp_g"); + // R["interp_fc"] = + // Rcpp::wrap(chem.GetWorkerInterpolationFunctionCallTimings()); + // R.parseEvalQ("profiling$interp_function_calls <- interp_fc"); + // R["interp_calls"] = Rcpp::wrap(chem.GetWorkerInterpolationCalls()); + // R.parseEvalQ("profiling$interp_calls <- interp_calls"); + // R["interp_cached"] = Rcpp::wrap(chem.GetWorkerPHTCacheHits()); + // R.parseEvalQ("profiling$interp_cached <- interp_cached"); + // } - chem.MasterLoopBreak(); - diffusion.end(); + // chem.MasterLoopBreak(); return dSimTime; } @@ -271,24 +455,24 @@ int main(int argc, char *argv[]) { if (world_rank > 0) { { - SimParams params(world_rank, world_size); - int pret = params.parseFromCmdl(argv, R); + // 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; - } + // if (pret == poet::PARSER_ERROR) { + // MPI_Finalize(); + // return EXIT_FAILURE; + // } else if (pret == poet::PARSER_HELP) { + // MPI_Finalize(); + // return EXIT_SUCCESS; + // } - // ChemistryModule worker(nxyz, nxyz, MPI_COMM_WORLD); - ChemistryModule worker = poet::ChemistryModule::createWorker( - MPI_COMM_WORLD, params.getChemParams()); - set_chem_parameters(worker, worker.GetWPSize(), - params.getChemParams().database_path); + // // ChemistryModule worker(nxyz, nxyz, MPI_COMM_WORLD); + // ChemistryModule worker = poet::ChemistryModule::createWorker( + // MPI_COMM_WORLD, params.getChemParams()); + // set_chem_parameters(worker, worker.GetWPSize(), + // params.getChemParams().database_path); - worker.WorkerLoop(); + // worker.WorkerLoop(); } MPI_Barrier(MPI_COMM_WORLD); @@ -304,33 +488,31 @@ int main(int argc, char *argv[]) { // TODO: kann raus R.parseEvalQ(kin_r_library); - SimParams params(world_rank, world_size); - int pret = params.parseFromCmdl(argv, R); + RuntimeParameters run_params; - if (pret == poet::PARSER_ERROR) { + switch (parseInitValues(argv, R, run_params)) { + case ParseRet::PARSER_ERROR: + case ParseRet::PARSER_HELP: MPI_Finalize(); - return EXIT_FAILURE; - } else if (pret == poet::PARSER_HELP) { - MPI_Finalize(); - return EXIT_SUCCESS; + return 0; + case ParseRet::PARSER_OK: + break; } MSG("RInside initialized on process " + std::to_string(world_rank)); - 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.parseEvalQ("mysetup <- setup"); + // // if (world_rank == 0) { // get timestep vector from + // // grid_init function ... // + std::string master_init_code = "mysetup <- master_init(setup=mysetup)"; R.parseEval(master_init_code); - GridParams g_params(R); - - params.initVectorParams(R); + // run_params.initVectorParams(R); // MDL: store all parameters if (world_rank == 0) { MSG("Calling R Function to store calling parameters"); - R.parseEvalQ("StoreSetup(setup=mysetup)"); + // R.parseEvalQ("StoreSetup(setup=mysetup)"); } if (world_rank == 0) { @@ -339,23 +521,28 @@ int main(int argc, char *argv[]) { // MPI_Barrier(MPI_COMM_WORLD); - uint32_t nxyz_master = (world_size == 1 ? g_params.total_n : 1); + InitialList init_list(R); + init_list.importList(run_params.init_params); - dSimTime = RunMasterLoop(params, R, g_params, nxyz_master); + DiffusionModule diffusion(init_list.getDiffusionInit(), + init_list.getInitialGrid()); + + dSimTime = RunMasterLoop(R, run_params, diffusion); MSG("finished simulation loop"); MSG("start timing profiling"); - R["simtime"] = dSimTime; - R.parseEvalQ("profiling$simtime <- simtime"); + // 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); + // string r_vis_code; + // r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; + // R.parseEval(r_vis_code); - MSG("Done! Results are stored as R objects into <" + params.getOutDir() + - "/timings.rds>"); + // MSG("Done! Results are stored as R objects into <" + run_params.getOutDir() + // + + // "/timings.rds>"); MPI_Barrier(MPI_COMM_WORLD); diff --git a/src/poet.hpp.in b/src/poet.hpp.in index 115ac7dd7..99b3e7a58 100644 --- a/src/poet.hpp.in +++ b/src/poet.hpp.in @@ -1,12 +1,79 @@ -#ifndef POET_H -#define POET_H +/* +** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of +** Potsdam) +** +** Copyright (C) 2018-2023 Marco De Lucia, Max Luebke (GFZ Potsdam) +** +** Copyright (C) 2023-2024 Max Luebke (University of 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. +*/ +#pragma once + +#include #include +#include + +#include + static const char *poet_version = "@POET_VERSION@"; // using the Raw string literal to avoid escaping the quotes -static inline std::string kin_r_library = R"(@R_KIN_LIB@)"; +static const inline std::string kin_r_library = R"(@R_KIN_LIB@)"; -static inline std::string init_r_library = R"(@R_INIT_LIB@)"; +static const inline std::string init_r_library = R"(@R_INIT_LIB@)"; -#endif // POET_H +static const inline std::string r_runtime_parameters = "mysetup"; + +const std::set flaglist{"ignore-result", "dht", "P", "progress", + "interp"}; +const std::set paramlist{ + "work-package-size", "dht-strategy", "dht-size", "dht-snaps", + "dht-file", "interp-size", "interp-min", "interp-bucket-entries"}; + +struct RuntimeParameters { + std::vector timesteps; + + bool print_progressbar; + + Rcpp::List init_params; + + struct ChemistryParams { + // std::string database_path; + // std::string input_script; + + // bool use_dht; + // std::uint64_t dht_size; + // int dht_snaps; + // std::string dht_file; + // std::string dht_outdir; + // NamedVector dht_signifs; + + // bool use_interp; + // std::uint64_t pht_size; + // std::uint32_t pht_max_entries; + // std::uint32_t interp_min_entries; + // NamedVector pht_signifs; + + // struct Chem_Hook_Functions { + // RHookFunction dht_fill; + // RHookFunction> dht_fuzz; + // RHookFunction> interp_pre; + // RHookFunction interp_post; + // } hooks; + + // void initFromR(RInsidePOET &R); + }; +}; From 80ce92699fe1fd783e52f9ff10db968445e77c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Thu, 28 Mar 2024 14:23:20 +0000 Subject: [PATCH 22/77] Update dependencies and refactor code --- ext/iphreeqc | 2 +- ext/tug | 2 +- src/Base/SimParams.cpp | 1 - src/Base/SimParams.hpp | 57 ++-- src/CMakeLists.txt | 9 + src/Chemistry/ChemistryDefs.hpp | 23 ++ src/Chemistry/ChemistryModule.cpp | 302 ++++-------------- src/Chemistry/ChemistryModule.hpp | 72 ++--- src/Chemistry/MasterFunctions.cpp | 59 ++-- src/Chemistry/SurrogateModels/DHT_Wrapper.cpp | 3 +- src/Chemistry/SurrogateModels/DHT_Wrapper.hpp | 11 +- .../SurrogateModels/Interpolation.hpp | 7 +- .../SurrogateModels/InterpolationModule.cpp | 2 +- src/Chemistry/WorkerFunctions.cpp | 119 +++---- src/Chemistry/enums.hpp | 10 - src/DataStructures/Field.hpp | 1 + src/Init/ChemistryInit.cpp | 2 - src/Init/GridInit.cpp | 4 +- src/Init/InitialList.hpp | 2 - src/initializer.cpp | 4 +- src/poet.cpp | 119 +++---- 21 files changed, 309 insertions(+), 502 deletions(-) create mode 100644 src/Chemistry/ChemistryDefs.hpp delete mode 100644 src/Chemistry/enums.hpp diff --git a/ext/iphreeqc b/ext/iphreeqc index d6e713074..f69561987 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit d6e7130746f9823e0bc5f711179e676e27ba3737 +Subproject commit f695619875fcf43e411af67d592c05b199f41a15 diff --git a/ext/tug b/ext/tug index 8c0687a6c..3ffa0ef62 160000 --- a/ext/tug +++ b/ext/tug @@ -1 +1 @@ -Subproject commit 8c0687a6cd4a10a79c7a554083a35eda11cc55f0 +Subproject commit 3ffa0ef6242d467a269be83751c857cb24ae532e diff --git a/src/Base/SimParams.cpp b/src/Base/SimParams.cpp index 3ae76dd65..8264b6c60 100644 --- a/src/Base/SimParams.cpp +++ b/src/Base/SimParams.cpp @@ -29,7 +29,6 @@ #include #include -#include #include "Base/RInsidePOET.hpp" #include "argh.hpp" // Argument handler https://github.com/adishavit/argh diff --git a/src/Base/SimParams.hpp b/src/Base/SimParams.hpp index b4e20f262..74d6d2078 100644 --- a/src/Base/SimParams.hpp +++ b/src/Base/SimParams.hpp @@ -47,36 +47,37 @@ enum { PARSER_OK, PARSER_ERROR, PARSER_HELP }; * @brief Defining all simulation parameters * */ -struct RuntimeParameters { +// struct RuntimeParameters { - /** Count of processes in MPI_COMM_WORLD */ - int world_size; - /** rank of proces in MPI_COMM_WORLD */ - int world_rank; - /** indicates if DHT should be used */ - bool dht_enabled; - /** apply logarithm to key before rounding */ - bool dht_log; - /** indicates if timestep dt differs between iterations */ - bool dt_differ; - /** Indicates, when a DHT snapshot should be written */ - int dht_snaps; - /** not implemented: How a DHT is distributed over processes */ - int dht_strategy; - /** Size of DHt per process in byter */ - unsigned int dht_size_per_process; - /** Default significant digit for rounding */ - int dht_significant_digits; - /** Default work package size */ - unsigned int wp_size; - /** indicates if resulting grid should be stored after every iteration */ - bool store_result; - /** indicating whether the progress bar during chemistry simulation should be - * printed or not */ - bool print_progressbar; +// /** Count of processes in MPI_COMM_WORLD */ +// int world_size; +// /** rank of proces in MPI_COMM_WORLD */ +// int world_rank; +// /** indicates if DHT should be used */ +// bool dht_enabled; +// /** apply logarithm to key before rounding */ +// bool dht_log; +// /** indicates if timestep dt differs between iterations */ +// bool dt_differ; +// /** Indicates, when a DHT snapshot should be written */ +// int dht_snaps; +// /** not implemented: How a DHT is distributed over processes */ +// int dht_strategy; +// /** Size of DHt per process in byter */ +// unsigned int dht_size_per_process; +// /** Default significant digit for rounding */ +// int dht_significant_digits; +// /** Default work package size */ +// unsigned int wp_size; +// /** indicates if resulting grid should be stored after every iteration */ +// bool store_result; +// /** indicating whether the progress bar during chemistry simulation should +// be +// * printed or not */ +// bool print_progressbar; - bool interp_enabled; -}; +// bool interp_enabled; +// }; // using GridParams = struct s_GridParams { // std::array n_cells; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e4430848..c4e8d759d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,14 @@ target_sources(POETLib Init/ChemistryInit.cpp DataStructures/Field.cpp Transport/DiffusionModule.cpp + Chemistry/ChemistryModule.cpp + Chemistry/MasterFunctions.cpp + Chemistry/WorkerFunctions.cpp + Chemistry/SurrogateModels/DHT_Wrapper.cpp + Chemistry/SurrogateModels/DHT.c + Chemistry/SurrogateModels/HashFunctions.cpp + Chemistry/SurrogateModels/InterpolationModule.cpp + Chemistry/SurrogateModels/ProximityHashTable.cpp ) target_include_directories(POETLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") @@ -16,6 +24,7 @@ target_link_libraries( PUBLIC RRuntime PUBLIC IPhreeqcPOET PUBLIC tug + PUBLIC MPI::MPI_C ) # add_library(poetlib diff --git a/src/Chemistry/ChemistryDefs.hpp b/src/Chemistry/ChemistryDefs.hpp new file mode 100644 index 000000000..71c82edf6 --- /dev/null +++ b/src/Chemistry/ChemistryDefs.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace poet { + +enum DHT_PROP_TYPES { DHT_TYPE_DEFAULT, DHT_TYPE_CHARGE, DHT_TYPE_TOTAL }; +enum CHEMISTRY_OUT_SOURCE { CHEM_PQC, CHEM_DHT, CHEM_INTERP }; + +struct WorkPackage { + std::size_t size; + std::vector> input; + std::vector> output; + std::vector mapping; + + WorkPackage(std::size_t _size) : size(_size) { + input.resize(size); + output.resize(size); + mapping.resize(size, CHEM_PQC); + } +}; +} // namespace poet \ No newline at end of file diff --git a/src/Chemistry/ChemistryModule.cpp b/src/Chemistry/ChemistryModule.cpp index 46531f2c6..8623ef38f 100644 --- a/src/Chemistry/ChemistryModule.cpp +++ b/src/Chemistry/ChemistryModule.cpp @@ -1,20 +1,16 @@ #include "ChemistryModule.hpp" +#include "IPhreeqcPOET.hpp" #include "SurrogateModels/DHT_Wrapper.hpp" #include "SurrogateModels/Interpolation.hpp" -#include - #include #include #include #include -#include #include #include -#include #include -#include #include constexpr uint32_t MB_FACTOR = 1E6; @@ -158,25 +154,26 @@ inverseDistanceWeighting(const std::vector &to_calc, return results; } -poet::ChemistryModule::ChemistryModule(uint32_t nxyz, uint32_t wp_size, - std::uint32_t maxiter, - const ChemistryParams &chem_param, - MPI_Comm communicator) - : PhreeqcRM(nxyz, 1), group_comm(communicator), wp_size(wp_size), - params(chem_param) { +poet::ChemistryModule::ChemistryModule( + uint32_t wp_size_, const InitialList::ChemistryInit &chem_params, + MPI_Comm communicator) + : params(chem_params), wp_size(wp_size_), group_comm(communicator) { + MPI_Comm_rank(communicator, &comm_rank); + MPI_Comm_size(communicator, &comm_size); - MPI_Comm_size(communicator, &this->comm_size); - MPI_Comm_rank(communicator, &this->comm_rank); + this->is_sequential = comm_size == 1; + this->is_master = comm_rank == 0; - this->is_sequential = (this->comm_size == 1); - this->is_master = (this->comm_rank == 0); + this->n_cells = chem_params.total_grid_cells; - if (!is_sequential && is_master) { - MPI_Bcast(&wp_size, 1, MPI_UINT32_T, 0, this->group_comm); - MPI_Bcast(&maxiter, 1, MPI_UINT32_T, 0, this->group_comm); + if (!is_master) { + for (std::size_t i = 0; i < chem_params.pqc_ids.size(); i++) { + this->phreeqc_instances[chem_params.pqc_ids[i]] = + std::make_unique(chem_params.database, + chem_params.pqc_scripts[i], + chem_params.pqc_sol_order, wp_size_); + } } - - this->file_pad = std::ceil(std::log10(maxiter + 1)); } poet::ChemistryModule::~ChemistryModule() { @@ -185,206 +182,45 @@ poet::ChemistryModule::~ChemistryModule() { } } -poet::ChemistryModule -poet::ChemistryModule::createWorker(MPI_Comm communicator, - const ChemistryParams &chem_param) { - uint32_t wp_size; - MPI_Bcast(&wp_size, 1, MPI_UINT32_T, 0, communicator); - - std::uint32_t maxiter; - MPI_Bcast(&maxiter, 1, MPI_UINT32_T, 0, communicator); - - return ChemistryModule(wp_size, wp_size, maxiter, chem_param, communicator); -} - -void poet::ChemistryModule::RunInitFile(const std::string &input_script_path) { - if (this->is_master) { - int f_type = CHEM_INIT; - PropagateFunctionType(f_type); - - int count = input_script_path.size(); - ChemBCast(&count, 1, MPI_INT); - ChemBCast(const_cast(input_script_path.data()), count, MPI_CHAR); - } - - this->RunFile(true, true, false, input_script_path); - this->RunString(true, false, false, "DELETE; -all; PRINT; -warnings 0;"); - - this->FindComponents(); - - PhreeqcRM::initializePOET(this->speciesPerModule, this->prop_names); - this->prop_count = prop_names.size(); - - char exchange = (speciesPerModule[1] == 0 ? -1 : 1); - char kinetics = (speciesPerModule[2] == 0 ? -1 : 1); - char equilibrium = (speciesPerModule[3] == 0 ? -1 : 1); - char surface = (speciesPerModule[4] == 0 ? -1 : 1); - - std::vector 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); -} - -void poet::ChemistryModule::initializeField(const Field &trans_field) { - - if (is_master) { - int f_type = CHEM_INIT_SPECIES; - PropagateFunctionType(f_type); - } - - std::vector essentials_backup{ - prop_names.begin() + speciesPerModule[0], prop_names.end()}; - - std::vector new_solution_names{ - this->prop_names.begin(), this->prop_names.begin() + speciesPerModule[0]}; - - if (is_master) { - for (auto &prop : trans_field.GetProps()) { - if (std::find(new_solution_names.begin(), new_solution_names.end(), - prop) == new_solution_names.end()) { - int size = prop.size(); - ChemBCast(&size, 1, MPI_INT); - ChemBCast(prop.data(), prop.size(), MPI_CHAR); - new_solution_names.push_back(prop); - } - } - int end = 0; - ChemBCast(&end, 1, MPI_INT); - } else { - constexpr int MAXSIZE = 128; - MPI_Status status; - int recv_size; - char recv_buffer[MAXSIZE]; - while (1) { - ChemBCast(&recv_size, 1, MPI_INT); - if (recv_size == 0) { - break; - } - ChemBCast(recv_buffer, recv_size, MPI_CHAR); - recv_buffer[recv_size] = '\0'; - new_solution_names.push_back(std::string(recv_buffer)); - } - } - - // now sort the new values - std::sort(new_solution_names.begin() + 3, new_solution_names.end()); - this->SetPOETSolutionNames(new_solution_names); - this->speciesPerModule[0] = new_solution_names.size(); - - // and append other processes than solutions - std::vector new_prop_names = new_solution_names; - new_prop_names.insert(new_prop_names.end(), essentials_backup.begin(), - essentials_backup.end()); - - std::vector old_prop_names{this->prop_names}; - this->prop_names = std::move(new_prop_names); - this->prop_count = prop_names.size(); - - if (is_master) { - this->n_cells = trans_field.GetRequestedVecSize(); - - std::vector> phreeqc_dump(this->nxyz); - this->getDumpedField(phreeqc_dump); - - if (is_sequential) { - std::vector init_vec; - for (std::size_t i = 0; i < n_cells; i++) { - init_vec.insert(init_vec.end(), phreeqc_dump[i].begin(), - phreeqc_dump[i].end()); - } - - const auto tmp_buffer{init_vec}; - this->unshuffleField(tmp_buffer, n_cells, prop_count, 1, init_vec); - this->chem_field = Field(n_cells, init_vec, prop_names); - return; - } - - std::vector &phreeqc_init = phreeqc_dump[0]; - std::vector> initial_values; - - for (const auto &vec : trans_field.As2DVector()) { - initial_values.push_back(vec); - } - - this->base_totals = {initial_values.at(0).at(0), - initial_values.at(1).at(0)}; - ChemBCast(base_totals.data(), 2, MPI_DOUBLE); - - for (int i = speciesPerModule[0]; i < phreeqc_init.size(); i++) { - std::vector init(n_cells, phreeqc_init[i]); - initial_values.push_back(std::move(init)); - } - - this->chem_field = Field(n_cells, initial_values, prop_names); - } else { - ChemBCast(base_totals.data(), 2, MPI_DOUBLE); - } - - if (this->params.use_dht || this->params.use_interp) { - initializeDHT(this->params.dht_size, this->params.dht_signifs); - setDHTSnapshots(this->params.dht_snaps, this->params.dht_outdir); - setDHTReadFile(this->params.dht_file); - - this->dht_enabled = this->params.use_dht; - - if (this->params.use_interp) { - initializeInterp(this->params.pht_max_entries, this->params.pht_size, - this->params.interp_min_entries, - this->params.pht_signifs); - this->interp_enabled = this->params.use_interp; - } - } -} - void poet::ChemistryModule::initializeDHT( uint32_t size_mb, const NamedVector &key_species) { - constexpr uint32_t MB_FACTOR = 1E6; + // constexpr uint32_t MB_FACTOR = 1E6; - this->dht_enabled = true; + // this->dht_enabled = true; - MPI_Comm dht_comm; + // MPI_Comm dht_comm; - if (this->is_master) { - MPI_Comm_split(this->group_comm, MPI_UNDEFINED, this->comm_rank, &dht_comm); - return; - } + // if (this->is_master) { + // MPI_Comm_split(this->group_comm, MPI_UNDEFINED, this->comm_rank, + // &dht_comm); return; + // } - if (!this->is_master) { + // if (!this->is_master) { - MPI_Comm_split(this->group_comm, 1, this->comm_rank, &dht_comm); + // MPI_Comm_split(this->group_comm, 1, this->comm_rank, &dht_comm); - auto map_copy = key_species; + // auto map_copy = key_species; - if (key_species.empty()) { - std::vector default_signif( - this->prop_names.size(), DHT_Wrapper::DHT_KEY_SIGNIF_DEFAULT); - map_copy = NamedVector(this->prop_names, default_signif); - } + // if (key_species.empty()) { + // std::vector default_signif( + // this->prop_names.size(), DHT_Wrapper::DHT_KEY_SIGNIF_DEFAULT); + // map_copy = NamedVector(this->prop_names, + // default_signif); + // } - auto key_indices = parseDHTSpeciesVec(key_species, this->prop_names); + // auto key_indices = parseDHTSpeciesVec(key_species, this->prop_names); - if (this->dht) { - delete this->dht; - } + // if (this->dht) { + // delete this->dht; + // } - const std::uint64_t dht_size = size_mb * MB_FACTOR; + // const std::uint64_t dht_size = size_mb * MB_FACTOR; - this->dht = new DHT_Wrapper(dht_comm, dht_size, map_copy, key_indices, - this->prop_names, params.hooks, - this->prop_count, params.use_interp); - this->dht->setBaseTotals(base_totals.at(0), base_totals.at(1)); - } + // this->dht = new DHT_Wrapper(dht_comm, dht_size, map_copy, key_indices, + // this->prop_names, params.hooks, + // this->prop_count, params.use_interp); + // this->dht->setBaseTotals(base_totals.at(0), base_totals.at(1)); + // } } inline std::vector poet::ChemistryModule::parseDHTSpeciesVec( @@ -457,42 +293,42 @@ void poet::ChemistryModule::initializeInterp( std::uint32_t bucket_size, std::uint32_t size_mb, std::uint32_t min_entries, const NamedVector &key_species) { - if (!this->is_master) { + // if (!this->is_master) { - constexpr uint32_t MB_FACTOR = 1E6; + // constexpr uint32_t MB_FACTOR = 1E6; - assert(this->dht); + // assert(this->dht); - this->interp_enabled = true; + // this->interp_enabled = true; - auto map_copy = key_species; + // auto map_copy = key_species; - if (key_species.empty()) { - map_copy = this->dht->getKeySpecies(); - for (std::size_t i = 0; i < map_copy.size(); i++) { - const std::uint32_t signif = - map_copy[i] - (map_copy[i] > InterpolationModule::COARSE_DIFF - ? InterpolationModule::COARSE_DIFF - : 0); - map_copy[i] = signif; - } - } + // if (key_species.empty()) { + // map_copy = this->dht->getKeySpecies(); + // for (std::size_t i = 0; i < map_copy.size(); i++) { + // const std::uint32_t signif = + // map_copy[i] - (map_copy[i] > InterpolationModule::COARSE_DIFF + // ? InterpolationModule::COARSE_DIFF + // : 0); + // map_copy[i] = signif; + // } + // } - auto key_indices = - parseDHTSpeciesVec(map_copy, dht->getKeySpecies().getNames()); + // auto key_indices = + // parseDHTSpeciesVec(map_copy, dht->getKeySpecies().getNames()); - if (this->interp) { - this->interp.reset(); - } + // if (this->interp) { + // this->interp.reset(); + // } - const uint64_t pht_size = size_mb * MB_FACTOR; + // const uint64_t pht_size = size_mb * MB_FACTOR; - interp = std::make_unique( - bucket_size, pht_size, min_entries, *(this->dht), map_copy, key_indices, - this->prop_names, this->params.hooks); + // interp = std::make_unique( + // bucket_size, pht_size, min_entries, *(this->dht), map_copy, + // key_indices, this->prop_names, this->params.hooks); - interp->setInterpolationFunction(inverseDistanceWeighting); - } + // interp->setInterpolationFunction(inverseDistanceWeighting); + // } } std::vector diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index d343ffa31..9ca8394ea 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -2,16 +2,17 @@ #ifndef CHEMISTRYMODULE_H_ #define CHEMISTRYMODULE_H_ -#include "../Base/SimParams.hpp" -#include "../DataStructures/DataStructures.hpp" +#include "DataStructures/Field.hpp" +#include "DataStructures/NamedVector.hpp" + +#include "ChemistryDefs.hpp" + +#include "Init/InitialList.hpp" #include "SurrogateModels/DHT_Wrapper.hpp" #include "SurrogateModels/Interpolation.hpp" -#include -#include - +#include "IPhreeqcPOET.hpp" #include -#include #include #include #include @@ -24,7 +25,7 @@ namespace poet { * \brief Wrapper around PhreeqcRM to provide POET specific parallelization with * easy access. */ -class ChemistryModule : public PhreeqcRM { +class ChemistryModule { public: /** * Creates a new instance of Chemistry module with given grid cell count, work @@ -41,45 +42,40 @@ public: * \param wp_size Count of grid cells to fill each work package at maximum. * \param communicator MPI communicator to distribute work in. */ - ChemistryModule(uint32_t nxyz, uint32_t wp_size, std::uint32_t maxiter, - const ChemistryParams &chem_param, MPI_Comm communicator); + ChemistryModule(uint32_t wp_size, + const InitialList::ChemistryInit &chem_params, + MPI_Comm communicator); /** * Deconstructor, which frees DHT data structure if used. */ ~ChemistryModule(); - /** - * Parses the input script and extract information needed during runtime. - * - * **Only run by master**. - * - * Database must be loaded beforehand. - * - * \param input_script_path Path to input script to parse. - */ - void RunInitFile(const std::string &input_script_path); - + void masterSetField(Field field); /** * Run the chemical simulation with parameters set. */ - void RunCells(); + void simulate(double dt); /** * Returns the chemical field. */ - auto GetField() const { return this->chem_field; } + auto &GetField() { return this->chem_field; } /** * Returns all known species names, including not only aqueous species, but * also equilibrium, exchange, surface and kinetic reactants. */ - auto GetPropNames() const { return this->prop_names; } + // auto GetPropNames() const { return this->prop_names; } /** * Return the accumulated runtime in seconds for chemical simulation. */ auto GetChemistryTime() const { return this->chem_t; } + void setFilePadding(std::uint32_t maxiter) { + this->file_pad = std::ceil(std::log10(maxiter + 1)); + } + /** * Create a new worker instance inside given MPI communicator. * @@ -118,17 +114,6 @@ public: DHT_SNAPS_ITEREND //!< output snapshots after each iteration }; - /** - * **This function has to be run!** - * - * Merge initial values from existing module with the chemistry module and set - * according internal variables. - * - * \param other Field to merge chemistry with. Most likely it is something - * like the diffusion field. - */ - void initializeField(const Field &other); - /** * **Only called by workers!** Start the worker listening loop. */ @@ -243,9 +228,7 @@ protected: const NamedVector &key_species); enum { - CHEM_INIT, - CHEM_WP_SIZE, - CHEM_INIT_SPECIES, + CHEM_FIELD_INIT, CHEM_DHT_ENABLE, CHEM_DHT_SIGNIF_VEC, CHEM_DHT_SNAPS, @@ -294,7 +277,7 @@ protected: using worker_list_t = std::vector; using workpointer_t = std::vector::iterator; - void MasterRunParallel(); + void MasterRunParallel(double dt); void MasterRunSequential(); void MasterSendPkgs(worker_list_t &w_list, workpointer_t &work_pointer, @@ -320,8 +303,8 @@ protected: void WorkerPerfToMaster(int type, const struct worker_s &timings); void WorkerMetricsToMaster(int type); - IRM_RESULT WorkerRunWorkPackage(WorkPackage &work_package, double dSimTime, - double dTimestep); + void WorkerRunWorkPackage(WorkPackage &work_package, double dSimTime, + double dTimestep); std::vector CalculateWPSizesVector(uint32_t n_cells, uint32_t wp_size) const; @@ -372,21 +355,18 @@ protected: bool print_progessbar{false}; - std::uint32_t file_pad; + std::uint32_t file_pad{1}; double chem_t{0.}; uint32_t n_cells = 0; uint32_t prop_count = 0; - std::vector prop_names; Field chem_field; - static constexpr int MODULE_COUNT = 5; + const InitialList::ChemistryInit ¶ms; - const ChemistryParams ¶ms; - - std::array speciesPerModule{}; + std::map> phreeqc_instances; }; } // namespace poet diff --git a/src/Chemistry/MasterFunctions.cpp b/src/Chemistry/MasterFunctions.cpp index 543cd21a8..9ee52be82 100644 --- a/src/Chemistry/MasterFunctions.cpp +++ b/src/Chemistry/MasterFunctions.cpp @@ -1,12 +1,9 @@ #include "ChemistryModule.hpp" -#include - #include #include #include #include -#include #include std::vector @@ -308,45 +305,46 @@ inline void poet::ChemistryModule::MasterRecvPkgs(worker_list_t &w_list, } } -void poet::ChemistryModule::RunCells() { +void poet::ChemistryModule::simulate(double dt) { double start_t{MPI_Wtime()}; if (this->is_sequential) { MasterRunSequential(); return; } - MasterRunParallel(); + MasterRunParallel(dt); double end_t{MPI_Wtime()}; this->chem_t += end_t - start_t; } void poet::ChemistryModule::MasterRunSequential() { - std::vector shuffled_field = - shuffleField(chem_field.AsVector(), n_cells, prop_count, 1); + // std::vector shuffled_field = + // shuffleField(chem_field.AsVector(), n_cells, prop_count, 1); - std::vector> input; - for (std::size_t i = 0; i < n_cells; i++) { - input.push_back( - std::vector(shuffled_field.begin() + (i * prop_count), - shuffled_field.begin() + ((i + 1) * prop_count))); - } + // std::vector> input; + // for (std::size_t i = 0; i < n_cells; i++) { + // input.push_back( + // std::vector(shuffled_field.begin() + (i * prop_count), + // shuffled_field.begin() + ((i + 1) * + // prop_count))); + // } - this->setDumpedField(input); - PhreeqcRM::RunCells(); - this->getDumpedField(input); + // this->setDumpedField(input); + // PhreeqcRM::RunCells(); + // this->getDumpedField(input); - shuffled_field.clear(); - for (std::size_t i = 0; i < n_cells; i++) { - shuffled_field.insert(shuffled_field.end(), input[i].begin(), - input[i].end()); - } + // shuffled_field.clear(); + // for (std::size_t i = 0; i < n_cells; i++) { + // shuffled_field.insert(shuffled_field.end(), input[i].begin(), + // input[i].end()); + // } - std::vector out_vec{shuffled_field}; - unshuffleField(shuffled_field, n_cells, prop_count, 1, out_vec); - chem_field = out_vec; + // std::vector out_vec{shuffled_field}; + // unshuffleField(shuffled_field, n_cells, prop_count, 1, out_vec); + // chem_field = out_vec; } -void poet::ChemistryModule::MasterRunParallel() { +void poet::ChemistryModule::MasterRunParallel(double dt) { /* declare most of the needed variables here */ double seq_a, seq_b, seq_c, seq_d; double worker_chemistry_a, worker_chemistry_b; @@ -360,7 +358,6 @@ void poet::ChemistryModule::MasterRunParallel() { MPI_Barrier(this->group_comm); - double dt = this->PhreeqcRM::GetTimeStep(); static uint32_t iteration = 0; /* start time measurement of sequential part */ @@ -466,3 +463,13 @@ poet::ChemistryModule::CalculateWPSizesVector(uint32_t n_cells, return wp_sizes_vector; } + +void poet::ChemistryModule::masterSetField(Field field) { + this->chem_field = field; + this->prop_count = field.GetProps().size(); + + int ftype = CHEM_FIELD_INIT; + PropagateFunctionType(ftype); + + ChemBCast(&this->prop_count, 1, MPI_UINT32_T); +} \ No newline at end of file diff --git a/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp b/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp index 69491b2c2..53ef72826 100644 --- a/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp +++ b/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp @@ -22,13 +22,14 @@ #include "DHT_Wrapper.hpp" +#include "Rounding.hpp" + #include #include #include #include #include #include -#include #include #include diff --git a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp index 791be2d1b..8b741f7e1 100644 --- a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp +++ b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp @@ -23,19 +23,18 @@ #ifndef DHT_WRAPPER_H #define DHT_WRAPPER_H -#include "../../Base/RInsidePOET.hpp" +#include "Base/RInsidePOET.hpp" +#include "DataStructures/NamedVector.hpp" + #include "../../Base/SimParams.hpp" -#include "../../DataStructures/DataStructures.hpp" -#include "../enums.hpp" -#include "HashFunctions.hpp" +#include "Chemistry/ChemistryDefs.hpp" + #include "LookupKey.hpp" -#include "Rounding.hpp" #include #include #include #include -#include #include #include diff --git a/src/Chemistry/SurrogateModels/Interpolation.hpp b/src/Chemistry/SurrogateModels/Interpolation.hpp index 15361f4bf..72b0ea3bd 100644 --- a/src/Chemistry/SurrogateModels/Interpolation.hpp +++ b/src/Chemistry/SurrogateModels/Interpolation.hpp @@ -3,14 +3,12 @@ #ifndef INTERPOLATION_H_ #define INTERPOLATION_H_ -#include "../../Base/SimParams.hpp" -#include "../../DataStructures/DataStructures.hpp" +#include "DataStructures/NamedVector.hpp" + #include "DHT_Wrapper.hpp" #include "LookupKey.hpp" #include "Rounding.hpp" -#include -#include #include #include #include @@ -22,7 +20,6 @@ extern "C" { } #include -#include #include #include diff --git a/src/Chemistry/SurrogateModels/InterpolationModule.cpp b/src/Chemistry/SurrogateModels/InterpolationModule.cpp index 26bfd4ab0..7dc64919b 100644 --- a/src/Chemistry/SurrogateModels/InterpolationModule.cpp +++ b/src/Chemistry/SurrogateModels/InterpolationModule.cpp @@ -1,8 +1,8 @@ // Time-stamp: "Last modified 2023-08-16 17:02:31 mluebke" #include "Interpolation.hpp" -#include "../../DataStructures/DataStructures.hpp" #include "DHT_Wrapper.hpp" +#include "DataStructures/NamedVector.hpp" #include "HashFunctions.hpp" #include "LookupKey.hpp" #include "Rounding.hpp" diff --git a/src/Chemistry/WorkerFunctions.cpp b/src/Chemistry/WorkerFunctions.cpp index 8cec96d62..6f4f81c6d 100644 --- a/src/Chemistry/WorkerFunctions.cpp +++ b/src/Chemistry/WorkerFunctions.cpp @@ -2,10 +2,8 @@ #include "SurrogateModels/DHT_Wrapper.hpp" #include "SurrogateModels/Interpolation.hpp" -#include -#include -#include -#include +#include "Chemistry/ChemistryDefs.hpp" + #include #include #include @@ -18,19 +16,6 @@ namespace poet { -struct WorkPackage { - std::size_t size; - std::vector> input; - std::vector> output; - std::vector mapping; - - WorkPackage(size_t _size) : size(_size) { - input.resize(size); - output.resize(size); - mapping.resize(size, CHEM_PQC); - } -}; - inline std::string get_string(int root, MPI_Comm communicator) { int count; MPI_Bcast(&count, 1, MPI_INT, root, communicator); @@ -59,13 +44,8 @@ void poet::ChemistryModule::WorkerLoop() { PropagateFunctionType(func_type); switch (func_type) { - case CHEM_INIT: { - RunInitFile(get_string(0, this->group_comm)); - break; - } - case CHEM_INIT_SPECIES: { - Field dummy; - initializeField(dummy); + case CHEM_FIELD_INIT: { + ChemBCast(&this->prop_count, 1, MPI_UINT32_T); break; } case CHEM_WORK_LOOP: { @@ -191,9 +171,7 @@ void poet::ChemistryModule::WorkerDoWork(MPI_Status &probe_status, phreeqc_time_start = MPI_Wtime(); - if (WorkerRunWorkPackage(s_curr_wp, current_sim_time, dt) != IRM_OK) { - std::cerr << "Phreeqc error" << std::endl; - }; + WorkerRunWorkPackage(s_curr_wp, current_sim_time, dt); phreeqc_time_end = MPI_Wtime(); @@ -299,42 +277,65 @@ void poet::ChemistryModule::WorkerReadDHTDump( } } -IRM_RESULT -poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, - double dSimTime, double dTimestep) { +void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, + double dSimTime, + double dTimestep) { // check if we actually need to start phreeqc - std::vector pqc_mapping; + bool queued_cell = false; - for (std::size_t i = 0; i < work_package.size; i++) { - if (work_package.mapping[i] == CHEM_PQC) { - pqc_mapping.push_back(i); + for (std::size_t wp_id = 0; wp_id < work_package.size; wp_id++) { + if (work_package.mapping[wp_id] != CHEM_PQC) { + continue; + } + + const auto &input = work_package.input[wp_id]; + const auto &sol_id = input[0]; + + auto &phreeqc_instance = this->phreeqc_instances[sol_id]; + work_package.output[wp_id] = work_package.input[wp_id]; + + work_package.input[wp_id].erase(work_package.input[wp_id].begin()); + + // remove NaNs from the input + work_package.input[wp_id].erase( + std::remove_if(work_package.input[wp_id].begin(), + work_package.input[wp_id].end(), + [](double d) { return std::isnan(d); }), + work_package.input[wp_id].end()); + + phreeqc_instance->queueCell(work_package.input[wp_id]); + queued_cell = true; + } + + if (!queued_cell) { + return; + } + + std::map> zone_mapping; + + // run the phreeqc instances + for (const auto &[pqc_id, phreeqc_instance] : this->phreeqc_instances) { + if (zone_mapping.find(pqc_id) == zone_mapping.end()) { + continue; + } + phreeqc_instance->runQueuedCells(dTimestep); + + // remap the output to the work_package + std::vector> pqc_out; + phreeqc_instance->dequeueCells(pqc_out); + + std::size_t output_id = 0; + + for (const auto &wp_id : zone_mapping[pqc_id]) { + std::size_t output_index = 0; + for (std::size_t i = 1; i < work_package.output[wp_id].size(); i++) { + if (!(std::isnan(work_package.output[wp_id][i]))) { + work_package.output[wp_id][i] = pqc_out[output_id][output_index++]; + } + } + output_id++; } } - - if (pqc_mapping.empty()) { - return IRM_OK; - } - - IRM_RESULT result; - this->PhreeqcRM::setPOETMapping(pqc_mapping); - this->setDumpedField(work_package.input); - - this->PhreeqcRM::SetTime(dSimTime); - this->PhreeqcRM::SetTimeStep(dTimestep); - - result = this->PhreeqcRM::RunCells(); - - std::vector> output_tmp(work_package.size); - - this->getDumpedField(output_tmp); - - for (std::size_t i = 0; i < work_package.size; i++) { - if (work_package.mapping[i] == CHEM_PQC) { - work_package.output[i] = output_tmp[i]; - } - } - - return result; } void poet::ChemistryModule::WorkerPerfToMaster(int type, diff --git a/src/Chemistry/enums.hpp b/src/Chemistry/enums.hpp deleted file mode 100644 index 11c3c1281..000000000 --- a/src/Chemistry/enums.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef ENUMS_H_ -#define ENUMS_H_ - -namespace poet { -enum DHT_PROP_TYPES { DHT_TYPE_DEFAULT, DHT_TYPE_CHARGE, DHT_TYPE_TOTAL }; - -enum CHEMISTRY_OUT_SOURCE { CHEM_PQC, CHEM_DHT, CHEM_INTERP }; -} // namespace poet - -#endif // ENUMS_H_ diff --git a/src/DataStructures/Field.hpp b/src/DataStructures/Field.hpp index 2f2269653..90119f2a6 100644 --- a/src/DataStructures/Field.hpp +++ b/src/DataStructures/Field.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index 2975eec2c..9b86d5c41 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -4,8 +4,6 @@ namespace poet { InitialList::ChemistryInit InitialList::getChemistryInit() const { ChemistryInit chem_init; - chem_init.initial_grid = Field(initial_grid); - chem_init.total_grid_cells = this->n_cols * this->n_rows; chem_init.database = database; diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 2b9d030ab..2ec7fab33 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -39,9 +39,9 @@ static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { static inline Rcpp::List matToGrid(RInside &R, const Rcpp::NumericMatrix &mat, const Rcpp::NumericMatrix &grid) { - Rcpp::Function pqc_to_grid("pqc_to_grid"); + Rcpp::Function pqc_to_grid_R("pqc_to_grid"); - return pqc_to_grid(mat, grid); + return pqc_to_grid_R(mat, grid); } static inline std::map diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 86c4ded77..cb11bd3d6 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -160,8 +160,6 @@ private: public: struct ChemistryInit { - Field initial_grid; - uint32_t total_grid_cells; std::string database; diff --git a/src/initializer.cpp b/src/initializer.cpp index 1f95babed..eacc45a72 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -18,7 +18,9 @@ int main(int argc, char **argv) { R.parseEvalQ(init_r_library); const std::string script = argv[1]; - R.parseEvalQ("source('" + script + "')"); + Rcpp::Function source_R("source"); + + source_R(script); Rcpp::List setup = R["setup"]; diff --git a/src/poet.cpp b/src/poet.cpp index fa7819460..f162b7820 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -23,6 +23,7 @@ #include "Base/Macros.hpp" #include "Base/RInsidePOET.hpp" // #include "Chemistry/ChemistryModule.hpp" +#include "Chemistry/ChemistryModule.hpp" #include "DataStructures/Field.hpp" #include "Init/InitialList.hpp" #include "Transport/DiffusionModule.hpp" @@ -48,41 +49,16 @@ using namespace Rcpp; static int MY_RANK = 0; -// poet::ChemistryModule::SingleCMap DFToHashMap(const Rcpp::DataFrame &df) { -// std::unordered_map out_map; -// vector col_names = Rcpp::as>(df.names()); - -// for (const auto &name : col_names) { -// double val = df[name.c_str()]; -// out_map.insert({name, val}); -// } - -// return out_map; -// } - // HACK: this is a step back as the order and also the count of fields is // predefined, but it will change in the future -void writeFieldsToR(RInside &R, const Field &trans) { - // , const Field &chem) { +void writeFieldsToR(RInside &R, const Field &trans, const Field &chem) { Rcpp::DataFrame t_field(trans.asSEXP()); - R["TMP"] = t_field; - R.parseEval("mysetup$state_T <- TMP"); + + R["TMP"] = chem.asSEXP(); R.parseEval("mysetup$state_C <- TMP"); - - // R["TMP"] = Rcpp::wrap(trans.AsVector()); - // R["TMP_PROPS"] = Rcpp::wrap(trans.GetProps()); - // R.parseEval(std::string( - // "mysetup$state_T <- setNames(data.frame(matrix(TMP, nrow=" + - // std::to_string(trans.GetRequestedVecSize()) + ")), TMP_PROPS)")); - - // R["TMP"] = Rcpp::wrap(chem.AsVector()); - // R["TMP_PROPS"] = Rcpp::wrap(chem.GetProps()); - // R.parseEval(std::string( - // "mysetup$state_C <- setNames(data.frame(matrix(TMP, nrow=" + - // std::to_string(chem.GetRequestedVecSize()) + ")), TMP_PROPS)")); } enum ParseRet { PARSER_OK, PARSER_ERROR, PARSER_HELP }; @@ -102,11 +78,12 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, return ParseRet::PARSER_HELP; } // if positional arguments are missing - else if (!cmdl(2)) { + if (!cmdl(3)) { if (MY_RANK == 0) { - ERRMSG("POET needs 2 positional arguments: "); - ERRMSG("1) the R script defining your simulation and"); - ERRMSG("2) the directory prefix where to save results and profiling"); + ERRMSG("POET needs 3 positional arguments: "); + ERRMSG("1) the R script defining your simulation runtime."); + ERRMSG("2) the initial .rds file generated by poet_init."); + ERRMSG("3) the directory prefix where to save results and profiling"); } return ParseRet::PARSER_ERROR; } @@ -203,8 +180,8 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, std::string runtime_file; std::string out_dir; - cmdl(1) >> init_file; - cmdl(2) >> runtime_file; + cmdl(1) >> runtime_file; + cmdl(2) >> init_file; cmdl(3) >> out_dir; // chem_params.dht_outdir = out_dir; @@ -300,7 +277,7 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, // } static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, - DiffusionModule &diffusion) { + DiffusionModule &diffusion, ChemistryModule &chem) { /* Iteration Count is dynamic, retrieving value from R (is only needed by * master for the following loop) */ @@ -320,7 +297,7 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, // chem.initializeField(diffusion.getField()); // if (params.getNumParams().print_progressbar) { - // chem.setProgressBarPrintout(true); + chem.setProgressBarPrintout(true); // } /* SIMULATION LOOP */ @@ -332,7 +309,7 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, // cout << "CPP: Evaluating next time step" << endl; // R.parseEvalQ("mysetup <- master_iteration_setup(mysetup)"); - double dt = params.timesteps[iter - 1]; + const double &dt = params.timesteps[iter - 1]; // cout << "CPP: Next time step is " << dt << "[s]" << endl; MSG("Next time step is " + std::to_string(dt) + " [s]"); @@ -347,14 +324,15 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, // TODO: transport to diffusion diffusion.simulate(dt); - // chem.getField().update(diffusion.getField()); + chem.GetField().update(diffusion.getField()); + + // chem.getfield().update(diffusion.getfield()); MSG("Chemistry step"); - // chem.SetTimeStep(dt); - // chem.RunCells(); + chem.simulate(dt); - writeFieldsToR(R, diffusion.getField()); + writeFieldsToR(R, diffusion.getField(), chem.GetField()); // diffusion.getField().update(chem.GetField()); R["req_dt"] = dt; @@ -431,7 +409,7 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, // R.parseEvalQ("profiling$interp_cached <- interp_cached"); // } - // chem.MasterLoopBreak(); + chem.MasterLoopBreak(); return dSimTime; } @@ -453,37 +431,6 @@ int main(int argc, char *argv[]) { MSG("Running POET version " + std::string(poet_version)); } - if (world_rank > 0) { - { - // 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; - // } - - // // ChemistryModule worker(nxyz, nxyz, MPI_COMM_WORLD); - // ChemistryModule worker = poet::ChemistryModule::createWorker( - // MPI_COMM_WORLD, params.getChemParams()); - // set_chem_parameters(worker, worker.GetWPSize(), - // params.getChemParams().database_path); - - // worker.WorkerLoop(); - } - - MPI_Barrier(MPI_COMM_WORLD); - - MSG("finished, cleanup of process " + std::to_string(world_rank)); - - MPI_Finalize(); - - return EXIT_SUCCESS; - } - /*Loading Dependencies*/ // TODO: kann raus R.parseEvalQ(kin_r_library); @@ -499,8 +446,25 @@ int main(int argc, char *argv[]) { break; } + InitialList init_list(R); + init_list.importList(run_params.init_params); + MSG("RInside initialized on process " + std::to_string(world_rank)); + if (world_rank > 0) { + + ChemistryModule worker(1, init_list.getChemistryInit(), MPI_COMM_WORLD); + worker.WorkerLoop(); + + MPI_Barrier(MPI_COMM_WORLD); + + MSG("finished, cleanup of process " + std::to_string(world_rank)); + + MPI_Finalize(); + + return EXIT_SUCCESS; + } + // R.parseEvalQ("mysetup <- setup"); // // if (world_rank == 0) { // get timestep vector from // // grid_init function ... // @@ -521,13 +485,14 @@ int main(int argc, char *argv[]) { // MPI_Barrier(MPI_COMM_WORLD); - InitialList init_list(R); - init_list.importList(run_params.init_params); - DiffusionModule diffusion(init_list.getDiffusionInit(), init_list.getInitialGrid()); - dSimTime = RunMasterLoop(R, run_params, diffusion); + ChemistryModule chemistry(1, init_list.getChemistryInit(), MPI_COMM_WORLD); + + chemistry.masterSetField(init_list.getInitialGrid()); + + dSimTime = RunMasterLoop(R, run_params, diffusion, chemistry); MSG("finished simulation loop"); From 08a2baba118cd4da547eba484b6a8533dc3e5199 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 09:16:58 +0000 Subject: [PATCH 23/77] Remove unnecessary includes and update function signature --- R_lib/kin_r_library.R | 37 +++++++++---------- src/Chemistry/WorkerFunctions.cpp | 59 ++++++++++++++++++++---------- src/Transport/DiffusionModule.cpp | 2 - src/poet.cpp | 61 +++++++++++++++---------------- 4 files changed, 86 insertions(+), 73 deletions(-) diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index d4d04f9e2..a314eb702 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -67,33 +67,32 @@ master_init <- function(setup) { ## This function, called only by master, stores on disk the last ## calculated time step if store_result is TRUE and increments the ## iteration counter -master_iteration_end <- function(setup) { +master_iteration_end <- function(setup,iter) { # iter <- setup$iter # print(iter) ## max digits for iterations - iter <- 1 - dgts <- as.integer(ceiling(log10(1))) + dgts <- as.integer(ceiling(log10(iter))) ## string format to use in sprintf fmt <- paste0("%0", dgts, "d") ## Write on disk state_T and state_C after every iteration ## comprised in setup$out_save - # if (setup$store_result) { - # if (iter %in% setup$out_save) { - nameout <- paste0(fileout, "/iter_", sprintf(fmt = fmt, iter), ".rds") - info <- list( - tr_req_dt = as.integer(1) - ## tr_allow_dt = setup$allowed_dt, - ## tr_inniter = as.integer(setup$inniter) - ) - saveRDS(list( - T = setup$state_T, C = setup$state_C, - simtime = as.integer(0), - tr_info = info - ), file = nameout) - msgm("results stored in <", nameout, ">") - # } - # } + if (setup$store_result) { + if (iter %in% setup$out_save) { + nameout <- paste0(fileout, "/iter_", sprintf(fmt = fmt, iter), ".rds") + info <- list( + tr_req_dt = as.integer(1) + ## tr_allow_dt = setup$allowed_dt, + ## tr_inniter = as.integer(setup$inniter) + ) + saveRDS(list( + T = setup$state_T, C = setup$state_C, + simtime = as.integer(0), + tr_info = info + ), file = nameout) + msgm("results stored in <", nameout, ">") + } + } msgm("done iteration", iter, "/", 1) setup$iter <- setup$iter + 1 return(setup) diff --git a/src/Chemistry/WorkerFunctions.cpp b/src/Chemistry/WorkerFunctions.cpp index 6f4f81c6d..d3d4edf23 100644 --- a/src/Chemistry/WorkerFunctions.cpp +++ b/src/Chemistry/WorkerFunctions.cpp @@ -281,7 +281,7 @@ void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, double dSimTime, double dTimestep) { // check if we actually need to start phreeqc - bool queued_cell = false; + std::map> zone_mapping; for (std::size_t wp_id = 0; wp_id < work_package.size; wp_id++) { if (work_package.mapping[wp_id] != CHEM_PQC) { @@ -289,9 +289,9 @@ void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, } const auto &input = work_package.input[wp_id]; - const auto &sol_id = input[0]; + const auto pqc_id = input[0]; - auto &phreeqc_instance = this->phreeqc_instances[sol_id]; + auto &phreeqc_instance = this->phreeqc_instances[pqc_id]; work_package.output[wp_id] = work_package.input[wp_id]; work_package.input[wp_id].erase(work_package.input[wp_id].begin()); @@ -304,38 +304,57 @@ void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, work_package.input[wp_id].end()); phreeqc_instance->queueCell(work_package.input[wp_id]); - queued_cell = true; + zone_mapping[pqc_id].push_back(wp_id); } - if (!queued_cell) { + if (zone_mapping.empty()) { return; } - std::map> zone_mapping; - - // run the phreeqc instances - for (const auto &[pqc_id, phreeqc_instance] : this->phreeqc_instances) { - if (zone_mapping.find(pqc_id) == zone_mapping.end()) { + for (const auto &[pqc_id, eval_cells] : zone_mapping) { + if (eval_cells.empty()) { continue; } - phreeqc_instance->runQueuedCells(dTimestep); - // remap the output to the work_package + this->phreeqc_instances[pqc_id]->runQueuedCells(dTimestep); + std::vector> pqc_out; - phreeqc_instance->dequeueCells(pqc_out); + this->phreeqc_instances[pqc_id]->dequeueCells(pqc_out); - std::size_t output_id = 0; - - for (const auto &wp_id : zone_mapping[pqc_id]) { + for (std::size_t i = 0; i < eval_cells.size(); i++) { + std::size_t wp_id = eval_cells[i]; std::size_t output_index = 0; - for (std::size_t i = 1; i < work_package.output[wp_id].size(); i++) { - if (!(std::isnan(work_package.output[wp_id][i]))) { - work_package.output[wp_id][i] = pqc_out[output_id][output_index++]; + for (std::size_t j = 1; j < work_package.output[wp_id].size(); j++) { + if (!(std::isnan(work_package.output[wp_id][j]))) { + work_package.output[wp_id][j] = pqc_out[i][output_index++]; } } - output_id++; } } + + // run the phreeqc instances + // for (const auto &[pqc_id, phreeqc_instance] : this->phreeqc_instances) { + // // if (zone_mapping.find(pqc_id) == zone_mapping.end()) { + // // continue; + // // } + // phreeqc_instance->runQueuedCells(dTimestep); + + // // remap the output to the work_package + // std::vector> pqc_out; + // phreeqc_instance->dequeueCells(pqc_out); + + // std::size_t output_id = 0; + + // for (const auto &wp_id : zone_mapping[pqc_id]) { + // std::size_t output_index = 0; + // for (std::size_t i = 1; i < work_package.output[wp_id].size(); i++) { + // if (!(std::isnan(work_package.output[wp_id][i]))) { + // work_package.output[wp_id][i] = pqc_out[output_id][output_index++]; + // } + // } + // output_id++; + // } + // } } void poet::ChemistryModule::WorkerPerfToMaster(int type, diff --git a/src/Transport/DiffusionModule.cpp b/src/Transport/DiffusionModule.cpp index 17f761b57..d81f0d885 100644 --- a/src/Transport/DiffusionModule.cpp +++ b/src/Transport/DiffusionModule.cpp @@ -35,8 +35,6 @@ #include "tug/Grid.hpp" #include "tug/Simulation.hpp" -#include -#include #include #include diff --git a/src/poet.cpp b/src/poet.cpp index f162b7820..1f6be971f 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -276,8 +276,9 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, // chem.LoadDatabase(database_path); // } -static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, - DiffusionModule &diffusion, ChemistryModule &chem) { +static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, + DiffusionModule &diffusion, + ChemistryModule &chem) { /* Iteration Count is dynamic, retrieving value from R (is only needed by * master for the following loop) */ @@ -333,7 +334,9 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, chem.simulate(dt); writeFieldsToR(R, diffusion.getField(), chem.GetField()); - // diffusion.getField().update(chem.GetField()); + // R["store_result"] = true; + // R.parseEval("mysetup$store_result <- TRUE"); + diffusion.getField().update(chem.GetField()); R["req_dt"] = dt; R["simtime"] = (sim_time += dt); @@ -341,11 +344,13 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, R.parseEval("mysetup$req_dt <- req_dt"); R.parseEval("mysetup$simtime <- simtime"); + R["iter"] = iter; + // 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.parseEval("mysetup <- master_iteration_end(setup=mysetup)"); + R.parseEval("mysetup <- master_iteration_end(setup=mysetup, iter)"); MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + std::to_string(maxiter)); @@ -356,31 +361,21 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, dSimTime += end_t - start_t; } // END SIMULATION LOOP - // R.parseEvalQ("profiling <- list()"); + Rcpp::List chem_profiling; + chem_profiling["simtime"] = chem.GetChemistryTime(); + chem_profiling["loop"] = chem.GetMasterLoopTime(); + chem_profiling["sequential"] = chem.GetMasterSequentialTime(); + chem_profiling["idle_master"] = chem.GetMasterIdleTime(); + chem_profiling["idle_worker"] = Rcpp::wrap(chem.GetWorkerIdleTimings()); + chem_profiling["phreeqc_time"] = Rcpp::wrap(chem.GetWorkerPhreeqcTimings()); - // R["simtime_chemistry"] = chem.GetChemistryTime(); - // R.parseEvalQ("profiling$simtime_chemistry <- simtime_chemistry"); + Rcpp::List diffusion_profiling; + diffusion_profiling["simtime"] = diffusion.getTransportTime(); - // R["chemistry_loop"] = chem.GetMasterLoopTime(); - // R.parseEvalQ("profiling$chemistry_loop <- chemistry_loop"); - - // R["chemistry_sequential"] = chem.GetMasterSequentialTime(); - // R.parseEvalQ("profiling$simtime_sequential <- chemistry_sequential"); - - // R["idle_master"] = chem.GetMasterIdleTime(); - // R.parseEvalQ("profiling$idle_master <- idle_master"); - - // R["idle_worker"] = Rcpp::wrap(chem.GetWorkerIdleTimings()); - // R.parseEvalQ("profiling$idle_worker <- idle_worker"); - - // R["phreeqc_time"] = Rcpp::wrap(chem.GetWorkerPhreeqcTimings()); - // R.parseEvalQ("profiling$phreeqc <- phreeqc_time"); - - // R["simtime_transport"] = diffusion.getTransportTime(); - // R.parseEvalQ("profiling$simtime_transport <- simtime_transport"); - - // R["phreeqc_count"] = phreeqc_counts; - // R.parseEvalQ("profiling$phreeqc_count <- phreeqc_count"); + Rcpp::List profiling; + profiling["simtime"] = dSimTime; + profiling["chemistry"] = chem_profiling; + profiling["diffusion"] = diffusion_profiling; // if (params.getChemParams().use_dht) { // R["dht_hits"] = Rcpp::wrap(chem.GetWorkerDHTHits()); @@ -411,7 +406,7 @@ static double RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, chem.MasterLoopBreak(); - return dSimTime; + return profiling; } int main(int argc, char *argv[]) { @@ -492,7 +487,7 @@ int main(int argc, char *argv[]) { chemistry.masterSetField(init_list.getInitialGrid()); - dSimTime = RunMasterLoop(R, run_params, diffusion, chemistry); + Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); MSG("finished simulation loop"); @@ -501,9 +496,11 @@ int main(int argc, char *argv[]) { // 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); + R["profiling"] = profiling; + + string r_vis_code; + r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; + R.parseEval(r_vis_code); // MSG("Done! Results are stored as R objects into <" + run_params.getOutDir() // + From fe4d71f68026fa2f915f5adf63e25b6e42289ea8 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 09:25:18 +0000 Subject: [PATCH 24/77] Update CMakeLists.txt and include headers in test files --- test/CMakeLists.txt | 2 +- test/testField.cpp | 5 +---- test/testNamedVector.cpp | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 884750735..2f2842b6d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB test_SRC "*.cpp" "*.c") add_executable(testPOET ${test_SRC}) -target_link_libraries(testPOET doctest poetlib) +target_link_libraries(testPOET doctest POETLib) target_include_directories(testPOET PRIVATE "${PROJECT_SOURCE_DIR}/src") get_filename_component(TEST_RInsideSourceFile "RInsidePOET_funcs.R" REALPATH) diff --git a/test/testField.cpp b/test/testField.cpp index acfe8d1a8..0800b4dbd 100644 --- a/test/testField.cpp +++ b/test/testField.cpp @@ -1,15 +1,12 @@ #include -#include -#include #include #include #include -#include #include #include #include -#include +#include #include "testDataStructures.hpp" diff --git a/test/testNamedVector.cpp b/test/testNamedVector.cpp index d5ee908f5..7b86c7496 100644 --- a/test/testNamedVector.cpp +++ b/test/testNamedVector.cpp @@ -1,11 +1,10 @@ #include #include #include -#include #include #include -#include +#include #include "testDataStructures.hpp" From 5d46360c33fb18dd5501deb67e5dcd65b64a6f76 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 09:43:30 +0000 Subject: [PATCH 25/77] Remove doctest submodule and update gitmodules --- .devcontainer/Dockerfile | 12 ++++++++++-- .gitlab-ci.yml | 2 +- .gitmodules | 8 +------- CMakeLists.txt | 1 - ext/doctest | 1 - ext/tug | 2 +- test/CMakeLists.txt | 4 +++- util/ci.Dockerfile | 11 ----------- 8 files changed, 16 insertions(+), 25 deletions(-) delete mode 160000 ext/doctest delete mode 100644 util/ci.Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8016eb576..07e77023c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,10 +3,18 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:debian RUN sudo apt-get update && export DEBIAN_FRONTEND=noninteractive \ && sudo apt-get install -y \ cmake-curses-gui \ - clangd \ git \ libeigen3-dev \ libopenmpi-dev \ r-cran-rcpp \ - r-cran-rinside + r-cran-rinside \ + gdb +RUN git clone https://github.com/doctest/doctest.git /doctest \ + && cd /doctest \ + && mkdir build \ + && cd build \ + && cmake .. \ + && make install \ + && cd / \ + && rm -rf /doctest diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46f15eb8b..c861d40a3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ stages: # List of stages for jobs, and their order of execution - test variables: - GIT_SUBMODULE_STRATEGY: recursive +# GIT_SUBMODULE_STRATEGY: recursive SOURCE_ARCHIVE_NAME: 'poet_${CI_COMMIT_TAG}_sources.tar.gz' CHANGELOG_FILE: 'commit_changelog.md' diff --git a/.gitmodules b/.gitmodules index 645e48d00..26a3acc7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,12 +2,6 @@ path = ext/tug url = ../tug.git -[submodule "ext/doctest"] - path = ext/doctest - url = https://github.com/doctest/doctest.git -[submodule "ext/phreeqc"] - path = ext/phreeqc - url = git@git.gfz-potsdam.de:naaice/phreeqcpoet.git [submodule "ext/iphreeqc"] path = ext/iphreeqc - url = git@git.gfz-potsdam.de:naaice/iphreeqc.git + url = ../iphreeqc.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a57f557df..1873d6ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ add_subdirectory(ext/iphreeqc EXCLUDE_FROM_ALL) option(POET_ENABLE_TESTING "Build test suite for POET" OFF) if (POET_ENABLE_TESTING) - add_subdirectory(ext/doctest EXCLUDE_FROM_ALL) add_subdirectory(test) endif() diff --git a/ext/doctest b/ext/doctest deleted file mode 160000 index ae7a13539..000000000 --- a/ext/doctest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae7a13539fb71f270b87eb2e874fbac80bc8dda2 diff --git a/ext/tug b/ext/tug index 3ffa0ef62..b104fdcf5 160000 --- a/ext/tug +++ b/ext/tug @@ -1 +1 @@ -Subproject commit 3ffa0ef6242d467a269be83751c857cb24ae532e +Subproject commit b104fdcf5238a8a2948b4e835b2d99b64758bb2a diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2f2842b6d..8bc494158 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,8 +2,10 @@ file(GLOB test_SRC CONFIGURE_DEPENDS "*.cpp" "*.c") +find_package(doctest REQUIRED) + add_executable(testPOET ${test_SRC}) -target_link_libraries(testPOET doctest POETLib) +target_link_libraries(testPOET doctest::doctest POETLib) target_include_directories(testPOET PRIVATE "${PROJECT_SOURCE_DIR}/src") get_filename_component(TEST_RInsideSourceFile "RInsidePOET_funcs.R" REALPATH) diff --git a/util/ci.Dockerfile b/util/ci.Dockerfile deleted file mode 100644 index e795879a5..000000000 --- a/util/ci.Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM debian - -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get install -y \ - cmake \ - git \ - libeigen3-dev \ - libopenmpi-dev \ - r-cran-rcpp \ - r-cran-rinside \ - libssl-dev \ No newline at end of file From 1c004dfda9951e013ee8d483f46b633c37dc619d Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 11:39:59 +0000 Subject: [PATCH 26/77] Update dependencies and refactor code --- ext/iphreeqc | 2 +- src/poet.cpp | 29 +++++++++++------------------ src/poet.hpp.in | 4 ++++ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/ext/iphreeqc b/ext/iphreeqc index f69561987..daeecf112 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit f695619875fcf43e411af67d592c05b199f41a15 +Subproject commit daeecf11263dbeb08cb13b43df81d5d9dcc22060 diff --git a/src/poet.cpp b/src/poet.cpp index 1f6be971f..ecb5b5bf8 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -22,27 +22,21 @@ #include "Base/Macros.hpp" #include "Base/RInsidePOET.hpp" -// #include "Chemistry/ChemistryModule.hpp" #include "Chemistry/ChemistryModule.hpp" #include "DataStructures/Field.hpp" #include "Init/InitialList.hpp" #include "Transport/DiffusionModule.hpp" #include -#include -#include -#include -#include - #include #include - +#include #include -#include - #include "Base/argh.hpp" +#include + using namespace std; using namespace poet; using namespace Rcpp; @@ -110,9 +104,11 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, } } - // simparams.print_progressbar = cmdl[{"P", "progress"}]; + params.print_progressbar = cmdl[{"P", "progress"}]; - // // simparams.print_progressbar = cmdl[{"P", "progress"}]; + /*Parse work package size*/ + cmdl("work-package-size", CHEM_DEFAULT_WORK_PACKAGE_SIZE) >> + params.work_package_size; // /* Parse DHT arguments */ // chem_params.use_dht = cmdl["dht"]; @@ -136,9 +132,6 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, // /*Parse output options*/ // simparams.store_result = !cmdl["ignore-result"]; - // /*Parse work package size*/ - // cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; - // chem_params.use_interp = cmdl["interp"]; // cmdl("interp-size", 100) >> chem_params.pht_size; // cmdl("interp-min", 5) >> chem_params.interp_min_entries; @@ -446,10 +439,12 @@ int main(int argc, char *argv[]) { MSG("RInside initialized on process " + std::to_string(world_rank)); + ChemistryModule chemistry(run_params.work_package_size, + init_list.getChemistryInit(), MPI_COMM_WORLD); + if (world_rank > 0) { - ChemistryModule worker(1, init_list.getChemistryInit(), MPI_COMM_WORLD); - worker.WorkerLoop(); + chemistry.WorkerLoop(); MPI_Barrier(MPI_COMM_WORLD); @@ -483,8 +478,6 @@ int main(int argc, char *argv[]) { DiffusionModule diffusion(init_list.getDiffusionInit(), init_list.getInitialGrid()); - ChemistryModule chemistry(1, init_list.getChemistryInit(), MPI_COMM_WORLD); - chemistry.masterSetField(init_list.getInitialGrid()); Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); diff --git a/src/poet.hpp.in b/src/poet.hpp.in index 99b3e7a58..dcf71b972 100644 --- a/src/poet.hpp.in +++ b/src/poet.hpp.in @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -43,10 +44,13 @@ const std::set paramlist{ "work-package-size", "dht-strategy", "dht-size", "dht-snaps", "dht-file", "interp-size", "interp-min", "interp-bucket-entries"}; +constexpr uint32_t CHEM_DEFAULT_WORK_PACKAGE_SIZE = 32; + struct RuntimeParameters { std::vector timesteps; bool print_progressbar; + uint32_t work_package_size; Rcpp::List init_params; From d196d3c25d9ccc0b9a4d078f7637c2a88774f7a8 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 11:40:25 +0000 Subject: [PATCH 27/77] Add dolo_200_rt.R, dol.pqi, and dolo_200.R files for simulation setup --- bench/dolo/het/dol.pqi | 42 + bench/dolo/het/dolo_200.R | 35 + bench/dolo/het/dolo_200_rt.R | 8 + bench/dolo/het/phreeqc_kin.dat | 1307 ++++++++++++++++++++++++++++++++ 4 files changed, 1392 insertions(+) create mode 100644 bench/dolo/het/dol.pqi create mode 100644 bench/dolo/het/dolo_200.R create mode 100644 bench/dolo/het/dolo_200_rt.R create mode 100644 bench/dolo/het/phreeqc_kin.dat diff --git a/bench/dolo/het/dol.pqi b/bench/dolo/het/dol.pqi new file mode 100644 index 000000000..ae556bc5a --- /dev/null +++ b/bench/dolo/het/dol.pqi @@ -0,0 +1,42 @@ +SOLUTION 1 + units mol/kgw + water 1 + temperature 25 + pH 7 + pe 4 + C 1e-12 + Ca 1e-12 + Cl 1e-12 + Mg 1e-12 +PURE 1 + Calcite 0.0 1 +END + +RUN_CELLS + -cells 1 + +COPY solution 1 2 + +PURE 2 + O2g -0.1675 10 +KINETICS 2 + Calcite + -m 0.000207 + -parms 0.0032 + -tol 1e-10 + Dolomite + -m 0.0 + -parms 0.00032 + -tol 1e-10 +END + +SOLUTION 3 + pH 7 + water 1 + temp 25 + Mg 0.001 + Cl 0.002 +END + +RUN_CELLS + -cells 2-3 diff --git a/bench/dolo/het/dolo_200.R b/bench/dolo/het/dolo_200.R new file mode 100644 index 000000000..87bf4951f --- /dev/null +++ b/bench/dolo/het/dolo_200.R @@ -0,0 +1,35 @@ +grid_def <- matrix(2, nrow = 200, ncol = 200) + +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./dol.pqi", + pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(ncol(grid_def), nrow(grid_def)), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) + +bound_size <- 2 + +diffusion_setup <- list( + boundaries = list( + "W" = list( + "type" = rep("constant", bound_size), + "sol_id" = rep(3, bound_size), + "cell" = seq(1, bound_size) + ), + "N" = list( + "type" = rep("constant", bound_size), + "sol_id" = rep(3, bound_size), + "cell" = seq(1, bound_size) + ) + ), + alpha_x = 1e-6, + alpha_y = 1e-6 +) + +# Define a setup list for simulation configuration +setup <- list( + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup # Parameters related to the diffusion process +) diff --git a/bench/dolo/het/dolo_200_rt.R b/bench/dolo/het/dolo_200_rt.R new file mode 100644 index 000000000..88e382432 --- /dev/null +++ b/bench/dolo/het/dolo_200_rt.R @@ -0,0 +1,8 @@ +iterations <- 500 +dt <- 50 + +list( + timesteps = rep(dt, iterations), + store_result = TRUE, + out_save = c(5, iterations, by = 5) +) \ No newline at end of file diff --git a/bench/dolo/het/phreeqc_kin.dat b/bench/dolo/het/phreeqc_kin.dat new file mode 100644 index 000000000..01d5bf516 --- /dev/null +++ b/bench/dolo/het/phreeqc_kin.dat @@ -0,0 +1,1307 @@ +### This is the standard "phreeqc.dat" stripped of EXCHANGE and +### SURFACE and with the RATES for Calcite and Dolomite to use with +### RedModRphree + +### Time-stamp: "Last modified 2023-05-23 10:35:56 mluebke" + +# PHREEQC.DAT for calculating pressure dependence of reactions, with +# molal volumina of aqueous species and of minerals, and +# critical temperatures and pressures of gases used in Peng-Robinson's EOS. +# Details are given at the end of this file. + +SOLUTION_MASTER_SPECIES +# +#element species alk gfw_formula element_gfw +# +H H+ -1.0 H 1.008 +H(0) H2 0 H +H(1) H+ -1.0 0 +E e- 0 0.0 0 +O H2O 0 O 16.0 +O(0) O2 0 O +O(-2) H2O 0 0 +Ca Ca+2 0 Ca 40.08 +Mg Mg+2 0 Mg 24.312 +Na Na+ 0 Na 22.9898 +K K+ 0 K 39.102 +Fe Fe+2 0 Fe 55.847 +Fe(+2) Fe+2 0 Fe +Fe(+3) Fe+3 -2.0 Fe +Mn Mn+2 0 Mn 54.938 +Mn(+2) Mn+2 0 Mn +Mn(+3) Mn+3 0 Mn +Al Al+3 0 Al 26.9815 +Ba Ba+2 0 Ba 137.34 +Sr Sr+2 0 Sr 87.62 +Si H4SiO4 0 SiO2 28.0843 +Cl Cl- 0 Cl 35.453 +C CO3-2 2.0 HCO3 12.0111 +C(+4) CO3-2 2.0 HCO3 +C(-4) CH4 0 CH4 +Alkalinity CO3-2 1.0 Ca0.5(CO3)0.5 50.05 +S SO4-2 0 SO4 32.064 +S(6) SO4-2 0 SO4 +S(-2) HS- 1.0 S +N NO3- 0 N 14.0067 +N(+5) NO3- 0 N +N(+3) NO2- 0 N +N(0) N2 0 N +N(-3) NH4+ 0 N 14.0067 +#Amm AmmH+ 0 AmmH 17.0 +B H3BO3 0 B 10.81 +P PO4-3 2.0 P 30.9738 +F F- 0 F 18.9984 +Li Li+ 0 Li 6.939 +Br Br- 0 Br 79.904 +Zn Zn+2 0 Zn 65.37 +Cd Cd+2 0 Cd 112.4 +Pb Pb+2 0 Pb 207.19 +Cu Cu+2 0 Cu 63.546 +Cu(+2) Cu+2 0 Cu +Cu(+1) Cu+1 0 Cu +# redox-uncoupled gases +Hdg Hdg 0 Hdg 2.016 # H2 gas +Oxg Oxg 0 Oxg 32 # O2 gas +Mtg Mtg 0 Mtg 16.032 # CH4 gas +Sg H2Sg 1.0 H2Sg 34.08 +Ntg Ntg 0 Ntg 28.0134 # N2 gas + +SOLUTION_SPECIES +H+ = H+ + -gamma 9.0 0 + -dw 9.31e-9 +e- = e- +H2O = H2O +Ca+2 = Ca+2 + -gamma 5.0 0.1650 + -dw 0.793e-9 + -Vm -0.3456 -7.252 6.149 -2.479 1.239 5 1.60 -57.1 -6.12e-3 1 # ref. 1 +Mg+2 = Mg+2 + -gamma 5.5 0.20 + -dw 0.705e-9 + -Vm -1.410 -8.6 11.13 -2.39 1.332 5.5 1.29 -32.9 -5.86e-3 1 # ref. 1 +Na+ = Na+ + -gamma 4.0 0.075 + -gamma 4.08 0.082 # halite solubility + -dw 1.33e-9 + -Vm 2.28 -4.38 -4.1 -0.586 0.09 4 0.3 52 -3.33e-3 0.566 # ref. 1 +# for calculating densities (rho) when I > 3... + # -Vm 2.28 -4.38 -4.1 -0.586 0.09 4 0.3 52 -3.33e-3 0.45 +K+ = K+ + -gamma 3.5 0.015 + -dw 1.96e-9 + -Vm 3.322 -1.473 6.534 -2.712 9.06e-2 3.5 0 29.7 0 1 # ref. 1 +Fe+2 = Fe+2 + -gamma 6.0 0 + -dw 0.719e-9 + -Vm -0.3255 -9.687 1.536 -2.379 0.3033 6 -4.21e-2 39.7 0 1 # ref. 1 +Mn+2 = Mn+2 + -gamma 6.0 0 + -dw 0.688e-9 + -Vm -1.10 -8.03 4.08 -2.45 1.4 6 8.07 0 -1.51e-2 0.118 # ref. 2 +Al+3 = Al+3 + -gamma 9.0 0 + -dw 0.559e-9 + -Vm -2.28 -17.1 10.9 -2.07 2.87 9 0 0 5.5e-3 1 # ref. 2 and Barta and Hepler, 1986, Can. J.C. 64, 353. +Ba+2 = Ba+2 + -gamma 5.0 0 + -gamma 4.0 0.153 # Barite solubility + -dw 0.848e-9 + -Vm 2.063 -10.06 1.9534 -2.36 0.4218 5 1.58 -12.03 -8.35e-3 1 # ref. 1 +Sr+2 = Sr+2 + -gamma 5.260 0.121 + -dw 0.794e-9 + -Vm -1.57e-2 -10.15 10.18 -2.36 0.860 5.26 0.859 -27.0 -4.1e-3 1.97 # ref. 1 +H4SiO4 = H4SiO4 + -dw 1.10e-9 + -Vm 10.5 1.7 20 -2.7 0.1291 # supcrt + 2*H2O in a1 +Cl- = Cl- + -gamma 3.5 0.015 + -gamma 3.63 0.017 # cf. pitzer.dat + -dw 2.03e-9 + -Vm 4.465 4.801 4.325 -2.847 1.748 0 -0.331 20.16 0 1 # ref. 1 +CO3-2 = CO3-2 + -gamma 5.4 0 + -dw 0.955e-9 + -Vm 5.95 0 0 -5.67 6.85 0 1.37 106 -0.0343 1 # ref. 1 +SO4-2 = SO4-2 + -gamma 5.0 -0.04 + -dw 1.07e-9 + -Vm 8.0 2.3 -46.04 6.245 3.82 0 0 0 0 1 # ref. 1 +NO3- = NO3- + -gamma 3.0 0 + -dw 1.9e-9 + -Vm 6.32 6.78 0 -3.06 0.346 0 0.93 0 -0.012 1 # ref. 1 +#AmmH+ = AmmH+ +# -gamma 2.5 0 +# -dw 1.98e-9 +# -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # ref. 1 +H3BO3 = H3BO3 + -dw 1.1e-9 + -Vm 7.0643 8.8547 3.5844 -3.1451 -.2000 # supcrt +PO4-3 = PO4-3 + -gamma 4.0 0 + -dw 0.612e-9 + -Vm 1.24 -9.07 9.31 -2.4 5.61 0 0 0 -1.41e-2 1 # ref. 2 +F- = F- + -gamma 3.5 0 + -dw 1.46e-9 + -Vm 0.928 1.36 6.27 -2.84 1.84 0 0 -0.318 0 1 # ref. 2 +Li+ = Li+ + -gamma 6.0 0 + -dw 1.03e-9 + -Vm -0.419 -0.069 13.16 -2.78 0.416 0 0.296 -12.4 -2.74e-3 1.26 # ref. 2 and Ellis, 1968, J. Chem. Soc. A, 1138 +Br- = Br- + -gamma 3.0 0 + -dw 2.01e-9 + -Vm 6.72 2.85 4.21 -3.14 1.38 0 -9.56e-2 7.08 -1.56e-3 1 # ref. 2 +Zn+2 = Zn+2 + -gamma 5.0 0 + -dw 0.715e-9 + -Vm -1.96 -10.4 14.3 -2.35 1.46 5 -1.43 24 1.67e-2 1.11 # ref. 2 +Cd+2 = Cd+2 + -dw 0.717e-9 + -Vm 1.63 -10.7 1.01 -2.34 1.47 5 0 0 0 1 # ref. 2 +Pb+2 = Pb+2 + -dw 0.945e-9 + -Vm -.0051 -7.7939 8.8134 -2.4568 1.0788 4.5 # supcrt +Cu+2 = Cu+2 + -gamma 6.0 0 + -dw 0.733e-9 + -Vm -1.13 -10.5 7.29 -2.35 1.61 6 9.78e-2 0 3.42e-3 1 # ref. 2 +# redox-uncoupled gases +Hdg = Hdg # H2 + -dw 5.13e-9 + -Vm 6.52 0.78 0.12 # supcrt +Oxg = Oxg # O2 + -dw 2.35e-9 + -Vm 5.7889 6.3536 3.2528 -3.0417 -0.3943 # supcrt +Mtg = Mtg # CH4 + -dw 1.85e-9 + -Vm 7.7 # CH4 solubility, 25-100C, 1-700atm +Ntg = Ntg # N2 + -dw 1.96e-9 + -Vm 7 # Pray et al., 1952, IEC 44. 1146 +H2Sg = H2Sg # H2S + -dw 2.1e-9 + -Vm 7.81 2.96 -0.46 # supcrt +# aqueous species +H2O = OH- + H+ + -analytic 293.29227 0.1360833 -10576.913 -123.73158 0 -6.996455e-5 + -gamma 3.5 0 + -dw 5.27e-9 + -Vm -9.66 28.5 80.0 -22.9 1.89 0 1.09 0 0 1 # ref. 1 +2 H2O = O2 + 4 H+ + 4 e- + -log_k -86.08 + -delta_h 134.79 kcal + -dw 2.35e-9 + -Vm 5.7889 6.3536 3.2528 -3.0417 -0.3943 # supcrt +2 H+ + 2 e- = H2 + -log_k -3.15 + -delta_h -1.759 kcal + -dw 5.13e-9 + -Vm 6.52 0.78 0.12 # supcrt +CO3-2 + H+ = HCO3- + -log_k 10.329 + -delta_h -3.561 kcal + -analytic 107.8871 0.03252849 -5151.79 -38.92561 563713.9 + -gamma 5.4 0 + -dw 1.18e-9 + -Vm 8.472 0 -11.5 0 1.56 0 0 146 3.16e-3 1 # ref. 1 +CO3-2 + 2 H+ = CO2 + H2O + -log_k 16.681 + -delta_h -5.738 kcal + -analytic 464.1965 0.09344813 -26986.16 -165.75951 2248628.9 + -dw 1.92e-9 + -Vm 20.85 -46.93 -79.0 27.9 -0.193 # ref. 1 +CO3-2 + 10 H+ + 8 e- = CH4 + 3 H2O + -log_k 41.071 + -delta_h -61.039 kcal + -dw 1.85e-9 + -Vm 7.7 +SO4-2 + H+ = HSO4- + -log_k 1.988 + -delta_h 3.85 kcal + -analytic -56.889 0.006473 2307.9 19.8858 + -dw 1.33e-9 + -Vm 8.2 9.2590 2.1108 -3.1618 1.1748 0 -0.3 15 0 1 # ref. 1 +HS- = S-2 + H+ + -log_k -12.918 + -delta_h 12.1 kcal + -gamma 5.0 0 + -dw 0.731e-9 +SO4-2 + 9 H+ + 8 e- = HS- + 4 H2O + -log_k 33.65 + -delta_h -60.140 kcal + -gamma 3.5 0 + -dw 1.73e-9 + -Vm 5.0119 4.9799 3.4765 -2.9849 1.4410 # supcrt +HS- + H+ = H2S + -log_k 6.994 + -delta_h -5.30 kcal + -analytical -11.17 0.02386 3279.0 + -dw 2.1e-9 + -Vm 7.81 2.96 -0.46 # supcrt +H2Sg = HSg- + H+ + -log_k -6.994 + -delta_h 5.30 kcal + -analytical 11.17 -0.02386 -3279.0 + -dw 2.1e-9 + -Vm 5.0119 4.9799 3.4765 -2.9849 1.4410 # supcrt +NO3- + 2 H+ + 2 e- = NO2- + H2O + -log_k 28.570 + -delta_h -43.760 kcal + -gamma 3.0 0 + -dw 1.91e-9 + -Vm 5.5864 5.8590 3.4472 -3.0212 1.1847 # supcrt +2 NO3- + 12 H+ + 10 e- = N2 + 6 H2O + -log_k 207.08 + -delta_h -312.130 kcal + -dw 1.96e-9 + -Vm 7 # Pray et al., 1952, IEC 44. 1146 +NO3- + 10 H+ + 8 e- = NH4+ + 3 H2O + -log_k 119.077 + -delta_h -187.055 kcal + -gamma 2.5 0 + -dw 1.98e-9 + -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # ref. 1 +#AmmH+ = AmmH+ +# -gamma 2.5 0.0 +# -dw 1.98e-9 +# -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # supcrt modified +NH4+ = NH3 + H+ + -log_k -9.252 + -delta_h 12.48 kcal + -analytic 0.6322 -0.001225 -2835.76 + -dw 2.28e-9 + -Vm 6.69 2.8 3.58 -2.88 1.43 # ref. 2 +#AmmH+ = Amm + H+ +# -log_k -9.252 +# -delta_h 12.48 kcal +# -analytic 0.6322 -0.001225 -2835.76 +# -dw 2.28e-9 +# -Vm 6.69 2.8 3.58 -2.88 1.43 # ref. 2 +NH4+ + SO4-2 = NH4SO4- + log_k 1.11 + -Vm 14.0 0 -35.2 0 0 0 12.3 0 -0.141 1 # ref. 2 +#AmmH+ + SO4-2 = AmmHSO4- +# -log_k 1.11 +# -Vm 14.0 0 -35.2 0 0 0 12.3 0 -0.141 1 # ref. 2 +H3BO3 = H2BO3- + H+ + -log_k -9.24 + -delta_h 3.224 kcal +H3BO3 + F- = BF(OH)3- + -log_k -0.4 + -delta_h 1.850 kcal +H3BO3 + 2 F- + H+ = BF2(OH)2- + H2O + -log_k 7.63 + -delta_h 1.618 kcal +H3BO3 + 2 H+ + 3 F- = BF3OH- + 2 H2O + -log_k 13.67 + -delta_h -1.614 kcal +H3BO3 + 3 H+ + 4 F- = BF4- + 3 H2O + -log_k 20.28 + -delta_h -1.846 kcal +PO4-3 + H+ = HPO4-2 + -log_k 12.346 + -delta_h -3.530 kcal + -gamma 5.0 0 + -dw 0.69e-9 + -Vm 3.52 1.09 8.39 -2.82 3.34 0 0 0 0 1 # ref. 2 +PO4-3 + 2 H+ = H2PO4- + -log_k 19.553 + -delta_h -4.520 kcal + -gamma 5.4 0 + -dw 0.846e-9 + -Vm 5.58 8.06 12.2 -3.11 1.3 0 0 0 1.62e-2 1 # ref. 2 +PO4-3 + 3H+ = H3PO4 + log_k 21.721 # log_k and delta_h from minteq.v4.dat, NIST46.3 + delta_h -10.1 kJ + -Vm 7.47 12.4 6.29 -3.29 0 # ref. 2 +H+ + F- = HF + -log_k 3.18 + -delta_h 3.18 kcal + -analytic -2.033 0.012645 429.01 + -Vm 3.4753 .7042 5.4732 -2.8081 -.0007 # supcrt +H+ + 2 F- = HF2- + -log_k 3.76 + -delta_h 4.550 kcal + -Vm 5.2263 4.9797 3.7928 -2.9849 1.2934 # supcrt +Ca+2 + H2O = CaOH+ + H+ + -log_k -12.78 +Ca+2 + CO3-2 = CaCO3 + -log_k 3.224 + -delta_h 3.545 kcal + -analytic -1228.732 -0.299440 35512.75 485.818 + -dw 4.46e-10 # complexes: calc'd with the Pikal formula + -Vm -.2430 -8.3748 9.0417 -2.4328 -.0300 # supcrt +Ca+2 + CO3-2 + H+ = CaHCO3+ + -log_k 11.435 + -delta_h -0.871 kcal + -analytic 1317.0071 0.34546894 -39916.84 -517.70761 563713.9 + -gamma 6.0 0 + -dw 5.06e-10 + -Vm 3.1911 .0104 5.7459 -2.7794 .3084 5.4 # supcrt +Ca+2 + SO4-2 = CaSO4 + -log_k 2.25 + -delta_h 1.325 kcal + -dw 4.71e-10 + -Vm 2.7910 -.9666 6.1300 -2.7390 -.0010 # supcrt +Ca+2 + HSO4- = CaHSO4+ + -log_k 1.08 +Ca+2 + PO4-3 = CaPO4- + -log_k 6.459 + -delta_h 3.10 kcal + -gamma 5.4 0.0 +Ca+2 + HPO4-2 = CaHPO4 + -log_k 2.739 + -delta_h 3.3 kcal +Ca+2 + H2PO4- = CaH2PO4+ + -log_k 1.408 + -delta_h 3.4 kcal + -gamma 5.4 0.0 +# Ca+2 + F- = CaF+ + # -log_k 0.94 + # -delta_h 4.120 kcal + # -gamma 5.5 0.0 + # -Vm .9846 -5.3773 7.8635 -2.5567 .6911 5.5 # supcrt +Mg+2 + H2O = MgOH+ + H+ + -log_k -11.44 + -delta_h 15.952 kcal + -gamma 6.5 0 +Mg+2 + CO3-2 = MgCO3 + -log_k 2.98 + -delta_h 2.713 kcal + -analytic 0.9910 0.00667 + -dw 4.21e-10 + -Vm -.5837 -9.2067 9.3687 -2.3984 -.0300 # supcrt +Mg+2 + H+ + CO3-2 = MgHCO3+ + -log_k 11.399 + -delta_h -2.771 kcal + -analytic 48.6721 0.03252849 -2614.335 -18.00263 563713.9 + -gamma 4.0 0 + -dw 4.78e-10 + -Vm 2.7171 -1.1469 6.2008 -2.7316 .5985 4 # supcrt +Mg+2 + SO4-2 = MgSO4 + -log_k 2.37 + -delta_h 4.550 kcal + -dw 4.45e-10 + -Vm 2.4 -0.97 6.1 -2.74 # est'd +Mg+2 + PO4-3 = MgPO4- + -log_k 6.589 + -delta_h 3.10 kcal + -gamma 5.4 0 +Mg+2 + HPO4-2 = MgHPO4 + -log_k 2.87 + -delta_h 3.3 kcal +Mg+2 + H2PO4- = MgH2PO4+ + -log_k 1.513 + -delta_h 3.4 kcal + -gamma 5.4 0 +Mg+2 + F- = MgF+ + -log_k 1.82 + -delta_h 3.20 kcal + -gamma 4.5 0 + -Vm .6494 -6.1958 8.1852 -2.5229 .9706 4.5 # supcrt +Na+ + OH- = NaOH + -log_k -10 # remove this complex +Na+ + CO3-2 = NaCO3- + -log_k 1.27 + -delta_h 8.91 kcal + -dw 5.85e-10 + -Vm 3.89 -8.23e-4 20 -9.44 3.02 9.05e-3 3.07 0 0.0233 1 # ref. 1 +Na+ + HCO3- = NaHCO3 + -log_k -0.25 + -delta_h -1 kcal + -dw 6.73e-10 + -Vm 0.431 # ref. 1 +Na+ + SO4-2 = NaSO4- + -log_k 0.7 + -delta_h 1.120 kcal + -gamma 5.4 0 + -dw 6.18e-10 + -Vm 1e-5 16.4 -0.0678 -1.05 4.14 0 6.86 0 0.0242 0.53 # ref. 1 +Na+ + HPO4-2 = NaHPO4- + -log_k 0.29 + -gamma 5.4 0 + -Vm 5.2 8.1 13 -3 0.9 0 0 1.62e-2 1 # ref. 2 +Na+ + F- = NaF + -log_k -0.24 + -Vm 2.7483 -1.0708 6.1709 -2.7347 -.030 # supcrt +K+ + SO4-2 = KSO4- + -log_k 0.85 + -delta_h 2.250 kcal + -analytical 3.106 0.0 -673.6 + -gamma 5.4 0 + -dw 7.46e-10 + -Vm 6.8 7.06 3.0 -2.07 1.1 0 0 0 0 1 # ref. 1 +K+ + HPO4-2 = KHPO4- + -log_k 0.29 + -gamma 5.4 0 + -Vm 5.4 8.1 19 -3.1 0.7 0 0 0 1.62e-2 1 # ref. 2 +Fe+2 + H2O = FeOH+ + H+ + -log_k -9.5 + -delta_h 13.20 kcal + -gamma 5.0 0 +Fe+2 + 3H2O = Fe(OH)3- + 3H+ + -log_k -31.0 + -delta_h 30.3 kcal + -gamma 5.0 0 +Fe+2 + Cl- = FeCl+ + -log_k 0.14 +Fe+2 + CO3-2 = FeCO3 + -log_k 4.38 +Fe+2 + HCO3- = FeHCO3+ + -log_k 2.0 +Fe+2 + SO4-2 = FeSO4 + -log_k 2.25 + -delta_h 3.230 kcal + -Vm -13 0 123 # ref. 2 +Fe+2 + HSO4- = FeHSO4+ + -log_k 1.08 +Fe+2 + 2HS- = Fe(HS)2 + -log_k 8.95 +Fe+2 + 3HS- = Fe(HS)3- + -log_k 10.987 +Fe+2 + HPO4-2 = FeHPO4 + -log_k 3.6 +Fe+2 + H2PO4- = FeH2PO4+ + -log_k 2.7 + -gamma 5.4 0 +Fe+2 + F- = FeF+ + -log_k 1.0 +Fe+2 = Fe+3 + e- + -log_k -13.02 + -delta_h 9.680 kcal + -gamma 9.0 0 +Fe+3 + H2O = FeOH+2 + H+ + -log_k -2.19 + -delta_h 10.4 kcal + -gamma 5.0 0 +Fe+3 + 2 H2O = Fe(OH)2+ + 2 H+ + -log_k -5.67 + -delta_h 17.1 kcal + -gamma 5.4 0 +Fe+3 + 3 H2O = Fe(OH)3 + 3 H+ + -log_k -12.56 + -delta_h 24.8 kcal +Fe+3 + 4 H2O = Fe(OH)4- + 4 H+ + -log_k -21.6 + -delta_h 31.9 kcal + -gamma 5.4 0 +Fe+2 + 2H2O = Fe(OH)2 + 2H+ + -log_k -20.57 + -delta_h 28.565 kcal +2 Fe+3 + 2 H2O = Fe2(OH)2+4 + 2 H+ + -log_k -2.95 + -delta_h 13.5 kcal +3 Fe+3 + 4 H2O = Fe3(OH)4+5 + 4 H+ + -log_k -6.3 + -delta_h 14.3 kcal +Fe+3 + Cl- = FeCl+2 + -log_k 1.48 + -delta_h 5.6 kcal + -gamma 5.0 0 +Fe+3 + 2 Cl- = FeCl2+ + -log_k 2.13 + -gamma 5.0 0 +Fe+3 + 3 Cl- = FeCl3 + -log_k 1.13 +Fe+3 + SO4-2 = FeSO4+ + -log_k 4.04 + -delta_h 3.91 kcal + -gamma 5.0 0 +Fe+3 + HSO4- = FeHSO4+2 + -log_k 2.48 +Fe+3 + 2 SO4-2 = Fe(SO4)2- + -log_k 5.38 + -delta_h 4.60 kcal +Fe+3 + HPO4-2 = FeHPO4+ + -log_k 5.43 + -delta_h 5.76 kcal + -gamma 5.0 0 +Fe+3 + H2PO4- = FeH2PO4+2 + -log_k 5.43 + -gamma 5.4 0 +Fe+3 + F- = FeF+2 + -log_k 6.2 + -delta_h 2.7 kcal + -gamma 5.0 0 +Fe+3 + 2 F- = FeF2+ + -log_k 10.8 + -delta_h 4.8 kcal + -gamma 5.0 0 +Fe+3 + 3 F- = FeF3 + -log_k 14.0 + -delta_h 5.4 kcal +Mn+2 + H2O = MnOH+ + H+ + -log_k -10.59 + -delta_h 14.40 kcal + -gamma 5.0 0 +Mn+2 + 3H2O = Mn(OH)3- + 3H+ + -log_k -34.8 + -gamma 5.0 0 +Mn+2 + Cl- = MnCl+ + -log_k 0.61 + -gamma 5.0 0 + -Vm 7.25 -1.08 -25.8 -2.73 3.99 5 0 0 0 1 # ref. 2 +Mn+2 + 2 Cl- = MnCl2 + -log_k 0.25 + -Vm 1e-5 0 144 # ref. 2 +Mn+2 + 3 Cl- = MnCl3- + -log_k -0.31 + -gamma 5.0 0 + -Vm 11.8 0 0 0 2.4 0 0 0 3.6e-2 1 # ref. 2 +Mn+2 + CO3-2 = MnCO3 + -log_k 4.9 +Mn+2 + HCO3- = MnHCO3+ + -log_k 1.95 + -gamma 5.0 0 +Mn+2 + SO4-2 = MnSO4 + -log_k 2.25 + -delta_h 3.370 kcal + -Vm -1.31 -1.83 62.3 -2.7 # ref. 2 +Mn+2 + 2 NO3- = Mn(NO3)2 + -log_k 0.6 + -delta_h -0.396 kcal + -Vm 6.16 0 29.4 0 0.9 # ref. 2 +Mn+2 + F- = MnF+ + -log_k 0.84 + -gamma 5.0 0 +Mn+2 = Mn+3 + e- + -log_k -25.51 + -delta_h 25.80 kcal + -gamma 9.0 0 +Al+3 + H2O = AlOH+2 + H+ + -log_k -5.0 + -delta_h 11.49 kcal + -analytic -38.253 0.0 -656.27 14.327 + -gamma 5.4 0 + -Vm -1.46 -11.4 10.2 -2.31 1.67 5.4 0 0 0 1 # ref. 2 and Barta and Hepler, 1986, Can. J. Chem. 64, 353. +Al+3 + 2 H2O = Al(OH)2+ + 2 H+ + -log_k -10.1 + -delta_h 26.90 kcal + -gamma 5.4 0 + -analytic 88.50 0.0 -9391.6 -27.121 +Al+3 + 3 H2O = Al(OH)3 + 3 H+ + -log_k -16.9 + -delta_h 39.89 kcal + -analytic 226.374 0.0 -18247.8 -73.597 +Al+3 + 4 H2O = Al(OH)4- + 4 H+ + -log_k -22.7 + -delta_h 42.30 kcal + -analytic 51.578 0.0 -11168.9 -14.865 + -gamma 4.5 0 +Al+3 + SO4-2 = AlSO4+ + -log_k 3.5 + -delta_h 2.29 kcal + -gamma 4.5 0 +Al+3 + 2SO4-2 = Al(SO4)2- + -log_k 5.0 + -delta_h 3.11 kcal + -gamma 4.5 0 +Al+3 + HSO4- = AlHSO4+2 + -log_k 0.46 +Al+3 + F- = AlF+2 + -log_k 7.0 + -delta_h 1.060 kcal + -gamma 5.4 0 +Al+3 + 2 F- = AlF2+ + -log_k 12.7 + -delta_h 1.980 kcal + -gamma 5.4 0 +Al+3 + 3 F- = AlF3 + -log_k 16.8 + -delta_h 2.160 kcal +Al+3 + 4 F- = AlF4- + -log_k 19.4 + -delta_h 2.20 kcal + -gamma 4.5 0 +# Al+3 + 5 F- = AlF5-2 + # log_k 20.6 + # delta_h 1.840 kcal +# Al+3 + 6 F- = AlF6-3 + # log_k 20.6 + # delta_h -1.670 kcal +H4SiO4 = H3SiO4- + H+ + -log_k -9.83 + -delta_h 6.12 kcal + -analytic -302.3724 -0.050698 15669.69 108.18466 -1119669.0 + -gamma 4 0 + -Vm 7.94 1.0881 5.3224 -2.8240 1.4767 # supcrt + H2O in a1 +H4SiO4 = H2SiO4-2 + 2 H+ + -log_k -23.0 + -delta_h 17.6 kcal + -analytic -294.0184 -0.072650 11204.49 108.18466 -1119669.0 + -gamma 5.4 0 +H4SiO4 + 4 H+ + 6 F- = SiF6-2 + 4 H2O + -log_k 30.18 + -delta_h -16.260 kcal + -gamma 5.0 0 + -Vm 8.5311 13.0492 .6211 -3.3185 2.7716 # supcrt +Ba+2 + H2O = BaOH+ + H+ + -log_k -13.47 + -gamma 5.0 0 +Ba+2 + CO3-2 = BaCO3 + -log_k 2.71 + -delta_h 3.55 kcal + -analytic 0.113 0.008721 + -Vm .2907 -7.0717 8.5295 -2.4867 -.0300 # supcrt +Ba+2 + HCO3- = BaHCO3+ + -log_k 0.982 + -delta_h 5.56 kcal + -analytic -3.0938 0.013669 +Ba+2 + SO4-2 = BaSO4 + -log_k 2.7 +Sr+2 + H2O = SrOH+ + H+ + -log_k -13.29 + -gamma 5.0 0 +Sr+2 + CO3-2 + H+ = SrHCO3+ + -log_k 11.509 + -delta_h 2.489 kcal + -analytic 104.6391 0.04739549 -5151.79 -38.92561 563713.9 + -gamma 5.4 0 +Sr+2 + CO3-2 = SrCO3 + -log_k 2.81 + -delta_h 5.22 kcal + -analytic -1.019 0.012826 + -Vm -.1787 -8.2177 8.9799 -2.4393 -.0300 # supcrt +Sr+2 + SO4-2 = SrSO4 + -log_k 2.29 + -delta_h 2.08 kcal + -Vm 6.7910 -.9666 6.1300 -2.7390 -.0010 # celestite solubility +Li+ + SO4-2 = LiSO4- + -log_k 0.64 + -gamma 5.0 0 +Cu+2 + e- = Cu+ + -log_k 2.72 + -delta_h 1.65 kcal + -gamma 2.5 0 +Cu+ + 2Cl- = CuCl2- + -log_k 5.50 + -delta_h -0.42 kcal + -gamma 4.0 0 +Cu+ + 3Cl- = CuCl3-2 + -log_k 5.70 + -delta_h 0.26 kcal + -gamma 5.0 0.0 +Cu+2 + CO3-2 = CuCO3 + -log_k 6.73 +Cu+2 + 2CO3-2 = Cu(CO3)2-2 + -log_k 9.83 +Cu+2 + HCO3- = CuHCO3+ + -log_k 2.7 +Cu+2 + Cl- = CuCl+ + -log_k 0.43 + -delta_h 8.65 kcal + -gamma 4.0 0 + -Vm -4.19 0 30.4 0 0 4 0 0 1.94e-2 1 # ref. 2 +Cu+2 + 2Cl- = CuCl2 + -log_k 0.16 + -delta_h 10.56 kcal + -Vm 26.8 0 -136 # ref. 2 +Cu+2 + 3Cl- = CuCl3- + -log_k -2.29 + -delta_h 13.69 kcal + -gamma 4.0 0 +Cu+2 + 4Cl- = CuCl4-2 + -log_k -4.59 + -delta_h 17.78 kcal + -gamma 5.0 0 +Cu+2 + F- = CuF+ + -log_k 1.26 + -delta_h 1.62 kcal +Cu+2 + H2O = CuOH+ + H+ + -log_k -8.0 + -gamma 4.0 0 +Cu+2 + 2 H2O = Cu(OH)2 + 2 H+ + -log_k -13.68 +Cu+2 + 3 H2O = Cu(OH)3- + 3 H+ + -log_k -26.9 +Cu+2 + 4 H2O = Cu(OH)4-2 + 4 H+ + -log_k -39.6 +2Cu+2 + 2H2O = Cu2(OH)2+2 + 2H+ + -log_k -10.359 + -delta_h 17.539 kcal + -analytical 2.497 0.0 -3833.0 +Cu+2 + SO4-2 = CuSO4 + -log_k 2.31 + -delta_h 1.220 kcal + -Vm 5.21 0 -14.6 # ref. 2 +Cu+2 + 3HS- = Cu(HS)3- + -log_k 25.9 +Zn+2 + H2O = ZnOH+ + H+ + -log_k -8.96 + -delta_h 13.4 kcal +Zn+2 + 2 H2O = Zn(OH)2 + 2 H+ + -log_k -16.9 +Zn+2 + 3 H2O = Zn(OH)3- + 3 H+ + -log_k -28.4 +Zn+2 + 4 H2O = Zn(OH)4-2 + 4 H+ + -log_k -41.2 +Zn+2 + Cl- = ZnCl+ + -log_k 0.43 + -delta_h 7.79 kcal + -gamma 4.0 0 + -Vm 14.8 -3.91 -105.7 -2.62 0.203 4 0 0 -5.05e-2 1 # ref. 2 +Zn+2 + 2 Cl- = ZnCl2 + -log_k 0.45 + -delta_h 8.5 kcal + -Vm -10.1 4.57 241 -2.97 -1e-3 # ref. 2 +Zn+2 + 3Cl- = ZnCl3- + -log_k 0.5 + -delta_h 9.56 kcal + -gamma 4.0 0 + -Vm 0.772 15.5 -0.349 -3.42 1.25 0 -7.77 0 0 1 # ref. 2 +Zn+2 + 4Cl- = ZnCl4-2 + -log_k 0.2 + -delta_h 10.96 kcal + -gamma 5.0 0 + -Vm 28.42 28 -5.26 -3.94 2.67 0 0 0 4.62e-2 1 # ref. 2 +Zn+2 + H2O + Cl- = ZnOHCl + H+ + -log_k -7.48 +Zn+2 + 2HS- = Zn(HS)2 + -log_k 14.94 +Zn+2 + 3HS- = Zn(HS)3- + -log_k 16.1 +Zn+2 + CO3-2 = ZnCO3 + -log_k 5.3 +Zn+2 + 2CO3-2 = Zn(CO3)2-2 + -log_k 9.63 +Zn+2 + HCO3- = ZnHCO3+ + -log_k 2.1 +Zn+2 + SO4-2 = ZnSO4 + -log_k 2.37 + -delta_h 1.36 kcal + -Vm 2.51 0 18.8 # ref. 2 +Zn+2 + 2SO4-2 = Zn(SO4)2-2 + -log_k 3.28 + -Vm 10.9 0 -98.7 0 0 0 24 0 -0.236 1 # ref. 2 +Zn+2 + Br- = ZnBr+ + -log_k -0.58 +Zn+2 + 2Br- = ZnBr2 + -log_k -0.98 +Zn+2 + F- = ZnF+ + -log_k 1.15 + -delta_h 2.22 kcal +Cd+2 + H2O = CdOH+ + H+ + -log_k -10.08 + -delta_h 13.1 kcal +Cd+2 + 2 H2O = Cd(OH)2 + 2 H+ + -log_k -20.35 +Cd+2 + 3 H2O = Cd(OH)3- + 3 H+ + -log_k -33.3 +Cd+2 + 4 H2O = Cd(OH)4-2 + 4 H+ + -log_k -47.35 +2Cd+2 + H2O = Cd2OH+3 + H+ + -log_k -9.39 + -delta_h 10.9 kcal +Cd+2 + H2O + Cl- = CdOHCl + H+ + -log_k -7.404 + -delta_h 4.355 kcal +Cd+2 + NO3- = CdNO3+ + -log_k 0.4 + -delta_h -5.2 kcal + -Vm 5.95 0 -1.11 0 2.67 7 0 0 1.53e-2 1 # ref. 2 +Cd+2 + Cl- = CdCl+ + -log_k 1.98 + -delta_h 0.59 kcal + -Vm 5.69 0 -30.2 0 0 6 0 0 0.112 1 # ref. 2 +Cd+2 + 2 Cl- = CdCl2 + -log_k 2.6 + -delta_h 1.24 kcal + -Vm 5.53 # ref. 2 +Cd+2 + 3 Cl- = CdCl3- + -log_k 2.4 + -delta_h 3.9 kcal + -Vm 4.6 0 83.9 0 0 0 0 0 0 1 # ref. 2 +Cd+2 + CO3-2 = CdCO3 + -log_k 2.9 +Cd+2 + 2CO3-2 = Cd(CO3)2-2 + -log_k 6.4 +Cd+2 + HCO3- = CdHCO3+ + -log_k 1.5 +Cd+2 + SO4-2 = CdSO4 + -log_k 2.46 + -delta_h 1.08 kcal + -Vm 10.4 0 57.9 # ref. 2 +Cd+2 + 2SO4-2 = Cd(SO4)2-2 + -log_k 3.5 + -Vm -6.29 0 -93 0 9.5 7 0 0 0 1 # ref. 2 +Cd+2 + Br- = CdBr+ + -log_k 2.17 + -delta_h -0.81 kcal +Cd+2 + 2Br- = CdBr2 + -log_k 2.9 +Cd+2 + F- = CdF+ + -log_k 1.1 +Cd+2 + 2F- = CdF2 + -log_k 1.5 +Cd+2 + HS- = CdHS+ + -log_k 10.17 +Cd+2 + 2HS- = Cd(HS)2 + -log_k 16.53 +Cd+2 + 3HS- = Cd(HS)3- + -log_k 18.71 +Cd+2 + 4HS- = Cd(HS)4-2 + -log_k 20.9 +Pb+2 + H2O = PbOH+ + H+ + -log_k -7.71 +Pb+2 + 2 H2O = Pb(OH)2 + 2 H+ + -log_k -17.12 +Pb+2 + 3 H2O = Pb(OH)3- + 3 H+ + -log_k -28.06 +Pb+2 + 4 H2O = Pb(OH)4-2 + 4 H+ + -log_k -39.7 +2 Pb+2 + H2O = Pb2OH+3 + H+ + -log_k -6.36 +Pb+2 + Cl- = PbCl+ + -log_k 1.6 + -delta_h 4.38 kcal + -Vm 2.8934 -.7165 6.0316 -2.7494 .1281 6 # supcrt +Pb+2 + 2 Cl- = PbCl2 + -log_k 1.8 + -delta_h 1.08 kcal + -Vm 6.5402 8.1879 2.5318 -3.1175 -.0300 # supcrt +Pb+2 + 3 Cl- = PbCl3- + -log_k 1.7 + -delta_h 2.17 kcal + -Vm 11.0396 19.1743 -1.7863 -3.5717 .7356 # supcrt +Pb+2 + 4 Cl- = PbCl4-2 + -log_k 1.38 + -delta_h 3.53 kcal + -Vm 16.4150 32.2997 -6.9452 -4.1143 2.3118 # supcrt +Pb+2 + CO3-2 = PbCO3 + -log_k 7.24 +Pb+2 + 2 CO3-2 = Pb(CO3)2-2 + -log_k 10.64 +Pb+2 + HCO3- = PbHCO3+ + -log_k 2.9 +Pb+2 + SO4-2 = PbSO4 + -log_k 2.75 +Pb+2 + 2 SO4-2 = Pb(SO4)2-2 + -log_k 3.47 +Pb+2 + 2HS- = Pb(HS)2 + -log_k 15.27 +Pb+2 + 3HS- = Pb(HS)3- + -log_k 16.57 +3Pb+2 + 4H2O = Pb3(OH)4+2 + 4H+ + -log_k -23.88 + -delta_h 26.5 kcal +Pb+2 + NO3- = PbNO3+ + -log_k 1.17 +Pb+2 + Br- = PbBr+ + -log_k 1.77 + -delta_h 2.88 kcal +Pb+2 + 2Br- = PbBr2 + -log_k 1.44 +Pb+2 + F- = PbF+ + -log_k 1.25 +Pb+2 + 2F- = PbF2 + -log_k 2.56 +Pb+2 + 3F- = PbF3- + -log_k 3.42 +Pb+2 + 4F- = PbF4-2 + -log_k 3.1 + +PHASES +Calcite + CaCO3 = CO3-2 + Ca+2 + -log_k -8.48 + -delta_h -2.297 kcal + -analytic -171.9065 -0.077993 2839.319 71.595 + -Vm 36.9 cm3/mol # MW (100.09 g/mol) / rho (2.71 g/cm3) +Aragonite + CaCO3 = CO3-2 + Ca+2 + -log_k -8.336 + -delta_h -2.589 kcal + -analytic -171.9773 -0.077993 2903.293 71.595 + -Vm 34.04 +Dolomite + CaMg(CO3)2 = Ca+2 + Mg+2 + 2 CO3-2 + -log_k -17.09 + -delta_h -9.436 kcal + -Vm 64.5 +Siderite + FeCO3 = Fe+2 + CO3-2 + -log_k -10.89 + -delta_h -2.480 kcal + -Vm 29.2 +Rhodochrosite + MnCO3 = Mn+2 + CO3-2 + -log_k -11.13 + -delta_h -1.430 kcal + -Vm 31.1 +Strontianite + SrCO3 = Sr+2 + CO3-2 + -log_k -9.271 + -delta_h -0.400 kcal + -analytic 155.0305 0.0 -7239.594 -56.58638 + -Vm 39.69 +Witherite + BaCO3 = Ba+2 + CO3-2 + -log_k -8.562 + -delta_h 0.703 kcal + -analytic 607.642 0.121098 -20011.25 -236.4948 + -Vm 46 +Gypsum + CaSO4:2H2O = Ca+2 + SO4-2 + 2 H2O + -log_k -4.58 + -delta_h -0.109 kcal + -analytic 68.2401 0.0 -3221.51 -25.0627 + -Vm 73.9 # 172.18 / 2.33 (Vm H2O = 13.9 cm3/mol) +Anhydrite + CaSO4 = Ca+2 + SO4-2 + -log_k -4.36 + -delta_h -1.710 kcal + -analytic 84.90 0 -3135.12 -31.79 # 50 - 160oC, 1 - 1e3 atm, anhydrite dissolution, Blount and Dickson, 1973, Am. Mineral. 58, 323. + -Vm 46.1 # 136.14 / 2.95 +Celestite + SrSO4 = Sr+2 + SO4-2 + -log_k -6.63 + -delta_h -4.037 kcal +# -analytic -14805.9622 -2.4660924 756968.533 5436.3588 -40553604.0 + -analytic -7.14 6.11e-3 75 0 0 -1.79e-5 # Howell et al., 1992, JCED 37, 464. + -Vm 46.4 +Barite + BaSO4 = Ba+2 + SO4-2 + -log_k -9.97 + -delta_h 6.35 kcal + -analytic 136.035 0.0 -7680.41 -48.595 + -Vm 51.9 +Hydroxyapatite + Ca5(PO4)3OH + 4 H+ = H2O + 3 HPO4-2 + 5 Ca+2 + -log_k -3.421 + -delta_h -36.155 kcal + -Vm 128.9 +Fluorite + CaF2 = Ca+2 + 2 F- + -log_k -10.6 + -delta_h 4.69 kcal + -analytic 66.348 0.0 -4298.2 -25.271 + -Vm 15.7 +SiO2(a) + SiO2 + 2 H2O = H4SiO4 + -log_k -2.71 + -delta_h 3.340 kcal + -analytic -0.26 0.0 -731.0 +Chalcedony + SiO2 + 2 H2O = H4SiO4 + -log_k -3.55 + -delta_h 4.720 kcal + -analytic -0.09 0.0 -1032.0 + -Vm 23.1 +Quartz + SiO2 + 2 H2O = H4SiO4 + -log_k -3.98 + -delta_h 5.990 kcal + -analytic 0.41 0.0 -1309.0 + -Vm 22.67 +Gibbsite + Al(OH)3 + 3 H+ = Al+3 + 3 H2O + -log_k 8.11 + -delta_h -22.800 kcal +Al(OH)3(a) + Al(OH)3 + 3 H+ = Al+3 + 3 H2O + -log_k 10.8 + -delta_h -26.500 kcal +Kaolinite + Al2Si2O5(OH)4 + 6 H+ = H2O + 2 H4SiO4 + 2 Al+3 + -log_k 7.435 + -delta_h -35.300 kcal +Albite + NaAlSi3O8 + 8 H2O = Na+ + Al(OH)4- + 3 H4SiO4 + -log_k -18.002 + -delta_h 25.896 kcal +Anorthite + CaAl2Si2O8 + 8 H2O = Ca+2 + 2 Al(OH)4- + 2 H4SiO4 + -log_k -19.714 + -delta_h 11.580 kcal +K-feldspar + KAlSi3O8 + 8 H2O = K+ + Al(OH)4- + 3 H4SiO4 + -log_k -20.573 + -delta_h 30.820 kcal +K-mica + KAl3Si3O10(OH)2 + 10 H+ = K+ + 3 Al+3 + 3 H4SiO4 + -log_k 12.703 + -delta_h -59.376 kcal +Chlorite(14A) + Mg5Al2Si3O10(OH)8 + 16H+ = 5Mg+2 + 2Al+3 + 3H4SiO4 + 6H2O + -log_k 68.38 + -delta_h -151.494 kcal +Ca-Montmorillonite + Ca0.165Al2.33Si3.67O10(OH)2 + 12 H2O = 0.165Ca+2 + 2.33 Al(OH)4- + 3.67 H4SiO4 + 2 H+ + -log_k -45.027 + -delta_h 58.373 kcal +Talc + Mg3Si4O10(OH)2 + 4 H2O + 6 H+ = 3 Mg+2 + 4 H4SiO4 + -log_k 21.399 + -delta_h -46.352 kcal +Illite + K0.6Mg0.25Al2.3Si3.5O10(OH)2 + 11.2H2O = 0.6K+ + 0.25Mg+2 + 2.3Al(OH)4- + 3.5H4SiO4 + 1.2H+ + -log_k -40.267 + -delta_h 54.684 kcal +Chrysotile + Mg3Si2O5(OH)4 + 6 H+ = H2O + 2 H4SiO4 + 3 Mg+2 + -log_k 32.2 + -delta_h -46.800 kcal + -analytic 13.248 0.0 10217.1 -6.1894 +Sepiolite + Mg2Si3O7.5OH:3H2O + 4 H+ + 0.5H2O = 2 Mg+2 + 3 H4SiO4 + -log_k 15.760 + -delta_h -10.700 kcal +Sepiolite(d) + Mg2Si3O7.5OH:3H2O + 4 H+ + 0.5H2O = 2 Mg+2 + 3 H4SiO4 + -log_k 18.66 +Hematite + Fe2O3 + 6 H+ = 2 Fe+3 + 3 H2O + -log_k -4.008 + -delta_h -30.845 kcal +Goethite + FeOOH + 3 H+ = Fe+3 + 2 H2O + -log_k -1.0 + -delta_h -14.48 kcal +Fe(OH)3(a) + Fe(OH)3 + 3 H+ = Fe+3 + 3 H2O + -log_k 4.891 +Pyrite + FeS2 + 2 H+ + 2 e- = Fe+2 + 2 HS- + -log_k -18.479 + -delta_h 11.300 kcal +FeS(ppt) + FeS + H+ = Fe+2 + HS- + -log_k -3.915 +Mackinawite + FeS + H+ = Fe+2 + HS- + -log_k -4.648 +Sulfur + S + 2H+ + 2e- = H2S + -log_k 4.882 + -delta_h -9.5 kcal +Vivianite + Fe3(PO4)2:8H2O = 3 Fe+2 + 2 PO4-3 + 8 H2O + -log_k -36.0 +Pyrolusite # H2O added for surface calc's + MnO2:H2O + 4 H+ + 2 e- = Mn+2 + 3 H2O + -log_k 41.38 + -delta_h -65.110 kcal +Hausmannite + Mn3O4 + 8 H+ + 2 e- = 3 Mn+2 + 4 H2O + -log_k 61.03 + -delta_h -100.640 kcal +Manganite + MnOOH + 3 H+ + e- = Mn+2 + 2 H2O + -log_k 25.34 +Pyrochroite + Mn(OH)2 + 2 H+ = Mn+2 + 2 H2O + -log_k 15.2 +Halite + NaCl = Cl- + Na+ + log_k 1.570 + -delta_h 1.37 + #-analytic -713.4616 -.1201241 37302.21 262.4583 -2106915. + -Vm 27.1 +Sylvite + KCl = K+ + Cl- + log_k 0.900 + -delta_h 8.5 + # -analytic 3.984 0.0 -919.55 + Vm 37.5 +CO2(g) + CO2 = CO2 + -log_k -1.468 + -delta_h -4.776 kcal + -analytic 109.534 1.9913e-2 -6986.04 -40.83 669370 + -T_c 304.2 # critical T, K + -P_c 72.86 # critical P, atm + -Omega 0.225 # acentric factor +H2O(g) + H2O = H2O + -log_k 1.506; delta_h -44.03 kJ + -T_c 647.3 + -P_c 217.60 + -Omega 0.344 + -analytic -16.5066 -2.0013E-3 2710.7 3.7646 0 2.24E-6 + +# Gases from LLNL... +O2(g) + O2 = O2 + -log_k -2.8983 + -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e5 + -T_c 154.6 + -P_c 49.80 + -Omega 0.021 +### MDL species added just for syntax - without parenthesis +O2g + O2 = O2 + log_k -2.8983 + -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e+5 + -T_c 154.6 + -P_c 49.80 + -Omega 0.021 +H2(g) + H2 = H2 + -log_k -3.1050 + -delta_h -4.184 kJ + -analytic -9.3114 4.6473e-3 -49.335 1.4341 1.2815e5 + -T_c 33.2 + -P_c 12.80 + -Omega -0.225 +N2(g) + N2 = N2 + -log_k -3.1864 + -analytic -58.453 1.818e-3 3199 17.909 -27460 + -T_c 126.2 + -P_c 33.50 + -Omega 0.039 +H2S(g) + H2S = H+ + HS- + -log_k -7.9759 + -analytic -97.354 -3.1576e-2 1.8285e3 37.44 28.56 + -T_c 373.2 + -P_c 88.20 + -Omega 0.1 +CH4(g) + CH4 = CH4 + -log_k -2.8502 + -analytic -24.027 4.7146e-3 372.27 6.4264 2.3362e5 + -T_c 190.6 + -P_c 45.40 + -Omega 0.008 +NH3(g) + NH3 = NH3 + -log_k 1.7966 + -analytic -18.758 3.3670e-4 2.5113e3 4.8619 39.192 + -T_c 405.6 + -P_c 111.3 + -Omega 0.25 +#Amm(g) +# Amm = Amm +# -log_k 1.7966 +# -analytic -18.758 3.3670e-4 2.5113e3 4.8619 39.192 +# -T_c 405.6 +# -P_c 111.3 +# -Omega 0.25 +# redox-uncoupled gases +Oxg(g) + Oxg = Oxg + -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e5 + -T_c 154.6 ; -P_c 49.80 ; -Omega 0.021 +Hdg(g) + Hdg = Hdg + -analytic -9.3114 4.6473e-3 -49.335 1.4341 1.2815e5 + -T_c 33.2 ; -P_c 12.80 ; -Omega -0.225 +Ntg(g) + Ntg = Ntg + -analytic -58.453 1.81800e-3 3199 17.909 -27460 + T_c 126.2 ; -P_c 33.50 ; -Omega 0.039 +Mtg(g) + Mtg = Mtg + -analytic -24.027 4.7146e-3 3.7227e2 6.4264 2.3362e5 + -T_c 190.6 ; -P_c 45.40 ; -Omega 0.008 +H2Sg(g) + H2Sg = H+ + HSg- + -analytic -97.354 -3.1576e-2 1.8285e3 37.44 28.56 + -T_c 373.2 ; -P_c 88.20 ; -Omega 0.1 +Melanterite + FeSO4:7H2O = 7 H2O + Fe+2 + SO4-2 + -log_k -2.209 + -delta_h 4.910 kcal + -analytic 1.447 -0.004153 0.0 0.0 -214949.0 +Alunite + KAl3(SO4)2(OH)6 + 6 H+ = K+ + 3 Al+3 + 2 SO4-2 + 6H2O + -log_k -1.4 + -delta_h -50.250 kcal +Jarosite-K + KFe3(SO4)2(OH)6 + 6 H+ = 3 Fe+3 + 6 H2O + K+ + 2 SO4-2 + -log_k -9.21 + -delta_h -31.280 kcal +Zn(OH)2(e) + Zn(OH)2 + 2 H+ = Zn+2 + 2 H2O + -log_k 11.5 +Smithsonite + ZnCO3 = Zn+2 + CO3-2 + -log_k -10.0 + -delta_h -4.36 kcal +Sphalerite + ZnS + H+ = Zn+2 + HS- + -log_k -11.618 + -delta_h 8.250 kcal +Willemite 289 + Zn2SiO4 + 4H+ = 2Zn+2 + H4SiO4 + -log_k 15.33 + -delta_h -33.37 kcal +Cd(OH)2 + Cd(OH)2 + 2 H+ = Cd+2 + 2 H2O + -log_k 13.65 +Otavite 315 + CdCO3 = Cd+2 + CO3-2 + -log_k -12.1 + -delta_h -0.019 kcal +CdSiO3 328 + CdSiO3 + H2O + 2H+ = Cd+2 + H4SiO4 + -log_k 9.06 + -delta_h -16.63 kcal +CdSO4 329 + CdSO4 = Cd+2 + SO4-2 + -log_k -0.1 + -delta_h -14.74 kcal +Cerrusite 365 + PbCO3 = Pb+2 + CO3-2 + -log_k -13.13 + -delta_h 4.86 kcal +Anglesite 384 + PbSO4 = Pb+2 + SO4-2 + -log_k -7.79 + -delta_h 2.15 kcal +Pb(OH)2 389 + Pb(OH)2 + 2H+ = Pb+2 + 2H2O + -log_k 8.15 + -delta_h -13.99 kcal + +RATES +Calcite +-start + 10 moles=0 + 20 IF ((M<=0) and (SI("Calcite")<0)) then goto 200 + 30 R=8.314462 # in J*K-1*mol-1 + 40 deltaT=1/TK-1/298.15 # wird für 40°C berechnet; TK is temp in Kelvin + 50 e=2.718282 # Eulersche Zahl + ## mechanism 1 (acid) + 60 Ea=14400 # Aktivierungsenergie in J/mol => 65.0 in KJ/mol + 70 logK25=-0.3 # Reaktionskonstante 25C mol/m2/s + 90 mech_a=(10^logK25)*(e^(-Ea/R*deltaT))*ACT("H+") ## removed exponent + ## base term (neutral mechanism) + 100 Ea=23500 + 110 logK25=-5.81 + 120 mech_c=(10^logK25)*(e^(-Ea/R*deltaT)) + 130 rate=mech_a+mech_c + 140 IF (SI("Calcite")<0 AND M>0) then moles=parm(1)*rate*(1-SR("Calcite")) # dissolution + ## 145 IF SI("Calcite")>0 then moles=parm(1)*M*rate*(-1+SR("Calcite")) # precipitation + ## 150 moles=parm(1)*rate*(1-SR("Calcite")) # precipitation + 200 save moles*time +-end + +Dolomite +-start + 10 moles=0 + 20 IF ((M<=0) and (SI("Dolomite")<0)) then goto 200 + 30 R=8.314462 # in J*K-1*mol-1 + 40 deltaT=1/TK-1/298.15 # wird für 40°C berechnet; TK is temp in Kelvin + 50 e=2.718282 # Eulersche Zahl + ## mechanism 1 (acid) + 60 Ea=36100 # Aktivierungsenergie in J/mol => 65.0 in KJ/mol + 70 logK25=-3.19 # Reaktionskonstante 25C mol/m2/s + 90 mech_a=(10^logK25)*(e^(-Ea/R*deltaT))*ACT("H+")^0.5 ## removed exponent + ## base term (neutral mechanism) + 100 Ea=52200 + 110 logK25=-7.53 + 120 mech_c=(10^logK25)*(e^(-Ea/R*deltaT)) + 130 rate=mech_a+mech_c + ## 140 IF SI("Dolomite")<0 then moles=parm(1)*rate*(1-SR("Dolomite")) # dissolution + ## 140 IF SI("Dolomite")<0 then moles=parm(1)*rate*(1-SR("Dolomite")) # dissolution + 150 moles=parm(1)*rate*(1-SR("Dolomite")) # precipitation + 200 save moles*time +-end + +END From 40e7bbe7cc2e790a2eef0a12cc32fb1d83be6af0 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 12:06:55 +0000 Subject: [PATCH 28/77] Add chemistry initialization to InitialList class --- bench/dolo/het/dolo_200.R | 17 ++++++++++++++++- src/Init/ChemistryInit.cpp | 12 ++++++++++++ src/Init/InitialList.cpp | 11 +++++++++++ src/Init/InitialList.hpp | 15 ++++++++++++--- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/bench/dolo/het/dolo_200.R b/bench/dolo/het/dolo_200.R index 87bf4951f..8d1ef2c4a 100644 --- a/bench/dolo/het/dolo_200.R +++ b/bench/dolo/het/dolo_200.R @@ -28,8 +28,23 @@ diffusion_setup <- list( alpha_y = 1e-6 ) +chemistry_setup <- list( + dht_species = c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ) +) + # Define a setup list for simulation configuration setup <- list( Grid = grid_setup, # Parameters related to the grid structure - Diffusion = diffusion_setup # Parameters related to the diffusion process + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup # Parameters related to the chemistry process ) diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index 9b86d5c41..763144417 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -1,6 +1,15 @@ #include "InitialList.hpp" namespace poet { + +void InitialList::initChemistry(const Rcpp::List &chem) { + this->dht_defined = chem.containsElementNamed("dht_species"); + + if (this->dht_defined) { + this->dht_species = Rcpp::as>(chem["dht_species"]); + } +} + InitialList::ChemistryInit InitialList::getChemistryInit() const { ChemistryInit chem_init; @@ -12,6 +21,9 @@ InitialList::ChemistryInit InitialList::getChemistryInit() const { chem_init.pqc_sol_order = pqc_sol_order; + chem_init.dht_defined = dht_defined; + chem_init.dht_species = dht_species; + return chem_init; } } // namespace poet \ No newline at end of file diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 63e3e2742..d06342310 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -1,4 +1,5 @@ #include "InitialList.hpp" +#include "DataStructures/NamedVector.hpp" #include #include #include @@ -10,6 +11,7 @@ namespace poet { void InitialList::initializeFromList(const Rcpp::List &setup) { initGrid(setup[grid_key]); initDiffusion(setup[diffusion_key]); + initChemistry(setup[chemistry_key]); } void InitialList::importList(const Rcpp::List &setup) { @@ -51,6 +53,11 @@ void InitialList::importList(const Rcpp::List &setup) { setup[static_cast(ExportList::CHEM_PQC_IDS)]); this->pqc_sol_order = Rcpp::as>( setup[static_cast(ExportList::CHEM_PQC_SOL_ORDER)]); + + this->dht_defined = + Rcpp::as(setup[static_cast(ExportList::CHEM_DHT_DEFINED)]); + this->dht_species = Rcpp::as>( + setup[static_cast(ExportList::CHEM_DHT_SPECIES)]); } Rcpp::List InitialList::exportList() { @@ -78,6 +85,10 @@ Rcpp::List InitialList::exportList() { out[static_cast(ExportList::CHEM_PQC_IDS)] = Rcpp::wrap(this->pqc_ids); out[static_cast(ExportList::CHEM_PQC_SOL_ORDER)] = Rcpp::wrap(this->pqc_sol_order); + out[static_cast(ExportList::CHEM_DHT_DEFINED)] = + Rcpp::wrap(this->dht_defined); + out[static_cast(ExportList::CHEM_DHT_SPECIES)] = + Rcpp::wrap(this->dht_species); return out; } diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index cb11bd3d6..6dbbaeb33 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -1,10 +1,12 @@ #pragma once +#include "Chemistry/ChemistryDefs.hpp" +#include "DataStructures/NamedVector.hpp" +#include #include #include #include -#include #include #include #include @@ -12,7 +14,6 @@ #include #include #include -#include #include #include @@ -50,6 +51,8 @@ private: CHEM_PQC_SCRIPTS, CHEM_PQC_IDS, CHEM_PQC_SOL_ORDER, + CHEM_DHT_DEFINED, + CHEM_DHT_SPECIES, ENUM_SIZE }; @@ -150,7 +153,7 @@ private: // Chemistry Members static constexpr const char *chemistry_key = "Chemistry"; - void initChemistry(); + void initChemistry(const Rcpp::List &chem_input); std::string database; std::vector pqc_scripts; @@ -158,6 +161,9 @@ private: std::vector pqc_sol_order; + bool dht_defined; + NamedVector dht_species; + public: struct ChemistryInit { uint32_t total_grid_cells; @@ -166,6 +172,9 @@ public: std::vector pqc_scripts; std::vector pqc_ids; std::vector pqc_sol_order; + + bool dht_defined; + NamedVector dht_species; }; ChemistryInit getChemistryInit() const; From 6d050ad34c4bafbdb3046b3f28eab47ec119f743 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 14:14:19 +0000 Subject: [PATCH 29/77] Add DHT functionality, still need to be validated --- bench/dolo/het/dolo_200_rt.R | 2 +- src/Base/RInsidePOET.hpp | 10 + src/Chemistry/ChemistryModule.cpp | 109 ++++++----- src/Chemistry/ChemistryModule.hpp | 49 +++-- src/Chemistry/SurrogateModels/DHT_Wrapper.cpp | 3 +- src/Chemistry/SurrogateModels/DHT_Wrapper.hpp | 5 +- .../SurrogateModels/Interpolation.hpp | 5 +- .../SurrogateModels/InterpolationModule.cpp | 3 +- src/Init/ChemistryInit.cpp | 32 ++- src/Init/InitialList.cpp | 19 +- src/Init/InitialList.hpp | 23 ++- src/poet.cpp | 184 +++++++----------- src/poet.hpp.in | 11 ++ 13 files changed, 246 insertions(+), 209 deletions(-) diff --git a/bench/dolo/het/dolo_200_rt.R b/bench/dolo/het/dolo_200_rt.R index 88e382432..1df317130 100644 --- a/bench/dolo/het/dolo_200_rt.R +++ b/bench/dolo/het/dolo_200_rt.R @@ -1,4 +1,4 @@ -iterations <- 500 +iterations <- 100 dt <- 50 list( diff --git a/src/Base/RInsidePOET.hpp b/src/Base/RInsidePOET.hpp index 6467e5760..c67b52b9e 100644 --- a/src/Base/RInsidePOET.hpp +++ b/src/Base/RInsidePOET.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,13 @@ public: } } + RHookFunction(SEXP f) { + try { + this->func = Rcpp::Function(f); + } catch (const std::exception &e) { + } + } + template T operator()(Args... args) const { if (func.has_value()) { return (Rcpp::as(this->func.value()(args...))); @@ -52,6 +60,8 @@ public: bool isValid() const { return this->func.has_value(); } + SEXP asSEXP() const { return Rcpp::as(this->func.value()); } + private: std::optional func; }; diff --git a/src/Chemistry/ChemistryModule.cpp b/src/Chemistry/ChemistryModule.cpp index 8623ef38f..17a0af1a8 100644 --- a/src/Chemistry/ChemistryModule.cpp +++ b/src/Chemistry/ChemistryModule.cpp @@ -157,7 +157,9 @@ inverseDistanceWeighting(const std::vector &to_calc, poet::ChemistryModule::ChemistryModule( uint32_t wp_size_, const InitialList::ChemistryInit &chem_params, MPI_Comm communicator) - : params(chem_params), wp_size(wp_size_), group_comm(communicator) { + : params(chem_params), wp_size(wp_size_), group_comm(communicator), + dht_species(chem_params.dht_species), + interp_species(chem_params.interp_species) { MPI_Comm_rank(communicator, &comm_rank); MPI_Comm_size(communicator, &comm_size); @@ -184,43 +186,42 @@ poet::ChemistryModule::~ChemistryModule() { void poet::ChemistryModule::initializeDHT( uint32_t size_mb, const NamedVector &key_species) { - // constexpr uint32_t MB_FACTOR = 1E6; + constexpr uint32_t MB_FACTOR = 1E6; - // this->dht_enabled = true; + this->dht_enabled = true; - // MPI_Comm dht_comm; + MPI_Comm dht_comm; - // if (this->is_master) { - // MPI_Comm_split(this->group_comm, MPI_UNDEFINED, this->comm_rank, - // &dht_comm); return; - // } + if (this->is_master) { + MPI_Comm_split(this->group_comm, MPI_UNDEFINED, this->comm_rank, &dht_comm); + return; + } - // if (!this->is_master) { + if (!this->is_master) { - // MPI_Comm_split(this->group_comm, 1, this->comm_rank, &dht_comm); + MPI_Comm_split(this->group_comm, 1, this->comm_rank, &dht_comm); - // auto map_copy = key_species; + auto map_copy = key_species; - // if (key_species.empty()) { - // std::vector default_signif( - // this->prop_names.size(), DHT_Wrapper::DHT_KEY_SIGNIF_DEFAULT); - // map_copy = NamedVector(this->prop_names, - // default_signif); - // } + if (key_species.empty()) { + std::vector default_signif( + this->prop_count, DHT_Wrapper::DHT_KEY_SIGNIF_DEFAULT); + map_copy = NamedVector(this->prop_names, default_signif); + } - // auto key_indices = parseDHTSpeciesVec(key_species, this->prop_names); + auto key_indices = parseDHTSpeciesVec(key_species, this->prop_names); - // if (this->dht) { - // delete this->dht; - // } + if (this->dht) { + delete this->dht; + } - // const std::uint64_t dht_size = size_mb * MB_FACTOR; + const std::uint64_t dht_size = size_mb * MB_FACTOR; - // this->dht = new DHT_Wrapper(dht_comm, dht_size, map_copy, key_indices, - // this->prop_names, params.hooks, - // this->prop_count, params.use_interp); - // this->dht->setBaseTotals(base_totals.at(0), base_totals.at(1)); - // } + this->dht = new DHT_Wrapper(dht_comm, dht_size, map_copy, key_indices, + this->prop_names, params.hooks, + this->prop_count, interp_enabled); + this->dht->setBaseTotals(base_totals.at(0), base_totals.at(1)); + } } inline std::vector poet::ChemistryModule::parseDHTSpeciesVec( @@ -229,6 +230,8 @@ inline std::vector poet::ChemistryModule::parseDHTSpeciesVec( std::vector species_indices; species_indices.reserve(key_species.size()); + const auto test = key_species.getNames(); + for (const auto &species : key_species.getNames()) { auto it = std::find(to_compare.begin(), to_compare.end(), species); if (it == to_compare.end()) { @@ -293,42 +296,42 @@ void poet::ChemistryModule::initializeInterp( std::uint32_t bucket_size, std::uint32_t size_mb, std::uint32_t min_entries, const NamedVector &key_species) { - // if (!this->is_master) { + if (!this->is_master) { - // constexpr uint32_t MB_FACTOR = 1E6; + constexpr uint32_t MB_FACTOR = 1E6; - // assert(this->dht); + assert(this->dht); - // this->interp_enabled = true; + this->interp_enabled = true; - // auto map_copy = key_species; + auto map_copy = key_species; - // if (key_species.empty()) { - // map_copy = this->dht->getKeySpecies(); - // for (std::size_t i = 0; i < map_copy.size(); i++) { - // const std::uint32_t signif = - // map_copy[i] - (map_copy[i] > InterpolationModule::COARSE_DIFF - // ? InterpolationModule::COARSE_DIFF - // : 0); - // map_copy[i] = signif; - // } - // } + if (key_species.empty()) { + map_copy = this->dht->getKeySpecies(); + for (std::size_t i = 0; i < map_copy.size(); i++) { + const std::uint32_t signif = + map_copy[i] - (map_copy[i] > InterpolationModule::COARSE_DIFF + ? InterpolationModule::COARSE_DIFF + : 0); + map_copy[i] = signif; + } + } - // auto key_indices = - // parseDHTSpeciesVec(map_copy, dht->getKeySpecies().getNames()); + auto key_indices = + parseDHTSpeciesVec(map_copy, dht->getKeySpecies().getNames()); - // if (this->interp) { - // this->interp.reset(); - // } + if (this->interp) { + this->interp.reset(); + } - // const uint64_t pht_size = size_mb * MB_FACTOR; + const uint64_t pht_size = size_mb * MB_FACTOR; - // interp = std::make_unique( - // bucket_size, pht_size, min_entries, *(this->dht), map_copy, - // key_indices, this->prop_names, this->params.hooks); + interp = std::make_unique( + bucket_size, pht_size, min_entries, *(this->dht), map_copy, key_indices, + this->prop_names, this->params.hooks); - // interp->setInterpolationFunction(inverseDistanceWeighting); - // } + interp->setInterpolationFunction(inverseDistanceWeighting); + } } std::vector diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index 9ca8394ea..0cd0402e7 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -76,22 +76,35 @@ public: this->file_pad = std::ceil(std::log10(maxiter + 1)); } - /** - * Create a new worker instance inside given MPI communicator. - * - * Wraps communication needed before instanciation can take place. - * - * \param communicator MPI communicator to distribute work in. - * - * \returns A worker instance with fixed work package size. - */ - static ChemistryModule createWorker(MPI_Comm communicator, - const ChemistryParams &chem_param); + struct SurrogateSetup { + std::vector prop_names; - /** - * Default work package size. - */ - static constexpr uint32_t CHEM_DEFAULT_WP_SIZE = 5; + bool dht_enabled; + std::uint32_t dht_size_mb; + + bool interp_enabled; + std::uint32_t interp_bucket_size; + std::uint32_t interp_size_mb; + std::uint32_t interp_min_entries; + }; + + void masterEnableSurrogates(const SurrogateSetup &setup) { + // FIXME: This is a hack to get the prop_names and prop_count from the setup + this->prop_names = setup.prop_names; + this->prop_count = setup.prop_names.size(); + + this->dht_enabled = setup.dht_enabled; + this->interp_enabled = setup.interp_enabled; + + if (this->dht_enabled || this->interp_enabled) { + this->initializeDHT(setup.dht_size_mb, this->dht_species); + } + + if (this->interp_enabled) { + this->initializeInterp(setup.interp_bucket_size, setup.interp_size_mb, + setup.interp_min_entries, this->interp_species); + } + } /** * Intended to alias input parameters for grid initialization with a single @@ -327,7 +340,7 @@ protected: bool is_sequential; bool is_master; - uint32_t wp_size{CHEM_DEFAULT_WP_SIZE}; + uint32_t wp_size; bool dht_enabled{false}; int dht_snaps_type{DHT_SNAPS_DISABLED}; std::string dht_file_out_dir; @@ -361,6 +374,10 @@ protected: uint32_t n_cells = 0; uint32_t prop_count = 0; + std::vector prop_names; + + NamedVector dht_species; + NamedVector interp_species; Field chem_field; diff --git a/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp b/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp index 53ef72826..eac73b14a 100644 --- a/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp +++ b/src/Chemistry/SurrogateModels/DHT_Wrapper.cpp @@ -22,6 +22,7 @@ #include "DHT_Wrapper.hpp" +#include "Init/InitialList.hpp" #include "Rounding.hpp" #include @@ -41,7 +42,7 @@ DHT_Wrapper::DHT_Wrapper(MPI_Comm dht_comm, std::uint64_t dht_size, const NamedVector &key_species, const std::vector &key_indices, const std::vector &_output_names, - const ChemistryParams::Chem_Hook_Functions &_hooks, + const InitialList::ChemistryHookFunctions &_hooks, uint32_t data_count, bool _with_interp) : key_count(key_indices.size()), data_count(data_count), input_key_elements(key_indices), communicator(dht_comm), diff --git a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp index 8b741f7e1..0633469c8 100644 --- a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp +++ b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp @@ -29,6 +29,7 @@ #include "../../Base/SimParams.hpp" #include "Chemistry/ChemistryDefs.hpp" +#include "Init/InitialList.hpp" #include "LookupKey.hpp" #include @@ -87,7 +88,7 @@ public: const NamedVector &key_species, const std::vector &key_indices, const std::vector &output_names, - const ChemistryParams::Chem_Hook_Functions &hooks, + const InitialList::ChemistryHookFunctions &hooks, uint32_t data_count, bool with_interp); /** * @brief Destroy the dht wrapper object @@ -259,7 +260,7 @@ private: const std::vector &output_names; - const ChemistryParams::Chem_Hook_Functions &hooks; + const InitialList::ChemistryHookFunctions &hooks; const bool with_interp; DHT_ResultObject dht_results; diff --git a/src/Chemistry/SurrogateModels/Interpolation.hpp b/src/Chemistry/SurrogateModels/Interpolation.hpp index 72b0ea3bd..a1886965d 100644 --- a/src/Chemistry/SurrogateModels/Interpolation.hpp +++ b/src/Chemistry/SurrogateModels/Interpolation.hpp @@ -6,6 +6,7 @@ #include "DataStructures/NamedVector.hpp" #include "DHT_Wrapper.hpp" +#include "Init/InitialList.hpp" #include "LookupKey.hpp" #include "Rounding.hpp" @@ -162,7 +163,7 @@ public: const NamedVector &interp_key_signifs, const std::vector &dht_key_indices, const std::vector &out_names, - const ChemistryParams::Chem_Hook_Functions &hooks); + const InitialList::ChemistryHookFunctions &hooks); enum result_status { RES_OK, INSUFFICIENT_DATA, NOT_NEEDED }; @@ -258,7 +259,7 @@ private: return out_key; } - const ChemistryParams::Chem_Hook_Functions &hooks; + const InitialList::ChemistryHookFunctions &hooks; const std::vector &out_names; const std::vector dht_names; }; diff --git a/src/Chemistry/SurrogateModels/InterpolationModule.cpp b/src/Chemistry/SurrogateModels/InterpolationModule.cpp index 7dc64919b..455c96729 100644 --- a/src/Chemistry/SurrogateModels/InterpolationModule.cpp +++ b/src/Chemistry/SurrogateModels/InterpolationModule.cpp @@ -1,4 +1,5 @@ // Time-stamp: "Last modified 2023-08-16 17:02:31 mluebke" +#include "Init/InitialList.hpp" #include "Interpolation.hpp" #include "DHT_Wrapper.hpp" @@ -35,7 +36,7 @@ InterpolationModule::InterpolationModule( const NamedVector &interp_key_signifs, const std::vector &dht_key_indices, const std::vector &_out_names, - const ChemistryParams::Chem_Hook_Functions &_hooks) + const InitialList::ChemistryHookFunctions &_hooks) : dht_instance(dht), key_signifs(interp_key_signifs), key_indices(dht_key_indices), min_entries_needed(min_entries_needed), dht_names(dht.getKeySpecies().getNames()), out_names(_out_names), diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index 763144417..6fd077750 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -1,13 +1,30 @@ #include "InitialList.hpp" +#include +#include + namespace poet { void InitialList::initChemistry(const Rcpp::List &chem) { - this->dht_defined = chem.containsElementNamed("dht_species"); - - if (this->dht_defined) { + if (chem.containsElementNamed("dht_species")) { this->dht_species = Rcpp::as>(chem["dht_species"]); } + + if (chem.containsElementNamed("pht_species")) { + this->interp_species = Rcpp::as>(chem["pht_species"]); + } + + if (chem.containsElementNamed("hooks")) { + this->chem_hooks = Rcpp::List(chem["hooks"]); + + std::vector hook_names = this->chem_hooks.names(); + + for (const auto &name : hook_names) { + if (this->hook_name_list.find(name) == this->hook_name_list.end()) { + Rcpp::Rcerr << "Unknown chemistry hook: " << name << std::endl; + } + } + } } InitialList::ChemistryInit InitialList::getChemistryInit() const { @@ -21,8 +38,15 @@ InitialList::ChemistryInit InitialList::getChemistryInit() const { chem_init.pqc_sol_order = pqc_sol_order; - chem_init.dht_defined = dht_defined; chem_init.dht_species = dht_species; + chem_init.interp_species = interp_species; + + if (this->chem_hooks.size() > 0) { + chem_init.hooks.dht_fill = this->chem_hooks["dht_fill"]; + chem_init.hooks.dht_fuzz = this->chem_hooks["dht_fuzz"]; + chem_init.hooks.interp_pre = this->chem_hooks["interp_pre"]; + chem_init.hooks.interp_post = this->chem_hooks["interp_post"]; + } return chem_init; } diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index d06342310..bca49a239 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -1,6 +1,7 @@ #include "InitialList.hpp" #include "DataStructures/NamedVector.hpp" #include +#include #include #include #include @@ -54,10 +55,14 @@ void InitialList::importList(const Rcpp::List &setup) { this->pqc_sol_order = Rcpp::as>( setup[static_cast(ExportList::CHEM_PQC_SOL_ORDER)]); - this->dht_defined = - Rcpp::as(setup[static_cast(ExportList::CHEM_DHT_DEFINED)]); - this->dht_species = Rcpp::as>( + this->dht_species = NamedVector( setup[static_cast(ExportList::CHEM_DHT_SPECIES)]); + + this->interp_species = Rcpp::as>( + setup[static_cast(ExportList::CHEM_INTERP_SPECIES)]); + + this->chem_hooks = + Rcpp::as(setup[static_cast(ExportList::CHEM_HOOKS)]); } Rcpp::List InitialList::exportList() { @@ -85,10 +90,10 @@ Rcpp::List InitialList::exportList() { out[static_cast(ExportList::CHEM_PQC_IDS)] = Rcpp::wrap(this->pqc_ids); out[static_cast(ExportList::CHEM_PQC_SOL_ORDER)] = Rcpp::wrap(this->pqc_sol_order); - out[static_cast(ExportList::CHEM_DHT_DEFINED)] = - Rcpp::wrap(this->dht_defined); - out[static_cast(ExportList::CHEM_DHT_SPECIES)] = - Rcpp::wrap(this->dht_species); + out[static_cast(ExportList::CHEM_DHT_SPECIES)] = this->dht_species; + out[static_cast(ExportList::CHEM_INTERP_SPECIES)] = + Rcpp::wrap(this->interp_species); + out[static_cast(ExportList::CHEM_HOOKS)] = this->chem_hooks; return out; } diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 6dbbaeb33..3a73ad0ba 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -1,8 +1,10 @@ #pragma once +#include "Base/RInsidePOET.hpp" #include "Chemistry/ChemistryDefs.hpp" #include "DataStructures/NamedVector.hpp" #include +#include #include #include @@ -51,8 +53,9 @@ private: CHEM_PQC_SCRIPTS, CHEM_PQC_IDS, CHEM_PQC_SOL_ORDER, - CHEM_DHT_DEFINED, CHEM_DHT_SPECIES, + CHEM_INTERP_SPECIES, + CHEM_HOOKS, ENUM_SIZE }; @@ -161,10 +164,23 @@ private: std::vector pqc_sol_order; - bool dht_defined; NamedVector dht_species; + NamedVector interp_species; + + Rcpp::List chem_hooks; + + const std::set hook_name_list{"dht_fill", "dht_fuzz", + "interp_pre", "interp_post"}; + public: + struct ChemistryHookFunctions { + RHookFunction dht_fill; + RHookFunction> dht_fuzz; + RHookFunction> interp_pre; + RHookFunction interp_post; + }; + struct ChemistryInit { uint32_t total_grid_cells; @@ -173,8 +189,9 @@ public: std::vector pqc_ids; std::vector pqc_sol_order; - bool dht_defined; NamedVector dht_species; + NamedVector interp_species; + ChemistryHookFunctions hooks; }; ChemistryInit getChemistryInit() const; diff --git a/src/poet.cpp b/src/poet.cpp index ecb5b5bf8..0c1dcc613 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -110,64 +110,55 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, cmdl("work-package-size", CHEM_DEFAULT_WORK_PACKAGE_SIZE) >> params.work_package_size; - // /* Parse DHT arguments */ - // chem_params.use_dht = cmdl["dht"]; - // chem_params.use_interp = cmdl["interp"]; - // // cout << "CPP: DHT is " << ( dht_enabled ? "ON" : "OFF" ) << '\n'; + /* Parse DHT arguments */ + params.use_dht = cmdl["dht"]; + params.use_interp = cmdl["interp"]; + // cout << "CPP: DHT is " << ( dht_enabled ? "ON" : "OFF" ) << '\n'; - // cmdl("dht-size", DHT_SIZE_PER_PROCESS_MB) >> chem_params.dht_size; - // // cout << "CPP: DHT size per process (Byte) = " << dht_size_per_process << - // // endl; + cmdl("dht-size", CHEM_DHT_SIZE_PER_PROCESS_MB) >> params.dht_size; + // cout << "CPP: DHT size per process (Byte) = " << dht_size_per_process << + // endl; - // cmdl("dht-snaps", 0) >> chem_params.dht_snaps; + cmdl("dht-snaps", 0) >> params.dht_snaps; - // cmdl("dht-file") >> chem_params.dht_file; - // /*Parse work package size*/ - // cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; + params.use_interp = cmdl["interp"]; + cmdl("interp-size", 100) >> params.interp_size; + cmdl("interp-min", 5) >> params.interp_min_entries; + cmdl("interp-bucket-entries", 20) >> params.interp_bucket_entries; - // cmdl("interp-size", 100) >> chem_params.pht_size; - // cmdl("interp-min", 5) >> chem_params.interp_min_entries; - // cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; - - // /*Parse output options*/ + /*Parse output options*/ // simparams.store_result = !cmdl["ignore-result"]; - // chem_params.use_interp = cmdl["interp"]; - // cmdl("interp-size", 100) >> chem_params.pht_size; - // cmdl("interp-min", 5) >> chem_params.interp_min_entries; - // cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; - - // /*Parse output options*/ + /*Parse output options*/ // simparams.store_result = !cmdl["ignore-result"]; - // if (simparams.world_rank == 0) { - // MSG("Complete results storage is " + BOOL_PRINT(simparams.store_result)); - // MSG("Work Package Size: " + std::to_string(simparams.wp_size)); - // MSG("DHT is " + BOOL_PRINT(chem_params.use_dht)); + if (MY_RANK == 0) { + // MSG("Complete results storage is " + BOOL_PRINT(simparams.store_result)); + MSG("Work Package Size: " + std::to_string(params.work_package_size)); + MSG("DHT is " + BOOL_PRINT(params.use_dht)); - // if (chem_params.use_dht) { - // MSG("DHT strategy is " + std::to_string(simparams.dht_strategy)); - // // MDL: these should be outdated (?) - // // MSG("DHT key default digits (ignored if 'signif_vector' is " - // // "defined) = " - // // << simparams.dht_significant_digits); - // // MSG("DHT logarithm before rounding: " - // // << (simparams.dht_log ? "ON" : "OFF")); - // MSG("DHT size per process (Megabyte) = " + - // std::to_string(chem_params.dht_size)); - // MSG("DHT save snapshots is " + BOOL_PRINT(chem_params.dht_snaps)); - // MSG("DHT load file is " + chem_params.dht_file); - // } + if (params.use_dht) { + // MSG("DHT strategy is " + std::to_string(simparams.dht_strategy)); + // MDL: these should be outdated (?) + // MSG("DHT key default digits (ignored if 'signif_vector' is " + // "defined) = " + // << simparams.dht_significant_digits); + // MSG("DHT logarithm before rounding: " + // << (simparams.dht_log ? "ON" : "OFF")); + MSG("DHT size per process (Megabyte) = " + + std::to_string(params.dht_size)); + MSG("DHT save snapshots is " + BOOL_PRINT(params.dht_snaps)); + // MSG("DHT load file is " + chem_params.dht_file); + } - // if (chem_params.use_interp) { - // MSG("PHT interpolation enabled: " + - // BOOL_PRINT(chem_params.use_interp)); MSG("PHT interp-size = " + - // std::to_string(chem_params.pht_size)); MSG("PHT interp-min = " + - // std::to_string(chem_params.interp_min_entries)); - // MSG("PHT interp-bucket-entries = " + - // std::to_string(chem_params.pht_max_entries)); - // } - // } + if (params.use_interp) { + MSG("PHT interpolation enabled: " + BOOL_PRINT(params.use_interp)); + MSG("PHT interp-size = " + std::to_string(params.interp_size)); + MSG("PHT interp-min = " + std::to_string(params.interp_min_entries)); + MSG("PHT interp-bucket-entries = " + + std::to_string(params.interp_bucket_entries)); + } + } std::string init_file; std::string runtime_file; @@ -225,50 +216,6 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, return ParseRet::PARSER_OK; } -// 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 rv; -// rv.resize(wp_size, 1.0); -// chem.SetRepresentativeVolume(rv); - -// // Set initial porosity -// std::vector por; -// por.resize(wp_size, 1); -// chem.SetPorosity(por); - -// // Set initial saturation -// std::vector sat; -// sat.resize(wp_size, 1.0); -// chem.SetSaturation(sat); - -// // Load database -// chem.LoadDatabase(database_path); -// } - static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, DiffusionModule &diffusion, ChemistryModule &chem) { @@ -279,20 +226,9 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, double sim_time = .0; - // ChemistryModule chem(nxyz_master, params.getNumParams().wp_size, maxiter, - // params.getChemParams(), MPI_COMM_WORLD); - - // set_chem_parameters(chem, nxyz_master, - // params.getChemParams().database_path); - // chem.RunInitFile(params.getChemParams().input_script); - - // poet::ChemistryModule::SingleCMap init_df = - // DFToHashMap(d_params.initial_t); - // chem.initializeField(diffusion.getField()); - - // if (params.getNumParams().print_progressbar) { - chem.setProgressBarPrintout(true); - // } + if (params.print_progressbar) { + chem.setProgressBarPrintout(true); + } /* SIMULATION LOOP */ @@ -405,17 +341,16 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, int main(int argc, char *argv[]) { double dSimTime, sim_end; - int world_size, world_rank; + int world_size; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &world_size); - - MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + MPI_Comm_rank(MPI_COMM_WORLD, &MY_RANK); RInsidePOET &R = RInsidePOET::getInstance(); - if (world_rank == 0) { + if (MY_RANK == 0) { MSG("Running POET version " + std::string(poet_version)); } @@ -437,18 +372,29 @@ int main(int argc, char *argv[]) { InitialList init_list(R); init_list.importList(run_params.init_params); - MSG("RInside initialized on process " + std::to_string(world_rank)); + MSG("RInside initialized on process " + std::to_string(MY_RANK)); ChemistryModule chemistry(run_params.work_package_size, init_list.getChemistryInit(), MPI_COMM_WORLD); - if (world_rank > 0) { + const ChemistryModule::SurrogateSetup surr_setup = { + init_list.getInitialGrid().GetProps(), + run_params.use_dht, + run_params.dht_size, + run_params.use_interp, + run_params.interp_bucket_entries, + run_params.interp_size, + run_params.interp_min_entries}; + + chemistry.masterEnableSurrogates(surr_setup); + + if (MY_RANK > 0) { chemistry.WorkerLoop(); MPI_Barrier(MPI_COMM_WORLD); - MSG("finished, cleanup of process " + std::to_string(world_rank)); + MSG("finished, cleanup of process " + std::to_string(MY_RANK)); MPI_Finalize(); @@ -456,7 +402,7 @@ int main(int argc, char *argv[]) { } // R.parseEvalQ("mysetup <- setup"); - // // if (world_rank == 0) { // get timestep vector from + // // if (MY_RANK == 0) { // get timestep vector from // // grid_init function ... // std::string master_init_code = "mysetup <- master_init(setup=mysetup)"; R.parseEval(master_init_code); @@ -464,13 +410,13 @@ int main(int argc, char *argv[]) { // run_params.initVectorParams(R); // MDL: store all parameters - if (world_rank == 0) { + if (MY_RANK == 0) { MSG("Calling R Function to store calling parameters"); // R.parseEvalQ("StoreSetup(setup=mysetup)"); } - if (world_rank == 0) { - MSG("Init done on process with rank " + std::to_string(world_rank)); + if (MY_RANK == 0) { + MSG("Init done on process with rank " + std::to_string(MY_RANK)); } // MPI_Barrier(MPI_COMM_WORLD); @@ -501,10 +447,10 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); - MSG("finished, cleanup of process " + std::to_string(world_rank)); + MSG("finished, cleanup of process " + std::to_string(MY_RANK)); MPI_Finalize(); - if (world_rank == 0) { + if (MY_RANK == 0) { MSG("done, bye!"); } diff --git a/src/poet.hpp.in b/src/poet.hpp.in index dcf71b972..80db8d436 100644 --- a/src/poet.hpp.in +++ b/src/poet.hpp.in @@ -46,6 +46,8 @@ const std::set paramlist{ constexpr uint32_t CHEM_DEFAULT_WORK_PACKAGE_SIZE = 32; +constexpr uint32_t CHEM_DHT_SIZE_PER_PROCESS_MB = 1.5E3; + struct RuntimeParameters { std::vector timesteps; @@ -54,6 +56,15 @@ struct RuntimeParameters { Rcpp::List init_params; + bool use_dht; + std::uint32_t dht_size; + std::uint8_t dht_snaps; + + bool use_interp; + std::uint32_t interp_size; + std::uint32_t interp_min_entries; + std::uint32_t interp_bucket_entries; + struct ChemistryParams { // std::string database_path; // std::string input_script; From 7d6871a1808b44766937ea1c4f7f9d0a7d8786c0 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 14:17:59 +0000 Subject: [PATCH 30/77] Add profiling data for DHT and interpolation --- src/poet.cpp | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/poet.cpp b/src/poet.cpp index 0c1dcc613..0adf6f56a 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -301,38 +301,33 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, Rcpp::List diffusion_profiling; diffusion_profiling["simtime"] = diffusion.getTransportTime(); + if (params.use_dht) { + chem_profiling["dht_hits"] = Rcpp::wrap(chem.GetWorkerDHTHits()); + chem_profiling["dht_evictions"] = Rcpp::wrap(chem.GetWorkerDHTEvictions()); + chem_profiling["dht_get_time"] = Rcpp::wrap(chem.GetWorkerDHTGetTimings()); + chem_profiling["dht_fill_time"] = + Rcpp::wrap(chem.GetWorkerDHTFillTimings()); + } + + if (params.use_interp) { + chem_profiling["interp_w"] = + Rcpp::wrap(chem.GetWorkerInterpolationWriteTimings()); + chem_profiling["interp_r"] = + Rcpp::wrap(chem.GetWorkerInterpolationReadTimings()); + chem_profiling["interp_g"] = + Rcpp::wrap(chem.GetWorkerInterpolationGatherTimings()); + chem_profiling["interp_fc"] = + Rcpp::wrap(chem.GetWorkerInterpolationFunctionCallTimings()); + chem_profiling["interp_calls"] = + Rcpp::wrap(chem.GetWorkerInterpolationCalls()); + chem_profiling["interp_cached"] = Rcpp::wrap(chem.GetWorkerPHTCacheHits()); + } + Rcpp::List profiling; profiling["simtime"] = dSimTime; profiling["chemistry"] = chem_profiling; profiling["diffusion"] = diffusion_profiling; - // if (params.getChemParams().use_dht) { - // R["dht_hits"] = Rcpp::wrap(chem.GetWorkerDHTHits()); - // R.parseEvalQ("profiling$dht_hits <- dht_hits"); - // R["dht_evictions"] = Rcpp::wrap(chem.GetWorkerDHTEvictions()); - // R.parseEvalQ("profiling$dht_evictions <- dht_evictions"); - // R["dht_get_time"] = Rcpp::wrap(chem.GetWorkerDHTGetTimings()); - // R.parseEvalQ("profiling$dht_get_time <- dht_get_time"); - // R["dht_fill_time"] = Rcpp::wrap(chem.GetWorkerDHTFillTimings()); - // R.parseEvalQ("profiling$dht_fill_time <- dht_fill_time"); - // } - // if (params.getChemParams().use_interp) { - // R["interp_w"] = Rcpp::wrap(chem.GetWorkerInterpolationWriteTimings()); - // R.parseEvalQ("profiling$interp_write <- interp_w"); - // R["interp_r"] = Rcpp::wrap(chem.GetWorkerInterpolationReadTimings()); - // R.parseEvalQ("profiling$interp_read <- interp_r"); - // R["interp_g"] = - // Rcpp::wrap(chem.GetWorkerInterpolationGatherTimings()); - // R.parseEvalQ("profiling$interp_gather <- interp_g"); - // R["interp_fc"] = - // Rcpp::wrap(chem.GetWorkerInterpolationFunctionCallTimings()); - // R.parseEvalQ("profiling$interp_function_calls <- interp_fc"); - // R["interp_calls"] = Rcpp::wrap(chem.GetWorkerInterpolationCalls()); - // R.parseEvalQ("profiling$interp_calls <- interp_calls"); - // R["interp_cached"] = Rcpp::wrap(chem.GetWorkerPHTCacheHits()); - // R.parseEvalQ("profiling$interp_cached <- interp_cached"); - // } - chem.MasterLoopBreak(); return profiling; From c7b9ab0b536054d225b510a797bfd29e6dead890 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 14:37:20 +0000 Subject: [PATCH 31/77] Update iteration end message in kin_r_library.R --- R_lib/kin_r_library.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index a314eb702..c8bdedb73 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -93,7 +93,7 @@ master_iteration_end <- function(setup,iter) { msgm("results stored in <", nameout, ">") } } - msgm("done iteration", iter, "/", 1) + msgm("done iteration", iter, "/", length(setup$timesteps)) setup$iter <- setup$iter + 1 return(setup) } From ca1f8a19bb144b4c3e1f29c05c8f8c11ede80e4d Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 20:23:42 +0000 Subject: [PATCH 32/77] Refactor chemistry module and RHookFunction --- src/Base/RInsidePOET.hpp | 7 +++++++ src/Chemistry/ChemistryModule.cpp | 6 ++---- src/Chemistry/ChemistryModule.hpp | 12 +++++------- src/Init/ChemistryInit.cpp | 16 ++++++++++++---- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Base/RInsidePOET.hpp b/src/Base/RInsidePOET.hpp index c67b52b9e..2897fc5a8 100644 --- a/src/Base/RInsidePOET.hpp +++ b/src/Base/RInsidePOET.hpp @@ -58,6 +58,13 @@ public: } } + RHookFunction &operator=(const RHookFunction &rhs) { + this->func = rhs.func; + return *this; + } + + RHookFunction(const RHookFunction &rhs) { this->func = rhs.func; } + bool isValid() const { return this->func.has_value(); } SEXP asSEXP() const { return Rcpp::as(this->func.value()); } diff --git a/src/Chemistry/ChemistryModule.cpp b/src/Chemistry/ChemistryModule.cpp index 17a0af1a8..422ae2e83 100644 --- a/src/Chemistry/ChemistryModule.cpp +++ b/src/Chemistry/ChemistryModule.cpp @@ -155,11 +155,9 @@ inverseDistanceWeighting(const std::vector &to_calc, } poet::ChemistryModule::ChemistryModule( - uint32_t wp_size_, const InitialList::ChemistryInit &chem_params, + uint32_t wp_size_, const InitialList::ChemistryInit chem_params, MPI_Comm communicator) - : params(chem_params), wp_size(wp_size_), group_comm(communicator), - dht_species(chem_params.dht_species), - interp_species(chem_params.interp_species) { + : params(chem_params), wp_size(wp_size_), group_comm(communicator) { MPI_Comm_rank(communicator, &comm_rank); MPI_Comm_size(communicator, &comm_size); diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index 0cd0402e7..12d322986 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -43,7 +43,7 @@ public: * \param communicator MPI communicator to distribute work in. */ ChemistryModule(uint32_t wp_size, - const InitialList::ChemistryInit &chem_params, + const InitialList::ChemistryInit chem_params, MPI_Comm communicator); /** @@ -97,12 +97,13 @@ public: this->interp_enabled = setup.interp_enabled; if (this->dht_enabled || this->interp_enabled) { - this->initializeDHT(setup.dht_size_mb, this->dht_species); + this->initializeDHT(setup.dht_size_mb, this->params.dht_species); } if (this->interp_enabled) { this->initializeInterp(setup.interp_bucket_size, setup.interp_size_mb, - setup.interp_min_entries, this->interp_species); + setup.interp_min_entries, + this->params.interp_species); } } @@ -376,12 +377,9 @@ protected: uint32_t prop_count = 0; std::vector prop_names; - NamedVector dht_species; - NamedVector interp_species; - Field chem_field; - const InitialList::ChemistryInit ¶ms; + const InitialList::ChemistryInit params; std::map> phreeqc_instances; }; diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index 6fd077750..c1f884fa2 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -42,10 +42,18 @@ InitialList::ChemistryInit InitialList::getChemistryInit() const { chem_init.interp_species = interp_species; if (this->chem_hooks.size() > 0) { - chem_init.hooks.dht_fill = this->chem_hooks["dht_fill"]; - chem_init.hooks.dht_fuzz = this->chem_hooks["dht_fuzz"]; - chem_init.hooks.interp_pre = this->chem_hooks["interp_pre"]; - chem_init.hooks.interp_post = this->chem_hooks["interp_post"]; + if (this->chem_hooks.containsElementNamed("dht_fill")) { + chem_init.hooks.dht_fill = this->chem_hooks["dht_fill"]; + } + if (this->chem_hooks.containsElementNamed("dht_fuzz")) { + chem_init.hooks.dht_fuzz = this->chem_hooks["dht_fuzz"]; + } + if (this->chem_hooks.containsElementNamed("interp_pre")) { + chem_init.hooks.interp_pre = this->chem_hooks["interp_pre"]; + } + if (this->chem_hooks.containsElementNamed("interp_post")) { + chem_init.hooks.interp_post = this->chem_hooks["interp_post"]; + } } return chem_init; From 853888a19bd6fb0fed005f82673914c8077e72c1 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 20:24:04 +0000 Subject: [PATCH 33/77] Refactor WorkerRunWorkPackage to copy input instead of overwriting --- src/Chemistry/WorkerFunctions.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Chemistry/WorkerFunctions.cpp b/src/Chemistry/WorkerFunctions.cpp index d3d4edf23..fb9b1f015 100644 --- a/src/Chemistry/WorkerFunctions.cpp +++ b/src/Chemistry/WorkerFunctions.cpp @@ -288,22 +288,20 @@ void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, continue; } - const auto &input = work_package.input[wp_id]; - const auto pqc_id = input[0]; + auto curr_input = work_package.input[wp_id]; + const auto pqc_id = curr_input[0]; auto &phreeqc_instance = this->phreeqc_instances[pqc_id]; work_package.output[wp_id] = work_package.input[wp_id]; - work_package.input[wp_id].erase(work_package.input[wp_id].begin()); + curr_input.erase(curr_input.begin()); // remove NaNs from the input - work_package.input[wp_id].erase( - std::remove_if(work_package.input[wp_id].begin(), - work_package.input[wp_id].end(), - [](double d) { return std::isnan(d); }), - work_package.input[wp_id].end()); + curr_input.erase(std::remove_if(curr_input.begin(), curr_input.end(), + [](double d) { return std::isnan(d); }), + curr_input.end()); - phreeqc_instance->queueCell(work_package.input[wp_id]); + phreeqc_instance->queueCell(curr_input); zone_mapping[pqc_id].push_back(wp_id); } From 6c3761bb92ccecaeb8fde0db1b640ab61bb134e8 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 20:24:11 +0000 Subject: [PATCH 34/77] Add check_sign_cal_dol_dht and fuzz_input_dht_keys functions --- bench/dolo/het/dolo_200.R | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/bench/dolo/het/dolo_200.R b/bench/dolo/het/dolo_200.R index 8d1ef2c4a..53aee210d 100644 --- a/bench/dolo/het/dolo_200.R +++ b/bench/dolo/het/dolo_200.R @@ -28,6 +28,31 @@ diffusion_setup <- list( alpha_y = 1e-6 ) +check_sign_cal_dol_dht <- function(old, new) { + if ((old["Calcite"] == 0) != (new["Calcite"] == 0)) { + return(TRUE) + } + if ((old["Dolomite"] == 0) != (new["Dolomite"] == 0)) { + return(TRUE) + } + return(FALSE) +} + +fuzz_input_dht_keys <- function(input) { + dht_species <- c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ) + return(input[names(dht_species)]) +} + chemistry_setup <- list( dht_species = c( "H" = 3, @@ -39,6 +64,10 @@ chemistry_setup <- list( "Mg" = 5, "Calcite" = 4, "Dolomite" = 4 + ), + hooks = list( + dht_fill = check_sign_cal_dol_dht, + dht_fuzz = fuzz_input_dht_keys ) ) From 8a78ed718ec0325eb541cc09d59348e531f0b62e Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 20:36:32 +0000 Subject: [PATCH 35/77] Remove SimParams class --- src/Base/SimParams.cpp | 258 ---------------- src/Base/SimParams.hpp | 281 ------------------ src/Chemistry/SurrogateModels/DHT_Wrapper.hpp | 1 - 3 files changed, 540 deletions(-) delete mode 100644 src/Base/SimParams.cpp delete mode 100644 src/Base/SimParams.hpp diff --git a/src/Base/SimParams.cpp b/src/Base/SimParams.cpp deleted file mode 100644 index 8264b6c60..000000000 --- a/src/Base/SimParams.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of -** Potsdam) -** -** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) -** -** Copyright (C) 2018-2022 Marco De Lucia (GFZ Potsdam), Max Luebke (University -** of 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 "SimParams.hpp" - -#include "Base/Macros.hpp" - -#include - -#include -#include - -#include "Base/RInsidePOET.hpp" -#include "argh.hpp" // Argument handler https://github.com/adishavit/argh - -using namespace poet; - -RuntimeParameters::RuntimeParameters(RInsidePOET &R, char *argv[], - int world_rank_) - : world_rank(world_rank_) { - - // initialize argh object - argh::parser cmdl(argv); - - // if user asked for help - if (cmdl[{"help", "h"}]) { - if (this->world_rank == 0) { - MSG("Todo"); - MSG("See README.md for further information."); - } - - return poet::PARSER_HELP; - } - // if positional arguments are missing - else if (!cmdl(2)) { - if (simparams.world_rank == 0) { - ERRMSG("Kin needs 2 positional arguments: "); - ERRMSG("1) the R script defining your simulation and"); - ERRMSG("2) the directory prefix where to save results and profiling"); - } - return poet::PARSER_ERROR; - } - - // collect all parameters which are not known, print them to stderr and return - // with PARSER_ERROR - std::list optionsError = validateOptions(cmdl); - if (!optionsError.empty()) { - if (simparams.world_rank == 0) { - ERRMSG("Unrecognized option(s):\n"); - for (auto option : optionsError) { - ERRMSG(std::string(option)); - } - ERRMSG("Make sure to use available options. Exiting!"); - } - return poet::PARSER_ERROR; - } - - simparams.print_progressbar = cmdl[{"P", "progress"}]; - - // simparams.print_progressbar = cmdl[{"P", "progress"}]; - - /* Parse DHT arguments */ - chem_params.use_dht = cmdl["dht"]; - chem_params.use_interp = cmdl["interp"]; - // cout << "CPP: DHT is " << ( dht_enabled ? "ON" : "OFF" ) << '\n'; - - cmdl("dht-size", DHT_SIZE_PER_PROCESS_MB) >> chem_params.dht_size; - // cout << "CPP: DHT size per process (Byte) = " << dht_size_per_process << - // endl; - - cmdl("dht-snaps", 0) >> chem_params.dht_snaps; - - cmdl("dht-file") >> chem_params.dht_file; - /*Parse work package size*/ - cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; - - cmdl("interp-size", 100) >> chem_params.pht_size; - cmdl("interp-min", 5) >> chem_params.interp_min_entries; - cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; - - /*Parse output options*/ - simparams.store_result = !cmdl["ignore-result"]; - - /*Parse work package size*/ - cmdl("work-package-size", WORK_PACKAGE_SIZE_DEFAULT) >> simparams.wp_size; - - chem_params.use_interp = cmdl["interp"]; - cmdl("interp-size", 100) >> chem_params.pht_size; - cmdl("interp-min", 5) >> chem_params.interp_min_entries; - cmdl("interp-bucket-entries", 20) >> chem_params.pht_max_entries; - - /*Parse output options*/ - simparams.store_result = !cmdl["ignore-result"]; - - if (simparams.world_rank == 0) { - MSG("Complete results storage is " + BOOL_PRINT(simparams.store_result)); - MSG("Work Package Size: " + std::to_string(simparams.wp_size)); - MSG("DHT is " + BOOL_PRINT(chem_params.use_dht)); - - if (chem_params.use_dht) { - MSG("DHT strategy is " + std::to_string(simparams.dht_strategy)); - // MDL: these should be outdated (?) - // MSG("DHT key default digits (ignored if 'signif_vector' is " - // "defined) = " - // << simparams.dht_significant_digits); - // MSG("DHT logarithm before rounding: " - // << (simparams.dht_log ? "ON" : "OFF")); - MSG("DHT size per process (Megabyte) = " + - std::to_string(chem_params.dht_size)); - MSG("DHT save snapshots is " + BOOL_PRINT(chem_params.dht_snaps)); - MSG("DHT load file is " + chem_params.dht_file); - } - - if (chem_params.use_interp) { - MSG("PHT interpolation enabled: " + BOOL_PRINT(chem_params.use_interp)); - MSG("PHT interp-size = " + std::to_string(chem_params.pht_size)); - MSG("PHT interp-min = " + - std::to_string(chem_params.interp_min_entries)); - MSG("PHT interp-bucket-entries = " + - std::to_string(chem_params.pht_max_entries)); - } - } - - cmdl(1) >> filesim; - cmdl(2) >> out_dir; - - chem_params.dht_outdir = out_dir; - - /* distribute information to R runtime */ - // if local_rank == 0 then master else worker - R["local_rank"] = simparams.world_rank; - // assign a char* (string) to 'filesim' - R["filesim"] = wrap(filesim); - // assign a char* (string) to 'fileout' - R["fileout"] = wrap(out_dir); - // pass the boolean "store_result" to the R process - R["store_result"] = simparams.store_result; - // worker count - R["n_procs"] = simparams.world_size - 1; - // work package size - R["work_package_size"] = simparams.wp_size; - // dht enabled? - R["dht_enabled"] = chem_params.use_dht; - // log before rounding? - R["dht_log"] = simparams.dht_log; - - // eval the init string, ignoring any returns - R.parseEvalQ("source(filesim)"); - R.parseEvalQ("mysetup <- setup"); - - this->chem_params.initFromR(R); - - return poet::PARSER_OK; -}; - -// poet::GridParams::s_GridParams(RInside &R) { -// auto tmp_n_cells = -// Rcpp::as>(R.parseEval("mysetup$grid$n_cells")); -// assert(tmp_n_cells.size() < 3); - -// this->dim = tmp_n_cells.size(); - -// std::copy(tmp_n_cells.begin(), tmp_n_cells.end(), this->n_cells.begin()); - -// auto tmp_s_cells = -// Rcpp::as>(R.parseEval("mysetup$grid$s_cells")); - -// assert(tmp_s_cells.size() == this->dim); - -// std::copy(tmp_s_cells.begin(), tmp_s_cells.end(), this->s_cells.begin()); - -// this->total_n = -// (dim == 1 ? this->n_cells[0] : this->n_cells[0] * this->n_cells[1]); - -// this->type = Rcpp::as(R.parseEval("mysetup$grid$type")); -// } - -// poet::DiffusionParams::s_DiffusionParams(RInside &R) { -// this->initial_t = -// Rcpp::as(R.parseEval("mysetup$diffusion$init")); -// this->alpha = -// Rcpp::as(R.parseEval("mysetup$diffusion$alpha")); -// if (Rcpp::as( -// R.parseEval("'vecinj_inner' %in% names(mysetup$diffusion)"))) { -// this->vecinj_inner = -// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_inner")); -// } -// this->vecinj = -// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj")); -// this->vecinj_index = -// Rcpp::as(R.parseEval("mysetup$diffusion$vecinj_index")); -// } - -void poet::ChemistryParams::initFromR(RInsidePOET &R) { - // this->database_path = - // Rcpp::as(R.parseEval("mysetup$chemistry$database")); - // this->input_script = - // Rcpp::as(R.parseEval("mysetup$chemistry$input_script")); - - if (R.checkIfExists("dht_species", "mysetup$chemistry")) { - this->dht_signifs = Rcpp::as>( - R.parseEval(("mysetup$chemistry$dht_species"))); - } - - if (R.checkIfExists("pht_species", "mysetup$chemistry")) { - this->pht_signifs = Rcpp::as>( - R.parseEval(("mysetup$chemistry$pht_species"))); - } - this->hooks.dht_fill = - RHookFunction(R, "mysetup$chemistry$hooks$dht_fill"); - this->hooks.dht_fuzz = - RHookFunction>(R, "mysetup$chemistry$hooks$dht_fuzz"); - this->hooks.interp_pre = RHookFunction>( - R, "mysetup$chemistry$hooks$interp_pre_func"); - this->hooks.interp_post = - RHookFunction(R, "mysetup$chemistry$hooks$interp_post_func"); -} - -void RuntimeParameters::initVectorParams(RInside &R) {} - -std::list RuntimeParameters::validateOptions(argh::parser cmdl) { - /* store all unknown parameters here */ - std::list retList; - - /* loop over all flags and compare to given flaglist*/ - for (auto &flag : cmdl.flags()) { - if (!(flaglist.find(flag) != flaglist.end())) - retList.push_back(flag); - } - - /* and loop also over params and compare to given paramlist */ - for (auto ¶m : cmdl.params()) { - if (!(paramlist.find(param.first) != paramlist.end())) - retList.push_back(param.first); - } - - return retList; -} diff --git a/src/Base/SimParams.hpp b/src/Base/SimParams.hpp deleted file mode 100644 index 74d6d2078..000000000 --- a/src/Base/SimParams.hpp +++ /dev/null @@ -1,281 +0,0 @@ -/* -** Copyright (C) 2018-2021 Alexander Lindemann, Max Luebke (University of -** Potsdam) -** -** Copyright (C) 2018-2022 Marco De Lucia, Max Luebke (GFZ Potsdam) -** -** Copyright (C) 2018-2022 Marco De Lucia (GFZ Potsdam), Max Luebke (University -** of 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. -*/ - -#pragma once - -#include "DataStructures/NamedVector.hpp" -#include "RInsidePOET.hpp" - -#include -#include -#include - -#include -#include -// BSD-licenced - -/** Standard DHT Size. Defaults to 1 GB (1000 MB) */ -constexpr uint32_t DHT_SIZE_PER_PROCESS_MB = 1.5E3; -/** Standard work package size */ -#define WORK_PACKAGE_SIZE_DEFAULT 32 - -namespace poet { - -enum { PARSER_OK, PARSER_ERROR, PARSER_HELP }; - -/** - * @brief Defining all simulation parameters - * - */ -// struct RuntimeParameters { - -// /** Count of processes in MPI_COMM_WORLD */ -// int world_size; -// /** rank of proces in MPI_COMM_WORLD */ -// int world_rank; -// /** indicates if DHT should be used */ -// bool dht_enabled; -// /** apply logarithm to key before rounding */ -// bool dht_log; -// /** indicates if timestep dt differs between iterations */ -// bool dt_differ; -// /** Indicates, when a DHT snapshot should be written */ -// int dht_snaps; -// /** not implemented: How a DHT is distributed over processes */ -// int dht_strategy; -// /** Size of DHt per process in byter */ -// unsigned int dht_size_per_process; -// /** Default significant digit for rounding */ -// int dht_significant_digits; -// /** Default work package size */ -// unsigned int wp_size; -// /** indicates if resulting grid should be stored after every iteration */ -// bool store_result; -// /** indicating whether the progress bar during chemistry simulation should -// be -// * printed or not */ -// bool print_progressbar; - -// bool interp_enabled; -// }; - -// using GridParams = struct s_GridParams { -// std::array n_cells; -// std::array s_cells; -// std::uint8_t dim; -// std::uint32_t total_n; - -// std::string type; - -// Rcpp::DataFrame init_df; -// std::string input_script; -// std::string database_path; - -// std::vector props; - -// s_GridParams(RInside &R); -// }; - -// using DiffusionParams = struct s_DiffusionParams { -// Rcpp::DataFrame initial_t; - -// Rcpp::NumericVector alpha; -// Rcpp::List vecinj_inner; - -// Rcpp::DataFrame vecinj; -// Rcpp::DataFrame vecinj_index; - -// s_DiffusionParams(RInside &R); -// }; - -struct ChemistryParams { - // std::string database_path; - // std::string input_script; - - bool use_dht; - std::uint64_t dht_size; - int dht_snaps; - std::string dht_file; - std::string dht_outdir; - NamedVector dht_signifs; - - bool use_interp; - std::uint64_t pht_size; - std::uint32_t pht_max_entries; - std::uint32_t interp_min_entries; - NamedVector pht_signifs; - - struct Chem_Hook_Functions { - RHookFunction dht_fill; - RHookFunction> dht_fuzz; - RHookFunction> interp_pre; - RHookFunction interp_post; - } hooks; - - void initFromR(RInsidePOET &R); -}; - -} // namespace poet -/** - * @brief Reads information from program arguments and R runtime - * - * Providing functions to initialize parameters of the simulation using command - * line parameters and parameters from the R runtime. This class will also parse - * arguments from the commandline and decides if argument is known or unknown. - * - * Stores and distribute current simulation parameters at any time. - * - */ -// class SimParams { -// public: -// /** -// * @brief Construct a new SimParams object -// * -// * With all given parameters a new instance of this class will be created. -// * -// * @param world_rank Rank of process inside MPI_COMM_WORLD -// * @param world_size Size of communicator MPI_COMM_WORLD -// */ -// SimParams(int world_rank); - -// /** -// * @brief Parse program arguments -// * -// * This is done by the argh.h library. -// * -// * First, the function will check if there is a flag 'help' or 'h'. If this -// is -// * the case a help message is printed and the function will return with -// * PARSER_HELP. -// * -// * Second, if there are not 2 positional arguments an error will be printed -// to -// * stderr and the function returns with PARSER_ERROR. -// * -// * Then all given program parameters and flags will be read and checked, if -// * there are known by validateOptions. A list of all unknown options might -// be -// * returned, printed out and the function will return with PARSER_ERROR. -// * Oterhwise the function continuos. -// * -// * Now all program arguments will be stored inside t_simparams struct, -// printed -// * out and the function returns with PARSER_OK. -// * -// * Also, all parsed agruments are distributed to the R runtime. -// * -// * @param argv Argument value of the program -// * @param R Instantiated R runtime -// * @return int Returns with 0 if no error occured, otherwise value less -// than 0 -// * is returned. -// */ -// int parseFromCmdl(char *argv[], RInsidePOET &R); - -// /** -// * @brief Init std::vector values -// * -// * This will initialize dht_signif_vector and dht_prop_type_vector -// internally -// * depending on whether vectors are defined by R-Simulation file or not. -// * 'init_chemistry' must be run beforehand. -// * -// * @param R R runtime -// */ -// void initVectorParams(RInside &R); - -// /** -// * @brief Get the numerical params struct -// * -// * Returns a struct which contains all numerical or boolean simulation -// * parameters. -// * -// * @return t_simparams Parameter struct -// */ -// auto getNumParams() const { return this->simparams; }; - -// /** -// * @brief Get the DHT_Signif_Vector -// * -// * Returns a vector indicating which significant values are used for each -// * variable of a grid cell. -// * -// * @return std::vector Vector of integers containing information about -// * significant digits -// */ -// auto getDHTSignifVector() const { return this->dht_signif_vector; }; - -// auto getPHTSignifVector() const { return this->pht_signif_vector; }; - -// auto getPHTBucketSize() const { return this->pht_bucket_size; }; -// auto getPHTMinEntriesNeeded() const { return this->pht_min_entries_needed; -// }; - -// /** -// * @brief Get the filesim name -// * -// * Returns a string containing the absolute path to a R file defining the -// * simulation. -// * -// * @return std::string Absolute path to R file -// */ -// auto getFilesim() const { return this->filesim; }; - -// /** -// * @brief Get the output directory -// * -// * Returns the name of an absolute path where all output files should be -// * stored. -// * -// * @return std::string Absolute path to output path -// */ -// auto getOutDir() const { return this->out_dir; }; - -// const auto &getChemParams() const { return chem_params; } - -// private: -// std::list validateOptions(argh::parser cmdl); - -// const std::set flaglist{"ignore-result", "dht", "P", -// "progress", -// "interp"}; -// const std::set paramlist{ -// "work-package-size", "dht-strategy", -// "dht-size", "dht-snaps", -// "dht-file", "interp-size", -// "interp-min", "interp-bucket-entries"}; - -// t_simparams simparams; - -// std::vector dht_signif_vector; -// std::vector pht_signif_vector; - -// uint32_t pht_bucket_size; -// uint32_t pht_min_entries_needed; - -// std::string filesim; -// std::string out_dir; - -// ChemistryParams chem_params; -// }; -// } // namespace poet diff --git a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp index 0633469c8..fed271923 100644 --- a/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp +++ b/src/Chemistry/SurrogateModels/DHT_Wrapper.hpp @@ -26,7 +26,6 @@ #include "Base/RInsidePOET.hpp" #include "DataStructures/NamedVector.hpp" -#include "../../Base/SimParams.hpp" #include "Chemistry/ChemistryDefs.hpp" #include "Init/InitialList.hpp" From c95a6bea8bfb07ebabde0fac32793e990ad44fdf Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Tue, 2 Apr 2024 20:47:32 +0000 Subject: [PATCH 36/77] Refactor to wrap everything in main function into scope, to ensure DHT is freed before MPI_FInalize --- src/poet.cpp | 190 +++++++++++++++++++++++++-------------------------- 1 file changed, 92 insertions(+), 98 deletions(-) diff --git a/src/poet.cpp b/src/poet.cpp index 0adf6f56a..91dad5381 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -340,109 +340,103 @@ int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &world_size); - MPI_Comm_rank(MPI_COMM_WORLD, &MY_RANK); + { + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + MPI_Comm_rank(MPI_COMM_WORLD, &MY_RANK); - RInsidePOET &R = RInsidePOET::getInstance(); + RInsidePOET &R = RInsidePOET::getInstance(); - if (MY_RANK == 0) { - MSG("Running POET version " + std::string(poet_version)); + if (MY_RANK == 0) { + MSG("Running POET version " + std::string(poet_version)); + } + + /*Loading Dependencies*/ + // TODO: kann raus + R.parseEvalQ(kin_r_library); + + RuntimeParameters run_params; + + switch (parseInitValues(argv, R, run_params)) { + case ParseRet::PARSER_ERROR: + case ParseRet::PARSER_HELP: + MPI_Finalize(); + return 0; + case ParseRet::PARSER_OK: + break; + } + + InitialList init_list(R); + init_list.importList(run_params.init_params); + + MSG("RInside initialized on process " + std::to_string(MY_RANK)); + + ChemistryModule chemistry(run_params.work_package_size, + init_list.getChemistryInit(), MPI_COMM_WORLD); + + const ChemistryModule::SurrogateSetup surr_setup = { + init_list.getInitialGrid().GetProps(), + run_params.use_dht, + run_params.dht_size, + run_params.use_interp, + run_params.interp_bucket_entries, + run_params.interp_size, + run_params.interp_min_entries}; + + chemistry.masterEnableSurrogates(surr_setup); + + if (MY_RANK > 0) { + + chemistry.WorkerLoop(); + } else { + // R.parseEvalQ("mysetup <- setup"); + // // if (MY_RANK == 0) { // get timestep vector from + // // grid_init function ... // + std::string master_init_code = "mysetup <- master_init(setup=mysetup)"; + R.parseEval(master_init_code); + + // run_params.initVectorParams(R); + + // MDL: store all parameters + if (MY_RANK == 0) { + MSG("Calling R Function to store calling parameters"); + // R.parseEvalQ("StoreSetup(setup=mysetup)"); + } + + if (MY_RANK == 0) { + MSG("Init done on process with rank " + std::to_string(MY_RANK)); + } + + // MPI_Barrier(MPI_COMM_WORLD); + + DiffusionModule diffusion(init_list.getDiffusionInit(), + init_list.getInitialGrid()); + + chemistry.masterSetField(init_list.getInitialGrid()); + + Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); + + MSG("finished simulation loop"); + + MSG("start timing profiling"); + + // R["simtime"] = dSimTime; + // R.parseEvalQ("profiling$simtime <- simtime"); + + R["profiling"] = profiling; + + string r_vis_code; + r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; + R.parseEval(r_vis_code); + + // MSG("Done! Results are stored as R objects into <" + + // run_params.getOutDir() + // + + // "/timings.rds>"); + } } - /*Loading Dependencies*/ - // TODO: kann raus - R.parseEvalQ(kin_r_library); - - RuntimeParameters run_params; - - switch (parseInitValues(argv, R, run_params)) { - case ParseRet::PARSER_ERROR: - case ParseRet::PARSER_HELP: - MPI_Finalize(); - return 0; - case ParseRet::PARSER_OK: - break; - } - - InitialList init_list(R); - init_list.importList(run_params.init_params); - - MSG("RInside initialized on process " + std::to_string(MY_RANK)); - - ChemistryModule chemistry(run_params.work_package_size, - init_list.getChemistryInit(), MPI_COMM_WORLD); - - const ChemistryModule::SurrogateSetup surr_setup = { - init_list.getInitialGrid().GetProps(), - run_params.use_dht, - run_params.dht_size, - run_params.use_interp, - run_params.interp_bucket_entries, - run_params.interp_size, - run_params.interp_min_entries}; - - chemistry.masterEnableSurrogates(surr_setup); - - if (MY_RANK > 0) { - - chemistry.WorkerLoop(); - - MPI_Barrier(MPI_COMM_WORLD); - - MSG("finished, cleanup of process " + std::to_string(MY_RANK)); - - MPI_Finalize(); - - return EXIT_SUCCESS; - } - - // R.parseEvalQ("mysetup <- setup"); - // // if (MY_RANK == 0) { // get timestep vector from - // // grid_init function ... // - std::string master_init_code = "mysetup <- master_init(setup=mysetup)"; - R.parseEval(master_init_code); - - // run_params.initVectorParams(R); - - // MDL: store all parameters - if (MY_RANK == 0) { - MSG("Calling R Function to store calling parameters"); - // R.parseEvalQ("StoreSetup(setup=mysetup)"); - } - - if (MY_RANK == 0) { - MSG("Init done on process with rank " + std::to_string(MY_RANK)); - } - - // MPI_Barrier(MPI_COMM_WORLD); - - DiffusionModule diffusion(init_list.getDiffusionInit(), - init_list.getInitialGrid()); - - chemistry.masterSetField(init_list.getInitialGrid()); - - Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); - - MSG("finished simulation loop"); - - MSG("start timing profiling"); - - // R["simtime"] = dSimTime; - // R.parseEvalQ("profiling$simtime <- simtime"); - - R["profiling"] = profiling; - - string r_vis_code; - r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; - R.parseEval(r_vis_code); - - // MSG("Done! Results are stored as R objects into <" + run_params.getOutDir() - // + - // "/timings.rds>"); - - MPI_Barrier(MPI_COMM_WORLD); - MSG("finished, cleanup of process " + std::to_string(MY_RANK)); + MPI_Finalize(); if (MY_RANK == 0) { From cb6e6345766dfcce49b24511091e6be827b36d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 3 Apr 2024 10:08:02 +0200 Subject: [PATCH 37/77] Update out_save in dolo_200_rt.R --- bench/dolo/het/dolo_200_rt.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/dolo/het/dolo_200_rt.R b/bench/dolo/het/dolo_200_rt.R index 1df317130..922aade98 100644 --- a/bench/dolo/het/dolo_200_rt.R +++ b/bench/dolo/het/dolo_200_rt.R @@ -4,5 +4,5 @@ dt <- 50 list( timesteps = rep(dt, iterations), store_result = TRUE, - out_save = c(5, iterations, by = 5) -) \ No newline at end of file + out_save = seq(5, iterations, by = 5) +) From b665aa63074643a48498297a6d38cde3f584fbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 3 Apr 2024 10:08:37 +0200 Subject: [PATCH 38/77] Update Calcite and Dolomite parameters in dol.pqi --- bench/dolo/het/dol.pqi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/dolo/het/dol.pqi b/bench/dolo/het/dol.pqi index ae556bc5a..8ecf0f056 100644 --- a/bench/dolo/het/dol.pqi +++ b/bench/dolo/het/dol.pqi @@ -22,11 +22,11 @@ PURE 2 KINETICS 2 Calcite -m 0.000207 - -parms 0.0032 + -parms 0.05 -tol 1e-10 Dolomite -m 0.0 - -parms 0.00032 + -parms 0.005 -tol 1e-10 END From 774f0b7df32cc36915737a2517b99833c1ade689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 3 Apr 2024 10:10:02 +0200 Subject: [PATCH 39/77] Update GIT_SUBMODULE_STRATEGY in .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c861d40a3..46f15eb8b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ stages: # List of stages for jobs, and their order of execution - test variables: -# GIT_SUBMODULE_STRATEGY: recursive + GIT_SUBMODULE_STRATEGY: recursive SOURCE_ARCHIVE_NAME: 'poet_${CI_COMMIT_TAG}_sources.tar.gz' CHANGELOG_FILE: 'commit_changelog.md' From 82097e56b19b2cc63f0ccd629ed08e53be407f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 3 Apr 2024 10:59:31 +0200 Subject: [PATCH 40/77] Update units in dol.pqi --- bench/dolo/het/dol.pqi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/dolo/het/dol.pqi b/bench/dolo/het/dol.pqi index 8ecf0f056..a478b4fc7 100644 --- a/bench/dolo/het/dol.pqi +++ b/bench/dolo/het/dol.pqi @@ -31,7 +31,7 @@ KINETICS 2 END SOLUTION 3 - pH 7 + units mol/kgw water 1 temp 25 Mg 0.001 From 8e20d177e159d64ed2e83e83f8876ad98cf972b4 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 10:43:14 +0000 Subject: [PATCH 41/77] Update runtime and test scripts --- bench/barite/het/barite_het.pqi | 1 + bench/barite/het/runtime.R | 2 +- bench/barite/het/test.R | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bench/barite/het/barite_het.pqi b/bench/barite/het/barite_het.pqi index b13bcd1c0..b8cf1e101 100644 --- a/bench/barite/het/barite_het.pqi +++ b/bench/barite/het/barite_het.pqi @@ -60,6 +60,7 @@ END ## A BaCl2 solution (nr 4) is "injected" from the left boundary: SOLUTION 4 +units mol/kgw pH 7 water 1 temp 25 diff --git a/bench/barite/het/runtime.R b/bench/barite/het/runtime.R index 4dea41fdf..a0b63df67 100644 --- a/bench/barite/het/runtime.R +++ b/bench/barite/het/runtime.R @@ -1,4 +1,4 @@ list( - timesteps = c(1), + timesteps = rep(50, 100), store_result = TRUE ) \ No newline at end of file diff --git a/bench/barite/het/test.R b/bench/barite/het/test.R index f7269e3f7..63807144e 100644 --- a/bench/barite/het/test.R +++ b/bench/barite/het/test.R @@ -11,7 +11,7 @@ grid_setup <- list( diffusion_setup <- list( boundaries = list( - "E" = list( + "W" = list( "type" = rep("constant", nrow(grid_def)), "sol_id" = rep(4, nrow(grid_def)), "cell" = seq_len(nrow(grid_def)) @@ -27,5 +27,6 @@ diffusion_setup <- list( # Define a setup list for simulation configuration setup <- list( Grid = grid_setup, # Parameters related to the grid structure - Diffusion = diffusion_setup # Parameters related to the diffusion process + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = list() ) From 64989a8af830fd581ce42910c9f26682b59de181 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 10:46:25 +0000 Subject: [PATCH 42/77] Update chem.GetField() to chem.getField() in poet.cpp --- src/Chemistry/ChemistryModule.hpp | 4 ---- src/poet.cpp | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index 12d322986..e7d74c290 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -57,10 +57,6 @@ public: */ void simulate(double dt); - /** - * Returns the chemical field. - */ - auto &GetField() { return this->chem_field; } /** * Returns all known species names, including not only aqueous species, but * also equilibrium, exchange, surface and kinetic reactants. diff --git a/src/poet.cpp b/src/poet.cpp index 91dad5381..adb5dfcd9 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -254,7 +254,7 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, // TODO: transport to diffusion diffusion.simulate(dt); - chem.GetField().update(diffusion.getField()); + chem.getField().update(diffusion.getField()); // chem.getfield().update(diffusion.getfield()); @@ -262,10 +262,10 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, chem.simulate(dt); - writeFieldsToR(R, diffusion.getField(), chem.GetField()); + writeFieldsToR(R, diffusion.getField(), chem.getField()); // R["store_result"] = true; // R.parseEval("mysetup$store_result <- TRUE"); - diffusion.getField().update(chem.GetField()); + diffusion.getField().update(chem.getField()); R["req_dt"] = dt; R["simtime"] = (sim_time += dt); From d2b01c28fc37bf8bbd212f4b283e0c7d327b07ff Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 10:46:32 +0000 Subject: [PATCH 43/77] Update iphreeqc subproject commit --- ext/iphreeqc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/iphreeqc b/ext/iphreeqc index daeecf112..c0c830eab 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit daeecf11263dbeb08cb13b43df81d5d9dcc22060 +Subproject commit c0c830eab7c49ec0bf4ef87ef0669f6c15bae58c From 479bfa4c6ed777f6fb5c5dbe2b6d61d455bd738a Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 12:31:45 +0000 Subject: [PATCH 44/77] Add support for missing species in init grid, which are injected (by boundary condition) --- R_lib/init_r_lib.R | 28 +++++++++++++- ext/iphreeqc | 2 +- src/Init/DiffusionInit.cpp | 77 +++++++++++++++++++++++++++++++++++++- src/Init/GridInit.cpp | 16 ++++---- src/Init/InitialList.cpp | 2 +- src/Init/InitialList.hpp | 7 +++- 6 files changed, 119 insertions(+), 13 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index c9b096057..a33a3adba 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -29,7 +29,7 @@ pqc_to_grid <- function(pqc_in, grid) { return(res_df) } -resolvePqcBound <- function(pqc_mat, transport_spec, id) { +resolve_pqc_bound <- function(pqc_mat, transport_spec, id) { df <- as.data.frame(pqc_mat, check.names = FALSE) value <- df[df$ID == id, transport_spec] @@ -39,3 +39,29 @@ resolvePqcBound <- function(pqc_mat, transport_spec, id) { return(value) } + +add_column_after_position <- function(df, new_col, pos, new_col_name) { + # Split the data frame into two parts + df_left <- df[, 1:(pos)] + df_right <- df[, (pos + 1):ncol(df)] + + # Add the new column to the left part + df_left[[new_col_name]] <- new_col + + # Combine the left part, new column, and right part + df_new <- cbind(df_left, df_right) + + return(df_new) +} + +add_missing_transport_species <- function(init_grid, new_names, old_size) { + # skip the ID column + column_index <- old_size + 1 + + for (name in new_names) { + init_grid <- add_column_after_position(init_grid, rep(0, nrow(init_grid)), column_index, name) + column_index <- column_index + 1 + } + + return(init_grid) +} \ No newline at end of file diff --git a/ext/iphreeqc b/ext/iphreeqc index c0c830eab..4ec8b7006 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit c0c830eab7c49ec0bf4ef87ef0669f6c15bae58c +Subproject commit 4ec8b7006c215ad9fc1310505cd56d03ba4b17dd diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index c85c9c8d7..6abe43229 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -6,13 +6,16 @@ #include #include "DataStructures/Field.hpp" +#include "IPhreeqcPOET.hpp" #include "InitialList.hpp" +#include #include #include #include #include #include +#include #include #include #include @@ -49,9 +52,81 @@ static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, } } +static std::vector extend_transport_names( + std::unique_ptr &phreeqc, const Rcpp::List &boundaries_list, + const std::vector &old_trans_names, Rcpp::List &initial_grid) { + + std::vector transport_names = old_trans_names; + std::set constant_pqc_ids; + + for (const auto &side : tug_side_mapping) { + if (!boundaries_list.containsElementNamed(side.second.c_str())) { + continue; + } + + Rcpp::List mapping = boundaries_list[side.second]; + + const Rcpp::NumericVector cells = mapping["cell"]; + const Rcpp::NumericVector values = mapping["sol_id"]; + const Rcpp::CharacterVector type_str = mapping["type"]; + + if (cells.size() != values.size()) { + throw std::runtime_error("Boundary [" + side.second + + "] cells and values are not the same " + "length"); + } + + for (std::size_t i = 0; i < cells.size(); i++) { + if (type_str[i] == "constant") { + constant_pqc_ids.insert(values[i]); + } + } + } + + if (!constant_pqc_ids.empty()) { + for (const auto &pqc_id : constant_pqc_ids) { + const auto solution_names = phreeqc->getSolutionNames(pqc_id); + + // add those strings which are not already in the transport_names + for (const auto &name : solution_names) { + if (std::find(transport_names.begin(), transport_names.end(), name) == + transport_names.end()) { + transport_names.push_back(name); + } + } + } + } + + return transport_names; +} + +static Rcpp::List extend_initial_grid(const Rcpp::List &initial_grid, + std::vector transport_names, + std::size_t old_size) { + std::vector names_to_add(transport_names.begin() + old_size, + transport_names.end()); + + Rcpp::Function extend_grid_R("add_missing_transport_species"); + + return extend_grid_R(initial_grid, Rcpp::wrap(names_to_add), old_size); +} + Rcpp::List InitialList::resolveBoundaries(const Rcpp::List &boundaries_list) { Rcpp::List bound_list; - Rcpp::Function resolve_R("resolvePqcBound"); + Rcpp::Function resolve_R("resolve_pqc_bound"); + + const std::size_t old_transport_size = this->transport_names.size(); + + this->transport_names = + extend_transport_names(this->phreeqc, boundaries_list, + this->transport_names, this->initial_grid); + + const std::size_t new_transport_size = this->transport_names.size(); + + if (old_transport_size != new_transport_size) { + this->initial_grid = extend_initial_grid( + this->initial_grid, this->transport_names, old_transport_size); + } for (const auto &species : this->transport_names) { Rcpp::List spec_list; diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 2ec7fab33..29f9c9d48 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -13,8 +14,9 @@ namespace poet { -static Rcpp::NumericMatrix pqcScriptToGrid(IPhreeqcPOET &phreeqc, RInside &R) { - IPhreeqcPOET::PhreeqcMat phreeqc_mat = phreeqc.getPhreeqcMat(); +static Rcpp::NumericMatrix +pqcScriptToGrid(std::unique_ptr &phreeqc, RInside &R) { + IPhreeqcPOET::PhreeqcMat phreeqc_mat = phreeqc->getPhreeqcMat(); // add "id" to the front of the column names @@ -57,7 +59,7 @@ replaceRawKeywordIDs(std::map raws) { return raws; } -static inline uint32_t getSolutionCount(IPhreeqcPOET &phreeqc, +static inline uint32_t getSolutionCount(std::unique_ptr &phreeqc, const Rcpp::List &initial_grid) { IPhreeqcPOET::ModulesArray mod_array; Rcpp::Function unique_R("unique"); @@ -73,7 +75,7 @@ static inline uint32_t getSolutionCount(IPhreeqcPOET &phreeqc, // std::copy(sizes_vec.begin(), sizes_vec.end(), sizes.begin()); - return phreeqc.getModuleSizes(row_ids)[POET_SOL]; + return phreeqc->getModuleSizes(row_ids)[POET_SOL]; } static std::string readFile(const std::string &path) { @@ -95,7 +97,7 @@ static std::string readFile(const std::string &path) { return buffer.str(); } -void InitialList::initGrid(const Rcpp::List &grid_input) { +void InitialList::prepareGrid(const Rcpp::List &grid_input) { // parse input values Rcpp::Function unique_R("unique"); @@ -153,7 +155,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { throw std::runtime_error("Grid size must be positive."); } - IPhreeqcPOET phreeqc(database, script); + this->phreeqc = std::make_unique(database, script); this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); @@ -169,7 +171,7 @@ void InitialList::initGrid(const Rcpp::List &grid_input) { std::map pqc_raw_dumps; - pqc_raw_dumps = replaceRawKeywordIDs(phreeqc.raw_dumps()); + pqc_raw_dumps = replaceRawKeywordIDs(phreeqc->raw_dumps()); this->pqc_ids = Rcpp::as>(unique_R(this->initial_grid["ID"])); diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index bca49a239..90e0a1dd3 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -10,7 +10,7 @@ namespace poet { void InitialList::initializeFromList(const Rcpp::List &setup) { - initGrid(setup[grid_key]); + prepareGrid(setup[grid_key]); initDiffusion(setup[diffusion_key]); initChemistry(setup[chemistry_key]); } diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 3a73ad0ba..1500518c1 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -1,9 +1,9 @@ #pragma once #include "Base/RInsidePOET.hpp" -#include "Chemistry/ChemistryDefs.hpp" #include "DataStructures/NamedVector.hpp" #include +#include #include #include @@ -86,7 +86,10 @@ private: return GridMembersString[static_cast(member)]; } - void initGrid(const Rcpp::List &grid_input); + std::unique_ptr phreeqc; + + void prepareGrid(const Rcpp::List &grid_input); + std::uint8_t dim; std::uint32_t n_cols; From 2addcfbbf0ab25916963a9356e1cc7453a17b348 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 12:32:10 +0000 Subject: [PATCH 45/77] Update solution parameters in dol.pqi --- bench/dolo/het/dol.pqi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bench/dolo/het/dol.pqi b/bench/dolo/het/dol.pqi index a478b4fc7..b9ff89fd7 100644 --- a/bench/dolo/het/dol.pqi +++ b/bench/dolo/het/dol.pqi @@ -4,10 +4,10 @@ SOLUTION 1 temperature 25 pH 7 pe 4 - C 1e-12 - Ca 1e-12 - Cl 1e-12 - Mg 1e-12 +# C 1e-12 +# Ca 1e-12 +# Cl 1e-12 +# Mg 1e-12 PURE 1 Calcite 0.0 1 END From 1b52e25947d4037521b4aa303ba062885511e9d5 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 13:00:58 +0000 Subject: [PATCH 46/77] Fix initialization of transport_names in ChemistryInit and GridInit --- src/Init/ChemistryInit.cpp | 2 ++ src/Init/GridInit.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index c1f884fa2..e5f59380e 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -6,6 +6,8 @@ namespace poet { void InitialList::initChemistry(const Rcpp::List &chem) { + this->pqc_sol_order = this->transport_names; + if (chem.containsElementNamed("dht_species")) { this->dht_species = Rcpp::as>(chem["dht_species"]); } diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 29f9c9d48..a35295769 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -165,7 +165,7 @@ void InitialList::prepareGrid(const Rcpp::List &grid_input) { std::vector colnames = Rcpp::as>(this->initial_grid.names()); - this->transport_names = this->pqc_sol_order = std::vector( + this->transport_names = std::vector( colnames.begin() + 1, colnames.begin() + 1 + solution_count); // skip ID From 707a78d8b6535737b0f486d4db6a9892ca517a80 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 14:24:23 +0000 Subject: [PATCH 47/77] Add parallel grid creation function and update pqc_to_grid function --- R_lib/init_r_lib.R | 54 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index a33a3adba..f6b433b42 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -1,4 +1,7 @@ -pqc_to_grid <- function(pqc_in, grid) { +has_foreach <- require(foreach) +has_doParallel <- require(doParallel) + +seq_pqc_to_grid <- function(pqc_in, grid) { # Convert the input DataFrame to a matrix dt <- as.matrix(pqc_in) @@ -29,6 +32,55 @@ pqc_to_grid <- function(pqc_in, grid) { return(res_df) } +par_pqc_to_grid <- function(pqc_in, grid) { + # Convert the input DataFrame to a matrix + dt <- as.matrix(pqc_in) + + # Flatten the matrix into a vector + id_vector <- as.vector(t(grid)) + + # Initialize an empty matrix to store the results + # result_mat <- matrix(nrow = 0, ncol = ncol(dt)) + + # Set up parallel processing + num_cores <- detectCores() + cl <- makeCluster(num_cores) + registerDoParallel(cl) + + # Iterate over each ID in the vector in parallel + result_mat <- foreach(id_mat = id_vector, .combine = rbind) %dopar% { + # Find the matching row in the matrix + matching_row <- dt[dt[, "ID"] == id_mat, ] + + # Return the matching row + matching_row + } + + # Stop the parallel processing + stopCluster(cl) + + # Convert the result matrix to a data frame + res_df <- as.data.frame(result_mat) + + # Remove all columns which only contain NaN + res_df <- res_df[, colSums(is.na(res_df)) != nrow(res_df)] + + # Remove row names + rownames(res_df) <- NULL + + return(res_df) +} + +pqc_to_grid <- function(pqc_in, grid) { + if (has_doParallel && has_foreach) { + print("Using parallel grid creation") + return(par_pqc_to_grid(pqc_in, grid)) + } else { + print("Using sequential grid creation") + return(seq_pqc_to_grid(pqc_in, grid)) + } +} + resolve_pqc_bound <- function(pqc_mat, transport_spec, id) { df <- as.data.frame(pqc_mat, check.names = FALSE) value <- df[df$ID == id, transport_spec] From 5880f28762b335572a7c8a81b19b20096bf87da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 3 Apr 2024 16:46:50 +0200 Subject: [PATCH 48/77] Update iterations and dt values in dolo_200_rt.R --- bench/dolo/het/dolo_200_rt.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/dolo/het/dolo_200_rt.R b/bench/dolo/het/dolo_200_rt.R index 922aade98..7cf510bb9 100644 --- a/bench/dolo/het/dolo_200_rt.R +++ b/bench/dolo/het/dolo_200_rt.R @@ -1,8 +1,8 @@ -iterations <- 100 -dt <- 50 +iterations <- 500 +dt <- 500 list( timesteps = rep(dt, iterations), store_result = TRUE, - out_save = seq(5, iterations, by = 5) + out_save = seq(50, iterations, by = 50) ) From 79fd1ebe9d998dacb20928000ed6e09aef771249 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 21:03:10 +0000 Subject: [PATCH 49/77] Refactor R functions and how they are called --- R_lib/kin_r_library.R | 188 +++++------------------------------------- src/poet.cpp | 106 ++++++++++-------------- src/poet.hpp.in | 1 + 3 files changed, 67 insertions(+), 228 deletions(-) diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index c8bdedb73..33e6ef1dc 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -15,35 +15,19 @@ ### this program; if not, write to the Free Software Foundation, Inc., 51 ### Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -## Simple function to check file extension. It is needed to check if -## the GridFile is SUM (MUFITS format) or rds/RData -FileExt <- function(x) { - pos <- regexpr("\\.([[:alnum:]]+)$", x) - ifelse(pos > -1L, substring(x, pos + 1L), "") -} - -master_init <- function(setup) { - msgm("Process with rank 0 reading GRID properties") - +master_init <- function(setup, out_dir) { ## Setup the directory where we will store the results - verb <- FALSE - # if (local_rank == 0) { - verb <- TRUE ## verbosity loading MUFITS results - if (!dir.exists(fileout)) { - dir.create(fileout) - msgm("created directory ", fileout) - } else { - msgm("dir ", fileout, " already exists, I will overwrite!") - } - if (!exists("store_result")) { - msgm("store_result doesn't exist!") - } else { - msgm("store_result is ", store_result) - } - # } else { - - # } + if (!dir.exists(out_dir)) { + dir.create(out_dir) + msgm("created directory ", out_dir) + } else { + msgm("dir ", out_dir, " already exists, I will overwrite!") + } + if (!exists("setup$store_result")) { + msgm("store_result doesn't exist!") + } else { + msgm("store_result is ", setup$store_result) + } setup$iter <- 1 setup$timesteps <- setup$timesteps @@ -67,8 +51,8 @@ master_init <- function(setup) { ## This function, called only by master, stores on disk the last ## calculated time step if store_result is TRUE and increments the ## iteration counter -master_iteration_end <- function(setup,iter) { - # iter <- setup$iter +master_iteration_end <- function(setup, state_T, state_C) { + iter <- setup$iter # print(iter) ## max digits for iterations dgts <- as.integer(ceiling(log10(iter))) @@ -80,164 +64,34 @@ master_iteration_end <- function(setup,iter) { if (setup$store_result) { if (iter %in% setup$out_save) { nameout <- paste0(fileout, "/iter_", sprintf(fmt = fmt, iter), ".rds") - info <- list( - tr_req_dt = as.integer(1) - ## tr_allow_dt = setup$allowed_dt, - ## tr_inniter = as.integer(setup$inniter) - ) saveRDS(list( - T = setup$state_T, C = setup$state_C, - simtime = as.integer(0), - tr_info = info + T = state_T, C = state_C, + simtime = as.integer(setup$simulation_time) ), file = nameout) msgm("results stored in <", nameout, ">") } } + ## Add last time step to simulation time + setup$simulation_time <- setup$simulation_time + setup$dt_differ + msgm("done iteration", iter, "/", length(setup$timesteps)) setup$iter <- setup$iter + 1 return(setup) } -## function for the workers to compute chemistry through PHREEQC -slave_chemistry <- function(setup, data) { - base <- setup$base - first <- setup$first - prop <- setup$prop - immobile <- setup$immobile - kin <- setup$kin - ann <- setup$ann - - iter <- setup$iter - timesteps <- setup$timesteps - dt <- timesteps[iter] - - state_T <- data ## not the global field, but the work-package - - ## treat special H+/pH, e-/pe cases - state_T <- RedModRphree::Act2pH(state_T) - - ## reduction of the problem - if (setup$reduce) { - reduced <- ReduceStateOmit(state_T, omit = setup$ann) - } else { - reduced <- state_T - } - - ## form the PHREEQC input script for the current work package - inplist <- SplitMultiKin( - data = reduced, procs = 1, base = base, first = first, - ann = ann, prop = prop, minerals = immobile, kin = kin, dt = dt - ) - - ## if (local_rank==1 & iter==1) - ## RPhreeWriteInp("FirstInp", inplist) - - tmpC <- RunPQC(inplist, procs = 1, second = TRUE) - - ## recompose after the reduction - if (setup$reduce) { - state_C <- RecomposeState(tmpC, reduced) - } else { - state_C <- tmpC - } - - ## the next line is needed since we don't need all columns of - ## PHREEQC output - return(state_C[, prop]) -} - -## This function, called by master -master_chemistry <- function(setup, data) { - state_T <- setup$state_T - - msgm(" chemistry iteration", setup$iter) - - ## treat special H+/pH, e-/pe cases - state_T <- RedModRphree::Act2pH(state_T) - - ## reduction of the problem - if (setup$reduce) { - reduced <- ReduceStateOmit(state_T, omit = setup$ann) - } else { - reduced <- state_T - } - - ## inject data from workers - res_C <- data - - rownames(res_C) <- NULL - - ## print(res_C) - - if (nrow(res_C) > nrow(reduced)) { - res_C <- res_C[seq(2, nrow(res_C), by = 2), ] - } - - ## recompose after the reduction - if (setup$reduce) { - state_C <- RecomposeState(res_C, reduced) - } else { - state_C <- res_C - } - - setup$state_C <- state_C - setup$reduced <- reduced - - return(setup) -} - - -## Adapted version for "reduction" -ReduceStateOmit <- function(data, omit = NULL, sign = 6) { - require(mgcv) - - rem <- colnames(data) - if (is.list(omit)) { - indomi <- match(names(omit), colnames(data)) - datao <- data[, -indomi] - } else { - datao <- data - } - - datao <- signif(datao, sign) - red <- mgcv::uniquecombs(datao) - inds <- attr(red, "index") - now <- ncol(red) - - - ## reattach the omitted column(s) - ## FIXME: control if more than one ann is present - if (is.list(omit)) { - red <- cbind(red, rep(data[1, indomi], nrow(red))) - - colnames(red)[now + 1] <- names(omit) - - ret <- red[, colnames(data)] - } else { - ret <- red - } - rownames(ret) <- NULL - attr(ret, "index") <- inds - return(ret) -} - - ## Attach the name of the calling function to the message displayed on ## R's stdout msgm <- function(...) { - # if (local_rank == 0) { - fname <- as.list(sys.call(-1))[[1]] - prefix <- paste0("R: ", fname, " ::") + prefix <- paste0("R: ") cat(paste(prefix, ..., "\n")) - # } invisible() } ## Function called by master R process to store on disk all relevant ## parameters for the simulation -StoreSetup <- function(setup) { +StoreSetup <- function(setup, filesim, out_dir) { to_store <- vector(mode = "list", length = 4) ## names(to_store) <- c("Sim", "Flow", "Transport", "Chemistry", "DHT") names(to_store) <- c("Sim", "Transport", "DHT", "Cmdline") diff --git a/src/poet.cpp b/src/poet.cpp index adb5dfcd9..253062c88 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -29,8 +29,13 @@ #include #include +#include +#include +#include #include +#include #include +#include #include #include "Base/argh.hpp" @@ -43,6 +48,21 @@ using namespace Rcpp; static int MY_RANK = 0; +static std::unique_ptr global_rt_setup; + +// we need some layz evaluation, as we can't define the functions before the R +// runtime is initialized +static std::optional master_init_R; +static std::optional master_iteration_end_R; +static std::optional store_setup_R; + +static void init_global_functions(RInside &R) { + R.parseEval(kin_r_library); + master_init_R = Rcpp::Function("master_init"); + master_iteration_end_R = Rcpp::Function("master_iteration_end"); + store_setup_R = Rcpp::Function("StoreSetup"); +} + // HACK: this is a step back as the order and also the count of fields is // predefined, but it will change in the future void writeFieldsToR(RInside &R, const Field &trans, const Field &chem) { @@ -126,12 +146,6 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, cmdl("interp-min", 5) >> params.interp_min_entries; cmdl("interp-bucket-entries", 20) >> params.interp_bucket_entries; - /*Parse output options*/ - // simparams.store_result = !cmdl["ignore-result"]; - - /*Parse output options*/ - // simparams.store_result = !cmdl["ignore-result"]; - if (MY_RANK == 0) { // MSG("Complete results storage is " + BOOL_PRINT(simparams.store_result)); MSG("Work Package Size: " + std::to_string(params.work_package_size)); @@ -162,21 +176,20 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, std::string init_file; std::string runtime_file; - std::string out_dir; cmdl(1) >> runtime_file; cmdl(2) >> init_file; - cmdl(3) >> out_dir; + cmdl(3) >> params.out_dir; // chem_params.dht_outdir = out_dir; /* distribute information to R runtime */ // if local_rank == 0 then master else worker - R["local_rank"] = MY_RANK; + // R["local_rank"] = MY_RANK; // assign a char* (string) to 'filesim' - R["filesim"] = wrap(runtime_file); + // R["filesim"] = wrap(runtime_file); // assign a char* (string) to 'fileout' - R["fileout"] = wrap(out_dir); + // R["fileout"] = wrap(out_dir); // pass the boolean "store_result" to the R process // R["store_result"] = simparams.store_result; // // worker count @@ -195,23 +208,17 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, Rcpp::List init_params_ = readRDS(init_file); params.init_params = init_params_; - Rcpp::List runtime_params = - source(runtime_file, Rcpp::Named("local", true)); - runtime_params = runtime_params["value"]; - R[r_runtime_parameters] = runtime_params; + global_rt_setup = std::make_unique(); + *global_rt_setup = source(runtime_file, Rcpp::Named("local", true)); + *global_rt_setup = global_rt_setup->operator[]("value"); params.timesteps = - Rcpp::as>(runtime_params["timesteps"]); + Rcpp::as>(global_rt_setup->operator[]("timesteps")); } catch (const std::exception &e) { ERRMSG("Error while parsing R scripts: " + std::string(e.what())); return ParseRet::PARSER_ERROR; } - // eval the init string, ignoring any returns - // R.parseEvalQ("source(filesim)"); - // R.parseEvalQ("mysetup <- setup"); - - // this->chem_params.initFromR(R); return ParseRet::PARSER_OK; } @@ -236,8 +243,6 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, for (uint32_t iter = 1; iter < maxiter + 1; iter++) { double start_t = MPI_Wtime(); uint32_t tick = 0; - // cout << "CPP: Evaluating next time step" << endl; - // R.parseEvalQ("mysetup <- master_iteration_setup(mysetup)"); const double &dt = params.timesteps[iter - 1]; @@ -246,12 +251,8 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, /* displaying iteration number, with C++ and R iterator */ MSG("Going through iteration " + std::to_string(iter)); - // MSG("R's $iter: " + - // std::to_string((uint32_t)(R.parseEval("mysetup$iter"))) + - // ". Iteration"); /* run transport */ - // TODO: transport to diffusion diffusion.simulate(dt); chem.getField().update(diffusion.getField()); @@ -262,24 +263,15 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, chem.simulate(dt); - writeFieldsToR(R, diffusion.getField(), chem.getField()); - // R["store_result"] = true; - // R.parseEval("mysetup$store_result <- TRUE"); diffusion.getField().update(chem.getField()); - R["req_dt"] = dt; - R["simtime"] = (sim_time += dt); - - R.parseEval("mysetup$req_dt <- req_dt"); - R.parseEval("mysetup$simtime <- simtime"); - - R["iter"] = iter; - // 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.parseEval("mysetup <- master_iteration_end(setup=mysetup, iter)"); + *global_rt_setup = master_iteration_end_R.value()( + *global_rt_setup, diffusion.getField().asSEXP(), + chem.getField().asSEXP()); MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + std::to_string(maxiter)); @@ -350,10 +342,6 @@ int main(int argc, char *argv[]) { MSG("Running POET version " + std::string(poet_version)); } - /*Loading Dependencies*/ - // TODO: kann raus - R.parseEvalQ(kin_r_library); - RuntimeParameters run_params; switch (parseInitValues(argv, R, run_params)) { @@ -370,6 +358,10 @@ int main(int argc, char *argv[]) { MSG("RInside initialized on process " + std::to_string(MY_RANK)); + std::cout << std::flush; + + MPI_Barrier(MPI_COMM_WORLD); + ChemistryModule chemistry(run_params.work_package_size, init_list.getChemistryInit(), MPI_COMM_WORLD); @@ -385,26 +377,22 @@ int main(int argc, char *argv[]) { chemistry.masterEnableSurrogates(surr_setup); if (MY_RANK > 0) { - chemistry.WorkerLoop(); } else { + + init_global_functions(R); + // R.parseEvalQ("mysetup <- setup"); // // if (MY_RANK == 0) { // get timestep vector from // // grid_init function ... // - std::string master_init_code = "mysetup <- master_init(setup=mysetup)"; - R.parseEval(master_init_code); - - // run_params.initVectorParams(R); + *global_rt_setup = + master_init_R.value()(*global_rt_setup, run_params.out_dir); // MDL: store all parameters - if (MY_RANK == 0) { - MSG("Calling R Function to store calling parameters"); - // R.parseEvalQ("StoreSetup(setup=mysetup)"); - } + // MSG("Calling R Function to store calling parameters"); + // R.parseEvalQ("StoreSetup(setup=mysetup)"); - if (MY_RANK == 0) { - MSG("Init done on process with rank " + std::to_string(MY_RANK)); - } + MSG("Init done on process with rank " + std::to_string(MY_RANK)); // MPI_Barrier(MPI_COMM_WORLD); @@ -417,8 +405,6 @@ int main(int argc, char *argv[]) { MSG("finished simulation loop"); - MSG("start timing profiling"); - // R["simtime"] = dSimTime; // R.parseEvalQ("profiling$simtime <- simtime"); @@ -428,10 +414,8 @@ int main(int argc, char *argv[]) { r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; R.parseEval(r_vis_code); - // MSG("Done! Results are stored as R objects into <" + - // run_params.getOutDir() - // + - // "/timings.rds>"); + MSG("Done! Results are stored as R objects into <" + run_params.out_dir + + "/timings.rds>"); } } diff --git a/src/poet.hpp.in b/src/poet.hpp.in index 80db8d436..f9a86be77 100644 --- a/src/poet.hpp.in +++ b/src/poet.hpp.in @@ -49,6 +49,7 @@ constexpr uint32_t CHEM_DEFAULT_WORK_PACKAGE_SIZE = 32; constexpr uint32_t CHEM_DHT_SIZE_PER_PROCESS_MB = 1.5E3; struct RuntimeParameters { + std::string out_dir; std::vector timesteps; bool print_progressbar; From 320ae7a6f0ca6f44f6192525f10026fbadb8db51 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 21:03:16 +0000 Subject: [PATCH 50/77] Update Dockerfile with required dependencies and install R packages --- .devcontainer/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 07e77023c..3d5ad4b63 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,13 +2,11 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:debian RUN sudo apt-get update && export DEBIAN_FRONTEND=noninteractive \ && sudo apt-get install -y \ - cmake-curses-gui \ + cmake \ git \ libeigen3-dev \ libopenmpi-dev \ - r-cran-rcpp \ - r-cran-rinside \ - gdb + r-base-dev RUN git clone https://github.com/doctest/doctest.git /doctest \ && cd /doctest \ @@ -18,3 +16,5 @@ RUN git clone https://github.com/doctest/doctest.git /doctest \ && make install \ && cd / \ && rm -rf /doctest + +RUN /usr/bin/R -q -e "install.packages(c('foreach', 'doParallel', 'Rcpp', 'RInside'))" \ No newline at end of file From ec2dff0be1f3468a55c76202b5b7654011e2584e Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Wed, 3 Apr 2024 21:19:39 +0000 Subject: [PATCH 51/77] Add file extension replacement and print output filename --- src/initializer.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/initializer.cpp b/src/initializer.cpp index eacc45a72..d0cdada1a 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -6,6 +6,7 @@ #include #include +#include int main(int argc, char **argv) { if (argc < 2 || argc > 2) { @@ -32,9 +33,14 @@ int main(int argc, char **argv) { init.initializeFromList(setup); - Rcpp::Function save("saveRDS"); + // replace file extension by .rds + const std::string rds_out_filename = + script.substr(0, script.find_last_of('.')) + ".rds"; - save(init.exportList(), "init.rds"); + Rcpp::Function save("saveRDS"); + save(init.exportList(), Rcpp::wrap(rds_out_filename)); + + std::cout << "Saved result to " << rds_out_filename << std::endl; // parseGrid(R, grid, results); return EXIT_SUCCESS; From aed2ff4be14afe280350a2d123012a6873072882 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Thu, 4 Apr 2024 09:27:27 +0000 Subject: [PATCH 52/77] Add functions for checking sign and negativity in dol.pqi and dolo_200.R --- bench/dolo/het/dol.pqi | 4 ---- bench/dolo/het/dolo_200.R | 42 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/bench/dolo/het/dol.pqi b/bench/dolo/het/dol.pqi index b9ff89fd7..f05425129 100644 --- a/bench/dolo/het/dol.pqi +++ b/bench/dolo/het/dol.pqi @@ -4,10 +4,6 @@ SOLUTION 1 temperature 25 pH 7 pe 4 -# C 1e-12 -# Ca 1e-12 -# Cl 1e-12 -# Mg 1e-12 PURE 1 Calcite 0.0 1 END diff --git a/bench/dolo/het/dolo_200.R b/bench/dolo/het/dolo_200.R index 53aee210d..2f24e6d09 100644 --- a/bench/dolo/het/dolo_200.R +++ b/bench/dolo/het/dolo_200.R @@ -53,6 +53,43 @@ fuzz_input_dht_keys <- function(input) { return(input[names(dht_species)]) } +check_sign_cal_dol_interp <- function(to_interp, data_set) { + dht_species <- c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ) + data_set <- as.data.frame(do.call(rbind, data_set), check.names = FALSE, optional = TRUE) + names(data_set) <- names(dht_species) + cal <- (data_set$Calcite == 0) == (to_interp["Calcite"] == 0) + dol <- (data_set$Dolomite == 0) == (to_interp["Dolomite"] == 0) + + cal_dol_same_sig <- cal == dol + return(rev(which(!cal_dol_same_sig))) +} + +check_neg_cal_dol <- function(result) { + neg_sign <- (result["Calcite"] < 0) || (result["Dolomite"] < 0) + return(neg_sign) +} + +# Optional when using Interpolation (example with less key species and custom +# significant digits) + +pht_species <- c( + "C(4)" = 3, + "Ca" = 3, + "Mg" = 2, + "Calcite" = 2, + "Dolomite" = 2 +) + chemistry_setup <- list( dht_species = c( "H" = 3, @@ -65,9 +102,12 @@ chemistry_setup <- list( "Calcite" = 4, "Dolomite" = 4 ), + pht_species = pht_species, hooks = list( dht_fill = check_sign_cal_dol_dht, - dht_fuzz = fuzz_input_dht_keys + dht_fuzz = fuzz_input_dht_keys, + interp_pre = check_sign_cal_dol_interp, + interp_post = check_neg_cal_dol ) ) From 03ae8e50f30c53acbc5520b40a9e9dc83f554b50 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Thu, 4 Apr 2024 09:27:52 +0000 Subject: [PATCH 53/77] Refactor code for grid creation and result storage --- R_lib/init_r_lib.R | 32 ++++++++++++++++++-------------- R_lib/kin_r_library.R | 11 ++++++++--- src/poet.cpp | 11 +++++------ 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index f6b433b42..8e9bef96c 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -3,22 +3,26 @@ has_doParallel <- require(doParallel) seq_pqc_to_grid <- function(pqc_in, grid) { # Convert the input DataFrame to a matrix - dt <- as.matrix(pqc_in) + pqc_in <- as.matrix(pqc_in) # Flatten the matrix into a vector - id_vector <- as.vector(t(grid)) + id_vector <- as.numeric(t(grid)) # Initialize an empty matrix to store the results - result_mat <- matrix(nrow = 0, ncol = ncol(dt)) + # result_mat <- matrix(NA, nrow = length(id_vector), ncol = ncol(pqc_in)) + + row_indices <- match(id_vector, pqc_in[, "ID"]) + + result_mat <- pqc_in[row_indices, ] # Iterate over each ID in the vector - for (id_mat in id_vector) { - # Find the matching row in the matrix - matching_row <- dt[dt[, "ID"] == id_mat, ] + # for (i in seq_along(id_vector)) { + # # Find the matching row in the matrix + # # matching_row <- pqc_in[pqc_in[, "ID"] == i, ] - # Append the matching row to the result matrix - result_mat <- rbind(result_mat, matching_row) - } + # # Append the matching row to the result matrix + # result_mat[i, ] <- pqc_in[pqc_in[, "ID"] == i, ] + # } # Convert the result matrix to a data frame res_df <- as.data.frame(result_mat) @@ -72,13 +76,13 @@ par_pqc_to_grid <- function(pqc_in, grid) { } pqc_to_grid <- function(pqc_in, grid) { - if (has_doParallel && has_foreach) { - print("Using parallel grid creation") - return(par_pqc_to_grid(pqc_in, grid)) - } else { + # if (has_doParallel && has_foreach) { + # print("Using parallel grid creation") + # return(par_pqc_to_grid(pqc_in, grid)) + # } else { print("Using sequential grid creation") return(seq_pqc_to_grid(pqc_in, grid)) - } + # } } resolve_pqc_bound <- function(pqc_mat, transport_spec, id) { diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index 33e6ef1dc..b0e34ca61 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -15,7 +15,7 @@ ### this program; if not, write to the Free Software Foundation, Inc., 51 ### Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -master_init <- function(setup, out_dir) { +master_init <- function(setup, out_dir, init_field) { ## Setup the directory where we will store the results if (!dir.exists(out_dir)) { dir.create(out_dir) @@ -23,7 +23,7 @@ master_init <- function(setup, out_dir) { } else { msgm("dir ", out_dir, " already exists, I will overwrite!") } - if (!exists("setup$store_result")) { + if (is.null(setup$store_result)) { msgm("store_result doesn't exist!") } else { msgm("store_result is ", setup$store_result) @@ -40,11 +40,16 @@ master_init <- function(setup, out_dir) { } if (setup$store_result) { + init_field_out <- paste0(out_dir, "/iter_0.rds") + saveRDS(init_field, file = init_field_out) + msgm("Stored initial field in ", init_field_out) if (is.null(setup[["out_save"]])) { setup$out_save <- seq(1, setup$iterations) } } + setup$out_dir <- out_dir + return(setup) } @@ -63,7 +68,7 @@ master_iteration_end <- function(setup, state_T, state_C) { ## comprised in setup$out_save if (setup$store_result) { if (iter %in% setup$out_save) { - nameout <- paste0(fileout, "/iter_", sprintf(fmt = fmt, iter), ".rds") + nameout <- paste0(setup$out_dir, "/iter_", sprintf(fmt = fmt, iter), ".rds") saveRDS(list( T = state_T, C = state_C, simtime = as.integer(setup$simulation_time) diff --git a/src/poet.cpp b/src/poet.cpp index 253062c88..8ee5585a1 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -386,7 +385,8 @@ int main(int argc, char *argv[]) { // // if (MY_RANK == 0) { // get timestep vector from // // grid_init function ... // *global_rt_setup = - master_init_R.value()(*global_rt_setup, run_params.out_dir); + master_init_R.value()(*global_rt_setup, run_params.out_dir, + init_list.getInitialGrid().asSEXP()); // MDL: store all parameters // MSG("Calling R Function to store calling parameters"); @@ -405,13 +405,12 @@ int main(int argc, char *argv[]) { MSG("finished simulation loop"); - // R["simtime"] = dSimTime; - // R.parseEvalQ("profiling$simtime <- simtime"); - R["profiling"] = profiling; + R["setup"] = *global_rt_setup; string r_vis_code; - r_vis_code = "saveRDS(profiling, file=paste0(fileout,'/timings.rds'));"; + r_vis_code = + "saveRDS(profiling, file=paste0(setup$out_dir,'/timings.rds'));"; R.parseEval(r_vis_code); MSG("Done! Results are stored as R objects into <" + run_params.out_dir + From 3b3e5fcea2210f414e3256060360ef565f00bffb Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Fri, 5 Apr 2024 07:05:09 +0000 Subject: [PATCH 54/77] Update .gitignore to ignore .codechecker directory --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1e597b203..0e1d0720f 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,5 @@ vignettes/*.pdf build/ /.cache/ -.vscode \ No newline at end of file +.vscode +.codechecker \ No newline at end of file From 133aab2b09269a8bf69d62110cc6c48984e82d6c Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Fri, 5 Apr 2024 08:31:32 +0000 Subject: [PATCH 55/77] Add inner_boundaries handling in DiffusionModule and InitialList --- ext/tug | 2 +- src/Init/DiffusionInit.cpp | 110 ++++++++++++++++++++++++++---- src/Init/InitialList.cpp | 4 ++ src/Init/InitialList.hpp | 23 ++++++- src/Transport/DiffusionModule.cpp | 4 ++ 5 files changed, 127 insertions(+), 16 deletions(-) diff --git a/ext/tug b/ext/tug index b104fdcf5..449647010 160000 --- a/ext/tug +++ b/ext/tug @@ -1 +1 @@ -Subproject commit b104fdcf5238a8a2948b4e835b2d99b64758bb2a +Subproject commit 449647010ab9cdf9e405139f360424a2b21ab3ab diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index 6abe43229..8aa8aa96d 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -54,6 +54,7 @@ static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, static std::vector extend_transport_names( std::unique_ptr &phreeqc, const Rcpp::List &boundaries_list, + const Rcpp::List &inner_boundaries, const std::vector &old_trans_names, Rcpp::List &initial_grid) { std::vector transport_names = old_trans_names; @@ -83,6 +84,13 @@ static std::vector extend_transport_names( } } + if (inner_boundaries.size() > 0) { + const Rcpp::NumericVector values = inner_boundaries["sol_id"]; + for (std::size_t i = 0; i < values.size(); i++) { + constant_pqc_ids.insert(values[i]); + } + } + if (!constant_pqc_ids.empty()) { for (const auto &pqc_id : constant_pqc_ids) { const auto solution_names = phreeqc->getSolutionNames(pqc_id); @@ -111,14 +119,17 @@ static Rcpp::List extend_initial_grid(const Rcpp::List &initial_grid, return extend_grid_R(initial_grid, Rcpp::wrap(names_to_add), old_size); } -Rcpp::List InitialList::resolveBoundaries(const Rcpp::List &boundaries_list) { +std::pair +InitialList::resolveBoundaries(const Rcpp::List &boundaries_list, + const Rcpp::List &inner_boundaries) { Rcpp::List bound_list; + Rcpp::List inner_bound; Rcpp::Function resolve_R("resolve_pqc_bound"); const std::size_t old_transport_size = this->transport_names.size(); this->transport_names = - extend_transport_names(this->phreeqc, boundaries_list, + extend_transport_names(this->phreeqc, boundaries_list, inner_boundaries, this->transport_names, this->initial_grid); const std::size_t new_transport_size = this->transport_names.size(); @@ -128,6 +139,10 @@ Rcpp::List InitialList::resolveBoundaries(const Rcpp::List &boundaries_list) { this->initial_grid, this->transport_names, old_transport_size); } + const Rcpp::NumericVector &inner_row_vec = inner_boundaries["row"]; + const Rcpp::NumericVector &inner_col_vec = inner_boundaries["col"]; + const Rcpp::NumericVector &inner_pqc_id_vec = inner_boundaries["sol_id"]; + for (const auto &species : this->transport_names) { Rcpp::List spec_list; @@ -173,9 +188,34 @@ Rcpp::List InitialList::resolveBoundaries(const Rcpp::List &boundaries_list) { } bound_list[species] = spec_list; + + if (inner_boundaries.size() > 0) { + + std::vector rows; + std::vector cols; + std::vector c_value; + + if (inner_row_vec.size() != inner_col_vec.size() || + inner_row_vec.size() != inner_pqc_id_vec.size()) { + throw std::runtime_error( + "Inner boundary vectors are not the same length"); + } + + for (std::size_t i = 0; i < inner_row_vec.size(); i++) { + rows.push_back(inner_row_vec[i] - 1); + cols.push_back(inner_col_vec[i] - 1); + c_value.push_back(Rcpp::as(resolve_R( + this->phreeqc_mat, Rcpp::wrap(species), inner_pqc_id_vec[i]))); + } + + inner_bound[species] = + Rcpp::List::create(Rcpp::Named("row") = Rcpp::wrap(rows), + Rcpp::Named("col") = Rcpp::wrap(cols), + Rcpp::Named("value") = Rcpp::wrap(c_value)); + } } - return bound_list; + return std::make_pair(bound_list, inner_bound); } static inline SEXP_TYPE get_datatype(const SEXP &input) { @@ -230,26 +270,36 @@ static Rcpp::List parseAlphas(const SEXP &input, return out_list; } void InitialList::initDiffusion(const Rcpp::List &diffusion_input) { - const Rcpp::List &boundaries = - diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; + Rcpp::List boundaries; + Rcpp::List inner_boundaries; + + if (diffusion_input.containsElementNamed( + DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES))) { + boundaries = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::BOUNDARIES)]; + } + + if (diffusion_input.containsElementNamed( + DIFFU_MEMBER_STR(DiffusionMembers::INNER_BOUNDARIES))) { + inner_boundaries = + diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::INNER_BOUNDARIES)]; + } + const SEXP &alpha_x = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_X)]; const SEXP &alpha_y = diffusion_input[DIFFU_MEMBER_STR(DiffusionMembers::ALPHA_Y)]; - this->boundaries = resolveBoundaries(boundaries); + const auto resolved_boundaries = + resolveBoundaries(boundaries, inner_boundaries); + this->boundaries = resolved_boundaries.first; + this->inner_boundaries = resolved_boundaries.second; this->alpha_x = parseAlphas(alpha_x, this->transport_names, this->n_cols, this->n_rows); this->alpha_y = parseAlphas(alpha_y, this->transport_names, this->n_cols, this->n_rows); - - // R["alpha_x"] = this->alpha_x; - // R["alpha_y"] = this->alpha_y; - - // R.parseEval("print(alpha_x)"); - // R.parseEval("print(alpha_y)"); } InitialList::DiffusionInit::BoundaryMap @@ -287,6 +337,39 @@ RcppListToBoundaryMap(const std::vector &trans_names, return map; } +static InitialList::DiffusionInit::InnerBoundaryMap +RcppListToInnerBoundaryMap(const std::vector &trans_names, + const Rcpp::List &inner_bound_list, + std::uint32_t n_cols, std::uint32_t n_rows) { + InitialList::DiffusionInit::InnerBoundaryMap map; + + if (inner_bound_list.size() == 0) { + return map; + } + + for (const auto &name : trans_names) { + const Rcpp::List &conc_list = inner_bound_list[name]; + + std::map, TugType> inner_bc; + + const Rcpp::NumericVector &row = conc_list["row"]; + const Rcpp::NumericVector &col = conc_list["col"]; + const Rcpp::NumericVector &value = conc_list["value"]; + + if (row.size() != col.size() || row.size() != value.size()) { + throw std::runtime_error( + "Inner boundary vectors are not the same length"); + } + + for (std::size_t i = 0; i < row.size(); i++) { + inner_bc[std::make_pair(row[i], col[i])] = value[i]; + } + + map[name] = inner_bc; + } + + return map; +} InitialList::DiffusionInit InitialList::getDiffusionInit() const { DiffusionInit diff_init; @@ -304,6 +387,9 @@ InitialList::DiffusionInit InitialList::getDiffusionInit() const { diff_init.boundaries = RcppListToBoundaryMap( this->transport_names, this->boundaries, this->n_cols, this->n_rows); + diff_init.inner_boundaries = + RcppListToInnerBoundaryMap(this->transport_names, this->inner_boundaries, + this->n_cols, this->n_rows); diff_init.alpha_x = Field(this->alpha_x); diff_init.alpha_y = Field(this->alpha_y); diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 90e0a1dd3..7f5360c87 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -41,6 +41,8 @@ void InitialList::importList(const Rcpp::List &setup) { setup[static_cast(ExportList::DIFFU_TRANSPORT)]); this->boundaries = Rcpp::List(setup[static_cast(ExportList::DIFFU_BOUNDARIES)]); + this->inner_boundaries = + Rcpp::List(setup[static_cast(ExportList::DIFFU_INNER_BOUNDARIES)]); this->alpha_x = Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_X)]); this->alpha_y = @@ -81,6 +83,8 @@ Rcpp::List InitialList::exportList() { out[static_cast(ExportList::DIFFU_TRANSPORT)] = Rcpp::wrap(this->transport_names); out[static_cast(ExportList::DIFFU_BOUNDARIES)] = this->boundaries; + out[static_cast(ExportList::DIFFU_INNER_BOUNDARIES)] = + this->inner_boundaries; out[static_cast(ExportList::DIFFU_ALPHA_X)] = this->alpha_x; out[static_cast(ExportList::DIFFU_ALPHA_Y)] = this->alpha_y; diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 1500518c1..3b2576ea8 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ private: GRID_INITIAL, DIFFU_TRANSPORT, DIFFU_BOUNDARIES, + DIFFU_INNER_BOUNDARIES, DIFFU_ALPHA_X, DIFFU_ALPHA_Y, CHEM_DATABASE, @@ -111,6 +113,10 @@ public: using BoundaryMap = std::map>>; + using InnerBoundaryMap = + std::map, TugType>>; + uint8_t dim; std::uint32_t n_cols; std::uint32_t n_rows; @@ -123,6 +129,7 @@ public: std::vector transport_names; BoundaryMap boundaries; + InnerBoundaryMap inner_boundaries; Field alpha_x; Field alpha_y; @@ -134,22 +141,32 @@ private: // Diffusion members static constexpr const char *diffusion_key = "Diffusion"; - enum class DiffusionMembers { BOUNDARIES, ALPHA_X, ALPHA_Y, ENUM_SIZE }; + enum class DiffusionMembers { + BOUNDARIES, + INNER_BOUNDARIES, + ALPHA_X, + ALPHA_Y, + ENUM_SIZE + }; static constexpr std::size_t size_DiffusionMembers = static_cast(InitialList::DiffusionMembers::ENUM_SIZE); static constexpr std::array - DiffusionMembersString = {"boundaries", "alpha_x", "alpha_y"}; + DiffusionMembersString = {"boundaries", "inner_boundaries", "alpha_x", + "alpha_y"}; constexpr const char *DIFFU_MEMBER_STR(DiffusionMembers member) const { return DiffusionMembersString[static_cast(member)]; } void initDiffusion(const Rcpp::List &diffusion_input); - Rcpp::List resolveBoundaries(const Rcpp::List &boundaries_list); + std::pair + resolveBoundaries(const Rcpp::List &boundaries_list, + const Rcpp::List &inner_boundaries); Rcpp::List boundaries; + Rcpp::List inner_boundaries; Rcpp::List alpha_x; Rcpp::List alpha_y; diff --git a/src/Transport/DiffusionModule.cpp b/src/Transport/DiffusionModule.cpp index d81f0d885..2ea80564a 100644 --- a/src/Transport/DiffusionModule.cpp +++ b/src/Transport/DiffusionModule.cpp @@ -95,6 +95,10 @@ void DiffusionModule::simulate(double requested_dt) { boundary.deserialize(this->param_list.boundaries[sol_name]); + if (!this->param_list.inner_boundaries[sol_name].empty()) { + boundary.setInnerBoundaries(this->param_list.inner_boundaries[sol_name]); + } + grid.setAlpha(alpha_x, alpha_y); grid.setConcentrations(conc); From 793067f5823057be4ffa1fbab56a691562d2f502 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Fri, 5 Apr 2024 08:33:26 +0000 Subject: [PATCH 56/77] Move old benchmark files into `old` subdir Move new benchmark files from `het` folder --- bench/dolo/dol.pqi | 67 +++++++++--------- bench/dolo/{het => }/dolo_200.R | 0 bench/dolo/{het => }/dolo_200_rt.R | 0 bench/dolo/dolo_inner.rds | Bin 0 -> 23156 bytes bench/dolo/het/dol.pqi | 38 ---------- bench/dolo/{ => old}/Eval.R | 0 bench/dolo/old/dol.pqi | 35 +++++++++ bench/dolo/{ => old}/dolo_diffu_inner.R | 0 bench/dolo/{ => old}/dolo_diffu_inner_large.R | 0 bench/dolo/{ => old}/dolo_inner.pqi | 0 bench/dolo/{ => old}/dolo_interp_long.R | 0 bench/dolo/{het => old}/phreeqc_kin.dat | 0 12 files changed, 70 insertions(+), 70 deletions(-) rename bench/dolo/{het => }/dolo_200.R (100%) rename bench/dolo/{het => }/dolo_200_rt.R (100%) create mode 100644 bench/dolo/dolo_inner.rds delete mode 100644 bench/dolo/het/dol.pqi rename bench/dolo/{ => old}/Eval.R (100%) create mode 100644 bench/dolo/old/dol.pqi rename bench/dolo/{ => old}/dolo_diffu_inner.R (100%) rename bench/dolo/{ => old}/dolo_diffu_inner_large.R (100%) rename bench/dolo/{ => old}/dolo_inner.pqi (100%) rename bench/dolo/{ => old}/dolo_interp_long.R (100%) rename bench/dolo/{het => old}/phreeqc_kin.dat (100%) diff --git a/bench/dolo/dol.pqi b/bench/dolo/dol.pqi index 408339482..f05425129 100644 --- a/bench/dolo/dol.pqi +++ b/bench/dolo/dol.pqi @@ -1,35 +1,38 @@ -SELECTED_OUTPUT - -high_precision true - -reset false - -time - -soln - -temperature true - -water true - -pH - -pe - -totals C Ca Cl Mg - -kinetic_reactants Calcite Dolomite - -equilibrium O2g - SOLUTION 1 - units mol/kgw - temp 25.0 - water 1 - pH 9.91 charge - pe 4.0 - C 1.2279E-04 - Ca 1.2279E-04 - Cl 1E-12 - Mg 1E-12 + units mol/kgw + water 1 + temperature 25 + pH 7 + pe 4 PURE 1 - O2g -0.1675 10 -KINETICS 1 - Calcite - -m 0.000207 - -parms 0.0032 - -tol 1e-10 - Dolomite - -m 0.0 - -parms 0.00032 - -tol 1e-10 + Calcite 0.0 1 END + +RUN_CELLS + -cells 1 + +COPY solution 1 2 + +PURE 2 + O2g -0.1675 10 +KINETICS 2 + Calcite + -m 0.000207 + -parms 0.05 + -tol 1e-10 + Dolomite + -m 0.0 + -parms 0.005 + -tol 1e-10 +END + +SOLUTION 3 + units mol/kgw + water 1 + temp 25 + Mg 0.001 + Cl 0.002 +END + +RUN_CELLS + -cells 2-3 diff --git a/bench/dolo/het/dolo_200.R b/bench/dolo/dolo_200.R similarity index 100% rename from bench/dolo/het/dolo_200.R rename to bench/dolo/dolo_200.R diff --git a/bench/dolo/het/dolo_200_rt.R b/bench/dolo/dolo_200_rt.R similarity index 100% rename from bench/dolo/het/dolo_200_rt.R rename to bench/dolo/dolo_200_rt.R diff --git a/bench/dolo/dolo_inner.rds b/bench/dolo/dolo_inner.rds new file mode 100644 index 0000000000000000000000000000000000000000..18740ebfc14e12a4569669dc6719965168b5e6e8 GIT binary patch literal 23156 zcmYg$WmH^Eur2NyG`IwJ2<}dBcXubayE_C6Zo%E%H8=!!ch_N%dGp=3?t1V1I;*<6 ztGjB~uA1pX8jAq&KM(X(58`kAF=u=M-=JZXADa*ZZ&-SH>4=TPj(gl{W}WCA^7|IF!a}_v7`s1hn*+9h*Xx{aYbNU1rUZD z{wD-{J)Y&N;x?cu|9##}SdX+HlBnMhf9-E{qSM=BbfTbO5HwFvPtw()mB+{YT^mT9 zn&W>ZoXh@IYE4FWpWrEwm*J(k-7jWfW$0DpHAVK&zJZ-xr{ccgT$E3^K&{Vz&MSu> zef6Kx1Hu1SJvrA8#C@>ShO!HRX3R2$vR@0HaAW)V=(pg%$DtJPb43sCf40|{E5P== z?F<8 z97^EtVsvhW8uj%_P9PT_=d}Xsk~$S|aaXBn^6~7rLe{Kd+hUN&-$1*G&gx-av$%yI zqdmNDOj7EYsP>u~&^}i|mXb20vx8BC4B=RNdkh?+~Z>SkGh2wt|nPfMHzo-6mO^A zVOhf~>AOnA%JeA10q$c-{+RG%Ea+iF_`c)i|Av}q^)Ce4ZolGx(e+>lhp#>bj0i2{ z|4;4|my6<&4@RdE@lRu#|1ib>6%5S(H_?dc|C4vKdEDP$3;o-eX8-N$?PhO3#n+{J zqkUV~rP{=|CEKKHqgCT?$8e>4)iEO0vakieb_HD5t+8!MuQqe~oyF^S{?`mQb&CAs zUCpW#U8&+`dBn$4Qp4@|cFpWzS+&YxzH1#jYiGjJU2oZ^tTd*IZ)UNwspkCalC|Pd zPEFnNegDk)I^}Y2N}A$|u7k#foV)QL9iLlV{BskCuM+f4cD^W3CrR$WP`iU z@l=CZT{bzc0J3SaJ%$8_cLvhB2OO^5c7VvAkch-1&vCDFG$ zM&xxnb%N!Gno*!_kIsN<+R3tA%~QgXP8HL#9q|&?IGkIJfel2>7sMpy){8B^?{@BX zRdzuaVzHe(Z9AfaN3!rjL1dMhJvOT^?L%^7(xIt``R{_gbR|x(#S8_b7u*dAT_ZbAs$?kiBn5 z@}efOUB?>NbV*nx0dPhq^}9rVk?0=EK`4>}k;AUHR5$WJqfH$ve@!cDP-8}t3YHh= zWE;#_T4iWZ2e@^I*ztF$1qo|phRMGl@`TqDrMuEJu3`O#pF>6VnE$J=(zte(RWzE| zYeefyHBOvA96=d3;q0D}J7pmX=3e1UIbH~tLrVAAi z;O2(qROD112mF0P&O^^k;yyXfWxN-HCN1;dX;S! zv!AXl=wqPyH0W^OodH6StQSL3fDUhC&zVVvfZ(2LWOul^_&ejlevt%{?bq%~J0VXb zIMm8f73gPyxzd7Eeomn?rD25k>&hFnK_IR1X0S1;1Oa2&N>6xMElu=#)L<4 zxk2$AX6P)UgOXKSdR-esIBif&`_bh@L}kWix<4`4=%-vq1wBG%B@Us`IxD;3^`p1- zXZOT#qGE%3{m|wjAGX1Yeork@CspxuSb<(p>pWkTY;elTY(~@JNa?T-=xFTJ{TnfnZ~m|p ztHS_OTz532&xCGa`%2`6!gx7#G-uQ=4TD*dmOu@6fkCDf6%8XR0#uwX`n+n` za5!1bZkgu1so6hhvV7IA@6n4!%7PWU>Nr(+gq_3Qj99A)t@n3|1-efetNvgQ-WV=C z!xN_=Rwn>s_%i-UzLRy@!&oe=!?C+(A*-Ibwx7{s(`VBKIb4jH-?C@;SWws#O45ZQ zJ*sN7$ofr1X^8BaZjLX3WBVYsDN_JVTV|1vmCO;#ZF|yJjn*m3_Cy60OV}BzrBYTMZ)kp|^(4W8h%E z8mHDj6It0)wBV)IMT|p5T+!Tx^JG&B$6Vt-*ErZ zHGd zx}ipG_eR0;)1Abn83Cncsf%TCy}g%AQ8|Q-#&7`H59X*S9->bb&fmL9Ty;L|Fs2@fT`2aG>HvjP({jG z{)aYSx<>;xx7O&q%Uto1V75JZ@lnO&GlVm1O&ZPuym zH)gF04#hBCT{4IaSRIKI8Ug~fJ8S}>!A*Sb;{vCVy2UK^Y&MeC#;U2!k$@m?24UnO z&C%Y-x$>$H=9wWXi?ZEsvOiK(*a$1>#kN?wjHS2eO%BhBASQ**p{@1T9@Jm#XWME7 zrUoU;voyHM_65t8M9tQ*1F)=K$0G;6U(z|n8zLWITyZxj1v9}(DO^k_nvtewk3wc~ zF;S3^C{0Q5K%6o-SS+%>Q!Thm4T55mvoO)kIm-NPD}qh2q6@^OQ#WFr_I%%hrqhrzIZbM&vUO~CMQd02!9nWae6|EuERhlTVWHJ6xadAbZR7d8oLM4HGT9C#f@UW6z zCH&*NnWsy;sz{F@3q6|PUtz`|KfRG=jLV1#YWu9p{_#{>9693v60hfRlAof%@3k+9 zhH>MpN_&-gq_TVx7IcMzFxKBn8WTw7$OLJ4SqT}{=N9$?^>Z+wg_`kN(C;#lWSdLZ z6*tkfJ0X}p6Js-E>hy=o#Baop5H*I6OfQX=Yv-Ee)?3A9;~By^(WSJvEPD2%rz$Ry z;njH?nu$nZ)N`PYW;0?&WIb_K#7`?VG|F=HWf^0havZgo^;&8*Y_R9@{7wqM zB|r7Zdl$(;8*U#-uEzJcCGNO50qKoypuPAt%qQeNq+Q(XZ!Uwb%=Gl33A>hEoov%W z`(_P`X+826Bw}f$cSmK$E}z4XFV%r9xIE0Kkyj}iVjlQjJc+;x5_D5+6GVIn=-7I8 zm?OGSZYasY7PN8hu=Ahk5Xz}d!Dg6!X!RG6Lr9BrRo`_dk?|T|U4p8VtZSD~HE}ij zyS$CjmSMHSH_1wVx-}(~EEmZtRXF@q?X@P5FF7PsFe+ibu!bFjCj7ndugh_0bV;0+ z5b_nyBb{JxAk?J*_UKo<94VgfVfb3N(_8-+zn_z=D`c6Z?NqlQ6I&UWbi;J=7%dm; zq9$Y_#8=V7N&zatF015;9%r|}(#6%i3BhwU2nHOzXGFLWrkBUR$YeRF&@DO02D8vN z>C^m>)$j#N_9W?Vv`#xSd zoTnCor`Fdg7=7c0UZ)1}hA=!g1PA$#MA!`XG6!wi^cadiBqL@H#jfG4t#e5DTkgmO0?HG;RdP2WKkmeYfp_wL={OS{^q%JPbQm zzhIDuwVJpovpr<--JDMoUHe-j;OVK1GKF0XRt~V%K)_8f=t>b<+H1I!B;z@tcnfI5 zg%@U}$_5)shFK^%ba}N?Vd)ecizddnG-jbbI^|WAJF@Z8rbTdJ>b*`E9qhM;Ule2+ z6t`JA3HRkF$q4+F5f+My_Zyb(6{cKa{MPbL)|K#1e!Wh8Nl5HhK|69hP>uN*m)G!< z4gX;>IHqk<)-IUsC}vKQzcr!%CmXH6_XbNWr~Vd8v=%1TOosF+M9Q0@=h6M{TJNk4 z?k%`$%@+V_5-(4}FE*#tU>YMmUoI==)~S|dR0CUw_6de={R@G0**Q8&YAIUcGXTCYwh;TFIu*Z|;OdRW-(WqMRO9?httjU?JXgE}zdoKENINq-$ zWsq!fYFt%xzQMIpH$QJL-LpIj%e}wz5a=%_`~(J)4H4y(!tuxJs! z_A!maV$d=j-$Q(A#ysg)-OebQ9s(|&nf$n3OpEu&GWsg1b2GySE6BFmy3Uk@f&)d< z!9SGKk;V4%-7(@<78Wi7}N&)R-;I9@hOTGkuq}H$S>pg{R*A-p0;9lGqGX06@xB4Yf zzOxqe;Q@hO( z^I!;gk5pg0X$#9#p%jMW-b=P@>4y$XCg{Z0EVW2osn$G1@eQxDIJV@}8U+DjYUL#e zSrbmqDRH&J=gC>fP38=!5b#S(8_GbVK2DV(487WLTtIKiXIN<3l4^jyz%g?r6{-A) zp)#7F_E|VNW8DM^^QZBE3S$WqaQ}k@1xn+Fa;ZW5JC$;2QB1#Vo{%AJsw}y=$g0k> zaDPbIXhczY&?s}tFez`cX-G#(q| zHcS_QU2J$8Q@Z4g{&-LEnp-DKVz+8wZ$ zert`rOcz|00o|K;Le9z=WD9WNP{|E%5}ai&Tji)F{{ywl8*9c41BG*M3JET zNt^L^ZnO6H48z!`2@GVOW88SG-O;9t&~jrbh7kTM&J{pC6l$qGL7YM36Lk$eqpTz~ zJE_jFB%Mm#%3sb;N0{Gy6eFJ0qL#Hnyhc|m#wJNpY|C)#{HCT6suswHZ7*K4dSPU+ z@RIBE@+yDpMZ-$VR-)Kld)3J@wZ=z7aQ`r|blue5F6P*)50Z9hN78c56}t9#{Sv(H zdfHRRUg7y2N0?)yc@!LA$|1e7yewE##Q|1*UEFDxxNwPv?7j(gmcTc@R>6Dx{-Sc_?At7sDZhex~xRC%79 z9;9O(51mJ-=83|KejJbMqty2(Tgw0n!_5%*2Q!-(isRQG+RT#ixe0v6@)YF-^S5~k z`0O+&(%v`~iV{V$?{=e`%GfKzKS$^itL+~P#EiXI7z^ph?PBa~^<8MT2MGU&o%G8+ ztMF#DQB&l)QrpCnXq{wd<9Nj~OgpQ(*QyZTnB&Lt8r6~#*NHIbRQ7Yw-=5-&c+4`7 zBlUk96neMjOzu(pI#|%3AC#TGHRONZuO(%n!#j4K{A>Gb)}zniVZrg&QpGBQmGiT# zDj?U{i<{yV$*_A69l;LF3hdluo$p5x!&L!t|{hSsKxUwPbgDpM)e)TZWn{IZf3IJt`MvLwl} z5db7*SdDIE0EOi`Jkx2Lifnrj7P56JvZqEl=~XD;>lw_$UHr3?SXq9V^}?goytL~SRKR;G zB3xXQra8CBuZQq#Etv`tTeT9!aqmWPtqP!KB<&=>%^P8u@H)vPaF3T#3yCZ+zC;VF zC%eL|gRX9;Qff2HAg+U{WkbI}6=rl6&zo1)P1?hsl$`y+t2YbuqU(}JUGsowpz(vS z!X1ZadDnI>GHZ%pQ|k;LhN5p)$aXCqBOQ3Den9xj9B?WKWSr!IB^8%-W|G{j zbro=*-eiF@;kA1cg{X?gpn%&nxepPsv5V^1FN_-BNku9w8?>0apo< zpTs}-cL#?$B=n@G4r(cJTrW1-&EY86X=+h^6=ZA_T6uIWHK)c(X>%v>!#4mC&7} zl2s^^9;W9871x9qsE&QX5L~6=^a3WN^XaI!;bVnL$4Sf)?iuR1g= zm%DdHN0#5}gtZ@~JPjw9B%#bKqCWoU)b4P+ti#XnM+$b*E$zjC{dQ`5x>xKTwR5n% z*pcr1fReu=YoC1tHaY=plE z5SP^<6YYbY82&eyi84T6PKtdo(I2jv7K#$xr;;;5N1>ufSho5LkbG9Dsl_aT(A%FlM$_bo3*rX^5+s(hTf z`AM7<)}NWA{DDbYP=YZpY51S;Kf)Z2Hq9BTR!xD9+W~2jDXb7vQNhczgC$j^e5&Ho z!=;Dnzg(N`h*~q8jnT?p*^6j++jj(=b+9F6EMc7_*?kSO{WEv)WCry#Bo_;_3BV^hXj$z+s>EzUgp-;-5bCS}5(!R;kxmDH$#aX~sOy z5zc=hN`-2*HulaQNVp&yOufE2Pr>`*z^Q*qf=a?lmyQS zRZ1FtxJWM*u964Xw{EVoXtFp+YFQHt@BShci{7%eCSKU+*H;>I_0s@|dzM?5VquNF zi?`d%TE`QRb+Kz}!ZJEdouw^&a zT4Bq2@~iPm)|ZxP)$^^r7CDSyY-ppK)r`Tp zX+8_Qos=(@kVlc<-8%{{m-j2*Zf&a|k%ZowIUVtqHoDW<>;`>SZR?t=oi}$Q7-@Nv z`8R7B+p@GqsxIKDn*utl#)5w{rRo2**B&OeSTWb!GTzHbHN9w>T(7Pc_uI&GgyNr< z3ped^y5y+xZ5+L)403mH>@}=u(KtFs$}8C+8y$6oIkITt+iYi!InTk+%&^kbU0U9k z?OIZCuSA9dj`Py*uzdR${`277Bdsyt>?yb#5 z1yS?pq5{`u(A)x{KQ`cda!w+~rrZW`i)f}b66x`G;Kffct_f-i^&n{8es=&m`wRXL z*CUq}1zWzlncZ*szl8ru^%t%QQo=N`Fam7!###(WcjOBl^V5@Pe)rw)ro}S(wIK#n zcW9P$#jtc!F<0C6gqA@9zHEgqCrjD&tS!~O*RU9#8s`zGZ-y@KEroDa?PTcHzu$}g z#@&L7?F(Y7zS_6@ssS2cE(26Ua;kW$k+_Tp(Z~oWYP6$9#R1lN4U{y_cIrZnguG@`!S^#As?b z+JL5W->4|?iC<4RbhBGrvPipBD78m_A-Cx?e1Mc+#jj#h;fc*~o%7nsaZ+VGr^@0H zwY1bw)CGaoSNCg;i7LO`?e60%X5Wd%RT+IG;e)$pt^M8`VRQA<0nYw$(gtO~$7*^U zmjCZQn`hxo`<5;SbBN*IYGHQx`LKT*Fx4OS2XuUXPv0hK`qb^z`R&p?n0<@d;Av`C zA>A3)y)clZLeX^;54A30aWtA@H8vy--_ErRl%Z?!wVQmpL2BPOo6rkQqYpV+7L-3t zHlNW#JExf6WMwwdJciNKIfSH*HkH4x2dh)v9@csf4UPGFlL&`r=7&RA;jG(#FXB<_ z;lW=I|AChU7n;;#UZoc9)&A2boqgm(pwNGmnR@DB)J#iAh*6%qXEua;z)-v^&w7zE zjrzlb_x|zMpt}!=z_9ef>+8fpe8l-4;?KIKNv}2y_b+d!lgwfw!~Q6X)}|`Bo&%hG z=h9me^lM6PX;Q)i(HT0|3|Eu6nr++VDo%BSQ3e4+>@{q}2NJOSx{Ao$*|DO8R-4+VTzefk{d~UxUX6IvWn~{NQd}R@nKeZB(26$OVlfu zbTxYHyPCEQD;bv`-;ns)(Q;f#*dF6x_!-a&&1$jqv|szjxWjBlt>`aumt>oMT*zr< zTC9~X9@$R&dYnsImj>@9U@!6O*)VIhYZiv2z!jI04E{Oykwt4iq|)s`-AKe}%PpWm z&Dt*`z)e+u^G*Q@p5GCpJ>+Vf*YtH2&+(G@u+jXQhoO6k3S1oCX#&j`rzdb?6~Xpn8?C9a#|ux%|!2hH2jWFcVN>0n<||=-Dez< zR7>k9);Ockr$&}JHumfbiM|L?HwtyI(~jEBZVL4k>}Y|wweESxMC8VOVE}(;Jo@ql zWo5U|8%Zw#lwhw9HW`8eReKY1te5*Z!)`2UalR<8?;IcG_`j%TV}CugZ_kgS`tnc# zjxDYF1JPpx@CBlU*;`z<5S3dFEqA$Tl^l185aS2ornlC9W6MKJ`6b(fMfga!_{m@U z5kk>ycys$RjNe^MtRwLTejFlW(vEtZO$v#JgQpJaS zDzJ!#b*+MQHdD}t{WF>1h^p7G=igH8zDtu{2aKJUU&Rl*9y`$~1Q){!_jBT1Z(gf; zQjVFOO#jaVM~R)fUhb5Yx!kXja9ix#oi=9=!A0J)vqRZ~=_FpfdF?DV4C10jh6{a! z5F_G#XCZv^kuAaOW^vXNt)$4C?i%BTUz>^l8XMZ!UZ)=4rut0qA1gB@U4ehtYLY++ z&wAcL@e2J+n5A3uD#lW0XN&+qd9p-Jje9`NbFuCd4mykbX^{P}GW7oL@4}hSJq)9f zu{cuwI~GG}NpPgVNL7h=&lhDPU|OGX9L*NXP2ncae~cqEL^@Gmpx10lSU8uNN9UB;OkkGj@HdrI~E10ZaAE zm5%g2We@S3!|m=C(asn4F$P7_^;K79jh<2G26%<=P5`1MY~bh zJ;`#c+k|8o&8O`6thuq1dRvQ>RPHeN=fh zft4Y|Fp_vXW^UU~0zW>@+{>}0Z|wtJ11|7b0`NV$sz&a?d}7t&y;|gzlgUGBioKY` zq@&C3M~mp6<_MY#`{CY` zjut}`YJJ7KaL^V9`4dvFqATc}*j=sf%Qh|hFY@_{eb8DuxTD(ftAtYNab&cDOUf!#DqpAKxE7%QkP0OK* z678r_JbKNd7M`oA3z=TbTGIEE+ar*Vvgu8A7)QM%G!d`$nL4vzE8;$I`qTYg{GOP` zMh3t-9nbnrd@Hv4T9u>L{D<=zs=^uEO77Nbl>A^-Ymr%5!g0}#gl1o=-vwcjQMrIC zz(%>xd%wSuaiCo%7g!0@5g)%rnmg!TxLy?2PJ$2uj_llNy45p1{GJQl=OK5Mou zD39$4E_$WSdkARrggf#^A-Aa_y#XZ5*W7On`U47(Sn`xkbPbSQF8kqychhp%tLMqW z+HN(901OEkY6!Qv*(F6rXvB3WYC-4E4^K0u3@rlN_91B{ghd~37X16&#n=de<9umM z`XnNeTc&IXv3Z2I$N$tzl!Sc{27giX?@(OJ8D|J=Kvt~hsnPS=hFJm;kph97L6Wv> zOc{cGe~`-Jnm(JBSWpHj)?YqUfBbNB?=dnN>C}7n_xr+&;>Z1%RM5EpC%(2M5(0<^ zSAguO;{Lr)_sk8KSyS0gP3~YLvxlr%W69WhI{ZYh$2RK4JysDx{FpcIYILYYIXZxs zXP_N=(wbFk%+qg{iD49PUhP0BXaWD^AN*I-U5r3~giefhNy)BYsokwAQ~bdoQ8`ED zZEfP)L-^EE6iQ|K(9ep6F(9_)n0NGDNQ;N?^Z@ZmKfGoPRddKsGeNb!!N|l>ya6|H zqiA(OjOD+?zFTTzN+iNA#{jh^WZ*t^N8!I+vHNIA8{=RY$82Km2=+eAGbbD9?pfjdVGrxbt~0u_W3TV?HU0HJ4}_94J2;eRw&cY zF8SvDm0I&VOaskZDohN)Zs!#)gAdQYX2VlouIaFgm^aW){VOhc$?*(rTk!0VTTYhm z7HL%HD2ksJ@BJJKm+Xhn2@4MpCDLi7hz0$1Q3gje-^8p?XLs`InlI8G#!F7u#HxDy z!t*M0y2`9DxvkAu#TkD?)l+sq=lyUY;wpbJ@A=1Xy$T=RZ`3lDZ3|r4;m2p9qx#pU zX=D@R!|A-Z&iUOWD!JLROuhUwXH!FthBQNm>?Lp?P+?}3sMIh~)mhZdK>r11u%#uO z9*}9ffXIMsXCz~hIe)^i1gkM*d-N-MR1y^%qDx2HuXjm}R}Y~`9rbT=eQc3PmBH2B z*ykwjXspG@m99icU;#0m;?@Goa4AJqh3R~6w|0yyPF<;b6I8NgRV%h+=x{*MtIQJ~ zSx!~8hf9&rPRyHbWVnQX0|)HF+Undw&k&Bi3~S#2goIs9RF#%3Of4C(m)$C18jkzd zD+8U|QRW;6%VKt{!@U4CZ``QQgp9|kX_MwfMm05UC~&a1 zj@t?{6hu%h&f0r3B30NYHb8K|)iN_~9$_=>++^r#9$^U>BJyvyu`O9JtetODK?y#6 zxc%Qx_HTD^0jd6`u2LUQ{XK}|uU!a^9OU1T^wD}`ax9(5%7Fi-5AjYfEH!li@37}n zrFn|x3nn3J3WOZ4EsU4L^aY`moj!)-mX7DmqIMbVnV3XM=BO4vc;8}2UzkID-Sb5K zIh0wJ2ssTpfN#iK#&Cq)kwR+hGLbBr9HXY3t}8>y5uPN5c1xY;`E{IlS|qh%Nj@Ejy4sfPQl$V>j5g? zVmK5;TPn$zehn3#QZ5(!XlogSL?POVUy5Ejv_btoZghXA9hQ%cW$ioQwoTCus<(CM zv2(}Wcxqwhe34(&FZ+b@FmWcb5SW?XFIJJgWrd5LLNvD_ses|Y@2puSGrUlSR$J|- zaIj-yTqfAPsmIwQ6SWN1w5rT++Y14R8g#2bkB{aNJ=UBI2x6VEhABezwCNh@>fRKf z%M%}WCAauA>DaN9$MkcrB=PDTqj`+Ki9ozzpFE2$z2-rYwKhX}O2LvX8kK9ge|;%9 za`AK&vsVwG38?x`_G!=_R%tj1AGeNK%#2l;Z;ceo&@zHdmUVPINFncB(2cy5#vEg8 z(^Ekmai9P%Hl(zNO89duXSq?2)WtrT6`ogXj2qAn%=*GSD-%?t~q>gF|Z2KBQcRp>?cW zR#;-FoKb3unR3u-m_#Lw#H8P+XVqF6gGqAcm%nn9{@=@Zd?Jt0@M`M3D}I#35?Yqe zLml5~{5Z#07j*i%7%3tAEC#gcCRx^REUB_3p;#Iv^)Lfo4&CeYLF0r6R}W8?8VI3YULvjl@5ZEmL^-8%CKLB3-y7|PzSan;Sbc)y(2Asvw{kPA8a{ybttRjoTI_jjXX z)BO|13;Z2xR~B4#{zz>tE899~UZcoegr%8xT;ZEK8I8+}BWH&fBVtsZz`YaSg0ABD zLqqDwEq}N?clm2&s$s*fd60=fJ4|_-=21%+(!FTk3Z8S9D06s%OEYQ<6~#?_RUDF@ z-4!k)x%U}sY>Q%ppiRZs))ti#l{JYHvc>JC)A5F5(^36@+uhsUbM^-ImJ2I&+)Mob zd|q=VPc@#EWh)p-?gv9G-BH*3d%_Bb`W|LxdjfB2kvn%;Z*ahu&t)gaiG3!?T2|Z@ zbz5-__)14s9LzM%9tv&;n);zE<&uhf@;-uEDRHfidX+|%8cIvd_XGjrnAIBVx$7#w zqn;E;u0WdDqs=-)h1q9s2%@!*xPvF`K4a&-*go&sl)9r2%qwU`q_d|r3E8xPR!|fH zYEn-A-_ANdvta@<5F?YGkK2Xe^3J%Cfm?`P7~xd6ZCKqY=Q~OQY@d!;Xo4_5WBYgH zZiNPRmSyWI=JXJw-W~7&{xGE2?^n2h4{G)ID@*`l2s}*S>PZis*RfMwLB6~Q zW1#c|KmiHp%iaT|ykkUO9>5$ReSQhXGxBp5EPk?%B0H;C*!dWSKi-i|0w@Dx`JS(_ zeH;VDcH6$B0)2xF1i7uAOC5+r@;o$h%PG~vV=X-9tnRVdw7unE8VCBlhSz6 zV_l5dAq0Z|%ed7X0GR~uP>?+YO6;~_eiJTuv_o28o7iChOPbLI9|GlfZ@#rN0)!O- z)5F4I%SMNwuzn|;q*r0O+YMOrkKF0ufS-{;)qS*+j!1$J!Zf%1h}W1;`4Mgr_fB|8 z7lFiotW-}sJ~^QJGRWSPQkMk&l+o^dN&1*w6MEDKsnK2OK_#|xt9=SVHUu>HxI%#- zM3bS*x)R6Kn0#gbCWkiPz=BHX`+K7(+Bcc{oVKzgtNi9yw* zPN9!!sexVKHzUY1V!Fr8zB+6`57@?bo>-sOT%Y)@C(QueJjnA)o|)3uRnrd;t=UXn z+zAkq=H%tu=hkE9F$}E5`>lJ@w%luu`TOltQZHLL_@s6Jx%KJ6KdF}-cJ^^6Nwse{ zkkY@DS5CB+^cAEjvm^Dof!O#-mVZ;`@&gQt4VVBt(L9i{@TZZ?j^e8?I2f;Zi?iPZ zS3p;pJZP3+_y9k0q57mnmT%Az-VH-M5kGs87haSj2*d?ULn%|Y}^Ch ztNSO14<4Llgq6JcVGi$Jd1d;t#Ae??-TgP%Nk=cpNkYjXRzM{LpaGN%C{P7#BK6=w zE=ede8clv@fe(*3!_mOh&P$d@Ni7@{DAw76AKJ2=}#U|88cgubUcu()Y`I0nt z(njtdbMFbxn+N`+PoD6+S5RvI4JOz|SCUZfe>RYT8?c9;puGMaaNCKxob~1q}Ay%KCQgh%Vy}sp#?I^roDc-)kKm}$8P3@e(2G~(AvmK** z9vI3Ga0Ifb@-9>${CbaUC&?rIs`MDeaeVUa(-Jtv)y2&m+D;yY7vZINJPd??0AW13 zpAON1L5>^T7fV(X7(u2<93q7N!7xFJm2~N3o!u`ilC;b%e(P`D)qjJRH0op>*{_6= zgZu_{Snd>mQTx1tGX1D;C29oD zxqiHqHM1O}52F$n_$hV^`;@g7A_TSt{duttok*m)(+9N|fRRbE6a8NjLPO=_JjO{A z^UJ@!U^Yhy6Lo=MfR!|c=Vo)tnJO%mv;yMkt(PKhqyv#ddi%vDO@QH;&vg5SD8x9r z5`3r#LjqPOw9?@n%7t8_&l@#YOI7py3v1D9p zf%FT&KP2z24)Z|k3z()TMgpilOoGv2%|XuCU#`jT)^W&hNQ(mGt!{0rXLjhxE@o4{ zcC&5B&0ftSymN(61Q79|owd+;l?K)nfcfDCBq94oAtaV_P73@~fTH-=fSAI{I~oL! z%Z@v#A(8x?0BtM0B9wsqvHpNvWeKShFpK1;DKgskRW z&O!WK^)mqMSN^2!U*H^chYiRnU>fx#UXYyd1m~td7#AynY$g8EyYpk+x%Yx0mqyNh zJM_0y;5qYBeH36y4Gb?}0jJno+J9D^@BnP0vjESiJ7m~H;7+D#->=Uq*iRM6HBbQR zAEycH+{rJgpD%XgJ=ynd;4=5XEOVn!c=Ei%bi08d3wl!`@1X%x;0-1iuHeLMN__@< zjpa!xZ|eu>Ek4YugEjB0@5g^${ror#yeakz>jp*N4}5gp6uj%fn7{h-|GAL^*M&au zT_>t`g>m$k7oj9@rlTVOufRmz%TV%h74rF39*8^7YX16xvFB~j?^Oz~-yG1+0E^CJ z_K`Xq_*=+zDk|v-{^MVwC=hXCM5@VPsE8f zu%F(31o!2Wjn%dH0_lRmRVy8&g#6wfWS>t8Eime7_FV|U8-)4>`j7L#Odj)bR+tYB z>;e}@kTA<_7mWGG2dqq=%xf1o0Ry2P8_HNZcJ{35rGb1 zcJC7fL`L;RvX6f5%$30eM1nPLklvZWG_NEM?7zFDMq zF7UW8Hh>ts07&?cuq>Fb0>7PtdzAMNw!N`v;jlKO&rkW?HZT$UEAF--j=%4HZsnKl zf@k49{#Q*t`S)m|`l4Y11DS5YF#@yV|7wB$TMQ&O2ksVL-*&=;Mc#>JZeL*krzv?U z>Ia_aH!fpjQ5Ic*`<|Hvb5ULRF<){*di3lGHp^+lr_s7Ns*-)5}}MYN)i+D+Gn(o zC6R6HW6c(0FlL|gd&ch{*IehE>v7KW+~4p0xu02h%1>EpPe}=X@`a|<6lv``-)+7r zO#wJ+LwwUAOQ(aS!q@;wHL)LElMGl~+BOC5xmWX>4qn<&(2ZZ#Q&qKoF=DR}w_)N0 z^urQ`j9=Mn z&WZYo&(gzOg{AIUqi(hzidIBPqpU-pg>P$LjXfFh87Tsv+(Wb(m+A7p6tF)u76%{6 z+uj1afJ%6C2bIyBSZe@8ikD-Ci{IzQ5~q%hQp{O0;-J(nJ*3#<7@7_YJFy4{(=}~P zk&)foB-lvfi~)U2ozfIOtE3d6lj_*4Wk!fq5S9FMwF1ZeOtL=m3tS2U`CKjsK5 zl9DA(m4iH^NvGC@O4z^T1{C6hOLJWMNl6i0vQl9iif69qpXMGPl3iC_p%8$LKLqiD z7r;_4{a>Lw#x{=2{2PagC5vDLj=Ca55}?MOJR5=D!9e>|S3)wD)CCvepO64t3*`A$ zASqV3VIDysJhb|ZfR^hXEqRR-UX4b2p-)0i1rL< z*WAdRV+eJ=YzuS6Py~|>1{W0ueEE|SV#Zz+RN?SRY(R^~KM(kutt;l%X)W0;S3a$FGkTvJmO7{6cvn!V9mXgoshUNYAjU^Gckx;_W7U$~za}fr~z+T=c z`6(U2z+%)vHS*$fP+%z-R1v=7mwaJ}q_JcV=A2hukFr=g8;u%5vy%jmyfd1A5m*XF z{}cpl3vXS5cnTlspPq<0V>z8*O@a`e-dZS4)p-W=WECw46~KuP3HOu!<@5f@L*;Q_ z15`8_j0N5KTk2W^Uw8ZooVgsLpvY$Gi{ro)0l+}no&1=3`0Whkogx?A#Uwph67y36eXWb)h)GkWB67HV zWC!KBc{?30st1J7N~Laq^rtAN{nKy4)ZLK}0d>Z$R$|z-nCr!{*@JL&J#}|z#e29x zF-#W|w{r|LY=dh@ED8_d>M7c){fs7^yktcqGHTBZL)>x#rI)z}VMVeU^;@^_rr}f& zjj~BNxJ`(JHr;`j+qRNyxDR@DSvQR$Hd8NF;S2uTr=vUn$x`mm05(3ne@WU5L-ab2 zA{myxSVnA-orj!J3(N#!43~ahnhTFP$!q}?Z$fu!7%`gauU?S9hcl;6*I^c zu-Tv>bTK5j7+~gx4b0)pXp&)ri8^1U6xI~Op6i3-L~bFbyu~Frh$;laOVH>T;@l#k zQcRLr*vn-OoWxS}+K zF?f)xL{-ne0~}*zhSE@-|M5kUWy!7u^E0$!e)6 zvks-@jafTsS`<0l0_E}QO^`&V#cOSFYZa+Hi;u@0-*7F2N_nCJNjq9|Vue-w)$Fg^ z4n~?cP3t~H?NP;QcN;8+3i76VhrIxgG6h(wDU5ON(C5c(Be^*(opJi>G>%Q?A$A*? z--0UP2Pw-8*+~xiCJbI51>F|NK18)A4RKmrc6i2aohloTN3C#T3^sO9f| zZS_T;myya=$C$i@rIB_2I2sD#;AvnqT8nVvt4FIE zEkIpl?9ob)kmx`V6=1X)wVT%@Q%P>7#c&(WSx^kXG1XK%Cx&QVxDTn2q1ipsojjpi z$;%AMrnLaiZtdAB-YEw-TQS1mG0YPp?U~d+tXhG#PbS2*%WX}f#6;OrY_~&lcs09O zvcsDzakF=#!n2oVoDd2EHVVY}`vHh;WLe3>&TJznO?sA%6QjgM7ZG}OfB}K)Z>5n*+2R;8C zE}A74&nrw0u?Uly^4nc`VHL)kvn?fz8L+Vs$-{J!f_k*7tp$mG89c>-cXg7T0OLO3 z^G;Y&Qq2JZ)zwqXmiV?tFmY=q@*LPpc)*WDBS1*r={S(iSMXN@;aNs3ZsFQrPMZ*n zi!y>Sl6ih-zXb4ruD}FMzr9|lx^r4Z|HN@7?`lN`s zWzblDFk*%Iz-Eb+5cdlxbdaD?>R=d>Z89MbR0TqDH4*-_jkK_jiLfg1dkTxOu-m_? zrP97&E!bKD5SjmBZ^{NWLg=AOLrWw( zrc(@RODnpWx}KZ;)S75p*$hha_0tu39r_Sn9{A!i6F!_r$>lD9SI~|bKfvy62)h(; z#3UfYmDE9m(4*=ARFmMcdOuK*RDB#@6@V)IFbC*(8S6`Km**d$#rl_xQb}SFcEGaj zg+0yxP)X+OE`bl^NAuTtQ;j#i`*3OHJ0+s=7zLp$Fn4(== zXV=*>o_~<`9mgG<`4htf3B&JfpPzhtH9xEcifpVz>q`*t2OLwfA%64|V95Iz9sX6@#deW#R(^KXc(|dSwTO$`=99oCRqUnW2Eiv ztL?wJQ7oi*6VF$HZ}fY2>Pq`5fkqhAlzQr3tzUkpwJpLVr@*FX1#Av>N#R2==)HU; zeHu@6lDZ%S35d`|oO?&O!fTvGQ^pZ9mjN`cOc?IwnF{K^Cx#%8zTkjbW?)6u6BSvE zdpKIb90Ln?)@Z>|Q3pu`08ZSxge8MWGN?9JJ>0{eCn!h^1$JU|735kw$R z;T&&O9!AiWbiWcDYYL-LyI`y&C~Uxs3QRZgQp{x-Qt8yxg1`nUp41VW&Emw=Q`JLV zn_!9@(TaFD)UZU6mzKEMc-Quz4bXu8+v(yU=dF? zOPS=x$Lp5DR}SAVuV&AA(e{6c52G#1pb;2(DYOWge7$IA{7kiPrSN6+9NA_lYFTvkr=X0(N zRqJ#2ule7EvLETyx*^Ic3pRH_W;n)9m4nnX>+WtDx?Hzh|KfOfhO?8yS@fmCf-g~A zi(Rs1{y&F$q`pe6o+4~+ZsKz|NlOOJoJ$q%=nHaG8|j;9Im6@4kI~CVJBGGT+oaI6 z|JXuF`?HQUhCi0+LvQ)Af@<<1&K!t#;Sa6a_(W{#i6}U~;@Ezb;PaZJ=h}MUE4i>D zW#0Juz~%egt2IBbV4f1Ck~BLk?DQs7k!0|@boc-4E~Xq_(R#Yai8=oKN*N2#~4rue{|{)|JGaolx_e9Oil_3qvjAL*ykZ)$6{)E`MNnmA+V z>~*gMd}b7RHQx2pTw6K4xaZ<+GTF8GqOml6YgmlV=RW(@C;#nDHs;Ob>s!d6FKSOH zJvJd7Jhb-qiu0mM*&j1&$0b#J-}2s~a>MgCBsZVTce@q5RmnH$^z@wiK$p=r#bKj}h=}{nBwNgZXr~ADwt#`s|+ufqx^t4{Xj-NIqJ$L9g%6dJ| zC7vIkU&3BLnm6)UW)nm)5bIh*K5@}qbm%|JF>OZEoRQS|&pRaPbLB_=t`&aV+SPRz zefnSNxjgHTLvGjq|aoQCs=KIGV(QuoSqVt=e*V^EZQIG^rG=X#yB!`9kno8i(Xfu&cWKOfldyxxSI~W>a;_PawgTFG_*~lyU zZ|koaV*k|0IEFM{hdKC$#{QkR%@ulsxe=%ydGx&2t?{hP7d^*nXD^nm&bdIocGXXO zD>4inZ*+z!jQ8-bxT9N}gWWXle9Wkv{4(Qz*?D8x9HHIHV74b}aKEzqEf)!!J34PL z1O5T!7dCh;*6@eAP0)U8-y?aImCMysC9jhr--@dkvjJ{-Zbb&4^Q_w&TQ0O!xJ)|~ zSEEWQ{az)+Zw}O*yB6<(Wn7~_oNP+Dp>dp)U4QW1EVbUVzp3iX&7R&Q*?}8J+qBcV zJ^$n!6|bP3?EU9ZV?hyN^IPZBQu&r7w2e#L#?u4k(;RkA!U1~23ryd?970F>0f~wI zy)>72ssHBtaxS|4>Bu3davFtI|NRw~3)hmi`~H}jXbH=HKgT{BFjL~|!l@wAcl1|n zdQFnX6g$X0cU(lh^{~>s@#Ew1%+inGlN#^JM;zQ*TKH~Kby+CSn)4Sue7jfEuIKj7 zx_(kByV>$-f7^%h%8}XsoC`XKuPN!dpg(Aj_j;8R-KoJZ8{B$59k2IkD-No;5+vK38gXyC?ldZr_L4_mrl)BG){@2L={ewP#PNd(DxS*Ctd?z>d#;P3TmRL&p?6JEIz&DuYjHqaRP3yQNQZ$Z}Bb zy;M^!rm!7p*f8=rzdsOFbLD`X)teVm@1UTd4N$?ek&kC?7p=cN?C6B0YT zSC7`Aq0Zo2?5kqlts8k0>zF`v@Lmi}#-%jelrdY0y@@eIz>#L7IU{x2jd-doo|@Ng zh`y>HLoG=di`f(_^kkf)OfK?e>PKIUu9;am%*IUH^ptyOztd83yR4x=3S7=SB-?dY zSN7h%OQN?n!&(dH2p^Muufu&aXx~?six1V zbiNIj4-3NDX+QETkx2^+YBM=j;1WWcK5)~~{@bm9b60&^?!QgmKWFdRPJ4J4iF^VymcCyZHnC z6Z5CFzsIB0xl*0ay;Z-v4{q(>_k8f`)%USWqM@lWp;z@wGPHC;9t$C74OX{UCykdL z-(Q9-|G9L2Dqj5!V{Gk~cWChO{Ury=V_v!imE0+4$RpUM&ij7(3XdFGeloLCr+vd# zrlbAqLLzG-j4O2CZF+cvZK)U}|&56^$Ev0NKhH$3}Q z^Xn3TR7w%$WXB)XmQ)e@nNIW`VxZEUJ7pi&zsV|Ga zE-vd;+rGlEMamhy=?d!29mzcs6MeG-!9To!L4(=oUzN4z8yk};xsU3=d&-Tpvsz`w>>`r z7P%QwF_iigIvDWBE91Xs3GILDi+xi&-xc-gyvZF+ecR+l$+R-4ag{=}uJ)m4)x)w< z*Ho-@SGsR_MrV{=OnZFl--uXOVy=VMooqAp_LMN} Date: Fri, 5 Apr 2024 08:34:41 +0000 Subject: [PATCH 57/77] Add dolo_inner benchmark --- bench/dolo/dolo_inner.R | 112 +++++++++++++++++++++++++++++++++++++ bench/dolo/dolo_inner_rt.R | 7 +++ 2 files changed, 119 insertions(+) create mode 100644 bench/dolo/dolo_inner.R create mode 100644 bench/dolo/dolo_inner_rt.R diff --git a/bench/dolo/dolo_inner.R b/bench/dolo/dolo_inner.R new file mode 100644 index 000000000..072474ad5 --- /dev/null +++ b/bench/dolo/dolo_inner.R @@ -0,0 +1,112 @@ +grid_def <- matrix(2, nrow = 10, ncol = 10) + +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./dol.pqi", + pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(ncol(grid_def) / 10, nrow(grid_def) / 10), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) + +bound_size <- 2 + +diffusion_setup <- list( + inner_boundaries = list( + "row" = c(1, 10), + "col" = c(1, 10), + "sol_id" = c(3, 3) + ), + alpha_x = 1e-6, + alpha_y = 1e-6 +) + +check_sign_cal_dol_dht <- function(old, new) { + if ((old["Calcite"] == 0) != (new["Calcite"] == 0)) { + return(TRUE) + } + if ((old["Dolomite"] == 0) != (new["Dolomite"] == 0)) { + return(TRUE) + } + return(FALSE) +} + +fuzz_input_dht_keys <- function(input) { + dht_species <- c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ) + return(input[names(dht_species)]) +} + +check_sign_cal_dol_interp <- function(to_interp, data_set) { + dht_species <- c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ) + data_set <- as.data.frame(do.call(rbind, data_set), check.names = FALSE, optional = TRUE) + names(data_set) <- names(dht_species) + cal <- (data_set$Calcite == 0) == (to_interp["Calcite"] == 0) + dol <- (data_set$Dolomite == 0) == (to_interp["Dolomite"] == 0) + + cal_dol_same_sig <- cal == dol + return(rev(which(!cal_dol_same_sig))) +} + +check_neg_cal_dol <- function(result) { + neg_sign <- (result["Calcite"] < 0) || (result["Dolomite"] < 0) + return(neg_sign) +} + +# Optional when using Interpolation (example with less key species and custom +# significant digits) + +pht_species <- c( + "C(4)" = 3, + "Ca" = 3, + "Mg" = 2, + "Calcite" = 2, + "Dolomite" = 2 +) + +chemistry_setup <- list( + dht_species = c( + "H" = 3, + "O" = 3, + "Charge" = 3, + "C(4)" = 6, + "Ca" = 6, + "Cl" = 3, + "Mg" = 5, + "Calcite" = 4, + "Dolomite" = 4 + ), + pht_species = pht_species, + hooks = list( + dht_fill = check_sign_cal_dol_dht, + dht_fuzz = fuzz_input_dht_keys, + interp_pre = check_sign_cal_dol_interp, + interp_post = check_neg_cal_dol + ) +) + +# Define a setup list for simulation configuration +setup <- list( + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup # Parameters related to the chemistry process +) diff --git a/bench/dolo/dolo_inner_rt.R b/bench/dolo/dolo_inner_rt.R new file mode 100644 index 000000000..bc59d3798 --- /dev/null +++ b/bench/dolo/dolo_inner_rt.R @@ -0,0 +1,7 @@ +iterations <- 200 +dt <- 3600 + +list( + timesteps = rep(dt, iterations), + store_result = TRUE +) From b8fd16a8d945310c64aef333b5071aaf41da2554 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 09:19:48 +0000 Subject: [PATCH 58/77] Refactor code according to static analyzers --- src/Chemistry/ChemistryModule.cpp | 31 ++++++++++++++++--------------- src/Chemistry/ChemistryModule.hpp | 5 +++-- src/Init/InitialList.cpp | 4 ++-- src/Init/InitialList.hpp | 10 +++++----- src/Transport/DiffusionModule.hpp | 2 +- src/initializer.cpp | 4 ---- src/poet.cpp | 14 ++++---------- 7 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/Chemistry/ChemistryModule.cpp b/src/Chemistry/ChemistryModule.cpp index 422ae2e83..f48bd9a00 100644 --- a/src/Chemistry/ChemistryModule.cpp +++ b/src/Chemistry/ChemistryModule.cpp @@ -13,8 +13,6 @@ #include #include -constexpr uint32_t MB_FACTOR = 1E6; - std::vector inverseDistanceWeighting(const std::vector &to_calc, const std::vector &from, @@ -22,20 +20,21 @@ inverseDistanceWeighting(const std::vector &to_calc, const std::vector> &output) { std::vector results = from; - const std::uint32_t buffer_size = input.size() + 1; - double buffer[buffer_size]; - double from_rescaled; + // const std::uint32_t buffer_size = input.size() + 1; + // double buffer[buffer_size]; + // double from_rescaled; const std::uint32_t data_set_n = input.size(); double rescaled[to_calc.size()][data_set_n + 1]; double weights[data_set_n]; // rescaling over all key elements - for (int key_comp_i = 0; key_comp_i < to_calc.size(); key_comp_i++) { + for (std::uint32_t key_comp_i = 0; key_comp_i < to_calc.size(); + key_comp_i++) { const auto output_comp_i = to_calc[key_comp_i]; // rescale input between 0 and 1 - for (int point_i = 0; point_i < data_set_n; point_i++) { + for (std::uint32_t point_i = 0; point_i < data_set_n; point_i++) { rescaled[key_comp_i][point_i] = input[point_i][key_comp_i]; } @@ -46,7 +45,7 @@ inverseDistanceWeighting(const std::vector &to_calc, const double max = *std::max_element(rescaled[key_comp_i], rescaled[key_comp_i] + data_set_n + 1); - for (int point_i = 0; point_i < data_set_n; point_i++) { + for (std::uint32_t point_i = 0; point_i < data_set_n; point_i++) { rescaled[key_comp_i][point_i] = ((max - min) != 0 ? (rescaled[key_comp_i][point_i] - min) / (max - min) @@ -58,9 +57,10 @@ inverseDistanceWeighting(const std::vector &to_calc, // calculate distances for each data set double inv_sum = 0; - for (int point_i = 0; point_i < data_set_n; point_i++) { + for (std::uint32_t point_i = 0; point_i < data_set_n; point_i++) { double distance = 0; - for (int key_comp_i = 0; key_comp_i < to_calc.size(); key_comp_i++) { + for (std::uint32_t key_comp_i = 0; key_comp_i < to_calc.size(); + key_comp_i++) { distance += std::pow( rescaled[key_comp_i][point_i] - rescaled[key_comp_i][data_set_n], 2); } @@ -75,7 +75,8 @@ inverseDistanceWeighting(const std::vector &to_calc, // bool has_h = false; // bool has_o = false; - for (int key_comp_i = 0; key_comp_i < to_calc.size(); key_comp_i++) { + for (std::uint32_t key_comp_i = 0; key_comp_i < to_calc.size(); + key_comp_i++) { const auto output_comp_i = to_calc[key_comp_i]; double key_delta = 0; @@ -87,7 +88,7 @@ inverseDistanceWeighting(const std::vector &to_calc, // has_o = true; // } - for (int j = 0; j < data_set_n; j++) { + for (std::uint32_t j = 0; j < data_set_n; j++) { key_delta += weights[j] * output[j][output_comp_i]; } @@ -157,7 +158,7 @@ inverseDistanceWeighting(const std::vector &to_calc, poet::ChemistryModule::ChemistryModule( uint32_t wp_size_, const InitialList::ChemistryInit chem_params, MPI_Comm communicator) - : params(chem_params), wp_size(wp_size_), group_comm(communicator) { + : group_comm(communicator), wp_size(wp_size_), params(chem_params) { MPI_Comm_rank(communicator, &comm_rank); MPI_Comm_size(communicator, &comm_size); @@ -306,9 +307,9 @@ void poet::ChemistryModule::initializeInterp( if (key_species.empty()) { map_copy = this->dht->getKeySpecies(); - for (std::size_t i = 0; i < map_copy.size(); i++) { + for (auto i = 0; i < map_copy.size(); i++) { const std::uint32_t signif = - map_copy[i] - (map_copy[i] > InterpolationModule::COARSE_DIFF + static_cast(map_copy[i]) - (map_copy[i] > InterpolationModule::COARSE_DIFF ? InterpolationModule::COARSE_DIFF : 0); map_copy[i] = signif; diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index e7d74c290..80be5a22f 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -69,7 +69,8 @@ public: auto GetChemistryTime() const { return this->chem_t; } void setFilePadding(std::uint32_t maxiter) { - this->file_pad = std::ceil(std::log10(maxiter + 1)); + this->file_pad = + static_cast(std::ceil(std::log10(maxiter + 1))); } struct SurrogateSetup { @@ -365,7 +366,7 @@ protected: bool print_progessbar{false}; - std::uint32_t file_pad{1}; + std::uint8_t file_pad{1}; double chem_t{0.}; diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 7f5360c87..57ce957c2 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -20,8 +20,8 @@ void InitialList::importList(const Rcpp::List &setup) { Rcpp::NumericVector grid_specs = setup[static_cast(ExportList::GRID_SPECS)]; - this->n_rows = grid_specs[0]; - this->n_cols = grid_specs[1]; + this->n_rows = static_cast(grid_specs[0]); + this->n_cols = static_cast(grid_specs[1]); Rcpp::NumericVector spatial = setup[static_cast(ExportList::GRID_SPATIAL)]; diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 3b2576ea8..74ee9de4b 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -92,13 +92,13 @@ private: void prepareGrid(const Rcpp::List &grid_input); - std::uint8_t dim; + std::uint8_t dim{0}; - std::uint32_t n_cols; - std::uint32_t n_rows; + std::uint32_t n_cols{0}; + std::uint32_t n_rows{0}; - double s_cols; - double s_rows; + double s_cols{0}; + double s_rows{0}; std::vector constant_cells; std::vector porosity; diff --git a/src/Transport/DiffusionModule.hpp b/src/Transport/DiffusionModule.hpp index f19ee2064..e8a576499 100644 --- a/src/Transport/DiffusionModule.hpp +++ b/src/Transport/DiffusionModule.hpp @@ -85,7 +85,7 @@ private: * @brief time spent for transport * */ - double transport_t = 0.f; + double transport_t = 0.; }; } // namespace poet diff --git a/src/initializer.cpp b/src/initializer.cpp index d0cdada1a..c71fbed19 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -25,10 +25,6 @@ int main(int argc, char **argv) { Rcpp::List setup = R["setup"]; - // Rcpp::List grid = R.parseEval("setup$grid"); - - // Rcpp::List results; - poet::InitialList init(R); init.initializeFromList(setup); diff --git a/src/poet.cpp b/src/poet.cpp index 8ee5585a1..38ce1f974 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -76,8 +76,7 @@ void writeFieldsToR(RInside &R, const Field &trans, const Field &chem) { enum ParseRet { PARSER_OK, PARSER_ERROR, PARSER_HELP }; -ParseRet parseInitValues(char **argv, RInsidePOET &R, - RuntimeParameters ¶ms) { +ParseRet parseInitValues(char **argv, RuntimeParameters ¶ms) { // initialize argh object argh::parser cmdl(argv); @@ -222,7 +221,7 @@ ParseRet parseInitValues(char **argv, RInsidePOET &R, return ParseRet::PARSER_OK; } -static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, +static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, DiffusionModule &diffusion, ChemistryModule &chem) { @@ -230,8 +229,6 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, * master for the following loop) */ uint32_t maxiter = params.timesteps.size(); - double sim_time = .0; - if (params.print_progressbar) { chem.setProgressBarPrintout(true); } @@ -241,7 +238,6 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, double dSimTime{0}; for (uint32_t iter = 1; iter < maxiter + 1; iter++) { double start_t = MPI_Wtime(); - uint32_t tick = 0; const double &dt = params.timesteps[iter - 1]; @@ -325,8 +321,6 @@ static Rcpp::List RunMasterLoop(RInside &R, const RuntimeParameters ¶ms, } int main(int argc, char *argv[]) { - double dSimTime, sim_end; - int world_size; MPI_Init(&argc, &argv); @@ -343,7 +337,7 @@ int main(int argc, char *argv[]) { RuntimeParameters run_params; - switch (parseInitValues(argv, R, run_params)) { + switch (parseInitValues(argv, run_params)) { case ParseRet::PARSER_ERROR: case ParseRet::PARSER_HELP: MPI_Finalize(); @@ -401,7 +395,7 @@ int main(int argc, char *argv[]) { chemistry.masterSetField(init_list.getInitialGrid()); - Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); + Rcpp::List profiling = RunMasterLoop(run_params, diffusion, chemistry); MSG("finished simulation loop"); From 93ba7837d7f660ebabed221b178655343d528875 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 10:31:47 +0000 Subject: [PATCH 59/77] Update minimum required CMake version to 3.14 --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1873d6ff5..26d2cf9fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,4 @@ -# Version 3.9+ offers new MPI package variables -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.14) project(POET LANGUAGES CXX C From 4fa935475ecc69c97966cc6dcfb2bcdbe02d8b5b Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 10:32:00 +0000 Subject: [PATCH 60/77] Fix inner_boundaries handling in DiffusionModule and InitialList --- src/Init/DiffusionInit.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index 8aa8aa96d..d39636d4e 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -139,10 +139,6 @@ InitialList::resolveBoundaries(const Rcpp::List &boundaries_list, this->initial_grid, this->transport_names, old_transport_size); } - const Rcpp::NumericVector &inner_row_vec = inner_boundaries["row"]; - const Rcpp::NumericVector &inner_col_vec = inner_boundaries["col"]; - const Rcpp::NumericVector &inner_pqc_id_vec = inner_boundaries["sol_id"]; - for (const auto &species : this->transport_names) { Rcpp::List spec_list; @@ -190,6 +186,9 @@ InitialList::resolveBoundaries(const Rcpp::List &boundaries_list, bound_list[species] = spec_list; if (inner_boundaries.size() > 0) { + const Rcpp::NumericVector &inner_row_vec = inner_boundaries["row"]; + const Rcpp::NumericVector &inner_col_vec = inner_boundaries["col"]; + const Rcpp::NumericVector &inner_pqc_id_vec = inner_boundaries["sol_id"]; std::vector rows; std::vector cols; From af48694d22fbc022a8cabef8fc151dc8cf447696 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 11:27:06 +0000 Subject: [PATCH 61/77] Refactor code for grid creation and result storage --- R_lib/init_r_lib.R | 68 ++-------------------------------------------- 1 file changed, 3 insertions(+), 65 deletions(-) diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index 8e9bef96c..33bba851e 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -1,29 +1,16 @@ -has_foreach <- require(foreach) -has_doParallel <- require(doParallel) - -seq_pqc_to_grid <- function(pqc_in, grid) { +pqc_to_grid <- function(pqc_in, grid) { # Convert the input DataFrame to a matrix pqc_in <- as.matrix(pqc_in) # Flatten the matrix into a vector id_vector <- as.numeric(t(grid)) - # Initialize an empty matrix to store the results - # result_mat <- matrix(NA, nrow = length(id_vector), ncol = ncol(pqc_in)) - + # Find the matching rows in the matrix row_indices <- match(id_vector, pqc_in[, "ID"]) + # Extract the matching rows from pqc_in to size of grid matrix result_mat <- pqc_in[row_indices, ] - # Iterate over each ID in the vector - # for (i in seq_along(id_vector)) { - # # Find the matching row in the matrix - # # matching_row <- pqc_in[pqc_in[, "ID"] == i, ] - - # # Append the matching row to the result matrix - # result_mat[i, ] <- pqc_in[pqc_in[, "ID"] == i, ] - # } - # Convert the result matrix to a data frame res_df <- as.data.frame(result_mat) @@ -36,55 +23,6 @@ seq_pqc_to_grid <- function(pqc_in, grid) { return(res_df) } -par_pqc_to_grid <- function(pqc_in, grid) { - # Convert the input DataFrame to a matrix - dt <- as.matrix(pqc_in) - - # Flatten the matrix into a vector - id_vector <- as.vector(t(grid)) - - # Initialize an empty matrix to store the results - # result_mat <- matrix(nrow = 0, ncol = ncol(dt)) - - # Set up parallel processing - num_cores <- detectCores() - cl <- makeCluster(num_cores) - registerDoParallel(cl) - - # Iterate over each ID in the vector in parallel - result_mat <- foreach(id_mat = id_vector, .combine = rbind) %dopar% { - # Find the matching row in the matrix - matching_row <- dt[dt[, "ID"] == id_mat, ] - - # Return the matching row - matching_row - } - - # Stop the parallel processing - stopCluster(cl) - - # Convert the result matrix to a data frame - res_df <- as.data.frame(result_mat) - - # Remove all columns which only contain NaN - res_df <- res_df[, colSums(is.na(res_df)) != nrow(res_df)] - - # Remove row names - rownames(res_df) <- NULL - - return(res_df) -} - -pqc_to_grid <- function(pqc_in, grid) { - # if (has_doParallel && has_foreach) { - # print("Using parallel grid creation") - # return(par_pqc_to_grid(pqc_in, grid)) - # } else { - print("Using sequential grid creation") - return(seq_pqc_to_grid(pqc_in, grid)) - # } -} - resolve_pqc_bound <- function(pqc_mat, transport_spec, id) { df <- as.data.frame(pqc_mat, check.names = FALSE) value <- df[df$ID == id, transport_spec] From 8bd05088bcc8c5fad98f0dc983ae0766b0685713 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 12:02:47 +0000 Subject: [PATCH 62/77] Refactor initializer.cpp to handle command line arguments and improve script sourcing --- src/initializer.cpp | 59 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/initializer.cpp b/src/initializer.cpp index c71fbed19..9d4a9ac04 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -1,27 +1,65 @@ #include "Init/InitialList.hpp" #include "poet.hpp" -#include +#include "Base/argh.hpp" + #include #include #include #include +#include int main(int argc, char **argv) { - if (argc < 2 || argc > 2) { - std::cerr << "Usage: " << argv[0] << " \n"; - return 1; + + argh::parser cmdl(argc, argv); + + if (cmdl[{"-h", "--help"}] || cmdl.pos_args().size() != 2) { + std::cout << "Usage: " << argv[0] + << " [-o, --output output_file] " + "[--setwd] " + "" + << std::endl; + return EXIT_SUCCESS; } RInside R(argc, argv); R.parseEvalQ(init_r_library); - const std::string script = argv[1]; - Rcpp::Function source_R("source"); + std::string input_script = cmdl.pos_args()[1]; + std::string normalized_path_script; + std::string in_file_name; - source_R(script); + std::string curr_path = + Rcpp::as(Rcpp::Function("normalizePath")(Rcpp::wrap("."))); + + try { + normalized_path_script = + Rcpp::as(Rcpp::Function("normalizePath")(input_script)); + + in_file_name = Rcpp::as( + Rcpp::Function("basename")(normalized_path_script)); + + std::cout << "Using script " << input_script << std::endl; + Rcpp::Function("source")(input_script); + } catch (Rcpp::exception &e) { + std::cerr << "Error while sourcing " << input_script << e.what() + << std::endl; + return EXIT_FAILURE; + } + + std::string output_file; + cmdl({"-o", "--output"}, + in_file_name.substr(0, in_file_name.find_last_of('.')) + ".rds") >> + output_file; + + if (cmdl[{"--setwd"}]) { + const std::string dir_path = Rcpp::as( + Rcpp::Function("dirname")(normalized_path_script)); + + Rcpp::Function("setwd")(Rcpp::wrap(dir_path)); + } Rcpp::List setup = R["setup"]; @@ -30,13 +68,10 @@ int main(int argc, char **argv) { init.initializeFromList(setup); // replace file extension by .rds - const std::string rds_out_filename = - script.substr(0, script.find_last_of('.')) + ".rds"; - Rcpp::Function save("saveRDS"); - save(init.exportList(), Rcpp::wrap(rds_out_filename)); + save(init.exportList(), Rcpp::wrap(curr_path + "/" + output_file)); - std::cout << "Saved result to " << rds_out_filename << std::endl; + std::cout << "Saved result to " << output_file << std::endl; // parseGrid(R, grid, results); return EXIT_SUCCESS; From 91e134b8f6ec3cb05a6eb9b9ebf6556e706264bf Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 12:49:58 +0000 Subject: [PATCH 63/77] Refactor command line argument handling and improve script sourcing in initializer.cpp --- src/initializer.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/initializer.cpp b/src/initializer.cpp index 9d4a9ac04..d9a8afadf 100644 --- a/src/initializer.cpp +++ b/src/initializer.cpp @@ -12,13 +12,15 @@ int main(int argc, char **argv) { - argh::parser cmdl(argc, argv); + argh::parser cmdl({"-o", "--output"}); + + cmdl.parse(argc, argv); if (cmdl[{"-h", "--help"}] || cmdl.pos_args().size() != 2) { std::cout << "Usage: " << argv[0] - << " [-o, --output output_file] " - "[--setwd] " - "" + << " [-o, --output output_file]" + " [-s, --setwd] " + " " << std::endl; return EXIT_SUCCESS; } @@ -50,11 +52,13 @@ int main(int argc, char **argv) { } std::string output_file; + cmdl({"-o", "--output"}, - in_file_name.substr(0, in_file_name.find_last_of('.')) + ".rds") >> + curr_path + "/" + + in_file_name.substr(0, in_file_name.find_last_of('.')) + ".rds") >> output_file; - if (cmdl[{"--setwd"}]) { + if (cmdl[{"-s", "--setwd"}]) { const std::string dir_path = Rcpp::as( Rcpp::Function("dirname")(normalized_path_script)); @@ -69,7 +73,8 @@ int main(int argc, char **argv) { // replace file extension by .rds Rcpp::Function save("saveRDS"); - save(init.exportList(), Rcpp::wrap(curr_path + "/" + output_file)); + + save(init.exportList(), Rcpp::wrap(output_file)); std::cout << "Saved result to " << output_file << std::endl; From b3a0590bd02237f00dfb01127d733dab4bc8e75d Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 15:28:52 +0000 Subject: [PATCH 64/77] Refactor benchmark files to current POET input expectations --- bench/barite/README.org | 5 +- bench/barite/barite.R | 149 -- bench/barite/barite.pqi | 53 +- bench/barite/barite_200.R | 144 +- .../barite_200_rt.R} | 6 +- bench/barite/{het/test.R => barite_het.R} | 0 bench/barite/{het => }/barite_het.pqi | 0 .../barite/{het/runtime.R => barite_het_rt.R} | 0 bench/barite/barite_interp_eval.R | 136 -- bench/dolo/README.org | 9 +- bench/dolo/dol.pqi | 9 +- .../dolo/{dolo_inner.R => dolo_inner_large.R} | 13 +- .../{dolo_200_rt.R => dolo_inner_large_rt.R} | 6 +- bench/dolo/{dolo_200.R => dolo_interp.R} | 38 +- bench/dolo/dolo_interp_rt.R | 10 + bench/dolo/old/Eval.R | 51 - bench/dolo/old/dol.pqi | 35 - bench/dolo/old/dolo_diffu_inner.R | 190 --- bench/dolo/old/dolo_diffu_inner_large.R | 190 --- bench/dolo/old/dolo_inner.pqi | 28 - bench/dolo/old/dolo_interp_long.R | 204 --- bench/dolo/old/phreeqc_kin.dat | 1307 ----------------- bench/surfex/ExBase.pqi | 24 + bench/surfex/README.org | 2 +- bench/surfex/SurfExBase.pqi | 24 + bench/surfex/ex.R | 159 +- bench/surfex/ex_rt.R | 7 + bench/surfex/surfex.R | 160 +- bench/surfex/surfex_rt.R | 10 + 29 files changed, 247 insertions(+), 2722 deletions(-) delete mode 100644 bench/barite/barite.R rename bench/{dolo/dolo_inner_rt.R => barite/barite_200_rt.R} (68%) rename bench/barite/{het/test.R => barite_het.R} (100%) rename bench/barite/{het => }/barite_het.pqi (100%) rename bench/barite/{het/runtime.R => barite_het_rt.R} (100%) delete mode 100644 bench/barite/barite_interp_eval.R rename bench/dolo/{dolo_inner.R => dolo_inner_large.R} (91%) rename bench/dolo/{dolo_200_rt.R => dolo_inner_large_rt.R} (54%) rename bench/dolo/{dolo_200.R => dolo_interp.R} (81%) create mode 100644 bench/dolo/dolo_interp_rt.R delete mode 100644 bench/dolo/old/Eval.R delete mode 100644 bench/dolo/old/dol.pqi delete mode 100644 bench/dolo/old/dolo_diffu_inner.R delete mode 100644 bench/dolo/old/dolo_diffu_inner_large.R delete mode 100644 bench/dolo/old/dolo_inner.pqi delete mode 100644 bench/dolo/old/dolo_interp_long.R delete mode 100644 bench/dolo/old/phreeqc_kin.dat create mode 100644 bench/surfex/ex_rt.R create mode 100644 bench/surfex/surfex_rt.R diff --git a/bench/barite/README.org b/bench/barite/README.org index e7b316052..86239c5de 100644 --- a/bench/barite/README.org +++ b/bench/barite/README.org @@ -18,8 +18,9 @@ mpirun -np 4 ./poet --interp barite_interp_eval.R barite_results * List of Files -- =barite.R=: POET input script for a 20x20 simulation grid -- =barite_interp_eval.R=: POET input script for a 400x200 simulation +- =barite_het.R=: POET input script with homogeneous zones for a 5x2 simulation + grid +- =barite_200.R=: POET input script for a 200x200 simulation grid - =db_barite.dat=: PHREEQC database containing the kinetic expressions for barite and celestite, stripped down from =phreeqc.dat= diff --git a/bench/barite/barite.R b/bench/barite/barite.R deleted file mode 100644 index 7d73de75b..000000000 --- a/bench/barite/barite.R +++ /dev/null @@ -1,149 +0,0 @@ -## Time-stamp: "Last modified 2024-01-12 12:39:14 delucia" -database <- normalizePath("../share/poet/bench/barite/db_barite.dat") -input_script <- normalizePath("../share/poet/bench/barite/barite.pqi") - -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# - -n <- 20 -m <- 20 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04, - "Barite" = 0.001, - "Celestite" = 1 -) - -grid <- list( - n_cells = c(n, m), - s_cells = c(1, 1), - type = types[1], - init_cell = as.data.frame(init_cell, check.names = FALSE), - props = names(init_cell), - database = database, - input_script = input_script -) - - -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions - -init_diffu <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04 -) - -injection_diff <- list( - list( - "H" = 111.0124, - "O" = 55.50622, - "Charge" = -3.336970273297e-08, - "Ba" = 0.1, - "Cl" = 0.2, - "S(6)" = 0, - "Sr" = 0) -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-06, - "O" = 1E-06, - "Charge" = 1E-06, - "Ba" = 1E-06, - "Cl" = 1E-06, - "S(6)" = 1E-06, - "Sr" = 1E-06 -) - -## vecinj_inner <- list( -## l1 = c(1,20,20), -## l2 = c(2,80,80), -## l3 = c(2,60,80) -## ) - -boundary <- list( - "N" = c(1,1, rep(0, n-2)), -## "N" = rep(0, n), - "E" = rep(0, n), - "S" = rep(0, n), -# "W" = rep(0, n) - "W" = c(1,1, rep(0, n-2)) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, injection_diff) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, -# vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - - -## # Needed when using DHT -dht_species <- c( - "H" = 7, - "O" = 7, - "Charge" = 4, - "Ba" = 7, - "Cl" = 7, - "S(6)" = 7, - "Sr" = 7, - "Barite" = 4, - "Celestite" = 4 -) - - - -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 4 -dt <- 100 - -setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = seq(1, iterations) -) diff --git a/bench/barite/barite.pqi b/bench/barite/barite.pqi index 651b0e645..1fdc05e50 100644 --- a/bench/barite/barite.pqi +++ b/bench/barite/barite.pqi @@ -1,25 +1,32 @@ -SELECTED_OUTPUT - -high_precision true - -reset false - -kinetic_reactants Barite Celestite - -saturation_indices Barite Celestite SOLUTION 1 -units mol/kgw -water 1 -temperature 25 -pH 7 -pe 10.799 -Ba 0.1 -Cl 0.2 -S 1e-9 -Sr 1e-9 -KINETICS 1 -Barite --m 0.001 --parms 50. # reactive surface area --tol 1e-9 -Celestite --m 1 --parms 10.0 # reactive surface area --tol 1e-9 + units mol/kgw + water 1 + temperature 25 + pH 7 +PURE 1 + Celestite 0.0 1 END + +RUN_CELLS + -cells 1 + +COPY solution 1 2 + +KINETICS 2 + Barite + -m 0.001 + -parms 50. # reactive surface area + -tol 1e-9 + Celestite + -m 1 + -parms 10.0 # reactive surface area + -tol 1e-9 +END + +SOLUTION 3 + units mol/kgw + water 1 + temperature 25 + Ba 0.1 + Cl 0.2 +END \ No newline at end of file diff --git a/bench/barite/barite_200.R b/bench/barite/barite_200.R index 76526b00e..337f903eb 100644 --- a/bench/barite/barite_200.R +++ b/bench/barite/barite_200.R @@ -1,105 +1,39 @@ -## Time-stamp: "Last modified 2024-01-12 12:49:03 delucia" +cols <- 200 +rows <- 200 -database <- normalizePath("../share/poet/bench/barite/db_barite.dat") -input_script <- normalizePath("../share/poet/bench/barite/barite.pqi") -## database <- normalizePath("/home/work/simR/Rphree/poetsims/Sims/Hans/db_barite.dat") -## input_script <- normalizePath("/home/work/simR/Rphree/poetsims/Sims/Hans/barite.pqi") +s_cols <- 1 +s_rows <- 1 -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# +grid_def <- matrix(2, nrow = rows, ncol = cols) -n <- 200 -m <- 200 - -init_cell <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04, - "Barite" = 0.001, - "Celestite" = 1 +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./barite.pqi", + pqc_db_file = "./db_barite.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(s_rows, s_cols), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration ) -grid <- list( - n_cells = c(n, m), - s_cells = c(1, 1), - type = "scratch", - init_cell = as.data.frame(init_cell, check.names = FALSE), - props = names(init_cell), - database = database, - input_script = input_script +bound_length <- 2 + +bound_def <- list( + "type" = rep("constant", bound_length), + "sol_id" = rep(3, bound_length), + "cell" = seq(1, bound_length) ) +homogenous_alpha <- 1e-6 -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions - -init_diffu <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04 +diffusion_setup <- list( + boundaries = list( + "W" = bound_def, + "N" = bound_def + ), + alpha_x = homogenous_alpha, + alpha_y = homogenous_alpha ) -injection_diff <- list( - list( - "H" = 111.0124, - "O" = 55.50622, - "Charge" = -3.336970273297e-08, - "Ba" = 0.1, - "Cl" = 0.2, - "S(6)" = 0, - "Sr" = 0) -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-06, - "O" = 1E-06, - "Charge" = 1E-06, - "Ba" = 1E-06, - "Cl" = 1E-06, - "S(6)" = 1E-06, - "Sr" = 1E-06 -) - -boundary <- list( - "N" = c(1,1, rep(0, n-2)), - "E" = rep(0, n), - "S" = rep(0, n), - "W" = c(1,1, rep(0, n-2)) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, injection_diff) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - -## DHT significant digits dht_species <- c( "H" = 7, "O" = 7, @@ -112,27 +46,13 @@ dht_species <- c( "Celestite" = 4 ) -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species +chemistry_setup <- list( + dht_species = dht_species ) -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - -iterations <- 50 -dt <- 100 - +# Define a setup list for simulation configuration setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = seq(1, iterations) - ## out_save = c(1, 5, 10, seq(50, iterations, by=50)) + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup ) diff --git a/bench/dolo/dolo_inner_rt.R b/bench/barite/barite_200_rt.R similarity index 68% rename from bench/dolo/dolo_inner_rt.R rename to bench/barite/barite_200_rt.R index bc59d3798..2b4a2836d 100644 --- a/bench/dolo/dolo_inner_rt.R +++ b/bench/barite/barite_200_rt.R @@ -1,7 +1,7 @@ -iterations <- 200 -dt <- 3600 +iterations <- 50 +dt <- 100 list( timesteps = rep(dt, iterations), store_result = TRUE -) +) \ No newline at end of file diff --git a/bench/barite/het/test.R b/bench/barite/barite_het.R similarity index 100% rename from bench/barite/het/test.R rename to bench/barite/barite_het.R diff --git a/bench/barite/het/barite_het.pqi b/bench/barite/barite_het.pqi similarity index 100% rename from bench/barite/het/barite_het.pqi rename to bench/barite/barite_het.pqi diff --git a/bench/barite/het/runtime.R b/bench/barite/barite_het_rt.R similarity index 100% rename from bench/barite/het/runtime.R rename to bench/barite/barite_het_rt.R diff --git a/bench/barite/barite_interp_eval.R b/bench/barite/barite_interp_eval.R deleted file mode 100644 index 6f2b79a34..000000000 --- a/bench/barite/barite_interp_eval.R +++ /dev/null @@ -1,136 +0,0 @@ -## Time-stamp: "Last modified 2024-01-12 11:35:11 delucia" - -database <- normalizePath("../share/poet/bench/barite/db_barite.dat") -input_script <- normalizePath("../share/poet/bench/barite/barite.pqi") - -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# - -n <- 400 -m <- 200 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04, - "Barite" = 0.001, - "Celestite" = 1 -) - -grid <- list( - n_cells = c(n, m), - s_cells = c(1, 1), - type = types[1], - init_cell = as.data.frame(init_cell, check.names = FALSE), - props = names(init_cell), - database = database, - input_script = input_script -) - - -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions - -init_diffu <- list( - "H" = 110.0124, - "O" = 55.5087, - "Charge" = -1.216307845207e-09, - "Ba" = 1.E-12, - "Cl" = 2.E-12, - "S(6)" = 6.204727095976e-04, - "Sr" = 6.204727095976e-04 -) - -injection_diff <- list( - list( - "H" = 111.0124, - "O" = 55.50622, - "Charge" = -3.336970273297e-08, - "Ba" = 0.1, - "Cl" = 0.2, - "S(6)" = 0, - "Sr" = 0) -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-06, - "O" = 1E-06, - "Charge" = 1E-06, - "Ba" = 1E-06, - "Cl" = 1E-06, - "S(6)" = 1E-06, - "Sr" = 1E-06 -) - -boundary <- list( - "N" = c(1,1, rep(0, n-2)), - "E" = rep(0, n), - "S" = rep(0, n), - "W" = c(1,1, rep(0, n-2)) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, injection_diff) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - -## # Needed when using DHT -dht_species <- c( - "H" = 7, - "O" = 7, - "Charge" = 4, - "Ba" = 7, - "Cl" = 7, - "S(6)" = 7, - "Sr" = 7, - "Barite" = 4, - "Celestite" = 4 -) - -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# -iterations <- 200 -dt <- 250 - -setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = seq(1, iterations) -) diff --git a/bench/dolo/README.org b/bench/dolo/README.org index 67caf6e12..102b054fb 100644 --- a/bench/dolo/README.org +++ b/bench/dolo/README.org @@ -18,16 +18,13 @@ mpirun -np 4 ./poet --dht --interp dolo_interp_long.R dolo_interp_long_res * List of Files -- =dolo_diffu_inner.R=: POET input script for a 100x100 simulation - grid -- =dolo_interp_long.R=: POET input script for a 400x200 simulation +- =dolo_interp.R=: POET input script for a 400x200 simulation grid +- =dolo_diffu_inner_large.R=: POET input script for a 400x200 + simulation grid - =phreeqc_kin.dat=: PHREEQC database containing the kinetic expressions for dolomite and celestite, stripped down from =phreeqc.dat= - =dol.pqi=: PHREEQC input script for the chemical system -# - =dolo.R=: POET input script for a 20x20 simulation grid -# - =dolo_diffu_inner_large.R=: POET input script for a 400x200 -# simulation grid * Chemical system diff --git a/bench/dolo/dol.pqi b/bench/dolo/dol.pqi index f05425129..a9706bcf1 100644 --- a/bench/dolo/dol.pqi +++ b/bench/dolo/dol.pqi @@ -34,5 +34,10 @@ SOLUTION 3 Cl 0.002 END -RUN_CELLS - -cells 2-3 +SOLUTION 4 + units mol/kgw + water 1 + temp 25 + Mg 0.002 + Cl 0.002 +END diff --git a/bench/dolo/dolo_inner.R b/bench/dolo/dolo_inner_large.R similarity index 91% rename from bench/dolo/dolo_inner.R rename to bench/dolo/dolo_inner_large.R index 072474ad5..73b1da839 100644 --- a/bench/dolo/dolo_inner.R +++ b/bench/dolo/dolo_inner_large.R @@ -1,11 +1,14 @@ -grid_def <- matrix(2, nrow = 10, ncol = 10) +rows <- 2000 +cols <- 1000 + +grid_def <- matrix(2, nrow = rows, ncol = cols) # Define grid configuration for POET model grid_setup <- list( pqc_in_file = "./dol.pqi", pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script - grid_size = c(ncol(grid_def) / 10, nrow(grid_def) / 10), # Size of the grid in meters + grid_size = c(rows, cols) / 100, # Size of the grid in meters constant_cells = c() # IDs of cells with constant concentration ) @@ -13,9 +16,9 @@ bound_size <- 2 diffusion_setup <- list( inner_boundaries = list( - "row" = c(1, 10), - "col" = c(1, 10), - "sol_id" = c(3, 3) + "row" = c(200, 800, 800), + "col" = c(400, 1400, 1600), + "sol_id" = c(3, 4, 4) ), alpha_x = 1e-6, alpha_y = 1e-6 diff --git a/bench/dolo/dolo_200_rt.R b/bench/dolo/dolo_inner_large_rt.R similarity index 54% rename from bench/dolo/dolo_200_rt.R rename to bench/dolo/dolo_inner_large_rt.R index 7cf510bb9..27dda1f45 100644 --- a/bench/dolo/dolo_200_rt.R +++ b/bench/dolo/dolo_inner_large_rt.R @@ -1,8 +1,10 @@ iterations <- 500 -dt <- 500 +dt <- 50 + +out_save <- seq(5, iterations, by = 5) list( timesteps = rep(dt, iterations), store_result = TRUE, - out_save = seq(50, iterations, by = 50) + out_save = out_save ) diff --git a/bench/dolo/dolo_200.R b/bench/dolo/dolo_interp.R similarity index 81% rename from bench/dolo/dolo_200.R rename to bench/dolo/dolo_interp.R index 2f24e6d09..bb88e457d 100644 --- a/bench/dolo/dolo_200.R +++ b/bench/dolo/dolo_interp.R @@ -1,28 +1,40 @@ -grid_def <- matrix(2, nrow = 200, ncol = 200) +rows <- 400 +cols <- 200 + +grid_def <- matrix(2, nrow = rows, ncol = cols) # Define grid configuration for POET model grid_setup <- list( pqc_in_file = "./dol.pqi", pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script - grid_size = c(ncol(grid_def), nrow(grid_def)), # Size of the grid in meters + grid_size = c(5, 2.5), # Size of the grid in meters constant_cells = c() # IDs of cells with constant concentration ) -bound_size <- 2 +bound_def_we <- list( + "type" = rep("constant", rows), + "sol_id" = rep(1, rows), + "cell" = seq(1, rows) +) + +bound_def_ns <- list( + "type" = rep("constant", cols), + "sol_id" = rep(1, cols), + "cell" = seq(1, cols) +) diffusion_setup <- list( boundaries = list( - "W" = list( - "type" = rep("constant", bound_size), - "sol_id" = rep(3, bound_size), - "cell" = seq(1, bound_size) - ), - "N" = list( - "type" = rep("constant", bound_size), - "sol_id" = rep(3, bound_size), - "cell" = seq(1, bound_size) - ) + "W" = bound_def_we, + "E" = bound_def_we, + "N" = bound_def_ns, + "S" = bound_def_ns + ), + inner_boundaries = list( + "row" = floor(rows / 2), + "col" = floor(cols / 2), + "sol_id" = c(3) ), alpha_x = 1e-6, alpha_y = 1e-6 diff --git a/bench/dolo/dolo_interp_rt.R b/bench/dolo/dolo_interp_rt.R new file mode 100644 index 000000000..417cd5b8d --- /dev/null +++ b/bench/dolo/dolo_interp_rt.R @@ -0,0 +1,10 @@ +iterations <- 20000 +dt <- 200 + +out_save <- seq(50, iterations, by = 50) + +list( + timesteps = rep(dt, iterations), + store_result = TRUE, + out_save = out_save +) diff --git a/bench/dolo/old/Eval.R b/bench/dolo/old/Eval.R deleted file mode 100644 index 4ac96ef1a..000000000 --- a/bench/dolo/old/Eval.R +++ /dev/null @@ -1,51 +0,0 @@ -## Time-stamp: "Last modified 2022-12-16 20:26:03 delucia" - -source("../../../util/data_evaluation/RFun_Eval.R") - -sd <- ReadRTSims("naaice_2d") - -sd <- ReadRTSims("Sim2D") - - -sd <- ReadRTSims("inner") - -tim <- readRDS("inner/timings.rds") - - -simtimes <- sapply(sd, "[","simtime") - -## workhorse function to be used with package "animation" -PlotAn <- function(tot, prop, grid, breaks) { - for (step in seq(1, length(tot))) { - snap <- tot[[step]]$C - time <- tot[[step]]$simtime/3600/24 - ind <- match(prop, colnames(snap)) - Plot2DCellData(snap[,ind], grid=grid, contour=FALSE, breaks=breaks, nlevels=length(breaks), scale=TRUE, main=paste0(prop," after ", time, "days")) - } -} - - -options(width=110) -library(viridis) - -Plot2DCellData(sd$iter_050$C$Cl, nx=1/100, ny=1/100, contour = TRUE, - nlevels = 12, palette = "heat.colors", - rev.palette = TRUE, scale = TRUE, main="Cl") - -Plot2DCellData(sd$iter_050$C$Dolomite, nx=100, ny=100, contour = FALSE, - nlevels = 12, palette = "heat.colors", - rev.palette = TRUE, scale = TRUE, ) - -cairo_pdf("naaice_inner_Dolo.pdf", width=8, height = 6, family="serif") -Plot2DCellData(sd$iter_100$C$Dolomite, nx=100, ny=100, contour = FALSE, - nlevels = 12, palette = "viridis", - rev.palette = TRUE, scale = TRUE, plot.axes = FALSE, - main="2D Diffusion - Dolomite after 2E+4 s (100 iterations)") -dev.off() - -cairo_pdf("naaice_inner_Mg.pdf", width=8, height = 6, family="serif") -Plot2DCellData(sd$iter_100$C$Mg, nx=100, ny=100, contour = FALSE, - nlevels = 12, palette = "terrain.colors", - rev.palette = TRUE, scale = TRUE, plot.axes=FALSE, - main="2D Diffusion - Mg after 2E+4 s (100 iterations)") -dev.off() diff --git a/bench/dolo/old/dol.pqi b/bench/dolo/old/dol.pqi deleted file mode 100644 index 408339482..000000000 --- a/bench/dolo/old/dol.pqi +++ /dev/null @@ -1,35 +0,0 @@ -SELECTED_OUTPUT - -high_precision true - -reset false - -time - -soln - -temperature true - -water true - -pH - -pe - -totals C Ca Cl Mg - -kinetic_reactants Calcite Dolomite - -equilibrium O2g - -SOLUTION 1 - units mol/kgw - temp 25.0 - water 1 - pH 9.91 charge - pe 4.0 - C 1.2279E-04 - Ca 1.2279E-04 - Cl 1E-12 - Mg 1E-12 -PURE 1 - O2g -0.1675 10 -KINETICS 1 - Calcite - -m 0.000207 - -parms 0.0032 - -tol 1e-10 - Dolomite - -m 0.0 - -parms 0.00032 - -tol 1e-10 -END diff --git a/bench/dolo/old/dolo_diffu_inner.R b/bench/dolo/old/dolo_diffu_inner.R deleted file mode 100644 index a16f8a49c..000000000 --- a/bench/dolo/old/dolo_diffu_inner.R +++ /dev/null @@ -1,190 +0,0 @@ -## Time-stamp: "Last modified 2023-08-16 17:04:42 mluebke" - -database <- normalizePath("../share/poet/bench/dolo/phreeqc_kin.dat") -input_script <- normalizePath("../share/poet/bench/dolo/dolo_inner.pqi") - -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# - -n <- 100 -m <- 100 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = -5.0822e-19, - "C(4)" = 1.2279E-4, - "Ca" = 1.2279E-4, - "Cl" = 0, - "Mg" = 0, - "O2g" = 0.499957, - "Calcite" = 2.07e-4, - "Dolomite" = 0 -) - -grid <- list( - n_cells = c(n, m), - s_cells = c(1, 1), - type = types[1] -) - - -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions -init_diffu <- list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = -5.0822e-19, - "C(4)" = 1.2279E-4, - "Ca" = 1.2279E-4, - "Cl" = 0, - "Mg" = 0 -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-6, - "O" = 1E-6, - "Charge" = 1E-6, - "C(4)" = 1E-6, - "Ca" = 1E-6, - "Cl" = 1E-6, - "Mg" = 1E-6 -) - -## list of boundary conditions/inner nodes -vecinj_diffu <- list( - list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = 1.90431e-16, - "C(4)" = 0, - "Ca" = 0, - "Cl" = 0.002, - "Mg" = 0.001 - ), - list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = 1.90431e-16, - "C(4)" = 0, - "Ca" = 0.0, - "Cl" = 0.004, - "Mg" = 0.002 - ) -) - -vecinj_inner <- list( - l1 = c(1, 20, 20), - l2 = c(2, 80, 80), - l3 = c(2, 60, 80) -) - -boundary <- list( - # "N" = c(1, rep(0, n-1)), - "N" = rep(0, n), - "E" = rep(0, n), - "S" = rep(0, n), - "W" = rep(0, n) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, - vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - - -## # Needed when using DHT -dht_species <- c( - "H" = 10, - "O" = 10, - "Charge" = 3, - "C(4)" = 5, - "Ca" = 5, - "Cl" = 5, - "Mg" = 5, - "Calcite" = 5, - "Dolomite" = 5 -) - -check_sign_cal_dol_dht <- function(old, new) { - if ((old["Calcite"] == 0) != (new["Calcite"] == 0)) { - return(TRUE) - } - if ((old["Dolomite"] == 0) != (new["Dolomite"] == 0)) { - return(TRUE) - } - return(FALSE) -} - -fuzz_input_dht_keys <- function(input) { - return(input[names(dht_species)]) -} - -check_sign_cal_dol_interp <- function(to_interp, data_set) { - data_set <- as.data.frame(do.call(rbind, data_set), check.names = FALSE, optional = TRUE) - names(data_set) <- names(dht_species) - cal <- (data_set$Calcite == 0) == (to_interp["Calcite"] == 0) - dol <- (data_set$Dolomite == 0) == (to_interp["Dolomite"] == 0) - - cal_dol_same_sig <- cal == dol - return(rev(which(!cal_dol_same_sig))) -} - -check_neg_cal_dol <- function(result) { - neg_sign <- (result["Calcite"] <- 0) || (result["Dolomite"] < 0) - return(any(neg_sign)) -} - -hooks <- list( - dht_fill = check_sign_cal_dol_dht, - dht_fuzz = fuzz_input_dht_keys, - interp_pre_func = check_sign_cal_dol_interp, - interp_post_func = check_neg_cal_dol -) - -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species, - hooks = hooks -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 10 -dt <- 200 - -setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE -) diff --git a/bench/dolo/old/dolo_diffu_inner_large.R b/bench/dolo/old/dolo_diffu_inner_large.R deleted file mode 100644 index c9c70c6a4..000000000 --- a/bench/dolo/old/dolo_diffu_inner_large.R +++ /dev/null @@ -1,190 +0,0 @@ -## Time-stamp: "Last modified 2023-08-16 17:05:04 mluebke" - -database <- normalizePath("../share/poet/bench/dolo/phreeqc_kin.dat") -input_script <- normalizePath("../share/poet/bench/dolo/dolo_inner.pqi") - -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# - -n <- 2000 -m <- 1000 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = -5.0822e-19, - "C" = 1.2279E-4, - "Ca" = 1.2279E-4, - "Cl" = 0, - "Mg" = 0, - "O2g" = 0.499957, - "Calcite" = 2.07e-4, - "Dolomite" = 0 -) - -grid <- list( - n_cells = c(n, m), - s_cells = c(20, 10), - type = types[1] -) - - -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions -init_diffu <- list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = -5.0822e-19, - "C(4)" = 1.2279E-4, - "Ca" = 1.2279E-4, - "Cl" = 0, - "Mg" = 0 -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-6, - "O" = 1E-6, - "Charge" = 1E-6, - "C(4)" = 1E-6, - "Ca" = 1E-6, - "Cl" = 1E-6, - "Mg" = 1E-6 -) - -## list of boundary conditions/inner nodes -vecinj_diffu <- list( - list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = 1.90431e-16, - "C(4)" = 0, - "Ca" = 0, - "Cl" = 0.002, - "Mg" = 0.001 - ), - list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = 1.90431e-16, - "C(4)" = 0, - "Ca" = 0.0, - "Cl" = 0.004, - "Mg" = 0.002 - ) -) - -vecinj_inner <- list( - l1 = c(1, 400, 200), - l2 = c(2, 1400, 800), - l3 = c(2, 1600, 800) -) - -boundary <- list( - # "N" = c(1, rep(0, n-1)), - "N" = rep(0, n), - "E" = rep(0, m), - "S" = rep(0, n), - "W" = rep(0, m) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, - vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - -## # Needed when using DHT -dht_species <- c( - "H" = 10, - "O" = 10, - "Charge" = 3, - "C(4)" = 5, - "Ca" = 5, - "Cl" = 5, - "Mg" = 5, - "Calcite" = 5, - "Dolomite" = 5 -) - -check_sign_cal_dol_dht <- function(old, new) { - if ((old["Calcite"] == 0) != (new["Calcite"] == 0)) { - return(TRUE) - } - if ((old["Dolomite"] == 0) != (new["Dolomite"] == 0)) { - return(TRUE) - } - return(FALSE) -} - -fuzz_input_dht_keys <- function(input) { - return(input[names(dht_species)]) -} - -check_sign_cal_dol_interp <- function(to_interp, data_set) { - data_set <- as.data.frame(do.call(rbind, data_set), check.names = FALSE, optional = TRUE) - names(data_set) <- names(dht_species) - cal <- (data_set$Calcite == 0) == (to_interp["Calcite"] == 0) - dol <- (data_set$Dolomite == 0) == (to_interp["Dolomite"] == 0) - - cal_dol_same_sig <- cal == dol - return(rev(which(!cal_dol_same_sig))) -} - -check_neg_cal_dol <- function(result) { - neg_sign <- (result["Calcite"] <- 0) || (result["Dolomite"] < 0) - return(any(neg_sign)) -} - -hooks <- list( - dht_fill = check_sign_cal_dol_dht, - dht_fuzz = fuzz_input_dht_keys, - interp_pre_func = check_sign_cal_dol_interp, - interp_post_func = check_neg_cal_dol -) - -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species, - hooks = hooks -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 500 -dt <- 50 - -setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = seq(5, iterations, by = 5) -) diff --git a/bench/dolo/old/dolo_inner.pqi b/bench/dolo/old/dolo_inner.pqi deleted file mode 100644 index 99e3a2f89..000000000 --- a/bench/dolo/old/dolo_inner.pqi +++ /dev/null @@ -1,28 +0,0 @@ -SELECTED_OUTPUT - -high_precision true - -reset false - -kinetic_reactants Calcite Dolomite - -equilibrium O2g - -SOLUTION 1 - units mol/kgw - temp 25.0 - water 1 - pH 9.91 charge - pe 4.0 - C 1.2279E-04 - Ca 1.2279E-04 - Cl 1E-12 - Mg 1E-12 -PURE 1 - O2g -0.1675 10 -KINETICS 1 - Calcite - -m 0.00020 - -parms 0.05 - -tol 1e-10 - Dolomite - -m 0.0 - -parms 0.005 - -tol 1e-10 -END diff --git a/bench/dolo/old/dolo_interp_long.R b/bench/dolo/old/dolo_interp_long.R deleted file mode 100644 index 7acca4298..000000000 --- a/bench/dolo/old/dolo_interp_long.R +++ /dev/null @@ -1,204 +0,0 @@ -## Time-stamp: "Last modified 2023-08-16 14:57:25 mluebke" - -database <- normalizePath("../share/poet/bench/dolo/phreeqc_kin.dat") -input_script <- normalizePath("../share/poet/bench/dolo/dolo_inner.pqi") - -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# - -n <- 400 -m <- 200 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = -5.0822e-19, - "C" = 1.2279E-4, - "Ca" = 1.2279E-4, - "Cl" = 0, - "Mg" = 0, - "O2g" = 0.499957, - "Calcite" = 2.07e-4, - "Dolomite" = 0 -) - -grid <- list( - n_cells = c(n, m), - s_cells = c(5, 2.5), - type = types[1] -) - - -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -## initial conditions -init_diffu <- list( - "H" = 1.110124E+02, - "O" = 5.550833E+01, - "Charge" = -1.216307659761E-09, - "C(4)" = 1.230067028174E-04, - "Ca" = 1.230067028174E-04, - "Cl" = 0, - "Mg" = 0 -) - -## diffusion coefficients -alpha_diffu <- c( - "H" = 1E-6, - "O" = 1E-6, - "Charge" = 1E-6, - "C(4)" = 1E-6, - "Ca" = 1E-6, - "Cl" = 1E-6, - "Mg" = 1E-6 -) - -## list of boundary conditions/inner nodes -vecinj_diffu <- list( - list( - "H" = 1.110124E+02, - "O" = 5.550796E+01, - "Charge" = -3.230390327801E-08, - "C(4)" = 0, - "Ca" = 0, - "Cl" = 0.002, - "Mg" = 0.001 - ), - list( - "H" = 110.683, - "O" = 55.3413, - "Charge" = 1.90431e-16, - "C(4)" = 0, - "Ca" = 0.0, - "Cl" = 0.004, - "Mg" = 0.002 - ), - init_diffu -) - -vecinj_inner <- list( - l1 = c(1, floor(n / 2), floor(m / 2)) - # l2 = c(2,1400,800), - # l3 = c(2,1600,800) -) - -boundary <- list( - # "N" = c(1, rep(0, n-1)), - "N" = rep(3, n), - "E" = rep(3, m), - "S" = rep(3, n), - "W" = rep(3, m) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- names(init_diffu) - -diffusion <- list( - init = as.data.frame(init_diffu, check.names = FALSE), - vecinj = vecinj, - vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - - -## # optional when using DHT -dht_species <- c( - "H" = 3, - "O" = 3, - "Charge" = 3, - "C(4)" = 6, - "Ca" = 6, - "Cl" = 3, - "Mg" = 5, - "Calcite" = 4, - "Dolomite" = 4 -) - -## # Optional when using Interpolation (example with less key species and custom -## # significant digits) - -# pht_species <- c( -# "C(4)" = 3, -# "Ca" = 3, -# "Mg" = 2, -# "Calcite" = 2, -# "Dolomite" = 2 -# ) - -check_sign_cal_dol_dht <- function(old, new) { - if ((old["Calcite"] == 0) != (new["Calcite"] == 0)) { - return(TRUE) - } - if ((old["Dolomite"] == 0) != (new["Dolomite"] == 0)) { - return(TRUE) - } - return(FALSE) -} - -fuzz_input_dht_keys <- function(input) { - return(input[names(dht_species)]) -} - -check_sign_cal_dol_interp <- function(to_interp, data_set) { - data_set <- as.data.frame(do.call(rbind, data_set), check.names = FALSE, optional = TRUE) - names(data_set) <- names(dht_species) - cal <- (data_set$Calcite == 0) == (to_interp["Calcite"] == 0) - dol <- (data_set$Dolomite == 0) == (to_interp["Dolomite"] == 0) - - cal_dol_same_sig <- cal == dol - return(rev(which(!cal_dol_same_sig))) -} - -check_neg_cal_dol <- function(result) { - neg_sign <- (result["Calcite"] < 0) || (result["Dolomite"] < 0) - return(neg_sign) -} - -hooks <- list( - dht_fill = check_sign_cal_dol_dht, - dht_fuzz = fuzz_input_dht_keys, - interp_pre_func = check_sign_cal_dol_interp, - interp_post_func = check_neg_cal_dol -) - -chemistry <- list( - database = database, - input_script = input_script, - dht_species = dht_species, - hooks = hooks - # pht_species = pht_species -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 20000 -dt <- 200 - -setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = c(1, seq(50, iterations, by = 50)) -) diff --git a/bench/dolo/old/phreeqc_kin.dat b/bench/dolo/old/phreeqc_kin.dat deleted file mode 100644 index 01d5bf516..000000000 --- a/bench/dolo/old/phreeqc_kin.dat +++ /dev/null @@ -1,1307 +0,0 @@ -### This is the standard "phreeqc.dat" stripped of EXCHANGE and -### SURFACE and with the RATES for Calcite and Dolomite to use with -### RedModRphree - -### Time-stamp: "Last modified 2023-05-23 10:35:56 mluebke" - -# PHREEQC.DAT for calculating pressure dependence of reactions, with -# molal volumina of aqueous species and of minerals, and -# critical temperatures and pressures of gases used in Peng-Robinson's EOS. -# Details are given at the end of this file. - -SOLUTION_MASTER_SPECIES -# -#element species alk gfw_formula element_gfw -# -H H+ -1.0 H 1.008 -H(0) H2 0 H -H(1) H+ -1.0 0 -E e- 0 0.0 0 -O H2O 0 O 16.0 -O(0) O2 0 O -O(-2) H2O 0 0 -Ca Ca+2 0 Ca 40.08 -Mg Mg+2 0 Mg 24.312 -Na Na+ 0 Na 22.9898 -K K+ 0 K 39.102 -Fe Fe+2 0 Fe 55.847 -Fe(+2) Fe+2 0 Fe -Fe(+3) Fe+3 -2.0 Fe -Mn Mn+2 0 Mn 54.938 -Mn(+2) Mn+2 0 Mn -Mn(+3) Mn+3 0 Mn -Al Al+3 0 Al 26.9815 -Ba Ba+2 0 Ba 137.34 -Sr Sr+2 0 Sr 87.62 -Si H4SiO4 0 SiO2 28.0843 -Cl Cl- 0 Cl 35.453 -C CO3-2 2.0 HCO3 12.0111 -C(+4) CO3-2 2.0 HCO3 -C(-4) CH4 0 CH4 -Alkalinity CO3-2 1.0 Ca0.5(CO3)0.5 50.05 -S SO4-2 0 SO4 32.064 -S(6) SO4-2 0 SO4 -S(-2) HS- 1.0 S -N NO3- 0 N 14.0067 -N(+5) NO3- 0 N -N(+3) NO2- 0 N -N(0) N2 0 N -N(-3) NH4+ 0 N 14.0067 -#Amm AmmH+ 0 AmmH 17.0 -B H3BO3 0 B 10.81 -P PO4-3 2.0 P 30.9738 -F F- 0 F 18.9984 -Li Li+ 0 Li 6.939 -Br Br- 0 Br 79.904 -Zn Zn+2 0 Zn 65.37 -Cd Cd+2 0 Cd 112.4 -Pb Pb+2 0 Pb 207.19 -Cu Cu+2 0 Cu 63.546 -Cu(+2) Cu+2 0 Cu -Cu(+1) Cu+1 0 Cu -# redox-uncoupled gases -Hdg Hdg 0 Hdg 2.016 # H2 gas -Oxg Oxg 0 Oxg 32 # O2 gas -Mtg Mtg 0 Mtg 16.032 # CH4 gas -Sg H2Sg 1.0 H2Sg 34.08 -Ntg Ntg 0 Ntg 28.0134 # N2 gas - -SOLUTION_SPECIES -H+ = H+ - -gamma 9.0 0 - -dw 9.31e-9 -e- = e- -H2O = H2O -Ca+2 = Ca+2 - -gamma 5.0 0.1650 - -dw 0.793e-9 - -Vm -0.3456 -7.252 6.149 -2.479 1.239 5 1.60 -57.1 -6.12e-3 1 # ref. 1 -Mg+2 = Mg+2 - -gamma 5.5 0.20 - -dw 0.705e-9 - -Vm -1.410 -8.6 11.13 -2.39 1.332 5.5 1.29 -32.9 -5.86e-3 1 # ref. 1 -Na+ = Na+ - -gamma 4.0 0.075 - -gamma 4.08 0.082 # halite solubility - -dw 1.33e-9 - -Vm 2.28 -4.38 -4.1 -0.586 0.09 4 0.3 52 -3.33e-3 0.566 # ref. 1 -# for calculating densities (rho) when I > 3... - # -Vm 2.28 -4.38 -4.1 -0.586 0.09 4 0.3 52 -3.33e-3 0.45 -K+ = K+ - -gamma 3.5 0.015 - -dw 1.96e-9 - -Vm 3.322 -1.473 6.534 -2.712 9.06e-2 3.5 0 29.7 0 1 # ref. 1 -Fe+2 = Fe+2 - -gamma 6.0 0 - -dw 0.719e-9 - -Vm -0.3255 -9.687 1.536 -2.379 0.3033 6 -4.21e-2 39.7 0 1 # ref. 1 -Mn+2 = Mn+2 - -gamma 6.0 0 - -dw 0.688e-9 - -Vm -1.10 -8.03 4.08 -2.45 1.4 6 8.07 0 -1.51e-2 0.118 # ref. 2 -Al+3 = Al+3 - -gamma 9.0 0 - -dw 0.559e-9 - -Vm -2.28 -17.1 10.9 -2.07 2.87 9 0 0 5.5e-3 1 # ref. 2 and Barta and Hepler, 1986, Can. J.C. 64, 353. -Ba+2 = Ba+2 - -gamma 5.0 0 - -gamma 4.0 0.153 # Barite solubility - -dw 0.848e-9 - -Vm 2.063 -10.06 1.9534 -2.36 0.4218 5 1.58 -12.03 -8.35e-3 1 # ref. 1 -Sr+2 = Sr+2 - -gamma 5.260 0.121 - -dw 0.794e-9 - -Vm -1.57e-2 -10.15 10.18 -2.36 0.860 5.26 0.859 -27.0 -4.1e-3 1.97 # ref. 1 -H4SiO4 = H4SiO4 - -dw 1.10e-9 - -Vm 10.5 1.7 20 -2.7 0.1291 # supcrt + 2*H2O in a1 -Cl- = Cl- - -gamma 3.5 0.015 - -gamma 3.63 0.017 # cf. pitzer.dat - -dw 2.03e-9 - -Vm 4.465 4.801 4.325 -2.847 1.748 0 -0.331 20.16 0 1 # ref. 1 -CO3-2 = CO3-2 - -gamma 5.4 0 - -dw 0.955e-9 - -Vm 5.95 0 0 -5.67 6.85 0 1.37 106 -0.0343 1 # ref. 1 -SO4-2 = SO4-2 - -gamma 5.0 -0.04 - -dw 1.07e-9 - -Vm 8.0 2.3 -46.04 6.245 3.82 0 0 0 0 1 # ref. 1 -NO3- = NO3- - -gamma 3.0 0 - -dw 1.9e-9 - -Vm 6.32 6.78 0 -3.06 0.346 0 0.93 0 -0.012 1 # ref. 1 -#AmmH+ = AmmH+ -# -gamma 2.5 0 -# -dw 1.98e-9 -# -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # ref. 1 -H3BO3 = H3BO3 - -dw 1.1e-9 - -Vm 7.0643 8.8547 3.5844 -3.1451 -.2000 # supcrt -PO4-3 = PO4-3 - -gamma 4.0 0 - -dw 0.612e-9 - -Vm 1.24 -9.07 9.31 -2.4 5.61 0 0 0 -1.41e-2 1 # ref. 2 -F- = F- - -gamma 3.5 0 - -dw 1.46e-9 - -Vm 0.928 1.36 6.27 -2.84 1.84 0 0 -0.318 0 1 # ref. 2 -Li+ = Li+ - -gamma 6.0 0 - -dw 1.03e-9 - -Vm -0.419 -0.069 13.16 -2.78 0.416 0 0.296 -12.4 -2.74e-3 1.26 # ref. 2 and Ellis, 1968, J. Chem. Soc. A, 1138 -Br- = Br- - -gamma 3.0 0 - -dw 2.01e-9 - -Vm 6.72 2.85 4.21 -3.14 1.38 0 -9.56e-2 7.08 -1.56e-3 1 # ref. 2 -Zn+2 = Zn+2 - -gamma 5.0 0 - -dw 0.715e-9 - -Vm -1.96 -10.4 14.3 -2.35 1.46 5 -1.43 24 1.67e-2 1.11 # ref. 2 -Cd+2 = Cd+2 - -dw 0.717e-9 - -Vm 1.63 -10.7 1.01 -2.34 1.47 5 0 0 0 1 # ref. 2 -Pb+2 = Pb+2 - -dw 0.945e-9 - -Vm -.0051 -7.7939 8.8134 -2.4568 1.0788 4.5 # supcrt -Cu+2 = Cu+2 - -gamma 6.0 0 - -dw 0.733e-9 - -Vm -1.13 -10.5 7.29 -2.35 1.61 6 9.78e-2 0 3.42e-3 1 # ref. 2 -# redox-uncoupled gases -Hdg = Hdg # H2 - -dw 5.13e-9 - -Vm 6.52 0.78 0.12 # supcrt -Oxg = Oxg # O2 - -dw 2.35e-9 - -Vm 5.7889 6.3536 3.2528 -3.0417 -0.3943 # supcrt -Mtg = Mtg # CH4 - -dw 1.85e-9 - -Vm 7.7 # CH4 solubility, 25-100C, 1-700atm -Ntg = Ntg # N2 - -dw 1.96e-9 - -Vm 7 # Pray et al., 1952, IEC 44. 1146 -H2Sg = H2Sg # H2S - -dw 2.1e-9 - -Vm 7.81 2.96 -0.46 # supcrt -# aqueous species -H2O = OH- + H+ - -analytic 293.29227 0.1360833 -10576.913 -123.73158 0 -6.996455e-5 - -gamma 3.5 0 - -dw 5.27e-9 - -Vm -9.66 28.5 80.0 -22.9 1.89 0 1.09 0 0 1 # ref. 1 -2 H2O = O2 + 4 H+ + 4 e- - -log_k -86.08 - -delta_h 134.79 kcal - -dw 2.35e-9 - -Vm 5.7889 6.3536 3.2528 -3.0417 -0.3943 # supcrt -2 H+ + 2 e- = H2 - -log_k -3.15 - -delta_h -1.759 kcal - -dw 5.13e-9 - -Vm 6.52 0.78 0.12 # supcrt -CO3-2 + H+ = HCO3- - -log_k 10.329 - -delta_h -3.561 kcal - -analytic 107.8871 0.03252849 -5151.79 -38.92561 563713.9 - -gamma 5.4 0 - -dw 1.18e-9 - -Vm 8.472 0 -11.5 0 1.56 0 0 146 3.16e-3 1 # ref. 1 -CO3-2 + 2 H+ = CO2 + H2O - -log_k 16.681 - -delta_h -5.738 kcal - -analytic 464.1965 0.09344813 -26986.16 -165.75951 2248628.9 - -dw 1.92e-9 - -Vm 20.85 -46.93 -79.0 27.9 -0.193 # ref. 1 -CO3-2 + 10 H+ + 8 e- = CH4 + 3 H2O - -log_k 41.071 - -delta_h -61.039 kcal - -dw 1.85e-9 - -Vm 7.7 -SO4-2 + H+ = HSO4- - -log_k 1.988 - -delta_h 3.85 kcal - -analytic -56.889 0.006473 2307.9 19.8858 - -dw 1.33e-9 - -Vm 8.2 9.2590 2.1108 -3.1618 1.1748 0 -0.3 15 0 1 # ref. 1 -HS- = S-2 + H+ - -log_k -12.918 - -delta_h 12.1 kcal - -gamma 5.0 0 - -dw 0.731e-9 -SO4-2 + 9 H+ + 8 e- = HS- + 4 H2O - -log_k 33.65 - -delta_h -60.140 kcal - -gamma 3.5 0 - -dw 1.73e-9 - -Vm 5.0119 4.9799 3.4765 -2.9849 1.4410 # supcrt -HS- + H+ = H2S - -log_k 6.994 - -delta_h -5.30 kcal - -analytical -11.17 0.02386 3279.0 - -dw 2.1e-9 - -Vm 7.81 2.96 -0.46 # supcrt -H2Sg = HSg- + H+ - -log_k -6.994 - -delta_h 5.30 kcal - -analytical 11.17 -0.02386 -3279.0 - -dw 2.1e-9 - -Vm 5.0119 4.9799 3.4765 -2.9849 1.4410 # supcrt -NO3- + 2 H+ + 2 e- = NO2- + H2O - -log_k 28.570 - -delta_h -43.760 kcal - -gamma 3.0 0 - -dw 1.91e-9 - -Vm 5.5864 5.8590 3.4472 -3.0212 1.1847 # supcrt -2 NO3- + 12 H+ + 10 e- = N2 + 6 H2O - -log_k 207.08 - -delta_h -312.130 kcal - -dw 1.96e-9 - -Vm 7 # Pray et al., 1952, IEC 44. 1146 -NO3- + 10 H+ + 8 e- = NH4+ + 3 H2O - -log_k 119.077 - -delta_h -187.055 kcal - -gamma 2.5 0 - -dw 1.98e-9 - -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # ref. 1 -#AmmH+ = AmmH+ -# -gamma 2.5 0.0 -# -dw 1.98e-9 -# -Vm 4.837 2.345 5.522 -2.88 1.096 3 -1.456 75.0 7.17e-3 1 # supcrt modified -NH4+ = NH3 + H+ - -log_k -9.252 - -delta_h 12.48 kcal - -analytic 0.6322 -0.001225 -2835.76 - -dw 2.28e-9 - -Vm 6.69 2.8 3.58 -2.88 1.43 # ref. 2 -#AmmH+ = Amm + H+ -# -log_k -9.252 -# -delta_h 12.48 kcal -# -analytic 0.6322 -0.001225 -2835.76 -# -dw 2.28e-9 -# -Vm 6.69 2.8 3.58 -2.88 1.43 # ref. 2 -NH4+ + SO4-2 = NH4SO4- - log_k 1.11 - -Vm 14.0 0 -35.2 0 0 0 12.3 0 -0.141 1 # ref. 2 -#AmmH+ + SO4-2 = AmmHSO4- -# -log_k 1.11 -# -Vm 14.0 0 -35.2 0 0 0 12.3 0 -0.141 1 # ref. 2 -H3BO3 = H2BO3- + H+ - -log_k -9.24 - -delta_h 3.224 kcal -H3BO3 + F- = BF(OH)3- - -log_k -0.4 - -delta_h 1.850 kcal -H3BO3 + 2 F- + H+ = BF2(OH)2- + H2O - -log_k 7.63 - -delta_h 1.618 kcal -H3BO3 + 2 H+ + 3 F- = BF3OH- + 2 H2O - -log_k 13.67 - -delta_h -1.614 kcal -H3BO3 + 3 H+ + 4 F- = BF4- + 3 H2O - -log_k 20.28 - -delta_h -1.846 kcal -PO4-3 + H+ = HPO4-2 - -log_k 12.346 - -delta_h -3.530 kcal - -gamma 5.0 0 - -dw 0.69e-9 - -Vm 3.52 1.09 8.39 -2.82 3.34 0 0 0 0 1 # ref. 2 -PO4-3 + 2 H+ = H2PO4- - -log_k 19.553 - -delta_h -4.520 kcal - -gamma 5.4 0 - -dw 0.846e-9 - -Vm 5.58 8.06 12.2 -3.11 1.3 0 0 0 1.62e-2 1 # ref. 2 -PO4-3 + 3H+ = H3PO4 - log_k 21.721 # log_k and delta_h from minteq.v4.dat, NIST46.3 - delta_h -10.1 kJ - -Vm 7.47 12.4 6.29 -3.29 0 # ref. 2 -H+ + F- = HF - -log_k 3.18 - -delta_h 3.18 kcal - -analytic -2.033 0.012645 429.01 - -Vm 3.4753 .7042 5.4732 -2.8081 -.0007 # supcrt -H+ + 2 F- = HF2- - -log_k 3.76 - -delta_h 4.550 kcal - -Vm 5.2263 4.9797 3.7928 -2.9849 1.2934 # supcrt -Ca+2 + H2O = CaOH+ + H+ - -log_k -12.78 -Ca+2 + CO3-2 = CaCO3 - -log_k 3.224 - -delta_h 3.545 kcal - -analytic -1228.732 -0.299440 35512.75 485.818 - -dw 4.46e-10 # complexes: calc'd with the Pikal formula - -Vm -.2430 -8.3748 9.0417 -2.4328 -.0300 # supcrt -Ca+2 + CO3-2 + H+ = CaHCO3+ - -log_k 11.435 - -delta_h -0.871 kcal - -analytic 1317.0071 0.34546894 -39916.84 -517.70761 563713.9 - -gamma 6.0 0 - -dw 5.06e-10 - -Vm 3.1911 .0104 5.7459 -2.7794 .3084 5.4 # supcrt -Ca+2 + SO4-2 = CaSO4 - -log_k 2.25 - -delta_h 1.325 kcal - -dw 4.71e-10 - -Vm 2.7910 -.9666 6.1300 -2.7390 -.0010 # supcrt -Ca+2 + HSO4- = CaHSO4+ - -log_k 1.08 -Ca+2 + PO4-3 = CaPO4- - -log_k 6.459 - -delta_h 3.10 kcal - -gamma 5.4 0.0 -Ca+2 + HPO4-2 = CaHPO4 - -log_k 2.739 - -delta_h 3.3 kcal -Ca+2 + H2PO4- = CaH2PO4+ - -log_k 1.408 - -delta_h 3.4 kcal - -gamma 5.4 0.0 -# Ca+2 + F- = CaF+ - # -log_k 0.94 - # -delta_h 4.120 kcal - # -gamma 5.5 0.0 - # -Vm .9846 -5.3773 7.8635 -2.5567 .6911 5.5 # supcrt -Mg+2 + H2O = MgOH+ + H+ - -log_k -11.44 - -delta_h 15.952 kcal - -gamma 6.5 0 -Mg+2 + CO3-2 = MgCO3 - -log_k 2.98 - -delta_h 2.713 kcal - -analytic 0.9910 0.00667 - -dw 4.21e-10 - -Vm -.5837 -9.2067 9.3687 -2.3984 -.0300 # supcrt -Mg+2 + H+ + CO3-2 = MgHCO3+ - -log_k 11.399 - -delta_h -2.771 kcal - -analytic 48.6721 0.03252849 -2614.335 -18.00263 563713.9 - -gamma 4.0 0 - -dw 4.78e-10 - -Vm 2.7171 -1.1469 6.2008 -2.7316 .5985 4 # supcrt -Mg+2 + SO4-2 = MgSO4 - -log_k 2.37 - -delta_h 4.550 kcal - -dw 4.45e-10 - -Vm 2.4 -0.97 6.1 -2.74 # est'd -Mg+2 + PO4-3 = MgPO4- - -log_k 6.589 - -delta_h 3.10 kcal - -gamma 5.4 0 -Mg+2 + HPO4-2 = MgHPO4 - -log_k 2.87 - -delta_h 3.3 kcal -Mg+2 + H2PO4- = MgH2PO4+ - -log_k 1.513 - -delta_h 3.4 kcal - -gamma 5.4 0 -Mg+2 + F- = MgF+ - -log_k 1.82 - -delta_h 3.20 kcal - -gamma 4.5 0 - -Vm .6494 -6.1958 8.1852 -2.5229 .9706 4.5 # supcrt -Na+ + OH- = NaOH - -log_k -10 # remove this complex -Na+ + CO3-2 = NaCO3- - -log_k 1.27 - -delta_h 8.91 kcal - -dw 5.85e-10 - -Vm 3.89 -8.23e-4 20 -9.44 3.02 9.05e-3 3.07 0 0.0233 1 # ref. 1 -Na+ + HCO3- = NaHCO3 - -log_k -0.25 - -delta_h -1 kcal - -dw 6.73e-10 - -Vm 0.431 # ref. 1 -Na+ + SO4-2 = NaSO4- - -log_k 0.7 - -delta_h 1.120 kcal - -gamma 5.4 0 - -dw 6.18e-10 - -Vm 1e-5 16.4 -0.0678 -1.05 4.14 0 6.86 0 0.0242 0.53 # ref. 1 -Na+ + HPO4-2 = NaHPO4- - -log_k 0.29 - -gamma 5.4 0 - -Vm 5.2 8.1 13 -3 0.9 0 0 1.62e-2 1 # ref. 2 -Na+ + F- = NaF - -log_k -0.24 - -Vm 2.7483 -1.0708 6.1709 -2.7347 -.030 # supcrt -K+ + SO4-2 = KSO4- - -log_k 0.85 - -delta_h 2.250 kcal - -analytical 3.106 0.0 -673.6 - -gamma 5.4 0 - -dw 7.46e-10 - -Vm 6.8 7.06 3.0 -2.07 1.1 0 0 0 0 1 # ref. 1 -K+ + HPO4-2 = KHPO4- - -log_k 0.29 - -gamma 5.4 0 - -Vm 5.4 8.1 19 -3.1 0.7 0 0 0 1.62e-2 1 # ref. 2 -Fe+2 + H2O = FeOH+ + H+ - -log_k -9.5 - -delta_h 13.20 kcal - -gamma 5.0 0 -Fe+2 + 3H2O = Fe(OH)3- + 3H+ - -log_k -31.0 - -delta_h 30.3 kcal - -gamma 5.0 0 -Fe+2 + Cl- = FeCl+ - -log_k 0.14 -Fe+2 + CO3-2 = FeCO3 - -log_k 4.38 -Fe+2 + HCO3- = FeHCO3+ - -log_k 2.0 -Fe+2 + SO4-2 = FeSO4 - -log_k 2.25 - -delta_h 3.230 kcal - -Vm -13 0 123 # ref. 2 -Fe+2 + HSO4- = FeHSO4+ - -log_k 1.08 -Fe+2 + 2HS- = Fe(HS)2 - -log_k 8.95 -Fe+2 + 3HS- = Fe(HS)3- - -log_k 10.987 -Fe+2 + HPO4-2 = FeHPO4 - -log_k 3.6 -Fe+2 + H2PO4- = FeH2PO4+ - -log_k 2.7 - -gamma 5.4 0 -Fe+2 + F- = FeF+ - -log_k 1.0 -Fe+2 = Fe+3 + e- - -log_k -13.02 - -delta_h 9.680 kcal - -gamma 9.0 0 -Fe+3 + H2O = FeOH+2 + H+ - -log_k -2.19 - -delta_h 10.4 kcal - -gamma 5.0 0 -Fe+3 + 2 H2O = Fe(OH)2+ + 2 H+ - -log_k -5.67 - -delta_h 17.1 kcal - -gamma 5.4 0 -Fe+3 + 3 H2O = Fe(OH)3 + 3 H+ - -log_k -12.56 - -delta_h 24.8 kcal -Fe+3 + 4 H2O = Fe(OH)4- + 4 H+ - -log_k -21.6 - -delta_h 31.9 kcal - -gamma 5.4 0 -Fe+2 + 2H2O = Fe(OH)2 + 2H+ - -log_k -20.57 - -delta_h 28.565 kcal -2 Fe+3 + 2 H2O = Fe2(OH)2+4 + 2 H+ - -log_k -2.95 - -delta_h 13.5 kcal -3 Fe+3 + 4 H2O = Fe3(OH)4+5 + 4 H+ - -log_k -6.3 - -delta_h 14.3 kcal -Fe+3 + Cl- = FeCl+2 - -log_k 1.48 - -delta_h 5.6 kcal - -gamma 5.0 0 -Fe+3 + 2 Cl- = FeCl2+ - -log_k 2.13 - -gamma 5.0 0 -Fe+3 + 3 Cl- = FeCl3 - -log_k 1.13 -Fe+3 + SO4-2 = FeSO4+ - -log_k 4.04 - -delta_h 3.91 kcal - -gamma 5.0 0 -Fe+3 + HSO4- = FeHSO4+2 - -log_k 2.48 -Fe+3 + 2 SO4-2 = Fe(SO4)2- - -log_k 5.38 - -delta_h 4.60 kcal -Fe+3 + HPO4-2 = FeHPO4+ - -log_k 5.43 - -delta_h 5.76 kcal - -gamma 5.0 0 -Fe+3 + H2PO4- = FeH2PO4+2 - -log_k 5.43 - -gamma 5.4 0 -Fe+3 + F- = FeF+2 - -log_k 6.2 - -delta_h 2.7 kcal - -gamma 5.0 0 -Fe+3 + 2 F- = FeF2+ - -log_k 10.8 - -delta_h 4.8 kcal - -gamma 5.0 0 -Fe+3 + 3 F- = FeF3 - -log_k 14.0 - -delta_h 5.4 kcal -Mn+2 + H2O = MnOH+ + H+ - -log_k -10.59 - -delta_h 14.40 kcal - -gamma 5.0 0 -Mn+2 + 3H2O = Mn(OH)3- + 3H+ - -log_k -34.8 - -gamma 5.0 0 -Mn+2 + Cl- = MnCl+ - -log_k 0.61 - -gamma 5.0 0 - -Vm 7.25 -1.08 -25.8 -2.73 3.99 5 0 0 0 1 # ref. 2 -Mn+2 + 2 Cl- = MnCl2 - -log_k 0.25 - -Vm 1e-5 0 144 # ref. 2 -Mn+2 + 3 Cl- = MnCl3- - -log_k -0.31 - -gamma 5.0 0 - -Vm 11.8 0 0 0 2.4 0 0 0 3.6e-2 1 # ref. 2 -Mn+2 + CO3-2 = MnCO3 - -log_k 4.9 -Mn+2 + HCO3- = MnHCO3+ - -log_k 1.95 - -gamma 5.0 0 -Mn+2 + SO4-2 = MnSO4 - -log_k 2.25 - -delta_h 3.370 kcal - -Vm -1.31 -1.83 62.3 -2.7 # ref. 2 -Mn+2 + 2 NO3- = Mn(NO3)2 - -log_k 0.6 - -delta_h -0.396 kcal - -Vm 6.16 0 29.4 0 0.9 # ref. 2 -Mn+2 + F- = MnF+ - -log_k 0.84 - -gamma 5.0 0 -Mn+2 = Mn+3 + e- - -log_k -25.51 - -delta_h 25.80 kcal - -gamma 9.0 0 -Al+3 + H2O = AlOH+2 + H+ - -log_k -5.0 - -delta_h 11.49 kcal - -analytic -38.253 0.0 -656.27 14.327 - -gamma 5.4 0 - -Vm -1.46 -11.4 10.2 -2.31 1.67 5.4 0 0 0 1 # ref. 2 and Barta and Hepler, 1986, Can. J. Chem. 64, 353. -Al+3 + 2 H2O = Al(OH)2+ + 2 H+ - -log_k -10.1 - -delta_h 26.90 kcal - -gamma 5.4 0 - -analytic 88.50 0.0 -9391.6 -27.121 -Al+3 + 3 H2O = Al(OH)3 + 3 H+ - -log_k -16.9 - -delta_h 39.89 kcal - -analytic 226.374 0.0 -18247.8 -73.597 -Al+3 + 4 H2O = Al(OH)4- + 4 H+ - -log_k -22.7 - -delta_h 42.30 kcal - -analytic 51.578 0.0 -11168.9 -14.865 - -gamma 4.5 0 -Al+3 + SO4-2 = AlSO4+ - -log_k 3.5 - -delta_h 2.29 kcal - -gamma 4.5 0 -Al+3 + 2SO4-2 = Al(SO4)2- - -log_k 5.0 - -delta_h 3.11 kcal - -gamma 4.5 0 -Al+3 + HSO4- = AlHSO4+2 - -log_k 0.46 -Al+3 + F- = AlF+2 - -log_k 7.0 - -delta_h 1.060 kcal - -gamma 5.4 0 -Al+3 + 2 F- = AlF2+ - -log_k 12.7 - -delta_h 1.980 kcal - -gamma 5.4 0 -Al+3 + 3 F- = AlF3 - -log_k 16.8 - -delta_h 2.160 kcal -Al+3 + 4 F- = AlF4- - -log_k 19.4 - -delta_h 2.20 kcal - -gamma 4.5 0 -# Al+3 + 5 F- = AlF5-2 - # log_k 20.6 - # delta_h 1.840 kcal -# Al+3 + 6 F- = AlF6-3 - # log_k 20.6 - # delta_h -1.670 kcal -H4SiO4 = H3SiO4- + H+ - -log_k -9.83 - -delta_h 6.12 kcal - -analytic -302.3724 -0.050698 15669.69 108.18466 -1119669.0 - -gamma 4 0 - -Vm 7.94 1.0881 5.3224 -2.8240 1.4767 # supcrt + H2O in a1 -H4SiO4 = H2SiO4-2 + 2 H+ - -log_k -23.0 - -delta_h 17.6 kcal - -analytic -294.0184 -0.072650 11204.49 108.18466 -1119669.0 - -gamma 5.4 0 -H4SiO4 + 4 H+ + 6 F- = SiF6-2 + 4 H2O - -log_k 30.18 - -delta_h -16.260 kcal - -gamma 5.0 0 - -Vm 8.5311 13.0492 .6211 -3.3185 2.7716 # supcrt -Ba+2 + H2O = BaOH+ + H+ - -log_k -13.47 - -gamma 5.0 0 -Ba+2 + CO3-2 = BaCO3 - -log_k 2.71 - -delta_h 3.55 kcal - -analytic 0.113 0.008721 - -Vm .2907 -7.0717 8.5295 -2.4867 -.0300 # supcrt -Ba+2 + HCO3- = BaHCO3+ - -log_k 0.982 - -delta_h 5.56 kcal - -analytic -3.0938 0.013669 -Ba+2 + SO4-2 = BaSO4 - -log_k 2.7 -Sr+2 + H2O = SrOH+ + H+ - -log_k -13.29 - -gamma 5.0 0 -Sr+2 + CO3-2 + H+ = SrHCO3+ - -log_k 11.509 - -delta_h 2.489 kcal - -analytic 104.6391 0.04739549 -5151.79 -38.92561 563713.9 - -gamma 5.4 0 -Sr+2 + CO3-2 = SrCO3 - -log_k 2.81 - -delta_h 5.22 kcal - -analytic -1.019 0.012826 - -Vm -.1787 -8.2177 8.9799 -2.4393 -.0300 # supcrt -Sr+2 + SO4-2 = SrSO4 - -log_k 2.29 - -delta_h 2.08 kcal - -Vm 6.7910 -.9666 6.1300 -2.7390 -.0010 # celestite solubility -Li+ + SO4-2 = LiSO4- - -log_k 0.64 - -gamma 5.0 0 -Cu+2 + e- = Cu+ - -log_k 2.72 - -delta_h 1.65 kcal - -gamma 2.5 0 -Cu+ + 2Cl- = CuCl2- - -log_k 5.50 - -delta_h -0.42 kcal - -gamma 4.0 0 -Cu+ + 3Cl- = CuCl3-2 - -log_k 5.70 - -delta_h 0.26 kcal - -gamma 5.0 0.0 -Cu+2 + CO3-2 = CuCO3 - -log_k 6.73 -Cu+2 + 2CO3-2 = Cu(CO3)2-2 - -log_k 9.83 -Cu+2 + HCO3- = CuHCO3+ - -log_k 2.7 -Cu+2 + Cl- = CuCl+ - -log_k 0.43 - -delta_h 8.65 kcal - -gamma 4.0 0 - -Vm -4.19 0 30.4 0 0 4 0 0 1.94e-2 1 # ref. 2 -Cu+2 + 2Cl- = CuCl2 - -log_k 0.16 - -delta_h 10.56 kcal - -Vm 26.8 0 -136 # ref. 2 -Cu+2 + 3Cl- = CuCl3- - -log_k -2.29 - -delta_h 13.69 kcal - -gamma 4.0 0 -Cu+2 + 4Cl- = CuCl4-2 - -log_k -4.59 - -delta_h 17.78 kcal - -gamma 5.0 0 -Cu+2 + F- = CuF+ - -log_k 1.26 - -delta_h 1.62 kcal -Cu+2 + H2O = CuOH+ + H+ - -log_k -8.0 - -gamma 4.0 0 -Cu+2 + 2 H2O = Cu(OH)2 + 2 H+ - -log_k -13.68 -Cu+2 + 3 H2O = Cu(OH)3- + 3 H+ - -log_k -26.9 -Cu+2 + 4 H2O = Cu(OH)4-2 + 4 H+ - -log_k -39.6 -2Cu+2 + 2H2O = Cu2(OH)2+2 + 2H+ - -log_k -10.359 - -delta_h 17.539 kcal - -analytical 2.497 0.0 -3833.0 -Cu+2 + SO4-2 = CuSO4 - -log_k 2.31 - -delta_h 1.220 kcal - -Vm 5.21 0 -14.6 # ref. 2 -Cu+2 + 3HS- = Cu(HS)3- - -log_k 25.9 -Zn+2 + H2O = ZnOH+ + H+ - -log_k -8.96 - -delta_h 13.4 kcal -Zn+2 + 2 H2O = Zn(OH)2 + 2 H+ - -log_k -16.9 -Zn+2 + 3 H2O = Zn(OH)3- + 3 H+ - -log_k -28.4 -Zn+2 + 4 H2O = Zn(OH)4-2 + 4 H+ - -log_k -41.2 -Zn+2 + Cl- = ZnCl+ - -log_k 0.43 - -delta_h 7.79 kcal - -gamma 4.0 0 - -Vm 14.8 -3.91 -105.7 -2.62 0.203 4 0 0 -5.05e-2 1 # ref. 2 -Zn+2 + 2 Cl- = ZnCl2 - -log_k 0.45 - -delta_h 8.5 kcal - -Vm -10.1 4.57 241 -2.97 -1e-3 # ref. 2 -Zn+2 + 3Cl- = ZnCl3- - -log_k 0.5 - -delta_h 9.56 kcal - -gamma 4.0 0 - -Vm 0.772 15.5 -0.349 -3.42 1.25 0 -7.77 0 0 1 # ref. 2 -Zn+2 + 4Cl- = ZnCl4-2 - -log_k 0.2 - -delta_h 10.96 kcal - -gamma 5.0 0 - -Vm 28.42 28 -5.26 -3.94 2.67 0 0 0 4.62e-2 1 # ref. 2 -Zn+2 + H2O + Cl- = ZnOHCl + H+ - -log_k -7.48 -Zn+2 + 2HS- = Zn(HS)2 - -log_k 14.94 -Zn+2 + 3HS- = Zn(HS)3- - -log_k 16.1 -Zn+2 + CO3-2 = ZnCO3 - -log_k 5.3 -Zn+2 + 2CO3-2 = Zn(CO3)2-2 - -log_k 9.63 -Zn+2 + HCO3- = ZnHCO3+ - -log_k 2.1 -Zn+2 + SO4-2 = ZnSO4 - -log_k 2.37 - -delta_h 1.36 kcal - -Vm 2.51 0 18.8 # ref. 2 -Zn+2 + 2SO4-2 = Zn(SO4)2-2 - -log_k 3.28 - -Vm 10.9 0 -98.7 0 0 0 24 0 -0.236 1 # ref. 2 -Zn+2 + Br- = ZnBr+ - -log_k -0.58 -Zn+2 + 2Br- = ZnBr2 - -log_k -0.98 -Zn+2 + F- = ZnF+ - -log_k 1.15 - -delta_h 2.22 kcal -Cd+2 + H2O = CdOH+ + H+ - -log_k -10.08 - -delta_h 13.1 kcal -Cd+2 + 2 H2O = Cd(OH)2 + 2 H+ - -log_k -20.35 -Cd+2 + 3 H2O = Cd(OH)3- + 3 H+ - -log_k -33.3 -Cd+2 + 4 H2O = Cd(OH)4-2 + 4 H+ - -log_k -47.35 -2Cd+2 + H2O = Cd2OH+3 + H+ - -log_k -9.39 - -delta_h 10.9 kcal -Cd+2 + H2O + Cl- = CdOHCl + H+ - -log_k -7.404 - -delta_h 4.355 kcal -Cd+2 + NO3- = CdNO3+ - -log_k 0.4 - -delta_h -5.2 kcal - -Vm 5.95 0 -1.11 0 2.67 7 0 0 1.53e-2 1 # ref. 2 -Cd+2 + Cl- = CdCl+ - -log_k 1.98 - -delta_h 0.59 kcal - -Vm 5.69 0 -30.2 0 0 6 0 0 0.112 1 # ref. 2 -Cd+2 + 2 Cl- = CdCl2 - -log_k 2.6 - -delta_h 1.24 kcal - -Vm 5.53 # ref. 2 -Cd+2 + 3 Cl- = CdCl3- - -log_k 2.4 - -delta_h 3.9 kcal - -Vm 4.6 0 83.9 0 0 0 0 0 0 1 # ref. 2 -Cd+2 + CO3-2 = CdCO3 - -log_k 2.9 -Cd+2 + 2CO3-2 = Cd(CO3)2-2 - -log_k 6.4 -Cd+2 + HCO3- = CdHCO3+ - -log_k 1.5 -Cd+2 + SO4-2 = CdSO4 - -log_k 2.46 - -delta_h 1.08 kcal - -Vm 10.4 0 57.9 # ref. 2 -Cd+2 + 2SO4-2 = Cd(SO4)2-2 - -log_k 3.5 - -Vm -6.29 0 -93 0 9.5 7 0 0 0 1 # ref. 2 -Cd+2 + Br- = CdBr+ - -log_k 2.17 - -delta_h -0.81 kcal -Cd+2 + 2Br- = CdBr2 - -log_k 2.9 -Cd+2 + F- = CdF+ - -log_k 1.1 -Cd+2 + 2F- = CdF2 - -log_k 1.5 -Cd+2 + HS- = CdHS+ - -log_k 10.17 -Cd+2 + 2HS- = Cd(HS)2 - -log_k 16.53 -Cd+2 + 3HS- = Cd(HS)3- - -log_k 18.71 -Cd+2 + 4HS- = Cd(HS)4-2 - -log_k 20.9 -Pb+2 + H2O = PbOH+ + H+ - -log_k -7.71 -Pb+2 + 2 H2O = Pb(OH)2 + 2 H+ - -log_k -17.12 -Pb+2 + 3 H2O = Pb(OH)3- + 3 H+ - -log_k -28.06 -Pb+2 + 4 H2O = Pb(OH)4-2 + 4 H+ - -log_k -39.7 -2 Pb+2 + H2O = Pb2OH+3 + H+ - -log_k -6.36 -Pb+2 + Cl- = PbCl+ - -log_k 1.6 - -delta_h 4.38 kcal - -Vm 2.8934 -.7165 6.0316 -2.7494 .1281 6 # supcrt -Pb+2 + 2 Cl- = PbCl2 - -log_k 1.8 - -delta_h 1.08 kcal - -Vm 6.5402 8.1879 2.5318 -3.1175 -.0300 # supcrt -Pb+2 + 3 Cl- = PbCl3- - -log_k 1.7 - -delta_h 2.17 kcal - -Vm 11.0396 19.1743 -1.7863 -3.5717 .7356 # supcrt -Pb+2 + 4 Cl- = PbCl4-2 - -log_k 1.38 - -delta_h 3.53 kcal - -Vm 16.4150 32.2997 -6.9452 -4.1143 2.3118 # supcrt -Pb+2 + CO3-2 = PbCO3 - -log_k 7.24 -Pb+2 + 2 CO3-2 = Pb(CO3)2-2 - -log_k 10.64 -Pb+2 + HCO3- = PbHCO3+ - -log_k 2.9 -Pb+2 + SO4-2 = PbSO4 - -log_k 2.75 -Pb+2 + 2 SO4-2 = Pb(SO4)2-2 - -log_k 3.47 -Pb+2 + 2HS- = Pb(HS)2 - -log_k 15.27 -Pb+2 + 3HS- = Pb(HS)3- - -log_k 16.57 -3Pb+2 + 4H2O = Pb3(OH)4+2 + 4H+ - -log_k -23.88 - -delta_h 26.5 kcal -Pb+2 + NO3- = PbNO3+ - -log_k 1.17 -Pb+2 + Br- = PbBr+ - -log_k 1.77 - -delta_h 2.88 kcal -Pb+2 + 2Br- = PbBr2 - -log_k 1.44 -Pb+2 + F- = PbF+ - -log_k 1.25 -Pb+2 + 2F- = PbF2 - -log_k 2.56 -Pb+2 + 3F- = PbF3- - -log_k 3.42 -Pb+2 + 4F- = PbF4-2 - -log_k 3.1 - -PHASES -Calcite - CaCO3 = CO3-2 + Ca+2 - -log_k -8.48 - -delta_h -2.297 kcal - -analytic -171.9065 -0.077993 2839.319 71.595 - -Vm 36.9 cm3/mol # MW (100.09 g/mol) / rho (2.71 g/cm3) -Aragonite - CaCO3 = CO3-2 + Ca+2 - -log_k -8.336 - -delta_h -2.589 kcal - -analytic -171.9773 -0.077993 2903.293 71.595 - -Vm 34.04 -Dolomite - CaMg(CO3)2 = Ca+2 + Mg+2 + 2 CO3-2 - -log_k -17.09 - -delta_h -9.436 kcal - -Vm 64.5 -Siderite - FeCO3 = Fe+2 + CO3-2 - -log_k -10.89 - -delta_h -2.480 kcal - -Vm 29.2 -Rhodochrosite - MnCO3 = Mn+2 + CO3-2 - -log_k -11.13 - -delta_h -1.430 kcal - -Vm 31.1 -Strontianite - SrCO3 = Sr+2 + CO3-2 - -log_k -9.271 - -delta_h -0.400 kcal - -analytic 155.0305 0.0 -7239.594 -56.58638 - -Vm 39.69 -Witherite - BaCO3 = Ba+2 + CO3-2 - -log_k -8.562 - -delta_h 0.703 kcal - -analytic 607.642 0.121098 -20011.25 -236.4948 - -Vm 46 -Gypsum - CaSO4:2H2O = Ca+2 + SO4-2 + 2 H2O - -log_k -4.58 - -delta_h -0.109 kcal - -analytic 68.2401 0.0 -3221.51 -25.0627 - -Vm 73.9 # 172.18 / 2.33 (Vm H2O = 13.9 cm3/mol) -Anhydrite - CaSO4 = Ca+2 + SO4-2 - -log_k -4.36 - -delta_h -1.710 kcal - -analytic 84.90 0 -3135.12 -31.79 # 50 - 160oC, 1 - 1e3 atm, anhydrite dissolution, Blount and Dickson, 1973, Am. Mineral. 58, 323. - -Vm 46.1 # 136.14 / 2.95 -Celestite - SrSO4 = Sr+2 + SO4-2 - -log_k -6.63 - -delta_h -4.037 kcal -# -analytic -14805.9622 -2.4660924 756968.533 5436.3588 -40553604.0 - -analytic -7.14 6.11e-3 75 0 0 -1.79e-5 # Howell et al., 1992, JCED 37, 464. - -Vm 46.4 -Barite - BaSO4 = Ba+2 + SO4-2 - -log_k -9.97 - -delta_h 6.35 kcal - -analytic 136.035 0.0 -7680.41 -48.595 - -Vm 51.9 -Hydroxyapatite - Ca5(PO4)3OH + 4 H+ = H2O + 3 HPO4-2 + 5 Ca+2 - -log_k -3.421 - -delta_h -36.155 kcal - -Vm 128.9 -Fluorite - CaF2 = Ca+2 + 2 F- - -log_k -10.6 - -delta_h 4.69 kcal - -analytic 66.348 0.0 -4298.2 -25.271 - -Vm 15.7 -SiO2(a) - SiO2 + 2 H2O = H4SiO4 - -log_k -2.71 - -delta_h 3.340 kcal - -analytic -0.26 0.0 -731.0 -Chalcedony - SiO2 + 2 H2O = H4SiO4 - -log_k -3.55 - -delta_h 4.720 kcal - -analytic -0.09 0.0 -1032.0 - -Vm 23.1 -Quartz - SiO2 + 2 H2O = H4SiO4 - -log_k -3.98 - -delta_h 5.990 kcal - -analytic 0.41 0.0 -1309.0 - -Vm 22.67 -Gibbsite - Al(OH)3 + 3 H+ = Al+3 + 3 H2O - -log_k 8.11 - -delta_h -22.800 kcal -Al(OH)3(a) - Al(OH)3 + 3 H+ = Al+3 + 3 H2O - -log_k 10.8 - -delta_h -26.500 kcal -Kaolinite - Al2Si2O5(OH)4 + 6 H+ = H2O + 2 H4SiO4 + 2 Al+3 - -log_k 7.435 - -delta_h -35.300 kcal -Albite - NaAlSi3O8 + 8 H2O = Na+ + Al(OH)4- + 3 H4SiO4 - -log_k -18.002 - -delta_h 25.896 kcal -Anorthite - CaAl2Si2O8 + 8 H2O = Ca+2 + 2 Al(OH)4- + 2 H4SiO4 - -log_k -19.714 - -delta_h 11.580 kcal -K-feldspar - KAlSi3O8 + 8 H2O = K+ + Al(OH)4- + 3 H4SiO4 - -log_k -20.573 - -delta_h 30.820 kcal -K-mica - KAl3Si3O10(OH)2 + 10 H+ = K+ + 3 Al+3 + 3 H4SiO4 - -log_k 12.703 - -delta_h -59.376 kcal -Chlorite(14A) - Mg5Al2Si3O10(OH)8 + 16H+ = 5Mg+2 + 2Al+3 + 3H4SiO4 + 6H2O - -log_k 68.38 - -delta_h -151.494 kcal -Ca-Montmorillonite - Ca0.165Al2.33Si3.67O10(OH)2 + 12 H2O = 0.165Ca+2 + 2.33 Al(OH)4- + 3.67 H4SiO4 + 2 H+ - -log_k -45.027 - -delta_h 58.373 kcal -Talc - Mg3Si4O10(OH)2 + 4 H2O + 6 H+ = 3 Mg+2 + 4 H4SiO4 - -log_k 21.399 - -delta_h -46.352 kcal -Illite - K0.6Mg0.25Al2.3Si3.5O10(OH)2 + 11.2H2O = 0.6K+ + 0.25Mg+2 + 2.3Al(OH)4- + 3.5H4SiO4 + 1.2H+ - -log_k -40.267 - -delta_h 54.684 kcal -Chrysotile - Mg3Si2O5(OH)4 + 6 H+ = H2O + 2 H4SiO4 + 3 Mg+2 - -log_k 32.2 - -delta_h -46.800 kcal - -analytic 13.248 0.0 10217.1 -6.1894 -Sepiolite - Mg2Si3O7.5OH:3H2O + 4 H+ + 0.5H2O = 2 Mg+2 + 3 H4SiO4 - -log_k 15.760 - -delta_h -10.700 kcal -Sepiolite(d) - Mg2Si3O7.5OH:3H2O + 4 H+ + 0.5H2O = 2 Mg+2 + 3 H4SiO4 - -log_k 18.66 -Hematite - Fe2O3 + 6 H+ = 2 Fe+3 + 3 H2O - -log_k -4.008 - -delta_h -30.845 kcal -Goethite - FeOOH + 3 H+ = Fe+3 + 2 H2O - -log_k -1.0 - -delta_h -14.48 kcal -Fe(OH)3(a) - Fe(OH)3 + 3 H+ = Fe+3 + 3 H2O - -log_k 4.891 -Pyrite - FeS2 + 2 H+ + 2 e- = Fe+2 + 2 HS- - -log_k -18.479 - -delta_h 11.300 kcal -FeS(ppt) - FeS + H+ = Fe+2 + HS- - -log_k -3.915 -Mackinawite - FeS + H+ = Fe+2 + HS- - -log_k -4.648 -Sulfur - S + 2H+ + 2e- = H2S - -log_k 4.882 - -delta_h -9.5 kcal -Vivianite - Fe3(PO4)2:8H2O = 3 Fe+2 + 2 PO4-3 + 8 H2O - -log_k -36.0 -Pyrolusite # H2O added for surface calc's - MnO2:H2O + 4 H+ + 2 e- = Mn+2 + 3 H2O - -log_k 41.38 - -delta_h -65.110 kcal -Hausmannite - Mn3O4 + 8 H+ + 2 e- = 3 Mn+2 + 4 H2O - -log_k 61.03 - -delta_h -100.640 kcal -Manganite - MnOOH + 3 H+ + e- = Mn+2 + 2 H2O - -log_k 25.34 -Pyrochroite - Mn(OH)2 + 2 H+ = Mn+2 + 2 H2O - -log_k 15.2 -Halite - NaCl = Cl- + Na+ - log_k 1.570 - -delta_h 1.37 - #-analytic -713.4616 -.1201241 37302.21 262.4583 -2106915. - -Vm 27.1 -Sylvite - KCl = K+ + Cl- - log_k 0.900 - -delta_h 8.5 - # -analytic 3.984 0.0 -919.55 - Vm 37.5 -CO2(g) - CO2 = CO2 - -log_k -1.468 - -delta_h -4.776 kcal - -analytic 109.534 1.9913e-2 -6986.04 -40.83 669370 - -T_c 304.2 # critical T, K - -P_c 72.86 # critical P, atm - -Omega 0.225 # acentric factor -H2O(g) - H2O = H2O - -log_k 1.506; delta_h -44.03 kJ - -T_c 647.3 - -P_c 217.60 - -Omega 0.344 - -analytic -16.5066 -2.0013E-3 2710.7 3.7646 0 2.24E-6 - -# Gases from LLNL... -O2(g) - O2 = O2 - -log_k -2.8983 - -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e5 - -T_c 154.6 - -P_c 49.80 - -Omega 0.021 -### MDL species added just for syntax - without parenthesis -O2g - O2 = O2 - log_k -2.8983 - -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e+5 - -T_c 154.6 - -P_c 49.80 - -Omega 0.021 -H2(g) - H2 = H2 - -log_k -3.1050 - -delta_h -4.184 kJ - -analytic -9.3114 4.6473e-3 -49.335 1.4341 1.2815e5 - -T_c 33.2 - -P_c 12.80 - -Omega -0.225 -N2(g) - N2 = N2 - -log_k -3.1864 - -analytic -58.453 1.818e-3 3199 17.909 -27460 - -T_c 126.2 - -P_c 33.50 - -Omega 0.039 -H2S(g) - H2S = H+ + HS- - -log_k -7.9759 - -analytic -97.354 -3.1576e-2 1.8285e3 37.44 28.56 - -T_c 373.2 - -P_c 88.20 - -Omega 0.1 -CH4(g) - CH4 = CH4 - -log_k -2.8502 - -analytic -24.027 4.7146e-3 372.27 6.4264 2.3362e5 - -T_c 190.6 - -P_c 45.40 - -Omega 0.008 -NH3(g) - NH3 = NH3 - -log_k 1.7966 - -analytic -18.758 3.3670e-4 2.5113e3 4.8619 39.192 - -T_c 405.6 - -P_c 111.3 - -Omega 0.25 -#Amm(g) -# Amm = Amm -# -log_k 1.7966 -# -analytic -18.758 3.3670e-4 2.5113e3 4.8619 39.192 -# -T_c 405.6 -# -P_c 111.3 -# -Omega 0.25 -# redox-uncoupled gases -Oxg(g) - Oxg = Oxg - -analytic -7.5001 7.8981e-3 0.0 0.0 2.0027e5 - -T_c 154.6 ; -P_c 49.80 ; -Omega 0.021 -Hdg(g) - Hdg = Hdg - -analytic -9.3114 4.6473e-3 -49.335 1.4341 1.2815e5 - -T_c 33.2 ; -P_c 12.80 ; -Omega -0.225 -Ntg(g) - Ntg = Ntg - -analytic -58.453 1.81800e-3 3199 17.909 -27460 - T_c 126.2 ; -P_c 33.50 ; -Omega 0.039 -Mtg(g) - Mtg = Mtg - -analytic -24.027 4.7146e-3 3.7227e2 6.4264 2.3362e5 - -T_c 190.6 ; -P_c 45.40 ; -Omega 0.008 -H2Sg(g) - H2Sg = H+ + HSg- - -analytic -97.354 -3.1576e-2 1.8285e3 37.44 28.56 - -T_c 373.2 ; -P_c 88.20 ; -Omega 0.1 -Melanterite - FeSO4:7H2O = 7 H2O + Fe+2 + SO4-2 - -log_k -2.209 - -delta_h 4.910 kcal - -analytic 1.447 -0.004153 0.0 0.0 -214949.0 -Alunite - KAl3(SO4)2(OH)6 + 6 H+ = K+ + 3 Al+3 + 2 SO4-2 + 6H2O - -log_k -1.4 - -delta_h -50.250 kcal -Jarosite-K - KFe3(SO4)2(OH)6 + 6 H+ = 3 Fe+3 + 6 H2O + K+ + 2 SO4-2 - -log_k -9.21 - -delta_h -31.280 kcal -Zn(OH)2(e) - Zn(OH)2 + 2 H+ = Zn+2 + 2 H2O - -log_k 11.5 -Smithsonite - ZnCO3 = Zn+2 + CO3-2 - -log_k -10.0 - -delta_h -4.36 kcal -Sphalerite - ZnS + H+ = Zn+2 + HS- - -log_k -11.618 - -delta_h 8.250 kcal -Willemite 289 - Zn2SiO4 + 4H+ = 2Zn+2 + H4SiO4 - -log_k 15.33 - -delta_h -33.37 kcal -Cd(OH)2 - Cd(OH)2 + 2 H+ = Cd+2 + 2 H2O - -log_k 13.65 -Otavite 315 - CdCO3 = Cd+2 + CO3-2 - -log_k -12.1 - -delta_h -0.019 kcal -CdSiO3 328 - CdSiO3 + H2O + 2H+ = Cd+2 + H4SiO4 - -log_k 9.06 - -delta_h -16.63 kcal -CdSO4 329 - CdSO4 = Cd+2 + SO4-2 - -log_k -0.1 - -delta_h -14.74 kcal -Cerrusite 365 - PbCO3 = Pb+2 + CO3-2 - -log_k -13.13 - -delta_h 4.86 kcal -Anglesite 384 - PbSO4 = Pb+2 + SO4-2 - -log_k -7.79 - -delta_h 2.15 kcal -Pb(OH)2 389 - Pb(OH)2 + 2H+ = Pb+2 + 2H2O - -log_k 8.15 - -delta_h -13.99 kcal - -RATES -Calcite --start - 10 moles=0 - 20 IF ((M<=0) and (SI("Calcite")<0)) then goto 200 - 30 R=8.314462 # in J*K-1*mol-1 - 40 deltaT=1/TK-1/298.15 # wird für 40°C berechnet; TK is temp in Kelvin - 50 e=2.718282 # Eulersche Zahl - ## mechanism 1 (acid) - 60 Ea=14400 # Aktivierungsenergie in J/mol => 65.0 in KJ/mol - 70 logK25=-0.3 # Reaktionskonstante 25C mol/m2/s - 90 mech_a=(10^logK25)*(e^(-Ea/R*deltaT))*ACT("H+") ## removed exponent - ## base term (neutral mechanism) - 100 Ea=23500 - 110 logK25=-5.81 - 120 mech_c=(10^logK25)*(e^(-Ea/R*deltaT)) - 130 rate=mech_a+mech_c - 140 IF (SI("Calcite")<0 AND M>0) then moles=parm(1)*rate*(1-SR("Calcite")) # dissolution - ## 145 IF SI("Calcite")>0 then moles=parm(1)*M*rate*(-1+SR("Calcite")) # precipitation - ## 150 moles=parm(1)*rate*(1-SR("Calcite")) # precipitation - 200 save moles*time --end - -Dolomite --start - 10 moles=0 - 20 IF ((M<=0) and (SI("Dolomite")<0)) then goto 200 - 30 R=8.314462 # in J*K-1*mol-1 - 40 deltaT=1/TK-1/298.15 # wird für 40°C berechnet; TK is temp in Kelvin - 50 e=2.718282 # Eulersche Zahl - ## mechanism 1 (acid) - 60 Ea=36100 # Aktivierungsenergie in J/mol => 65.0 in KJ/mol - 70 logK25=-3.19 # Reaktionskonstante 25C mol/m2/s - 90 mech_a=(10^logK25)*(e^(-Ea/R*deltaT))*ACT("H+")^0.5 ## removed exponent - ## base term (neutral mechanism) - 100 Ea=52200 - 110 logK25=-7.53 - 120 mech_c=(10^logK25)*(e^(-Ea/R*deltaT)) - 130 rate=mech_a+mech_c - ## 140 IF SI("Dolomite")<0 then moles=parm(1)*rate*(1-SR("Dolomite")) # dissolution - ## 140 IF SI("Dolomite")<0 then moles=parm(1)*rate*(1-SR("Dolomite")) # dissolution - 150 moles=parm(1)*rate*(1-SR("Dolomite")) # precipitation - 200 save moles*time --end - -END diff --git a/bench/surfex/ExBase.pqi b/bench/surfex/ExBase.pqi index af9c945a3..908488f1c 100644 --- a/bench/surfex/ExBase.pqi +++ b/bench/surfex/ExBase.pqi @@ -37,3 +37,27 @@ EXCHANGE 1 Z 0.0012585 Y 0.0009418 END + +SOLUTION 2 +temp 13 +units mol/kgw + +C(-4) 2.92438561098248e-21 +C(4) 2.65160558871092e-06 +Ca 2.89001071336443e-05 +Cl 0.000429291158114428 +Fe(2) 1.90823391198114e-07 +Fe(3) 3.10832423034763e-12 +H(0) 2.7888235127385e-15 +K 2.5301787e-06 +Mg 2.31391999937907e-05 +Na 0.00036746969 +S(-2) 1.01376078438546e-14 +S(2) 1.42247026981542e-19 +S(4) 9.49422092568557e-18 +S(6) 2.19812504654191e-05 +Sr 6.01218519999999e-07 +U(4) 4.82255946569383e-12 +U(5) 5.49050615347901e-13 +U(6) 1.32462838991902e-09 +END diff --git a/bench/surfex/README.org b/bench/surfex/README.org index b765f4ef5..c99f1184e 100644 --- a/bench/surfex/README.org +++ b/bench/surfex/README.org @@ -20,7 +20,7 @@ mpirun -np 4 ./poet surfex.R surfex_res - =ex.R=: POET input script for a 100x100 simulation grid, only exchange - =ExBase.pqi=: PHREEQC input script for the =ex.R= model -- =surfex.R=: POET input script for a 100x100 simulation grid +- =surfex.R=: POET input script for a 1000x1000 simulation grid considering both cation exchange and surface complexation - =SurfExBase.pqi=: PHREEQC input script for the =surfex.R= model - =SMILE_2021_11_01_TH.dat=: PHREEQC database containing the diff --git a/bench/surfex/SurfExBase.pqi b/bench/surfex/SurfExBase.pqi index a820d70e0..2598b72b2 100644 --- a/bench/surfex/SurfExBase.pqi +++ b/bench/surfex/SurfExBase.pqi @@ -54,3 +54,27 @@ EXCHANGE 1 Z 0.0012585 Y 0.0009418 END + +SOLUTION 2 +temp 13 +units mol/kgw + +C(-4) 2.92438561098248e-21 +C(4) 2.65160558871092e-06 +Ca 2.89001071336443e-05 +Cl 0.000429291158114428 +Fe(2) 1.90823391198114e-07 +Fe(3) 3.10832423034763e-12 +H(0) 2.7888235127385e-15 +K 2.5301787e-06 +Mg 2.31391999937907e-05 +Na 0.00036746969 +S(-2) 1.01376078438546e-14 +S(2) 1.42247026981542e-19 +S(4) 9.49422092568557e-18 +S(6) 2.19812504654191e-05 +Sr 6.01218519999999e-07 +U(4) 4.82255946569383e-12 +U(5) 5.49050615347901e-13 +U(6) 1.32462838991902e-09 +END \ No newline at end of file diff --git a/bench/surfex/ex.R b/bench/surfex/ex.R index 13feea1d8..2ba5399bb 100644 --- a/bench/surfex/ex.R +++ b/bench/surfex/ex.R @@ -1,140 +1,37 @@ -## Time-stamp: "Last modified 2023-08-02 13:59:35 mluebke" +rows <- 100 +cols <- 100 -database <- normalizePath("./SMILE_2021_11_01_TH.dat") -input_script <- normalizePath("./ExBase.pqi") +grid_def <- matrix(1, nrow = rows, ncol = cols) -cat(paste(":: R This is a test 1\n")) +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./SurfExBase.pqi", + pqc_db_file = "./SMILE_2021_11_01_TH.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(1, 1), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# +bound_def <- list( + "type" = rep("constant", cols), + "sol_id" = rep(2, cols), + "cell" = seq(1, cols) +) -n <- 100 -m <- 100 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list(H = 1.476571028625e-01, - O = 7.392297218936e-02, - Charge = -1.765225732724e-18, - `C(-4)` = 2.477908970828e-21, - `C(4)` = 2.647623016916e-06, - Ca = 2.889623169138e-05, - Cl = 4.292806181039e-04, - `Fe(2)` =1.908142472666e-07, - `Fe(3)` =3.173306589931e-12, - `H(0)` =2.675642675119e-15, - K = 2.530134809667e-06, - Mg =2.313806319294e-05, - Na =3.674633059628e-04, - `S(-2)` = 8.589766637180e-15, - `S(2)` = 1.205284362720e-19, - `S(4)` = 9.108958772790e-18, - `S(6)` = 2.198092329098e-05, - Sr = 6.012080128154e-07, - `U(4)` = 1.039668623852e-14, - `U(5)` = 1.208394829796e-15, - `U(6)` = 2.976409147150e-12) - -grid <- list( - n_cells = c(n, m), - s_cells = c(1, 1), - type = "scratch" +diffusion_setup <- list( + boundaries = list( + "N" = bound_def + ), + alpha_x = 1e-6, + alpha_y = 1e-6 ) -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -vecinj_diffu <- list( - list(H = 0.147659686316291, - O = 0.0739242798146046, - Charge = 7.46361643222701e-20, - `C(-4)` = 2.92438561098248e-21, - `C(4)` = 2.65160558871092e-06, - Ca = 2.89001071336443e-05, - Cl = 0.000429291158114428, - `Fe(2)` = 1.90823391198114e-07, - `Fe(3)` = 3.10832423034763e-12, - `H(0)` = 2.7888235127385e-15, - K = 2.5301787e-06, - Mg = 2.31391999937907e-05, - Na = 0.00036746969, - `S(-2)` = 1.01376078438546e-14, - `S(2)` = 1.42247026981542e-19, - `S(4)` = 9.49422092568557e-18, - `S(6)` = 2.19812504654191e-05, - Sr = 6.01218519999999e-07, - `U(4)` = 4.82255946569383e-12, - `U(5)` = 5.49050615347901e-13, - `U(6)` = 1.32462838991902e-09) -) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- grid$props - -## diffusion coefficients -alpha_diffu <- c(H = 1E-6, O = 1E-6, Charge = 1E-6, `C(-4)` = 1E-6, - `C(4)` = 1E-6, Ca = 1E-6, Cl = 1E-6, `Fe(2)` = 1E-6, - `Fe(3)` = 1E-6, `H(0)` = 1E-6, K = 1E-6, Mg = 1E-6, - Na = 1E-6, `S(-2)` = 1E-6, `S(2)` = 1E-6, - `S(4)` = 1E-6, `S(6)` = 1E-6, Sr = 1E-6, - `U(4)` = 1E-6, `U(5)` = 1E-6, `U(6)` = 1E-6) - -## list of boundary conditions/inner nodes - -## vecinj_inner <- list( -## list(1,1,1) -## ) - -boundary <- list( - "N" = rep(1, n), - "E" = rep(0, n), - "S" = rep(0, n), - "W" = rep(0, n) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- names(init_cell) - -diffusion <- list( - init = as.data.frame(init_cell, check.names = FALSE), - vecinj = vecinj, -# vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - - -chemistry <- list( - database = database, - input_script = input_script -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 10 -dt <- 200 +chemistry_setup <- list() +# Define a setup list for simulation configuration setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE -) + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup # Parameters related to the chemistry process +) \ No newline at end of file diff --git a/bench/surfex/ex_rt.R b/bench/surfex/ex_rt.R new file mode 100644 index 000000000..dff0b5c1a --- /dev/null +++ b/bench/surfex/ex_rt.R @@ -0,0 +1,7 @@ +iterations <- 10 +dt <- 200 + +list( + timesteps = rep(dt, iterations), + store_result = TRUE +) \ No newline at end of file diff --git a/bench/surfex/surfex.R b/bench/surfex/surfex.R index 27409b97f..df05aab70 100644 --- a/bench/surfex/surfex.R +++ b/bench/surfex/surfex.R @@ -1,141 +1,37 @@ -## Time-stamp: "Last modified 2023-08-02 13:59:44 mluebke" +rows <- 1000 +cols <- 1000 -database <- normalizePath("../share/poet/bench/surfex/SMILE_2021_11_01_TH.dat") -input_script <- normalizePath("../share/poet/bench/surfex/SurfExBase.pqi") +grid_def <- matrix(1, nrow = rows, ncol = cols) -cat(paste(":: R This is a test 1\n")) +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./SurfExBase.pqi", + pqc_db_file = "./SMILE_2021_11_01_TH.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(rows, cols) / 10, # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) -################################################################# -## Section 1 ## -## Grid initialization ## -################################################################# +bound_def <- list( + "type" = rep("constant", cols), + "sol_id" = rep(2, cols), + "cell" = seq(1, cols) +) -n <- 1000 -m <- 1000 - -types <- c("scratch", "phreeqc", "rds") - -init_cell <- list(H = 1.476571028625e-01, - O = 7.392297218936e-02, - Charge = -1.765225732724e-18, - `C(-4)` = 2.477908970828e-21, - `C(4)` = 2.647623016916e-06, - Ca = 2.889623169138e-05, - Cl = 4.292806181039e-04, - `Fe(2)` =1.908142472666e-07, - `Fe(3)` =3.173306589931e-12, - `H(0)` =2.675642675119e-15, - K = 2.530134809667e-06, - Mg =2.313806319294e-05, - Na =3.674633059628e-04, - `S(-2)` = 8.589766637180e-15, - `S(2)` = 1.205284362720e-19, - `S(4)` = 9.108958772790e-18, - `S(6)` = 2.198092329098e-05, - Sr = 6.012080128154e-07, - `U(4)` = 1.039668623852e-14, - `U(5)` = 1.208394829796e-15, - `U(6)` = 2.976409147150e-12) - -grid <- list( - n_cells = c(n, m), - s_cells = c(n/10, m/10), - type = "scratch" +diffusion_setup <- list( + boundaries = list( + "N" = bound_def + ), + alpha_x = 1e-6, + alpha_y = 1e-6 ) -################################################################## -## Section 2 ## -## Diffusion parameters and boundary conditions ## -################################################################## - -vecinj_diffu <- list( - list(H = 0.147659686316291, - O = 0.0739242798146046, - Charge = 7.46361643222701e-20, - `C(-4)` = 2.92438561098248e-21, - `C(4)` = 2.65160558871092e-06, - Ca = 2.89001071336443e-05, - Cl = 0.000429291158114428, - `Fe(2)` = 1.90823391198114e-07, - `Fe(3)` = 3.10832423034763e-12, - `H(0)` = 2.7888235127385e-15, - K = 2.5301787e-06, - Mg = 2.31391999937907e-05, - Na = 0.00036746969, - `S(-2)` = 1.01376078438546e-14, - `S(2)` = 1.42247026981542e-19, - `S(4)` = 9.49422092568557e-18, - `S(6)` = 2.19812504654191e-05, - Sr = 6.01218519999999e-07, - `U(4)` = 4.82255946569383e-12, - `U(5)` = 5.49050615347901e-13, - `U(6)` = 1.32462838991902e-09) -) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- grid$props - -## diffusion coefficients -alpha_diffu <- c(H = 1E-6, O = 1E-6, Charge = 1E-6, `C(-4)` = 1E-6, - `C(4)` = 1E-6, Ca = 1E-6, Cl = 1E-6, `Fe(2)` = 1E-6, - `Fe(3)` = 1E-6, `H(0)` = 1E-6, K = 1E-6, Mg = 1E-6, - Na = 1E-6, `S(-2)` = 1E-6, `S(2)` = 1E-6, - `S(4)` = 1E-6, `S(6)` = 1E-6, Sr = 1E-6, - `U(4)` = 1E-6, `U(5)` = 1E-6, `U(6)` = 1E-6) - -## list of boundary conditions/inner nodes - -## vecinj_inner <- list( -## list(1,1,1) -## ) - -boundary <- list( - "N" = rep(1, n), - "E" = rep(0, n), - "S" = rep(0, n), - "W" = rep(0, n) -) - -diffu_list <- names(alpha_diffu) - -vecinj <- do.call(rbind.data.frame, vecinj_diffu) -names(vecinj) <- names(init_cell) - -diffusion <- list( - init = as.data.frame(init_cell, check.names = FALSE), - vecinj = vecinj, -# vecinj_inner = vecinj_inner, - vecinj_index = boundary, - alpha = alpha_diffu -) - -################################################################# -## Section 3 ## -## Chemistry module (Phreeqc) ## -################################################################# - - -chemistry <- list( - database = database, - input_script = input_script -) - -################################################################# -## Section 4 ## -## Putting all those things together ## -################################################################# - - -iterations <- 100 -dt <- 200 +chemistry_setup <- list() +# Define a setup list for simulation configuration setup <- list( - grid = grid, - diffusion = diffusion, - chemistry = chemistry, - iterations = iterations, - timesteps = rep(dt, iterations), - store_result = TRUE, - out_save = c(5, iterations) -) + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup # Parameters related to the chemistry process +) \ No newline at end of file diff --git a/bench/surfex/surfex_rt.R b/bench/surfex/surfex_rt.R new file mode 100644 index 000000000..e429fd771 --- /dev/null +++ b/bench/surfex/surfex_rt.R @@ -0,0 +1,10 @@ +iterations <- 100 +dt <- 200 + +out_save <- seq(5, iterations, by = 5) + +list( + timesteps = rep(dt, iterations), + store_result = TRUE, + out_save = out_save +) \ No newline at end of file From 001b000789f759a54502654e1e51242faa2cbf85 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 15:29:47 +0000 Subject: [PATCH 65/77] Refactor build file generation --- bench/CMakeLists.txt | 32 +++++++++++++++++++++++++++++++- bench/barite/CMakeLists.txt | 26 +++++++++++++++++++------- bench/dolo/CMakeLists.txt | 25 +++++++++++++++++-------- bench/surfex/CMakeLists.txt | 23 ++++++++++++++++------- src/CMakeLists.txt | 2 +- 5 files changed, 84 insertions(+), 24 deletions(-) diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index 6b5e9b9f3..2f0eb9cbd 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -1,3 +1,33 @@ + +function(ADD_BENCH_TARGET TARGET POET_BENCH_LIST RT_FILES OUT_PATH) + add_custom_target(${TARGET}) + + set(bench_install_dir share/poet/${OUT_PATH}) + foreach(BENCH_FILE ${${POET_BENCH_LIST}}) + get_filename_component(BENCH_NAME ${BENCH_FILE} NAME_WE) + set(OUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${BENCH_NAME}.rds) + + add_custom_command(TARGET ${TARGET} + COMMAND $ -o ${OUT_FILE} -s ${CMAKE_CURRENT_SOURCE_DIR}/${BENCH_FILE} + COMMENT "Running poet_init on ${BENCH_FILE}" + DEPENDS poet_init + VERBATIM + ) + + install(FILES ${OUT_FILE} DESTINATION ${bench_install_dir}) + endforeach(BENCH_FILE ${${POET_BENCH_LIST}}) + + # install all ADD_FILES to the same location + install(FILES ${${RT_FILES}} DESTINATION ${bench_install_dir}) +endfunction() + + +# define target name +set(BENCHTARGET benchmarks) + +add_custom_target(${BENCHTARGET} ALL) + +add_subdirectory(barite) add_subdirectory(dolo) add_subdirectory(surfex) -add_subdirectory(barite) + diff --git a/bench/barite/CMakeLists.txt b/bench/barite/CMakeLists.txt index 6c8b63aee..b51d1533b 100644 --- a/bench/barite/CMakeLists.txt +++ b/bench/barite/CMakeLists.txt @@ -1,8 +1,20 @@ -install(FILES - barite.R - barite_interp_eval.R - barite.pqi - db_barite.dat -DESTINATION - share/poet/bench/barite +# Create a list of files +set(bench_files + barite_200.R + barite_het.R ) + +set(runtime_files + barite_200_rt.R + barite_het_rt.R +) + +# add_custom_target(barite_bench DEPENDS ${bench_files} ${runtime_files}) + +ADD_BENCH_TARGET(barite_bench + bench_files + runtime_files + "barite" +) + +add_dependencies(${BENCHTARGET} barite_bench) \ No newline at end of file diff --git a/bench/dolo/CMakeLists.txt b/bench/dolo/CMakeLists.txt index d2c0acd1e..b32d79432 100644 --- a/bench/dolo/CMakeLists.txt +++ b/bench/dolo/CMakeLists.txt @@ -1,9 +1,18 @@ -install(FILES - dolo_diffu_inner.R - dolo_diffu_inner_large.R - dolo_inner.pqi - dolo_interp_long.R - phreeqc_kin.dat -DESTINATION - share/poet/bench/dolo +set(bench_files + dolo_inner_large.R + dolo_interp.R ) + +set(runtime_files + dolo_inner_large_rt.R + dolo_interp_rt.R +) + +ADD_BENCH_TARGET( + dolo_bench + bench_files + runtime_files + "dolo" +) + +add_dependencies(${BENCHTARGET} dolo_bench) \ No newline at end of file diff --git a/bench/surfex/CMakeLists.txt b/bench/surfex/CMakeLists.txt index c5a605c6c..09408e038 100644 --- a/bench/surfex/CMakeLists.txt +++ b/bench/surfex/CMakeLists.txt @@ -1,9 +1,18 @@ -install(FILES - ExBase.pqi - ex.R +set(bench_files surfex.R - SurfExBase.pqi - SMILE_2021_11_01_TH.dat -DESTINATION - share/poet/bench/surfex + ex.R ) + +set(runtime_files + surfex_rt.R + ex_rt.R +) + +ADD_BENCH_TARGET( + surfex_bench + bench_files + runtime_files + "surfex" +) + +add_dependencies(${BENCHTARGET} surfex_bench) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4e8d759d..5d77d60e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,5 +81,5 @@ add_executable(poet_init initializer.cpp) target_link_libraries(poet_init PRIVATE POETLib RRuntime) target_include_directories(poet_init PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") -# install(TARGETS poet DESTINATION bin) +install(TARGETS poet poet_init DESTINATION bin) From 30014494d295270c2c7cb4d5f9bda0e521aebd82 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 15:56:06 +0000 Subject: [PATCH 66/77] Refactor Field.cpp to use Rcpp DataFrame for conversion to SEXP --- R_lib/kin_r_library.R | 12 ++++-- src/DataStructures/Field.cpp | 84 +++++++++++------------------------- src/poet.cpp | 10 +++-- 3 files changed, 42 insertions(+), 64 deletions(-) diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index b0e34ca61..4ecffdff7 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -68,16 +68,22 @@ master_iteration_end <- function(setup, state_T, state_C) { ## comprised in setup$out_save if (setup$store_result) { if (iter %in% setup$out_save) { + print(head(state_T)) + print(head(state_C)) nameout <- paste0(setup$out_dir, "/iter_", sprintf(fmt = fmt, iter), ".rds") + print(nameout) + # saveRDS(list( + # T = state_T, C = state_C, + # simtime = as.integer(setup$simulation_time) + # ), file = nameout) saveRDS(list( - T = state_T, C = state_C, - simtime = as.integer(setup$simulation_time) + T = state_T, C = state_C ), file = nameout) msgm("results stored in <", nameout, ">") } } ## Add last time step to simulation time - setup$simulation_time <- setup$simulation_time + setup$dt_differ + setup$simulation_time <- setup$simulation_time + setup$timesteps[iter] msgm("done iteration", iter, "/", length(setup$timesteps)) setup$iter <- setup$iter + 1 diff --git a/src/DataStructures/Field.cpp b/src/DataStructures/Field.cpp index 69ab648de..5f942640d 100644 --- a/src/DataStructures/Field.cpp +++ b/src/DataStructures/Field.cpp @@ -1,6 +1,9 @@ #include "Field.hpp" #include +#include +#include +#include #include #include #include @@ -117,40 +120,14 @@ poet::FieldColumn &poet::Field::operator[](const std::string &key) { } SEXP poet::Field::asSEXP() const { - const std::size_t cols = this->props.size(); + Rcpp::List output; - SEXP s_names = PROTECT(Rf_allocVector(STRSXP, cols)); - SEXP s_output = PROTECT(Rf_allocVector(VECSXP, cols)); - - for (std::size_t prop_i = 0; prop_i < this->props.size(); prop_i++) { - const auto &name = this->props[prop_i]; - SEXP s_values = PROTECT(Rf_allocVector(REALSXP, this->req_vec_size)); - const auto values = this->find(name)->second; - - SET_STRING_ELT(s_names, prop_i, Rf_mkChar(name.c_str())); - - for (std::size_t i = 0; i < this->req_vec_size; i++) { - REAL(s_values)[i] = values[i]; - } - - SET_VECTOR_ELT(s_output, prop_i, s_values); - - UNPROTECT(1); + for (const auto &elem : this->props) { + const auto map_it = this->find(elem); + output[elem] = Rcpp::wrap(map_it->second); } - SEXP s_rownames = PROTECT(Rf_allocVector(INTSXP, this->req_vec_size)); - for (std::size_t i = 0; i < this->req_vec_size; i++) { - INTEGER(s_rownames)[i] = static_cast(i + 1); - } - - Rf_setAttrib(s_output, R_ClassSymbol, - Rf_ScalarString(Rf_mkChar("data.frame"))); - Rf_setAttrib(s_output, R_NamesSymbol, s_names); - Rf_setAttrib(s_output, R_RowNamesSymbol, s_rownames); - - UNPROTECT(3); - - return s_output; + return Rcpp::DataFrame(output); } poet::Field &poet::Field::operator=(const FieldColumn &cont_field) { @@ -199,34 +176,25 @@ poet::Field::operator=(const std::vector &cont_field) { void poet::Field::fromSEXP(const SEXP &s_rhs) { this->clear(); - SEXP s_vec = PROTECT(Rf_coerceVector(s_rhs, VECSXP)); - SEXP s_names = PROTECT(Rf_getAttrib(s_vec, R_NamesSymbol)); + Rcpp::List in_list; - std::size_t cols = static_cast(Rf_length(s_vec)); - - this->props.clear(); - this->props.reserve(cols); - - for (std::size_t i = 0; i < cols; i++) { - const std::string prop_name(CHAR(STRING_ELT(s_names, i))); - this->props.push_back(prop_name); - - SEXP s_values = PROTECT(VECTOR_ELT(s_vec, i)); - - if (i == 0) { - this->req_vec_size = static_cast(Rf_length(s_values)); - } - - FieldColumn input(this->req_vec_size); - - for (std::size_t j = 0; j < this->req_vec_size; j++) { - input[j] = static_cast(REAL(s_values)[j]); - } - - UNPROTECT(1); - - this->insert({prop_name, input}); + try { + in_list = Rcpp::List(s_rhs); + } catch (const Rcpp::exception &e) { + throw std::runtime_error("Input cannot be casted as list."); } - UNPROTECT(2); + if (in_list.size() == 0) { + return; + } + + this->props = Rcpp::as>(in_list.names()); + + this->req_vec_size = + static_cast(Rcpp::DataFrame(in_list).nrow()); + + for (const auto &elem : this->props) { + const auto values = Rcpp::as>(in_list[elem]); + this->insert({elem, values}); + } } diff --git a/src/poet.cpp b/src/poet.cpp index 38ce1f974..5c749aa7e 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -264,9 +265,12 @@ static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, // state_C after every iteration if the cmdline option // --ignore-results is not given (and thus the R variable // store_result is TRUE) - *global_rt_setup = master_iteration_end_R.value()( - *global_rt_setup, diffusion.getField().asSEXP(), - chem.getField().asSEXP()); + { + Rcpp::DataFrame t_field = diffusion.getField().asSEXP(); + Rcpp::DataFrame c_field = chem.getField().asSEXP(); + *global_rt_setup = + master_iteration_end_R.value()(*global_rt_setup, t_field, c_field); + } MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + std::to_string(maxiter)); From ca2fe83554d8562670acf68461b665f851fc14ed Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 8 Apr 2024 20:47:38 +0000 Subject: [PATCH 67/77] Add minimal flag to importList function in InitialList --- src/Init/InitialList.cpp | 27 +++++++++++++++------------ src/Init/InitialList.hpp | 2 +- src/poet.cpp | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 57ce957c2..9909906cc 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -15,7 +15,7 @@ void InitialList::initializeFromList(const Rcpp::List &setup) { initChemistry(setup[chemistry_key]); } -void InitialList::importList(const Rcpp::List &setup) { +void InitialList::importList(const Rcpp::List &setup, bool minimal) { this->dim = Rcpp::as(setup[static_cast(ExportList::GRID_DIM)]); Rcpp::NumericVector grid_specs = @@ -34,20 +34,23 @@ void InitialList::importList(const Rcpp::List &setup) { this->porosity = Rcpp::as>( setup[static_cast(ExportList::GRID_POROSITY)]); - this->initial_grid = - Rcpp::List(setup[static_cast(ExportList::GRID_INITIAL)]); + if (!minimal) { + this->initial_grid = + Rcpp::List(setup[static_cast(ExportList::GRID_INITIAL)]); + } this->transport_names = Rcpp::as>( setup[static_cast(ExportList::DIFFU_TRANSPORT)]); - this->boundaries = - Rcpp::List(setup[static_cast(ExportList::DIFFU_BOUNDARIES)]); - this->inner_boundaries = - Rcpp::List(setup[static_cast(ExportList::DIFFU_INNER_BOUNDARIES)]); - this->alpha_x = - Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_X)]); - this->alpha_y = - Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_Y)]); - + if (!minimal) { + this->boundaries = + Rcpp::List(setup[static_cast(ExportList::DIFFU_BOUNDARIES)]); + this->inner_boundaries = + Rcpp::List(setup[static_cast(ExportList::DIFFU_INNER_BOUNDARIES)]); + this->alpha_x = + Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_X)]); + this->alpha_y = + Rcpp::List(setup[static_cast(ExportList::DIFFU_ALPHA_Y)]); + } this->database = Rcpp::as(setup[static_cast(ExportList::CHEM_DATABASE)]); this->pqc_scripts = Rcpp::as>( diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 74ee9de4b..532de6b74 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -31,7 +31,7 @@ public: void initializeFromList(const Rcpp::List &setup); - void importList(const Rcpp::List &setup); + void importList(const Rcpp::List &setup, bool minimal = false); Rcpp::List exportList(); Field getInitialGrid() const { return Field(this->initial_grid); } diff --git a/src/poet.cpp b/src/poet.cpp index 5c749aa7e..aa92a9f39 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -351,7 +351,7 @@ int main(int argc, char *argv[]) { } InitialList init_list(R); - init_list.importList(run_params.init_params); + init_list.importList(run_params.init_params, MY_RANK != 0); MSG("RInside initialized on process " + std::to_string(MY_RANK)); From 09cb4997ba36f4f328bfb8ab2437a617cfbb689c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 9 Apr 2024 08:09:47 +0000 Subject: [PATCH 68/77] Refactor R package dependencies in Dockerfile --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3d5ad4b63..f3ad8d911 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -17,4 +17,4 @@ RUN git clone https://github.com/doctest/doctest.git /doctest \ && cd / \ && rm -rf /doctest -RUN /usr/bin/R -q -e "install.packages(c('foreach', 'doParallel', 'Rcpp', 'RInside'))" \ No newline at end of file +RUN /usr/bin/R -q -e "install.packages(c('Rcpp', 'RInside'))" \ No newline at end of file From e2a6cf31896de0fe7f7484bb242b9f7fe9df41c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Tue, 9 Apr 2024 08:15:42 +0000 Subject: [PATCH 69/77] Refactor process to output as DataFrames --- R_lib/init_r_lib.R | 31 +++++++++----------- R_lib/kin_r_library.R | 16 +++++------ ext/doctest | 1 + src/DataStructures/Field.cpp | 7 +++-- src/Init/DiffusionInit.cpp | 56 ++++++++++++++++++++---------------- src/poet.cpp | 9 +++--- test/RInsidePOET_funcs.R | 3 ++ 7 files changed, 66 insertions(+), 57 deletions(-) create mode 160000 ext/doctest diff --git a/R_lib/init_r_lib.R b/R_lib/init_r_lib.R index 33bba851e..640c0e07b 100644 --- a/R_lib/init_r_lib.R +++ b/R_lib/init_r_lib.R @@ -34,28 +34,23 @@ resolve_pqc_bound <- function(pqc_mat, transport_spec, id) { return(value) } -add_column_after_position <- function(df, new_col, pos, new_col_name) { - # Split the data frame into two parts - df_left <- df[, 1:(pos)] - df_right <- df[, (pos + 1):ncol(df)] +add_missing_transport_species <- function(init_grid, new_names) { + # add 'ID' to new_names front, as it is not a transport species but required + new_names <- c("ID", new_names) + sol_length <- length(new_names) - # Add the new column to the left part - df_left[[new_col_name]] <- new_col + new_grid <- data.frame(matrix(0, nrow = nrow(init_grid), ncol = sol_length)) + names(new_grid) <- new_names - # Combine the left part, new column, and right part - df_new <- cbind(df_left, df_right) + matching_cols <- intersect(names(init_grid), new_names) - return(df_new) -} + # Copy matching columns from init_grid to new_grid + new_grid[, matching_cols] <- init_grid[, matching_cols] -add_missing_transport_species <- function(init_grid, new_names, old_size) { - # skip the ID column - column_index <- old_size + 1 - for (name in new_names) { - init_grid <- add_column_after_position(init_grid, rep(0, nrow(init_grid)), column_index, name) - column_index <- column_index + 1 - } + # Add missing columns to new_grid + append_df <- init_grid[, !(names(init_grid) %in% new_names)] + new_grid <- cbind(new_grid, append_df) - return(init_grid) + return(new_grid) } \ No newline at end of file diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index 4ecffdff7..835eea080 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -41,6 +41,7 @@ master_init <- function(setup, out_dir, init_field) { if (setup$store_result) { init_field_out <- paste0(out_dir, "/iter_0.rds") + init_field <- data.frame(init_field, check.names = FALSE) saveRDS(init_field, file = init_field_out) msgm("Stored initial field in ", init_field_out) if (is.null(setup[["out_save"]])) { @@ -68,16 +69,15 @@ master_iteration_end <- function(setup, state_T, state_C) { ## comprised in setup$out_save if (setup$store_result) { if (iter %in% setup$out_save) { - print(head(state_T)) - print(head(state_C)) nameout <- paste0(setup$out_dir, "/iter_", sprintf(fmt = fmt, iter), ".rds") - print(nameout) - # saveRDS(list( - # T = state_T, C = state_C, - # simtime = as.integer(setup$simulation_time) - # ), file = nameout) + + state_T <- data.frame(state_T, check.names = FALSE) + state_C <- data.frame(state_C, check.names = FALSE) + saveRDS(list( - T = state_T, C = state_C + T = state_T, + C = state_C, + simtime = as.integer(setup$simulation_time) ), file = nameout) msgm("results stored in <", nameout, ">") } diff --git a/ext/doctest b/ext/doctest new file mode 160000 index 000000000..ae7a13539 --- /dev/null +++ b/ext/doctest @@ -0,0 +1 @@ +Subproject commit ae7a13539fb71f270b87eb2e874fbac80bc8dda2 diff --git a/src/DataStructures/Field.cpp b/src/DataStructures/Field.cpp index 5f942640d..6eb6cab1f 100644 --- a/src/DataStructures/Field.cpp +++ b/src/DataStructures/Field.cpp @@ -127,7 +127,7 @@ SEXP poet::Field::asSEXP() const { output[elem] = Rcpp::wrap(map_it->second); } - return Rcpp::DataFrame(output); + return output; } poet::Field &poet::Field::operator=(const FieldColumn &cont_field) { @@ -190,8 +190,9 @@ void poet::Field::fromSEXP(const SEXP &s_rhs) { this->props = Rcpp::as>(in_list.names()); - this->req_vec_size = - static_cast(Rcpp::DataFrame(in_list).nrow()); + const Rcpp::NumericVector &in_vec = in_list[0]; + + this->req_vec_size = static_cast(in_vec.size()); for (const auto &elem : this->props) { const auto values = Rcpp::as>(in_list[elem]); diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index d39636d4e..1b2406a3a 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -1,3 +1,4 @@ +#include #include // leave above Rcpp includes, as eigen seem to have problems with a preceding // Rcpp include @@ -52,10 +53,11 @@ static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, } } -static std::vector extend_transport_names( - std::unique_ptr &phreeqc, const Rcpp::List &boundaries_list, - const Rcpp::List &inner_boundaries, - const std::vector &old_trans_names, Rcpp::List &initial_grid) { +static std::vector +extend_transport_names(std::unique_ptr &phreeqc, + const Rcpp::List &boundaries_list, + const Rcpp::List &inner_boundaries, + const std::vector &old_trans_names) { std::vector transport_names = old_trans_names; std::set constant_pqc_ids; @@ -77,21 +79,23 @@ static std::vector extend_transport_names( "length"); } - for (std::size_t i = 0; i < cells.size(); i++) { + for (auto i = 0; i < cells.size(); i++) { if (type_str[i] == "constant") { - constant_pqc_ids.insert(values[i]); + constant_pqc_ids.insert(static_cast(values[i])); } } } if (inner_boundaries.size() > 0) { const Rcpp::NumericVector values = inner_boundaries["sol_id"]; - for (std::size_t i = 0; i < values.size(); i++) { - constant_pqc_ids.insert(values[i]); + for (auto i = 0; i < values.size(); i++) { + constant_pqc_ids.insert(static_cast(values[i])); } } if (!constant_pqc_ids.empty()) { + constexpr std::size_t keep_h_o_charge = 3; + for (const auto &pqc_id : constant_pqc_ids) { const auto solution_names = phreeqc->getSolutionNames(pqc_id); @@ -99,7 +103,11 @@ static std::vector extend_transport_names( for (const auto &name : solution_names) { if (std::find(transport_names.begin(), transport_names.end(), name) == transport_names.end()) { - transport_names.push_back(name); + auto position = + std::lower_bound(transport_names.begin() + keep_h_o_charge, + transport_names.end(), name); + + transport_names.insert(position, name); } } } @@ -108,15 +116,15 @@ static std::vector extend_transport_names( return transport_names; } -static Rcpp::List extend_initial_grid(const Rcpp::List &initial_grid, - std::vector transport_names, - std::size_t old_size) { - std::vector names_to_add(transport_names.begin() + old_size, - transport_names.end()); +static Rcpp::List +extend_initial_grid(const Rcpp::List &initial_grid, + const std::vector &transport_names) { + // std::vector names_to_add(transport_names.begin() + old_size, + // transport_names.end()); Rcpp::Function extend_grid_R("add_missing_transport_species"); - return extend_grid_R(initial_grid, Rcpp::wrap(names_to_add), old_size); + return extend_grid_R(initial_grid, Rcpp::wrap(transport_names)); } std::pair @@ -128,15 +136,14 @@ InitialList::resolveBoundaries(const Rcpp::List &boundaries_list, const std::size_t old_transport_size = this->transport_names.size(); - this->transport_names = - extend_transport_names(this->phreeqc, boundaries_list, inner_boundaries, - this->transport_names, this->initial_grid); + this->transport_names = extend_transport_names( + this->phreeqc, boundaries_list, inner_boundaries, this->transport_names); const std::size_t new_transport_size = this->transport_names.size(); if (old_transport_size != new_transport_size) { - this->initial_grid = extend_initial_grid( - this->initial_grid, this->transport_names, old_transport_size); + this->initial_grid = + extend_initial_grid(this->initial_grid, this->transport_names); } for (const auto &species : this->transport_names) { @@ -166,12 +173,13 @@ InitialList::resolveBoundaries(const Rcpp::List &boundaries_list, "] cells and values are not the same length"); } - for (std::size_t i = 0; i < cells.size(); i++) { + for (auto i = 0; i < cells.size(); i++) { + const auto c_id = cells[i] - 1; if (type_str[i] == "closed") { - c_type[cells[i] - 1] = tug::BC_TYPE_CLOSED; + c_type[c_id] = tug::BC_TYPE_CLOSED; } else if (type_str[i] == "constant") { - c_type[cells[i] - 1] = tug::BC_TYPE_CONSTANT; - c_value[cells[i] - 1] = Rcpp::as( + c_type[c_id] = tug::BC_TYPE_CONSTANT; + c_value[c_id] = Rcpp::as( resolve_R(this->phreeqc_mat, Rcpp::wrap(species), values[i])); } else { throw std::runtime_error("Unknown boundary type"); diff --git a/src/poet.cpp b/src/poet.cpp index aa92a9f39..68c39592f 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -266,10 +266,11 @@ static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, // --ignore-results is not given (and thus the R variable // store_result is TRUE) { - Rcpp::DataFrame t_field = diffusion.getField().asSEXP(); - Rcpp::DataFrame c_field = chem.getField().asSEXP(); - *global_rt_setup = - master_iteration_end_R.value()(*global_rt_setup, t_field, c_field); + const auto &trans_field = diffusion.getField().asSEXP(); + const auto &chem_field = chem.getField().asSEXP(); + + *global_rt_setup = master_iteration_end_R.value()( + *global_rt_setup, trans_field, chem_field); } MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + diff --git a/test/RInsidePOET_funcs.R b/test/RInsidePOET_funcs.R index 668b05169..787a42252 100644 --- a/test/RInsidePOET_funcs.R +++ b/test/RInsidePOET_funcs.R @@ -13,10 +13,13 @@ bool_named_vec <- function(input) { } simple_field <- function(field) { + field <- as.data.frame(field, check.names = FALSE) field$Na <- 0 return(field) } extended_field <- function(field, additional) { + field <- as.data.frame(field, check.names = FALSE) + additional <- as.data.frame(additional, check.names = FALSE) return(field + additional) } From b594fc93fc8a7fae0ea534a6176a3f054d2f2d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 10 Apr 2024 09:57:56 +0000 Subject: [PATCH 70/77] Fix diffusion and chem field update order in RunMasterLoop --- src/poet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/poet.cpp b/src/poet.cpp index 68c39592f..7dac258af 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -259,8 +259,6 @@ static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, chem.simulate(dt); - diffusion.getField().update(chem.getField()); - // 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 @@ -273,6 +271,8 @@ static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, *global_rt_setup, trans_field, chem_field); } + diffusion.getField().update(chem.getField()); + MSG("End of *coupling* iteration " + std::to_string(iter) + "/" + std::to_string(maxiter)); MSG(); From cb7ca9f7d3a068fb97765cc2dce8975fac555e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 10 Apr 2024 09:58:39 +0000 Subject: [PATCH 71/77] Remove doctest submodule --- ext/doctest | 1 - 1 file changed, 1 deletion(-) delete mode 160000 ext/doctest diff --git a/ext/doctest b/ext/doctest deleted file mode 160000 index ae7a13539..000000000 --- a/ext/doctest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae7a13539fb71f270b87eb2e874fbac80bc8dda2 From 00392d5d623ae0fb5f1eaaeca9b4c89ddb1597d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Wed, 10 Apr 2024 10:20:59 +0000 Subject: [PATCH 72/77] Refactor R_lib/kin_r_library.R to use setup$maxiter instead of iter for calculating max digits --- R_lib/kin_r_library.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R_lib/kin_r_library.R b/R_lib/kin_r_library.R index 835eea080..58941a032 100644 --- a/R_lib/kin_r_library.R +++ b/R_lib/kin_r_library.R @@ -61,7 +61,7 @@ master_iteration_end <- function(setup, state_T, state_C) { iter <- setup$iter # print(iter) ## max digits for iterations - dgts <- as.integer(ceiling(log10(iter))) + dgts <- as.integer(ceiling(log10(setup$maxiter))) ## string format to use in sprintf fmt <- paste0("%0", dgts, "d") From 4e74eeef8b5e4229cfd6e38d66dced99e2d49cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Fri, 12 Apr 2024 12:35:43 +0000 Subject: [PATCH 73/77] Fix grid size assignment in GridInit.cpp --- bench/dolo/dolo_inner_large.R | 2 +- bench/dolo/dolo_interp.R | 2 +- src/Init/GridInit.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bench/dolo/dolo_inner_large.R b/bench/dolo/dolo_inner_large.R index 73b1da839..802793581 100644 --- a/bench/dolo/dolo_inner_large.R +++ b/bench/dolo/dolo_inner_large.R @@ -8,7 +8,7 @@ grid_setup <- list( pqc_in_file = "./dol.pqi", pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script - grid_size = c(rows, cols) / 100, # Size of the grid in meters + grid_size = c(cols, rows) / 100, # Size of the grid in meters constant_cells = c() # IDs of cells with constant concentration ) diff --git a/bench/dolo/dolo_interp.R b/bench/dolo/dolo_interp.R index bb88e457d..f48527d00 100644 --- a/bench/dolo/dolo_interp.R +++ b/bench/dolo/dolo_interp.R @@ -8,7 +8,7 @@ grid_setup <- list( pqc_in_file = "./dol.pqi", pqc_db_file = "./phreeqc_kin.dat", # Path to the database file for Phreeqc grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script - grid_size = c(5, 2.5), # Size of the grid in meters + grid_size = c(2.5, 5), # Size of the grid in meters constant_cells = c() # IDs of cells with constant concentration ) diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index a35295769..4a3acaf65 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -135,8 +135,8 @@ void InitialList::prepareGrid(const Rcpp::List &grid_input) { this->n_rows = grid_def.nrow(); this->n_cols = grid_def.ncol(); - this->s_rows = grid_size[0]; - this->s_cols = grid_size[1]; + this->s_cols = grid_size[0]; + this->s_rows = grid_size[1]; this->dim = n_cols == 1 ? 1 : 2; From 60c3e67a5a119d7e258db88a26eaf18e57dabe91 Mon Sep 17 00:00:00 2001 From: Max Luebke Date: Mon, 15 Apr 2024 09:10:11 +0000 Subject: [PATCH 74/77] Fix build process to only produce benchmarks when needed --- bench/CMakeLists.txt | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index 2f0eb9cbd..17045c31b 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -1,21 +1,32 @@ function(ADD_BENCH_TARGET TARGET POET_BENCH_LIST RT_FILES OUT_PATH) - add_custom_target(${TARGET}) - set(bench_install_dir share/poet/${OUT_PATH}) + + # create empty list + set(OUT_FILES_LIST "") + foreach(BENCH_FILE ${${POET_BENCH_LIST}}) get_filename_component(BENCH_NAME ${BENCH_FILE} NAME_WE) set(OUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${BENCH_NAME}.rds) - add_custom_command(TARGET ${TARGET} + add_custom_command( + OUTPUT ${OUT_FILE} COMMAND $ -o ${OUT_FILE} -s ${CMAKE_CURRENT_SOURCE_DIR}/${BENCH_FILE} COMMENT "Running poet_init on ${BENCH_FILE}" - DEPENDS poet_init + DEPENDS poet_init ${CMAKE_CURRENT_SOURCE_DIR}/${BENCH_FILE} VERBATIM + COMMAND_EXPAND_LISTS ) - install(FILES ${OUT_FILE} DESTINATION ${bench_install_dir}) + list(APPEND OUT_FILES_LIST ${OUT_FILE}) + endforeach(BENCH_FILE ${${POET_BENCH_LIST}}) + + add_custom_target( + ${TARGET} + DEPENDS ${OUT_FILES_LIST}) + + install(FILES ${OUT_FILES_LIST} DESTINATION ${bench_install_dir}) # install all ADD_FILES to the same location install(FILES ${${RT_FILES}} DESTINATION ${bench_install_dir}) From 21dcbd14d4ee9701795c7bc1891dc9177e3b9f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Fri, 12 Apr 2024 19:33:18 +0200 Subject: [PATCH 75/77] BREAKING CHANGE: Enable Surface/Exchange using new API of PhreeqcEngine --- CMakeLists.txt | 2 +- bench/dolo/dol.pqi | 2 +- bench/dolo/dolo_inner_large.R | 4 +- ext/iphreeqc | 2 +- src/Chemistry/ChemistryModule.cpp | 17 +++++---- src/Chemistry/ChemistryModule.hpp | 4 +- src/Chemistry/WorkerFunctions.cpp | 61 ++++-------------------------- src/Init/ChemistryInit.cpp | 33 +++++++++++++--- src/Init/DiffusionInit.cpp | 6 +-- src/Init/GridInit.cpp | 18 ++++++--- src/Init/InitialList.cpp | 36 ++++++++++++++++-- src/Init/InitialList.hpp | 37 ++++++++++++++---- src/poet.cpp | 46 ++++++++++++++-------- util/data_evaluation/jlFun_Eval.jl | 31 +++++++++++++++ 14 files changed, 189 insertions(+), 110 deletions(-) create mode 100644 util/data_evaluation/jlFun_Eval.jl diff --git a/CMakeLists.txt b/CMakeLists.txt index 26d2cf9fc..1c17fb843 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(POET DESCRIPTION "A coupled reactive transport simulator") # specify the C++ standard -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) diff --git a/bench/dolo/dol.pqi b/bench/dolo/dol.pqi index a9706bcf1..30a6674d7 100644 --- a/bench/dolo/dol.pqi +++ b/bench/dolo/dol.pqi @@ -39,5 +39,5 @@ SOLUTION 4 water 1 temp 25 Mg 0.002 - Cl 0.002 + Cl 0.004 END diff --git a/bench/dolo/dolo_inner_large.R b/bench/dolo/dolo_inner_large.R index 802793581..155f75c85 100644 --- a/bench/dolo/dolo_inner_large.R +++ b/bench/dolo/dolo_inner_large.R @@ -16,8 +16,8 @@ bound_size <- 2 diffusion_setup <- list( inner_boundaries = list( - "row" = c(200, 800, 800), - "col" = c(400, 1400, 1600), + "row" = c(400, 1400, 1600), + "col" = c(200, 800, 800), "sol_id" = c(3, 4, 4) ), alpha_x = 1e-6, diff --git a/ext/iphreeqc b/ext/iphreeqc index 4ec8b7006..749fdbc2e 160000 --- a/ext/iphreeqc +++ b/ext/iphreeqc @@ -1 +1 @@ -Subproject commit 4ec8b7006c215ad9fc1310505cd56d03ba4b17dd +Subproject commit 749fdbc2e9478046bf3f270c70e5800637246712 diff --git a/src/Chemistry/ChemistryModule.cpp b/src/Chemistry/ChemistryModule.cpp index f48bd9a00..155b90569 100644 --- a/src/Chemistry/ChemistryModule.cpp +++ b/src/Chemistry/ChemistryModule.cpp @@ -1,12 +1,11 @@ #include "ChemistryModule.hpp" -#include "IPhreeqcPOET.hpp" +#include "PhreeqcEngine.hpp" #include "SurrogateModels/DHT_Wrapper.hpp" #include "SurrogateModels/Interpolation.hpp" #include #include -#include #include #include #include @@ -168,12 +167,16 @@ poet::ChemistryModule::ChemistryModule( this->n_cells = chem_params.total_grid_cells; if (!is_master) { - for (std::size_t i = 0; i < chem_params.pqc_ids.size(); i++) { - this->phreeqc_instances[chem_params.pqc_ids[i]] = - std::make_unique(chem_params.database, - chem_params.pqc_scripts[i], - chem_params.pqc_sol_order, wp_size_); + for (const auto &[pqc_id, pqc_config] : chem_params.pqc_config) { + this->phreeqc_instances[pqc_id] = + std::make_unique(pqc_config); } + // for (std::size_t i = 0; i < chem_params.pqc_ids.size(); i++) { + // this->phreeqc_instances[chem_params.pqc_ids[i]] = + // std::make_unique( + // chem_params.database, chem_params.pqc_scripts[i], + // chem_params.pqc_sol_order, chem_params.field_header, wp_size_); + // } } } diff --git a/src/Chemistry/ChemistryModule.hpp b/src/Chemistry/ChemistryModule.hpp index 80be5a22f..7260422fb 100644 --- a/src/Chemistry/ChemistryModule.hpp +++ b/src/Chemistry/ChemistryModule.hpp @@ -11,7 +11,7 @@ #include "SurrogateModels/DHT_Wrapper.hpp" #include "SurrogateModels/Interpolation.hpp" -#include "IPhreeqcPOET.hpp" +#include "PhreeqcEngine.hpp" #include #include #include @@ -378,7 +378,7 @@ protected: const InitialList::ChemistryInit params; - std::map> phreeqc_instances; + std::map> phreeqc_instances; }; } // namespace poet diff --git a/src/Chemistry/WorkerFunctions.cpp b/src/Chemistry/WorkerFunctions.cpp index fb9b1f015..96a67898d 100644 --- a/src/Chemistry/WorkerFunctions.cpp +++ b/src/Chemistry/WorkerFunctions.cpp @@ -4,6 +4,7 @@ #include "Chemistry/ChemistryDefs.hpp" +#include #include #include #include @@ -280,8 +281,6 @@ void poet::ChemistryModule::WorkerReadDHTDump( void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, double dSimTime, double dTimestep) { - // check if we actually need to start phreeqc - std::map> zone_mapping; for (std::size_t wp_id = 0; wp_id < work_package.size; wp_id++) { if (work_package.mapping[wp_id] != CHEM_PQC) { @@ -289,70 +288,24 @@ void poet::ChemistryModule::WorkerRunWorkPackage(WorkPackage &work_package, } auto curr_input = work_package.input[wp_id]; - const auto pqc_id = curr_input[0]; + const auto pqc_id = static_cast(curr_input[0]); auto &phreeqc_instance = this->phreeqc_instances[pqc_id]; work_package.output[wp_id] = work_package.input[wp_id]; - curr_input.erase(curr_input.begin()); - - // remove NaNs from the input curr_input.erase(std::remove_if(curr_input.begin(), curr_input.end(), [](double d) { return std::isnan(d); }), curr_input.end()); - phreeqc_instance->queueCell(curr_input); - zone_mapping[pqc_id].push_back(wp_id); - } + phreeqc_instance->runCell(curr_input, dTimestep); - if (zone_mapping.empty()) { - return; - } - - for (const auto &[pqc_id, eval_cells] : zone_mapping) { - if (eval_cells.empty()) { - continue; - } - - this->phreeqc_instances[pqc_id]->runQueuedCells(dTimestep); - - std::vector> pqc_out; - this->phreeqc_instances[pqc_id]->dequeueCells(pqc_out); - - for (std::size_t i = 0; i < eval_cells.size(); i++) { - std::size_t wp_id = eval_cells[i]; - std::size_t output_index = 0; - for (std::size_t j = 1; j < work_package.output[wp_id].size(); j++) { - if (!(std::isnan(work_package.output[wp_id][j]))) { - work_package.output[wp_id][j] = pqc_out[i][output_index++]; - } + std::size_t output_index = 0; + for (std::size_t i = 0; i < work_package.output[wp_id].size(); i++) { + if (std::isnan(work_package.output[wp_id][i])) { + work_package.output[wp_id][i] = curr_input[output_index++]; } } } - - // run the phreeqc instances - // for (const auto &[pqc_id, phreeqc_instance] : this->phreeqc_instances) { - // // if (zone_mapping.find(pqc_id) == zone_mapping.end()) { - // // continue; - // // } - // phreeqc_instance->runQueuedCells(dTimestep); - - // // remap the output to the work_package - // std::vector> pqc_out; - // phreeqc_instance->dequeueCells(pqc_out); - - // std::size_t output_id = 0; - - // for (const auto &wp_id : zone_mapping[pqc_id]) { - // std::size_t output_index = 0; - // for (std::size_t i = 1; i < work_package.output[wp_id].size(); i++) { - // if (!(std::isnan(work_package.output[wp_id][i]))) { - // work_package.output[wp_id][i] = pqc_out[output_id][output_index++]; - // } - // } - // output_id++; - // } - // } } void poet::ChemistryModule::WorkerPerfToMaster(int type, diff --git a/src/Init/ChemistryInit.cpp b/src/Init/ChemistryInit.cpp index e5f59380e..5eb0d01f4 100644 --- a/src/Init/ChemistryInit.cpp +++ b/src/Init/ChemistryInit.cpp @@ -1,12 +1,16 @@ #include "InitialList.hpp" #include +#include #include namespace poet { void InitialList::initChemistry(const Rcpp::List &chem) { - this->pqc_sol_order = this->transport_names; + this->pqc_solutions = std::vector( + this->transport_names.begin() + 3, this->transport_names.end()); + + this->pqc_solution_primaries = this->phreeqc->getSolutionPrimaries(); if (chem.containsElementNamed("dht_species")) { this->dht_species = Rcpp::as>(chem["dht_species"]); @@ -27,6 +31,10 @@ void InitialList::initChemistry(const Rcpp::List &chem) { } } } + + this->field_header = + Rcpp::as>(this->initial_grid.names()); + this->field_header.erase(this->field_header.begin()); } InitialList::ChemistryInit InitialList::getChemistryInit() const { @@ -34,11 +42,26 @@ InitialList::ChemistryInit InitialList::getChemistryInit() const { chem_init.total_grid_cells = this->n_cols * this->n_rows; - chem_init.database = database; - chem_init.pqc_scripts = pqc_scripts; - chem_init.pqc_ids = pqc_ids; + // chem_init.field_header = this->field_header; - chem_init.pqc_sol_order = pqc_sol_order; + chem_init.database = database; + // chem_init.pqc_scripts = pqc_scripts; + // chem_init.pqc_ids = pqc_ids; + + for (std::size_t i = 0; i < pqc_scripts.size(); i++) { + POETInitCell cell = { + pqc_solutions, + pqc_solution_primaries, + Rcpp::as>(pqc_exchanger[i]), + Rcpp::as>(pqc_kinetics[i]), + Rcpp::as>(pqc_equilibrium[i]), + Rcpp::as>(pqc_surface_comps[i]), + Rcpp::as>(pqc_surface_charges[i])}; + + chem_init.pqc_config[pqc_ids[i]] = {database, pqc_scripts[i], cell}; + } + + // chem_init.pqc_sol_order = pqc_solutions; chem_init.dht_species = dht_species; chem_init.interp_species = interp_species; diff --git a/src/Init/DiffusionInit.cpp b/src/Init/DiffusionInit.cpp index 1b2406a3a..3eb2fe2fd 100644 --- a/src/Init/DiffusionInit.cpp +++ b/src/Init/DiffusionInit.cpp @@ -7,8 +7,8 @@ #include #include "DataStructures/Field.hpp" -#include "IPhreeqcPOET.hpp" #include "InitialList.hpp" +#include "PhreeqcInit.hpp" #include #include @@ -54,7 +54,7 @@ static std::vector colMajToRowMaj(const Rcpp::NumericVector &vec, } static std::vector -extend_transport_names(std::unique_ptr &phreeqc, +extend_transport_names(std::unique_ptr &phreeqc, const Rcpp::List &boundaries_list, const Rcpp::List &inner_boundaries, const std::vector &old_trans_names) { @@ -332,7 +332,7 @@ RcppListToBoundaryMap(const std::vector &trans_names, } for (std::size_t i = 0; i < type.size(); i++) { - if (type[i] == tug::BC_TYPE_CONSTANT) { + if (static_cast(type[i]) == tug::BC_TYPE_CONSTANT) { bc.setBoundaryElementConstant(static_cast(tug_index), i, value[i]); } diff --git a/src/Init/GridInit.cpp b/src/Init/GridInit.cpp index 4a3acaf65..39305dbb2 100644 --- a/src/Init/GridInit.cpp +++ b/src/Init/GridInit.cpp @@ -1,6 +1,7 @@ #include "InitialList.hpp" -#include +#include "PhreeqcInit.hpp" + #include #include #include @@ -15,8 +16,8 @@ namespace poet { static Rcpp::NumericMatrix -pqcScriptToGrid(std::unique_ptr &phreeqc, RInside &R) { - IPhreeqcPOET::PhreeqcMat phreeqc_mat = phreeqc->getPhreeqcMat(); +pqcScriptToGrid(std::unique_ptr &phreeqc, RInside &R) { + PhreeqcInit::PhreeqcMat phreeqc_mat = phreeqc->getPhreeqcMat(); // add "id" to the front of the column names @@ -59,9 +60,9 @@ replaceRawKeywordIDs(std::map raws) { return raws; } -static inline uint32_t getSolutionCount(std::unique_ptr &phreeqc, +static inline uint32_t getSolutionCount(std::unique_ptr &phreeqc, const Rcpp::List &initial_grid) { - IPhreeqcPOET::ModulesArray mod_array; + PhreeqcInit::ModulesArray mod_array; Rcpp::Function unique_R("unique"); std::vector row_ids = @@ -155,7 +156,7 @@ void InitialList::prepareGrid(const Rcpp::List &grid_input) { throw std::runtime_error("Grid size must be positive."); } - this->phreeqc = std::make_unique(database, script); + this->phreeqc = std::make_unique(database, script); this->phreeqc_mat = pqcScriptToGrid(phreeqc, R); this->initial_grid = matToGrid(R, this->phreeqc_mat, grid_def); @@ -178,6 +179,11 @@ void InitialList::prepareGrid(const Rcpp::List &grid_input) { for (const auto &id : this->pqc_ids) { this->pqc_scripts.push_back(pqc_raw_dumps[id]); + this->pqc_exchanger.push_back(phreeqc->getExchanger(id)); + this->pqc_kinetics.push_back(phreeqc->getKineticsNames(id)); + this->pqc_equilibrium.push_back(phreeqc->getEquilibriumNames(id)); + this->pqc_surface_comps.push_back(phreeqc->getSurfaceCompNames(id)); + this->pqc_surface_charges.push_back(phreeqc->getSurfaceChargeNames(id)); } } diff --git a/src/Init/InitialList.cpp b/src/Init/InitialList.cpp index 9909906cc..e4bae7093 100644 --- a/src/Init/InitialList.cpp +++ b/src/Init/InitialList.cpp @@ -53,12 +53,26 @@ void InitialList::importList(const Rcpp::List &setup, bool minimal) { } this->database = Rcpp::as(setup[static_cast(ExportList::CHEM_DATABASE)]); + this->field_header = Rcpp::as>( + setup[static_cast(ExportList::CHEM_FIELD_HEADER)]); this->pqc_scripts = Rcpp::as>( setup[static_cast(ExportList::CHEM_PQC_SCRIPTS)]); this->pqc_ids = Rcpp::as>( setup[static_cast(ExportList::CHEM_PQC_IDS)]); - this->pqc_sol_order = Rcpp::as>( - setup[static_cast(ExportList::CHEM_PQC_SOL_ORDER)]); + this->pqc_solutions = Rcpp::as>( + setup[static_cast(ExportList::CHEM_PQC_SOLUTIONS)]); + this->pqc_solution_primaries = Rcpp::as>( + setup[static_cast(ExportList::CHEM_PQC_SOLUTION_PRIMARY)]); + this->pqc_exchanger = + Rcpp::List(setup[static_cast(ExportList::CHEM_PQC_EXCHANGER)]); + this->pqc_kinetics = + Rcpp::List(setup[static_cast(ExportList::CHEM_PQC_KINETICS)]); + this->pqc_equilibrium = + Rcpp::List(setup[static_cast(ExportList::CHEM_PQC_EQUILIBRIUM)]); + this->pqc_surface_comps = + Rcpp::List(setup[static_cast(ExportList::CHEM_PQC_SURFACE_COMPS)]); + this->pqc_surface_charges = + Rcpp::List(setup[static_cast(ExportList::CHEM_PQC_SURFACE_CHARGES)]); this->dht_species = NamedVector( setup[static_cast(ExportList::CHEM_DHT_SPECIES)]); @@ -92,11 +106,25 @@ Rcpp::List InitialList::exportList() { out[static_cast(ExportList::DIFFU_ALPHA_Y)] = this->alpha_y; out[static_cast(ExportList::CHEM_DATABASE)] = Rcpp::wrap(this->database); + out[static_cast(ExportList::CHEM_FIELD_HEADER)] = + Rcpp::wrap(this->field_header); out[static_cast(ExportList::CHEM_PQC_SCRIPTS)] = Rcpp::wrap(this->pqc_scripts); out[static_cast(ExportList::CHEM_PQC_IDS)] = Rcpp::wrap(this->pqc_ids); - out[static_cast(ExportList::CHEM_PQC_SOL_ORDER)] = - Rcpp::wrap(this->pqc_sol_order); + out[static_cast(ExportList::CHEM_PQC_SOLUTIONS)] = + Rcpp::wrap(this->pqc_solutions); + out[static_cast(ExportList::CHEM_PQC_SOLUTION_PRIMARY)] = + Rcpp::wrap(this->pqc_solution_primaries); + out[static_cast(ExportList::CHEM_PQC_EXCHANGER)] = + Rcpp::wrap(this->pqc_exchanger); + out[static_cast(ExportList::CHEM_PQC_KINETICS)] = + Rcpp::wrap(this->pqc_kinetics); + out[static_cast(ExportList::CHEM_PQC_EQUILIBRIUM)] = + Rcpp::wrap(this->pqc_equilibrium); + out[static_cast(ExportList::CHEM_PQC_SURFACE_COMPS)] = + Rcpp::wrap(this->pqc_surface_comps); + out[static_cast(ExportList::CHEM_PQC_SURFACE_CHARGES)] = + Rcpp::wrap(this->pqc_surface_charges); out[static_cast(ExportList::CHEM_DHT_SPECIES)] = this->dht_species; out[static_cast(ExportList::CHEM_INTERP_SPECIES)] = Rcpp::wrap(this->interp_species); diff --git a/src/Init/InitialList.hpp b/src/Init/InitialList.hpp index 532de6b74..bc9555329 100644 --- a/src/Init/InitialList.hpp +++ b/src/Init/InitialList.hpp @@ -2,8 +2,8 @@ #include "Base/RInsidePOET.hpp" #include "DataStructures/NamedVector.hpp" +#include "POETInit.hpp" #include -#include #include #include @@ -13,8 +13,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -52,9 +53,16 @@ private: DIFFU_ALPHA_X, DIFFU_ALPHA_Y, CHEM_DATABASE, + CHEM_FIELD_HEADER, CHEM_PQC_SCRIPTS, CHEM_PQC_IDS, - CHEM_PQC_SOL_ORDER, + CHEM_PQC_SOLUTIONS, + CHEM_PQC_SOLUTION_PRIMARY, + CHEM_PQC_EXCHANGER, + CHEM_PQC_KINETICS, + CHEM_PQC_EQUILIBRIUM, + CHEM_PQC_SURFACE_COMPS, + CHEM_PQC_SURFACE_CHARGES, CHEM_DHT_SPECIES, CHEM_INTERP_SPECIES, CHEM_HOOKS, @@ -88,7 +96,7 @@ private: return GridMembersString[static_cast(member)]; } - std::unique_ptr phreeqc; + std::unique_ptr phreeqc; void prepareGrid(const Rcpp::List &grid_input); @@ -178,11 +186,19 @@ private: void initChemistry(const Rcpp::List &chem_input); + std::vector field_header; + std::string database; std::vector pqc_scripts; std::vector pqc_ids; - std::vector pqc_sol_order; + std::vector pqc_solutions; + std::vector pqc_solution_primaries; + Rcpp::List pqc_exchanger; + Rcpp::List pqc_kinetics; + Rcpp::List pqc_equilibrium; + Rcpp::List pqc_surface_comps; + Rcpp::List pqc_surface_charges; NamedVector dht_species; @@ -204,10 +220,15 @@ public: struct ChemistryInit { uint32_t total_grid_cells; + // std::vector field_header; + std::string database; - std::vector pqc_scripts; - std::vector pqc_ids; - std::vector pqc_sol_order; + // std::vector pqc_scripts; + // std::vector pqc_ids; + + std::map pqc_config; + + // std::vector pqc_sol_order; NamedVector dht_species; NamedVector interp_species; diff --git a/src/poet.cpp b/src/poet.cpp index 7dac258af..48142cbf8 100644 --- a/src/poet.cpp +++ b/src/poet.cpp @@ -65,15 +65,16 @@ static void init_global_functions(RInside &R) { // HACK: this is a step back as the order and also the count of fields is // predefined, but it will change in the future -void writeFieldsToR(RInside &R, const Field &trans, const Field &chem) { +// static inline void writeFieldsToR(RInside &R, const Field &trans, +// const Field &chem) { - Rcpp::DataFrame t_field(trans.asSEXP()); - R["TMP"] = t_field; - R.parseEval("mysetup$state_T <- TMP"); +// Rcpp::DataFrame t_field(trans.asSEXP()); +// R["TMP"] = t_field; +// R.parseEval("mysetup$state_T <- TMP"); - R["TMP"] = chem.asSEXP(); - R.parseEval("mysetup$state_C <- TMP"); -} +// R["TMP"] = chem.asSEXP(); +// R.parseEval("mysetup$state_C <- TMP"); +// } enum ParseRet { PARSER_OK, PARSER_ERROR, PARSER_HELP }; @@ -222,7 +223,26 @@ ParseRet parseInitValues(char **argv, RuntimeParameters ¶ms) { return ParseRet::PARSER_OK; } -static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, +// HACK: this is a step back as the order and also the count of fields is +// predefined, but it will change in the future +void call_master_iter_end(RInside &R, const Field &trans, const Field &chem) { + R["TMP"] = Rcpp::wrap(trans.AsVector()); + R["TMP_PROPS"] = Rcpp::wrap(trans.GetProps()); + R.parseEval(std::string("state_T <- setNames(data.frame(matrix(TMP, nrow=" + + std::to_string(trans.GetRequestedVecSize()) + + ")), TMP_PROPS)")); + + R["TMP"] = Rcpp::wrap(chem.AsVector()); + R["TMP_PROPS"] = Rcpp::wrap(chem.GetProps()); + R.parseEval(std::string("state_C <- setNames(data.frame(matrix(TMP, nrow=" + + std::to_string(chem.GetRequestedVecSize()) + + ")), TMP_PROPS)")); + R["setup"] = *global_rt_setup; + R.parseEval("setup <- master_iteration_end(setup, state_T, state_C)"); + *global_rt_setup = R["setup"]; +} + +static Rcpp::List RunMasterLoop(RInsidePOET &R, const RuntimeParameters ¶ms, DiffusionModule &diffusion, ChemistryModule &chem) { @@ -263,13 +283,7 @@ static Rcpp::List RunMasterLoop(const RuntimeParameters ¶ms, // state_C after every iteration if the cmdline option // --ignore-results is not given (and thus the R variable // store_result is TRUE) - { - const auto &trans_field = diffusion.getField().asSEXP(); - const auto &chem_field = chem.getField().asSEXP(); - - *global_rt_setup = master_iteration_end_R.value()( - *global_rt_setup, trans_field, chem_field); - } + call_master_iter_end(R, diffusion.getField(), chem.getField()); diffusion.getField().update(chem.getField()); @@ -400,7 +414,7 @@ int main(int argc, char *argv[]) { chemistry.masterSetField(init_list.getInitialGrid()); - Rcpp::List profiling = RunMasterLoop(run_params, diffusion, chemistry); + Rcpp::List profiling = RunMasterLoop(R, run_params, diffusion, chemistry); MSG("finished simulation loop"); diff --git a/util/data_evaluation/jlFun_Eval.jl b/util/data_evaluation/jlFun_Eval.jl new file mode 100644 index 000000000..4c95d5ced --- /dev/null +++ b/util/data_evaluation/jlFun_Eval.jl @@ -0,0 +1,31 @@ +using RData, DataFrames, Plots + +# Load all .rds files in given directory +function load_data(directory) + files = readdir(directory) + # data is dictionary with iteration number as key + data = Dict{Int,Any}() + for file in files + if (endswith(file, ".rds") && startswith(file, "iter")) + # extract iteration number (iter_XXX.rds) + iter = parse(Int, split(split(file, "_")[2], ".")[1]) + data[iter] = load(joinpath(directory, file)) + end + end + return data +end + +function spec_to_mat(in_df::DataFrame, spec::Symbol, cols::Int) + specvec = in_df[!, spec] + specmat = transpose(reshape(specvec, cols, :)) + + return specmat +end + +function plot_field(data::AbstractMatrix, log::Bool=false) + if log + heatmap(1:size(data, 2), 1:size(data, 1), log10.(data), c=:viridis) + else + heatmap(1:size(data, 2), 1:size(data, 1), data, c=:viridis) + end +end \ No newline at end of file From 8bba4f31ea34745414d23af15b639343f91c0e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Mon, 6 May 2024 10:06:47 +0000 Subject: [PATCH 76/77] Add EGU debug model --- bench/surfex/CMakeLists.txt | 10 ++- bench/surfex/PoetEGU_surfex_500.R | 40 ++++++++++ bench/surfex/PoetEGU_surfex_500_rt.R | 11 +++ bench/surfex/SurfexEGU.pqi | 108 +++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 bench/surfex/PoetEGU_surfex_500.R create mode 100644 bench/surfex/PoetEGU_surfex_500_rt.R create mode 100644 bench/surfex/SurfexEGU.pqi diff --git a/bench/surfex/CMakeLists.txt b/bench/surfex/CMakeLists.txt index 09408e038..baf23bcb0 100644 --- a/bench/surfex/CMakeLists.txt +++ b/bench/surfex/CMakeLists.txt @@ -1,11 +1,13 @@ set(bench_files - surfex.R - ex.R + # surfex.R + # ex.R + PoetEGU_surfex_500.R ) set(runtime_files - surfex_rt.R - ex_rt.R + # surfex_rt.R + # ex_rt.R + PoetEGU_surfex_500_rt.R ) ADD_BENCH_TARGET( diff --git a/bench/surfex/PoetEGU_surfex_500.R b/bench/surfex/PoetEGU_surfex_500.R new file mode 100644 index 000000000..d6b32fd78 --- /dev/null +++ b/bench/surfex/PoetEGU_surfex_500.R @@ -0,0 +1,40 @@ +rows <- 500 +cols <- 200 + +grid_left <- matrix(1, nrow = rows, ncol = cols/2) +grid_rght <- matrix(2, nrow = rows, ncol = cols/2) +grid_def <- cbind(grid_left, grid_rght) + + +# Define grid configuration for POET model +grid_setup <- list( + pqc_in_file = "./SurfexEGU.pqi", + pqc_db_file = "./SMILE_2021_11_01_TH.dat", # Path to the database file for Phreeqc + grid_def = grid_def, # Definition of the grid, containing IDs according to the Phreeqc input script + grid_size = c(10, 4), # Size of the grid in meters + constant_cells = c() # IDs of cells with constant concentration +) + +bound_def <- list( + "type" = rep("constant", cols), + "sol_id" = rep(3, cols), + "cell" = seq(1, cols) +) + +diffusion_setup <- list( + boundaries = list( + "N" = bound_def + ), + alpha_x = matrix(runif(rows*cols))*1e-8, + alpha_y = matrix(runif(rows*cols))*1e-9## ,1e-10 +) + + +chemistry_setup <- list() + +# Define a setup list for simulation configuration +setup <- list( + Grid = grid_setup, # Parameters related to the grid structure + Diffusion = diffusion_setup, # Parameters related to the diffusion process + Chemistry = chemistry_setup # Parameters related to the chemistry process +) diff --git a/bench/surfex/PoetEGU_surfex_500_rt.R b/bench/surfex/PoetEGU_surfex_500_rt.R new file mode 100644 index 000000000..d91e17b3a --- /dev/null +++ b/bench/surfex/PoetEGU_surfex_500_rt.R @@ -0,0 +1,11 @@ +iterations <- 200 +dt <- 1000 + +out_save <- c(1, 2, seq(5, iterations, by=5)) +## out_save <- seq(1, iterations) + +list( + timesteps = rep(dt, iterations), + store_result = TRUE, + out_save = out_save +) diff --git a/bench/surfex/SurfexEGU.pqi b/bench/surfex/SurfexEGU.pqi new file mode 100644 index 000000000..a2b3342b2 --- /dev/null +++ b/bench/surfex/SurfexEGU.pqi @@ -0,0 +1,108 @@ +## Time-stamp: "Last modified 2024-04-12 10:59:59 delucia" +## KNOBS +## -logfile false +## -iterations 10000 +## -convergence_tolerance 1E-12 +## -step_size 2 +## -pe_step_size 2 + +SOLUTION 1 ## Porewater composition Opalinus Clay, WITHOUT radionuclides, AFTER EQUI_PHASES + pe -2.627 ## Eh = -227 mV, Value from Bossart & Thury (2008)-> PC borehole measurement 2003, Eh still decreasing + density 1.01583 ## kg/dm³ = g/cm³ + temp 13 ## mean temperature Mont Terri, Bossart & Thury (2008), calculations performed for 25°C + units mol/kgw + ## Mean composition + pH 7.064 + Na 2.763e-01 + Cl 3.228e-01 charge + S(6) 1.653e-02 as SO4 + Ca 2.173e-02 + Mg 1.740e-02 + K 1.902e-03 + Sr 4.520e-04 + Fe 1.435e-04 + U 2.247e-09 + +SURFACE 1 Opalinus Clay, clay minerals + ## calculated with rho_b=2.2903 kg/dm³, poro=0.1662 + ## 1 dm³ = 13.565641 kg_sed/kg_pw + -equil 1 ## equilibrate with solution 1 + -sites_units density ## set unit for binding site density to sites/nm2 + -donnan 4.9e-10 ## calculated after Wigger & Van Loon (2018) for ionic strength after equilibration with minerales for pCO2=2.2 log10 bar + + # surface density SSA (m2/g) mass (g/kgw) + Kln_aOH 1.155 11. 3798.4 ## Kaolinite 28 wt% (aluminol and silanol sites) + Kln_siOH 1.155 + Ill_sOH 0.05 100. 4205.35 ## Illite 31 wt% (weak und strong binding sites) + Ill_wOH 2.26 ## 2 % strong binding sites + Mll_sOH 0.05 100. 813.94 ## Montmorillonite = smektite = 6 wt% (weak und strong binding sites) + Mll_wOH 2.26 ## 2 % strong binding sites + +EXCHANGE 1 Exchanger, only illite+montmorillonite + ## Illite = 0.225 eq/kg_rock, Montmorillonit = 0.87 eq/kg_rock + -equil 1 ## equilibrate with solution 1 + Z 0.9462 ## = Illite + Y 0.70813 ## = Montmorillonite +END + +SOLUTION 2 ## Porewater composition Opalinus Clay, WITHOUT radionuclides, AFTER EQUI_PHASES + pe -2.627 ## Eh = -227 mV, Value from Bossart & Thury (2008)-> PC borehole measurement 2003, Eh still decreasing + density 1.01583 ## kg/dm³ = g/cm³ + temp 13 ## mean temperature Mont Terri, Bossart & Thury (2008), calculations performed for 25°C + units mol/kgw + ## Mean composition + pH 7.064 + Na 2.763e-01 + Cl 3.228e-01 charge + S(6) 1.653e-02 as SO4 + Ca 2.173e-02 + Mg 1.740e-02 + K 1.902e-03 + Sr 4.520e-04 + Fe 1.435e-04 + U 2.247e-09 + +SURFACE 2 Opalinus Clay, clay minerals + -equil 2 ## equilibrate with solution 2 + -sites_units density ## set unit for binding site density to + ## sites/nm2 + -donnan 4.9e-10 ## calculated after Wigger & Van Loon (2018) + ## for ionic strength after equilibration + ## with minerales for pCO2=2.2 log10 bar + + ## surface density SSA (m2/g) mass (g/kgw) + Kln_aOH 1.155 11. 2798.4 ## Kaolinite 28 wt% (aluminol and silanol sites) + Kln_siOH 1.155 + Ill_sOH 0.05 100. 1205.35 ## Illite 31 wt% (weak und strong binding sites) + Ill_wOH 2.26 ## 2 % strong binding sites + Mll_sOH 0.05 100. 113.94 ## Montmorillonite = smektite = 6 wt% (weak und strong binding sites) + Mll_wOH 2.26 ## 2 % strong binding sites + +EXCHANGE 2 Exchanger, only illite+montmorillonite + ## Illite = 0.225 eq/kg_rock, Montmorillonit = 0.87 eq/kg_rock + -equil 2 ## equilibrate with solution 1 + Z 0.5 ## = Illite + Y 0.2 ## = Montmorillonite +END + +SOLUTION 3 + pe -2.627 ## Eh = -227 mV, Value from Bossart & Thury (2008)-> PC borehole measurement 2003, Eh still decreasing + density 1.01583 ## kg/dm³ = g/cm³ + temp 13 ## mean temperature Mont Terri, Bossart & Thury (2008), calculations performed for 25°C + units mol/kgw + ## Mean composition + pH 7.064 + Na 3.763e-01 + Cl 4.228e-01 charge + S(6) 1.653e-02 as SO4 + Ca 2.173e-02 + Mg 1.740e-02 + K 1.902e-03 + Sr 4.520e-04 + Fe 1.435e-04 + U 1e-6 + C 1.991e-03 +END + +RUN_CELLS +END From 4a544d1be0936fba2244803d837564acf7c34d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Mon, 6 May 2024 09:09:24 +0000 Subject: [PATCH 77/77] Update Readme --- CMakeLists.txt | 5 -- README.md | 108 ++++++++++++++++++++++++------------------ docs/CMakeLists.txt | 1 - docs/Input_Scripts.md | 86 --------------------------------- docs/Output.md | 60 ++++++++++++++--------- 5 files changed, 101 insertions(+), 159 deletions(-) delete mode 100644 docs/Input_Scripts.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c17fb843..f2f4434bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,15 +15,10 @@ list(APPEND CMAKE_MODULE_PATH "${POET_SOURCE_DIR}/CMake") get_poet_version() -# set(GCC_CXX_FLAGS "-D STRICT_R_HEADERS") add_definitions(${GCC_CXX_FLAGS}) - find_package(MPI REQUIRED) find_package(RRuntime REQUIRED) -# add_compile_options(-fsanitize=address -fno-omit-frame-pointer) -# add_link_options(-fsanitize=address) - add_subdirectory(src) add_subdirectory(bench) diff --git a/README.md b/README.md index a273f7f10..e6535ed5f 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ pages](https://naaice.git-pages.gfz-potsdam.de/poet). The following external header library is shipped with POET: - **argh** - https://github.com/adishavit/argh (BSD license) -- **PhreeqcRM** with patches from GFZ - - https://www.usgs.gov/software/phreeqc-version-3 - - https://git.gfz-potsdam.de/mluebke/phreeqcrm-gfz -- **tug** - https://git.gfz-potsdam.de/sec34/tug +- **IPhreeqc** with patches from GFZ - + https://github.com/usgs-coupled/iphreeqc - + https://git.gfz-potsdam.de/naaice/iphreeqc +- **tug** - https://git.gfz-potsdam.de/naaice/tug ## Installation @@ -35,6 +35,7 @@ To compile POET you need several software to be installed: - MPI-Implementation (tested with OpenMPI and MVAPICH) - R language and environment - CMake 3.9+ +- Eigen3 3.4+ (required by `tug`) - *optional*: `doxygen` with `dot` bindings for documentiation The following R libraries must then be installed, which will get the @@ -107,58 +108,50 @@ The correspondending directory tree would look like this: ```sh poet ├── bin -│ └── poet -├── R_lib -│ └── kin_r_library.R +│   ├── poet +│   └── poet_init └── share └── poet - └── bench - ├── barite - │ ├── barite_interp_eval.R - │ ├── barite.pqi - │ ├── barite.R - │ └── db_barite.dat - ├── dolo - │ ├── dolo_diffu_inner_large.R - │ ├── dolo_diffu_inner.R - │ ├── dolo_inner.pqi - │ ├── dolo_interp_long.R - │ └── phreeqc_kin.dat - └── surfex - ├── ExBase.pqi - ├── ex.R - ├── SMILE_2021_11_01_TH.dat - ├── SurfExBase.pqi - └── surfex.R + ├── barite + │   ├── barite_200.rds + │   ├── barite_200_rt.R + │   ├── barite_het.rds + │   └── barite_het_rt.R + ├── dolo + │   ├── dolo_inner_large.rds + │   ├── dolo_inner_large_rt.R + │   ├── dolo_interp.rds + │   └── dolo_interp_rt.R + └── surfex + ├── PoetEGU_surfex_500.rds + └── PoetEGU_surfex_500_rt.R ``` -The R libraries will be loaded at runtime and the paths are hardcoded -absolute paths inside `poet.cpp`. So, if you consider to move -`bin/poet` either change paths of the R source files and recompile -POET or also move `R_lib/*` relative to the binary. +With the installation of POET, two executables are provided: + - `poet` - the main executable to run simulations + - `poet_init` - a preprocessor to generate input files for POET from R scripts -The benchmarks consist of input scripts, which are provided as .R files. -Additionally, Phreeqc scripts and their corresponding databases are required, -stored as .pqi and .dat files, respectively. +Preprocessed benchmarks can be found in the `share/poet` directory with an +according *runtime* setup. More on those files and how to create them later. ## Running -Run POET by `mpirun ./poet ` +Run POET by `mpirun ./poet [OPTIONS] ` where: -- **OPTIONS** - runtime parameters (explained below) -- **SIMFILE** - simulation described as R script (e.g. - `/share/poet/bench/dolo/dolo_interp_long.R`) +- **OPTIONS** - POET options (explained below) +- **RUNFILE** - Runtime parameters described as R script +- **SIMFILE** - Simulation input prepared by `poet_init` - **OUTPUT_DIRECTORY** - path, where all output of POET should be stored -### Runtime options +### POET options The following parameters can be set: | Option | Value | Description | |-----------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------| | **--work-package-size=** | _1..n_ | size of work packages (defaults to _5_) | -| **--ignore-result** | | disables store of simulation resuls | +| **-P, --progress** | | show progress bar | | **--dht** | | enabling DHT usage (defaults to _OFF_) | | **--dht-strategy=** | _0-1_ | change DHT strategy. **NOT IMPLEMENTED YET** (Defaults to _0_) | | **--dht-size=** | _1-n_ | size of DHT per process involved in megabyte (defaults to _1000 MByte_) | @@ -180,14 +173,16 @@ Following values can be set: ### Example: Running from scratch -We will continue the above example and start a simulation with -`dolo_diffu_inner.R`. As transport a simple fixed-coefficient diffusion is used. -It's a 2D, 100x100 grid, simulating 10 time steps. To start the simulation with -4 processes `cd` into your previously installed POET-dir -`/bin` and run: +We will continue the above example and start a simulation with *barite_het*, +which simulation files can be found in +`/share/poet/barite/barite_het*`. As transport a heterogeneous +diffusion is used. It's a small 2D grid, 2x5 grid, simulating 50 time steps with +a time step size of 100 seconds. To start the simulation with 4 processes `cd` +into your previously installed POET-dir `/bin` and run: ```sh -mpirun -n 4 ./poet ../share/poet/bench/dolo/dolo_diffu_inner.R/ output +cp ../share/poet/barite/barite_het* . +mpirun -n 4 ./poet barite_het_rt.R barite_het.rds output ``` After a finished simulation all data generated by POET will be found @@ -200,9 +195,32 @@ produced. This is done by appending the `--dht-snaps=` option. The resulting call would look like this: ```sh -mpirun -n 4 ./poet --dht --dht-snaps=2 ../share/poet/bench/dolo/dolo_diffu_inner.R/ output +mpirun -n 4 ./poet --dht --dht-snaps=2 barite_het_rt.R barite_het.rds output ``` +## Defining a model + +In order to provide a model to POET, you need to setup a R script which can then +be used by `poet_init` to generate the simulation input. Which parameters are +required can be found in the +[Wiki](https://git.gfz-potsdam.de/naaice/poet/-/wikis/Initialization). We try to +keep the document up-to-date. However, if you encounter missing information or +need help, please get in touch with us via the issue tracker or E-Mail. + +`poet_init` can be used as follows: + +```sh +./poet_init [-o, --output output_file] [-s, --setwd] +``` + +where: + +- **output** - name of the output file (defaults to the input file name + with the extension `.rds`) +- **setwd** - set the working directory to the directory of the input file (e.g. + to allow relative paths in the input script). However, the output file + will be stored in the directory from which `poet_init` was called. + ## About the usage of MPI_Wtime() Implemented time measurement functions uses `MPI_Wtime()`. Some diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 4781c2b87..fa9038767 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -14,7 +14,6 @@ if(DOXYGEN_FOUND) doxygen_add_docs(doxygen ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/README.md - ${PROJECT_SOURCE_DIR}/docs/Input_Scripts.md ${PROJECT_SOURCE_DIR}/docs/Output.md COMMENT "Generate html pages") endif() diff --git a/docs/Input_Scripts.md b/docs/Input_Scripts.md deleted file mode 100644 index 1c03de749..000000000 --- a/docs/Input_Scripts.md +++ /dev/null @@ -1,86 +0,0 @@ -# Input Scripts - -In the following the expected schemes of the input scripts is described. -Therefore, each section of the input script gets its own chapter. All sections -should return a `list` as results, which are concatenated to one setup list at -the end of the file. All values must have the same name in order to get parsed -by POET. - -## Grid initialization - -| name | type | description | -|----------------|----------------|-----------------------------------------------------------------------| -| `n_cells` | Numeric Vector | Number of cells in each direction | -| `s_cells` | Numeric Vector | Spatial resolution of grid in each direction | -| `type` | String | Type of initialization, can be set to *scratch*, *phreeqc* or *rds* | - -## Diffusion parameters - -| name | type | description | -|----------------|----------------------|-------------------------------------------| -| `init` | Named Numeric Vector | Initial state for each diffused species | -| `vecinj` | Data Frame | Defining all boundary conditions row wise | -| `vecinj_inner` | List of Triples | Inner boundaries | -| `vecinj_index` | List of 4 elements | Ghost nodes boundary conditions | -| `alpha` | Named Numeric Vector | Constant alpha for each species | - -### Remark on boundary conditions - -Each boundary condition should be defined in `vecinj` as a data frame, where one -row holds one boundary condition. - -To define inner (constant) boundary conditions, use a list of triples in -`vecinj_inner`, where each triples is defined by $(i,x,y)$. $i$ is defining the -boundary condition, referencing to the row in `vecinj`. $x$ and $y$ coordinates -then defining the position inside the grid. - -Ghost nodes are set by `vecinj_index` which is a list containing boundaries for -each celestial direction (**important**: named by `N, E, S, W`). Each direction -is a numeric vector, also representing a row index of the `vecinj` data frame -for each ghost node, starting at the left-most and upper cell respectively. By -setting the boundary condition to $0$, the ghost node is set as closed boundary. - -#### Example - -Suppose you have a `vecinj` data frame defining 2 boundary conditions and a grid -consisting of $10 \times 10$ grid cells. Grid cell $(1,1)$ should be set to the -first boundary condition and $(5,6)$ to the second. Also, all boundary -conditions for the ghost nodes should be closed. Except the southern boundary, -which should be set to the first boundary condition injection. The following -setup describes how to setup your initial script, where `n` and `m` are the -grids cell count for each direction ($n = m = 10$): - -```R -vecinj_inner <- list ( - l1 = c(1, 1, 1), - l2 = c(2, 5, 6) -) - -vecinj_index <- list( - "N" = rep(0, n), - "E" = rep(0, m), - "S" = rep(1, n), - "W" = rep(0, m) -) -``` - -## Chemistry parameters - -| name | type | description | -|----------------|--------------|----------------------------------------------------------------------------------| -| `database` | String | Path to the Phreeqc database | -| `input_script` | String | Path the the Phreeqc input script | -| `dht_species` | Named Vector | Indicates significant digits to use for each species for DHT rounding. | -| `pht_species` | Named Vector | Indicates significant digits to use for each species for Interpolation rounding. | - -## Final setup - -| name | type | description | -|----------------|----------------|------------------------------------------------------------| -| `grid` | List | Grid parameter list | -| `diffusion` | List | Diffusion parameter list | -| `chemistry` | List | Chemistry parameter list | -| `iterations` | Numeric Value | Count of iterations | -| `timesteps` | Numeric Vector | $\Delta t$ to use for specific iteration | -| `store_result` | Boolean | Indicates if results should be stored | -| `out_save` | Numeric Vector | *optional:* At which iteration the states should be stored | diff --git a/docs/Output.md b/docs/Output.md index 4044c84a6..82644d347 100644 --- a/docs/Output.md +++ b/docs/Output.md @@ -35,34 +35,50 @@ corresponding values can be found in `/timings.rds` and possible to read out within a R runtime with `readRDS("timings.rds")`. There you will find the following values: -| Value | Description | -|--------------------|----------------------------------------------------------------------------| -| simtime | time spent in whole simulation loop without any initialization and cleanup | -| simtime\_transport | measured time in *transport* subroutine | -| simtime\_chemistry | measured time in *chemistry* subroutine (actual parallelized part) | +| Value | Description | +| --------- | -------------------------------------------------------------------------- | +| simtime | time spent in whole simulation loop without any initialization and cleanup | +| chemistry | measured time in *chemistry* subroutine | +| diffusion | measured time in *diffusion* subroutine | -### chemistry subsetting +### Chemistry subsetting -If running parallel there are also measured timings which are subsets of -*simtime\_​chemistry*. +| Value | Description | +| ------------- | --------------------------------------------------------- | +| simtime | overall runtime of chemistry | +| loop | time spent in send/recv loop of master | +| sequential | sequential part of the master (e.g. shuffling field) | +| idle\_master | idling time of the master waiting for workers | +| idle\_worker | idling time (waiting for work from master) of the workers | +| phreeqc\_time | accumulated times for Phreeqc calls of every worker | -| Value | Description | -|-----------------------|-----------------------------------------------------------| -| chemistry\_loop | time spent in send/​recv loop of master | -| chemistry\_sequential | sequential part of master chemistry | -| idle\_master | idling time (waiting for any free worker) of the master | -| idle\_worker | idling time (waiting for work from master) of the workers | -| phreeqc\_time | accumulated times for Phreeqc calls of every worker | - -### DHT usage {#DHT-usage} +#### DHT usage If running in parallel and with activated DHT, two more timings and also some profiling about the DHT usage are given: | Value | Description | -|-----------------|---------------------------------------------------------| -| dht\_fill\_time | time to write data to DHT | -| dht\_get\_time | time to retreive data from DHT | -| dh\_hits | count of data points retrieved from DHT | -| dht\_miss | count of misses/count of data points written to DHT | +| --------------- | ------------------------------------------------------- | +| dht\_hits | count of data points retrieved from DHT | | dht\_evictions | count of data points evicted by another write operation | +| dht\_get\_time | time to retreive data from DHT | +| dht\_fill\_time | time to write data to DHT | + +#### Interpolation + +If using interpolation, the following values are given: + +| Value | Description | +| -------------- | --------------------------------------------------------------------- | +| interp\_w | time spent to write to PHT | +| interp\_r | time spent to read from DHT/PHT/Cache | +| interp\_g | time spent to gather results from DHT | +| interp\_fc | accumulated time spent in interpolation function call | +| interp\_calls | count of interpolations | +| interp\_cached | count of interpolation data sets, which where cached in the local map | + +### Diffusion subsetting + +| Value | Description | +| --------- | ------------------------------------------ | +| simtime | overall runtime of diffusion |