LCOV - code coverage report
Current view: top level - src/other - ThreadedRadialGreensConvolutionLoop.C (source / functions) Hit Total Coverage
Test: idaholab/magpie: 5710af Lines: 63 63 100.0 %
Date: 2025-07-21 23:34:39 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /**********************************************************************/
       2             : /*                     DO NOT MODIFY THIS HEADER                      */
       3             : /* MAGPIE - Mesoscale Atomistic Glue Program for Integrated Execution */
       4             : /*                                                                    */
       5             : /*            Copyright 2017 Battelle Energy Alliance, LLC            */
       6             : /*                        ALL RIGHTS RESERVED                         */
       7             : /**********************************************************************/
       8             : 
       9             : #include "ThreadedRadialGreensConvolutionLoop.h"
      10             : #include "Function.h"
      11             : 
      12             : // Remove after idaholab/moose#26102
      13             : #include "MagpieNanoflann.h"
      14             : 
      15          24 : ThreadedRadialGreensConvolutionLoop::ThreadedRadialGreensConvolutionLoop(
      16          24 :     RadialGreensConvolution & green)
      17          24 :   : _green(green), _function_name(_green.parameters().get<FunctionName>("function"))
      18             : {
      19          24 : }
      20             : 
      21             : // Splitting Constructor
      22           6 : ThreadedRadialGreensConvolutionLoop::ThreadedRadialGreensConvolutionLoop(
      23           6 :     const ThreadedRadialGreensConvolutionLoop & x, Threads::split /*split*/)
      24           6 :   : _green(x._green), _function_name(x._function_name)
      25             : {
      26           6 : }
      27             : 
      28             : void
      29          30 : ThreadedRadialGreensConvolutionLoop::operator()(const QPDataRange & qpdata_range)
      30             : {
      31             :   // fetch data from parent
      32          30 :   const auto r_cut = _green._r_cut;
      33             :   const auto & qp_data = _green._qp_data;
      34             :   const auto & correction_integral = _green._correction_integral;
      35             :   const auto & kd_tree = _green._kd_tree;
      36          30 :   const auto dim = _green._dim;
      37          30 :   const auto t = _green._t;
      38             : 
      39             :   // fetch thread copy of the function for safe evaluation
      40             :   ParallelUniqueId puid;
      41          30 :   const Function & function = _green._fe_problem.getFunction(_function_name, puid.id);
      42             : 
      43             :   // radial bin size
      44          30 :   const Real dr = r_cut / correction_integral.size();
      45             : 
      46             :   // integral of the convolution (used if normalization is requested)
      47          30 :   _convolution_integral = 0.0;
      48             : 
      49             :   // tree search data structures
      50             :   std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
      51             :   nanoflann::SearchParameters search_params;
      52             : 
      53             :   // result map entry
      54          30 :   const auto end_it = _green._convolution.end();
      55             :   auto it = end_it;
      56             : 
      57             :   // iterate over qp range
      58      142950 :   for (auto && local_qp : qpdata_range)
      59             :   {
      60             :     // Look up result map iterator only if we enter a new element. this saves a bunch
      61             :     // of map lookups because same element entries are consecutive in the qp_data vector.
      62      142920 :     if (it == end_it || it->first != local_qp._elem_id)
      63       34260 :       it = _green._convolution.find(local_qp._elem_id);
      64             : 
      65             :     // initialize result entry
      66             :     mooseAssert(it != end_it, "Current element id not found in result set.");
      67      142920 :     auto & sum = it->second[local_qp._qp];
      68      142920 :     sum = 0.0;
      69             : 
      70             :     // if the variable is periodic we need to perform extra searches translated onto
      71             :     // the periodic neighbors
      72      142920 :     std::list<Point> cell_vector = {Point()};
      73      440640 :     for (unsigned int j = 0; j < dim; ++j)
      74      297720 :       if (_green._periodic[j])
      75             :       {
      76             :         std::list<Point> new_cell_vector;
      77             : 
      78      641280 :         for (const auto & cell : cell_vector)
      79             :         {
      80      343560 :           if (local_qp._q_point(j) + _green._periodic_vector[j](j) - r_cut <
      81             :               _green._periodic_max[j])
      82       50814 :             new_cell_vector.push_back(cell + _green._periodic_vector[j]);
      83             : 
      84      343560 :           if (local_qp._q_point(j) - _green._periodic_vector[j](j) + r_cut >
      85             :               _green._periodic_min[j])
      86       50814 :             new_cell_vector.push_back(cell - _green._periodic_vector[j]);
      87             :         }
      88             : 
      89      297720 :         cell_vector.splice(cell_vector.end(), new_cell_vector);
      90             :       }
      91             : 
      92             :     // perform radius search and aggregate data considering potential periodicity
      93             :     Point center;
      94      387468 :     for (const auto & cell : cell_vector)
      95             :     {
      96             :       ret_matches.clear();
      97      244548 :       center = local_qp._q_point + cell;
      98             :       std::size_t n_result =
      99      244548 :           kd_tree->radiusSearch(&(center(0)), r_cut * r_cut, ret_matches, search_params);
     100    54405582 :       for (std::size_t j = 0; j < n_result; ++j)
     101             :       {
     102    54161034 :         const auto & other_qp = qp_data[ret_matches[j].first];
     103    54161034 :         const Real r = std::sqrt(ret_matches[j].second);
     104             : 
     105             :         // R is the equivalent sphere radius for the quadrature point. The spherical integral
     106             :         // integral_0^R 1/(4pi*r^2) *4pi*r^2 = R
     107             :         // So R is the integral over the geometric attenuation at the center quadrature point
     108    54161034 :         switch (dim)
     109             :         {
     110        1824 :           case 1:
     111             :           {
     112             :             // correction integral is the integral over the geometric attenuation
     113             :             // times the Green's function over a 2D disc inscribed into the r_cut
     114             :             // sphere and perpendicular to the mesh.
     115        1824 :             Real add = correction_integral[std::floor(r / dr)] * other_qp._volume;
     116             : 
     117        1824 :             if (r == 0)
     118             :             {
     119         120 :               const Real R = 0.5 * other_qp._volume;
     120         120 :               add += function.value(t, Point(0.0, 0.0, 0.0)) *
     121             :                      (
     122             :                          // add the center sphere attenuation integral
     123         120 :                          R +
     124             :                          // add the section missing or overlapping between correction_integral and
     125             :                          // center sphere
     126         120 :                          _green.attenuationIntegral(R, _green._zero_dh, 0.0, 1) * other_qp._volume);
     127             :             }
     128        1824 :             sum += add * other_qp._value;
     129        1824 :             break;
     130             :           }
     131             : 
     132    44229735 :           case 2:
     133             :           {
     134             :             // correction integral is the integral over the geometric attenuation
     135             :             // times the Green's function over a 1D line segment inscribed into the r_cut
     136             :             // sphere and perpendicular to the mesh.
     137    44229735 :             Real add = correction_integral[std::floor(r / dr)] * other_qp._volume;
     138    44229735 :             if (r == 0)
     139             :             {
     140      130800 :               const Real R = std::sqrt(other_qp._volume / (2.0 * libMesh::pi));
     141      130800 :               add += function.value(t, Point(0.0, 0.0, 0.0)) *
     142             :                      (
     143             :                          // add the center sphere attenuation integral
     144      130800 :                          R +
     145             :                          // add the section missing or overlapping between correction_integral and
     146             :                          // center sphere
     147      130800 :                          _green.attenuationIntegral(R, _green._zero_dh, 0.0, 2) * other_qp._volume);
     148             :             }
     149    44229735 :             sum += add * other_qp._volume * other_qp._value;
     150    44229735 :             break;
     151             :           }
     152             : 
     153     9929475 :           case 3:
     154             :           {
     155     9929475 :             const Real G = function.value(t, Point(r, 0.0, 0.0));
     156     9929475 :             if (r == 0)
     157             :             {
     158             :               // R is the integral over the geometric attenuation in a sphere around the origin
     159       12000 :               const Real R = std::cbrt(3.0 / 4.0 * other_qp._volume / libMesh::pi);
     160       12000 :               sum += G * R * other_qp._value;
     161             :             }
     162             :             else
     163     9917475 :               sum += G * 0.25 / (libMesh::pi * r * r) * other_qp._volume * other_qp._value;
     164             :           }
     165             :         }
     166             :       }
     167             :     }
     168             : 
     169             :     // integrate the convolution result
     170      142920 :     _convolution_integral += sum;
     171             :   }
     172          30 : }

Generated by: LCOV version 1.14