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 "FunctorBinnedValuesDivision.h" 11 : #include "MooseMesh.h" 12 : #include "MooseFunctorArguments.h" 13 : 14 : #include "libmesh/mesh_base.h" 15 : #include "libmesh/elem.h" 16 : 17 : registerMooseObject("MooseApp", FunctorBinnedValuesDivision); 18 : 19 : InputParameters 20 14290 : FunctorBinnedValuesDivision::validParams() 21 : { 22 14290 : InputParameters params = MeshDivision::validParams(); 23 14290 : params.addClassDescription( 24 : "Divide the mesh along based on uniformly binned values of a functor."); 25 14290 : params.addRequiredParam<Real>("min_value", "Minimum value of the functor for the binning"); 26 14290 : params.addRequiredParam<Real>("max_value", "Maximum value of the functor for the binning"); 27 14290 : params.addRequiredRangeCheckedParam<unsigned int>( 28 : "num_bins", "num_bins>0", "Number of uniform bins in functor values"); 29 14290 : params.addRequiredParam<MooseFunctorName>( 30 : "functor", "Functor to evaluate to assign points/elements to the bins"); 31 42870 : params.addParam<bool>("assign_out_of_bounds_to_extreme_bins", 32 28580 : false, 33 : "Whether to map functor values outside of the [min,max] range to the " 34 : "lowest and highest bins, or to use the invalid division index"); 35 : 36 14290 : return params; 37 0 : } 38 : 39 13 : FunctorBinnedValuesDivision::FunctorBinnedValuesDivision(const InputParameters & parameters) 40 : : MeshDivision(parameters), 41 : NonADFunctorInterface(this), 42 13 : _min(getParam<Real>("min_value")), 43 13 : _max(getParam<Real>("max_value")), 44 13 : _nbins(getParam<unsigned int>("num_bins")), 45 13 : _functor(getFunctor<Real>("functor")), 46 26 : _oob_is_edge_bins(getParam<bool>("assign_out_of_bounds_to_extreme_bins")) 47 : { 48 13 : if (MooseUtils::absoluteFuzzyLessEqual(_max, _min)) 49 0 : paramError("max_value", "Maximum value should be above minimum value."); 50 13 : FunctorBinnedValuesDivision::initialize(); 51 13 : } 52 : 53 : void 54 13 : FunctorBinnedValuesDivision::initialize() 55 : { 56 13 : setNumDivisions(_nbins); 57 : 58 : // We could alternatively check every point in the mesh but it seems expensive 59 : // the functor values can also change so this check would need to be done regularly 60 13 : _mesh_fully_indexed = true; 61 13 : if (!_oob_is_edge_bins) 62 13 : _mesh_fully_indexed = false; 63 13 : } 64 : 65 : unsigned int 66 640 : FunctorBinnedValuesDivision::getBinIndex(Real value, const Point & pt) const 67 : { 68 : // Handle out of bounds functor values 69 640 : if (!_oob_is_edge_bins) 70 : { 71 640 : if (value < _min) 72 0 : return MooseMeshDivision::INVALID_DIVISION_INDEX; 73 640 : else if (value > _max) 74 320 : return MooseMeshDivision::INVALID_DIVISION_INDEX; 75 : } 76 : else 77 : { 78 0 : if (value < _min) 79 0 : return 0; 80 0 : else if (value > _max) 81 0 : return _nbins - 1; 82 : } 83 : 84 1280 : for (const auto i_bin : make_range(_nbins + 1)) 85 : { 86 1280 : const auto border_value = _min + i_bin / _nbins * (_max - _min); 87 1280 : if (MooseUtils::absoluteFuzzyEqual(value, border_value)) 88 0 : mooseWarning("Functor value " + std::to_string(value) + 89 0 : " is on a bin edge for evaluation near " + Moose::stringify(pt)); 90 1280 : if (value < border_value) 91 320 : return (i_bin > 0) ? i_bin - 1 : 0; 92 : } 93 0 : return _nbins; 94 : } 95 : 96 : unsigned int 97 640 : FunctorBinnedValuesDivision::divisionIndex(const Elem & elem) const 98 : { 99 640 : Moose::ElemArg elem_arg = {&elem, false}; 100 640 : Moose::StateArg time_arg = {0, Moose::SolutionIterationType::Time}; 101 640 : return getBinIndex(_functor(elem_arg, time_arg), elem.vertex_average()); 102 : } 103 : 104 : unsigned int 105 0 : FunctorBinnedValuesDivision::divisionIndex(const Point & pt) const 106 : { 107 0 : Moose::StateArg time_arg = {0, Moose::SolutionIterationType::Time}; 108 : 109 0 : const auto & pl = _mesh.getMesh().sub_point_locator(); 110 : // There could be more than one elem if we are on the edge between two elements 111 0 : std::set<const Elem *> candidates; 112 0 : (*pl)(pt, candidates); 113 : 114 : // By convention we will use the element with the lowest element id 115 0 : const Elem * elem = nullptr; 116 0 : unsigned int min_elem_id = libMesh::invalid_uint; 117 0 : for (const auto elem_ptr : candidates) 118 0 : if (elem_ptr->id() < min_elem_id) 119 : { 120 0 : elem = elem_ptr; 121 0 : min_elem_id = elem_ptr->id(); 122 : } 123 0 : if (!elem) 124 0 : mooseError("Division index queried for a point outside the local mesh"); 125 0 : Moose::ElemPointArg elem_pt_arg = {elem, pt, false}; 126 : 127 : // Find the element with the lowest id to form an ElemPt argument 128 0 : return getBinIndex(_functor(elem_pt_arg, time_arg), pt); 129 0 : }