LCOV - code coverage report
Current view: top level - src/meshgenerators - SCMDetailedQuadSubChannelMeshGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #31405 (292dce) with base fef103 Lines: 335 337 99.4 %
Date: 2025-09-04 07:58:06 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "SCMDetailedQuadSubChannelMeshGenerator.h"
      11             : #include <array>
      12             : #include <cmath>
      13             : #include "libmesh/cell_prism6.h"
      14             : #include "libmesh/unstructured_mesh.h"
      15             : 
      16             : registerMooseObject("SubChannelApp", SCMDetailedQuadSubChannelMeshGenerator);
      17             : registerMooseObjectRenamed("SubChannelApp",
      18             :                            DetailedQuadSubChannelMeshGenerator,
      19             :                            "06/30/2025 24:00",
      20             :                            SCMDetailedQuadSubChannelMeshGenerator);
      21             : 
      22             : InputParameters
      23         206 : SCMDetailedQuadSubChannelMeshGenerator::validParams()
      24             : {
      25         206 :   InputParameters params = MeshGenerator::validParams();
      26         206 :   params.addClassDescription(
      27             :       "Creates a detailed mesh of subchannels in a square lattice arrangement");
      28         412 :   params.addRequiredParam<Real>("pitch", "Pitch [m]");
      29         412 :   params.addRequiredParam<Real>("pin_diameter", "Rod diameter [m]");
      30         412 :   params.addParam<Real>("unheated_length_entry", 0.0, "Unheated length at entry [m]");
      31         412 :   params.addRequiredParam<Real>("heated_length", "Heated length [m]");
      32         412 :   params.addParam<Real>("unheated_length_exit", 0.0, "Unheated length at exit [m]");
      33         412 :   params.addRequiredParam<unsigned int>("n_cells", "The number of cells in the axial direction");
      34         412 :   params.addRequiredParam<unsigned int>("nx", "Number of channels in the x direction [-]");
      35         412 :   params.addRequiredParam<unsigned int>("ny", "Number of channels in the y direction [-]");
      36         412 :   params.addRequiredParam<Real>(
      37             :       "gap",
      38             :       "The side gap, not to be confused with the gap between pins, this refers to the gap "
      39             :       "next to the duct or else the distance between the subchannel centroid to the duct wall."
      40             :       "distance(edge pin center, duct wall) = pitch / 2 + side_gap [m]");
      41         412 :   params.deprecateParam("gap", "side_gap", "08/06/2026");
      42         412 :   params.addParam<unsigned int>("block_id", 0, "Block ID used for the mesh subdomain.");
      43         206 :   return params;
      44           0 : }
      45             : 
      46         103 : SCMDetailedQuadSubChannelMeshGenerator::SCMDetailedQuadSubChannelMeshGenerator(
      47         103 :     const InputParameters & parameters)
      48             :   : MeshGenerator(parameters),
      49         103 :     _unheated_length_entry(getParam<Real>("unheated_length_entry")),
      50         206 :     _heated_length(getParam<Real>("heated_length")),
      51         206 :     _unheated_length_exit(getParam<Real>("unheated_length_exit")),
      52         206 :     _pitch(getParam<Real>("pitch")),
      53         206 :     _pin_diameter(getParam<Real>("pin_diameter")),
      54         206 :     _n_cells(getParam<unsigned int>("n_cells")),
      55         206 :     _nx(getParam<unsigned int>("nx")),
      56         206 :     _ny(getParam<unsigned int>("ny")),
      57         103 :     _n_channels(_nx * _ny),
      58         206 :     _side_gap(getParam<Real>("side_gap")),
      59         309 :     _block_id(getParam<unsigned int>("block_id"))
      60             : {
      61         103 :   Real L = _unheated_length_entry + _heated_length + _unheated_length_exit;
      62         103 :   Real dz = L / _n_cells;
      63        3168 :   for (unsigned int i = 0; i < _n_cells + 1; i++)
      64        3065 :     _z_grid.push_back(dz * i);
      65             : 
      66         103 :   _subchannel_position.resize(_n_channels);
      67        1385 :   for (unsigned int i = 0; i < _n_channels; i++)
      68             :   {
      69        1282 :     _subchannel_position[i].reserve(3);
      70        5128 :     for (unsigned int j = 0; j < 3; j++)
      71             :     {
      72        3846 :       _subchannel_position.at(i).push_back(0.0);
      73             :     }
      74             :   }
      75             : 
      76         103 :   _subch_type.resize(_n_channels);
      77         411 :   for (unsigned int iy = 0; iy < _ny; iy++)
      78             :   {
      79        1590 :     for (unsigned int ix = 0; ix < _nx; ix++)
      80             :     {
      81        1282 :       unsigned int i_ch = _nx * iy + ix;
      82        1179 :       bool is_corner = (ix == 0 && iy == 0) || (ix == _nx - 1 && iy == 0) ||
      83        2376 :                        (ix == 0 && iy == _ny - 1) || (ix == _nx - 1 && iy == _ny - 1);
      84        1282 :       bool is_edge = (ix == 0 || iy == 0 || ix == _nx - 1 || iy == _ny - 1);
      85             : 
      86        1282 :       if (is_corner)
      87         334 :         _subch_type[i_ch] = EChannelType::CORNER;
      88         948 :       else if (is_edge)
      89         570 :         _subch_type[i_ch] = EChannelType::EDGE;
      90             :       else
      91         378 :         _subch_type[i_ch] = EChannelType::CENTER;
      92             : 
      93             :       // set the subchannel positions so that the center of the assembly is the zero point
      94        1282 :       Real offset_x = (_nx - 1) * _pitch / 2.0;
      95        1282 :       Real offset_y = (_ny - 1) * _pitch / 2.0;
      96        1282 :       _subchannel_position[i_ch][0] = _pitch * ix - offset_x;
      97        1282 :       _subchannel_position[i_ch][1] = _pitch * iy - offset_y;
      98             :     }
      99             :   }
     100         103 : }
     101             : 
     102             : std::unique_ptr<MeshBase>
     103         103 : SCMDetailedQuadSubChannelMeshGenerator::generate()
     104             : {
     105         103 :   auto mesh_base = buildMeshBaseObject();
     106             :   BoundaryInfo & boundary_info = mesh_base->get_boundary_info();
     107         103 :   mesh_base->set_spatial_dimension(3);
     108             :   // Define the resolution (the number of points used to represent a circle).
     109             :   // This must be divisible by 4.
     110             :   const unsigned int theta_res = 16; // TODO: parameterize
     111             :   // Compute the number of points needed to represent one quarter of a circle.
     112             :   const unsigned int points_per_quad = theta_res / 4 + 1;
     113             : 
     114             :   // Compute the points needed to represent one axial cross-flow of a subchannel.
     115             :   // For the center subchannel (sc) there is one center point plus the points from 4 intersecting
     116             :   // circles.
     117             :   const unsigned int points_per_center = points_per_quad * 4 + 1;
     118             :   // For the corner sc there is one center point plus the points from 1 intersecting circle plus 3
     119             :   // corners
     120             :   const unsigned int points_per_corner = points_per_quad * 1 + 1 + 3;
     121             :   // For the side sc there is one center point plus the points from 2 intersecting circles plus 2
     122             :   // corners
     123             :   const unsigned int points_per_side = points_per_quad * 2 + 1 + 2;
     124             : 
     125             :   // Compute the number of elements (Prism6) which combined base creates the sub-channel
     126             :   // cross-section
     127             :   const unsigned int elems_per_center = theta_res + 4;
     128             :   const unsigned int elems_per_corner = theta_res / 4 + 4;
     129             :   const unsigned int elems_per_side = theta_res / 2 + 4;
     130             : 
     131             :   // specify number and type of sub-channel
     132             :   unsigned int n_center, n_side, n_corner;
     133         103 :   if (_n_channels == 2)
     134             :   {
     135             :     n_corner = 0;
     136             :     n_side = _n_channels;
     137             :     n_center = _n_channels - n_side - n_corner;
     138             :   }
     139          82 :   else if (_n_channels > 2 && (_ny == 1 || _nx == 1))
     140             :   {
     141             :     n_corner = 0;
     142             :     n_side = 2;
     143          18 :     n_center = _n_channels - n_side - n_corner;
     144             :   }
     145             :   else
     146             :   {
     147             :     n_corner = 4;
     148          64 :     n_side = 2 * (_ny - 2) + 2 * (_nx - 2);
     149          64 :     n_center = _n_channels - n_side - n_corner;
     150             :   }
     151             : 
     152             :   // Compute the total number of points and elements.
     153         103 :   const unsigned int points_per_level =
     154         103 :       n_corner * points_per_corner + n_side * points_per_side + n_center * points_per_center;
     155         103 :   const unsigned int elems_per_level =
     156         103 :       n_corner * elems_per_corner + n_side * elems_per_side + n_center * elems_per_center;
     157         103 :   const unsigned int n_points = points_per_level * (_n_cells + 1);
     158         103 :   const unsigned int n_elems = elems_per_level * _n_cells;
     159         103 :   mesh_base->reserve_nodes(n_points);
     160         103 :   mesh_base->reserve_elem(n_elems);
     161             :   // Build an array of points arranged in a circle on the xy-plane. (last and first node overlap)
     162         103 :   const Real radius = _pin_diameter / 2.0;
     163             :   std::array<Point, theta_res + 1> circle_points;
     164             :   {
     165             :     Real theta = 0;
     166        1854 :     for (unsigned int i = 0; i < theta_res + 1; i++)
     167             :     {
     168        1751 :       circle_points[i](0) = radius * std::cos(theta);
     169        1751 :       circle_points[i](1) = radius * std::sin(theta);
     170        1751 :       theta += 2 * M_PI / theta_res;
     171             :     }
     172             :   }
     173             :   // Define "quadrant center" reference points.  These will be the centers of
     174             :   // the 4 circles that represent the fuel pins.  These centers are
     175             :   // offset a little bit so that in the final mesh, there is a tiny gap between
     176             :   // neighboring subchannel cells.  That allows us to easily map a solution to
     177             :   // this detailed mesh with a nearest-neighbor search.
     178             :   const Real shrink_factor = 0.99999;
     179             :   std::array<Point, 4> quadrant_centers;
     180         103 :   quadrant_centers[0] = Point(_pitch * 0.5 * shrink_factor, _pitch * 0.5 * shrink_factor, 0);
     181         103 :   quadrant_centers[1] = Point(-_pitch * 0.5 * shrink_factor, _pitch * 0.5 * shrink_factor, 0);
     182         103 :   quadrant_centers[2] = Point(-_pitch * 0.5 * shrink_factor, -_pitch * 0.5 * shrink_factor, 0);
     183         103 :   quadrant_centers[3] = Point(_pitch * 0.5 * shrink_factor, -_pitch * 0.5 * shrink_factor, 0);
     184             : 
     185             :   const unsigned int m = theta_res / 4;
     186             :   // Build an array of points that represent a cross section of a center subchannel
     187             :   // cell.  The points are ordered in this fashion:
     188             :   //     4   3
     189             :   // 6 5       2 1
     190             :   //       0
     191             :   // 7 8       * *
     192             :   //     9   *
     193             :   std::array<Point, points_per_center> center_points;
     194             :   {
     195             :     unsigned int start;
     196         515 :     for (unsigned int i = 0; i < 4; i++)
     197             :     {
     198         412 :       if (i == 0)
     199             :         start = 3 * m;
     200         309 :       if (i == 1)
     201             :         start = 4 * m;
     202         309 :       if (i == 2)
     203             :         start = 1 * m;
     204         309 :       if (i == 3)
     205             :         start = 2 * m;
     206        2472 :       for (unsigned int ii = 0; ii < points_per_quad; ii++)
     207             :       {
     208        2060 :         auto c_pt = circle_points[start - ii];
     209        2060 :         center_points[i * points_per_quad + ii + 1] = quadrant_centers[i] + c_pt;
     210             :       }
     211             :     }
     212             :   }
     213             : 
     214             :   // Build an array of points that represent a cross section of a top left corner subchannel
     215             :   // cell. The points are ordered in this fashion:
     216             :   // 5            4
     217             :   //
     218             :   //       0
     219             :   //           2  3
     220             :   // 6       1
     221             :   std::array<Point, points_per_corner> tl_corner_points;
     222             :   {
     223         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     224             :     {
     225         515 :       auto c_pt = circle_points[2 * m - ii];
     226         515 :       tl_corner_points[ii + 1] = quadrant_centers[3] + c_pt;
     227             :     }
     228         103 :     tl_corner_points[points_per_quad + 1] = Point(_pitch * 0.5 * shrink_factor, _side_gap, 0);
     229         103 :     tl_corner_points[points_per_quad + 2] = Point(-_side_gap, _side_gap, 0);
     230         103 :     tl_corner_points[points_per_quad + 3] = Point(-_side_gap, -_pitch * 0.5 * shrink_factor, 0);
     231             :   }
     232             : 
     233             :   // Build an array of points that represent a cross section of a top right corner subchannel
     234             :   // cell.  The points are ordered in this fashion:
     235             :   // 6            5
     236             :   //
     237             :   //       0
     238             :   // 1 2
     239             :   //    3         4
     240             :   std::array<Point, points_per_corner> tr_corner_points;
     241             :   {
     242         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     243             :     {
     244         515 :       auto c_pt = circle_points[m - ii];
     245         515 :       tr_corner_points[ii + 1] = quadrant_centers[2] + c_pt;
     246             :     }
     247         103 :     tr_corner_points[points_per_quad + 1] = Point(_side_gap, -_pitch * 0.5 * shrink_factor, 0);
     248         103 :     tr_corner_points[points_per_quad + 2] = Point(_side_gap, _side_gap, 0);
     249         103 :     tr_corner_points[points_per_quad + 3] = Point(-_pitch * 0.5 * shrink_factor, _side_gap, 0);
     250             :   }
     251             : 
     252             :   // Build an array of points that represent a cross section of a bottom left corner subchannel
     253             :   // cell.  The points are ordered in this fashion:
     254             :   // 4       3
     255             :   //           2  1
     256             :   //       0
     257             :   //
     258             :   // 5            6
     259             :   std::array<Point, points_per_corner> bl_corner_points;
     260             :   {
     261         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     262             :     {
     263         515 :       auto c_pt = circle_points[3 * m - ii];
     264         515 :       bl_corner_points[ii + 1] = quadrant_centers[0] + c_pt;
     265             :     }
     266         103 :     bl_corner_points[points_per_quad + 1] = Point(-_side_gap, _pitch * 0.5 * shrink_factor, 0);
     267         103 :     bl_corner_points[points_per_quad + 2] = Point(-_side_gap, -_side_gap, 0);
     268         103 :     bl_corner_points[points_per_quad + 3] = Point(_pitch * 0.5 * shrink_factor, -_side_gap, 0);
     269             :   }
     270             : 
     271             :   // Build an array of points that represent a cross section of a bottom right corner subchannel
     272             :   // cell.  The points are ordered in this fashion:
     273             :   //    1        6
     274             :   // 3 2
     275             :   //       0
     276             :   //
     277             :   // 4           5
     278             :   std::array<Point, points_per_corner> br_corner_points;
     279             :   {
     280         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     281             :     {
     282         515 :       auto c_pt = circle_points[4 * m - ii];
     283         515 :       br_corner_points[ii + 1] = quadrant_centers[1] + c_pt;
     284             :     }
     285         103 :     br_corner_points[points_per_quad + 1] = Point(-_pitch * 0.5 * shrink_factor, -_side_gap, 0);
     286         103 :     br_corner_points[points_per_quad + 2] = Point(_side_gap, -_side_gap, 0);
     287         103 :     br_corner_points[points_per_quad + 3] = Point(_side_gap, _pitch * 0.5 * shrink_factor, 0);
     288             :   }
     289             : 
     290             :   // Build an array of points that represent a cross section of a top side subchannel
     291             :   // cell.  The points are ordered in this fashion:
     292             :   // 8            7
     293             :   //
     294             :   //       0
     295             :   // 1 2        5 6
     296             :   //    3     4
     297             :   std::array<Point, points_per_side> top_points;
     298             :   {
     299         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     300             :     {
     301         515 :       auto c_pt = circle_points[m - ii];
     302         515 :       top_points[ii + 1] = quadrant_centers[2] + c_pt;
     303             :     }
     304         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     305             :     {
     306         515 :       auto c_pt = circle_points[2 * m - ii];
     307         515 :       top_points[points_per_quad + ii + 1] = quadrant_centers[3] + c_pt;
     308             :     }
     309         103 :     top_points[2 * points_per_quad + 1] = Point(_pitch * 0.5 * shrink_factor, _side_gap, 0);
     310         103 :     top_points[2 * points_per_quad + 2] = Point(-_pitch * 0.5 * shrink_factor, _side_gap, 0);
     311             :   }
     312             : 
     313             :   // Build an array of points that represent a cross section of a left side subchannel
     314             :   // cell.  The points are ordered in this fashion:
     315             :   // 7        6
     316             :   //            5 4
     317             :   //      0
     318             :   //            2 3
     319             :   // 8        1
     320             :   std::array<Point, points_per_side> left_points;
     321             :   {
     322         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     323             :     {
     324         515 :       auto c_pt = circle_points[2 * m - ii];
     325         515 :       left_points[ii + 1] = quadrant_centers[3] + c_pt;
     326             :     }
     327         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     328             :     {
     329         515 :       auto c_pt = circle_points[3 * m - ii];
     330         515 :       left_points[points_per_quad + ii + 1] = quadrant_centers[0] + c_pt;
     331             :     }
     332         103 :     left_points[2 * points_per_quad + 1] = Point(-_side_gap, _pitch * 0.5 * shrink_factor, 0);
     333         103 :     left_points[2 * points_per_quad + 2] = Point(-_side_gap, -_pitch * 0.5 * shrink_factor, 0);
     334             :   }
     335             : 
     336             :   // Build an array of points that represent a cross section of a bottom side subchannel
     337             :   // cell.  The points are ordered in this fashion:
     338             :   //    4    3
     339             :   // 6 5       2 1
     340             :   //       0
     341             :   //
     342             :   // 7           8
     343             :   std::array<Point, points_per_side> bottom_points;
     344             :   {
     345         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     346             :     {
     347         515 :       auto c_pt = circle_points[3 * m - ii];
     348         515 :       bottom_points[ii + 1] = quadrant_centers[0] + c_pt;
     349             :     }
     350         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     351             :     {
     352         515 :       auto c_pt = circle_points[4 * m - ii];
     353         515 :       bottom_points[points_per_quad + ii + 1] = quadrant_centers[1] + c_pt;
     354             :     }
     355         103 :     bottom_points[2 * points_per_quad + 1] = Point(-_pitch * 0.5 * shrink_factor, -_side_gap, 0);
     356         103 :     bottom_points[2 * points_per_quad + 2] = Point(_pitch * 0.5 * shrink_factor, -_side_gap, 0);
     357             :   }
     358             : 
     359             :   // Build an array of points that represent a cross section of a right side subchannel
     360             :   // cell.  The points are ordered in this fashion:
     361             :   //    1        8
     362             :   // 3 2
     363             :   //       0
     364             :   // 4 5
     365             :   //   6         7
     366             :   std::array<Point, points_per_side> right_points;
     367             :   {
     368         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     369             :     {
     370         515 :       auto c_pt = circle_points[4 * m - ii];
     371         515 :       right_points[ii + 1] = quadrant_centers[1] + c_pt;
     372             :     }
     373         618 :     for (unsigned int ii = 0; ii < points_per_quad; ii++)
     374             :     {
     375         515 :       auto c_pt = circle_points[m - ii];
     376         515 :       right_points[points_per_quad + ii + 1] = quadrant_centers[2] + c_pt;
     377             :     }
     378         103 :     right_points[2 * points_per_quad + 1] = Point(_side_gap, -_pitch * 0.5 * shrink_factor, 0);
     379         103 :     right_points[2 * points_per_quad + 2] = Point(_side_gap, _pitch * 0.5 * shrink_factor, 0);
     380             :   }
     381             : 
     382             :   // Add the points to the mesh.
     383         103 :   if (_n_channels == 2)
     384             :   {
     385             :     unsigned int node_id = 0;
     386          21 :     Real offset_x = (_nx - 1) * _pitch / 2.0;
     387          21 :     Real offset_y = (_ny - 1) * _pitch / 2.0;
     388          51 :     for (unsigned int iy = 0; iy < _ny; iy++)
     389             :     {
     390          30 :       Point y0 = {0, _pitch * iy - offset_y, 0};
     391          72 :       for (unsigned int ix = 0; ix < _nx; ix++)
     392             :       {
     393          42 :         Point x0 = {_pitch * ix - offset_x, 0, 0};
     394        2664 :         for (auto z : _z_grid)
     395             :         {
     396             :           Point z0{0, 0, z};
     397        2622 :           if (_nx == 1 && iy == 0) // vertical orientation
     398             :           {
     399        1386 :             for (unsigned int i = 0; i < points_per_side; i++)
     400        1287 :               mesh_base->add_point(bottom_points[i] + x0 + y0 + z0, node_id++);
     401             :           }
     402        2622 :           if (_nx == 1 && iy == 1) // vertical orientation
     403             :           {
     404        1386 :             for (unsigned int i = 0; i < points_per_side; i++)
     405        1287 :               mesh_base->add_point(top_points[i] + x0 + y0 + z0, node_id++);
     406             :           }
     407        2622 :           if (_ny == 1 && ix == 0) // horizontal orientation
     408             :           {
     409       16968 :             for (unsigned int i = 0; i < points_per_side; i++)
     410       15756 :               mesh_base->add_point(left_points[i] + x0 + y0 + z0, node_id++);
     411             :           }
     412        2622 :           if (_ny == 1 && ix == 1) // horizontal orientation
     413             :           {
     414       16968 :             for (unsigned int i = 0; i < points_per_side; i++)
     415       15756 :               mesh_base->add_point(right_points[i] + x0 + y0 + z0, node_id++);
     416             :           }
     417             :         }
     418             :       }
     419             :     }
     420             :   }
     421          82 :   else if (_n_channels > 2 && (_ny == 1 || _nx == 1))
     422             :   {
     423             :     unsigned int node_id = 0;
     424          18 :     Real offset_x = (_nx - 1) * _pitch / 2.0;
     425          18 :     Real offset_y = (_ny - 1) * _pitch / 2.0;
     426          54 :     for (unsigned int iy = 0; iy < _ny; iy++)
     427             :     {
     428          36 :       Point y0 = {0, _pitch * iy - offset_y, 0};
     429          90 :       for (unsigned int ix = 0; ix < _nx; ix++)
     430             :       {
     431          54 :         Point x0 = {_pitch * ix - offset_x, 0, 0};
     432         648 :         for (auto z : _z_grid)
     433             :         {
     434             :           Point z0{0, 0, z};
     435         594 :           if (_nx == 1)
     436             :           {
     437         297 :             if (iy == 0)
     438             :             {
     439        1386 :               for (unsigned int i = 0; i < points_per_side; i++)
     440        1287 :                 mesh_base->add_point(bottom_points[i] + x0 + y0 + z0, node_id++);
     441             :             }
     442         198 :             else if (iy == _ny - 1)
     443             :             {
     444        1386 :               for (unsigned int i = 0; i < points_per_side; i++)
     445        1287 :                 mesh_base->add_point(top_points[i] + x0 + y0 + z0, node_id++);
     446             :             }
     447             :             else
     448             :             {
     449        2178 :               for (unsigned int i = 0; i < points_per_center; i++)
     450        2079 :                 mesh_base->add_point(center_points[i] + x0 + y0 + z0, node_id++);
     451             :             }
     452             :           }
     453         297 :           else if (_ny == 1)
     454             :           {
     455         297 :             if (ix == 0)
     456             :             {
     457        1386 :               for (unsigned int i = 0; i < points_per_side; i++)
     458        1287 :                 mesh_base->add_point(left_points[i] + x0 + y0 + z0, node_id++);
     459             :             }
     460         198 :             else if (ix == _nx - 1)
     461             :             {
     462        1386 :               for (unsigned int i = 0; i < points_per_side; i++)
     463        1287 :                 mesh_base->add_point(right_points[i] + x0 + y0 + z0, node_id++);
     464             :             }
     465             :             else
     466             :             {
     467        2178 :               for (unsigned int i = 0; i < points_per_center; i++)
     468        2079 :                 mesh_base->add_point(center_points[i] + x0 + y0 + z0, node_id++);
     469             :             }
     470             :           }
     471             :         }
     472             :       }
     473             :     }
     474             :   }
     475             :   else
     476             :   {
     477             :     unsigned int node_id = 0;
     478          64 :     Real offset_x = (_nx - 1) * _pitch / 2.0;
     479          64 :     Real offset_y = (_ny - 1) * _pitch / 2.0;
     480         306 :     for (unsigned int iy = 0; iy < _ny; iy++)
     481             :     {
     482         242 :       Point y0 = {0, _pitch * iy - offset_y, 0};
     483        1428 :       for (unsigned int ix = 0; ix < _nx; ix++)
     484             :       {
     485        1186 :         Point x0 = {_pitch * ix - offset_x, 0, 0};
     486        1186 :         if (ix == 0 && iy == 0) // Bottom Left corner
     487             :         {
     488        1620 :           for (auto z : _z_grid)
     489             :           {
     490             :             Point z0{0, 0, z};
     491       15560 :             for (unsigned int i = 0; i < points_per_corner; i++)
     492       14004 :               mesh_base->add_point(bl_corner_points[i] + x0 + y0 + z0, node_id++);
     493             :           }
     494             :         }
     495        1122 :         else if (ix == _nx - 1 && iy == 0) // Bottom right corner
     496             :         {
     497        1620 :           for (auto z : _z_grid)
     498             :           {
     499             :             Point z0{0, 0, z};
     500       15560 :             for (unsigned int i = 0; i < points_per_corner; i++)
     501       14004 :               mesh_base->add_point(br_corner_points[i] + x0 + y0 + z0, node_id++);
     502             :           }
     503             :         }
     504        1058 :         else if (ix == 0 && iy == _ny - 1) // top Left corner
     505             :         {
     506        1620 :           for (auto z : _z_grid)
     507             :           {
     508             :             Point z0{0, 0, z};
     509       15560 :             for (unsigned int i = 0; i < points_per_corner; i++)
     510       14004 :               mesh_base->add_point(tl_corner_points[i] + x0 + y0 + z0, node_id++);
     511             :           }
     512             :         }
     513         994 :         else if (ix == _nx - 1 && iy == _ny - 1) // top right corner
     514             :         {
     515        1620 :           for (auto z : _z_grid)
     516             :           {
     517             :             Point z0{0, 0, z};
     518       15560 :             for (unsigned int i = 0; i < points_per_corner; i++)
     519       14004 :               mesh_base->add_point(tr_corner_points[i] + x0 + y0 + z0, node_id++);
     520             :           }
     521             :         }
     522         930 :         else if (ix == 0 && (iy != _ny - 1 || iy != 0)) // left side
     523             :         {
     524        3570 :           for (auto z : _z_grid)
     525             :           {
     526             :             Point z0{0, 0, z};
     527       48384 :             for (unsigned int i = 0; i < points_per_side; i++)
     528       44928 :               mesh_base->add_point(left_points[i] + x0 + y0 + z0, node_id++);
     529             :           }
     530             :         }
     531         816 :         else if (ix == _nx - 1 && (iy != _ny - 1 || iy != 0)) // right side
     532             :         {
     533        3570 :           for (auto z : _z_grid)
     534             :           {
     535             :             Point z0{0, 0, z};
     536       48384 :             for (unsigned int i = 0; i < points_per_side; i++)
     537       44928 :               mesh_base->add_point(right_points[i] + x0 + y0 + z0, node_id++);
     538             :           }
     539             :         }
     540         702 :         else if (iy == 0 && (ix != _nx - 1 || ix != 0)) // bottom side
     541             :         {
     542        5970 :           for (auto z : _z_grid)
     543             :           {
     544             :             Point z0{0, 0, z};
     545       81312 :             for (unsigned int i = 0; i < points_per_side; i++)
     546       75504 :               mesh_base->add_point(bottom_points[i] + x0 + y0 + z0, node_id++);
     547             :           }
     548             :         }
     549         540 :         else if (iy == _ny - 1 && (ix != _nx - 1 || ix != 0)) // top side
     550             :         {
     551        5970 :           for (auto z : _z_grid)
     552             :           {
     553             :             Point z0{0, 0, z};
     554       81312 :             for (unsigned int i = 0; i < points_per_side; i++)
     555       75504 :               mesh_base->add_point(top_points[i] + x0 + y0 + z0, node_id++);
     556             :           }
     557             :         }
     558             :         else // center
     559             :         {
     560       13962 :           for (auto z : _z_grid)
     561             :           {
     562             :             Point z0{0, 0, z};
     563      298848 :             for (unsigned int i = 0; i < points_per_center; i++)
     564      285264 :               mesh_base->add_point(center_points[i] + x0 + y0 + z0, node_id++);
     565             :           }
     566             :         }
     567             :       }
     568             :     }
     569             :   }
     570             : 
     571             :   // Add elements to the mesh.  The elements are 6-node prisms.  The
     572             :   // bases of these prisms form a triangulated representation of a cross-section
     573             :   // of a center subchannel.
     574         103 :   if (_n_channels == 2)
     575             :   {
     576             :     unsigned int elem_id = 0;
     577          51 :     for (unsigned int iy = 0; iy < _ny; iy++)
     578             :     {
     579          72 :       for (unsigned int ix = 0; ix < _nx; ix++)
     580             :       {
     581          42 :         unsigned int i_ch = _nx * iy + ix;
     582        2622 :         for (unsigned int iz = 0; iz < _n_cells; iz++)
     583             :         {
     584       33540 :           for (unsigned int i = 0; i < elems_per_side; i++)
     585             :           {
     586       30960 :             Elem * elem = new Prism6;
     587       30960 :             elem->subdomain_id() = _block_id;
     588       30960 :             elem->set_id(elem_id++);
     589       30960 :             elem = mesh_base->add_elem(elem);
     590             :             // index of the central node at base of cell
     591       30960 :             unsigned int indx1 = iz * points_per_side + points_per_side * (_n_cells + 1) * i_ch;
     592             :             // index of the central node at top of cell
     593       30960 :             unsigned int indx2 =
     594             :                 (iz + 1) * points_per_side + points_per_side * (_n_cells + 1) * i_ch;
     595             :             unsigned int elems_per_channel = elems_per_side;
     596       30960 :             elem->set_node(0, mesh_base->node_ptr(indx1));
     597       30960 :             elem->set_node(1, mesh_base->node_ptr(indx1 + i + 1));
     598       30960 :             if (i != elems_per_channel - 1)
     599       28380 :               elem->set_node(2, mesh_base->node_ptr(indx1 + i + 2));
     600             :             else
     601        2580 :               elem->set_node(2, mesh_base->node_ptr(indx1 + 1));
     602             : 
     603       30960 :             elem->set_node(3, mesh_base->node_ptr(indx2));
     604       30960 :             elem->set_node(4, mesh_base->node_ptr(indx2 + i + 1));
     605       30960 :             if (i != elems_per_channel - 1)
     606       28380 :               elem->set_node(5, mesh_base->node_ptr(indx2 + i + 2));
     607             :             else
     608        2580 :               elem->set_node(5, mesh_base->node_ptr(indx2 + 1));
     609             : 
     610       30960 :             if (iz == 0)
     611         504 :               boundary_info.add_side(elem, 0, 0);
     612       30960 :             if (iz == _n_cells - 1)
     613         504 :               boundary_info.add_side(elem, 4, 1);
     614             :           }
     615             :         }
     616             :       }
     617             :     }
     618          21 :     boundary_info.sideset_name(0) = "inlet";
     619          21 :     boundary_info.sideset_name(1) = "outlet";
     620          21 :     mesh_base->subdomain_name(_block_id) = name();
     621          21 :     mesh_base->prepare_for_use();
     622             :   }
     623          82 :   else if (_n_channels > 2 && (_ny == 1 || _nx == 1))
     624             :   {
     625             :     unsigned int elem_id = 0;
     626             :     unsigned int number_of_corner = 0;
     627             :     unsigned int number_of_side = 0;
     628             :     unsigned int number_of_center = 0;
     629             :     unsigned int elems_per_channel = 0;
     630             :     unsigned int points_per_channel = 0;
     631          54 :     for (unsigned int iy = 0; iy < _ny; iy++)
     632             :     {
     633          90 :       for (unsigned int ix = 0; ix < _nx; ix++)
     634             :       {
     635          54 :         unsigned int i_ch = _nx * iy + ix;
     636             :         auto subch_type = getSubchannelType(i_ch);
     637             :         // note that in this case i use side geometry for corner subchannel
     638          54 :         if (subch_type == EChannelType::CORNER)
     639             :         {
     640          36 :           number_of_side++;
     641             :           elems_per_channel = elems_per_side;
     642             :           points_per_channel = points_per_side;
     643             :         }
     644             :         // note that in this case i use center geometry for edge subchannel
     645          18 :         else if (subch_type == EChannelType::EDGE)
     646             :         {
     647          18 :           number_of_center++;
     648             :           elems_per_channel = elems_per_center;
     649             :           points_per_channel = points_per_center;
     650             :         }
     651         594 :         for (unsigned int iz = 0; iz < _n_cells; iz++)
     652             :         {
     653         540 :           unsigned int elapsed_points = number_of_corner * points_per_corner * (_n_cells + 1) +
     654         540 :                                         number_of_side * points_per_side * (_n_cells + 1) +
     655             :                                         number_of_center * points_per_center * (_n_cells + 1) -
     656         540 :                                         points_per_channel * (_n_cells + 1);
     657             :           // index of the central node at base of cell
     658         540 :           unsigned int indx1 = iz * points_per_channel + elapsed_points;
     659             :           // index of the central node at top of cell
     660         540 :           unsigned int indx2 = (iz + 1) * points_per_channel + elapsed_points;
     661             : 
     662        8460 :           for (unsigned int i = 0; i < elems_per_channel; i++)
     663             :           {
     664        7920 :             Elem * elem = new Prism6;
     665        7920 :             elem->subdomain_id() = _block_id;
     666        7920 :             elem->set_id(elem_id++);
     667        7920 :             elem = mesh_base->add_elem(elem);
     668             : 
     669        7920 :             elem->set_node(0, mesh_base->node_ptr(indx1));
     670        7920 :             elem->set_node(1, mesh_base->node_ptr(indx1 + i + 1));
     671        7920 :             if (i != elems_per_channel - 1)
     672        7380 :               elem->set_node(2, mesh_base->node_ptr(indx1 + i + 2));
     673             :             else
     674         540 :               elem->set_node(2, mesh_base->node_ptr(indx1 + 1));
     675             : 
     676        7920 :             elem->set_node(3, mesh_base->node_ptr(indx2));
     677        7920 :             elem->set_node(4, mesh_base->node_ptr(indx2 + i + 1));
     678        7920 :             if (i != elems_per_channel - 1)
     679        7380 :               elem->set_node(5, mesh_base->node_ptr(indx2 + i + 2));
     680             :             else
     681         540 :               elem->set_node(5, mesh_base->node_ptr(indx2 + 1));
     682             : 
     683        7920 :             if (iz == 0)
     684         792 :               boundary_info.add_side(elem, 0, 0);
     685        7920 :             if (iz == _n_cells - 1)
     686         792 :               boundary_info.add_side(elem, 4, 1);
     687             :           }
     688             :         }
     689             :       }
     690             :     }
     691          18 :     boundary_info.sideset_name(0) = "inlet";
     692          18 :     boundary_info.sideset_name(1) = "outlet";
     693          18 :     mesh_base->subdomain_name(_block_id) = name();
     694          18 :     mesh_base->prepare_for_use();
     695             :   }
     696             :   else
     697             :   {
     698             :     unsigned int elem_id = 0;
     699             :     unsigned int number_of_corner = 0;
     700             :     unsigned int number_of_side = 0;
     701             :     unsigned int number_of_center = 0;
     702             :     unsigned int elems_per_channel = 0;
     703             :     unsigned int points_per_channel = 0;
     704         306 :     for (unsigned int iy = 0; iy < _ny; iy++)
     705             :     {
     706        1428 :       for (unsigned int ix = 0; ix < _nx; ix++)
     707             :       {
     708        1186 :         unsigned int i_ch = _nx * iy + ix;
     709             :         auto subch_type = getSubchannelType(i_ch);
     710        1186 :         if (subch_type == EChannelType::CORNER)
     711             :         {
     712         256 :           number_of_corner++;
     713             :           elems_per_channel = elems_per_corner;
     714             :           points_per_channel = points_per_corner;
     715             :         }
     716         930 :         else if (subch_type == EChannelType::EDGE)
     717             :         {
     718         552 :           number_of_side++;
     719             :           elems_per_channel = elems_per_side;
     720             :           points_per_channel = points_per_side;
     721             :         }
     722             :         else
     723             :         {
     724         378 :           number_of_center++;
     725             :           elems_per_channel = elems_per_center;
     726             :           points_per_channel = points_per_center;
     727             :         }
     728       38336 :         for (unsigned int iz = 0; iz < _n_cells; iz++)
     729             :         {
     730       37150 :           unsigned int elapsed_points = number_of_corner * points_per_corner * (_n_cells + 1) +
     731       37150 :                                         number_of_side * points_per_side * (_n_cells + 1) +
     732             :                                         number_of_center * points_per_center * (_n_cells + 1) -
     733       37150 :                                         points_per_channel * (_n_cells + 1);
     734             :           // index of the central node at base of cell
     735       37150 :           unsigned int indx1 = iz * points_per_channel + elapsed_points;
     736             :           // index of the central node at top of cell
     737       37150 :           unsigned int indx2 = (iz + 1) * points_per_channel + elapsed_points;
     738             : 
     739      564726 :           for (unsigned int i = 0; i < elems_per_channel; i++)
     740             :           {
     741      527576 :             Elem * elem = new Prism6;
     742      527576 :             elem->subdomain_id() = _block_id;
     743      527576 :             elem->set_id(elem_id++);
     744      527576 :             elem = mesh_base->add_elem(elem);
     745             : 
     746      527576 :             elem->set_node(0, mesh_base->node_ptr(indx1));
     747      527576 :             elem->set_node(1, mesh_base->node_ptr(indx1 + i + 1));
     748      527576 :             if (i != elems_per_channel - 1)
     749      490426 :               elem->set_node(2, mesh_base->node_ptr(indx1 + i + 2));
     750             :             else
     751       37150 :               elem->set_node(2, mesh_base->node_ptr(indx1 + 1));
     752             : 
     753      527576 :             elem->set_node(3, mesh_base->node_ptr(indx2));
     754      527576 :             elem->set_node(4, mesh_base->node_ptr(indx2 + i + 1));
     755      527576 :             if (i != elems_per_channel - 1)
     756      490426 :               elem->set_node(5, mesh_base->node_ptr(indx2 + i + 2));
     757             :             else
     758       37150 :               elem->set_node(5, mesh_base->node_ptr(indx2 + 1));
     759             : 
     760      527576 :             if (iz == 0)
     761       16232 :               boundary_info.add_side(elem, 0, 0);
     762      527576 :             if (iz == _n_cells - 1)
     763       16232 :               boundary_info.add_side(elem, 4, 1);
     764             :           }
     765             :         }
     766             :       }
     767             :     }
     768          64 :     boundary_info.sideset_name(0) = "inlet";
     769          64 :     boundary_info.sideset_name(1) = "outlet";
     770          64 :     mesh_base->subdomain_name(_block_id) = name();
     771          64 :     mesh_base->prepare_for_use();
     772             :   }
     773             : 
     774         103 :   return mesh_base;
     775           0 : }

Generated by: LCOV version 1.14