LCOV - code coverage report
Current view: top level - src/meshdivisions - FunctorBinnedValuesDivision.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 39 65 60.0 %
Date: 2025-07-17 01:28:37 Functions: 5 6 83.3 %
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 "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 : }

Generated by: LCOV version 1.14