LCOV - code coverage report
Current view: top level - src/samplers - Sampler.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 871361 Lines: 196 212 92.5 %
Date: 2025-06-05 18:02:15 Functions: 25 27 92.6 %
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             : // STL includes
      11             : #include <iterator>
      12             : 
      13             : // MOOSE includes
      14             : #include "Sampler.h"
      15             : 
      16             : InputParameters
      17       15007 : Sampler::validParams()
      18             : {
      19       15007 :   InputParameters params = MooseObject::validParams();
      20       15007 :   params += SetupInterface::validParams();
      21       15007 :   params += DistributionInterface::validParams();
      22       15007 :   params.addClassDescription("A base class for distribution sampling.");
      23             : 
      24       15007 :   ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
      25       15007 :   exec_enum.addAvailableFlags(EXEC_PRE_MULTIAPP_SETUP);
      26             : 
      27       15007 :   params.addParam<unsigned int>("seed", 0, "Random number generator initial seed");
      28       15007 :   params.registerBase("Sampler");
      29       15007 :   params.registerSystemAttributeName("Sampler");
      30             : 
      31             :   // Define the allowable limits for data returned by getSamples/getLocalSamples/getNextLocalRow
      32             :   // to prevent system for going over allowable limits. The DenseMatrix object uses unsigned int
      33             :   // for size definition, so as start the limits will be based the max of unsigned int. Note,
      34             :   // the values here are the limits of the number of items in the complete container. dof_id_type
      35             :   // is used just in case in the future we need more.
      36       45021 :   params.addParam<dof_id_type>("limit_get_global_samples",
      37       30014 :                                0.1 * std::numeric_limits<unsigned int>::max(),
      38             :                                "The maximum allowed number of items in the DenseMatrix returned by "
      39             :                                "getGlobalSamples method.");
      40       45021 :   params.addParam<dof_id_type>(
      41             :       "limit_get_local_samples",
      42       30014 :       0.1 * std::numeric_limits<unsigned int>::max(),
      43             :       "The maximum allowed number of items in the DenseMatrix returned by getLocalSamples method.");
      44       45021 :   params.addParam<dof_id_type>(
      45             :       "limit_get_next_local_row",
      46       30014 :       0.1 * std::numeric_limits<unsigned int>::max(),
      47             :       "The maximum allowed number of items in the std::vector returned by getNextLocalRow method.");
      48             : 
      49       45021 :   params.addParam<unsigned int>(
      50             :       "min_procs_per_row",
      51       30014 :       1,
      52             :       "This will ensure that the sampler is partitioned properly when "
      53             :       "'MultiApp/*/min_procs_per_app' is specified. It is not recommended to use otherwise.");
      54       45021 :   params.addParam<unsigned int>(
      55             :       "max_procs_per_row",
      56       30014 :       std::numeric_limits<unsigned int>::max(),
      57             :       "This will ensure that the sampler is partitioned properly when "
      58             :       "'MultiApp/*/max_procs_per_app' is specified. It is not recommended to use otherwise.");
      59       15007 :   return params;
      60           0 : }
      61             : 
      62         355 : Sampler::Sampler(const InputParameters & parameters)
      63             :   : MooseObject(parameters),
      64             :     SetupInterface(this),
      65             :     DistributionInterface(this),
      66             :     PerfGraphInterface(this),
      67             :     SamplerInterface(this),
      68             :     VectorPostprocessorInterface(this),
      69             :     ReporterInterface(this),
      70         710 :     _min_procs_per_row(getParam<unsigned int>("min_procs_per_row") > n_processors()
      71         355 :                            ? n_processors()
      72         355 :                            : getParam<unsigned int>("min_procs_per_row")),
      73         355 :     _max_procs_per_row(getParam<unsigned int>("max_procs_per_row")),
      74         355 :     _n_rows(0),
      75         355 :     _n_cols(0),
      76         355 :     _n_seeds(1),
      77         355 :     _next_local_row_requires_state_restore(true),
      78         355 :     _initialized(false),
      79         355 :     _needs_reinit(true),
      80         355 :     _has_executed(false),
      81         355 :     _limit_get_global_samples(getParam<dof_id_type>("limit_get_global_samples")),
      82         355 :     _limit_get_local_samples(getParam<dof_id_type>("limit_get_local_samples")),
      83         355 :     _limit_get_next_local_row(getParam<dof_id_type>("limit_get_next_local_row")),
      84        1065 :     _auto_advance_generators(true)
      85             : {
      86         355 : }
      87             : 
      88             : void
      89         343 : Sampler::init()
      90             : {
      91             :   // The init() method is private so it is un-likely to be called, but just in case the following
      92             :   // was added to help avoid future mistakes.
      93         343 :   if (_initialized)
      94           0 :     mooseError("The Sampler::init() method is called automatically and should not be called.");
      95             : 
      96             :   // Initialize the parallel partition of sample to return
      97         343 :   reinit();
      98             : 
      99             :   // Seed the "master" seed generator
     100         343 :   const unsigned int seed = getParam<unsigned int>("seed");
     101         343 :   MooseRandom seed_generator;
     102         343 :   seed_generator.seed(0, seed);
     103             : 
     104             :   // See the "secondary" generator that will be used for the random number generation
     105         686 :   for (std::size_t i = 0; i < _n_seeds; ++i)
     106         343 :     _generator.seed(i, seed_generator.randl(0));
     107             : 
     108             :   // Save the initial state
     109         343 :   saveGeneratorState();
     110             : 
     111             :   // Mark class as initialized, which locks out certain methods
     112         343 :   _initialized = true;
     113         343 : }
     114             : 
     115             : void
     116         348 : Sampler::reinit()
     117             : {
     118         348 :   _rank_config.first = constructRankConfig(false);
     119         348 :   _rank_config.second = constructRankConfig(true);
     120         348 :   if (_rank_config.first.num_local_sims != _rank_config.second.num_local_sims ||
     121         348 :       _rank_config.first.first_local_sim_index != _rank_config.second.first_local_sim_index ||
     122         348 :       _rank_config.first.is_first_local_rank != _rank_config.second.is_first_local_rank)
     123           0 :     mooseError("Sampler has inconsistent partitionings for normal and batch mode.");
     124             : 
     125         348 :   _n_local_rows = _rank_config.first.is_first_local_rank ? _rank_config.first.num_local_sims : 0;
     126         348 :   _local_row_begin = _rank_config.first.first_local_sim_index;
     127         348 :   _local_row_end = _local_row_begin + _n_local_rows;
     128             : 
     129             :   // Set the next row iterator index
     130         348 :   _next_local_row = _local_row_begin;
     131             : 
     132             :   // Create communicator that only has processors with rows
     133         348 :   _communicator.split(_n_local_rows > 0 ? 1 : MPI_UNDEFINED, processor_id(), _local_comm);
     134             : 
     135             :   // Update reinit() flag (see execute method)
     136         348 :   _needs_reinit = false;
     137         348 : }
     138             : 
     139             : LocalRankConfig
     140         696 : Sampler::constructRankConfig(bool batch_mode) const
     141             : {
     142         696 :   return rankConfig(
     143        1392 :       processor_id(), n_processors(), _n_rows, _min_procs_per_row, _max_procs_per_row, batch_mode);
     144             : }
     145             : 
     146             : void
     147         392 : Sampler::setNumberOfRows(dof_id_type n_rows)
     148             : {
     149         392 :   if (n_rows == 0)
     150           4 :     mooseError("The number of rows cannot be zero.");
     151             : 
     152         388 :   _needs_reinit = true;
     153         388 :   _n_rows = n_rows;
     154         388 : }
     155             : 
     156             : void
     157         351 : Sampler::setNumberOfCols(dof_id_type n_cols)
     158             : {
     159         351 :   if (n_cols == 0)
     160           4 :     mooseError("The number of columns cannot be zero.");
     161             : 
     162         347 :   _needs_reinit = true;
     163         347 :   _n_cols = n_cols;
     164         347 : }
     165             : 
     166             : void
     167           8 : Sampler::setNumberOfRandomSeeds(std::size_t n_seeds)
     168             : {
     169           8 :   if (_initialized)
     170           4 :     mooseError("The 'setNumberOfRandomSeeds()' method can not be called after the Sampler has been "
     171             :                "initialized; "
     172             :                "this method should be called in the constructor of the Sampler object.");
     173             : 
     174           4 :   if (n_seeds == 0)
     175           4 :     mooseError("The number of seeds must be larger than zero.");
     176             : 
     177           0 :   _n_seeds = n_seeds;
     178           0 : }
     179             : 
     180             : void
     181          55 : Sampler::execute()
     182             : {
     183          55 :   executeSetUp();
     184          23 :   if (_needs_reinit)
     185           5 :     reinit();
     186             : 
     187          23 :   if (_has_executed)
     188             :   {
     189           0 :     restoreGeneratorState();
     190           0 :     advanceGeneratorsInternal(_n_rows * _n_cols);
     191             :   }
     192          23 :   saveGeneratorState();
     193          23 :   executeTearDown();
     194          23 :   _has_executed = true;
     195          23 : }
     196             : 
     197             : DenseMatrix<Real>
     198         194 : Sampler::getGlobalSamples()
     199             : {
     200         194 :   TIME_SECTION("getGlobalSamples", 1, "Retrieving Global Samples");
     201             : 
     202         194 :   checkReinitStatus();
     203             : 
     204         190 :   if (_n_rows * _n_cols > _limit_get_global_samples)
     205           4 :     paramError("limit_get_global_samples",
     206             :                "The number of entries in the DenseMatrix (",
     207           4 :                _n_rows * _n_cols,
     208             :                ") exceeds the allowed limit of ",
     209           4 :                _limit_get_global_samples,
     210             :                ".");
     211             : 
     212         186 :   _next_local_row_requires_state_restore = true;
     213         186 :   restoreGeneratorState();
     214         186 :   sampleSetUp(SampleMode::GLOBAL);
     215         186 :   DenseMatrix<Real> output(_n_rows, _n_cols);
     216         186 :   computeSampleMatrix(output);
     217         182 :   sampleTearDown(SampleMode::GLOBAL);
     218         364 :   return output;
     219         182 : }
     220             : 
     221             : DenseMatrix<Real>
     222         137 : Sampler::getLocalSamples()
     223             : {
     224         137 :   TIME_SECTION("getLocalSamples", 1, "Retrieving Local Samples");
     225             : 
     226         137 :   checkReinitStatus();
     227             : 
     228         133 :   if (_n_local_rows * _n_cols > _limit_get_local_samples)
     229           7 :     paramError("limit_get_local_samples",
     230             :                "The number of entries in the DenseMatrix (",
     231           7 :                _n_local_rows * _n_cols,
     232             :                ") exceeds the allowed limit of ",
     233           7 :                _limit_get_local_samples,
     234             :                ".");
     235             : 
     236         126 :   DenseMatrix<Real> output(_n_local_rows, _n_cols);
     237         126 :   if (_n_local_rows == 0)
     238           0 :     return output;
     239             : 
     240         126 :   _next_local_row_requires_state_restore = true;
     241         126 :   restoreGeneratorState();
     242         126 :   sampleSetUp(SampleMode::LOCAL);
     243         126 :   computeLocalSampleMatrix(output);
     244         126 :   sampleTearDown(SampleMode::LOCAL);
     245         126 :   return output;
     246         126 : }
     247             : 
     248             : std::vector<Real>
     249     1400400 : Sampler::getNextLocalRow()
     250             : {
     251     1400400 :   checkReinitStatus();
     252             : 
     253     1400396 :   if (_next_local_row_requires_state_restore)
     254             :   {
     255          95 :     restoreGeneratorState();
     256          95 :     sampleSetUp(SampleMode::LOCAL);
     257          95 :     advanceGeneratorsInternal(_next_local_row * _n_cols);
     258          95 :     _next_local_row_requires_state_restore = false;
     259             : 
     260          95 :     if (_n_cols > _limit_get_next_local_row)
     261           4 :       paramError("limit_get_next_local_row",
     262             :                  "The number of entries in the std::vector (",
     263             :                  _n_cols,
     264             :                  ") exceeds the allowed limit of ",
     265           4 :                  _limit_get_next_local_row,
     266             :                  ".");
     267             :   }
     268             : 
     269     1400392 :   std::vector<Real> output(_n_cols);
     270     1400392 :   computeSampleRow(_next_local_row, output);
     271             :   mooseAssert(output.size() == _n_cols, "The row of sample data is not sized correctly.");
     272     1400392 :   _next_local_row++;
     273             : 
     274     1400392 :   if (_next_local_row == _local_row_end)
     275             :   {
     276          84 :     advanceGeneratorsInternal((_n_rows - _local_row_end) * _n_cols);
     277          84 :     sampleTearDown(SampleMode::LOCAL);
     278          84 :     _next_local_row = _local_row_begin;
     279          84 :     _next_local_row_requires_state_restore = true;
     280             :   }
     281             : 
     282     1400392 :   return output;
     283           0 : }
     284             : 
     285             : void
     286         186 : Sampler::computeSampleMatrix(DenseMatrix<Real> & matrix)
     287             : {
     288         186 :   TIME_SECTION("computeSampleMatrix", 2, "Computing Sample Matrix");
     289             : 
     290     3501789 :   for (dof_id_type i = 0; i < _n_rows; ++i)
     291             :   {
     292     3501607 :     std::vector<Real> row(_n_cols, 0);
     293     3501607 :     computeSampleRow(i, row);
     294             :     mooseAssert(row.size() == _n_cols, "The row of sample data is not sized correctly.");
     295             :     mooseAssert(!_needs_reinit,
     296             :                 "Changing the size of the sample must not occur during matrix access.");
     297     3501603 :     std::copy(row.begin(), row.end(), matrix.get_values().begin() + i * _n_cols);
     298     3501603 :   }
     299         182 : }
     300             : 
     301             : void
     302         126 : Sampler::computeLocalSampleMatrix(DenseMatrix<Real> & matrix)
     303             : {
     304         126 :   TIME_SECTION("computeLocalSampleMatrix", 2, "Computing Local Sample Matrix");
     305             : 
     306         126 :   advanceGeneratorsInternal(_local_row_begin * _n_cols);
     307     1400812 :   for (dof_id_type i = _local_row_begin; i < _local_row_end; ++i)
     308             :   {
     309     1400686 :     std::vector<Real> row(_n_cols, 0);
     310     1400686 :     computeSampleRow(i, row);
     311             :     mooseAssert(row.size() == _n_cols, "The row of sample data is not sized correctly.");
     312             :     mooseAssert(!_needs_reinit,
     313             :                 "Changing the size of the sample must not occur during matrix access.");
     314     1400686 :     std::copy(
     315     1400686 :         row.begin(), row.end(), matrix.get_values().begin() + ((i - _local_row_begin) * _n_cols));
     316     1400686 :   }
     317         126 :   advanceGeneratorsInternal((_n_rows - _local_row_end) * _n_cols);
     318         126 : }
     319             : 
     320             : void
     321     6302685 : Sampler::computeSampleRow(dof_id_type i, std::vector<Real> & data)
     322             : {
     323    12623888 :   for (dof_id_type j = 0; j < _n_cols; ++j)
     324             :   {
     325     6321207 :     data[j] = computeSample(i, j);
     326             :     mooseAssert(!_needs_reinit,
     327             :                 "Changing the size of the sample must not occur during matrix access.");
     328             :   }
     329     6302681 : }
     330             : 
     331             : void
     332         431 : Sampler::advanceGenerators(const dof_id_type count)
     333             : {
     334         431 :   TIME_SECTION("advanceGenerators", 2, "Advancing Generators");
     335             : 
     336         862 :   for (std::size_t j = 0; j < _generator.size(); ++j)
     337         431 :     advanceGenerator(j, count);
     338         431 : }
     339             : void
     340         431 : Sampler::advanceGenerator(const unsigned int seed_index, const dof_id_type count)
     341             : {
     342     4207879 :   for (std::size_t i = 0; i < count; ++i)
     343     4207448 :     getRand(seed_index);
     344         431 : }
     345             : 
     346             : void
     347         431 : Sampler::advanceGeneratorsInternal(const dof_id_type count)
     348             : {
     349         431 :   if (_auto_advance_generators)
     350         431 :     advanceGenerators(count);
     351         431 : }
     352             : 
     353             : void
     354           0 : Sampler::setAutoAdvanceGenerators(const bool state)
     355             : {
     356           0 :   _auto_advance_generators = state;
     357           0 : }
     358             : 
     359             : double
     360     4219208 : Sampler::getRand(const unsigned int index)
     361             : {
     362             :   mooseAssert(index < _generator.size(), "The seed number index does not exists.");
     363     4219208 :   return _generator.rand(index);
     364             : }
     365             : 
     366             : uint32_t
     367           0 : Sampler::getRandl(unsigned int index, uint32_t lower, uint32_t upper)
     368             : {
     369             :   mooseAssert(index < _generator.size(), "The seed number index does not exists.");
     370           0 :   return _generator.randl(index, lower, upper);
     371             : }
     372             : 
     373             : dof_id_type
     374          41 : Sampler::getNumberOfRows() const
     375             : {
     376          41 :   checkReinitStatus();
     377          37 :   return _n_rows;
     378             : }
     379             : 
     380             : dof_id_type
     381           4 : Sampler::getNumberOfCols() const
     382             : {
     383           4 :   checkReinitStatus();
     384           0 :   return _n_cols;
     385             : }
     386             : 
     387             : dof_id_type
     388           4 : Sampler::getNumberOfLocalRows() const
     389             : {
     390           4 :   checkReinitStatus();
     391           0 :   return _n_local_rows;
     392             : }
     393             : 
     394             : dof_id_type
     395          92 : Sampler::getLocalRowBegin() const
     396             : {
     397          92 :   checkReinitStatus();
     398          88 :   return _local_row_begin;
     399             : }
     400             : 
     401             : dof_id_type
     402     1400435 : Sampler::getLocalRowEnd() const
     403             : {
     404     1400435 :   checkReinitStatus();
     405     1400431 :   return _local_row_end;
     406             : }
     407             : 
     408             : void
     409     2801307 : Sampler::checkReinitStatus() const
     410             : {
     411     2801307 :   if (_needs_reinit)
     412          32 :     mooseError("A call to 'setNumberOfRows()/Columns()' was made after initialization, as such the "
     413             :                "expected Sampler output has changed and a new sample must be created. However, a "
     414             :                "call to Sampler::reinit() was not performed. The renit() method is automatically "
     415             :                "called during Sampler execution, which occurs according to the 'execute_on' "
     416             :                "settings of the Sampler object. An adjustment to this parameter may be required. "
     417             :                "It is recommended that calls to 'setNumberOfRows()/Columns() occur within the "
     418             :                "Sampler::executeSetUp() method; this will ensure that the reinitialize is handled "
     419             :                "correctly. Have a nice day.");
     420     2801275 : }

Generated by: LCOV version 1.14