LCOV - code coverage report
Current view: top level - src/mesh - NekRSMesh.C (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: 9f356e Lines: 348 396 87.9 %
Date: 2026-08-19 15:42:22 Functions: 22 25 88.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /********************************************************************/
       2             : /*                  SOFTWARE COPYRIGHT NOTIFICATION                 */
       3             : /*                             Cardinal                             */
       4             : /*                                                                  */
       5             : /*                  (c) 2021 UChicago Argonne, LLC                  */
       6             : /*                        ALL RIGHTS RESERVED                       */
       7             : /*                                                                  */
       8             : /*                 Prepared by UChicago Argonne, LLC                */
       9             : /*               Under Contract No. DE-AC02-06CH11357               */
      10             : /*                With the U. S. Department of Energy               */
      11             : /*                                                                  */
      12             : /*             Prepared by Battelle Energy Alliance, LLC            */
      13             : /*               Under Contract No. DE-AC07-05ID14517               */
      14             : /*                With the U. S. Department of Energy               */
      15             : /*                                                                  */
      16             : /*                 See LICENSE for full restrictions                */
      17             : /********************************************************************/
      18             : 
      19             : #ifdef ENABLE_NEK_COUPLING
      20             : 
      21             : #include "NekRSMesh.h"
      22             : #include "libmesh/face_quad4.h"
      23             : #include "libmesh/face_quad9.h"
      24             : #include "libmesh/cell_hex8.h"
      25             : #include "libmesh/cell_hex27.h"
      26             : #include "inipp.hpp"
      27             : #include "nekrs.hpp"
      28             : #include "CardinalUtils.h"
      29             : #include "VariadicTable.h"
      30             : 
      31             : registerMooseObject("CardinalApp", NekRSMesh);
      32             : 
      33             : InputParameters
      34        1531 : NekRSMesh::validParams()
      35             : {
      36        1531 :   InputParameters params = MooseMesh::validParams();
      37        3062 :   params.addParam<std::vector<int>>("boundary",
      38             :                                     "Boundary ID(s) through which nekRS will be coupled to MOOSE");
      39        3062 :   params.addParam<bool>("volume", false, "Whether the nekRS volume will be coupled to MOOSE");
      40        3062 :   params.addParam<bool>("exact", false, "Whether the mesh mirror is an exact replica of the NekRS mesh");
      41        3062 :   params.addParam<MooseEnum>(
      42        3062 :       "order", getNekOrderEnum(), "Order of the mesh interpolation between nekRS and MOOSE");
      43        4593 :   params.addRangeCheckedParam<Real>(
      44        3062 :       "scaling", 1.0, "scaling > 0.0", "Scaling factor to apply to the mesh");
      45        3062 :   params.addParam<unsigned int>("fluid_block_id", 0, "Subdomain ID to use for the fluid mesh mirror");
      46        3062 :   params.addParam<unsigned int>("solid_block_id", 1, "Subdomain ID to use for the solid mesh mirror");
      47        1531 :   params.addClassDescription(
      48             :       "Construct a mirror of the NekRS mesh in boundary and/or volume format");
      49        1531 :   return params;
      50           0 : }
      51             : 
      52         763 : NekRSMesh::NekRSMesh(const InputParameters & parameters)
      53             :   : MooseMesh(parameters),
      54         763 :     _volume(getParam<bool>("volume")),
      55        2254 :     _boundary(isParamValid("boundary") ? &getParam<std::vector<int>>("boundary") : nullptr),
      56        1526 :     _order(getParam<MooseEnum>("order").getEnum<order::NekOrderEnum>()),
      57        1526 :     _exact(getParam<bool>("exact")),
      58        1526 :     _scaling(getParam<Real>("scaling")),
      59        1526 :     _fluid_block_id(getParam<unsigned int>("fluid_block_id")),
      60        1526 :     _solid_block_id(getParam<unsigned int>("solid_block_id")),
      61         763 :     _n_surface_elems(0),
      62        1526 :     _n_volume_elems(0)
      63             : {
      64         763 :   if (_exact && _order != order::first)
      65           1 :     mooseError("When building an exact mesh mirror, the 'order' must be FIRST!");
      66             : 
      67         762 :   if (!_boundary && !_volume)
      68           0 :     mooseError("This mesh requires at least 'volume = true' or a list of IDs in 'boundary'!");
      69             : 
      70         762 :   if (_boundary && _boundary->empty())
      71           0 :     paramError("boundary", "The length of 'boundary' must be greater than zero!");
      72             : 
      73             :   // see if NekRS's mesh even exists
      74         762 :   if (!nekrs::isInitialized())
      75           1 :     mooseError("This mesh can only be used with wrapped Nek cases! "
      76             :                "You need to change the problem type to NekRSProblem.");
      77             : 
      78         761 :   _nek_internal_mesh = nekrs::entireMesh();
      79             : 
      80         761 :   nekrs::initializeHostMeshParameters();
      81         761 :   nekrs::updateHostMeshParameters();
      82             : 
      83             :   // nekRS will only ever support 3-D meshes. Just to be sure that this remains
      84             :   // the case for future Cardinal developers, throw an error if the mesh isn't 3-D
      85             :   // (since this would affect how we construct the mesh here).
      86         761 :   int dimension = nekrs::dim();
      87         761 :   if (dimension != 3)
      88           0 :     mooseError("This mesh assumes that the nekRS mesh dimension is 3!\n\nYour mesh is "
      89           0 :                "dimension " +
      90           0 :                std::to_string(dimension) + ".");
      91             : 
      92             :   // if doing a JIT build, the boundary information does not exist yet
      93         761 :   if (!nekrs::buildOnly() && _boundary)
      94             :   {
      95             :     int first_invalid_id, n_boundaries;
      96         363 :     bool valid_ids = nekrs::validBoundaryIDs(*_boundary, first_invalid_id, n_boundaries);
      97             : 
      98         363 :     if (!valid_ids)
      99           1 :       mooseError("Invalid 'boundary' entry: ",
     100             :                  first_invalid_id,
     101             :                  "\n\n"
     102             :                  "nekRS assumes the boundary IDs are ordered contiguously beginning at 1. "
     103             :                  "For this problem, nekRS has ",
     104             :                  n_boundaries,
     105             :                  " boundaries. "
     106             :                  "Did you enter a valid 'boundary'?");
     107             :   }
     108             : 
     109         760 :   _corner_indices = nekrs::cornerGLLIndices(nekrs::entireMesh()->N, _exact);
     110         760 : }
     111             : 
     112             : void
     113           1 : NekRSMesh::saveInitialVolMesh()
     114             : {
     115             :   // save the initial mesh structure in case we are applying displacements
     116             :   // (which are additive to the initial mesh structure)
     117             : 
     118           1 :   long ngllpts = _nek_internal_mesh->Nelements * _nek_internal_mesh->Np;
     119             : 
     120           1 :   _initial_x.resize(ngllpts,0.0);
     121           1 :   _initial_y.resize(ngllpts,0.0);
     122           1 :   _initial_z.resize(ngllpts,0.0);
     123             : 
     124           1 :   auto [x, y, z] = nekrs::host_xyz();
     125             : 
     126           1 :   memcpy(_initial_x.data(), nekrs::host_x(), ngllpts * sizeof(double));
     127           1 :   memcpy(_initial_y.data(), nekrs::host_y(), ngllpts * sizeof(double));
     128           1 :   memcpy(_initial_z.data(), nekrs::host_z(), ngllpts * sizeof(double));
     129           1 : }
     130             : 
     131             : void
     132           0 : NekRSMesh::initializePreviousDisplacements()
     133             : {
     134           0 :   long disp_length = _volume ? _n_vertices_per_volume * _n_volume_elems
     135           0 :            : _n_vertices_per_surface * _n_surface_elems;
     136           0 :   _prev_disp_x.resize(disp_length,0.0);
     137           0 :   _prev_disp_y.resize(disp_length,0.0);
     138           0 :   _prev_disp_z.resize(disp_length,0.0);
     139           0 : }
     140             : 
     141             : void
     142         747 : NekRSMesh::printMeshInfo() const
     143             : {
     144         747 :   _console << "\nNekRS mesh mapping to MOOSE:" << std::endl;
     145             :   VariadicTable<std::string, int, std::string, int, int> vt(
     146         747 :       {"", "Order", "Boundaries", "# Side Elems", "# Volume Elems"});
     147             : 
     148             :   std::vector<int> nek_bids;
     149        4609 :   for (int i = 1; i <= nekrs::NboundaryID(); ++i)
     150        3862 :     nek_bids.push_back(i);
     151             : 
     152        1494 :   vt.addRow("NekRS mesh",
     153             :             nekrs::polynomialOrder(),
     154        1494 :             Moose::stringify(nek_bids),
     155         747 :             _nek_n_surface_elems,
     156         747 :             _nek_n_volume_elems);
     157             : 
     158         747 :   std::string boundaries = "";
     159         747 :   if (_boundary)
     160         706 :     boundaries = Moose::stringify(*_boundary);
     161             :   else
     162         788 :     boundaries = Moose::stringify(nek_bids);
     163        1494 :   vt.addRow("NekRS mirror", _order + 1, boundaries, _n_surface_elems * _n_build_per_surface_elem,
     164         747 :     _n_volume_elems * _n_build_per_volume_elem);
     165             : 
     166         747 :   vt.print(_console);
     167         747 :   _console << std::endl;
     168         747 : }
     169             : 
     170             : std::unique_ptr<MooseMesh>
     171           4 : NekRSMesh::safeClone() const
     172             : {
     173           4 :   return _app.getFactory().copyConstruct(*this);
     174             : }
     175             : 
     176             : int
     177        1494 : NekRSMesh::numQuadraturePoints1D() const
     178             : {
     179        1494 :   return _order + 2;
     180             : }
     181             : 
     182             : int
     183         294 : NekRSMesh::nekNumQuadraturePoints1D() const
     184             : {
     185         294 :   return _nek_polynomial_order + 1;
     186             : }
     187             : 
     188             : void
     189         760 : NekRSMesh::initializeMeshParams()
     190             : {
     191         760 :   _nek_polynomial_order = nekrs::polynomialOrder();
     192         760 :   _n_build_per_surface_elem = _exact ? _nek_polynomial_order * _nek_polynomial_order : 1;
     193         760 :   _n_build_per_volume_elem = _exact ? std::pow(_nek_polynomial_order, 3) : 1;
     194             : 
     195             :   /**
     196             :    * The libMesh face numbering for a 3-D hexagonal element is
     197             :    *            0
     198             :    *            ^    3
     199             :    *            |   /
     200             :    *         o--------o
     201             :    *        /:  | /  /|
     202             :    *       / :  |/  / |
     203             :    *      /  :     /  |
     204             :    *     o--------o  -|-> 2
     205             :    *  4<-|-  o....|...o
     206             :    *     |  .     |  /
     207             :    *     | .  /|  | /
     208             :    *     |.  / |  |/
     209             :    *     o--------o
     210             :    *       /   |
     211             :    *      1    5
     212             :    *
     213             :    * but for nekRS it is
     214             :    *            3
     215             :    *            ^    5
     216             :    *            |   /
     217             :    *         o--------o
     218             :    *        /:  | /  /|
     219             :    *       / :  |/  / |
     220             :    *      /  :     /  |
     221             :    *     o--------o  -|-> 2
     222             :    *  4<-|-  o....|...o
     223             :    *     |  .     |  /
     224             :    *     | .  /|  | /
     225             :    *     |.  / |  |/
     226             :    *     o--------o
     227             :    *       /   |
     228             :    *      0    1
     229             : 
     230             :    */
     231         760 :   _side_index = {1, 5, 2, 0, 4, 3};
     232             : 
     233         760 :   switch (_order)
     234             :   {
     235         703 :     case order::first:
     236         703 :       _n_vertices_per_surface = 4;
     237         703 :       _n_vertices_per_volume = 8;
     238             : 
     239             :       /** The libMesh node numbering for Quad 4 is
     240             :        *
     241             :        *  3 -- 2
     242             :        *  |    |
     243             :        *  0 -- 1
     244             :        *
     245             :        *  but for nekRS it is
     246             :        *
     247             :        *  2 -- 3
     248             :        *  |    |
     249             :        *  0 -- 1
     250             :        **/
     251         703 :       _bnd_node_index = {0, 1, 3, 2};
     252             : 
     253             :       /** The libMesh node number for Hex 8 is
     254             :        *         3        2
     255             :        *         o--------o
     256             :        *        /:       /|
     257             :        *       / :      / |
     258             :        *    0 /  :   1 /  |
     259             :        *     o--------o   |
     260             :        *     |   o....|...o 6
     261             :        *     |  .7    |  /
     262             :        *     | .      | /
     263             :        *     |.       |/
     264             :        *     o--------o
     265             :        *     4        5
     266             :        *
     267             :        * but for nekRS it is
     268             :        *
     269             :        *         6        7
     270             :        *         o--------o
     271             :        *        /:       /|
     272             :        *       / :      / |
     273             :        *    2 /  :   3 /  |
     274             :        *     o--------o   |
     275             :        *     |   o....|...o 5
     276             :        *     |  .4    |  /
     277             :        *     | .      | /
     278             :        *     |.       |/
     279             :        *     o--------o
     280             :        *     0        1
     281             :        */
     282         703 :       _vol_node_index = {2, 3, 7, 6, 0, 1, 5, 4};
     283             : 
     284         703 :       break;
     285          57 :     case order::second:
     286          57 :       _n_vertices_per_surface = 9;
     287          57 :       _n_vertices_per_volume = 27;
     288             : 
     289             :       /** The libMesh node numbering for Quad 9 is
     290             :        *
     291             :        *  3 - 6 - 2
     292             :        *  |       |
     293             :        *  7   8   5
     294             :        *  |       |
     295             :        *  0 - 4 - 1
     296             :        *
     297             :        *  but for nekRS it is
     298             :        *
     299             :        *  6 - 7 - 8
     300             :        *  |       |
     301             :        *  3   4   5
     302             :        *  |       |
     303             :        *  0 - 1 - 2
     304             :        **/
     305          57 :       _bnd_node_index = {0, 2, 8, 6, 1, 5, 7, 3, 4};
     306             : 
     307             :       /** The libMesh node numbering for Hex 27 is
     308             :        *
     309             :        *
     310             :        *               3              10             2
     311             :        *              o--------------o--------------o
     312             :        *             /:             /              /|
     313             :        *            / :            /              / |
     314             :        *           /  :           /              /  |
     315             :        *        11/   :        20/             9/   |
     316             :        *         o--------------o--------------o    |
     317             :        *        /     :        /              /|    |
     318             :        *       /    15o       /    23o       / |  14o
     319             :        *      /       :      /              /  |   /|
     320             :        *    0/        :    8/             1/   |  / |
     321             :        *    o--------------o--------------o    | /  |
     322             :        *    |         :    |   26         |    |/   |
     323             :        *    |  24o    :    |    o         |  22o    |
     324             :        *    |         :    |       18     |   /|    |
     325             :        *    |        7o....|.........o....|../.|....o
     326             :        *    |        .     |              | /  |   / 6
     327             :        *    |       .    21|            13|/   |  /
     328             :        * 12 o--------------o--------------o    | /
     329             :        *    |     .        |              |    |/
     330             :        *    |  19o         | 25o          |    o
     331             :        *    |   .          |              |   / 17
     332             :        *    |  .           |              |  /
     333             :        *    | .            |              | /
     334             :        *    |.             |              |/
     335             :        *    o--------------o--------------o
     336             :        *    4              16              5
     337             :        *
     338             :        * but for nekRS it is
     339             :        *
     340             :        *               24             25             26
     341             :        *              o--------------o--------------o
     342             :        *             /:             /              /|
     343             :        *            / :            /              / |
     344             :        *           /  :           /              /  |
     345             :        *        15/   :        16/            17/   |
     346             :        *         o--------------o--------------o    |
     347             :        *        /     :        /              /|    |
     348             :        *       /    21o       /    22o       / |  23o
     349             :        *      /       :      /              /  |   /|
     350             :        *    6/        :    7/             8/   |  / |
     351             :        *    o--------------o--------------o    | /  |
     352             :        *    |         :    |   13         |    |/   |
     353             :        *    |  12o    :    |    o         |  14o    |
     354             :        *    |         :    |       19     |   /|    |
     355             :        *    |       18o....|.........o....|../.|....o
     356             :        *    |        .     |              | /  |   / 20
     357             :        *    |       .     4|             5|/   |  /
     358             :        *  3 o--------------o--------------o    | /
     359             :        *    |     .        |              |    |/
     360             :        *    |   9o         | 10o          |    o
     361             :        *    |   .          |              |   / 11
     362             :        *    |  .           |              |  /
     363             :        *    | .            |              | /
     364             :        *    |.             |              |/
     365             :        *    o--------------o--------------o
     366             :        *    0              1              2
     367             :        */
     368         114 :       _vol_node_index = {6,  8,  26, 24, 0,  2, 20, 18, 7,  17, 25, 15, 3, 5,
     369          57 :                          23, 21, 1,  11, 19, 9, 16, 4,  14, 22, 12, 10, 13};
     370             : 
     371          57 :       break;
     372           0 :     default:
     373           0 :       mooseError("Unhandled 'NekOrderEnum' in 'NekRSMesh'!");
     374             :   }
     375         760 : }
     376             : 
     377             : void
     378           0 : NekRSMesh::buildDummyMesh()
     379             : {
     380             :   int e = 1;
     381           0 :   auto elem = new Quad4;
     382           0 :   elem->set_id() = e;
     383           0 :   elem->processor_id() = 0;
     384           0 :   _mesh->add_elem(elem);
     385             : 
     386             :   Point pt1(0.0, 0.0, 0.0);
     387             :   Point pt2(1.0, 0.0, 0.0);
     388             :   Point pt3(1.0, 1.0, 0.0);
     389             :   Point pt4(0.0, 1.0, 0.0);
     390             : 
     391           0 :   elem->set_node(0) = _mesh->add_point(pt1);
     392           0 :   elem->set_node(1) = _mesh->add_point(pt2);
     393           0 :   elem->set_node(2) = _mesh->add_point(pt3);
     394           0 :   elem->set_node(3) = _mesh->add_point(pt4);
     395             : 
     396           0 :   _mesh->prepare_for_use();
     397           0 : }
     398             : 
     399             : void
     400         362 : NekRSMesh::storeBoundaryCoupling()
     401             : {
     402         362 :   int rank = nekrs::commRank();
     403         362 :   int max_possible_surfaces = _nek_internal_mesh->NboundaryFaces;
     404             : 
     405         362 :   int * etmp = (int *)malloc(max_possible_surfaces * sizeof(int));
     406         362 :   int * ftmp = (int *)malloc(max_possible_surfaces * sizeof(int));
     407         362 :   int * ptmp = (int *)malloc(max_possible_surfaces * sizeof(int));
     408         362 :   int * btmp = (int *)malloc(max_possible_surfaces * sizeof(int));
     409         362 :   int * element = (int *)malloc(max_possible_surfaces * sizeof(int));
     410         362 :   int * face = (int *)malloc(max_possible_surfaces * sizeof(int));
     411         362 :   int * process = (int *)malloc(max_possible_surfaces * sizeof(int));
     412         362 :   int * boundary_id = (int *)malloc(max_possible_surfaces * sizeof(int));
     413             : 
     414             :   // number of faces on boundary of interest for this process
     415         362 :   int Nfaces = 0;
     416             : 
     417             :   int d = 0;
     418      176322 :   for (int i = 0; i < _nek_internal_mesh->Nelements; ++i)
     419             :   {
     420     1231720 :     for (int j = 0; j < _nek_internal_mesh->Nfaces; ++j)
     421             :     {
     422     1055760 :       int face_id = _nek_internal_mesh->EToB[i * _nek_internal_mesh->Nfaces + j];
     423             : 
     424     1055760 :       if (std::find(_boundary->begin(), _boundary->end(), face_id) != _boundary->end())
     425             :       {
     426       37606 :         Nfaces += 1;
     427             : 
     428       37606 :         etmp[d] = i;
     429       37606 :         ftmp[d] = j;
     430       37606 :         ptmp[d] = rank;
     431       37606 :         btmp[d] = face_id;
     432       37606 :         d++;
     433             :       }
     434             :     }
     435             :   }
     436             : 
     437             :   // gather all the boundary face counters and make available in N
     438         362 :   MPI_Allreduce(&Nfaces, &_n_surface_elems, 1, MPI_INT, MPI_SUM, platform->comm.mpiComm());
     439         362 :   _boundary_coupling.n_faces = Nfaces;
     440         362 :   _boundary_coupling.total_n_faces = _n_surface_elems;
     441             : 
     442             :   // make available to all processes the number of faces owned by each process
     443         362 :   _boundary_coupling.counts.resize(nekrs::commSize());
     444         362 :   MPI_Allgather(
     445             :       &Nfaces, 1, MPI_INT, &_boundary_coupling.counts[0], 1, MPI_INT, platform->comm.mpiComm());
     446             : 
     447         362 :   int N_mirror_faces = Nfaces * _n_build_per_surface_elem;
     448         362 :   _boundary_coupling.mirror_counts.resize(nekrs::commSize());
     449         362 :   MPI_Allgather(&N_mirror_faces,
     450             :                 1,
     451             :                 MPI_INT,
     452             :                 &_boundary_coupling.mirror_counts[0],
     453             :                 1,
     454             :                 MPI_INT,
     455             :                 platform->comm.mpiComm());
     456             : 
     457             :   // compute the counts and displacements for face-based data exchange
     458         362 :   int * recvCounts = (int *)calloc(nekrs::commSize(), sizeof(int));
     459         362 :   int * displacement = (int *)calloc(nekrs::commSize(), sizeof(int));
     460         362 :   nekrs::displacementAndCounts(_boundary_coupling.counts, recvCounts, displacement, 1);
     461             : 
     462         362 :   _boundary_coupling.offset = displacement[rank];
     463             : 
     464         362 :   nekrs::allgatherv(_boundary_coupling.counts, etmp, element);
     465         362 :   nekrs::allgatherv(_boundary_coupling.counts, ftmp, face);
     466         362 :   nekrs::allgatherv(_boundary_coupling.counts, ptmp, process);
     467         362 :   nekrs::allgatherv(_boundary_coupling.counts, btmp, boundary_id);
     468             : 
     469      436256 :   for (int i = 0; i < max_possible_surfaces; ++i)
     470             :   {
     471      435894 :     _boundary_coupling.element.push_back(element[i]);
     472      435894 :     _boundary_coupling.face.push_back(face[i]);
     473      435894 :     _boundary_coupling.process.push_back(process[i]);
     474      435894 :     _boundary_coupling.boundary_id.push_back(boundary_id[i]);
     475             :   }
     476             : 
     477             :   freePointer(recvCounts);
     478             :   freePointer(displacement);
     479             :   freePointer(etmp);
     480             :   freePointer(ftmp);
     481             :   freePointer(ptmp);
     482             :   freePointer(btmp);
     483             :   freePointer(element);
     484             :   freePointer(face);
     485             :   freePointer(process);
     486             :   freePointer(boundary_id);
     487         362 : }
     488             : 
     489             : void
     490         451 : NekRSMesh::storeVolumeCoupling()
     491             : {
     492         451 :   int rank = nekrs::commRank();
     493             : 
     494         451 :   _volume_coupling.n_elems = _nek_internal_mesh->Nelements;
     495         451 :   MPI_Allreduce(
     496             :       &_volume_coupling.n_elems, &_n_volume_elems, 1, MPI_INT, MPI_SUM, platform->comm.mpiComm());
     497         451 :   _volume_coupling.total_n_elems = _n_volume_elems;
     498             : 
     499         451 :   _volume_coupling.counts.resize(nekrs::commSize());
     500         451 :   MPI_Allgather(&_volume_coupling.n_elems,
     501             :                 1,
     502             :                 MPI_INT,
     503             :                 &_volume_coupling.counts[0],
     504             :                 1,
     505             :                 MPI_INT,
     506             :                 platform->comm.mpiComm());
     507             : 
     508         451 :   _volume_coupling.mirror_counts.resize(nekrs::commSize());
     509         451 :   int N_mirror_elems = _volume_coupling.n_elems * _n_build_per_volume_elem;
     510         451 :   MPI_Allgather(&N_mirror_elems,
     511             :                 1,
     512             :                 MPI_INT,
     513             :                 &_volume_coupling.mirror_counts[0],
     514             :                 1,
     515             :                 MPI_INT,
     516             :                 platform->comm.mpiComm());
     517             : 
     518             :   // Save information regarding the volume mesh coupling in terms of the process-local
     519             :   // element IDs and process ownership; the 'tmp' arrays hold the rank-local data,
     520             :   // while the other arrays hold the result of the allgatherv
     521         451 :   int * etmp = (int *)malloc(_n_volume_elems * sizeof(int));
     522         451 :   int * ptmp = (int *)malloc(_n_volume_elems * sizeof(int));
     523         451 :   int * btmp = (int *)malloc(_n_volume_elems * _nek_internal_mesh->Nfaces * sizeof(int));
     524         451 :   int * element = (int *)malloc(_n_volume_elems * sizeof(int));
     525         451 :   int * process = (int *)malloc(_n_volume_elems * sizeof(int));
     526         451 :   int * boundary = (int *)malloc(_n_volume_elems * _nek_internal_mesh->Nfaces * sizeof(int));
     527             : 
     528      233863 :   for (int i = 0; i < _nek_internal_mesh->Nelements; ++i)
     529             :   {
     530      233412 :     etmp[i] = i;
     531      233412 :     ptmp[i] = rank;
     532             : 
     533     1633884 :     for (int j = 0; j < _nek_internal_mesh->Nfaces; ++j)
     534             :     {
     535     1400472 :       int id = i * _nek_internal_mesh->Nfaces + j;
     536     1400472 :       btmp[id] = _nek_internal_mesh->EToB[id];
     537             :     }
     538             :   }
     539             : 
     540         451 :   nekrs::allgatherv(_volume_coupling.counts, etmp, element, 1);
     541         451 :   nekrs::allgatherv(_volume_coupling.counts, ptmp, process, 1);
     542             : 
     543         451 :   int * ftmp = (int *)calloc(_n_volume_elems, sizeof(int));
     544         451 :   int * n_faces_on_boundary = (int *)calloc(_n_volume_elems, sizeof(int));
     545             : 
     546         451 :   int b_start = _boundary_coupling.offset;
     547        8021 :   for (int i = 0; i < _boundary_coupling.n_faces; ++i)
     548             :   {
     549        7570 :     int e = _boundary_coupling.element[b_start + i];
     550        7570 :     ftmp[e] += 1;
     551             :   }
     552             : 
     553         451 :   nekrs::allgatherv(_volume_coupling.counts, ftmp, n_faces_on_boundary, 1);
     554         451 :   nekrs::allgatherv(_volume_coupling.counts, btmp, boundary, _nek_internal_mesh->Nfaces);
     555             : 
     556     3575203 :   for (int i = 0; i < _n_volume_elems * _nek_internal_mesh->Nfaces; ++i)
     557     3574752 :     _volume_coupling.boundary.push_back(boundary[i]);
     558             : 
     559      596243 :   for (int i = 0; i < _n_volume_elems; ++i)
     560             :   {
     561      595792 :     _volume_coupling.element.push_back(element[i]);
     562      595792 :     _volume_coupling.process.push_back(process[i]);
     563      595792 :     _volume_coupling.n_faces_on_boundary.push_back(n_faces_on_boundary[i]);
     564             :   }
     565             : 
     566             :   freePointer(etmp);
     567             :   freePointer(ptmp);
     568             :   freePointer(ftmp);
     569             :   freePointer(btmp);
     570             :   freePointer(element);
     571             :   freePointer(process);
     572             :   freePointer(boundary);
     573             :   freePointer(n_faces_on_boundary);
     574         451 : }
     575             : 
     576             : void
     577         760 : NekRSMesh::buildMesh()
     578             : {
     579         760 :   if (nekrs::buildOnly())
     580             :   {
     581           0 :     buildDummyMesh();
     582           0 :     return;
     583             :   }
     584             : 
     585         760 :   _nek_n_surface_elems = nekrs::NboundaryFaces();
     586         760 :   _nek_n_volume_elems = nekrs::Nelements();
     587             : 
     588             :   // initialize the mesh mapping parameters that depend on order
     589         760 :   initializeMeshParams();
     590             : 
     591             :   // Loop through the mesh to establish a data structure (_boundary_coupling)
     592             :   // that holds the rank-local element ID, element-local face ID, and owning rank.
     593             :   // This data structure is used internally by nekRS during the transfer portion.
     594             :   // We must call this before the volume portion so that we can map the boundary
     595             :   // coupling to the volume coupling.
     596         760 :   if (_boundary)
     597         362 :     storeBoundaryCoupling();
     598             : 
     599             :   // Loop through the mesh to establish a data structure (_volume_coupling)
     600             :   // that holds the rank-local element ID and owning rank.
     601             :   // This data structure is used internally by nekRS during the transfer portion.
     602         760 :   if (_volume)
     603         451 :     storeVolumeCoupling();
     604             : 
     605         760 :   if (_boundary && !_volume)
     606         309 :     extractSurfaceMesh();
     607             : 
     608         760 :   if (_volume)
     609         451 :     extractVolumeMesh();
     610             : 
     611         760 :   addElems();
     612             : 
     613             :   // We're looking up the elements by id, so we can't let the ids get
     614             :   // renumbered.
     615             :   _mesh->allow_renumbering(false);
     616             : 
     617             :   // If we have a DistributedMesh then:
     618         760 :   if (!_mesh->is_replicated())
     619             :   {
     620             :     // we've already partitioned the elements to match the nekrs
     621             :     // mesh, and libMesh shouldn't try to improve on that.  We won't
     622             :     // ever be doing any element deletion or coarsening, so we don't
     623             :     // even need libMesh's "critical" partitioning.
     624             :     _mesh->skip_partitioning(true);
     625             : 
     626             :     // But that means we have to update the partitioning metadata
     627             :     // ourselves
     628         412 :     _mesh->recalculate_n_partitions();
     629             : 
     630             :     // But, we haven't yet partitioned nodes, and if we tell libMesh
     631             :     // not to do that automatically then we need to do it manually
     632         412 :     libMesh::Partitioner::set_node_processor_ids(*_mesh);
     633             :   }
     634             : 
     635         760 :   _mesh->prepare_for_use();
     636             : }
     637             : 
     638             : void
     639         760 : NekRSMesh::addElems()
     640             : {
     641             :   BoundaryInfo & boundary_info = _mesh->get_boundary_info();
     642         760 :   auto nested_elems_on_face = nekrs::nestedElementsOnFace(_nek_polynomial_order);
     643             : 
     644      684555 :   for (int e = 0; e < _n_elems; e++)
     645             :   {
     646     3861222 :     for (int build = 0; build < _n_moose_per_nek; ++build)
     647             :     {
     648     3177427 :       auto elem = (this->*_new_elem)();
     649     3177427 :       elem->set_id() = e * _n_moose_per_nek + build;
     650     3177427 :       elem->processor_id() = (this->*_elem_processor_id)(e);
     651     3177427 :       _mesh->add_elem(elem);
     652             : 
     653             :       // add one point for each vertex of the face element
     654    28599431 :       for (int n = 0; n < _n_vertices_per_elem; n++)
     655             :       {
     656    25422004 :         int node = (*_node_index)[n];
     657             : 
     658    25422004 :         auto node_offset = (e * _n_moose_per_nek + build) * _n_vertices_per_elem + node;
     659    25422004 :         Point p(_x[node_offset], _y[node_offset], _z[node_offset]);
     660    25422004 :         p *= _scaling;
     661             : 
     662    25422004 :         auto node_ptr = _mesh->add_point(p);
     663    25422004 :         elem->set_node(n) = node_ptr;
     664             :       }
     665             : 
     666             :       // add sideset IDs to the mesh if we have volume coupling (this only adds the
     667             :       // sidesets associated with the coupling)
     668     3177427 :       if (_volume)
     669             :       {
     670    20803440 :         for (int f = 0; f < nekrs::Nfaces(); ++f)
     671             :         {
     672    17831520 :           int b_id = boundary_id(e, f);
     673    17831520 :           if (b_id != -1 /* NekRS's setting to indicate not on a sideset */)
     674             :           {
     675     1942882 :             if (_exact)
     676             :             {
     677     1519244 :               auto faces = nested_elems_on_face[f];
     678     1519244 :               if (!std::count(faces.begin(), faces.end(), build))
     679             :                 continue;
     680     1519244 :             }
     681             : 
     682      792362 :             boundary_info.add_side(elem, _side_index[f], b_id);
     683             :           }
     684             :         }
     685             : 
     686     2971920 :         if (_phase[e * _n_moose_per_nek + build])
     687        1248 :           elem->subdomain_id() = _solid_block_id;
     688             :         else
     689     2970672 :           elem->subdomain_id() = _fluid_block_id;
     690             :       }
     691             :     }
     692             :   }
     693         760 : }
     694             : 
     695             : void
     696         309 : NekRSMesh::faceVertices()
     697             : {
     698         309 :   int n_vertices_in_mirror = _n_build_per_surface_elem * _n_surface_elems * _n_vertices_per_surface;
     699         309 :   double * x = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     700         309 :   double * y = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     701         309 :   double * z = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     702             : 
     703             :   // auto nrs = nekrs::nrsPtr();
     704         309 :   int rank = nekrs::commRank();
     705             : 
     706             :   mesh_t * mesh;
     707             :   int Nfp_mirror;
     708             : 
     709         309 :   if (_order == 0)
     710             :   {
     711             :     // For a first-order mesh mirror, we can take a shortcut and instead just fetch the
     712             :     // corner nodes. In this case, 'mesh' is no longer a custom-build mesh copy, but the
     713             :     // actual mesh for computation
     714         295 :     mesh = _nek_internal_mesh;
     715             :     Nfp_mirror = 4;
     716             :   }
     717             :   else
     718             :   {
     719             :     // Create a duplicate of the solution mesh, but with the desired order of the mesh
     720             :     // interpolation. Then we can just read the coordinates of the GLL points to find the libMesh
     721             :     // node positions. We only need to do this if the NekRS mesh is not already order 2.
     722          14 :     if (_nek_internal_mesh->N == 2)
     723             :       mesh = _nek_internal_mesh;
     724             :     else
     725             :     {
     726          13 :       mesh = nekrs::createMesh2(_nek_internal_mesh, _order + 1);
     727             :     }
     728             : 
     729          14 :     Nfp_mirror = mesh->Nfp;
     730             :   }
     731             : 
     732         309 :   std::vector<dfloat> x_mirror(mesh->Nlocal);
     733         309 :   std::vector<dfloat> y_mirror(mesh->Nlocal);
     734         309 :   std::vector<dfloat> z_mirror(mesh->Nlocal);
     735         309 :   mesh->o_x.copyTo(x_mirror.data(), x_mirror.size());
     736         309 :   mesh->o_y.copyTo(y_mirror.data(), y_mirror.size());
     737         309 :   mesh->o_z.copyTo(z_mirror.data(), z_mirror.size());
     738             : 
     739             :   // Allocate space for the coordinates that are on this rank
     740         309 :   int n_vertices_on_rank = _n_build_per_surface_elem * _boundary_coupling.n_faces * Nfp_mirror;
     741         309 :   double * xtmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     742         309 :   double * ytmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     743         309 :   double * ztmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     744             : 
     745             :   int c = 0;
     746       88312 :   for (int k = 0; k < _boundary_coupling.total_n_faces; ++k)
     747             :   {
     748       88003 :     if (_boundary_coupling.process[k] == rank)
     749             :     {
     750       30036 :       int i = _boundary_coupling.element[k];
     751       30036 :       int j = _boundary_coupling.face[k];
     752       30036 :       int offset = i * mesh->Nfaces * mesh->Nfp + j * mesh->Nfp;
     753             : 
     754       78504 :       for (int build = 0; build < _n_build_per_surface_elem; ++build)
     755             :       {
     756      247820 :         for (int v = 0; v < Nfp_mirror; ++v, ++c)
     757             :         {
     758      199352 :           int vertex_offset = _order == 0 ? _corner_indices[build][v] : v;
     759      199352 :           int id = mesh->vmapM[offset + vertex_offset];
     760             : 
     761      199352 :           xtmp[c] = x_mirror[id];
     762      199352 :           ytmp[c] = y_mirror[id];
     763      199352 :           ztmp[c] = z_mirror[id];
     764             :         }
     765             :       }
     766             :     }
     767             :   }
     768             : 
     769         309 :   nekrs::allgatherv(_boundary_coupling.mirror_counts, xtmp, x, Nfp_mirror);
     770         309 :   nekrs::allgatherv(_boundary_coupling.mirror_counts, ytmp, y, Nfp_mirror);
     771         309 :   nekrs::allgatherv(_boundary_coupling.mirror_counts, ztmp, z, Nfp_mirror);
     772             : 
     773      833297 :   for (int i = 0; i < n_vertices_in_mirror; ++i)
     774             :   {
     775      832988 :     _x.push_back(x[i]);
     776      832988 :     _y.push_back(y[i]);
     777      832988 :     _z.push_back(z[i]);
     778             :   }
     779             : 
     780             :   freePointer(x);
     781             :   freePointer(y);
     782             :   freePointer(z);
     783             :   freePointer(xtmp);
     784             :   freePointer(ytmp);
     785             :   freePointer(ztmp);
     786         309 : }
     787             : 
     788             : void
     789         451 : NekRSMesh::volumeVertices()
     790             : {
     791             :   // nekRS has already performed a global operation such that all processes know the
     792             :   // toal number of volume elements and their phase
     793         451 :   int n_vertices_in_mirror = _n_build_per_volume_elem * _n_volume_elems * _n_vertices_per_volume;
     794         451 :   double * x = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     795         451 :   double * y = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     796         451 :   double * z = (double *) malloc(n_vertices_in_mirror * sizeof(double));
     797         451 :   double * p = (double *) malloc(_n_build_per_volume_elem * _n_volume_elems * sizeof(double));
     798             : 
     799             :   // auto nrs = nekrs::nrsPtr();
     800         451 :   int rank = nekrs::commRank();
     801             : 
     802             :   mesh_t * mesh;
     803             :   int Np_mirror;
     804             : 
     805         451 :   if (_order == 0)
     806             :   {
     807             :     // For a first-order mesh mirror, we can take a shortcut and instead just fetch the
     808             :     // corner nodes. In this case, 'mesh' is no longer a custom-build mesh copy, but the
     809             :     // actual mesh for computation
     810         408 :     mesh = _nek_internal_mesh;
     811             :     Np_mirror = 8;
     812             :   }
     813             :   else
     814             :   {
     815             :     // Create a duplicate of the solution mesh, but with the desired order of the mesh interpolation.
     816             :     // Then we can just read the coordinates of the GLL points to find the libMesh node positions.
     817             :     // We only need to do this if the mesh is not already N = 2.
     818          43 :     if (_nek_internal_mesh->N == 2)
     819             :       mesh = _nek_internal_mesh;
     820             :     else
     821             :     {
     822          41 :       mesh = nekrs::createMesh2(_nek_internal_mesh, _order + 1);
     823             :     }
     824          43 :     Np_mirror = mesh->Np;
     825             :   }
     826             : 
     827         451 :   std::vector<dfloat> x_mirror(mesh->Nlocal);
     828         451 :   std::vector<dfloat> y_mirror(mesh->Nlocal);
     829         451 :   std::vector<dfloat> z_mirror(mesh->Nlocal);
     830         451 :   mesh->o_x.copyTo(x_mirror.data(), x_mirror.size());
     831         451 :   mesh->o_y.copyTo(y_mirror.data(), y_mirror.size());
     832         451 :   mesh->o_z.copyTo(z_mirror.data(), z_mirror.size());
     833             : 
     834             :   // Allocate space for the coordinates and phase that are on this rank
     835         451 :   int n_vertices_on_rank = _n_build_per_volume_elem * _volume_coupling.n_elems * Np_mirror;
     836         451 :   double * xtmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     837         451 :   double * ytmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     838         451 :   double * ztmp = (double *) malloc(n_vertices_on_rank * sizeof(double));
     839         451 :   double * ptmp = (double *) malloc(_n_build_per_volume_elem * _volume_coupling.n_elems * sizeof(double));
     840             : 
     841             :   int c = 0;
     842             :   int d = 0;
     843      596243 :   for (int k = 0; k < _volume_coupling.total_n_elems; ++k)
     844             :   {
     845      595792 :     if (_volume_coupling.process[k] == rank)
     846             :     {
     847      233412 :       int i = _volume_coupling.element[k];
     848      233412 :       int offset = i * mesh->Np;
     849             : 
     850     1421112 :       for (int build = 0; build < _n_build_per_volume_elem; ++build)
     851             :       {
     852     1187700 :         ptmp[d++] = i >= nekrs::flowMesh()->Nelements;
     853    10851446 :         for (int v = 0; v < Np_mirror; ++v, ++c)
     854             :         {
     855     9663746 :           int vertex_offset = _order == 0 ? _corner_indices[build][v] : v;
     856     9663746 :           int id = offset + vertex_offset;
     857             : 
     858     9663746 :           xtmp[c] = x_mirror[id];
     859     9663746 :           ytmp[c] = y_mirror[id];
     860     9663746 :           ztmp[c] = z_mirror[id];
     861             :         }
     862             :       }
     863             :     }
     864             :   }
     865             : 
     866         451 :   nekrs::allgatherv(_volume_coupling.mirror_counts, xtmp, x, Np_mirror);
     867         451 :   nekrs::allgatherv(_volume_coupling.mirror_counts, ytmp, y, Np_mirror);
     868         451 :   nekrs::allgatherv(_volume_coupling.mirror_counts, ztmp, z, Np_mirror);
     869         451 :   nekrs::allgatherv(_volume_coupling.mirror_counts, ptmp, p);
     870             : 
     871     2972371 :   for (int i = 0; i < _n_build_per_volume_elem * _n_volume_elems; ++i)
     872     2971920 :     _phase.push_back(p[i]);
     873             : 
     874    24589467 :   for (int i = 0; i < n_vertices_in_mirror; ++i)
     875             :   {
     876    24589016 :     _x.push_back(x[i]);
     877    24589016 :     _y.push_back(y[i]);
     878    24589016 :     _z.push_back(z[i]);
     879             :   }
     880             : 
     881             :   freePointer(x);
     882             :   freePointer(y);
     883             :   freePointer(z);
     884             :   freePointer(p);
     885             :   freePointer(xtmp);
     886             :   freePointer(ytmp);
     887             :   freePointer(ztmp);
     888             :   freePointer(ptmp);
     889         451 : }
     890             : 
     891             : void
     892         309 : NekRSMesh::extractSurfaceMesh()
     893             : {
     894             :   // Find the global vertex IDs that are on the _boundary. Note that nekRS performs a
     895             :   // global communciation here such that each nekRS process has knowledge of all the
     896             :   // boundary information.
     897         309 :   faceVertices();
     898             : 
     899         309 :   _new_elem = &NekRSMesh::boundaryElem;
     900         309 :   _n_elems = _n_surface_elems;
     901         309 :   _n_vertices_per_elem = _n_vertices_per_surface;
     902         309 :   _n_moose_per_nek = _n_build_per_surface_elem;
     903         309 :   _node_index = &_bnd_node_index;
     904         309 :   _elem_processor_id = &NekRSMesh::boundaryElemProcessorID;
     905         309 : }
     906             : 
     907             : void
     908         451 : NekRSMesh::extractVolumeMesh()
     909             : {
     910             :   // Find the global vertex IDs in the volume. Note that nekRS performs a
     911             :   // global communciation here such that each nekRS process has knowledge of all the
     912             :   // volume information.
     913         451 :   volumeVertices();
     914             : 
     915         451 :   _new_elem = &NekRSMesh::volumeElem;
     916         451 :   _n_elems = _n_volume_elems;
     917         451 :   _n_vertices_per_elem = _n_vertices_per_volume;
     918         451 :   _n_moose_per_nek = _n_build_per_volume_elem;
     919         451 :   _node_index = &_vol_node_index;
     920         451 :   _elem_processor_id = &NekRSMesh::volumeElemProcessorID;
     921         451 : }
     922             : 
     923             : Elem *
     924      205507 : NekRSMesh::boundaryElem() const
     925             : {
     926      205507 :   switch (_order)
     927             :   {
     928      203315 :     case order::first:
     929      203315 :       return new Quad4;
     930             :       break;
     931        2192 :     case order::second:
     932        2192 :       return new Quad9;
     933             :       break;
     934           0 :     default:
     935           0 :       mooseError("Unhandled 'NekOrderEnum' in 'NekRSMesh'!");
     936             :   }
     937             : }
     938             : 
     939             : Elem *
     940     2971920 : NekRSMesh::volumeElem() const
     941             : {
     942     2971920 :   switch (_order)
     943             :   {
     944     2929096 :     case order::first:
     945     2929096 :       return new Hex8;
     946             :       break;
     947       42824 :     case order::second:
     948       42824 :       return new Hex27;
     949             :       break;
     950           0 :     default:
     951           0 :       mooseError("Unhandled 'NekOrderEnum' in 'NekRSMesh'!");
     952             :   }
     953             : }
     954             : 
     955             : int
     956      205507 : NekRSMesh::boundaryElemProcessorID(const int elem_id)
     957             : {
     958      205507 :   return _boundary_coupling.processor_id(elem_id);
     959             : }
     960             : 
     961             : int
     962     2971920 : NekRSMesh::volumeElemProcessorID(const int elem_id)
     963             : {
     964     2971920 :   return _volume_coupling.processor_id(elem_id);
     965             : }
     966             : 
     967             : int
     968    17831520 : NekRSMesh::boundary_id(const int elem_id, const int face_id)
     969             : {
     970    17831520 :   return _volume_coupling.boundary[elem_id * _nek_internal_mesh->Nfaces + face_id];
     971             : }
     972             : 
     973             : int
     974     1339440 : NekRSMesh::facesOnBoundary(const int elem_id) const
     975             : {
     976     1339440 :   return _volume_coupling.n_faces_on_boundary[elem_id];
     977             : }
     978             : 
     979             : void
     980           0 : NekRSMesh::updateDisplacement(const int e, const double *src, const field::NekWriteEnum field)
     981             : {
     982           0 :   int nsrc = _volume? _n_vertices_per_volume : _n_vertices_per_surface;
     983           0 :   int offset = e * nsrc;
     984             : 
     985           0 :   switch (field)
     986             :   {
     987           0 :     case field::x_displacement:
     988           0 :       memcpy(&_prev_disp_x[offset], src, nsrc * sizeof(double));
     989           0 :       break;
     990           0 :     case field::y_displacement:
     991           0 :       memcpy(&_prev_disp_y[offset], src, nsrc * sizeof(double));
     992           0 :       break;
     993           0 :     case field::z_displacement:
     994           0 :       memcpy(&_prev_disp_z[offset], src, nsrc * sizeof(double));
     995           0 :       break;
     996           0 :     default:
     997           0 :       throw std::runtime_error("Unhandled NekWriteEnum in NekRSMesh::copyToDisplacement!\n");
     998             :   }
     999           0 : }
    1000             : #endif

Generated by: LCOV version 1.14