LCOV - code coverage report
Current view: top level - src/reporters - PMCMCDecision.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #32971 (54bef8) with base c6cf66 Lines: 115 120 95.8 %
Date: 2026-05-29 20:40:35 Functions: 7 7 100.0 %
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 "PMCMCDecision.h"
      11             : #include "Sampler.h"
      12             : #include "DenseMatrix.h"
      13             : 
      14             : registerMooseObject("StochasticToolsApp", PMCMCDecision);
      15             : 
      16             : InputParameters
      17         250 : PMCMCDecision::validParams()
      18             : {
      19         250 :   InputParameters params = GeneralReporter::validParams();
      20         250 :   params += LikelihoodInterface::validParams();
      21         250 :   params.addClassDescription("Generic reporter which decides whether or not to accept a proposed "
      22             :                              "sample in parallel Markov chain Monte Carlo type of algorithms.");
      23         500 :   params.addParam<ReporterName>("output_value", "Value of the model output from the SubApp.");
      24         500 :   params.addParam<ReporterValueName>(
      25             :       "outputs_required",
      26             :       "outputs_required",
      27             :       "Modified value of the model output from this reporter class.");
      28         500 :   params.addParam<ReporterValueName>("inputs", "inputs", "Uncertain inputs to the model.");
      29         500 :   params.addParam<ReporterValueName>("tpm", "tpm", "The transition probability matrix.");
      30         500 :   params.addParam<ReporterValueName>("variance", "variance", "Model variance term.");
      31         500 :   params.addParam<ReporterValueName>(
      32             :       "noise", "noise", "Model noise term to pass to Likelihoods object.");
      33         500 :   params.addRequiredParam<SamplerName>("sampler", "The sampler object.");
      34         500 :   params.addRequiredParam<std::vector<UserObjectName>>("likelihoods", "Names of likelihoods.");
      35         250 :   return params;
      36           0 : }
      37             : 
      38         120 : PMCMCDecision::PMCMCDecision(const InputParameters & parameters)
      39             :   : GeneralReporter(parameters),
      40             :     LikelihoodInterface(parameters),
      41         120 :     _inputs(declareValue<std::vector<std::vector<Real>>>("inputs")),
      42         120 :     _tpm(declareValue<std::vector<Real>>("tpm")),
      43         120 :     _variance(declareValue<std::vector<Real>>("variance")),
      44         120 :     _noise(declareValue<Real>("noise")),
      45         120 :     _sampler(getSampler("sampler")),
      46         120 :     _pmcmc(dynamic_cast<const PMCMCBase *>(&_sampler)),
      47         120 :     _rnd_vec(_pmcmc->getRandomNumbers()),
      48         120 :     _new_var_samples(_pmcmc->getVarSamples()),
      49         120 :     _priors(_pmcmc->getPriors()),
      50         120 :     _var_prior(_pmcmc->getVarPrior()),
      51         120 :     _outputs_required(
      52         120 :         isParamValid("output_value")
      53         480 :             ? &declareValue<std::vector<Real>>("outputs_required", REPORTER_MODE_DISTRIBUTED)
      54             :             : nullptr),
      55         480 :     _output_value(isParamValid("output_value") ? &getReporterValue<std::vector<Real>>(
      56             :                                                      "output_value", REPORTER_MODE_DISTRIBUTED)
      57             :                                                : nullptr),
      58         120 :     _local_comm(_sampler.getLocalComm()),
      59         240 :     _check_step(std::numeric_limits<int>::max())
      60             : {
      61             :   // Filling the `likelihoods` vector with the user-provided distributions.
      62         360 :   for (const UserObjectName & name : getParam<std::vector<UserObjectName>>("likelihoods"))
      63         120 :     _likelihoods.push_back(getLikelihoodFunctionByName(name));
      64             : 
      65             :   // Check whether the selected sampler is an MCMC sampler or not
      66         120 :   if (!_pmcmc)
      67           0 :     paramError("sampler", "The selected sampler is not of type MCMC.");
      68             : 
      69             :   // Fetching the sampler characteristics
      70         120 :   _props = _pmcmc->getNumParallelProposals();
      71         120 :   _num_confg_values = _pmcmc->getNumberOfConfigValues();
      72         120 :   _num_confg_params = _pmcmc->getNumberOfConfigParams();
      73             : 
      74             :   // Resizing the data arrays to transmit to the output file
      75         120 :   _inputs.resize(_props);
      76         600 :   for (unsigned int i = 0; i < _props; ++i)
      77         480 :     _inputs[i].resize(_sampler.getNumberOfCols() - _num_confg_params);
      78         120 :   if (_outputs_required)
      79         120 :     _outputs_required->resize(_sampler.getNumberOfRows());
      80         120 :   _tpm.resize(_props);
      81         120 :   _variance.resize(_props);
      82         120 : }
      83             : 
      84             : void
      85         600 : PMCMCDecision::initialize()
      86             : {
      87        1800 :   if (!isParamValid("output_value") && !usingGP())
      88           0 :     paramError("output_value", "Value of the model output from the SubApp should be specified.");
      89         600 : }
      90             : 
      91             : void
      92         340 : PMCMCDecision::computeEvidence(std::vector<Real> & evidence, const DenseMatrix<Real> & input_matrix)
      93             : {
      94         340 :   std::vector<Real> out1(_num_confg_values);
      95         340 :   std::vector<Real> out2(_num_confg_values);
      96        1560 :   for (unsigned int i = 0; i < evidence.size(); ++i)
      97             :   {
      98        1220 :     evidence[i] = 0.0;
      99        3660 :     for (unsigned int j = 0; j < _priors.size(); ++j)
     100        2440 :       evidence[i] += (std::log(_priors[j]->pdf(input_matrix(i, j))) -
     101        2440 :                       std::log(_priors[j]->pdf(_data_prev(i, j))));
     102        3660 :     for (unsigned int j = 0; j < _num_confg_values; ++j)
     103             :     {
     104        2440 :       out1[j] = (*_outputs_required)[j * _props + i];
     105        2440 :       out2[j] = _outputs_prev[j * _props + i];
     106             :     }
     107        1220 :     if (_var_prior)
     108             :     {
     109         300 :       evidence[i] += (std::log(_var_prior->pdf(_new_var_samples[i])) -
     110         300 :                       std::log(_var_prior->pdf(_var_prev[i])));
     111         300 :       _noise = std::sqrt(_new_var_samples[i]);
     112         600 :       for (unsigned int j = 0; j < _likelihoods.size(); ++j)
     113         300 :         evidence[i] += _likelihoods[j]->function(out1);
     114         300 :       _noise = std::sqrt(_var_prev[i]);
     115         600 :       for (unsigned int j = 0; j < _likelihoods.size(); ++j)
     116         300 :         evidence[i] -= _likelihoods[j]->function(out2);
     117             :     }
     118             :     else
     119        1840 :       for (unsigned int j = 0; j < _likelihoods.size(); ++j)
     120         920 :         evidence[i] += (_likelihoods[j]->function(out1) - _likelihoods[j]->function(out2));
     121             :   }
     122         340 : }
     123             : 
     124             : void
     125         160 : PMCMCDecision::computeTransitionVector(std::vector<Real> & tv,
     126             :                                        const std::vector<Real> & /*evidence*/)
     127             : {
     128         160 :   tv.assign(_props, 1.0);
     129         160 : }
     130             : 
     131             : void
     132        1900 : PMCMCDecision::nextSamples(std::vector<Real> & req_inputs,
     133             :                            DenseMatrix<Real> & input_matrix,
     134             :                            const std::vector<Real> & tv,
     135             :                            const unsigned int & parallel_index)
     136             : {
     137        1900 :   if (tv[parallel_index] >= _rnd_vec[parallel_index])
     138             :   {
     139        4020 :     for (unsigned int k = 0; k < _sampler.getNumberOfCols() - _num_confg_params; ++k)
     140        2680 :       req_inputs[k] = input_matrix(parallel_index, k);
     141        1340 :     _variance[parallel_index] = _new_var_samples[parallel_index];
     142             :   }
     143             :   else
     144             :   {
     145        1680 :     for (unsigned int k = 0; k < _sampler.getNumberOfCols() - _num_confg_params; ++k)
     146             :     {
     147        1120 :       req_inputs[k] = _data_prev(parallel_index, k);
     148        1120 :       input_matrix(parallel_index, k) = _data_prev(parallel_index, k);
     149             :     }
     150         560 :     if (_var_prior)
     151         220 :       _variance[parallel_index] = _var_prev[parallel_index];
     152        1680 :     for (unsigned int k = 0; k < _num_confg_values; ++k)
     153        1120 :       (*_outputs_required)[k * _props + parallel_index] =
     154        1120 :           _outputs_prev[k * _props + parallel_index];
     155             :   }
     156        1900 : }
     157             : 
     158             : void
     159         600 : PMCMCDecision::execute()
     160             : {
     161         600 :   if (_sampler.getNumberOfLocalRows() == 0 || _check_step == _t_step)
     162             :   {
     163           0 :     _check_step = _t_step;
     164           0 :     return;
     165             :   }
     166             : 
     167             :   // Gather inputs and outputs from the sampler and subApps
     168         600 :   DenseMatrix<Real> data_in(_sampler.getNumberOfRows(), _sampler.getNumberOfCols());
     169        1800 :   for (dof_id_type ss = _sampler.getLocalRowBegin(); ss < _sampler.getLocalRowEnd(); ++ss)
     170             :   {
     171        1200 :     const auto data = _sampler.getNextLocalRow();
     172        4800 :     for (unsigned int j = 0; j < _sampler.getNumberOfCols(); ++j)
     173        3600 :       data_in(ss, j) = data[j];
     174        1200 :   }
     175         600 :   _local_comm.sum(data_in.get_values());
     176         600 :   if (!usingGP())
     177             :   {
     178         600 :     (*_outputs_required) = *_output_value;
     179         600 :     _local_comm.allgather((*_outputs_required));
     180             :   }
     181             : 
     182             :   // Compute the evidence and transitimkon vectors
     183         600 :   std::vector<Real> evidence(_props);
     184         600 :   if (_t_step > _pmcmc->decisionStep())
     185             :   {
     186         400 :     computeEvidence(evidence, data_in);
     187         400 :     computeTransitionVector(_tpm, evidence);
     188             :   }
     189             :   else
     190         200 :     _tpm.assign(_props, 1.0);
     191             : 
     192             :   // Accept/reject the proposed samples and assign the correct outputs
     193         600 :   std::vector<Real> req_inputs(_sampler.getNumberOfCols() - _num_confg_params);
     194        3000 :   for (unsigned int i = 0; i < _props; ++i)
     195             :   {
     196        2400 :     nextSamples(req_inputs, data_in, _tpm, i);
     197        2400 :     _inputs[i] = req_inputs;
     198             :   }
     199             : 
     200             :   // Compute the next seeds to facilitate proposals (not always required)
     201         600 :   nextSeeds();
     202             : 
     203             :   // Store data from previous step
     204         600 :   _data_prev = data_in;
     205         600 :   _var_prev = _variance;
     206         600 :   if (!usingGP())
     207         600 :     _outputs_prev = (*_outputs_required);
     208             : 
     209             :   // Track the current step
     210         600 :   _check_step = _t_step;
     211         600 : }

Generated by: LCOV version 1.14