LCOV - code coverage report
Current view: top level - src/vectorpostprocessors - MeshDivisionFunctorReductionVectorPostprocessor.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 97 98 99.0 %
Date: 2025-07-17 01:28:37 Functions: 8 8 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 "MeshDivisionFunctorReductionVectorPostprocessor.h"
      11             : #include "MeshDivision.h"
      12             : #include "MooseMesh.h"
      13             : #include "MooseMeshUtils.h"
      14             : #include "FEProblemBase.h"
      15             : 
      16             : #include "libmesh/mesh_base.h"
      17             : 
      18             : registerMooseObject("MooseApp", MeshDivisionFunctorReductionVectorPostprocessor);
      19             : 
      20             : InputParameters
      21       14461 : MeshDivisionFunctorReductionVectorPostprocessor::validParams()
      22             : {
      23       14461 :   InputParameters params = SpatialUserObjectFunctor<ElementVectorPostprocessor>::validParams();
      24       14461 :   MooseEnum reduction("integral average min max");
      25       14461 :   params.addRequiredParam<MooseEnum>("reduction", reduction, "Reduction operation to apply");
      26       14461 :   params.addRequiredParam<std::vector<MooseFunctorName>>("functors",
      27             :                                                          "Functors to apply the reduction on");
      28       14461 :   params.addRequiredParam<MeshDivisionName>(
      29             :       "mesh_division",
      30             :       "Mesh division object which dictates the elements to perform the reduction with");
      31       14461 :   params.addClassDescription("Perform reductions on functors based on a per-mesh-division basis");
      32       28922 :   return params;
      33       14461 : }
      34             : 
      35         104 : MeshDivisionFunctorReductionVectorPostprocessor::MeshDivisionFunctorReductionVectorPostprocessor(
      36         104 :     const InputParameters & parameters)
      37             :   : SpatialUserObjectFunctor<ElementVectorPostprocessor>(parameters),
      38             :     NonADFunctorInterface(this),
      39         104 :     _reduction(getParam<MooseEnum>("reduction")),
      40         104 :     _nfunctors(getParam<std::vector<MooseFunctorName>>("functors").size()),
      41         208 :     _mesh_division(_fe_problem.getMeshDivision(getParam<MeshDivisionName>("mesh_division"), _tid))
      42             : {
      43             :   // Gather the functors
      44         104 :   const auto & functor_names = getParam<std::vector<MooseFunctorName>>("functors");
      45         442 :   for (const auto & functor_name : functor_names)
      46         338 :     _functors.push_back(&getFunctor<Real>(functor_name));
      47             : 
      48             :   // Set up reduction vectors
      49         104 :   const auto ndiv = _mesh_division.getNumDivisions();
      50         104 :   _volumes.resize(ndiv);
      51         442 :   for (const auto & functor_name : functor_names)
      52             :   {
      53         338 :     auto & p = declareVector(functor_name);
      54         338 :     p.resize(ndiv);
      55         338 :     _functor_reductions.push_back(&p);
      56             :   }
      57         104 : }
      58             : 
      59             : void
      60         100 : MeshDivisionFunctorReductionVectorPostprocessor::initialize()
      61             : {
      62         425 :   for (auto & reduction : _functor_reductions)
      63             :   {
      64         325 :     if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE)
      65         200 :       std::fill(reduction->begin(), reduction->end(), 0);
      66         125 :     else if (_reduction == ReductionEnum::MIN)
      67         100 :       std::fill(reduction->begin(), reduction->end(), std::numeric_limits<Real>::max());
      68          25 :     else if (_reduction == ReductionEnum::MAX)
      69          25 :       std::fill(reduction->begin(), reduction->end(), std::numeric_limits<Real>::min());
      70             :     else
      71             :       mooseAssert(false, "Unknown reduction type");
      72             :   }
      73         100 :   std::fill(_volumes.begin(), _volumes.end(), 0);
      74         100 : }
      75             : 
      76             : void
      77       12803 : MeshDivisionFunctorReductionVectorPostprocessor::execute()
      78             : {
      79       12803 :   const auto state_arg = determineState();
      80       12803 :   if (hasBlocks(_current_elem->subdomain_id()))
      81             :   {
      82       12803 :     const auto index = _mesh_division.divisionIndex(*_current_elem);
      83       12803 :     if (index == MooseMeshDivision::INVALID_DIVISION_INDEX)
      84             :     {
      85           6 :       mooseWarning("Spatial value sampled outside of the mesh_division specified in element: " +
      86           6 :                    Moose::stringify(_current_elem->id()) + " of centroid " +
      87           3 :                    Moose::stringify(_current_elem->true_centroid()));
      88           0 :       return;
      89             :     }
      90       54400 :     for (const auto i : make_range(_nfunctors))
      91       41600 :       if (_functors[i]->hasBlocks(_current_elem->subdomain_id()))
      92       83200 :         for (const auto qp : make_range(_qrule->n_points()))
      93             :         {
      94       41600 :           const Moose::ElemQpArg elem_qp = {_current_elem, qp, _qrule, _q_point[qp]};
      95       41600 :           const auto functor_value = (*_functors[i])(elem_qp, state_arg);
      96       41600 :           if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE)
      97       25600 :             (*_functor_reductions[i])[index] += _JxW[qp] * _coord[qp] * functor_value;
      98       16000 :           else if (_reduction == ReductionEnum::MIN)
      99             :           {
     100       12800 :             if ((*_functor_reductions[i])[index] > functor_value)
     101         752 :               (*_functor_reductions[i])[index] = functor_value;
     102             :           }
     103        3200 :           else if (_reduction == ReductionEnum::MAX)
     104        3200 :             if ((*_functor_reductions[i])[index] < functor_value)
     105        1450 :               (*_functor_reductions[i])[index] = functor_value;
     106             : 
     107       41600 :           if (i == 0 && _reduction == ReductionEnum::AVERAGE)
     108        3200 :             _volumes[index] += _JxW[qp] * _coord[qp];
     109             :         }
     110             :   }
     111             : }
     112             : 
     113             : void
     114          76 : MeshDivisionFunctorReductionVectorPostprocessor::finalize()
     115             : {
     116         323 :   for (auto & reduction : _functor_reductions)
     117         247 :     if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE)
     118         152 :       gatherSum(*reduction);
     119          95 :     else if (_reduction == ReductionEnum::MIN)
     120          76 :       gatherMin(*reduction);
     121          19 :     else if (_reduction == ReductionEnum::MAX)
     122          19 :       gatherMax(*reduction);
     123             : 
     124          76 :   if (_reduction == ReductionEnum::AVERAGE)
     125             :   {
     126          19 :     gatherSum(_volumes);
     127          95 :     for (const auto i_f : make_range(_nfunctors))
     128        1292 :       for (const auto i : index_range(*_functor_reductions[i_f]))
     129        1216 :         if (!MooseUtils::absoluteFuzzyEqual(_volumes[i], 0))
     130         608 :           (*_functor_reductions[i_f])[i] /= _volumes[i];
     131             :         else
     132         608 :           (*_functor_reductions[i_f])[i] = 0;
     133             :   }
     134          76 : }
     135             : 
     136             : void
     137          12 : MeshDivisionFunctorReductionVectorPostprocessor::threadJoin(const UserObject & s)
     138             : {
     139          12 :   const auto & sibling = static_cast<const MeshDivisionFunctorReductionVectorPostprocessor &>(s);
     140             : 
     141          51 :   for (const auto i_f : make_range(_nfunctors))
     142         663 :     for (const auto i : index_range(*_functor_reductions[i_f]))
     143             :     {
     144         624 :       if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE)
     145         384 :         (*_functor_reductions[i_f])[i] += (*sibling._functor_reductions[i_f])[i];
     146         240 :       else if (_reduction == ReductionEnum::MIN)
     147             :       {
     148         192 :         if ((*_functor_reductions[i_f])[i] > (*sibling._functor_reductions[i_f])[i])
     149          48 :           (*_functor_reductions[i_f])[i] = (*sibling._functor_reductions[i_f])[i];
     150             :       }
     151          48 :       else if (_reduction == ReductionEnum::MAX)
     152          48 :         if ((*_functor_reductions[i_f])[i] < (*sibling._functor_reductions[i_f])[i])
     153          12 :           (*_functor_reductions[i_f])[i] = (*sibling._functor_reductions[i_f])[i];
     154             : 
     155             :       // Average-reduction requires the reduction of the volume
     156         624 :       if (i_f == 0 && _reduction == ReductionEnum::AVERAGE)
     157          48 :         _volumes[i] += sibling._volumes[i];
     158             :     }
     159          12 : }
     160             : 
     161             : Real
     162          30 : MeshDivisionFunctorReductionVectorPostprocessor::spatialValue(const Point & p) const
     163             : {
     164          30 :   if (_nfunctors > 1)
     165           4 :     mooseError("The spatialValue user object interface was not conceived for objects that compute "
     166             :                "multiple values for a given spatial point. Please specify only one functor");
     167          26 :   const auto index = _mesh_division.divisionIndex(p);
     168          26 :   if (index == MooseMeshDivision::INVALID_DIVISION_INDEX)
     169           4 :     mooseError("Spatial value sampled outside of the mesh_division specified at", p);
     170          22 :   return (*_functor_reductions[0])[index];
     171             : }
     172             : 
     173             : bool
     174       12803 : MeshDivisionFunctorReductionVectorPostprocessor::hasBlocks(const SubdomainID sub) const
     175             : {
     176       12803 :   return BlockRestrictable::hasBlocks(sub);
     177             : }

Generated by: LCOV version 1.14