11#include "libmesh/replicated_mesh.h"
12#include "libmesh/mesh_generation.h"
14#include "libmesh/parallel_algebra.h"
15#include "libmesh/parallel_sync.h"
28 "Names of variables we want to "
29 "extract from solution vectors.");
31 "The errors allowed in the snapshot reconstruction.");
33 "Names of tags for the reduced operators.");
34 params.
addParam<std::vector<std::string>>(
35 "filenames",
"Files where the eigenvalues are printed for each variable (if given).");
39 "List of keywords describing if the tags"
40 " correspond to independent operators or not. (op/op_dir/src/src_dir)");
46 _var_names(declareModelData<
std::vector<
std::string>>(
47 "_var_names", getParam<
std::vector<
std::string>>(
"var_names"))),
48 _error_res(getParam<
std::vector<Real>>(
"error_res")),
49 _tag_names(declareModelData<
std::vector<
std::string>>(
50 "_tag_names", getParam<
std::vector<
std::string>>(
"tag_names"))),
51 _tag_types(declareModelData<
std::vector<
std::string>>(
52 "_tag_types", getParam<
std::vector<
std::string>>(
"tag_types"))),
53 _base(declareModelData<
std::vector<
std::vector<DenseVector<Real>>>>(
"_base")),
54 _red_operators(declareModelData<
std::vector<DenseMatrix<Real>>>(
"_red_operators")),
55 _base_completed(false),
56 _empty_operators(true)
60 "The number of elements is not equal to the number"
61 " of elements in 'var_names'!");
65 "The number of elements is not equal to the number"
66 " of elements in 'tag_names'!");
68 std::vector<std::string> available_names{
"op",
"src",
"op_dir",
"src_dir"};
71 auto it = std::find(available_names.begin(), available_names.end(), tag_type);
72 if (it == available_names.end())
76 "' is not valid, available names are:",
77 " op, op_dir, src, src_dir");
127 for (
unsigned int tag_i = 0; tag_i <
_red_operators.size(); ++tag_i)
136 const std::shared_ptr<DenseVector<Real>> & snapshot)
138 _snapshots[var_i].addNewEntry(glob_i, snapshot);
150 for (
unsigned int var_i = 0; var_i <
_snapshots.size(); ++var_i)
151 _corr_mx[var_i] = DenseMatrix<Real>(no_snaps, no_snaps);
163 MeshTools::Generation::build_square(
164 mesh, no_snaps, no_snaps, -0.5, no_snaps - 0.5, -0.5, no_snaps - 0.5);
168 mesh.add_elem_integer(
"filled");
173 for (Elem * elem :
mesh.active_element_ptr_range())
175 const auto centroid = elem->vertex_average();
176 if (centroid(0) > centroid(1))
177 mesh.delete_elem(elem);
181 mesh.prepare_for_use();
189 std::unordered_map<unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>> local_vectors;
190 for (
unsigned int loc_vec_i = 0; loc_vec_i <
_snapshots[0].getNumberOfLocalEntries(); ++loc_vec_i)
192 const unsigned int glob_vec_i =
_snapshots[0].getGlobalIndex(loc_vec_i);
193 auto & entry = local_vectors[glob_vec_i];
195 for (
unsigned int v_ind = 0; v_ind <
_snapshots.size(); ++v_ind)
196 entry.push_back(
_snapshots[v_ind].getLocalEntry(loc_vec_i));
210 std::unordered_map<processor_id_type, std::set<unsigned int>> send_vectors;
213 std::vector<std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>>>
218 for (Elem * elem :
mesh.active_element_ptr_range())
223 const auto centroid = elem->vertex_average();
224 const unsigned int i = centroid(0);
225 const unsigned int j = centroid(1);
236 if (send_vectors[elem->processor_id()].count(i))
241 send_vectors[elem->processor_id()].insert(i);
242 for (
unsigned int v_ind = 0; v_ind <
_snapshots.size(); ++v_ind)
243 send_map[elem->processor_id()].emplace_back(
244 i, v_ind,
_snapshots[v_ind].getGlobalEntry(i));
249 if (send_vectors[elem->processor_id()].count(j))
254 send_vectors[elem->processor_id()].insert(j);
255 for (
unsigned int v_ind = 0; v_ind <
_snapshots.size(); ++v_ind)
256 send_map[elem->processor_id()].emplace_back(
257 j, v_ind,
_snapshots[v_ind].getGlobalEntry(j));
262 elem->set_extra_integer(0, 0);
266 std::unordered_map<unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>>
271 [
this, &
mesh, &received_vectors, &local_vectors](
272 processor_id_type pid,
274 std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>> & vectors)
277 Parallel::push_parallel_packed_range(
_communicator, send_map, (
void *)
nullptr, functor);
283 std::vector<std::tuple<
unsigned int,
unsigned int, std::shared_ptr<DenseVector<Real>>>>());
291 for (
unsigned int row_i = 1; row_i < corr_mx.m(); ++row_i)
292 for (
unsigned int col_i = 0; col_i < row_i; ++col_i)
293 corr_mx(row_i, col_i) = corr_mx(col_i, row_i);
298 ReplicatedMesh & mesh,
299 std::unordered_map<
unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>> &
301 std::unordered_map<
unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>> &
304 const std::vector<std::tuple<
unsigned int,
unsigned int, std::shared_ptr<DenseVector<Real>>>> &
307 for (
auto & tuple : vectors)
309 const auto glob_vec_i = std::get<0>(tuple);
310 const auto var_i = std::get<1>(tuple);
311 const auto & vector = std::get<2>(tuple);
314 std::vector<std::shared_ptr<DenseVector<Real>>> & entry = received_vectors[glob_vec_i];
321 entry[var_i] = vector;
326 for (Elem * elem :
mesh.active_local_element_ptr_range())
329 if (elem->get_extra_integer(0))
334 const unsigned int i = elem->vertex_average()(0);
335 const unsigned int j = elem->vertex_average()(1);
336 std::vector<std::shared_ptr<DenseVector<Real>>> * i_vec =
nullptr;
337 std::vector<std::shared_ptr<DenseVector<Real>>> * j_vec =
nullptr;
339 const auto find_i_local = local_vectors.find(i);
340 if (find_i_local != local_vectors.end())
341 i_vec = &find_i_local->second;
344 const auto find_i_received = received_vectors.find(i);
345 if (find_i_received != received_vectors.end())
347 i_vec = &find_i_received->second;
353 const auto find_j_local = local_vectors.find(j);
354 if (find_j_local != local_vectors.end())
355 j_vec = &find_j_local->second;
358 const auto find_j_received = received_vectors.find(j);
359 if (find_j_received != received_vectors.end())
361 j_vec = &find_j_received->second;
368 for (
unsigned int v_ind = 0; v_ind <
_snapshots.size(); ++v_ind)
369 _corr_mx[v_ind](i, j) = (*i_vec)[v_ind]->dot(*(*j_vec)[v_ind]);
372 elem->set_extra_integer(0, 1);
379 for (
unsigned int v_ind = 0; v_ind <
_corr_mx.size(); ++v_ind)
381 unsigned int no_snaps =
_corr_mx[v_ind].n();
385 DenseVector<Real> eigenvalues(no_snaps);
386 DenseMatrix<Real> eigenvectors(no_snaps, no_snaps);
389 DenseVector<Real> eigenvalues_imag(no_snaps);
392 _corr_mx[v_ind].evd_left(eigenvalues, eigenvalues_imag, eigenvectors);
396 std::vector<unsigned int> idx(eigenvalues.size());
397 std::iota(idx.begin(), idx.end(), 0);
398 std::vector<Real> &
v = eigenvalues.get_values();
402 idx.begin(), idx.end(), [&
v](
unsigned int i,
unsigned int j) { return v[i] > v[j]; });
406 std::stable_sort(
v.begin(),
v.end(), std::greater<Real>());
411 _eigenvectors[v_ind] = DenseMatrix<Real>(eigenvectors.m(), cutoff);
414 for (
unsigned int j = 0; j < cutoff; ++j)
430 Real sum = std::accumulate(inp_vec.begin(), inp_vec.end(), 0.0);
433 for (
unsigned int i = 0; i < inp_vec.size(); ++i)
435 part_sum += inp_vec[i];
436 if (part_sum / sum > 1 - error)
439 return (inp_vec.size());
446 for (
unsigned int var_i = 0; var_i <
_eigenvectors.size(); ++var_i)
449 unsigned int no_snaps =
_snapshots[var_i].getNumberOfLocalEntries();
451 _base[var_i].resize(no_bases);
455 for (
unsigned int base_i = 0; base_i < no_bases; ++base_i)
457 _base[var_i][base_i].resize(
_snapshots[var_i].getLocalEntry(0)->size());
459 for (
unsigned int loc_i = 0; loc_i < no_snaps; ++loc_i)
461 unsigned int glob_i =
_snapshots[var_i].getGlobalIndex(loc_i);
462 const DenseVector<Real> & snapshot = *
_snapshots[var_i].getLocalEntry(loc_i);
464 for (
unsigned int i = 0; i <
_base[var_i][base_i].size(); ++i)
490 for (
unsigned int tag_i = 0; tag_i <
_red_operators.size(); ++tag_i)
502 std::vector<DenseVector<Real>> & residual)
507 unsigned int counter = 0;
508 for (
unsigned int var_i = 0; var_i <
_var_names.size(); ++var_i)
510 for (
unsigned int base_j = 0; base_j <
_base[var_i].size(); ++base_j)
523 return _snapshots[var_i].getNumberOfGlobalEntries();
529 unsigned int sum = 0;
531 for (
unsigned int i = 0; i <
_base.size(); ++i)
532 sum +=
_base[i].size();
537const DenseVector<Real> &
540 return _base[var_i][base_i];
543const DenseVector<Real> &
546 unsigned int counter = 0;
548 for (
unsigned int var_i = 0; var_i <
_var_names.size(); ++var_i)
549 for (
unsigned int base_i = 0; base_i <
_base[var_i].size(); ++base_i)
551 if (glob_i == counter)
552 return _base[var_i][base_i];
557 mooseError(
"The basis vector with global index ", glob_i,
"is not available!");
564 unsigned int counter = 0;
566 for (
unsigned int var_i = 0; var_i <
_var_names.size(); ++var_i)
567 for (
unsigned int base_i = 0; base_i <
_base[var_i].size(); ++base_i)
569 if (glob_i == counter)
575 mooseError(
"Variable with global base index ", glob_i,
"is not available!");
584 std::vector<std::string> filenames = getParam<std::vector<std::string>>(
"filenames");
588 "The number of file names is not equal to the number of variable names!");
590 for (
unsigned int var_i = 0; var_i <
_var_names.size(); ++var_i)
593 fb.open(filenames[var_i], std::ios::out);
594 std::ostream os(&fb);
595 os <<
"evs" << std::endl;
registerMooseObject("StochasticToolsApp", PODReducedBasisTrainer)
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
bool isParamValid(const std::string &name) const
void computeCorrelationMatrix()
Computes the correlation matrices using the snapshots.
unsigned int getSnapsSize(unsigned int var_i) const
Getting the snapshot size across all of the processors for a given variable with index var_i.
virtual void initialSetup() override
void receiveObjects(ReplicatedMesh &mesh, std::unordered_map< unsigned int, std::vector< std::shared_ptr< DenseVector< Real > > > > &received_vectors, std::unordered_map< unsigned int, std::vector< std::shared_ptr< DenseVector< Real > > > > &local_vectors, processor_id_type, const std::vector< std::tuple< unsigned int, unsigned int, std::shared_ptr< DenseVector< Real > > > > &vectors)
Function that manipulates the received objects and computes the correlation matrices on the fly.
unsigned int getSumBaseSize() const
Getting the overall base size, which is the sum of the individual bases.
virtual void finalize() override
std::vector< DenseMatrix< Real > > _eigenvectors
The eigenvectors of the correalation matrix for each variable.
unsigned int determineNumberOfModes(Real error, const std::vector< Real > &inp_vec) const
Computes the number of bases necessary for a given error indicator.
void printEigenvalues()
Prints the eigenvalues of the correlation matrix for each variable.
void computeBasisVectors()
Generates the basis vectors using the snapshots together with the eigen-decomposition of the correlat...
std::vector< DistributedSnapshots > _snapshots
Distributed container for snapshots per variable.
void computeEigenDecomposition()
Computes the eigen-decomposition of the stored correlation matrices.
void initReducedOperators()
Initializing the reduced operators.
std::vector< DenseVector< Real > > _eigenvalues
The eigenvalues of the correalation matrix for each variable.
std::vector< std::string > & _tag_names
Names of the tags that should be used to fetch residuals from the MultiApp.
bool _empty_operators
Flag describing if the reduced operators are empty or not.
PODReducedBasisTrainer(const InputParameters ¶meters)
bool _base_completed
Switch that tells if the object has already computed the necessary basis vectors.
std::vector< std::string > & _tag_types
list of bools describing which tag is indepedent of the solution.
void addSnapshot(unsigned int var_i, unsigned int glob_i, const std::shared_ptr< DenseVector< Real > > &snapshot)
Adding a snapshot for a variable.
std::vector< std::vector< DenseVector< Real > > > & _base
The reduced basis for the variables.
std::vector< DenseMatrix< Real > > _corr_mx
The correlation matrices for the variables.
static InputParameters validParams()
virtual void execute() override
const DenseVector< Real > & getBasisVector(unsigned int var_i, unsigned int base_i) const
Getting a basis vector for a given variable.
std::vector< std::string > & _var_names
Vector containing the names of the variables we want to use for constructing the surrogates.
void addToReducedOperator(unsigned int base_i, unsigned int tag_i, std::vector< DenseVector< Real > > &residual)
Adding the contribution of a residual to the reduced operators.
std::vector< Real > _error_res
Energy limits that define how many basis functions will be kept for each variable.
std::vector< DenseMatrix< Real > > & _red_operators
The reduced operators that should be transferred to the surrogate.
unsigned int getVariableIndex(unsigned int glob_i) const
Getting appropriate variable index for a global base index.
This is the base trainer class whose main functionality is the API for declaring model data.
static InputParameters validParams()
const Parallel::Communicator & _communicator
processor_id_type processor_id() const