https://mooseframework.inl.gov
PODReducedBasisTrainer.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PODReducedBasisTrainer.h"
11 #include "libmesh/replicated_mesh.h"
12 #include "libmesh/mesh_generation.h"
13 #include "SerializerGuard.h"
14 #include "libmesh/parallel_algebra.h"
15 #include "libmesh/parallel_sync.h"
16 #include "VectorPacker.h"
17 
18 registerMooseObject("StochasticToolsApp", PODReducedBasisTrainer);
19 
22 {
24 
25  params.addClassDescription("Computes the reduced subspace plus the reduced operators for "
26  "POD-RB surrogate.");
27  params.addRequiredParam<std::vector<std::string>>("var_names",
28  "Names of variables we want to "
29  "extract from solution vectors.");
30  params.addRequiredParam<std::vector<Real>>("error_res",
31  "The errors allowed in the snapshot reconstruction.");
32  params.addRequiredParam<std::vector<std::string>>("tag_names",
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).");
36 
37  params.addRequiredParam<std::vector<std::string>>(
38  "tag_types",
39  "List of keywords describing if the tags"
40  " correspond to independent operators or not. (op/op_dir/src/src_dir)");
41  return params;
42 }
43 
45  : SurrogateTrainerBase(parameters),
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)
57 {
58  if (_error_res.size() != _var_names.size())
59  paramError("error_res",
60  "The number of elements is not equal to the number"
61  " of elements in 'var_names'!");
62 
63  if (_tag_names.size() != _tag_types.size())
64  paramError("tag_types",
65  "The number of elements is not equal to the number"
66  " of elements in 'tag_names'!");
67 
68  std::vector<std::string> available_names{"op", "src", "op_dir", "src_dir"};
69  for (auto tag_type : _tag_types)
70  {
71  auto it = std::find(available_names.begin(), available_names.end(), tag_type);
72  if (it == available_names.end())
73  paramError("tag_types",
74  "Tag type '",
75  tag_type,
76  "' is not valid, available names are:",
77  " op, op_dir, src, src_dir");
78  }
79 }
80 
81 void
83 {
84  // Initializing the containers for the essential data to construct the
85  // reduced operators.
86 
87  _snapshots.clear();
89 
90  _base.clear();
91  _base.resize(_var_names.size());
92 
93  _corr_mx.clear();
94  _corr_mx.resize(_var_names.size());
95 
96  _eigenvalues.clear();
97  _eigenvalues.resize(_var_names.size());
98 
99  _eigenvectors.clear();
100  _eigenvectors.resize(_var_names.size());
101 }
102 
103 void
105 {
106  // If the base is not ready yet, create it by performing the POD on the
107  // snapshot matrices. Also, initialize the containers for the reduced
108  // operators.
109  if (!_base_completed)
110  {
115  _base_completed = true;
116  _empty_operators = true;
117  }
118 }
119 
120 void
122 {
123  // If the operators are already filled on each processor, gather and sum them
124  // together. This way every processor has access to every complete reduced
125  // operator.
126  if (!_empty_operators)
127  for (unsigned int tag_i = 0; tag_i < _red_operators.size(); ++tag_i)
128  {
129  gatherSum(_red_operators[tag_i].get_values());
130  }
131 }
132 
133 void
135  unsigned int glob_i,
136  const std::shared_ptr<DenseVector<Real>> & snapshot)
137 {
138  _snapshots[var_i].addNewEntry(glob_i, snapshot);
139 }
140 
141 void
143 {
144  // Getting the number of snapshots. It is assumed that every variable has the
145  // same number of snapshots. This assumption is used at multiple locations in
146  // this source file.
147  const auto no_snaps = getSnapsSize(0);
148 
149  // Initializing the correlation matrices for each variable.
150  for (unsigned int var_i = 0; var_i < _snapshots.size(); ++var_i)
151  _corr_mx[var_i] = DenseMatrix<Real>(no_snaps, no_snaps);
152 
153  /*
154  Creating a simple 2D map that distributes the elements in the correlation
155  matrices to each processor. A square mesh with elements corresponding to
156  the entries in the correlation matrix is used, since optimal partitioning
157  routines are already implemented for it. In this case, the centroids of the
158  elements are equivalent to the indices of the correlation matrix. This method
159  may seem too convoluted, but is necessary to ensure that the communication
160  stays balanced and scales well for runs with a large number of processors.
161  */
162  ReplicatedMesh mesh(_communicator, 2);
163  MeshTools::Generation::build_square(
164  mesh, no_snaps, no_snaps, -0.5, no_snaps - 0.5, -0.5, no_snaps - 0.5);
165 
166  // A flag is added to each element saying if the result has already been compuuted
167  // or not.
168  mesh.add_elem_integer("filled");
169 
170  // Since the correlation matrix is symmetric, it is enough to compute the
171  // entries on the diagonal in addition to the elements above the diagonal.
172  // Therefore, the elements in the mesh below the diagonal are deleted.
173  for (Elem * elem : mesh.active_element_ptr_range())
174  {
175  const auto centroid = elem->vertex_average();
176  if (centroid(0) > centroid(1))
177  mesh.delete_elem(elem);
178  }
179 
180  // The mesh is distributed among the processors.
181  mesh.prepare_for_use();
182 
183  /*
184  This step restructures the snapshots into an unordered map to make it easier
185  to do cross-products in the later stages. Since _snapshots only contains
186  pointers to the data, this should not include a considerable amount of copy
187  operations.
188  */
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)
191  {
192  const unsigned int glob_vec_i = _snapshots[0].getGlobalIndex(loc_vec_i);
193  auto & entry = local_vectors[glob_vec_i];
194 
195  for (unsigned int v_ind = 0; v_ind < _snapshots.size(); ++v_ind)
196  entry.push_back(_snapshots[v_ind].getLocalEntry(loc_vec_i));
197  }
198 
199  /*
200  Initializing containers for the objects that will be sent to other processors.
201  send_vectors is just a temporary object that ensures that the same snapshot is
202  sent to other processors only once. send_map, on the other hand, will be used
203  by the communicator and contains the required snapshots for each processor
204  which is not the the current rank.
205  std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>> type
206  is a container that uses (global snapshot index, variable index, snapshot) to
207  identify and send/receive snapshots during the communication.
208  */
209 
210  std::unordered_map<processor_id_type, std::set<unsigned int>> send_vectors;
211  std::unordered_map<
213  std::vector<std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>>>
214  send_map;
215 
216  // Fill the send map with snapshots we need to send for each processor. First,
217  // we loop over the matrix entries (elements in the mesh)
218  for (Elem * elem : mesh.active_element_ptr_range())
219  if (elem->processor_id() != processor_id())
220  {
221  // The centroids in the mesh correspond to the 2D corrdinates of the elements
222  // in the mesh.
223  const auto centroid = elem->vertex_average();
224  const unsigned int i = centroid(0);
225  const unsigned int j = centroid(1);
226 
227  /*
228  Checking if the current processor has the required snapshot.
229  We assume that every variable has the same number of snapshots with the
230  same distribution among processors. Therefore, it is enough to test
231  the first variable only.
232  */
233  if (_snapshots[0].hasGlobalEntry(i))
234  {
235  // Continue loop if the snapshot is already being sent.
236  if (send_vectors[elem->processor_id()].count(i))
237  continue;
238 
239  // Add another entry to the map if another processor needs the owned
240  // snapshot.
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));
245  }
246  else if (_snapshots[0].hasGlobalEntry(j))
247  {
248  // Continue loop if the snapshot is already being sent.
249  if (send_vectors[elem->processor_id()].count(j))
250  continue;
251 
252  // Add another entry to the map if another processor needs the owned
253  // snapshot.
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));
258  }
259  }
260  else
261  // Initializing the flag value with 0 (not computed) for each element.
262  elem->set_extra_integer(0, 0);
263 
264  // Creating container for received data. In this case the map contains the snapshots
265  // for each variable for each required global snapshot index.
266  std::unordered_map<unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>>
267  received_vectors;
268 
269  // Converting function to functor to be able to pass to push packed range.
270  auto functor =
271  [this, &mesh, &received_vectors, &local_vectors](
272  processor_id_type pid,
273  const std::vector<
274  std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>> & vectors)
275  { PODReducedBasisTrainer::receiveObjects(mesh, received_vectors, local_vectors, pid, vectors); };
276 
277  Parallel::push_parallel_packed_range(_communicator, send_map, (void *)nullptr, functor);
278 
279  // This extra call is necessary in case a processor has all the elements it needs
280  // (hence doesn't receive any).
281  functor(
282  processor_id(),
283  std::vector<std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>>());
284 
285  // Now, the correlation matrices aregathered and summed to make sure every processor
286  // sees them.
287  gatherSum(_corr_mx[0].get_values());
288 
289  // The lower triangle of the matrices are then filled using symmetry.
290  for (auto & corr_mx : _corr_mx)
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);
294 }
295 
296 void
298  ReplicatedMesh & mesh,
299  std::unordered_map<unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>> &
300  received_vectors,
301  std::unordered_map<unsigned int, std::vector<std::shared_ptr<DenseVector<Real>>>> &
302  local_vectors,
303  processor_id_type /*pid*/,
304  const std::vector<std::tuple<unsigned int, unsigned int, std::shared_ptr<DenseVector<Real>>>> &
305  vectors)
306 {
307  for (auto & tuple : vectors)
308  {
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);
312 
313  // The entry that will be filled with all of the variable solutions for a vector
314  std::vector<std::shared_ptr<DenseVector<Real>>> & entry = received_vectors[glob_vec_i];
315 
316  // Size it to the number of variables in case we haven't already
317  entry.resize(_snapshots.size(), nullptr);
318 
319  // Add this varaible's contribution - this is shared_ptr so we are claiming partial
320  // ownership of this vector and do not have to do a copy
321  entry[var_i] = vector;
322  }
323 
324  // Looping over the locally owned entries in the matrix and computing the
325  // values.
326  for (Elem * elem : mesh.active_local_element_ptr_range())
327  {
328  // If the matrix entry is already filled, the loop skips this element.
329  if (elem->get_extra_integer(0))
330  continue;
331 
332  // Getting pointers to the necessary snapshots for the matrix entry.
333  // This points to a vector of size (number of variables).
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;
338 
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;
342  else
343  {
344  const auto find_i_received = received_vectors.find(i);
345  if (find_i_received != received_vectors.end())
346  {
347  i_vec = &find_i_received->second;
348  }
349  else
350  continue;
351  }
352 
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;
356  else
357  {
358  const auto find_j_received = received_vectors.find(j);
359  if (find_j_received != received_vectors.end())
360  {
361  j_vec = &find_j_received->second;
362  }
363  else
364  continue;
365  }
366 
367  // Coputing the available matrix entries for every variable.
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]);
370 
371  // Set the 'filled' flag to 1 (true) to make sure it is not recomputed.
372  elem->set_extra_integer(0, 1);
373  }
374 }
375 
376 void
378 {
379  for (unsigned int v_ind = 0; v_ind < _corr_mx.size(); ++v_ind)
380  {
381  unsigned int no_snaps = _corr_mx[v_ind].n();
382 
383  // Initializing temporary objects for the eigenvalues and eigenvectors since
384  // evd_left() returns an unordered vector of eigenvalues.
385  DenseVector<Real> eigenvalues(no_snaps);
386  DenseMatrix<Real> eigenvectors(no_snaps, no_snaps);
387 
388  // Creating a temporary placeholder for the imaginary parts of the eigenvalues
389  DenseVector<Real> eigenvalues_imag(no_snaps);
390 
391  // Performing the eigenvalue decomposition
392  _corr_mx[v_ind].evd_left(eigenvalues, eigenvalues_imag, eigenvectors);
393 
394  // Sorting the eigenvectors and eigenvalues based on the magnitude of
395  // the eigenvalues
396  std::vector<unsigned int> idx(eigenvalues.size());
397  std::iota(idx.begin(), idx.end(), 0);
398  std::vector<Real> & v = eigenvalues.get_values();
399 
400  // Getting the indices to be able to copy the corresponding eigenvector too.
401  std::stable_sort(
402  idx.begin(), idx.end(), [&v](unsigned int i, unsigned int j) { return v[i] > v[j]; });
403 
404  // Getting a cutoff for the number of modes. The function requires a sorted list,
405  // thus the temporary vector is sorted.
406  std::stable_sort(v.begin(), v.end(), std::greater<Real>());
407  unsigned int cutoff = determineNumberOfModes(_error_res[v_ind], v);
408 
409  // Initializing the actual containers for the eigenvectors and eigenvalues.
410  _eigenvalues[v_ind] = DenseVector<Real>(cutoff);
411  _eigenvectors[v_ind] = DenseMatrix<Real>(eigenvectors.m(), cutoff);
412 
413  // Copying the kept eigenvalues and eigenvectors in a sorted container.
414  for (unsigned int j = 0; j < cutoff; ++j)
415  {
416  _eigenvalues[v_ind](j) = eigenvalues(j);
417  for (unsigned int k = 0; k < _eigenvectors[v_ind].m(); ++k)
418  {
419  _eigenvectors[v_ind](k, j) = eigenvectors(k, idx[j]);
420  }
421  }
422 
424  }
425 }
426 
427 unsigned int
428 PODReducedBasisTrainer::determineNumberOfModes(Real error, const std::vector<Real> & inp_vec) const
429 {
430  Real sum = std::accumulate(inp_vec.begin(), inp_vec.end(), 0.0);
431 
432  Real part_sum = 0.0;
433  for (unsigned int i = 0; i < inp_vec.size(); ++i)
434  {
435  part_sum += inp_vec[i];
436  if (part_sum / sum > 1 - error)
437  return (i + 1);
438  }
439  return (inp_vec.size());
440 }
441 
442 void
444 {
445  // Looping over all the variables.
446  for (unsigned int var_i = 0; var_i < _eigenvectors.size(); ++var_i)
447  {
448  unsigned int no_bases = _eigenvalues[var_i].size();
449  unsigned int no_snaps = _snapshots[var_i].getNumberOfLocalEntries();
450 
451  _base[var_i].resize(no_bases);
452 
453  // Filling the containers using the local snapshots and the eigenvalues and
454  // eigenvectors of the correlation matrices.
455  for (unsigned int base_i = 0; base_i < no_bases; ++base_i)
456  {
457  _base[var_i][base_i].resize(_snapshots[var_i].getLocalEntry(0)->size());
458 
459  for (unsigned int loc_i = 0; loc_i < no_snaps; ++loc_i)
460  {
461  unsigned int glob_i = _snapshots[var_i].getGlobalIndex(loc_i);
462  const DenseVector<Real> & snapshot = *_snapshots[var_i].getLocalEntry(loc_i);
463 
464  for (unsigned int i = 0; i < _base[var_i][base_i].size(); ++i)
465  {
466  _base[var_i][base_i](i) += _eigenvectors[var_i](glob_i, base_i) * snapshot(i);
467  }
468  }
469 
470  // Gathering and summing the local contributions over all of the processes.
471  // This makes sure that every process sees all of the basis functions.
472  gatherSum(_base[var_i][base_i].get_values());
473 
474  // Normalizing the basis functions to make sure they are orthonormal.
475  _base[var_i][base_i].scale(1.0 / sqrt(_eigenvalues[var_i](base_i)));
476  }
477  }
478 }
479 
480 void
482 {
483  _red_operators.resize(_tag_names.size());
484 
485  // Getting the sum of the ranks of the different bases. Every reduced operator
486  // is resized with this number. This way the construction can be more general.
487  unsigned int base_num = getSumBaseSize();
488 
489  // Initializing each operator (each operator with a tag).
490  for (unsigned int tag_i = 0; tag_i < _red_operators.size(); ++tag_i)
491  {
492  if (_tag_types[tag_i] == "src" || _tag_types[tag_i] == "src_dir")
493  _red_operators[tag_i].resize(base_num, 1);
494  else
495  _red_operators[tag_i].resize(base_num, base_num);
496  }
497 }
498 
499 void
501  unsigned int tag_i,
502  std::vector<DenseVector<Real>> & residual)
503 {
504  // Computing the elements of the reduced operator using Galerkin projection
505  // on the residual. This is done in parallel and the local contributions are
506  // gathered in finalize().
507  unsigned int counter = 0;
508  for (unsigned int var_i = 0; var_i < _var_names.size(); ++var_i)
509  {
510  for (unsigned int base_j = 0; base_j < _base[var_i].size(); ++base_j)
511  {
512  _red_operators[tag_i](counter, base_i) = residual[var_i].dot(_base[var_i][base_j]);
513  counter++;
514  }
515  }
516 
517  _empty_operators = false;
518 }
519 
520 unsigned int
521 PODReducedBasisTrainer::getSnapsSize(unsigned int var_i) const
522 {
523  return _snapshots[var_i].getNumberOfGlobalEntries();
524 }
525 
526 unsigned int
528 {
529  unsigned int sum = 0;
530 
531  for (unsigned int i = 0; i < _base.size(); ++i)
532  sum += _base[i].size();
533 
534  return sum;
535 }
536 
537 const DenseVector<Real> &
538 PODReducedBasisTrainer::getBasisVector(unsigned int var_i, unsigned int base_i) const
539 {
540  return _base[var_i][base_i];
541 }
542 
543 const DenseVector<Real> &
544 PODReducedBasisTrainer::getBasisVector(unsigned int glob_i) const
545 {
546  unsigned int counter = 0;
547 
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)
550  {
551  if (glob_i == counter)
552  return _base[var_i][base_i];
553 
554  counter += 1;
555  }
556 
557  mooseError("The basis vector with global index ", glob_i, "is not available!");
558  return _base[0][0];
559 }
560 
561 unsigned int
563 {
564  unsigned int counter = 0;
565 
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)
568  {
569  if (glob_i == counter)
570  return var_i;
571 
572  counter += 1;
573  }
574 
575  mooseError("Variable with global base index ", glob_i, "is not available!");
576  return 0;
577 }
578 
579 void
581 {
582  if (processor_id() == 0 && _tid == 0 && isParamValid("filenames"))
583  {
584  std::vector<std::string> filenames = getParam<std::vector<std::string>>("filenames");
585 
586  if (filenames.size() != _var_names.size())
587  paramError("filenames",
588  "The number of file names is not equal to the number of variable names!");
589 
590  for (unsigned int var_i = 0; var_i < _var_names.size(); ++var_i)
591  {
592  std::filebuf fb;
593  fb.open(filenames[var_i], std::ios::out);
594  std::ostream os(&fb);
595  os << "evs" << std::endl;
596  _eigenvalues[var_i].print_scientific(os);
597  }
598  }
599 }
virtual void execute() override
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< std::vector< DenseVector< Real > > > & _base
The reduced basis for the variables.
virtual void initialSetup() override
PODReducedBasisTrainer(const InputParameters &parameters)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< DenseMatrix< Real > > _eigenvectors
The eigenvectors of the correalation matrix for each variable.
void printEigenvalues()
Prints the eigenvalues of the correlation matrix for each variable.
MeshBase & mesh
void initReducedOperators()
Initializing the reduced operators.
unsigned int m() const
const Parallel::Communicator & _communicator
std::basic_ostream< charT, traits > * os
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...
static InputParameters validParams()
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addSnapshot(unsigned int var_i, unsigned int glob_i, const std::shared_ptr< DenseVector< Real >> &snapshot)
Adding a snapshot for a variable.
virtual void finalize() override
std::vector< DistributedSnapshots > _snapshots
Distributed container for snapshots per variable.
static InputParameters validParams()
bool isParamValid(const std::string &name) const
uint8_t processor_id_type
bool _empty_operators
Flag describing if the reduced operators are empty or not.
void gatherSum(T &value)
std::vector< std::string > & _tag_types
list of bools describing which tag is indepedent of the solution.
std::vector< DenseVector< Real > > _eigenvalues
The eigenvalues of the correalation matrix for each variable.
void paramError(const std::string &param, Args... args) const
unsigned int getVariableIndex(unsigned int glob_i) const
Getting appropriate variable index for a global base index.
std::vector< DenseMatrix< Real > > _corr_mx
The correlation matrices for the variables.
std::vector< DenseMatrix< Real > > & _red_operators
The reduced operators that should be transferred to the surrogate.
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...
unsigned int determineNumberOfModes(Real error, const std::vector< Real > &inp_vec) const
Computes the number of bases necessary for a given error indicator.
bool _base_completed
Switch that tells if the object has already computed the necessary basis vectors. ...
registerMooseObject("StochasticToolsApp", PODReducedBasisTrainer)
StochasticTools::DistributedData< std::shared_ptr< DenseVector< Real > > > DistributedSnapshots
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
Definition: NS.h:84
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
void computeEigenDecomposition()
Computes the eigen-decomposition of the stored correlation matrices.
const THREAD_ID _tid
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::vector< std::string > & _tag_names
Names of the tags that should be used to fetch residuals from the MultiApp.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< std::string > & _var_names
Vector containing the names of the variables we want to use for constructing the surrogates.
std::vector< Real > _error_res
Energy limits that define how many basis functions will be kept for each variable.
This is the base trainer class whose main functionality is the API for declaring model data...
processor_id_type processor_id() const
static const std::string k
Definition: NS.h:130
unsigned int getSumBaseSize() const
Getting the overall base size, which is the sum of the individual bases.
void computeCorrelationMatrix()
Computes the correlation matrices using the snapshots.
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
const DenseVector< Real > & getBasisVector(unsigned int var_i, unsigned int base_i) const
Getting a basis vector for a given variable.
void computeBasisVectors()
Generates the basis vectors using the snapshots together with the eigen-decomposition of the correlat...