mirror of
https://git.gfz-potsdam.de/naaice/poet.git
synced 2025-12-16 12:54:50 +01:00
325 lines
9.4 KiB
C++
325 lines
9.4 KiB
C++
#include "ChemistryModule.hpp"
|
|
|
|
#include "PhreeqcEngine.hpp"
|
|
#include "PhreeqcMatrix.hpp"
|
|
#include "PhreeqcRunner.hpp"
|
|
#include "SurrogateModels/DHT_Wrapper.hpp"
|
|
#include "SurrogateModels/Interpolation.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <mpi.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
std::vector<double>
|
|
inverseDistanceWeighting(const std::vector<std::int32_t> &to_calc,
|
|
const std::vector<double> &from,
|
|
const std::vector<std::vector<double>> &input,
|
|
const std::vector<std::vector<double>> &output) {
|
|
std::vector<double> results = from;
|
|
|
|
// 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 (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 (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];
|
|
}
|
|
|
|
rescaled[key_comp_i][data_set_n] = from[output_comp_i];
|
|
|
|
const double min = *std::min_element(rescaled[key_comp_i],
|
|
rescaled[key_comp_i] + data_set_n + 1);
|
|
const double max = *std::max_element(rescaled[key_comp_i],
|
|
rescaled[key_comp_i] + data_set_n + 1);
|
|
|
|
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)
|
|
: 0);
|
|
}
|
|
rescaled[key_comp_i][data_set_n] =
|
|
((max - min) != 0 ? (from[output_comp_i] - min) / (max - min) : 0);
|
|
}
|
|
|
|
// calculate distances for each data set
|
|
double inv_sum = 0;
|
|
for (std::uint32_t point_i = 0; point_i < data_set_n; point_i++) {
|
|
double distance = 0;
|
|
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);
|
|
}
|
|
|
|
weights[point_i] = distance != 0 ? 1 / std::sqrt(distance) : 0;
|
|
assert(!std::isnan(weights[point_i]));
|
|
inv_sum += weights[point_i];
|
|
}
|
|
|
|
assert(!std::isnan(inv_sum));
|
|
|
|
// actual interpolation
|
|
// bool has_h = false;
|
|
// bool has_o = false;
|
|
|
|
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;
|
|
|
|
// if (interp_i == 0) {
|
|
// has_h = true;
|
|
// }
|
|
|
|
// if (interp_i == 1) {
|
|
// has_o = true;
|
|
// }
|
|
|
|
for (std::uint32_t j = 0; j < data_set_n; j++) {
|
|
key_delta += weights[j] * output[j][output_comp_i];
|
|
}
|
|
|
|
key_delta /= inv_sum;
|
|
|
|
results[output_comp_i] = from[output_comp_i] + key_delta;
|
|
assert(!std::isnan(results[output_comp_i]));
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
poet::ChemistryModule::ChemistryModule(
|
|
uint32_t wp_size_, const InitialList::ChemistryInit chem_params,
|
|
MPI_Comm communicator)
|
|
: group_comm(communicator), wp_size(wp_size_), params(chem_params) {
|
|
MPI_Comm_rank(communicator, &comm_rank);
|
|
MPI_Comm_size(communicator, &comm_size);
|
|
|
|
this->is_sequential = comm_size == 1;
|
|
this->is_master = comm_rank == 0;
|
|
|
|
this->n_cells = chem_params.total_grid_cells;
|
|
|
|
if (!is_master) {
|
|
PhreeqcMatrix pqc_mat =
|
|
PhreeqcMatrix(chem_params.database, chem_params.pqc_script,
|
|
chem_params.with_h0_o0, chem_params.with_redox);
|
|
|
|
this->pqc_runner =
|
|
std::make_unique<PhreeqcRunner>(pqc_mat.subset(chem_params.pqc_ids));
|
|
}
|
|
}
|
|
|
|
poet::ChemistryModule::~ChemistryModule() {
|
|
if (dht) {
|
|
delete dht;
|
|
}
|
|
}
|
|
|
|
void poet::ChemistryModule::initializeDHT(
|
|
uint32_t size_mb, const NamedVector<std::uint32_t> &key_species,
|
|
bool has_het_ids) {
|
|
constexpr uint32_t MB_FACTOR = 1E6;
|
|
|
|
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, 1, this->comm_rank, &dht_comm);
|
|
|
|
auto map_copy = key_species;
|
|
|
|
if (key_species.empty()) {
|
|
std::vector<std::uint32_t> default_signif(
|
|
this->prop_count, DHT_Wrapper::DHT_KEY_SIGNIF_DEFAULT);
|
|
map_copy = NamedVector<std::uint32_t>(this->prop_names, default_signif);
|
|
}
|
|
|
|
auto key_indices = parseDHTSpeciesVec(key_species, this->prop_names);
|
|
|
|
if (this->dht) {
|
|
delete this->dht;
|
|
}
|
|
|
|
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, interp_enabled, has_het_ids);
|
|
this->dht->setBaseTotals(base_totals.at(0), base_totals.at(1));
|
|
}
|
|
}
|
|
|
|
inline std::vector<std::int32_t> poet::ChemistryModule::parseDHTSpeciesVec(
|
|
const NamedVector<std::uint32_t> &key_species,
|
|
const std::vector<std::string> &to_compare) const {
|
|
std::vector<int32_t> 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()) {
|
|
species_indices.push_back(DHT_Wrapper::DHT_KEY_INPUT_CUSTOM);
|
|
continue;
|
|
}
|
|
const std::uint32_t index = it - to_compare.begin();
|
|
species_indices.push_back(index);
|
|
}
|
|
|
|
return species_indices;
|
|
}
|
|
|
|
void poet::ChemistryModule::BCastStringVec(std::vector<std::string> &io) {
|
|
|
|
if (this->is_master) {
|
|
int vec_size = io.size();
|
|
ChemBCast(&vec_size, 1, MPI_INT);
|
|
|
|
for (const auto &value : io) {
|
|
int buf_size = value.size() + 1;
|
|
ChemBCast(&buf_size, 1, MPI_INT);
|
|
ChemBCast(const_cast<char *>(value.c_str()), buf_size, MPI_CHAR);
|
|
}
|
|
} else {
|
|
int vec_size;
|
|
ChemBCast(&vec_size, 1, MPI_INT);
|
|
|
|
io.resize(vec_size);
|
|
|
|
for (int i = 0; i < vec_size; i++) {
|
|
int buf_size;
|
|
ChemBCast(&buf_size, 1, MPI_INT);
|
|
char buf[buf_size];
|
|
ChemBCast(buf, buf_size, MPI_CHAR);
|
|
io[i] = std::string{buf};
|
|
}
|
|
}
|
|
}
|
|
|
|
void poet::ChemistryModule::setDHTSnapshots(int type,
|
|
const std::string &out_dir) {
|
|
if (this->is_master) {
|
|
return;
|
|
}
|
|
|
|
this->dht_file_out_dir = out_dir;
|
|
this->dht_snaps_type = type;
|
|
}
|
|
|
|
void poet::ChemistryModule::setDHTReadFile(const std::string &input_file) {
|
|
if (this->is_master) {
|
|
return;
|
|
}
|
|
|
|
if (!input_file.empty()) {
|
|
WorkerReadDHTDump(input_file);
|
|
}
|
|
}
|
|
|
|
void poet::ChemistryModule::initializeInterp(
|
|
std::uint32_t bucket_size, std::uint32_t size_mb, std::uint32_t min_entries,
|
|
const NamedVector<std::uint32_t> &key_species) {
|
|
|
|
if (!this->is_master) {
|
|
|
|
constexpr uint32_t MB_FACTOR = 1E6;
|
|
|
|
assert(this->dht);
|
|
|
|
this->interp_enabled = true;
|
|
|
|
auto map_copy = key_species;
|
|
|
|
if (key_species.empty()) {
|
|
map_copy = this->dht->getKeySpecies();
|
|
for (auto i = 0; i < map_copy.size(); i++) {
|
|
const std::uint32_t signif =
|
|
static_cast<std::uint32_t>(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());
|
|
|
|
if (this->interp) {
|
|
this->interp.reset();
|
|
}
|
|
|
|
const uint64_t pht_size = size_mb * MB_FACTOR;
|
|
|
|
interp = std::make_unique<poet::InterpolationModule>(
|
|
bucket_size, pht_size, min_entries, *(this->dht), map_copy, key_indices,
|
|
this->prop_names, this->params.hooks);
|
|
|
|
interp->setInterpolationFunction(inverseDistanceWeighting);
|
|
}
|
|
}
|
|
|
|
std::vector<double>
|
|
poet::ChemistryModule::shuffleField(const std::vector<double> &in_field,
|
|
uint32_t size_per_prop, uint32_t prop_count,
|
|
uint32_t wp_count) {
|
|
std::vector<double> out_buffer(in_field.size());
|
|
uint32_t write_i = 0;
|
|
for (uint32_t i = 0; i < wp_count; i++) {
|
|
for (uint32_t j = i; j < size_per_prop; j += wp_count) {
|
|
for (uint32_t k = 0; k < prop_count; k++) {
|
|
out_buffer[(write_i * prop_count) + k] =
|
|
in_field[(k * size_per_prop) + j];
|
|
}
|
|
write_i++;
|
|
}
|
|
}
|
|
return out_buffer;
|
|
}
|
|
|
|
void poet::ChemistryModule::unshuffleField(const std::vector<double> &in_buffer,
|
|
uint32_t size_per_prop,
|
|
uint32_t prop_count,
|
|
uint32_t wp_count,
|
|
std::vector<double> &out_field) {
|
|
uint32_t read_i = 0;
|
|
|
|
for (uint32_t i = 0; i < wp_count; i++) {
|
|
for (uint32_t j = i; j < size_per_prop; j += wp_count) {
|
|
for (uint32_t k = 0; k < prop_count; k++) {
|
|
out_field[(k * size_per_prop) + j] =
|
|
in_buffer[(read_i * prop_count) + k];
|
|
}
|
|
read_i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void poet::ChemistryModule::set_ai_surrogate_validity_vector(
|
|
std::vector<int> r_vector) {
|
|
this->ai_surrogate_validity_vector = r_vector;
|
|
}
|