https://mooseframework.inl.gov
PMCMCBase.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 "PMCMCBase.h"
12 #include "Uniform.h"
13 #include "DelimitedFileReader.h"
14 
15 registerMooseObject("StochasticToolsApp", PMCMCBase);
16 
19 {
21  params.addClassDescription("Parallel Markov chain Monte Carlo base.");
22  params.addRequiredParam<std::vector<DistributionName>>(
23  "prior_distributions", "The prior distributions of the parameters to be calibrated.");
24  params.addParam<DistributionName>(
25  "prior_variance", "The prior distribution of the variance parameter to be calibrated.");
26  params.addRequiredParam<unsigned int>(
27  "num_parallel_proposals",
28  "Number of proposals to make and corresponding subApps executed in "
29  "parallel.");
30  params.addRequiredParam<FileName>("file_name", "Name of the CSV file with configuration values.");
31  params.addParam<std::string>(
32  "file_column_name", "Name of column in CSV file to use, by default first column is used.");
33  params.addParam<unsigned int>(
34  "num_columns", "Number of columns to be used in the CSV file with the configuration values.");
35  params.addParam<std::vector<Real>>("lower_bound", "Lower bounds for making the next proposal.");
36  params.addParam<std::vector<Real>>("upper_bound", "Upper bounds for making the next proposal.");
37  params.addRequiredParam<std::vector<Real>>("initial_values",
38  "The starting values of the inputs to be calibrated.");
39  params.addParam<unsigned int>(
40  "num_random_seeds",
41  100000,
42  "Initialize a certain number of random seeds. Change from the default only if you have to.");
43  return params;
44 }
45 
47  : Sampler(parameters),
48  TransientInterface(this),
49  _num_parallel_proposals(getParam<unsigned int>("num_parallel_proposals")),
50  _lower_bound(isParamValid("lower_bound") ? &getParam<std::vector<Real>>("lower_bound")
51  : nullptr),
52  _upper_bound(isParamValid("upper_bound") ? &getParam<std::vector<Real>>("upper_bound")
53  : nullptr),
54  _check_step(0),
55  _initial_values(getParam<std::vector<Real>>("initial_values")),
56  _num_random_seeds(getParam<unsigned int>("num_random_seeds"))
57 {
58  // Filling the `priors` vector with the user-provided distributions.
59  for (const DistributionName & name :
60  getParam<std::vector<DistributionName>>("prior_distributions"))
61  _priors.push_back(&getDistributionByName(name));
62 
63  // Filling the `var_prior` object with the user-provided distribution for the variance.
64  if (isParamValid("prior_variance"))
65  _var_prior = &getDistributionByName(getParam<DistributionName>("prior_variance"));
66  else
67  _var_prior = nullptr;
68 
69  // Read the experimental configurations from a csv file
70  MooseUtils::DelimitedFileReader reader(getParam<FileName>("file_name"));
71  reader.read();
72  _confg_values.resize(1);
73  if (isParamValid("file_column_name"))
74  _confg_values[0] = reader.getData(getParam<std::string>("file_column_name"));
75  else if (isParamValid("num_columns"))
76  {
77  _confg_values.resize(getParam<unsigned int>("num_columns"));
78  for (unsigned int i = 0; i < _confg_values.size(); ++i)
79  _confg_values[i] = reader.getData(i);
80  }
81  else
82  _confg_values[0] = reader.getData(0);
83 
84  // Setting the number of sampler rows to be equal to the number of parallel proposals
86 
87  // Setting the number of columns in the sampler matrix (equal to the number of distributions).
88  setNumberOfCols(_priors.size() + _confg_values.size());
89 
90  // Resizing the vectors and vector of vectors
91  _new_samples.resize(_num_parallel_proposals, std::vector<Real>(_priors.size(), 0.0));
93  std::vector<Real>(_priors.size() + _confg_values.size(), 0.0));
96 
98 
99  _check_step = 0;
100 
101  // Check whether both the lower and the upper bounds are specified and of same size
102  bool bound_check1 = _lower_bound && !_upper_bound;
103  bool bound_check2 = !_lower_bound && _upper_bound;
104  if (bound_check1 || bound_check2)
105  mooseError("Both lower and upper bounds should be specified.");
106  bool size_check = _lower_bound ? ((*_lower_bound).size() != (*_upper_bound).size()) : 0;
107  if (size_check)
108  mooseError("Lower and upper bounds should be of the same size.");
109 
110  // Check whether the priors, bounds, and initial values are all of the same size
111  if (_priors.size() != _initial_values.size())
112  mooseError("The priors and initial values should be of the same size.");
113 }
114 
115 void
116 PMCMCBase::proposeSamples(const unsigned int seed_value)
117 {
118  for (unsigned int j = 0; j < _num_parallel_proposals; ++j)
119  for (unsigned int i = 0; i < _priors.size(); ++i)
120  _new_samples[j][i] = _priors[i]->quantile(getRand(seed_value));
121 }
122 
123 void
125 {
126  if (_t_step < 1 || _check_step == _t_step)
127  return;
129 
130  unsigned int seed_value = _t_step > 0 ? (_t_step - 1) : 0;
131 
132  // Filling the new_samples vector of vectors with new proposal samples
133  proposeSamples(seed_value);
134 
135  // Draw random numbers to facilitate decision making later on
136  for (unsigned int j = 0; j < _num_parallel_proposals; ++j)
137  _rnd_vec[j] = getRand(seed_value);
138 }
139 
140 void
141 PMCMCBase::randomIndex(const unsigned int & upper_bound,
142  const unsigned int & exclude,
143  const unsigned int & seed,
144  unsigned int & req_index)
145 {
146  req_index = exclude;
147  while (req_index == exclude)
148  req_index = getRandl(seed, 0, upper_bound);
149 }
150 
151 void
152 PMCMCBase::randomIndexPair(const unsigned int & upper_bound,
153  const unsigned int & exclude,
154  const unsigned int & seed,
155  unsigned int & req_index1,
156  unsigned int & req_index2)
157 {
158  randomIndex(upper_bound, exclude, seed, req_index1);
159  req_index2 = req_index1;
160  while (req_index1 == req_index2)
161  randomIndex(upper_bound, exclude, seed, req_index2);
162 }
163 
164 void
166 {
167  unsigned int index1;
168  int index2 = -1;
169  std::vector<Real> tmp;
170  for (unsigned int i = 0; i < _num_parallel_proposals * _confg_values[0].size(); ++i)
171  {
172  index1 = i % _num_parallel_proposals;
173  if (index1 == 0)
174  ++index2;
175  tmp = _new_samples[index1];
176  for (unsigned int j = 0; j < _confg_values.size(); ++j)
177  tmp.push_back(_confg_values[j][index2]);
178  _new_samples_confg[i] = tmp;
179  }
180 }
181 
182 const std::vector<Real> &
184 {
185  return _rnd_vec;
186 }
187 
188 const std::vector<Real> &
190 {
191  return _new_var_samples;
192 }
193 
194 const std::vector<const Distribution *>
196 {
197  return _priors;
198 }
199 
200 const Distribution *
202 {
203  return _var_prior;
204 }
205 
206 Real
208 {
209  if (_t_step < 1)
210  for (unsigned int i = 0; i < _num_parallel_proposals; ++i)
212 
213  // Combine the proposed samples with experimental configurations
215 
216  return _new_samples_confg[row_index][col_index];
217 }
void setNumberOfRows(dof_id_type n_rows)
const unsigned int _num_random_seeds
Initialize a certain number of random seeds. Change from the default only if you have to...
Definition: PMCMCBase.h:142
uint32_t getRandl(unsigned int index, uint32_t lower, uint32_t upper)
const unsigned int _num_parallel_proposals
Number of parallel proposals to be made and subApps to be executed.
Definition: PMCMCBase.h:106
const std::vector< Real > & _initial_values
Initial values of the input params to get the MCMC scheme started.
Definition: PMCMCBase.h:124
static InputParameters validParams()
std::vector< std::vector< Real > > _new_samples_confg
Vectors of new proposed samples combined with the experimental configuration values.
Definition: PMCMCBase.h:148
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const std::vector< Real > * _lower_bound
Lower bounds for making the next proposal.
Definition: PMCMCBase.h:115
void combineWithExperimentalConfig()
Generates combinations of the new samples with the experimental configurations.
Definition: PMCMCBase.C:165
PMCMCBase(const InputParameters &parameters)
Definition: PMCMCBase.C:46
std::vector< const Distribution * > _priors
Storage for prior distribution objects to be utilized.
Definition: PMCMCBase.h:109
registerMooseObject("StochasticToolsApp", PMCMCBase)
int _check_step
Ensure that the MCMC algorithm proceeds in a sequential fashion.
Definition: PMCMCBase.h:121
const std::vector< const Distribution * > getPriors() const
Return the priors to facilitate decision making in reporters.
Definition: PMCMCBase.C:195
Real getRand(unsigned int index=0)
virtual void proposeSamples(const unsigned int seed_value)
Fill in the _new_samples vector of vectors (happens within sampleSetUp)
Definition: PMCMCBase.C:116
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
const Distribution * getVarPrior() const
Return the prior over variance to facilitate decision making in reporters.
Definition: PMCMCBase.C:201
bool isParamValid(const std::string &name) const
std::vector< Real > _new_var_samples
Vector of new proposed variance samples.
Definition: PMCMCBase.h:130
const T & getParam(const std::string &name) const
std::vector< Real > _rnd_vec
Vector of random numbers for decision making.
Definition: PMCMCBase.h:133
const std::vector< std::vector< T > > & getData() const
const std::vector< Real > * _upper_bound
Upper bounds for making the next proposal.
Definition: PMCMCBase.h:118
void randomIndexPair(const unsigned int &upper_bound, const unsigned int &exclude, const unsigned int &seed, unsigned int &req_index1, unsigned int &req_index2)
Sample two random indices without repitition excluding a specified index.
Definition: PMCMCBase.C:152
const std::vector< Real > & getVarSamples() const
Return the proposed variance samples to facilitate decision making in reporters.
Definition: PMCMCBase.C:189
const Distribution & getDistributionByName(const DistributionName &name) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void setNumberOfCols(dof_id_type n_cols)
std::vector< std::vector< Real > > _new_samples
Vectors of new proposed samples.
Definition: PMCMCBase.h:127
virtual void sampleSetUp(const Sampler::SampleMode mode) override
Definition: PMCMCBase.C:124
const Distribution * _var_prior
Storage for prior distribution object of the variance to be utilized.
Definition: PMCMCBase.h:112
const std::vector< Real > & getRandomNumbers() const
Return the random numbers to facilitate decision making in reporters.
Definition: PMCMCBase.C:183
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
void randomIndex(const unsigned int &upper_bound, const unsigned int &exclude, const unsigned int &seed, unsigned int &req_index)
Sample a random index excluding a specified index.
Definition: PMCMCBase.C:141
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< std::vector< Real > > _confg_values
Configuration values.
Definition: PMCMCBase.h:145
virtual Real computeSample(dof_id_type row_index, dof_id_type col_index) override
Definition: PMCMCBase.C:207
void ErrorVector unsigned int
static InputParameters validParams()
Definition: PMCMCBase.C:18
uint8_t dof_id_type
void setNumberOfRandomSeeds(std::size_t number)
A base class used to perform Parallel Markov Chain Monte Carlo (MCMC) sampling.
Definition: PMCMCBase.h:19