LCOV - code coverage report
Current view: top level - src/partitioner - GridPartitioner.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 85 89 95.5 %
Date: 2025-07-17 01:28:37 Functions: 6 6 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 "GridPartitioner.h"
      11             : 
      12             : #include "GeneratedMesh.h"
      13             : #include "MooseApp.h"
      14             : 
      15             : #include "libmesh/mesh_tools.h"
      16             : #include "libmesh/elem.h"
      17             : 
      18             : registerMooseObject("MooseApp", GridPartitioner);
      19             : 
      20             : #include <memory>
      21             : 
      22             : InputParameters
      23       16689 : GridPartitioner::validParams()
      24             : {
      25       16689 :   InputParameters params = MoosePartitioner::validParams();
      26             : 
      27       16689 :   MooseEnum method("manual automatic", "manual");
      28       16689 :   params.addParam<MooseEnum>(
      29             :       "grid_computation",
      30             :       method,
      31             :       "Whether to determine the grid manually (using nx, ny and nz) or automatically. When using "
      32             :       "the automatic mode, the user can impose a certain value for nx, ny or nz, and the automatic "
      33             :       "factorization will adjust the number of processors in the other directions.");
      34             : 
      35             :   // Users specify how many processors they need along each direction
      36       16689 :   params.addParam<unsigned int>(
      37             :       "nx", "Number of processors in the X direction. Defaults to 1 in manual mode");
      38       16689 :   params.addParam<unsigned int>(
      39             :       "ny", "Number of processors in the Y direction. Defaults to 1 in manual mode");
      40       16689 :   params.addParam<unsigned int>(
      41             :       "nz", "Number of processors in the Z direction. Defaults to 1 in manual mode");
      42             : 
      43       16689 :   params.addClassDescription("Create a uniform grid that overlays the mesh to be partitioned.  "
      44             :                              "Assign all elements within each cell of the grid to the same "
      45             :                              "processor.");
      46             : 
      47       33378 :   return params;
      48       16689 : }
      49             : 
      50        1826 : GridPartitioner::GridPartitioner(const InputParameters & params)
      51        1826 :   : MoosePartitioner(params), _mesh(*getCheckedPointerParam<MooseMesh *>("mesh"))
      52             : {
      53        1826 : }
      54             : 
      55        3652 : GridPartitioner::~GridPartitioner() {}
      56             : 
      57             : std::unique_ptr<Partitioner>
      58        1228 : GridPartitioner::clone() const
      59             : {
      60        1228 :   return _app.getFactory().clone(*this);
      61             : }
      62             : 
      63             : void
      64         706 : GridPartitioner::_do_partition(MeshBase & mesh, const unsigned int /*n*/)
      65             : {
      66             :   // By default, there are one processor along each direction
      67             :   // nx: the number of processors along x direction
      68             :   // ny: the number of processors along y direction
      69             :   // nz: the number of processors along z direction
      70         706 :   unsigned int nx = 1, ny = 1, nz = 1;
      71             : 
      72             :   // Figure out the physical bounds of the given mesh
      73         706 :   auto bounding_box = MeshTools::create_bounding_box(mesh);
      74         706 :   const auto & min = bounding_box.min();
      75         706 :   const auto & max = bounding_box.max();
      76             : 
      77         706 :   auto dim = mesh.mesh_dimension();
      78             : 
      79             :   // Gather user parameters
      80         706 :   nx = isParamValid("nx") ? getParam<unsigned int>("nx") : nx;
      81         706 :   if (dim >= 2)
      82         706 :     ny = isParamValid("ny") ? getParam<unsigned int>("ny") : ny;
      83         706 :   if (dim == 3)
      84         286 :     nz = isParamValid("nz") ? getParam<unsigned int>("nz") : nz;
      85             : 
      86             :   // simple info message unused parameters as this can be normal: we could be partitioning
      87             :   // a 2D mesh before extruding it to 3D. The nz parameter is needed for the 3D mesh
      88         706 :   if (dim < 2 && isParamValid("ny") && getParam<unsigned int>("ny") > 1)
      89           0 :     paramInfo("ny", "Parameter ignored as mesh is currently of dimension less than 2.");
      90         706 :   if (dim < 3 && isParamValid("nz") && getParam<unsigned int>("nz") > 1)
      91          32 :     paramInfo("nz", "Parameter ignored as mesh is currently of dimension less than 3.");
      92             : 
      93             :   // User parameters, which should match the number of partitions needed
      94         706 :   if (getParam<MooseEnum>("grid_computation") == "manual")
      95             :   {
      96             :     //  Need to make sure the number of grid cells matches the number of procs to partition for
      97         504 :     if ((nx * ny * nz) != mesh.n_partitions())
      98           0 :       mooseError("Number of grid cells (" + std::to_string(nx * ny * nz) +
      99           0 :                  ") does not match the number of MPI processes (" +
     100           0 :                  std::to_string(mesh.n_partitions()) + ")");
     101             :   }
     102             : 
     103         202 :   else if (getParam<MooseEnum>("grid_computation") == "automatic")
     104             :   {
     105             :     // remove over-constraint and tell user
     106         202 :     if (nx * ny * nz > mesh.n_partitions())
     107             :     {
     108          28 :       nx = 0;
     109          28 :       ny = 0;
     110          28 :       nz = 0;
     111          28 :       paramWarning("grid_computation",
     112             :                    "User specified (nx,ny,nz) grid exceeded number of partitions, these parameters "
     113             :                    "will be ignored.");
     114             :     }
     115             :     // 0 means no restriction on which number to choose
     116         404 :     int dims[] = {isParamValid("nx") ? int(nx) : 0,
     117         404 :                   isParamValid("ny") ? int(ny) : 0,
     118         404 :                   isParamValid("nz") ? int(nz) : 0};
     119             : 
     120         124 :     if ((dims[0] > 0 && dim == 1 && dims[0] != int(mesh.n_partitions())) ||
     121         496 :         (dims[0] > 0 && dims[1] > 0 && dim == 2 && dims[0] * dims[1] != int(mesh.n_partitions())) ||
     122         170 :         (dims[0] > 0 && dims[1] > 0 && dims[2] > 0 && dim == 3 &&
     123          64 :          dims[0] * dims[1] * dims[2] != int(mesh.n_partitions())))
     124             :     {
     125          32 :       dims[0] = 0;
     126          32 :       dims[1] = 0;
     127          32 :       dims[2] = 0;
     128          32 :       paramWarning("grid_computation",
     129          64 :                    "User specified grid for the current dimension of the mesh (" +
     130         128 :                        std::to_string(dim) + ") does not fit the number of partitions (" +
     131         128 :                        std::to_string(mesh.n_partitions()) +
     132             :                        ") and constrain the grid partitioner in every direction, these parameters "
     133             :                        "will be ignored.");
     134             :     }
     135             : 
     136             :     // This will error if the factorization is not possible
     137         202 :     MPI_Dims_create(mesh.n_partitions(), dim, dims);
     138             : 
     139         202 :     nx = dims[0];
     140         202 :     if (dim >= 2)
     141         202 :       ny = dims[1];
     142         202 :     if (dim == 3)
     143          70 :       nz = dims[2];
     144             :   }
     145             : 
     146             :   // hx: grid interval along x direction
     147             :   // hy: grid interval along y direction
     148             :   // hz: grid interval along z direction
     149             :   // Lx: domain length along x direction
     150             :   // Ly: domain length along y direction
     151             :   // Lz: domain length along z direction
     152         706 :   Real hx = 1., hy = 1., hz = 1., Lx = 1., Ly = 1., Lz = 1.;
     153         706 :   Lx = max(0) - min(0);
     154         706 :   hx = Lx / nx;
     155         706 :   if (dim >= 2)
     156             :   {
     157         706 :     Ly = max(1) - min(1);
     158         706 :     hy = Ly / ny;
     159             :   }
     160             : 
     161         706 :   if (dim == 3)
     162             :   {
     163         286 :     Lz = max(2) - min(2);
     164         286 :     hz = Lz / nz;
     165             :   }
     166             : 
     167             :   // Processor coordinates along x, y, z directions
     168         706 :   unsigned int k = 0, j = 0, i = 0;
     169             :   // Coordinates for current element centroid
     170         706 :   Real coordx = 0, coordy = 0, coordz = 0;
     171             : 
     172             :   // Loop over all of the elements in the given mesh
     173      251138 :   for (auto & elem_ptr : mesh.active_element_ptr_range())
     174             :   {
     175             :     // Find the element it lands in in the GeneratedMesh
     176      250432 :     auto centroid = elem_ptr->vertex_average();
     177             : 
     178      250432 :     coordx = centroid(0);
     179             :     mooseAssert(coordx >= min(0) && coordy <= max(0),
     180             :                 "element is outside of bounding box along x direction");
     181      250432 :     if (dim >= 2)
     182             :     {
     183      250432 :       coordy = centroid(1);
     184             :       mooseAssert(coordy >= min(1) && coordy <= max(1),
     185             :                   "element is outside of bounding box along y direction");
     186             :     }
     187      250432 :     if (dim == 3)
     188             :     {
     189      212912 :       coordz = centroid(2);
     190             :       mooseAssert(coordz >= min(2) && coordz <= max(2),
     191             :                   "element is outside of bounding box along z direction");
     192             :     }
     193             : 
     194             :     // Compute processor coordinates
     195      250432 :     j = k = 0;
     196      250432 :     i = (coordx - min(0)) / hx;
     197      250432 :     if (dim >= 2)
     198      250432 :       j = (coordy - min(1)) / hy;
     199      250432 :     if (dim == 3)
     200      212912 :       k = (coordz - min(2)) / hz;
     201             : 
     202             :     mooseAssert(i < nx, "Index calculation is wrong along x direction");
     203             :     mooseAssert(j < ny || ny == 0, "Index calculation is wrong along y direction");
     204             :     mooseAssert(k < nz || nz == 0, "Index calculation is wrong along z direction");
     205             :     // Assign processor ID to current element
     206      250432 :     elem_ptr->processor_id() = k * nx * ny + j * nx + i;
     207         706 :   }
     208         706 : }

Generated by: LCOV version 1.14