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" 59 std::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;
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();
75 n_local_samples = (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)
110 template <
class Base>
113 template <
class Base>
118 RBParametrized::clear();
119 _training_parameters.clear();
122 template <
class Base>
130 inner_product_storage_vector->init (this->n_dofs(), this->n_local_dofs(),
false,
PARALLEL);
133 template <
class Base>
135 std::pair<numeric_index_type, Real> & error_pair)
139 unsigned int proc_ID_index;
143 communicator.broadcast(error_pair.first, proc_ID_index);
146 template <
class Base>
149 _normalize_solution_snapshots =
value;
152 template <
class Base>
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;
174 template <
class Base>
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;
190 template <
class Base>
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;
212 template <
class Base>
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;
224 template <
class Base>
227 set_parameters(get_params_from_training_set(global_index));
230 template <
class Base>
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()))
269 template <
class Base>
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);
291 template <
class Base>
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;
378 template <
class Base>
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];
455 template <
class Base>
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;
470 template <
class Base>
471 std::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) );
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));
553 Real log_range = std::log10(max_parameters.
get_value(param_name) / 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) -
562 min_parameters.get_value(param_name)) +
563 min_parameters.get_value(param_name)};
567 return {first_local_index, first_local_index+n_local_training_samples};
570 template <
class Base>
571 std::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);
649 Real min_param = min_parameters.get_value(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};
719 template <
class Base>
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);
779 template <
class Base>
782 this->_training_parameters_random_seed = seed;
788 #if defined(LIBMESH_HAVE_SLEPC) Real get_value(const std::string ¶m_name) const
Get the value of the specified parameter, throw an error if it does not exist.
This is the EquationSystems class.
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
The libMesh namespace provides an interface to certain functionality in the library.
uint8_t processor_id_type
unsigned int n_parameters() const
Get the number of parameters that have been added.
dof_id_type numeric_index_type
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
RBConstructionBase(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
std::vector< Real > RBParameter
Typedef for an individual RB parameter.
This class is part of the rbOOmit framework.
unsigned int n_samples() const
Returns the number of samples stored for all parameters.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void set_extra_value(const std::string ¶m_name, Real value)
Set the value of the specified extra parameter.
DIE A HORRIBLE DEATH HERE typedef MPI_Comm communicator
void set_value(const std::string ¶m_name, Real value)
Set the value of the specified parameter.
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...
This class is part of the rbOOmit framework.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...