LCOV - code coverage report
Current view: top level - src/samplers - MorrisSampler.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #31405 (292dce) with base fef103 Lines: 62 63 98.4 %
Date: 2025-09-04 07:57:52 Functions: 6 6 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 "MorrisSampler.h"
      11             : #include "Distribution.h"
      12             : 
      13             : registerMooseObject("StochasticToolsApp", MorrisSampler);
      14             : 
      15             : InputParameters
      16         408 : MorrisSampler::validParams()
      17             : {
      18         408 :   InputParameters params = Sampler::validParams();
      19         408 :   params.addClassDescription("Morris variance-based sensitivity analysis Sampler.");
      20         816 :   params.addRequiredParam<std::vector<DistributionName>>(
      21             :       "distributions",
      22             :       "The distribution names to be sampled, the number of distributions provided defines the "
      23             :       "number of columns per matrix.");
      24         816 :   params.addRequiredRangeCheckedParam<dof_id_type>(
      25             :       "trajectories",
      26             :       "trajectories > 0",
      27             :       "Number of unique trajectories to perform. The higher number of these usually means a more "
      28             :       "accurate sensitivity evaluation, but it is proportional to the number of required model "
      29             :       "evaluations: 'trajectoris' x (number of 'distributions' + 1).");
      30        1224 :   params.addRangeCheckedParam<unsigned int>(
      31             :       "levels",
      32         816 :       4,
      33             :       "levels % 2 = 0 & levels > 0",
      34             :       "The number of levels in the sampling. This determines the discretization of the input "
      35             :       "space, more levels means finer discretization and more possible model perturbations.");
      36         408 :   return params;
      37           0 : }
      38             : 
      39         235 : MorrisSampler::MorrisSampler(const InputParameters & parameters)
      40             :   : Sampler(parameters),
      41         235 :     _num_trajectories(getParam<dof_id_type>("trajectories")),
      42         705 :     _num_levels(getParam<unsigned int>("levels"))
      43             : 
      44             : {
      45        1451 :   for (const auto & name : getParam<std::vector<DistributionName>>("distributions"))
      46         981 :     _distributions.push_back(&getDistributionByName(name));
      47             : 
      48         235 :   setNumberOfCols(_distributions.size());
      49         235 :   setNumberOfRows(_num_trajectories * (_distributions.size() + 1));
      50         235 : }
      51             : 
      52             : void
      53         392 : MorrisSampler::sampleSetUp(const Sampler::SampleMode /*mode*/)
      54             : {
      55         392 :   const dof_id_type nc = getNumberOfCols();
      56         392 :   _b = RealEigenMatrix::Ones(nc + 1, nc).triangularView<Eigen::StrictlyLower>();
      57         392 :   _pstar.resize(nc, nc);
      58         392 :   _j.setOnes(nc + 1, nc);
      59         392 :   _dstar.resize(nc, nc);
      60         392 :   _xstar.resize(nc + 1, nc);
      61         392 :   _bstar.resize(nc + 1, nc);
      62         392 : }
      63             : 
      64             : Real
      65     1932480 : MorrisSampler::computeSample(dof_id_type row_index, dof_id_type col_index)
      66             : {
      67     1932480 :   const dof_id_type traj_ind = row_index % (getNumberOfCols() + 1);
      68     1932480 :   if (traj_ind == 0 && col_index == 0)
      69       46200 :     updateBstar();
      70     1932480 :   return _distributions[col_index]->quantile(_bstar(traj_ind, col_index));
      71             : }
      72             : 
      73             : void
      74       46200 : MorrisSampler::updateBstar()
      75             : {
      76       46200 :   const dof_id_type nc = getNumberOfCols(); // convenience
      77       46200 :   _pstar.setZero();
      78             :   // Which parameter to perturb
      79       46200 :   std::vector<dof_id_type> pchoice(nc);
      80             :   std::iota(pchoice.begin(), pchoice.end(), 0);
      81      322608 :   for (dof_id_type c = 0; c < nc; ++c)
      82             :   {
      83      276408 :     const unsigned int ind = nc > 1 ? getRandl(0, 0, pchoice.size()) : 0;
      84      276408 :     _pstar(pchoice[ind], c) = 1.0;
      85             :     pchoice.erase(pchoice.begin() + ind);
      86             :   }
      87             : 
      88       46200 :   _dstar.setZero();
      89             :   // Direction of perturbation
      90      322608 :   for (dof_id_type c = 0; c < nc; ++c)
      91      417890 :     _dstar(c, c) = getRand() < 0.5 ? -1.0 : 1.0;
      92             : 
      93             :   // Initial value
      94      322608 :   for (dof_id_type c = 0; c < nc; ++c)
      95             :   {
      96      276408 :     const auto lind = getRandl(0, 0, _num_levels / 2);
      97      276408 :     _xstar.col(c).setConstant((Real)lind * 1.0 / ((Real)_num_levels - 1));
      98             :   }
      99             : 
     100             :   _bstar =
     101       46200 :       _xstar + _num_levels / 4.0 / (_num_levels - 1) * ((2.0 * _b * _pstar - _j) * _dstar + _j);
     102             : 
     103             :   // This matrix represent _n_cols * (_n_cols + 1) samples, but so far we have only
     104             :   // advanced the generator 3 * _n_cols times. For the generator state restore
     105             :   // to work properly, we need to finish advancing the generator
     106       46200 :   if (nc > 2)
     107       46200 :     advanceGenerator(0, nc * (nc - 2));
     108       46200 : }
     109             : 
     110             : LocalRankConfig
     111         470 : MorrisSampler::constructRankConfig(bool batch_mode) const
     112             : {
     113         470 :   std::vector<LocalRankConfig> all_rc(processor_id() + 1);
     114        1410 :   for (processor_id_type r = 0; r <= processor_id(); ++r)
     115         940 :     all_rc[r] = rankConfig(
     116         940 :         r, n_processors(), _num_trajectories, _min_procs_per_row, _max_procs_per_row, batch_mode);
     117             :   LocalRankConfig & rc = all_rc.back();
     118             : 
     119         470 :   rc.num_local_sims *= _distributions.size() + 1;
     120             :   bool found_first = false;
     121        1410 :   for (auto it = all_rc.rbegin(); it != all_rc.rend(); ++it)
     122         940 :     if (it->is_first_local_rank)
     123             :     {
     124         820 :       if (found_first)
     125         350 :         rc.first_local_sim_index += it->num_local_sims * _distributions.size();
     126             :       else
     127             :         found_first = true;
     128             :     }
     129             : 
     130         470 :   if (!batch_mode)
     131             :   {
     132         235 :     rc.num_local_apps = rc.num_local_sims;
     133         235 :     rc.first_local_app_index = rc.first_local_sim_index;
     134             :   }
     135             : 
     136         470 :   return rc;
     137         470 : }

Generated by: LCOV version 1.14