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 14323 : SphericalGridDivision::validParams() 22 : { 23 14323 : InputParameters params = MeshDivision::validParams(); 24 14323 : params.addClassDescription("Divide the mesh along a spherical grid."); 25 : 26 : // Definition of the sphere(s) 27 14323 : params.addParam<Point>("center", "Center of the sphere"); 28 14323 : params.addParam<PositionsName>("center_positions", "Positions of the centers of the spheres"); 29 : 30 : // Spatial bounds of the sphere 31 14323 : params.addRangeCheckedParam<Real>( 32 : "r_min", 0, "r_min>=0", "Minimum radial coordinate (for a hollow sphere)"); 33 14323 : params.addRequiredRangeCheckedParam<Real>("r_max", "r_max>0", "Maximum radial coordinate"); 34 : 35 : // Number of bins 36 14323 : params.addRequiredRangeCheckedParam<unsigned int>( 37 : "n_radial", "n_radial>0", "Number of divisions in the sphere radial direction"); 38 : 39 42969 : params.addParam<bool>("assign_domain_outside_grid_to_border", 40 28646 : false, 41 : "Whether to map the domain outside the grid back to the border of the grid " 42 : "(radially or axially)"); 43 : 44 14323 : return params; 45 0 : } 46 : 47 32 : SphericalGridDivision::SphericalGridDivision(const InputParameters & parameters) 48 : : MeshDivision(parameters), 49 32 : _center(isParamValid("center") ? &getParam<Point>("center") : nullptr), 50 32 : _center_positions( 51 64 : isParamValid("center_positions") 52 32 : ? &_fe_problem->getPositionsObject(getParam<PositionsName>("center_positions")) 53 : : nullptr), 54 32 : _min_r(getParam<Real>("r_min")), 55 32 : _max_r(getParam<Real>("r_max")), 56 32 : _n_radial(getParam<unsigned int>("n_radial")), 57 64 : _outside_grid_counts_as_border(getParam<bool>("assign_domain_outside_grid_to_border")) 58 : { 59 32 : SphericalGridDivision::initialize(); 60 : 61 : // Check that we know the centers 62 28 : 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 28 : 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 28 : if (_n_radial > 1 && MooseUtils::absoluteFuzzyEqual(_min_r, _max_r)) 71 0 : paramError("n_radial", "Zero-thickness sphere cannot be subdivided radially"); 72 28 : } 73 : 74 : void 75 32 : SphericalGridDivision::initialize() 76 : { 77 32 : if (!_center_positions) 78 14 : setNumDivisions(_n_radial); 79 : else 80 18 : setNumDivisions(_center_positions->getNumPositions() * _n_radial); 81 : 82 : // Check that the grid is well-defined 83 32 : if (_center_positions) 84 : { 85 18 : Real min_dist = 2 * _max_r; 86 18 : 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 18 : 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 28 : _mesh_fully_indexed = true; 100 28 : if (!_outside_grid_counts_as_border || _center_positions) 101 28 : _mesh_fully_indexed = false; 102 28 : } 103 : 104 : unsigned int 105 1440 : SphericalGridDivision::divisionIndex(const Elem & elem) const 106 : { 107 1440 : return divisionIndex(elem.vertex_average()); 108 : } 109 : 110 : unsigned int 111 1440 : SphericalGridDivision::divisionIndex(const Point & pt) const 112 : { 113 : // Compute coordinates of the point in the spherical coordinates 114 1440 : Point pc; 115 1440 : unsigned int offset = 0; 116 1440 : if (_center) 117 720 : pc(0) = (pt - *_center).norm(); 118 : else 119 : { 120 : // If distributing using positions, find the closest position 121 720 : const bool initial = _fe_problem->getCurrentExecuteOnFlag() == EXEC_INITIAL; 122 720 : const auto nearest_center_index = _center_positions->getNearestPositionIndex(pt, initial); 123 720 : offset = nearest_center_index * _n_radial; 124 720 : pc(0) = (pt - _center_positions->getPosition(nearest_center_index, initial)).norm(); 125 : } 126 : 127 1440 : if (!_outside_grid_counts_as_border) 128 : { 129 2862 : if (MooseUtils::absoluteFuzzyLessThan(pc(0), _min_r) || 130 1422 : MooseUtils::absoluteFuzzyGreaterThan(pc(0), _max_r)) 131 18 : return MooseMeshDivision::INVALID_DIVISION_INDEX; 132 : } 133 : 134 1422 : const auto not_found = MooseMeshDivision::INVALID_DIVISION_INDEX; 135 1422 : auto ir = not_found; 136 1422 : const Real width = _max_r - _min_r; 137 : 138 : // Look inside the grid and on the left / back / bottom 139 4122 : for (const auto jr : make_range(_n_radial + 1)) 140 : { 141 4122 : const auto border_r = _min_r + width * jr / _n_radial; 142 4122 : 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 4122 : if (border_r >= pc(0)) 147 : { 148 1422 : ir = jr > 0 ? jr - 1 : 0; 149 1422 : break; 150 : } 151 : } 152 : 153 : // Look beyond the extent of the radial grid 154 1422 : if (MooseUtils::absoluteFuzzyGreaterEqual(pc(0), _max_r)) 155 0 : ir = _n_radial - 1; 156 : 157 : // Handle edge case on widths 158 1422 : 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 1422 : return offset + ir; 163 : }