LCOV - code coverage report
Current view: top level - include/userobjects - NearestPointBase.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 101 107 94.4 %
Date: 2025-08-08 20:01:16 Functions: 89 117 76.1 %
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             : #pragma once
      11             : 
      12             : // MOOSE includes
      13             : #include "SpatialUserObjectFunctor.h"
      14             : #include "Enumerate.h"
      15             : #include "DelimitedFileReader.h"
      16             : #include "LayeredBase.h"
      17             : #include "FEProblemBase.h"
      18             : #include "Positions.h"
      19             : 
      20             : // Forward Declarations
      21             : class UserObject;
      22             : 
      23             : /**
      24             :  * This UserObject computes averages of a variable storing partial
      25             :  * sums for the specified number of intervals in a direction (x,y,z).
      26             :  *
      27             :  * Given a list of points this object computes the layered average
      28             :  * closest to each one of those points.
      29             :  */
      30             : template <typename UserObjectType, typename BaseType>
      31             : class NearestPointBase : public SpatialUserObjectFunctor<BaseType>
      32             : {
      33             : public:
      34             :   static InputParameters validParams();
      35             : 
      36             :   NearestPointBase(const InputParameters & parameters);
      37             :   ~NearestPointBase();
      38             : 
      39             :   virtual void initialize() override;
      40             :   virtual void execute() override;
      41             :   virtual void finalize() override;
      42             :   virtual void threadJoin(const UserObject & y) override;
      43             : 
      44             :   /**
      45             :    * Given a Point return the integral value associated with the layer
      46             :    * that point falls in for the layered average closest to that
      47             :    * point.
      48             :    *
      49             :    * @param p The point to look for in the layers.
      50             :    */
      51             :   virtual Real spatialValue(const Point & p) const override;
      52             : 
      53             :   /**
      54             :    * Get the points at which the nearest operation is performed
      55             :    * @return points
      56             :    */
      57          13 :   virtual const std::vector<Point> & getPoints() const { return _points; }
      58             : 
      59             :   virtual const std::vector<Point> spatialPoints() const override;
      60             : 
      61             : protected:
      62             :   /**
      63             :    * Fills in the `_points` variable from either 'points' or 'points_file' parameter.
      64             :    * Also performs error checking.
      65             :    */
      66             :   void fillPoints();
      67             : 
      68             :   /**
      69             :    * Get the UserObject that is closest to the point.
      70             :    *
      71             :    * @param p The point.
      72             :    * @return The UserObject closest to p.
      73             :    */
      74             :   UserObjectType & nearestUserObject(const Point & p) const;
      75             : 
      76             :   std::vector<Point> _points;
      77             :   std::vector<std::unique_ptr<UserObjectType>> _user_objects;
      78             : 
      79             :   // To specify whether the distance is defined based on point or radius
      80             :   const unsigned int _dist_norm;
      81             :   // The axis around which the radius is determined
      82             :   const unsigned int _axis;
      83             : 
      84             :   using BaseType::_communicator;
      85             :   using BaseType::_current_elem;
      86             :   using BaseType::isParamValid;
      87             :   using BaseType::processor_id;
      88             :   using MooseBase::name;
      89             : };
      90             : 
      91             : template <typename UserObjectType, typename BaseType>
      92             : InputParameters
      93      157889 : NearestPointBase<UserObjectType, BaseType>::validParams()
      94             : {
      95      157889 :   InputParameters params = SpatialUserObjectFunctor<BaseType>::validParams();
      96             : 
      97      157889 :   params.addParam<std::vector<Point>>("points",
      98             :                                       "Computations will be lumped into values at these points.");
      99      157889 :   params.addParam<FileName>("points_file",
     100             :                             "A filename that should be looked in for points. Each "
     101             :                             "set of 3 values in that file will represent a Point. "
     102             :                             "This and 'points' cannot be both supplied.");
     103      157889 :   params.addParam<PositionsName>(
     104             :       "positions_object",
     105             :       "The name of a Positions object that will contain "
     106             :       "the locations. This, 'points' and 'points(_file)' cannot be both supplied. "
     107             :       "Note that only the vector of initial Positions are used at this time. "
     108             :       "Updates to the 'positions' vector are not supported.");
     109             : 
     110      157889 :   MooseEnum distnorm("point=0 radius=1", "point");
     111      157889 :   params.addParam<MooseEnum>(
     112             :       "dist_norm", distnorm, "To specify whether the distance is defined based on point or radius");
     113      157889 :   MooseEnum axis("x=0 y=1 z=2", "z");
     114      157889 :   params.addParam<MooseEnum>("axis", axis, "The axis around which the radius is determined");
     115             : 
     116      157889 :   params.addParamNamesToGroup("points points_file dist_norm axis", "Points and distance to points");
     117             : 
     118             :   // Add in the valid parameters
     119      157889 :   params += UserObjectType::validParams();
     120             : 
     121      315778 :   return params;
     122      157889 : }
     123             : 
     124             : template <typename UserObjectType, typename BaseType>
     125         518 : NearestPointBase<UserObjectType, BaseType>::NearestPointBase(const InputParameters & parameters)
     126             :   : SpatialUserObjectFunctor<BaseType>(parameters),
     127         518 :     _dist_norm(this->template getParam<MooseEnum>("dist_norm")),
     128        1036 :     _axis(this->template getParam<MooseEnum>("axis"))
     129             : {
     130        1526 :   if (this->template getParam<MooseEnum>("dist_norm") != "radius" &&
     131        1008 :       parameters.isParamSetByUser("axis"))
     132           0 :     this->paramError("axis", "'axis' should only be set if 'dist_norm' is set to 'radius'");
     133             : 
     134         518 :   fillPoints();
     135             : 
     136         506 :   _user_objects.resize(_points.size());
     137             : 
     138             :   // Build each of the UserObject objects that we will manage manually
     139             :   // If you're looking at this in the future and want to replace this behavior,
     140             :   // _please_ don't do it. MOOSE should manage these objects.
     141        2117 :   for (MooseIndex(_points) i = 0; i < _points.size(); ++i)
     142             :   {
     143        1623 :     const auto uo_type = MooseUtils::prettyCppType<UserObjectType>();
     144        1623 :     auto sub_params = this->_app.getFactory().getValidParams(uo_type);
     145        1623 :     sub_params.applyParameters(parameters, {}, true);
     146             : 
     147        1623 :     const auto sub_name = name() + "_sub" + std::to_string(i);
     148        1623 :     auto uo = this->_app.getFactory().template createUnique<UserObjectType>(
     149        1623 :         uo_type, sub_name, sub_params, this->_tid);
     150        1611 :     _user_objects[i] = std::move(uo);
     151             :   }
     152         494 : }
     153             : 
     154             : template <typename UserObjectType, typename BaseType>
     155         479 : NearestPointBase<UserObjectType, BaseType>::~NearestPointBase()
     156             : {
     157         479 : }
     158             : 
     159             : template <typename UserObjectType, typename BaseType>
     160             : void
     161         518 : NearestPointBase<UserObjectType, BaseType>::fillPoints()
     162             : {
     163         518 :   if (isParamValid("points"))
     164             :   {
     165         440 :     _points = this->template getParam<std::vector<Point>>("points");
     166         440 :     if (isParamValid("points_file"))
     167           4 :       this->paramError("points_file", "Cannot be specified together with 'points'");
     168         436 :     if (isParamValid("positions_object"))
     169           0 :       this->paramError("positions_object", "Cannot be specified together with 'points'");
     170             :   }
     171          78 :   else if (isParamValid("points_file"))
     172             :   {
     173          60 :     const FileName & points_file = this->template getParam<FileName>("points_file");
     174             : 
     175          60 :     MooseUtils::DelimitedFileReader file(points_file, &_communicator);
     176          60 :     file.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
     177          60 :     file.read();
     178          60 :     _points = file.getDataAsPoints();
     179             : 
     180          56 :     if (isParamValid("positions_object"))
     181           0 :       this->paramError("positions_object", "Cannot be specified together with 'points_file'");
     182          56 :   }
     183          18 :   else if (isParamValid("positions_object"))
     184             :   {
     185          14 :     const auto & positions_name = this->template getParam<PositionsName>("positions_object");
     186          14 :     const auto problem = this->template getCheckedPointerParam<FEProblemBase *>("_fe_problem_base");
     187          14 :     _points = problem->getPositionsObject(positions_name).getPositions(/*initial_positions*/ true);
     188             :   }
     189             :   else
     190           8 :     mooseError(
     191           4 :         name(),
     192             :         ": You need to supply either 'points', 'points_file' or 'positions_object' parameter.");
     193         506 : }
     194             : 
     195             : template <typename UserObjectType, typename BaseType>
     196             : void
     197        1016 : NearestPointBase<UserObjectType, BaseType>::initialize()
     198             : {
     199        4719 :   for (auto & user_object : _user_objects)
     200        3703 :     user_object->initialize();
     201        1016 : }
     202             : 
     203             : template <typename UserObjectType, typename BaseType>
     204             : void
     205      902391 : NearestPointBase<UserObjectType, BaseType>::execute()
     206             : {
     207      902391 :   nearestUserObject(_current_elem->vertex_average()).execute();
     208      902391 : }
     209             : 
     210             : template <typename UserObjectType, typename BaseType>
     211             : void
     212         738 : NearestPointBase<UserObjectType, BaseType>::finalize()
     213             : {
     214        3662 :   for (auto & user_object : _user_objects)
     215        2924 :     user_object->finalize();
     216         738 : }
     217             : 
     218             : template <typename UserObjectType, typename BaseType>
     219             : void
     220          78 : NearestPointBase<UserObjectType, BaseType>::threadJoin(const UserObject & y)
     221             : {
     222          78 :   auto & npla = static_cast<const NearestPointBase &>(y);
     223             : 
     224         361 :   for (MooseIndex(_user_objects) i = 0; i < _user_objects.size(); ++i)
     225         283 :     _user_objects[i]->threadJoin(*npla._user_objects[i]);
     226          78 : }
     227             : 
     228             : template <typename UserObjectType, typename BaseType>
     229             : Real
     230      934712 : NearestPointBase<UserObjectType, BaseType>::spatialValue(const Point & p) const
     231             : {
     232      934712 :   return nearestUserObject(p).spatialValue(p);
     233             : }
     234             : 
     235             : template <typename UserObjectType, typename BaseType>
     236             : UserObjectType &
     237     1837103 : NearestPointBase<UserObjectType, BaseType>::nearestUserObject(const Point & p) const
     238             : {
     239     1837103 :   unsigned int closest = 0;
     240     1837103 :   Real closest_distance = std::numeric_limits<Real>::max();
     241             : 
     242    10068560 :   for (auto it : Moose::enumerate(_points))
     243             :   {
     244     6394354 :     const auto & current_point = it.value();
     245             : 
     246             :     Real current_distance;
     247     6394354 :     if (_dist_norm == 0)
     248             :       // the distance is computed using standard norm
     249     5148994 :       current_distance = (p - current_point).norm();
     250             :     else
     251             :     {
     252             :       // the distance is to be computed based on radii
     253             :       // in that case, we need to determine the 2 coordinate indices
     254             :       // that define the radius
     255     1245360 :       unsigned int i = 0;
     256     1245360 :       unsigned int j = 1;
     257             : 
     258     1245360 :       if (_axis == 0)
     259           0 :         i = 2;
     260     1245360 :       else if (_axis == 1)
     261           0 :         j = 2;
     262             : 
     263     1245360 :       current_distance = std::abs(
     264     1245360 :           std::sqrt(p(i) * p(i) + p(j) * p(j)) -
     265     1245360 :           std::sqrt(current_point(i) * current_point(i) + current_point(j) * current_point(j)));
     266             :     }
     267             : 
     268     6394354 :     if (current_distance < closest_distance)
     269             :     {
     270     3609611 :       closest_distance = current_distance;
     271     3609611 :       closest = it.index();
     272             :     }
     273             :   }
     274             : 
     275     1837103 :   return *_user_objects[closest];
     276             : }
     277             : 
     278             : template <typename UserObjectType, typename BaseType>
     279             : const std::vector<Point>
     280          39 : NearestPointBase<UserObjectType, BaseType>::spatialPoints() const
     281             : {
     282          39 :   std::vector<Point> points;
     283             : 
     284         208 :   for (MooseIndex(_points) i = 0; i < _points.size(); ++i)
     285             :   {
     286         169 :     auto layered_base = dynamic_cast<LayeredBase *>(_user_objects[i].get());
     287         169 :     if (layered_base)
     288             :     {
     289         169 :       const auto & layers = layered_base->getLayerCenters();
     290         169 :       auto direction = layered_base->direction();
     291             : 
     292         611 :       for (const auto & l : layers)
     293             :       {
     294         442 :         Point pt = _points[i];
     295         442 :         pt(direction) = l;
     296         442 :         points.push_back(pt);
     297             :       }
     298             :     }
     299             :   }
     300             : 
     301          39 :   return points;
     302           0 : }

Generated by: LCOV version 1.14