LCOV - code coverage report
Current view: top level - src/utils - RandomData.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 61 63 96.8 %
Date: 2025-07-17 01:28:37 Functions: 4 5 80.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 "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 : }

Generated by: LCOV version 1.14