mirror of
https://git.gfz-potsdam.de/naaice/poet.git
synced 2025-12-15 20:38:23 +01:00
417 lines
14 KiB
C++
417 lines
14 KiB
C++
#include <tug/Boundary.hpp>
|
|
// leave above Rcpp includes, as eigen seem to have problems with a preceding
|
|
// Rcpp include
|
|
|
|
#include <map>
|
|
#include <set>
|
|
|
|
#include "DataStructures/Field.hpp"
|
|
#include "InitialList.hpp"
|
|
#include "PhreeqcMatrix.hpp"
|
|
|
|
#include <Rcpp/Function.h>
|
|
#include <Rcpp/proxy/ProtectedProxy.h>
|
|
#include <Rcpp/vector/instantiation.h>
|
|
#include <Rinternals.h>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace poet {
|
|
|
|
enum SEXP_TYPE { SEXP_IS_LIST, SEXP_IS_VEC };
|
|
|
|
const std::map<std::uint8_t, std::string> tug_side_mapping = {
|
|
{tug::BC_SIDE_RIGHT , "E"},
|
|
{tug::BC_SIDE_LEFT , "W"},
|
|
{tug::BC_SIDE_TOP , "N"},
|
|
{tug::BC_SIDE_BOTTOM, "S"}};
|
|
|
|
static std::vector<TugType> colMajToRowMaj(const Rcpp::NumericVector &vec,
|
|
std::uint32_t n_cols,
|
|
std::uint32_t n_rows) {
|
|
if (vec.size() == 1) {
|
|
return std::vector<TugType>(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<TugType> 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 std::vector<std::string>
|
|
// extend_transport_names(std::unique_ptr<PhreeqcInit> &phreeqc,
|
|
// const Rcpp::List &boundaries_list,
|
|
// const Rcpp::List &inner_boundaries,
|
|
// const std::vector<std::string> &old_trans_names) {
|
|
|
|
// std::vector<std::string> transport_names = old_trans_names;
|
|
// std::set<int> 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 (auto i = 0; i < cells.size(); i++) {
|
|
// if (type_str[i] == "constant") {
|
|
// constant_pqc_ids.insert(static_cast<std::size_t>(values[i]));
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// if (inner_boundaries.size() > 0) {
|
|
// const Rcpp::NumericVector values = inner_boundaries["sol_id"];
|
|
// for (auto i = 0; i < values.size(); i++) {
|
|
// constant_pqc_ids.insert(static_cast<std::size_t>(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);
|
|
|
|
// // 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()) {
|
|
// auto position =
|
|
// std::lower_bound(transport_names.begin() + keep_h_o_charge,
|
|
// transport_names.end(), name);
|
|
|
|
// transport_names.insert(position, name);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return transport_names;
|
|
// }
|
|
|
|
// static Rcpp::List
|
|
// extend_initial_grid(const Rcpp::List &initial_grid,
|
|
// const std::vector<std::string> &transport_names) {
|
|
// // std::vector<std::string> 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(transport_names));
|
|
// }
|
|
|
|
std::pair<Rcpp::List, Rcpp::List>
|
|
InitialList::resolveBoundaries(const Rcpp::List &boundaries_list,
|
|
const Rcpp::List &inner_boundaries,
|
|
const PhreeqcMatrix &phreeqc_mat) {
|
|
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, 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);
|
|
// }
|
|
|
|
for (const auto &species_name : 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::IntegerVector cells = mapping["cell"]; // MDL 2024-06-13
|
|
const Rcpp::IntegerVector values = mapping["sol_id"]; // MDL
|
|
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 (auto i = 0; i < cells.size(); i++) {
|
|
const auto c_id = cells[i] - 1;
|
|
if (type_str[i] == "closed") {
|
|
c_type[c_id] = tug::BC_TYPE_CLOSED;
|
|
} else if (type_str[i] == "constant") {
|
|
c_type[c_id] = tug::BC_TYPE_CONSTANT;
|
|
c_value[c_id] =
|
|
static_cast<TugType>(phreeqc_mat(values[i], species_name));
|
|
// c_value[c_id] = Rcpp::as<TugType>(
|
|
// resolve_R(this->phreeqc_mat, Rcpp::wrap(species_name),
|
|
// 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_name] = 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<std::uint32_t> rows;
|
|
std::vector<std::uint32_t> cols;
|
|
std::vector<TugType> 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(static_cast<TugType>(
|
|
phreeqc_mat(inner_pqc_id_vec[i], species_name)));
|
|
// c_value.push_back(Rcpp::as<TugType>(resolve_R(
|
|
// this->phreeqc_mat, Rcpp::wrap(species_name),
|
|
// inner_pqc_id_vec[i])));
|
|
}
|
|
|
|
inner_bound[species_name] =
|
|
Rcpp::List::create(Rcpp::Named("row") = Rcpp::wrap(rows),
|
|
Rcpp::Named("col") = Rcpp::wrap(cols),
|
|
Rcpp::Named("value") = Rcpp::wrap(c_value));
|
|
}
|
|
}
|
|
|
|
return std::make_pair(bound_list, inner_bound);
|
|
}
|
|
|
|
static inline SEXP_TYPE get_datatype(const SEXP &input) {
|
|
Rcpp::Function check_list("is.list");
|
|
|
|
if (Rcpp::as<bool>(check_list(input))) {
|
|
return SEXP_IS_LIST;
|
|
} else {
|
|
return SEXP_IS_VEC;
|
|
}
|
|
}
|
|
|
|
static Rcpp::List parseAlphas(const SEXP &input,
|
|
const std::vector<std::string> &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::NumericVector &alpha_col_order_vec = input_list[name];
|
|
|
|
out_list[name] =
|
|
Rcpp::wrap(colMajToRowMaj(alpha_col_order_vec, n_cols, n_rows));
|
|
}
|
|
break;
|
|
}
|
|
case SEXP_IS_VEC: {
|
|
const Rcpp::NumericVector alpha(input);
|
|
for (const auto &name : transport_names) {
|
|
out_list[name] = Rcpp::wrap(colMajToRowMaj(alpha, n_cols, n_rows));
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
throw std::runtime_error("Unknown data type");
|
|
}
|
|
|
|
return out_list;
|
|
}
|
|
void InitialList::initDiffusion(const Rcpp::List &diffusion_input,
|
|
const PhreeqcMatrix &phreeqc) {
|
|
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)];
|
|
|
|
const auto resolved_boundaries =
|
|
resolveBoundaries(boundaries, inner_boundaries, phreeqc);
|
|
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);
|
|
}
|
|
|
|
InitialList::DiffusionInit::BoundaryMap
|
|
RcppListToBoundaryMap(const std::vector<std::string> &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<TugType> 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 (static_cast<tug::BC_TYPE>(type[i]) == tug::BC_TYPE_CONSTANT) {
|
|
bc.setBoundaryElementConstant(static_cast<tug::BC_SIDE>(tug_index), i,
|
|
value[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
map[name] = bc.serialize();
|
|
}
|
|
|
|
return map;
|
|
}
|
|
static InitialList::DiffusionInit::InnerBoundaryMap
|
|
RcppListToInnerBoundaryMap(const std::vector<std::string> &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<std::pair<std::uint32_t, std::uint32_t>, 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;
|
|
|
|
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.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);
|
|
|
|
return diff_init;
|
|
}
|
|
|
|
} // namespace poet
|