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 : #pragma once 11 : 12 : #include "Shuffle.h" 13 : #include "DenseMatrix.h" 14 : #include "MooseObject.h" 15 : #include "MooseRandom.h" 16 : #include "SetupInterface.h" 17 : #include "DistributionInterface.h" 18 : #include "PerfGraphInterface.h" 19 : #include "SamplerInterface.h" 20 : #include "MultiApp.h" 21 : #include "VectorPostprocessorInterface.h" 22 : #include "ReporterInterface.h" 23 : #include "MooseRandomStateless.h" 24 : 25 : /** 26 : * This is the base class for Samplers as used within the Stochastic Tools module. 27 : * 28 : * A sampler is responsible for sampling distributions and providing an API for providing 29 : * the sample data to objects. The sampler is designed to handle any number of random number 30 : * generators. 31 : * 32 : * The main methods in this object is the getNextLocalRow/getSamples/getLocalSamples methods which 33 : * return the distribution samples. These methods will return the same results for each call 34 : * regardless of the number of calls, with getNextLocalRow being the exception because it is 35 : * designed be used in an iterative approach. 36 : * 37 : * Samplers support the use of "execute_on", which when called results in new set of random numbers, 38 : * thus after execute() calls to getSamples/getLocalSamples() methods will now produce a new set of 39 : * random numbers from calls prior to the execute() call. 40 : * 41 : * Not for MOOSE developers: Great care was taken to design the structure of this class to limit 42 : * access to the critical portions of this object while making it extensible. Please consider 43 : * carefully the impacts of altering the API. 44 : */ 45 : class Sampler : public MooseObject, 46 : public SetupInterface, 47 : public DistributionInterface, 48 : public PerfGraphInterface, 49 : public SamplerInterface, 50 : public VectorPostprocessorInterface, 51 : public ReporterInterface 52 : { 53 : public: 54 : enum class SampleMode 55 : { 56 : GLOBAL = 0, 57 : LOCAL = 1 58 : }; 59 : 60 : static InputParameters validParams(); 61 : Sampler(const InputParameters & parameters); 62 : 63 : // The public members define the API that is exposed to application developers that are using 64 : // Sampler objects to perform calculations, so be very careful when adding items here since 65 : // they are exposed to any other object via the SamplerInterface. 66 : // 67 : // It is also important to point out that when Sampler objects, when used, are not const. This is 68 : // due to the fact that calling the various get methods below must store various pieces of data as 69 : // well as control the state of the random number generators. 70 : 71 : ///@{ 72 : /** 73 : * Return the sampled complete or distributed sample data. 74 : * 75 : * Use these with caution as they can result in a large amount of memory use, the preferred 76 : * method for accessing Sampler data is the getNextLocalRow() method. 77 : */ 78 : DenseMatrix<Real> getGlobalSamples(); 79 : DenseMatrix<Real> getLocalSamples(); 80 : ///@} 81 : 82 : /** 83 : * Return the "next" local row. This is designed to be used within a loop using the 84 : * getLocalRowBegin/End methods as such: 85 : * 86 : * for (dof_id_type i = getLocalRowBegin(); i < getLocalRowEnd(); ++i) 87 : * std::vector<Real> row = getNextLocalRow(); 88 : * 89 : * This is the preferred method for accessing Sampler data. 90 : * 91 : * Calls to getNextLocalRow() will continue to return the next row of data until the last local 92 : * row has been reached, it will then start again at the beginning if called again. Also, calls 93 : * to getNextLocalRow() can be partial, followed by call(s) to getSamples or getLocalSamples. 94 : * Continued calls to getNextLocalRow() will still continue to give the next row as if the 95 : * other get calls were not made. However, when this occurs calls to restore and advance the 96 : * generators are made after each call to getSamples or getLocalSamples, so this generally 97 : * should be avoided. 98 : */ 99 : std::vector<Real> getNextLocalRow(); 100 : 101 : /** 102 : * Return the number of samples. 103 : * @return The total number of rows that exist in all DenseMatrix values from the 104 : * getSamples/getLocalSamples methods. 105 : */ 106 : dof_id_type getNumberOfRows() const; 107 : dof_id_type getNumberOfCols() const; 108 : dof_id_type getNumberOfLocalRows() const; 109 : 110 : ///@{ 111 : /** 112 : * Return the beginning/end local row index for this processor 113 : */ 114 : dof_id_type getLocalRowBegin() const; 115 : dof_id_type getLocalRowEnd() const; 116 : ///@} 117 : 118 : /** 119 : * Reference to rank configuration defining the partitioning of the sampler matrix 120 : * This is primarily used by MultiApps to ensure consistent partitioning 121 : */ 122 : const LocalRankConfig & getRankConfig(bool batch_mode) const 123 : { 124 : return batch_mode ? _rank_config.second : _rank_config.first; 125 : } 126 : 127 : /** 128 : * Returns true if the adaptive sampling is completed 129 : */ 130 0 : virtual bool isAdaptiveSamplingCompleted() const 131 : { 132 0 : mooseError("This method should be overridden in adaptive sampling classes."); 133 : return false; 134 : } 135 : 136 : /** 137 : * Return the parallel communicator 138 : */ 139 : libMesh::Parallel::Communicator & getLocalComm() { return _local_comm; } 140 : 141 : protected: 142 : // The following methods are the basic methods that should be utilized my most application 143 : // developers that are creating a custom Sampler. 144 : 145 : ///@{ 146 : /** 147 : * These methods must be called within the constructor of child classes to define the size of 148 : * the matrix to be created. 149 : */ 150 : void setNumberOfRows(dof_id_type n_rows); 151 : void setNumberOfCols(dof_id_type n_cols); 152 : ///@} 153 : 154 : /** 155 : * Set the number of seeds required by the sampler. The Sampler will generate 156 : * additional seeds as needed. This function should be called in the constructor 157 : * of child objects. 158 : * @param number The required number of random seeds, by default this is called with 1. 159 : */ 160 : void setNumberOfRandomSeeds(std::size_t number); 161 : 162 : /** 163 : * Get nth random number from the generator. 164 : * @param n 0-based index of the random number to generate 165 : * @param index The index of the seed, by default this is zero. To add additional seeds 166 : * indices call the setNumberOfRequiedRandomSeeds method. 167 : * 168 : * @return A double for the random number, this is double because MooseRandom class uses double. 169 : */ 170 : Real getRand(std::size_t n, unsigned int index = 0) const; 171 : 172 : /** 173 : * Get nth random integer from the generator within the specified range [lower, upper) 174 : * @param n 0-based index of the random number to generate 175 : * @param lower Lower bounds 176 : * @param upper Upper bounds 177 : * @param index The index of the seed, by default this is zero. To add additional seeds 178 : * indices call the setNumberOfRequiedRandomSeeds method. 179 : * 180 : * @return A integer for the random number 181 : */ 182 : unsigned int 183 : getRandl(std::size_t n, unsigned int lower, unsigned int upper, unsigned int index = 0) const; 184 : 185 : /** 186 : * Base class must override this method to supply the sample distribution data. 187 : * @param row_index The row index of sample value to compute. 188 : * @param col_index The column index of sample value to compute. 189 : * @return The value for the given row and column. 190 : */ 191 : virtual Real computeSample(dof_id_type row_index, dof_id_type col_index) = 0; 192 : 193 : // The following methods are advanced methods that should not be needed by application developers, 194 : // but exist for special cases. 195 : 196 : ///@{ 197 : /** 198 : * Methods to populate the global or local sample matrix. 199 : * @param matrix The correctly sized matrix of sample values to populate 200 : * 201 : * These methods should not be called directly, each is automatically called by the public 202 : * getGlobalSamples() or getLocalSamples() methods. 203 : */ 204 : virtual void computeSampleMatrix(DenseMatrix<Real> & matrix); 205 : virtual void computeLocalSampleMatrix(DenseMatrix<Real> & matrix); 206 : ///@} 207 : 208 : ///@{ 209 : /** 210 : * Method to populate a complete row of sample data. 211 : * @param i The global row index to compute 212 : * @param data The correctly sized vector of sample value to poplulate 213 : 214 : * This method should not be called directly, it is automatically called by the public 215 : * getGlobalSamples(), getLocalSamples(), or getNextLocalRow() methods. 216 : */ 217 : virtual void computeSampleRow(dof_id_type i, std::vector<Real> & data); 218 : 219 : /** 220 : * Method for advancing the random number generator(s) by the supplied number or calls to rand(). 221 : */ 222 : virtual void advanceGenerators(const dof_id_type count); 223 : virtual void advanceGenerator(const unsigned int seed_index, const dof_id_type count); 224 : void setAutoAdvanceGenerators(const bool state); 225 : 226 : //@{ 227 : /** 228 : * Callbacks for before and after execute. 229 : * 230 : * These were added to support of dynamic sampler sizes. Recall that execute is simply to advance 231 : * the state of the generators such that the next sample will be unique. These methods allow 232 : * operations before and after the call to generator advancement. 233 : */ 234 0 : virtual void executeSetUp() {} 235 271 : virtual void executeTearDown() {} 236 : ///@} 237 : 238 : /** 239 : * This is where the sampler partitioning is defined. It is NOT recommended to 240 : * override this function unless you know EXACTLY what you are doing 241 : */ 242 : virtual LocalRankConfig constructRankConfig(bool batch_mode) const; 243 : 244 : /// The minimum number of processors that are associated with a set of rows 245 : const dof_id_type _min_procs_per_row; 246 : /// The maximum number of processors that are associated with a set of rows 247 : const dof_id_type _max_procs_per_row; 248 : 249 : /// Communicator that was split based on samples that have rows 250 : libMesh::Parallel::Communicator _local_comm; 251 : 252 : private: 253 : ///@{ 254 : /** 255 : * Functions called by MOOSE to setup the Sampler for use. The primary purpose is to partition 256 : * the DenseMatrix rows for parallel distribution. A separate methods are required so that the 257 : * set methods can be called within the constructors of child objects, see 258 : * FEProblemBase::addSampler method. The reinit was added to support re-partitioning to allow 259 : * for dynamic changes in sampler size. 260 : * 261 : * This init() method is called by FEProblemBase::addSampler; it should not be called elsewhere. 262 : */ 263 : void init(); // sets up MooseRandom 264 : void reinit(); // partitions sampler output 265 : ///@} 266 : friend void FEProblemBase::addSampler(const std::string & type, 267 : const std::string & name, 268 : InputParameters & parameters); 269 : /** 270 : * Advance MooseRandomStateless generators so that new calls to 271 : * sample methods will create new numbers. 272 : */ 273 : void execute(); 274 : friend void FEProblemBase::objectExecuteHelper<Sampler>(const std::vector<Sampler *> & objects); 275 : 276 : /** 277 : * Helper function for reinit() errors. 278 : **/ 279 : void checkReinitStatus() const; 280 : 281 : /** 282 : * Advance method for internal use that considers the auto advance flag. 283 : */ 284 : void advanceGeneratorsInternal(const dof_id_type count); 285 : 286 : /// Random number generators, don't give users access. Control it via the interface from this class. 287 : std::vector<std::unique_ptr<MooseRandomStateless>> _generators; 288 : 289 : /// Number of rows for this processor 290 : dof_id_type _n_local_rows; 291 : 292 : /// Global row index for start of data for this processor 293 : dof_id_type _local_row_begin; 294 : 295 : /// Global row index for end of data for this processor 296 : dof_id_type _local_row_end; 297 : 298 : /// Total number of rows in the sample matrix 299 : dof_id_type _n_rows; 300 : 301 : /// Total number of columns in the sample matrix 302 : dof_id_type _n_cols; 303 : 304 : /// Number of seeds 305 : std::size_t _n_seeds; 306 : 307 : /// Iterator index for getNextLocalRow method 308 : dof_id_type _next_local_row; 309 : 310 : /// Flag for restoring state during getNextLocalRow iteration 311 : bool _next_local_row_requires_state_restore; 312 : 313 : /// Flag to indicate if the init method for this class was called 314 : bool _initialized; 315 : 316 : /// Flag to indicate if the reinit method should be called during execute 317 : bool _needs_reinit; 318 : 319 : /// Flag for initial execute to allow the first set of random numbers to be always be the same 320 : bool _has_executed; 321 : 322 : /// Max number of entries for matrix returned by getGlobalSamples 323 : const dof_id_type _limit_get_global_samples; 324 : 325 : /// Max number of entries for matrix returned by getLocalSamples 326 : const dof_id_type _limit_get_local_samples; 327 : 328 : /// Max number of entries for matrix returned by getNextLocalRow 329 : const dof_id_type _limit_get_next_local_row; 330 : 331 : /// The partitioning of the sampler matrix, built in reinit() 332 : /// first is for normal mode and send is for batch mode 333 : std::pair<LocalRankConfig, LocalRankConfig> _rank_config; 334 : 335 : /// Flag for disabling automatic generator advancing 336 : bool _auto_advance_generators; 337 : };