LCOV - code coverage report
Current view: top level - src/meshdivisions - SphericalGridDivision.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 65 74 87.8 %
Date: 2025-07-17 01:28:37 Functions: 5 5 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 "SphericalGridDivision.h"
      11             : #include "MooseMesh.h"
      12             : #include "FEProblemBase.h"
      13             : #include "Positions.h"
      14             : 
      15             : #include "libmesh/elem.h"
      16             : #include <math.h>
      17             : 
      18             : registerMooseObject("MooseApp", SphericalGridDivision);
      19             : 
      20             : InputParameters
      21       14319 : SphericalGridDivision::validParams()
      22             : {
      23       14319 :   InputParameters params = MeshDivision::validParams();
      24       14319 :   params.addClassDescription("Divide the mesh along a spherical grid.");
      25             : 
      26             :   // Definition of the sphere(s)
      27       14319 :   params.addParam<Point>("center", "Center of the sphere");
      28       14319 :   params.addParam<PositionsName>("center_positions", "Positions of the centers of the spheres");
      29             : 
      30             :   // Spatial bounds of the sphere
      31       14319 :   params.addRangeCheckedParam<Real>(
      32             :       "r_min", 0, "r_min>=0", "Minimum radial coordinate (for a hollow sphere)");
      33       14319 :   params.addRequiredRangeCheckedParam<Real>("r_max", "r_max>0", "Maximum radial coordinate");
      34             : 
      35             :   // Number of bins
      36       14319 :   params.addRequiredRangeCheckedParam<unsigned int>(
      37             :       "n_radial", "n_radial>0", "Number of divisions in the sphere radial direction");
      38             : 
      39       42957 :   params.addParam<bool>("assign_domain_outside_grid_to_border",
      40       28638 :                         false,
      41             :                         "Whether to map the domain outside the grid back to the border of the grid "
      42             :                         "(radially or axially)");
      43             : 
      44       14319 :   return params;
      45           0 : }
      46             : 
      47          30 : SphericalGridDivision::SphericalGridDivision(const InputParameters & parameters)
      48             :   : MeshDivision(parameters),
      49          30 :     _center(isParamValid("center") ? &getParam<Point>("center") : nullptr),
      50          30 :     _center_positions(
      51          60 :         isParamValid("center_positions")
      52          30 :             ? &_fe_problem->getPositionsObject(getParam<PositionsName>("center_positions"))
      53             :             : nullptr),
      54          30 :     _min_r(getParam<Real>("r_min")),
      55          30 :     _max_r(getParam<Real>("r_max")),
      56          30 :     _n_radial(getParam<unsigned int>("n_radial")),
      57          60 :     _outside_grid_counts_as_border(getParam<bool>("assign_domain_outside_grid_to_border"))
      58             : {
      59          30 :   SphericalGridDivision::initialize();
      60             : 
      61             :   // Check that we know the centers
      62          26 :   if (!_center && !_center_positions)
      63           0 :     paramError("center", "You must pass a parameter for the center of the spherical frame");
      64             : 
      65             :   // Check non-negative size
      66          26 :   if (_max_r < _min_r)
      67           0 :     paramError("r_min", "Maximum radius must be larger than minimum radius");
      68             : 
      69             :   // Check non-zero size if subdivided
      70          26 :   if (_n_radial > 1 && MooseUtils::absoluteFuzzyEqual(_min_r, _max_r))
      71           0 :     paramError("n_radial", "Zero-thickness sphere cannot be subdivided radially");
      72          26 : }
      73             : 
      74             : void
      75          30 : SphericalGridDivision::initialize()
      76             : {
      77          30 :   if (!_center_positions)
      78          13 :     setNumDivisions(_n_radial);
      79             :   else
      80          17 :     setNumDivisions(_center_positions->getNumPositions() * _n_radial);
      81             : 
      82             :   // Check that the grid is well-defined
      83          30 :   if (_center_positions)
      84             :   {
      85          17 :     Real min_dist = 2 * _max_r;
      86          17 :     Real min_center_dist = _center_positions->getMinDistanceBetweenPositions();
      87             :     // Note that if the positions are not co-planar, the distance reported would be bigger but there
      88             :     // could still be an overlap. Looking at min_center_dist is not enough
      89          17 :     if (MooseUtils::absoluteFuzzyGreaterThan(min_dist, min_center_dist))
      90           4 :       mooseWarning(
      91             :           "Spherical grids centered on the positions are too close to each other (min distance: ",
      92             :           min_center_dist,
      93             :           "), closer than the radial extent of each grid. Mesh division is ill-defined");
      94             :   }
      95             : 
      96             :   // We could alternatively check every point in the mesh but it seems expensive
      97             :   // A bounding box check could also suffice but the sphere would need to be excessively large to
      98             :   // enclose the entire mesh
      99          26 :   _mesh_fully_indexed = true;
     100          26 :   if (!_outside_grid_counts_as_border || _center_positions)
     101          26 :     _mesh_fully_indexed = false;
     102          26 : }
     103             : 
     104             : unsigned int
     105        1280 : SphericalGridDivision::divisionIndex(const Elem & elem) const
     106             : {
     107        1280 :   return divisionIndex(elem.vertex_average());
     108             : }
     109             : 
     110             : unsigned int
     111        1280 : SphericalGridDivision::divisionIndex(const Point & pt) const
     112             : {
     113             :   // Compute coordinates of the point in the spherical coordinates
     114        1280 :   Point pc;
     115        1280 :   unsigned int offset = 0;
     116        1280 :   if (_center)
     117         640 :     pc(0) = (pt - *_center).norm();
     118             :   else
     119             :   {
     120             :     // If distributing using positions, find the closest position
     121         640 :     const bool initial = _fe_problem->getCurrentExecuteOnFlag() == EXEC_INITIAL;
     122         640 :     const auto nearest_center_index = _center_positions->getNearestPositionIndex(pt, initial);
     123         640 :     offset = nearest_center_index * _n_radial;
     124         640 :     pc(0) = (pt - _center_positions->getPosition(nearest_center_index, initial)).norm();
     125             :   }
     126             : 
     127        1280 :   if (!_outside_grid_counts_as_border)
     128             :   {
     129        2544 :     if (MooseUtils::absoluteFuzzyLessThan(pc(0), _min_r) ||
     130        1264 :         MooseUtils::absoluteFuzzyGreaterThan(pc(0), _max_r))
     131          16 :       return MooseMeshDivision::INVALID_DIVISION_INDEX;
     132             :   }
     133             : 
     134        1264 :   const auto not_found = MooseMeshDivision::INVALID_DIVISION_INDEX;
     135        1264 :   auto ir = not_found;
     136        1264 :   const Real width = _max_r - _min_r;
     137             : 
     138             :   // Look inside the grid and on the left / back / bottom
     139        3664 :   for (const auto jr : make_range(_n_radial + 1))
     140             :   {
     141        3664 :     const auto border_r = _min_r + width * jr / _n_radial;
     142        3664 :     if (jr > 0 && jr < _n_radial && MooseUtils::absoluteFuzzyEqual(border_r, pc(0)))
     143           0 :       mooseWarning(
     144           0 :           "Querying the division index for a point of a boundary between two regions radially: " +
     145           0 :           Moose::stringify(pt));
     146        3664 :     if (border_r >= pc(0))
     147             :     {
     148        1264 :       ir = jr > 0 ? jr - 1 : 0;
     149        1264 :       break;
     150             :     }
     151             :   }
     152             : 
     153             :   // Look beyond the extent of the radial grid
     154        1264 :   if (MooseUtils::absoluteFuzzyGreaterEqual(pc(0), _max_r))
     155           0 :     ir = _n_radial - 1;
     156             : 
     157             :   // Handle edge case on widths
     158        1264 :   if (ir == not_found && MooseUtils::absoluteFuzzyEqual(width, 0))
     159           0 :     ir = 0;
     160             : 
     161             :   mooseAssert(ir != not_found, "We should have found a mesh division bin radially");
     162        1264 :   return offset + ir;
     163             : }

Generated by: LCOV version 1.14