LCOV - code coverage report
Current view: top level - src/samplers - PMCMCBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #32971 (54bef8) with base c6cf66 Lines: 104 111 93.7 %
Date: 2026-05-29 20:40:35 Functions: 13 14 92.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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"
      11             : #include "AdaptiveMonteCarloUtils.h"
      12             : #include "Uniform.h"
      13             : #include "DelimitedFileReader.h"
      14             : 
      15             : registerMooseObject("StochasticToolsApp", PMCMCBase);
      16             : 
      17             : InputParameters
      18         283 : PMCMCBase::validParams()
      19             : {
      20         283 :   InputParameters params = Sampler::validParams();
      21         283 :   params.addClassDescription("Parallel Markov chain Monte Carlo base.");
      22         566 :   params.addRequiredParam<std::vector<DistributionName>>(
      23             :       "prior_distributions", "The prior distributions of the parameters to be calibrated.");
      24         566 :   params.addParam<DistributionName>(
      25             :       "prior_variance", "The prior distribution of the variance parameter to be calibrated.");
      26         566 :   params.addRequiredParam<unsigned int>(
      27             :       "num_parallel_proposals",
      28             :       "Number of proposals to make and corresponding subApps executed in "
      29             :       "parallel.");
      30         566 :   params.addRequiredParam<FileName>("file_name", "Name of the CSV file with configuration values.");
      31         566 :   params.addParam<std::string>(
      32             :       "file_column_name", "Name of column in CSV file to use, by default first column is used.");
      33         566 :   params.addParam<unsigned int>(
      34             :       "num_columns", "Number of columns to be used in the CSV file with the configuration values.");
      35         566 :   params.addParam<std::vector<Real>>("lower_bound", "Lower bounds for making the next proposal.");
      36         566 :   params.addParam<std::vector<Real>>("upper_bound", "Upper bounds for making the next proposal.");
      37         566 :   params.addParam<Real>("variance_bound",
      38         566 :                         std::numeric_limits<Real>::max(),
      39             :                         "Upper bound for variance for making the next proposal.");
      40         566 :   params.addRequiredParam<std::vector<Real>>("initial_values",
      41             :                                              "The starting values of the inputs to be calibrated.");
      42         566 :   params.addParam<unsigned int>(
      43             :       "num_random_seeds",
      44         566 :       100000,
      45             :       "Initialize a certain number of random seeds. Change from the default only if you have to.");
      46         283 :   return params;
      47           0 : }
      48             : 
      49         159 : PMCMCBase::PMCMCBase(const InputParameters & parameters)
      50             :   : Sampler(parameters),
      51             :     TransientInterface(this),
      52         159 :     _num_parallel_proposals(getParam<unsigned int>("num_parallel_proposals")),
      53         374 :     _lower_bound(isParamValid("lower_bound") ? &getParam<std::vector<Real>>("lower_bound")
      54             :                                              : nullptr),
      55         370 :     _upper_bound(isParamValid("upper_bound") ? &getParam<std::vector<Real>>("upper_bound")
      56             :                                              : nullptr),
      57         318 :     _variance_bound(getParam<Real>("variance_bound")),
      58         318 :     _initial_values(getParam<std::vector<Real>>("initial_values")),
      59         318 :     _num_random_seeds(getParam<unsigned int>("num_random_seeds")),
      60         159 :     _seed_index(0),
      61         318 :     _rand_index(0)
      62             : {
      63             :   // Filling the `priors` vector with the user-provided distributions.
      64         159 :   for (const DistributionName & name :
      65         636 :        getParam<std::vector<DistributionName>>("prior_distributions"))
      66         318 :     _priors.push_back(&getDistributionByName(name));
      67             : 
      68             :   // Filling the `var_prior` object with the user-provided distribution for the variance.
      69         318 :   if (isParamValid("prior_variance"))
      70          48 :     _var_prior = &getDistributionByName(getParam<DistributionName>("prior_variance"));
      71             :   else
      72         135 :     _var_prior = nullptr;
      73             : 
      74             :   // Read the experimental configurations from a csv file
      75         318 :   MooseUtils::DelimitedFileReader reader(getParam<FileName>("file_name"));
      76         159 :   reader.read();
      77         159 :   _confg_values.resize(1);
      78         318 :   if (isParamValid("file_column_name"))
      79           0 :     _confg_values[0] = reader.getData(getParam<std::string>("file_column_name"));
      80         318 :   else if (isParamValid("num_columns"))
      81             :   {
      82           0 :     _confg_values.resize(getParam<unsigned int>("num_columns"));
      83           0 :     for (unsigned int i = 0; i < _confg_values.size(); ++i)
      84           0 :       _confg_values[i] = reader.getData(i);
      85             :   }
      86             :   else
      87         159 :     _confg_values[0] = reader.getData(0);
      88             : 
      89             :   // Setting the number of sampler rows to be equal to the number of parallel proposals
      90         159 :   setNumberOfRows(_num_parallel_proposals * _confg_values[0].size());
      91             : 
      92             :   // Setting the number of columns in the sampler matrix (equal to the number of distributions).
      93         159 :   setNumberOfCols(_priors.size() + _confg_values.size());
      94             : 
      95             :   // Resizing the vectors and vector of vectors
      96         159 :   _new_samples.resize(_num_parallel_proposals, _initial_values);
      97         159 :   _new_samples_confg.resize(_num_parallel_proposals * _confg_values[0].size(),
      98         318 :                             std::vector<Real>(_priors.size() + _confg_values.size(), 0.0));
      99         159 :   _rnd_vec.resize(_num_parallel_proposals);
     100         159 :   _new_var_samples.assign(_num_parallel_proposals, 0.0);
     101             : 
     102         159 :   setNumberOfRandomSeeds(_num_random_seeds);
     103         159 :   setAutoAdvanceGenerators(false);
     104             : 
     105             :   // Check whether both the lower and the upper bounds are specified and of same size
     106         159 :   bool bound_check1 = _lower_bound && !_upper_bound;
     107         159 :   bool bound_check2 = !_lower_bound && _upper_bound;
     108         159 :   if (bound_check1 || bound_check2)
     109           2 :     mooseError("Both lower and upper bounds should be specified.");
     110         157 :   bool size_check = _lower_bound ? ((*_lower_bound).size() != (*_upper_bound).size()) : 0;
     111             :   if (size_check)
     112           2 :     mooseError("Lower and upper bounds should be of the same size.");
     113             : 
     114             :   // Check whether the priors, bounds, and initial values are all of the same size
     115         155 :   if (_priors.size() != _initial_values.size())
     116           2 :     mooseError("The priors and initial values should be of the same size.");
     117         153 : }
     118             : 
     119             : void
     120         288 : PMCMCBase::proposeSamples()
     121             : {
     122         864 :   for (unsigned int j = 0; j < _num_parallel_proposals; ++j)
     123        1728 :     for (unsigned int i = 0; i < _priors.size(); ++i)
     124        1152 :       _new_samples[j][i] = _priors[i]->quantile(random());
     125         288 : }
     126             : 
     127             : void
     128         894 : PMCMCBase::executeSetUp()
     129             : {
     130         894 :   _seed_index = _t_step;
     131         894 :   _rand_index = 0;
     132             : 
     133             :   // Filling the new_samples vector of vectors with new proposal samples
     134         894 :   proposeSamples();
     135             : 
     136             :   // Draw random numbers to facilitate decision making later on
     137        4500 :   for (unsigned int j = 0; j < _num_parallel_proposals; ++j)
     138        3606 :     _rnd_vec[j] = random();
     139         894 : }
     140             : 
     141             : Real
     142       18536 : PMCMCBase::random()
     143             : {
     144       18536 :   return getRand(_rand_index++, _seed_index);
     145             : }
     146             : 
     147             : unsigned int
     148        4320 : PMCMCBase::randomIndex(const unsigned int & upper_bound, const unsigned int & exclude)
     149             : {
     150        4320 :   auto req_index = exclude;
     151        9936 :   while (req_index == exclude)
     152        5616 :     req_index = getRandl(_rand_index++, 0, upper_bound, _seed_index);
     153        4320 :   return req_index;
     154             : }
     155             : 
     156             : std::pair<unsigned int, unsigned int>
     157        1536 : PMCMCBase::randomIndexPair(const unsigned int & upper_bound, const unsigned int & exclude)
     158             : {
     159        1536 :   auto req_index1 = randomIndex(upper_bound, exclude);
     160             :   auto req_index2 = req_index1;
     161        3600 :   while (req_index1 == req_index2)
     162        2064 :     req_index2 = randomIndex(upper_bound, exclude);
     163        1536 :   return {req_index1, req_index2};
     164             : }
     165             : 
     166             : void
     167        8400 : PMCMCBase::combineWithExperimentalConfig()
     168             : {
     169             :   unsigned int index1;
     170             :   int index2 = -1;
     171             :   std::vector<Real> tmp;
     172       85200 :   for (unsigned int i = 0; i < _num_parallel_proposals * _confg_values[0].size(); ++i)
     173             :   {
     174       76800 :     index1 = i % _num_parallel_proposals;
     175       76800 :     if (index1 == 0)
     176       16800 :       ++index2;
     177       76800 :     tmp = _new_samples[index1];
     178      153600 :     for (unsigned int j = 0; j < _confg_values.size(); ++j)
     179       76800 :       tmp.push_back(_confg_values[j][index2]);
     180       76800 :     _new_samples_confg[i] = tmp;
     181             :   }
     182        8400 : }
     183             : 
     184             : const std::vector<Real> &
     185         120 : PMCMCBase::getRandomNumbers() const
     186             : {
     187         120 :   return _rnd_vec;
     188             : }
     189             : 
     190             : const std::vector<Real> &
     191         124 : PMCMCBase::getVarSamples() const
     192             : {
     193         124 :   return _new_var_samples;
     194             : }
     195             : 
     196             : const std::vector<std::vector<Real>> &
     197           0 : PMCMCBase::getSamples() const
     198             : {
     199           0 :   return _new_samples;
     200             : }
     201             : 
     202             : const std::vector<const Distribution *>
     203         120 : PMCMCBase::getPriors() const
     204             : {
     205         120 :   return _priors;
     206             : }
     207             : 
     208             : const Distribution *
     209         124 : PMCMCBase::getVarPrior() const
     210             : {
     211         124 :   return _var_prior;
     212             : }
     213             : 
     214             : Real
     215        8400 : PMCMCBase::computeSample(dof_id_type row_index, dof_id_type col_index)
     216             : {
     217        8400 :   if (_t_step < 1)
     218        4680 :     for (unsigned int i = 0; i < _num_parallel_proposals; ++i)
     219        3840 :       _new_samples[i] = _initial_values;
     220             : 
     221             :   // Combine the proposed samples with experimental configurations
     222        8400 :   combineWithExperimentalConfig();
     223             : 
     224        8400 :   return _new_samples_confg[row_index][col_index];
     225             : }

Generated by: LCOV version 1.14