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 "RandomData.h" 11 : #include "FEProblem.h" 12 : #include "MooseMesh.h" 13 : #include "RandomInterface.h" 14 : 15 : const unsigned int MASTER = std::numeric_limits<unsigned int>::max(); 16 : 17 419 : RandomData::RandomData(FEProblemBase & fe_problem, const RandomInterface & random_interface) 18 : : RandomData(fe_problem, 19 419 : random_interface.isNodal(), 20 838 : random_interface.getResetOnTime(), 21 838 : random_interface.getMasterSeed()) 22 : { 23 419 : } 24 : 25 1411 : RandomData::RandomData(FEProblemBase & fe_problem, 26 : bool is_nodal, 27 : ExecFlagType reset_on, 28 1411 : unsigned int seed) 29 1411 : : _rd_problem(fe_problem), 30 1411 : _rd_mesh(fe_problem.mesh()), 31 1411 : _is_nodal(is_nodal), 32 1411 : _reset_on(reset_on), 33 1411 : _master_seed(seed), 34 1411 : _current_master_seed(std::numeric_limits<unsigned int>::max()), 35 2822 : _new_seed(0) 36 : { 37 1411 : } 38 : 39 : unsigned int 40 0 : RandomData::getSeed(dof_id_type id) 41 : { 42 : mooseAssert(_seeds.find(id) != _seeds.end(), 43 : "Call to updateSeeds() is stale! Check your initialize() or timestepSetup() calls"); 44 : 45 0 : return _seeds[id]; 46 : } 47 : 48 : void 49 19210 : RandomData::updateSeeds(ExecFlagType exec_flag) 50 : { 51 : /** 52 : * Set the seed. This part is critical! If this is done incorrectly, it may lead to difficult to 53 : * detect patterns in your random numbers either within a single run or over the course of 54 : * several runs. We will default to _master_seed + the current time step. 55 : */ 56 19210 : if (exec_flag == EXEC_INITIAL) 57 1330 : _new_seed = _master_seed; 58 : else 59 17880 : _new_seed = _master_seed + _rd_problem.timeStep(); 60 : /** 61 : * case EXEC_TIMESTEP_BEGIN: // reset and advance every timestep 62 : * case EXEC_TIMESTEP_END: // reset and advance every timestep 63 : * case EXEC_LINEAR: // Reset every residual, advance every timestep 64 : * case EXEC_NONLINEAR: // Reset every Jacobian, advance every timestep 65 : */ 66 : 67 : // If the _new_seed has been updated, we need to update all of the generators 68 19210 : if (_new_seed != _current_master_seed) 69 : { 70 2845 : _current_master_seed = _new_seed; 71 2845 : updateGenerators(); 72 2845 : _generator.saveState(); // Save states so that we can reset on demand 73 : } 74 : 75 19210 : if (_reset_on == exec_flag) 76 12850 : _generator.restoreState(); // Restore states here 77 19210 : } 78 : 79 : void 80 2845 : RandomData::updateGenerators() 81 : { 82 : // Set the master seed and repopulate all of the child generators 83 2845 : _generator.seed(MASTER, _current_master_seed); 84 : 85 : /** 86 : * When using parallel mesh it's not worth generating parallel consistent numbers. 87 : * Each processor may not be aware of which entities belong on another mesh. We do have 88 : * to be careful to *not* generate the same patterns on different processors however. 89 : * To do that, we will use the MASTER generator to generate new master seeds for each 90 : * processor based on their individual processor ids before generating seeds for 91 : * the mesh entities. 92 : */ 93 2845 : if (_rd_mesh.isDistributedMesh()) 94 : { 95 500 : unsigned int parallel_seed = 0; 96 1500 : for (processor_id_type proc_id = 0; proc_id < _rd_problem.n_processors(); ++proc_id) 97 1000 : if (proc_id == _rd_problem.processor_id()) 98 500 : parallel_seed = _generator.randl(MASTER); 99 : else 100 500 : _generator.randl(MASTER); // Generate but throw away numbers that aren't mine 101 : 102 500 : _generator.seed(MASTER, parallel_seed); 103 : } 104 : 105 2845 : auto processor_id = _rd_problem.processor_id(); 106 : 107 2845 : if (_is_nodal) 108 : { 109 815 : const auto & node_to_elem = _rd_mesh.nodeToElemMap(); 110 815 : auto & mesh = _rd_mesh.getMesh(); 111 : 112 815 : for (const auto node_ptr : 113 392944 : as_range(_rd_mesh.getMesh().active_nodes_begin(), _rd_mesh.getMesh().active_nodes_end())) 114 : { 115 195657 : auto id = node_ptr->id(); 116 195657 : auto rand_int = _generator.randl(MASTER); 117 : 118 : // Only save states for nodes attached to active elements 119 195657 : auto elem_id_it = node_to_elem.find(id); 120 : 121 195657 : if (elem_id_it != node_to_elem.end()) 122 : { 123 352020 : for (auto elem_id : elem_id_it->second) 124 : { 125 309070 : const auto * elem_ptr = mesh.elem_ptr(elem_id); 126 : 127 309070 : if (elem_ptr && processor_id == elem_ptr->processor_id()) 128 : { 129 150991 : _seeds[id] = rand_int; 130 : 131 : // Update the individual dof object generators 132 150991 : _generator.seed(id, rand_int); 133 150991 : break; 134 : } 135 : } 136 : } 137 815 : } 138 : } 139 : else 140 : { 141 4060 : for (const auto & elem_ptr : as_range(_rd_mesh.getMesh().active_elements_begin(), 142 694730 : _rd_mesh.getMesh().active_elements_end())) 143 : { 144 344320 : auto id = elem_ptr->id(); 145 344320 : auto rand_int = _generator.randl(MASTER); 146 : 147 : // Only save states for local elements 148 344320 : if (processor_id == elem_ptr->processor_id()) 149 : { 150 246944 : _seeds[id] = rand_int; 151 : 152 : // Update the individual dof object generators 153 246944 : _generator.seed(id, rand_int); 154 : } 155 2030 : } 156 : } 157 2845 : }