LCOV - code coverage report
Current view: top level - src/mesh - GeneratedMesh.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 123 136 90.4 %
Date: 2025-08-08 20:01:16 Functions: 6 7 85.7 %
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 "GeneratedMesh.h"
      11             : 
      12             : #include "MooseApp.h"
      13             : 
      14             : #include "libmesh/mesh_generation.h"
      15             : #include "libmesh/string_to_enum.h"
      16             : #include "libmesh/periodic_boundaries.h"
      17             : #include "libmesh/periodic_boundary_base.h"
      18             : #include "libmesh/unstructured_mesh.h"
      19             : #include "libmesh/node.h"
      20             : 
      21             : // C++ includes
      22             : #include <cmath> // provides round, not std::round (see http://www.cplusplus.com/reference/cmath/round/)
      23             : #include <array>
      24             : 
      25             : registerMooseObject("MooseApp", GeneratedMesh);
      26             : 
      27             : InputParameters
      28      118416 : GeneratedMesh::validParams()
      29             : {
      30      118416 :   InputParameters params = MooseMesh::validParams();
      31             : 
      32      118416 :   MooseEnum elem_types(LIST_GEOM_ELEM); // no default
      33             : 
      34      118416 :   MooseEnum dims("1=1 2 3");
      35      118416 :   params.addRequiredParam<MooseEnum>("dim", dims, "The dimension of the mesh to be generated");
      36             : 
      37      118416 :   params.addParam<unsigned int>("nx", 1, "Number of elements in the X direction");
      38      118416 :   params.addParam<unsigned int>("ny", 1, "Number of elements in the Y direction");
      39      118416 :   params.addParam<unsigned int>("nz", 1, "Number of elements in the Z direction");
      40      118416 :   params.addParam<Real>("xmin", 0.0, "Lower X Coordinate of the generated mesh");
      41      118416 :   params.addParam<Real>("ymin", 0.0, "Lower Y Coordinate of the generated mesh");
      42      118416 :   params.addParam<Real>("zmin", 0.0, "Lower Z Coordinate of the generated mesh");
      43      118416 :   params.addParam<Real>("xmax", 1.0, "Upper X Coordinate of the generated mesh");
      44      118416 :   params.addParam<Real>("ymax", 1.0, "Upper Y Coordinate of the generated mesh");
      45      118416 :   params.addParam<Real>("zmax", 1.0, "Upper Z Coordinate of the generated mesh");
      46      118416 :   params.addParam<MooseEnum>("elem_type",
      47             :                              elem_types,
      48             :                              "The type of element from libMesh to "
      49             :                              "generate (default: linear element for "
      50             :                              "requested dimension)");
      51      355248 :   params.addParam<bool>(
      52             :       "gauss_lobatto_grid",
      53      236832 :       false,
      54             :       "Grade mesh into boundaries according to Gauss-Lobatto quadrature spacing.");
      55      355248 :   params.addRangeCheckedParam<Real>(
      56             :       "bias_x",
      57      236832 :       1.,
      58             :       "bias_x>=0.5 & bias_x<=2",
      59             :       "The amount by which to grow (or shrink) the cells in the x-direction.");
      60      355248 :   params.addRangeCheckedParam<Real>(
      61             :       "bias_y",
      62      236832 :       1.,
      63             :       "bias_y>=0.5 & bias_y<=2",
      64             :       "The amount by which to grow (or shrink) the cells in the y-direction.");
      65      355248 :   params.addRangeCheckedParam<Real>(
      66             :       "bias_z",
      67      236832 :       1.,
      68             :       "bias_z>=0.5 & bias_z<=2",
      69             :       "The amount by which to grow (or shrink) the cells in the z-direction.");
      70             : 
      71      118416 :   params.addParamNamesToGroup("dim", "Required");
      72             : 
      73      118416 :   params.addClassDescription(
      74             :       "Create a line, square, or cube mesh with uniformly spaced or biased elements.");
      75      236832 :   return params;
      76      118416 : }
      77             : 
      78       36276 : GeneratedMesh::GeneratedMesh(const InputParameters & parameters)
      79             :   : MooseMesh(parameters),
      80       36276 :     _dim(getParam<MooseEnum>("dim")),
      81       36276 :     _nx(getParam<unsigned int>("nx")),
      82       36276 :     _ny(getParam<unsigned int>("ny")),
      83       36276 :     _nz(getParam<unsigned int>("nz")),
      84       36276 :     _xmin(getParam<Real>("xmin")),
      85       36276 :     _xmax(getParam<Real>("xmax")),
      86       36276 :     _ymin(getParam<Real>("ymin")),
      87       36276 :     _ymax(getParam<Real>("ymax")),
      88       36276 :     _zmin(getParam<Real>("zmin")),
      89       36276 :     _zmax(getParam<Real>("zmax")),
      90       36276 :     _gauss_lobatto_grid(getParam<bool>("gauss_lobatto_grid")),
      91       36276 :     _bias_x(getParam<Real>("bias_x")),
      92       36276 :     _bias_y(getParam<Real>("bias_y")),
      93       36276 :     _bias_z(getParam<Real>("bias_z")),
      94       36276 :     _dims_may_have_changed(false)
      95             : {
      96       36276 :   if (_gauss_lobatto_grid && (_bias_x != 1.0 || _bias_y != 1.0 || _bias_z != 1.0))
      97           0 :     mooseError("Cannot apply both Gauss-Lobatto mesh grading and biasing at the same time.");
      98             : 
      99             :   // All generated meshes are regular orthogonal meshes - until they get modified ;)
     100       36276 :   _regular_orthogonal_mesh = true;
     101       36276 : }
     102             : 
     103             : void
     104           0 : GeneratedMesh::prepared(bool state)
     105             : {
     106           0 :   MooseMesh::prepared(state);
     107             : 
     108             :   // Fall back on scanning the mesh for coordinates instead of using input parameters for queries
     109           0 :   if (!state)
     110           0 :     _dims_may_have_changed = true;
     111           0 : }
     112             : 
     113             : Real
     114       43367 : GeneratedMesh::getMinInDimension(unsigned int component) const
     115             : {
     116       43367 :   if (_dims_may_have_changed)
     117           0 :     return MooseMesh::getMinInDimension(component);
     118             : 
     119       43367 :   switch (component)
     120             :   {
     121         894 :     case 0:
     122         894 :       return _xmin;
     123       20744 :     case 1:
     124       20744 :       return _dim > 1 ? _ymin : 0;
     125       21729 :     case 2:
     126       21729 :       return _dim > 2 ? _zmin : 0;
     127           0 :     default:
     128           0 :       mooseError("Invalid component");
     129             :   }
     130             : }
     131             : 
     132             : Real
     133       43301 : GeneratedMesh::getMaxInDimension(unsigned int component) const
     134             : {
     135       43301 :   if (_dims_may_have_changed)
     136           0 :     return MooseMesh::getMaxInDimension(component);
     137             : 
     138       43301 :   switch (component)
     139             :   {
     140         872 :     case 0:
     141         872 :       return _xmax;
     142       20722 :     case 1:
     143       20722 :       return _dim > 1 ? _ymax : 0;
     144       21707 :     case 2:
     145       21707 :       return _dim > 2 ? _zmax : 0;
     146           0 :     default:
     147           0 :       mooseError("Invalid component");
     148             :   }
     149             : }
     150             : 
     151             : std::unique_ptr<MooseMesh>
     152        1943 : GeneratedMesh::safeClone() const
     153             : {
     154        1943 :   return _app.getFactory().copyConstruct(*this);
     155             : }
     156             : 
     157             : void
     158       34435 : GeneratedMesh::buildMesh()
     159             : {
     160       34435 :   MooseEnum elem_type_enum = getParam<MooseEnum>("elem_type");
     161             : 
     162       34435 :   if (!isParamValid("elem_type"))
     163             :   {
     164             :     // Switching on MooseEnum
     165       28694 :     switch (_dim)
     166             :     {
     167        5222 :       case 1:
     168        5222 :         elem_type_enum = "EDGE2";
     169        5222 :         break;
     170       22275 :       case 2:
     171       22275 :         elem_type_enum = "QUAD4";
     172       22275 :         break;
     173        1197 :       case 3:
     174        1197 :         elem_type_enum = "HEX8";
     175        1197 :         break;
     176             :     }
     177             :   }
     178             : 
     179       34435 :   ElemType elem_type = Utility::string_to_enum<ElemType>(elem_type_enum);
     180             : 
     181             :   // Switching on MooseEnum
     182       34435 :   switch (_dim)
     183             :   {
     184             :     // The build_XYZ mesh generation functions take an
     185             :     // UnstructuredMesh& as the first argument, hence the dynamic_cast.
     186        5577 :     case 1:
     187        5577 :       MeshTools::Generation::build_line(dynamic_cast<UnstructuredMesh &>(getMesh()),
     188             :                                         _nx,
     189             :                                         _xmin,
     190             :                                         _xmax,
     191             :                                         elem_type,
     192        5577 :                                         _gauss_lobatto_grid);
     193        5577 :       break;
     194       27291 :     case 2:
     195       27291 :       MeshTools::Generation::build_square(dynamic_cast<UnstructuredMesh &>(getMesh()),
     196             :                                           _nx,
     197             :                                           _ny,
     198             :                                           _xmin,
     199             :                                           _xmax,
     200             :                                           _ymin,
     201             :                                           _ymax,
     202             :                                           elem_type,
     203       27291 :                                           _gauss_lobatto_grid);
     204       27291 :       break;
     205        1567 :     case 3:
     206        1567 :       MeshTools::Generation::build_cube(dynamic_cast<UnstructuredMesh &>(getMesh()),
     207             :                                         _nx,
     208             :                                         _ny,
     209             :                                         _nz,
     210             :                                         _xmin,
     211             :                                         _xmax,
     212             :                                         _ymin,
     213             :                                         _ymax,
     214             :                                         _zmin,
     215             :                                         _zmax,
     216             :                                         elem_type,
     217        1567 :                                         _gauss_lobatto_grid);
     218        1567 :       break;
     219             :   }
     220             : 
     221             :   // Apply the bias if any exists
     222       34435 :   if (_bias_x != 1.0 || _bias_y != 1.0 || _bias_z != 1.0)
     223             :   {
     224             :     // Reference to the libmesh mesh
     225          22 :     MeshBase & mesh = getMesh();
     226             : 
     227             :     // Biases
     228             :     std::array<Real, LIBMESH_DIM> bias = {
     229          22 :         {_bias_x, _dim > 1 ? _bias_y : 1.0, _dim > 2 ? _bias_z : 1.0}};
     230             : 
     231             :     // "width" of the mesh in each direction
     232             :     std::array<Real, LIBMESH_DIM> width = {
     233          22 :         {_xmax - _xmin, _dim > 1 ? _ymax - _ymin : 0, _dim > 2 ? _zmax - _zmin : 0}};
     234             : 
     235             :     // Min mesh extent in each direction.
     236             :     std::array<Real, LIBMESH_DIM> mins = {
     237          22 :         {getMinInDimension(0), getMinInDimension(1), getMinInDimension(2)}};
     238             : 
     239             :     // Number of elements in each direction.
     240          22 :     std::array<unsigned int, LIBMESH_DIM> nelem = {{_nx, _dim > 1 ? _ny : 1, _dim > 2 ? _nz : 1}};
     241             : 
     242             :     // We will need the biases raised to integer powers in each
     243             :     // direction, so let's pre-compute those...
     244          22 :     std::array<std::vector<Real>, LIBMESH_DIM> pows;
     245          88 :     for (unsigned int dir = 0; dir < LIBMESH_DIM; ++dir)
     246             :     {
     247          66 :       pows[dir].resize(nelem[dir] + 1);
     248         462 :       for (unsigned int i = 0; i < pows[dir].size(); ++i)
     249         396 :         pows[dir][i] = std::pow(bias[dir], static_cast<int>(i));
     250             :     }
     251             : 
     252             :     // Loop over the nodes and move them to the desired location
     253       16438 :     for (auto & node_ptr : mesh.node_ptr_range())
     254             :     {
     255       16416 :       Node & node = *node_ptr;
     256             : 
     257       65664 :       for (unsigned int dir = 0; dir < LIBMESH_DIM; ++dir)
     258             :       {
     259       49248 :         if (width[dir] != 0. && bias[dir] != 1.)
     260             :         {
     261             :           // Compute the scaled "index" of the current point.  This
     262             :           // will either be close to a whole integer or a whole
     263             :           // integer+0.5 for quadratic nodes.
     264       32832 :           Real float_index = (node(dir) - mins[dir]) * nelem[dir] / width[dir];
     265             : 
     266       32832 :           Real integer_part = 0;
     267       32832 :           Real fractional_part = std::modf(float_index, &integer_part);
     268             : 
     269             :           // Figure out where to move the node...
     270       32832 :           if (std::abs(fractional_part) < TOLERANCE || std::abs(fractional_part - 1.0) < TOLERANCE)
     271             :           {
     272             :             // If the fractional_part ~ 0.0 or 1.0, this is a vertex node, so
     273             :             // we don't need an average.
     274             :             //
     275             :             // Compute the "index" we are at in the current direction.  We
     276             :             // round to the nearest integral value to get this instead
     277             :             // of using "integer_part", since that could be off by a
     278             :             // lot (e.g. we want 3.9999 to map to 4.0 instead of 3.0).
     279       20029 :             int index = round(float_index);
     280             : 
     281             :             mooseAssert(index >= static_cast<int>(0) && index < static_cast<int>(pows[dir].size()),
     282             :                         "Scaled \"index\" out of range");
     283             : 
     284             :             // Move node to biased location.
     285       20029 :             node(dir) =
     286       20029 :                 mins[dir] + width[dir] * (1. - pows[dir][index]) / (1. - pows[dir][nelem[dir]]);
     287             :           }
     288       12803 :           else if (std::abs(fractional_part - 0.5) < TOLERANCE)
     289             :           {
     290             :             // If the fractional_part ~ 0.5, this is a midedge/face
     291             :             // (i.e. quadratic) node.  We don't move those with the same
     292             :             // bias as the vertices, instead we put them midway between
     293             :             // their respective vertices.
     294             :             //
     295             :             // Also, since the fractional part is nearly 0.5, we know that
     296             :             // the integer_part will be the index of the vertex to the
     297             :             // left, and integer_part+1 will be the index of the
     298             :             // vertex to the right.
     299       25606 :             node(dir) = mins[dir] +
     300       12803 :                         width[dir] *
     301       12803 :                             (1. - 0.5 * (pows[dir][integer_part] + pows[dir][integer_part + 1])) /
     302       12803 :                             (1. - pows[dir][nelem[dir]]);
     303             :           }
     304             :           else
     305             :           {
     306             :             // We don't yet handle anything higher order than quadratic...
     307           0 :             mooseError("Unable to bias node at node(", dir, ")=", node(dir));
     308             :           }
     309             :         }
     310             :       }
     311          22 :     }
     312          22 :   }
     313       34435 : }

Generated by: LCOV version 1.14