31#include "libmesh/rb_construction_base.h"
32#include "libmesh/rb_parameters.h"
35#include "libmesh/id_types.h"
36#include "libmesh/libmesh_common.h"
37#include "libmesh/numeric_vector.h"
38#include "libmesh/equation_systems.h"
39#include "libmesh/parallel.h"
40#include "libmesh/condensed_eigen_system.h"
41#include "libmesh/linear_implicit_system.h"
42#include "libmesh/int_range.h"
43#include "libmesh/utility.h"
46#include "libmesh/dof_map.h"
47#include "libmesh/shell_matrix.h"
48#include "libmesh/sparse_matrix.h"
59std::pair<unsigned int, unsigned int> calculate_n_local_samples_and_index(
61 const unsigned int n_global_samples,
64 unsigned int n_local_samples = n_global_samples;
65 unsigned int first_local_index = 0;
67 if (serial || communicator.size() == 1)
68 return {n_local_samples, first_local_index};
71 unsigned int quotient = n_global_samples/communicator.size();
72 unsigned int remainder = n_global_samples%communicator.size();
73 if (communicator.rank() < remainder)
75 n_local_samples = (quotient + 1);
76 first_local_index = communicator.rank()*(quotient+1);
80 n_local_samples = quotient;
81 first_local_index = communicator.rank()*quotient + remainder;
83 return {n_local_samples, first_local_index};
96 const std::string & name_in,
97 const unsigned int number_in)
98 : Base(es, name_in, number_in),
100 serial_training_set(false),
101 _normalize_solution_snapshots(false),
102 _training_parameters_initialized(false),
103 _first_local_index(0),
104 _n_local_training_samples(0),
105 _n_global_training_samples(0),
106 _training_parameters_random_seed(-1)
119 _training_parameters.clear();
130 inner_product_storage_vector->init (this->n_dofs(), this->n_local_dofs(),
false,
PARALLEL);
135 std::pair<numeric_index_type, Real> & error_pair)
139 unsigned int proc_ID_index;
140 communicator.maxloc(error_pair.second, proc_ID_index);
143 communicator.broadcast(error_pair.first, proc_ID_index);
149 _normalize_solution_snapshots =
value;
155 libmesh_error_msg_if(!_training_parameters_initialized,
156 "Error: training parameters must first be initialized.");
163 if (_training_parameters.empty())
165 if (serial_training_set)
168 return this->comm().size();
171 return _n_global_training_samples;
177 libmesh_error_msg_if(!_training_parameters_initialized,
178 "Error: training parameters must first be initialized.");
184 if (_training_parameters.empty())
187 return _n_local_training_samples;
193 libmesh_error_msg_if(!_training_parameters_initialized,
194 "Error: training parameters must first be initialized.");
201 if (_training_parameters.empty())
203 if (serial_training_set)
206 return this->comm().rank();
209 return _first_local_index;
215 libmesh_error_msg_if(!_training_parameters_initialized,
216 "Error: training parameters must first be initialized.");
218 if (_training_parameters.empty())
221 return _first_local_index + _n_local_training_samples;
227 set_parameters(get_params_from_training_set(global_index));
233 libmesh_error_msg_if(!_training_parameters_initialized,
234 "Error: training parameters must first be initialized.");
239 if (!_training_parameters.empty())
241 libmesh_error_msg_if((global_index < this->get_first_local_training_index()) ||
242 (global_index >= this->get_last_local_training_index()),
245 <<
" must be within range: "
246 << this->get_first_local_training_index()
248 << this->get_last_local_training_index());
250 const numeric_index_type local_index = global_index - get_first_local_training_index();
251 for (
const auto & [param_name, sample_vector] : _training_parameters)
252 params.set_value(param_name, sample_vector[local_index]);
257 const auto & mine = get_parameters();
258 for (
const auto & [key, extra_sample_vector] :
259 as_range(mine.extra_begin(), mine.extra_end()))
261 for (
const auto idx :
index_range(extra_sample_vector))
262 params.set_extra_value(key, idx, extra_sample_vector[idx]);
272 libmesh_error_msg_if(!_training_parameters_initialized,
273 "Error: training parameters must first be initialized.");
276 if ((this->get_first_local_training_index() <= global_index) &&
277 (global_index < this->get_last_local_training_index()))
280 set_params_from_training_set(global_index);
283 root_id = this->processor_id();
287 this->comm().max(root_id);
288 broadcast_parameters(root_id);
294 const unsigned int n_global_training_samples,
295 const std::map<std::string,bool> & log_param_scale,
296 const bool deterministic)
301 libMesh::out <<
"Initializing training parameters with "
302 << (deterministic ?
"deterministic " :
"random " )
303 <<
"training set..." << std::endl;
305 for (
const auto & pr : log_param_scale)
308 <<
": log scaling = "
317 const auto [first_local_index, last_local_index] =
318 generate_training_parameters_deterministic(this->comm(),
320 _training_parameters,
321 n_global_training_samples,
324 serial_training_set);
325 _first_local_index = first_local_index;
326 _n_local_training_samples = last_local_index-first_local_index;
331 const auto [first_local_index, last_local_index] =
332 generate_training_parameters_random(this->comm(),
334 _training_parameters,
335 n_global_training_samples,
338 this->_training_parameters_random_seed,
339 serial_training_set);
340 _first_local_index = first_local_index;
341 _n_local_training_samples = last_local_index-first_local_index;
343 _n_global_training_samples = _n_local_training_samples;
345 if (!serial_training_set)
346 this->comm().sum(_n_global_training_samples);
350 if (get_n_discrete_params() > 0)
352 for (
auto & [param_name, sample_vector] : _training_parameters)
354 if (is_discrete_parameter(param_name))
356 const std::vector<Real> & discrete_values =
357 libmesh_map_find(get_discrete_parameter_values(), param_name);
359 for (
const auto sample_idx :
index_range(sample_vector))
362 std::vector<Real> discretized_vector(sample_vector[sample_idx].size());
363 std::transform(sample_vector[sample_idx].cbegin(),
364 sample_vector[sample_idx].cend(),
365 discretized_vector.begin(),
366 [&discrete_values](
const Real & val) {
367 return get_closest_value(val, discrete_values);
369 sample_vector[sample_idx] = discretized_vector;
375 _training_parameters_initialized =
true;
382 libmesh_parallel_only(this->comm());
385 libmesh_error_msg_if(!_training_parameters_initialized,
386 "Error: load_training_set cannot be used to initialize parameters");
389 const unsigned int n_params = get_n_params();
390 libmesh_error_msg_if(new_training_set.size() > n_params,
391 "Error: new_training_set should not have more than get_n_params() parameters.");
395 const bool size_matches = (new_training_set.size() == n_params);
404 _first_local_index = 0;
405 _n_local_training_samples =
406 cast_int<numeric_index_type>(new_training_set.begin()->second.size());
407 _n_global_training_samples = _n_local_training_samples;
409 if (!serial_training_set)
411 this->comm().sum(_n_global_training_samples);
414 std::vector<numeric_index_type> local_sizes (this->n_processors(), 0);
415 local_sizes[this->processor_id()] = _n_local_training_samples;
416 this->comm().sum(local_sizes);
420 for (
auto p :
make_range(this->processor_id()))
421 _first_local_index += local_sizes[p];
425 for (
const auto & pr : _training_parameters)
426 libmesh_error_msg_if(!new_training_set.count(pr.first),
427 "Parameters must be identical in order to overwrite dataset.");
430 _training_parameters = new_training_set;
438 for (
auto & [param_name, sample_vector]: _training_parameters)
440 if (new_training_set.count(param_name))
442 for (
const auto i :
make_range(get_local_n_training_samples()))
444 const unsigned int num_new_samples = libmesh_map_find(new_training_set,param_name).size();
445 libmesh_error_msg_if (num_new_samples==0,
"new_training_set set should not be empty");
447 const unsigned int new_training_set_index = i % num_new_samples;
448 sample_vector[i] = libmesh_map_find(new_training_set,param_name)[new_training_set_index];
457 const std::string & param_name,
const std::vector<RBParameter> & values)
459 libmesh_error_msg_if(!_training_parameters_initialized,
460 "Training parameters must be initialized before calling set_training_parameter_values");
461 libmesh_error_msg_if(values.size() != get_local_n_training_samples(),
462 "Inconsistent sizes");
465 auto & training_vector = libmesh_map_find(_training_parameters, param_name);
466 training_vector = values;
471std::pair<std::size_t, std::size_t>
473 const std::map<std::string, bool> & log_param_scale,
474 std::map<std::string, std::vector<RBParameter>> & local_training_parameters_in,
475 const unsigned int n_global_training_samples_in,
478 const int training_parameters_random_seed,
479 const bool serial_training_set)
481 const unsigned int num_params = min_parameters.
n_parameters();
482 libmesh_error_msg_if(num_params!=max_parameters.
n_parameters(),
483 "Number of parameters must be identical for min/max.");
486 local_training_parameters_in.clear();
491 if (training_parameters_random_seed < 0)
493 if (!serial_training_set)
498 std::srand(
static_cast<unsigned>( std::time(0)*(1+communicator.rank()) ));
507 unsigned int current_time =
static_cast<unsigned>( std::time(0) );
508 communicator.broadcast(current_time, 0);
509 std::srand(current_time);
514 if (!serial_training_set)
519 std::srand(
static_cast<unsigned>( training_parameters_random_seed*(1+communicator.rank()) ));
525 std::srand(
static_cast<unsigned>( training_parameters_random_seed ));
536 const auto & [n_local_training_samples, first_local_index] =
537 calculate_n_local_samples_and_index(communicator, n_global_training_samples_in,
538 serial_training_set);
539 for (
const auto & pr : min_parameters)
540 local_training_parameters_in[pr.first] = std::vector<RBParameter>(n_local_training_samples);
543 for (
auto & [param_name, sample_vector] : local_training_parameters_in)
545 for (
auto i :
make_range(n_local_training_samples))
547 Real random_number =
static_cast<Real>(std::rand()) / RAND_MAX;
550 if (libmesh_map_find(log_param_scale, param_name))
552 Real log_min = std::log10(min_parameters.
get_value(param_name));
555 sample_vector[i] = {std::pow(
Real(10.), log_min + random_number*log_range )};
561 random_number * (max_parameters.
get_value(param_name) -
567 return {first_local_index, first_local_index+n_local_training_samples};
571std::pair<std::size_t, std::size_t>
573 const std::map<std::string, bool> & log_param_scale,
574 std::map<std::string, std::vector<RBParameter>> & local_training_parameters_in,
575 const unsigned int n_global_training_samples_in,
578 const bool serial_training_set)
581 const unsigned int num_params = min_parameters.
n_parameters();
587 libmesh_not_implemented_msg(
"ERROR: Deterministic training sample generation "
588 "not implemented for more than three parameters.");
597 const auto &[n_local_training_samples, first_local_index] =
598 calculate_n_local_samples_and_index(communicator, n_global_training_samples_in,
599 serial_training_set);
600 const auto last_local_index = first_local_index + n_local_training_samples;
601 for (
const auto & pr : min_parameters)
602 local_training_parameters_in[pr.first] = std::vector<RBParameter>(n_local_training_samples);
608 std::vector<unsigned int> n_training_samples_per_param(3);
609 for (
unsigned int param=0; param<3; param++)
611 if (param < num_params)
613 n_training_samples_per_param[param] =
614 static_cast<unsigned int>( std::round(std::pow(
static_cast<Real>(n_global_training_samples_in), 1./num_params)) );
618 n_training_samples_per_param[param] = 1;
626 unsigned int total_samples_check = 1;
627 for (
unsigned int n_samples : n_training_samples_per_param)
629 total_samples_check *= n_samples;
632 libmesh_error_msg_if(total_samples_check != n_global_training_samples_in,
633 "Error: Number of training samples = "
634 << n_global_training_samples_in
635 <<
" does not enable a uniform grid of samples with "
636 << num_params <<
" parameters. Try "
637 << total_samples_check <<
" samples instead?");
642 std::vector<std::vector<Real>> training_samples_per_param(num_params);
645 for (
const auto & pr : min_parameters)
647 const std::string & param_name = pr.first;
648 const bool use_log_scaling = libmesh_map_find(log_param_scale, param_name);
652 training_samples_per_param[i].resize(n_training_samples_per_param[i]);
654 for (
unsigned int j=0; j<n_training_samples_per_param[i]; j++)
659 Real epsilon = 1.e-6;
660 Real log_min = std::log10(min_param + epsilon);
661 Real log_range = std::log10( (max_param-epsilon) / (min_param+epsilon) );
662 Real step_size = log_range /
663 std::max((
unsigned int)1,(n_training_samples_per_param[i]-1));
665 if (j<(n_training_samples_per_param[i]-1))
667 training_samples_per_param[i][j] = std::pow(10., log_min + j*step_size );
673 training_samples_per_param[i][j] = max_param;
679 Real step_size = (max_param - min_param) /
680 std::max((
unsigned int)1,(n_training_samples_per_param[i]-1));
681 training_samples_per_param[i][j] = j*step_size + min_param;
691 std::vector<unsigned int> indices(3);
692 unsigned int index_count = 0;
693 for (indices[0]=0; indices[0]<n_training_samples_per_param[0]; indices[0]++)
695 for (indices[1]=0; indices[1]<n_training_samples_per_param[1]; indices[1]++)
697 for (indices[2]=0; indices[2]<n_training_samples_per_param[2]; indices[2]++)
699 unsigned int param_count = 0;
700 for (
const auto & pr : min_parameters)
702 std::vector<RBParameter> & training_vector =
703 libmesh_map_find(local_training_parameters_in, pr.first);
704 if (first_local_index <= index_count && index_count < last_local_index)
705 training_vector[index_count - first_local_index] =
706 {training_samples_per_param[param_count][indices[param_count]]};
715 return {first_local_index, first_local_index+n_local_training_samples};
722 libmesh_assert_less (proc_id, this->n_processors());
726 libmesh_error_msg_if(current_parameters.
n_samples()!=1,
727 "Only single-sample RBParameter objects can be broadcast.");
732 const std::size_t nparams = current_parameters.
n_parameters();
733 const std::size_t nsamples = current_parameters.
n_samples();
736 std::vector<std::size_t> param_value_sizes;
737 param_value_sizes.reserve(nparams);
738 for (
const auto & pr : current_parameters)
739 param_value_sizes.push_back(pr.second[0].size());
742 this->comm().broadcast(param_value_sizes, proc_id);
743 std::size_t buffsize = std::accumulate(param_value_sizes.cbegin(), param_value_sizes.cend(), 0ul);
744 std::vector<Real> serialized_parameters;
745 serialized_parameters.reserve(buffsize);
748 for (
const auto & pr : current_parameters)
750 for (
const auto sample_idx :
make_range(nsamples))
751 serialized_parameters.insert(serialized_parameters.end(),
752 pr.second[sample_idx].cbegin(),
753 pr.second[sample_idx].cend());
757 this->comm().broadcast(serialized_parameters, proc_id);
760 std::size_t param_idx = 0;
761 auto val_idx = serialized_parameters.cbegin();
762 for (
const auto & pr : current_parameters)
764 const std::size_t param_value_size = param_value_sizes[param_idx];
765 for (
const auto sample_idx:
make_range(nsamples))
767 auto end_val_idx = std::next(val_idx,param_value_size);
769 current_parameters.
set_value(pr.first, sample_idx, sample_val);
770 val_idx = end_val_idx;
776 set_parameters(current_parameters);
782 this->_training_parameters_random_seed = seed;
788#if defined(LIBMESH_HAVE_SLEPC)
This is the EquationSystems class.
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
This class is part of the rbOOmit framework.
virtual void init_data()
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
RBParameters get_params_from_training_set(unsigned int global_index)
Return the RBParameters in index global_index of the global training set.
virtual void set_params_from_training_set_and_broadcast(unsigned int global_index)
Load the specified training parameter and then broadcast to all processors.
void set_training_random_seed(int seed)
Set the seed that is used to randomly generate training parameters.
virtual void clear()
Clear all the data structures associated with the system.
virtual ~RBConstructionBase()
static std::pair< std::size_t, std::size_t > generate_training_parameters_random(const Parallel::Communicator &communicator, const std::map< std::string, bool > &log_param_scale, std::map< std::string, std::vector< RBParameter > > &local_training_parameters_in, const unsigned int n_global_training_samples_in, const RBParameters &min_parameters, const RBParameters &max_parameters, const int training_parameters_random_seed=-1, const bool serial_training_set=false)
Static helper function for generating a randomized set of parameters.
void set_training_parameter_values(const std::string ¶m_name, const std::vector< RBParameter > &values)
Overwrite the local training samples for param_name using values.
numeric_index_type get_first_local_training_index() const
Get the first local index of the training parameters.
numeric_index_type get_local_n_training_samples() const
Get the total number of training samples local to this processor.
RBConstructionBase(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
void broadcast_parameters(const unsigned int proc_id)
Broadcasts parameters from processor proc_id to all processors.
numeric_index_type get_n_training_samples() const
Get the number of global training samples.
void set_normalize_solution_snapshots(bool value)
Set the boolean option that indicates if we normalization solution snapshots or not.
virtual void initialize_training_parameters(const RBParameters &mu_min, const RBParameters &mu_max, const unsigned int n_global_training_samples, const std::map< std::string, bool > &log_param_scale, const bool deterministic=true)
Initialize the parameter ranges and indicate whether deterministic or random training parameters shou...
void set_params_from_training_set(unsigned int global_index)
Set parameters to the RBParameters stored in index global_index of the global training set.
static std::pair< std::size_t, std::size_t > generate_training_parameters_deterministic(const Parallel::Communicator &communicator, const std::map< std::string, bool > &log_param_scale, std::map< std::string, std::vector< RBParameter > > &local_training_parameters_in, const unsigned int n_global_training_samples_in, const RBParameters &min_parameters, const RBParameters &max_parameters, const bool serial_training_set=false)
Static helper function for generating a deterministic set of parameters.
numeric_index_type get_last_local_training_index() const
Get the last local index of the training parameters.
static void get_global_max_error_pair(const Parallel::Communicator &communicator, std::pair< numeric_index_type, Real > &error_pair)
Static function to return the error pair (index,error) that is corresponds to the largest error on al...
virtual void load_training_set(const std::map< std::string, std::vector< RBParameter > > &new_training_set)
Overwrite the training parameters with new_training_set.
This class is part of the rbOOmit framework.
unsigned int n_parameters() const
Get the number of parameters that have been added.
Real get_value(const std::string ¶m_name) const
Get the value of the specified parameter, throw an error if it does not exist.
unsigned int n_samples() const
Returns the number of samples stored for all parameters.
void set_value(const std::string ¶m_name, Real value)
Set the value of the specified parameter.
virtual void clear()
Clear all the data structures associated with the system.
The libMesh namespace provides an interface to certain functionality in the library.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
dof_id_type numeric_index_type
std::vector< Real > RBParameter
Typedef for an individual RB parameter.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...