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 14469 : MeshDivisionFunctorReductionVectorPostprocessor::validParams() 22 : { 23 14469 : InputParameters params = SpatialUserObjectFunctor<ElementVectorPostprocessor>::validParams(); 24 14469 : MooseEnum reduction("integral average min max"); 25 14469 : params.addRequiredParam<MooseEnum>("reduction", reduction, "Reduction operation to apply"); 26 14469 : params.addRequiredParam<std::vector<MooseFunctorName>>("functors", 27 : "Functors to apply the reduction on"); 28 14469 : params.addRequiredParam<MeshDivisionName>( 29 : "mesh_division", 30 : "Mesh division object which dictates the elements to perform the reduction with"); 31 14469 : params.addClassDescription("Perform reductions on functors based on a per-mesh-division basis"); 32 28938 : return params; 33 14469 : } 34 : 35 108 : MeshDivisionFunctorReductionVectorPostprocessor::MeshDivisionFunctorReductionVectorPostprocessor( 36 108 : const InputParameters & parameters) 37 : : SpatialUserObjectFunctor<ElementVectorPostprocessor>(parameters), 38 : NonADFunctorInterface(this), 39 108 : _reduction(getParam<MooseEnum>("reduction")), 40 108 : _nfunctors(getParam<std::vector<MooseFunctorName>>("functors").size()), 41 216 : _mesh_division(_fe_problem.getMeshDivision(getParam<MeshDivisionName>("mesh_division"), _tid)) 42 : { 43 : // Gather the functors 44 108 : const auto & functor_names = getParam<std::vector<MooseFunctorName>>("functors"); 45 459 : for (const auto & functor_name : functor_names) 46 351 : _functors.push_back(&getFunctor<Real>(functor_name)); 47 : 48 : // Set up reduction vectors 49 108 : const auto ndiv = _mesh_division.getNumDivisions(); 50 108 : _volumes.resize(ndiv); 51 459 : for (const auto & functor_name : functor_names) 52 : { 53 351 : auto & p = declareVector(functor_name); 54 351 : p.resize(ndiv); 55 351 : _functor_reductions.push_back(&p); 56 : } 57 108 : } 58 : 59 : void 60 104 : MeshDivisionFunctorReductionVectorPostprocessor::initialize() 61 : { 62 442 : for (auto & reduction : _functor_reductions) 63 : { 64 338 : if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE) 65 208 : std::fill(reduction->begin(), reduction->end(), 0); 66 130 : else if (_reduction == ReductionEnum::MIN) 67 104 : std::fill(reduction->begin(), reduction->end(), std::numeric_limits<Real>::max()); 68 26 : else if (_reduction == ReductionEnum::MAX) 69 26 : std::fill(reduction->begin(), reduction->end(), std::numeric_limits<Real>::min()); 70 : else 71 : mooseAssert(false, "Unknown reduction type"); 72 : } 73 104 : std::fill(_volumes.begin(), _volumes.end(), 0); 74 104 : } 75 : 76 : void 77 13603 : MeshDivisionFunctorReductionVectorPostprocessor::execute() 78 : { 79 13603 : const auto state_arg = determineState(); 80 13603 : if (hasBlocks(_current_elem->subdomain_id())) 81 : { 82 13603 : const auto index = _mesh_division.divisionIndex(*_current_elem); 83 13603 : 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 57800 : for (const auto i : make_range(_nfunctors)) 91 44200 : if (_functors[i]->hasBlocks(_current_elem->subdomain_id())) 92 88400 : for (const auto qp : make_range(_qrule->n_points())) 93 : { 94 44200 : const Moose::ElemQpArg elem_qp = {_current_elem, qp, _qrule, _q_point[qp]}; 95 44200 : const auto functor_value = (*_functors[i])(elem_qp, state_arg); 96 44200 : if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE) 97 27200 : (*_functor_reductions[i])[index] += _JxW[qp] * _coord[qp] * functor_value; 98 17000 : else if (_reduction == ReductionEnum::MIN) 99 : { 100 13600 : if ((*_functor_reductions[i])[index] > functor_value) 101 798 : (*_functor_reductions[i])[index] = functor_value; 102 : } 103 3400 : else if (_reduction == ReductionEnum::MAX) 104 3400 : if ((*_functor_reductions[i])[index] < functor_value) 105 1540 : (*_functor_reductions[i])[index] = functor_value; 106 : 107 44200 : if (i == 0 && _reduction == ReductionEnum::AVERAGE) 108 3400 : _volumes[index] += _JxW[qp] * _coord[qp]; 109 : } 110 : } 111 : } 112 : 113 : void 114 80 : MeshDivisionFunctorReductionVectorPostprocessor::finalize() 115 : { 116 340 : for (auto & reduction : _functor_reductions) 117 260 : if (_reduction == ReductionEnum::INTEGRAL || _reduction == ReductionEnum::AVERAGE) 118 160 : gatherSum(*reduction); 119 100 : else if (_reduction == ReductionEnum::MIN) 120 80 : gatherMin(*reduction); 121 20 : else if (_reduction == ReductionEnum::MAX) 122 20 : gatherMax(*reduction); 123 : 124 80 : if (_reduction == ReductionEnum::AVERAGE) 125 : { 126 20 : gatherSum(_volumes); 127 100 : for (const auto i_f : make_range(_nfunctors)) 128 1360 : for (const auto i : index_range(*_functor_reductions[i_f])) 129 1280 : if (!MooseUtils::absoluteFuzzyEqual(_volumes[i], 0)) 130 640 : (*_functor_reductions[i_f])[i] /= _volumes[i]; 131 : else 132 640 : (*_functor_reductions[i_f])[i] = 0; 133 : } 134 80 : } 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 32 : MeshDivisionFunctorReductionVectorPostprocessor::spatialValue(const Point & p) const 163 : { 164 32 : 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 28 : const auto index = _mesh_division.divisionIndex(p); 168 28 : if (index == MooseMeshDivision::INVALID_DIVISION_INDEX) 169 4 : mooseError("Spatial value sampled outside of the mesh_division specified at", p); 170 24 : return (*_functor_reductions[0])[index]; 171 : } 172 : 173 : bool 174 13603 : MeshDivisionFunctorReductionVectorPostprocessor::hasBlocks(const SubdomainID sub) const 175 : { 176 13603 : return BlockRestrictable::hasBlocks(sub); 177 : }