LCOV - code coverage report
Current view: top level - src/userobjects - RepeatableRayStudyBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose ray_tracing: #31405 (292dce) with base fef103 Lines: 99 109 90.8 %
Date: 2025-09-04 07:56:07 Functions: 7 7 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 "RepeatableRayStudyBase.h"
      11             : 
      12             : // libMesh includes
      13             : #include "libmesh/parallel_sync.h"
      14             : 
      15             : #include "DataIO.h"
      16             : 
      17             : InputParameters
      18        7156 : RepeatableRayStudyBase::validParams()
      19             : {
      20        7156 :   auto params = RayTracingStudy::validParams();
      21             : 
      22             :   // Whether or not the _rays filled by defineRays() are replicated
      23             :   // (the same across all processors)
      24        7156 :   params.addPrivateParam<bool>("_define_rays_replicated", true);
      25             :   // Whether or not Rays need to be claimed after calling defineRays()
      26        7156 :   params.addPrivateParam<bool>("_claim_after_define_rays", true);
      27             : 
      28        7156 :   return params;
      29           0 : }
      30             : 
      31        3600 : RepeatableRayStudyBase::RepeatableRayStudyBase(const InputParameters & parameters)
      32             :   : RayTracingStudy(parameters),
      33        3600 :     _rays(declareRestartableDataWithContext<std::vector<std::shared_ptr<Ray>>>("rays", this)),
      34        3600 :     _define_rays_replicated(getParam<bool>("_claim_after_define_rays")
      35        5526 :                                 ? getParam<bool>("_define_rays_replicated")
      36             :                                 : false),
      37        7200 :     _claim_after_define_rays(getParam<bool>("_claim_after_define_rays")),
      38        7200 :     _should_define_rays(declareRestartableData<bool>("should_define_rays", true)),
      39        3600 :     _local_rays(
      40        3600 :         declareRestartableDataWithContext<std::vector<std::shared_ptr<Ray>>>("local_rays", this)),
      41        3600 :     _claim_rays(*this,
      42        3600 :                 _rays,
      43             :                 _local_rays,
      44        3600 :                 /* do_exchange = */ !_define_rays_replicated),
      45        3600 :     _should_claim_rays(
      46        7200 :         declareRestartableData<bool>("claim_after_define_rays", _claim_after_define_rays))
      47             : {
      48        8874 :   if (!_claim_after_define_rays && getParam<bool>("_define_rays_replicated"))
      49           2 :     mooseWarning("The combination of private parameters:",
      50             :                  "\n  '_define_rays_replicated' == true",
      51             :                  "\n  '_claim_after_define_rays' == false",
      52             :                  "\nis not a valid combination.",
      53             :                  "\n\n_define_rays_replicated is being set to false.");
      54        3598 : }
      55             : 
      56             : void
      57        7569 : RepeatableRayStudyBase::generateRays()
      58             : {
      59             :   // Initially, the user is to define the Rays that they want to trace by overriding
      60             :   // defineRays() and filling into _rays within this method. These Rays are not
      61             :   // the Rays that will actually be traced, they just serve as a template for
      62             :   // Rays that will be put into the tracer to be traced.
      63             :   //
      64             :   // If the private parameter '_claim_after_define_rays' == true, it is assumed
      65             :   // that the Rays that were filled into _rays from the overridden defineRays()
      66             :   // do not have their starting element and incoming sides set. The Rays in _rays
      67             :   // will be "claimed" later and communicated to the processors that will start them
      68             :   // with their starting element set and incoming side set (if any). An example of this
      69             :   // is in RepeatableRayStudy.
      70             :   //
      71             :   // If the private parameter '_claim_after_define_rays' == false, it is assumed
      72             :   // that the Rays that were filled into _rays from the overridden defineRays():
      73             :   // - Have their starting element and incoming side (if applicable) set and it is
      74             :   //   correct
      75             :   // - Are on the processor that will start them (the processor that contains
      76             :   //   the starting element)
      77             :   // At this point, the Rays in _rays will be also inserted into _local_rays
      78             :   // because they are on the right processor with starting information set.
      79             :   // An example of this is in LotsOfRaysRayStudy.
      80        7569 :   if (_should_define_rays)
      81             :   {
      82        2614 :     _should_define_rays = false;
      83             : 
      84        2614 :     defineRaysInternal();
      85             :   }
      86             : 
      87        7561 :   if (_should_claim_rays)
      88             :   {
      89         893 :     _should_claim_rays = false;
      90             : 
      91         893 :     claimRaysInternal();
      92             :   }
      93             : 
      94             :   // Reserve ahead of time how many Rays we are adding to the buffer
      95        7561 :   reserveRayBuffer(_local_rays.size());
      96             : 
      97             :   // To make this study "repeatable", we will not trace the Rays that
      98             :   // are ready to go in _local_rays. We will instead create new Rays
      99             :   // that are duplicates of the ones in _local_rays, and trace those.
     100             :   // This ensures that on multiple executions of this study, we always
     101             :   // have the information to create the same Rays.
     102     4043184 :   for (const auto & ray : _local_rays)
     103             :   {
     104             :     // This acquires a new ray that is copied from a Ray that has already
     105             :     // been claimed to begin on this processor with the user-defined trajectory
     106     4035623 :     std::shared_ptr<Ray> copied_ray = acquireCopiedRay(*ray);
     107             : 
     108             :     // This calls std::move() on the ray, which means that copied_ray in this context
     109             :     // is no longer valid. We use the move method because copied_ray is a shared_ptr
     110             :     // and otherwise we would increase the count as we add it to the buffer and also
     111             :     // decrease the count once this goes out of scope.
     112     4035623 :     moveRayToBuffer(copied_ray);
     113             :   }
     114        7561 : }
     115             : 
     116             : void
     117         224 : RepeatableRayStudyBase::meshChanged()
     118             : {
     119         224 :   RayTracingStudy::meshChanged();
     120             : 
     121             :   // Need to reclaim after this
     122         224 :   _should_claim_rays = true;
     123             : 
     124             :   // Invalidate all of the old starting info because we can't be sure those elements still exist
     125       46880 :   for (const auto & ray : _rays)
     126             :   {
     127       46656 :     ray->invalidateStartingElem();
     128       46656 :     ray->invalidateStartingIncomingSide();
     129             :   }
     130       46880 :   for (const auto & ray : _local_rays)
     131             :   {
     132       46656 :     ray->invalidateStartingElem();
     133       46656 :     ray->invalidateStartingIncomingSide();
     134             :   }
     135         224 : }
     136             : 
     137             : void
     138         893 : RepeatableRayStudyBase::claimRaysInternal()
     139             : {
     140        1786 :   TIME_SECTION("claimRaysInternal", 2, "Claiming Rays");
     141             : 
     142         893 :   _claim_rays.claim();
     143         893 : }
     144             : 
     145             : void
     146        2614 : RepeatableRayStudyBase::defineRaysInternal()
     147             : {
     148             :   {
     149        5228 :     TIME_SECTION("defineRaysInternal", 2, "Defining Rays");
     150             : 
     151        2614 :     _rays.clear();
     152        2614 :     _local_rays.clear();
     153             : 
     154        2614 :     defineRays();
     155             :   }
     156             : 
     157             :   // Do we actually have Rays
     158        2614 :   auto num_rays = _rays.size();
     159        2614 :   _communicator.sum(num_rays);
     160        2614 :   if (!num_rays)
     161           2 :     mooseError("No Rays were moved to _rays in defineRays()");
     162     3975713 :   for (const auto & ray : _rays)
     163     3973103 :     if (!ray)
     164           2 :       mooseError("A nullptr Ray was found in _rays after defineRays().");
     165             : 
     166             :   // The Rays in _rays are ready to go as is: they have their starting element
     167             :   // set, their incoming set (if any), and are on the processor that owns said
     168             :   // starting element. Therefore, we move them right into _local_rays and
     169             :   // set that we don't need to claim.
     170        2610 :   if (!_claim_after_define_rays)
     171             :   {
     172        1937 :     _local_rays.reserve(_rays.size());
     173     3971471 :     for (const std::shared_ptr<Ray> & ray : _rays)
     174     3969534 :       _local_rays.emplace_back(ray);
     175             : 
     176        1937 :     _should_claim_rays = false;
     177             :   }
     178             :   // Claiming is required after defining. The Rays in _rays should not
     179             :   // have their starting elems or incoming sides set - verify that.
     180             :   else
     181             :   {
     182        4238 :     for (const std::shared_ptr<Ray> & ray : _rays)
     183        3567 :       if (ray->currentElem() || !ray->invalidCurrentIncomingSide())
     184           2 :         mooseError(
     185             :             "A Ray was found in _rays after defineRays() that has a starting element or "
     186             :             "incoming side set.\n\n",
     187             :             "With the mode in which the private param '_claim_after_define_rays' == true,",
     188             :             "\nthe defined Rays at this point should not have their starting elem/side set.\n",
     189             :             "\nTheir starting information will be set internally using a claiming process.\n\n",
     190           2 :             ray->getInfo());
     191             :   }
     192             : 
     193             :   // Sanity checks on if the Rays are actually replicated
     194        2608 :   if (_define_rays_replicated && verifyRays())
     195         671 :     verifyReplicatedRays();
     196        2606 : }
     197             : 
     198             : void
     199         671 : RepeatableRayStudyBase::verifyReplicatedRays()
     200             : {
     201        1342 :   TIME_SECTION("verifyReplicatedRays", 2, "Verifying Replicated Rays");
     202             : 
     203             :   const std::string error_suffix =
     204             :       "\n\nThe Rays added in defineRays() must be replicated across all processors\nwith the "
     205         671 :       "private param '_define_rays_replicated' == true.";
     206             : 
     207             :   // First, verify that our _rays have unique IDs beacuse we will do mapping based on Ray ID
     208         671 :   verifyUniqueRayIDs(_rays.begin(),
     209         671 :                      _rays.end(),
     210             :                      /* global = */ false,
     211        1340 :                      "in _rays after calling defineRays()." + error_suffix);
     212             : 
     213             :   // Tag for sending rays from rank 0 -> all other ranks
     214         669 :   const auto tag = comm().get_unique_tag();
     215             : 
     216             :   // Send a copy of the rays on rank 0 to all other processors for verification
     217         669 :   if (_pid == 0)
     218             :   {
     219         427 :     std::vector<Parallel::Request> requests(n_processors() - 1);
     220             :     auto request_it = requests.begin();
     221             : 
     222        1096 :     for (processor_id_type pid = 0; pid < n_processors(); ++pid)
     223         669 :       if (pid != 0)
     224         242 :         comm().send_packed_range(
     225         242 :             pid, parallelStudy(), _rays.begin(), _rays.end(), *request_it++, tag);
     226             : 
     227         427 :     Parallel::wait(requests);
     228         427 :   }
     229             :   // All other processors will receive and verify that their rays match the rays on rank 0
     230             :   else
     231             :   {
     232             :     // Map of RayID -> Ray for comparison from the Rays on rank 0 to the local rays
     233             :     std::unordered_map<RayID, const Ray *> ray_map;
     234         242 :     ray_map.reserve(_rays.size());
     235        1622 :     for (const auto & ray : _rays)
     236        1380 :       ray_map.emplace(ray->id(), ray.get());
     237             : 
     238             :     // Receive the duplicated rays from rank 0
     239             :     std::vector<std::shared_ptr<Ray>> rank_0_rays;
     240         242 :     rank_0_rays.reserve(_rays.size());
     241         242 :     comm().receive_packed_range(
     242             :         0, parallelStudy(), std::back_inserter(rank_0_rays), (std::shared_ptr<Ray> *)nullptr, tag);
     243             : 
     244             :     // The sizes better match
     245         242 :     if (rank_0_rays.size() != _rays.size())
     246           0 :       mooseError("The size of _rays on rank ",
     247           0 :                  _pid,
     248             :                  " does not match the size of rays on rank 0.",
     249             :                  error_suffix);
     250             : 
     251             :     // Make sure we have a matching local ray for each ray from rank 0
     252        1622 :     for (const auto & ray : rank_0_rays)
     253             :     {
     254        1380 :       const auto find = ray_map.find(ray->id());
     255        1380 :       if (find == ray_map.end())
     256           0 :         mooseError("A Ray was found on rank ",
     257           0 :                    _pid,
     258             :                    " with an ID that does not exist on rank 0.",
     259             :                    error_suffix,
     260             :                    "\n\n",
     261           0 :                    ray->getInfo());
     262             : 
     263        1380 :       const Ray * root_ray = find->second;
     264        1380 :       if (*root_ray != *ray)
     265             :       {
     266           0 :         mooseError("A Ray was found on rank ",
     267           0 :                    _pid,
     268             :                    " that does not exist on rank 0.",
     269             :                    error_suffix,
     270             :                    "\n\nLocal ray:\n\n",
     271           0 :                    ray->getInfo(),
     272             :                    "\n\nRank 0 ray:\n\n",
     273           0 :                    root_ray->getInfo());
     274             :       }
     275             :     }
     276         242 :   }
     277        1338 : }

Generated by: LCOV version 1.14