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

Generated by: LCOV version 1.14