LCOV - code coverage report
Current view: top level - src/meshgenerators - SCMQuadInterWrapperMeshGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #31405 (292dce) with base fef103 Lines: 196 199 98.5 %
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 "SCMQuadInterWrapperMeshGenerator.h"
      11             : #include "QuadInterWrapperMesh.h"
      12             : #include "libmesh/edge_edge2.h"
      13             : #include <numeric>
      14             : 
      15             : registerMooseObject("SubChannelApp", SCMQuadInterWrapperMeshGenerator);
      16             : registerMooseObjectRenamed("SubChannelApp",
      17             :                            QuadInterWrapperMeshGenerator,
      18             :                            "06/30/2025 24:00",
      19             :                            SCMQuadInterWrapperMeshGenerator);
      20             : 
      21             : InputParameters
      22          84 : SCMQuadInterWrapperMeshGenerator::validParams()
      23             : {
      24          84 :   InputParameters params = MeshGenerator::validParams();
      25          84 :   params.addClassDescription("Creates a mesh for the inter-wrapper around square subassemblies");
      26         168 :   params.addRequiredParam<Real>("assembly_pitch", "Assembly Pitch [m]");
      27         168 :   params.addRequiredParam<Real>("assembly_side_x",
      28             :                                 "Outer side lengths of assembly in x [m] - including duct");
      29         168 :   params.addRequiredParam<Real>("assembly_side_y",
      30             :                                 "Outer side lengths of assembly in y [m] - including duct");
      31         168 :   params.addParam<Real>("unheated_length_entry", 0.0, "Unheated length at entry [m]");
      32         168 :   params.addRequiredParam<Real>("heated_length", "Heated length [m]");
      33         168 :   params.addParam<Real>("unheated_length_exit", 0.0, "Unheated length at exit [m]");
      34         168 :   params.addParam<Real>("Kij", 0.5, "Lateral form loss coefficient [-]");
      35         168 :   params.addRequiredParam<unsigned int>("n_cells", "The number of cells in the axial direction");
      36         168 :   params.addRequiredParam<unsigned int>("nx", "Number of assemblies in the x direction [-]");
      37         168 :   params.addRequiredParam<unsigned int>("ny", "Number of assemblies in the y direction [-]");
      38         168 :   params.addRequiredParam<Real>("side_bypass",
      39             :                                 "Extra size of the bypass for the side assemblies [m]");
      40         168 :   params.addParam<unsigned int>("block_id", 0, "Domain Index");
      41          84 :   return params;
      42           0 : }
      43             : 
      44          42 : SCMQuadInterWrapperMeshGenerator::SCMQuadInterWrapperMeshGenerator(const InputParameters & params)
      45             :   : MeshGenerator(params),
      46          42 :     _assembly_pitch(getParam<Real>("assembly_pitch")),
      47          84 :     _assembly_side_x(getParam<Real>("assembly_side_x")),
      48          84 :     _assembly_side_y(getParam<Real>("assembly_side_y")),
      49          84 :     _unheated_length_entry(getParam<Real>("unheated_length_entry")),
      50          84 :     _heated_length(getParam<Real>("heated_length")),
      51          84 :     _unheated_length_exit(getParam<Real>("unheated_length_exit")),
      52          84 :     _kij(getParam<Real>("Kij")),
      53          84 :     _n_cells(getParam<unsigned int>("n_cells")),
      54          84 :     _nx(getParam<unsigned int>("nx")),
      55          84 :     _ny(getParam<unsigned int>("ny")),
      56          84 :     _side_bypass_length(getParam<Real>("side_bypass")),
      57          42 :     _n_channels((_nx + 1) * (_ny + 1)),
      58          42 :     _n_gaps(_nx * (_ny + 1) + _ny * (_nx + 1)),
      59          42 :     _n_assemblies(_nx * _ny),
      60         126 :     _block_id(getParam<unsigned int>("block_id"))
      61             : {
      62             :   // Converting number of assemblies into number of inter-wrapper flow channels
      63          42 :   _nx += 1;
      64          42 :   _ny += 1;
      65             : 
      66          42 :   if (_nx < 2 && _ny < 2)
      67           0 :     mooseError(name(), ": The number of assemblies cannot be less than one in any direction. ");
      68             : 
      69             :   // Defining the total length from 3 axial sections
      70          42 :   Real L = _unheated_length_entry + _heated_length + _unheated_length_exit;
      71             : 
      72             :   // Defining the dz based in the total length and the specified number of axial cells
      73          42 :   Real dz = L / _n_cells;
      74         864 :   for (unsigned int i = 0; i < _n_cells + 1; i++)
      75         822 :     _z_grid.push_back(dz * i);
      76             : 
      77             :   // Defining the array for axial resistances
      78          42 :   _k_grid.resize(_n_channels, std::vector<Real>(_n_cells + 1));
      79             : 
      80             :   // Defining the size of the maps
      81          42 :   _gap_to_chan_map.resize(_n_gaps);
      82          42 :   _gapnodes.resize(_n_gaps);
      83          42 :   _chan_to_gap_map.resize(_n_channels);
      84          42 :   _chan_to_pin_map.resize(_n_channels);
      85          42 :   _pin_to_chan_map.resize(_n_assemblies);
      86          42 :   _sign_id_crossflow_map.resize(_n_channels);
      87          42 :   _gij_map.resize(_n_gaps);
      88             : 
      89             :   // Defining the signs for positive and negative flows
      90          42 :   Real positive_flow = 1.0;
      91          42 :   Real negative_flow = -1.0;
      92             : 
      93             :   // Defining the subchannel types
      94          42 :   _subch_type.resize(_n_channels);
      95         366 :   for (unsigned int iy = 0; iy < _ny; iy++)
      96             :   {
      97        3636 :     for (unsigned int ix = 0; ix < _nx; ix++)
      98             :     {
      99        3312 :       unsigned int i_ch = _nx * iy + ix;
     100        3270 :       bool is_corner = (ix == 0 && iy == 0) || (ix == _nx - 1 && iy == 0) ||
     101        6540 :                        (ix == 0 && iy == _ny - 1) || (ix == _nx - 1 && iy == _ny - 1);
     102        3312 :       bool is_edge = (ix == 0 || iy == 0 || ix == _nx - 1 || iy == _ny - 1);
     103             : 
     104        3312 :       if (is_corner)
     105         168 :         _subch_type[i_ch] = EChannelType::CORNER;
     106        3144 :       else if (is_edge)
     107         960 :         _subch_type[i_ch] = EChannelType::EDGE;
     108             :       else
     109        2184 :         _subch_type[i_ch] = EChannelType::CENTER;
     110             :     }
     111             :   }
     112             : 
     113             :   // Index the east-west gaps.
     114          42 :   unsigned int i_gap = 0;
     115         366 :   for (unsigned int iy = 0; iy < _ny; iy++)
     116             :   {
     117        3312 :     for (unsigned int ix = 0; ix < _nx - 1; ix++)
     118             :     {
     119        2988 :       unsigned int i_ch = _nx * iy + ix;
     120        2988 :       unsigned int j_ch = _nx * iy + (ix + 1);
     121        2988 :       _gap_to_chan_map[i_gap] = {i_ch, j_ch};
     122        2988 :       _chan_to_gap_map[i_ch].push_back(i_gap);
     123        2988 :       _chan_to_gap_map[j_ch].push_back(i_gap);
     124        2988 :       _sign_id_crossflow_map[i_ch].push_back(positive_flow);
     125        2988 :       _sign_id_crossflow_map[j_ch].push_back(negative_flow);
     126             : 
     127             :       // make a gap size map
     128        2988 :       if (iy == 0 || iy == _ny - 1)
     129         564 :         _gij_map[i_gap] = (_assembly_pitch - _assembly_side_x) / 2 + _side_bypass_length;
     130             :       else
     131        2424 :         _gij_map[i_gap] = (_assembly_pitch - _assembly_side_x);
     132        2988 :       ++i_gap;
     133             :     }
     134             :   }
     135             : 
     136             :   // Index the north-south gaps.
     137         324 :   for (unsigned int iy = 0; iy < _ny - 1; iy++)
     138             :   {
     139        3270 :     for (unsigned int ix = 0; ix < _nx; ix++)
     140             :     {
     141        2988 :       unsigned int i_ch = _nx * iy + ix;
     142        2988 :       unsigned int j_ch = _nx * (iy + 1) + ix;
     143        2988 :       _gap_to_chan_map[i_gap] = {i_ch, j_ch};
     144        2988 :       _chan_to_gap_map[i_ch].push_back(i_gap);
     145        2988 :       _chan_to_gap_map[j_ch].push_back(i_gap);
     146        2988 :       _sign_id_crossflow_map[i_ch].push_back(positive_flow);
     147        2988 :       _sign_id_crossflow_map[j_ch].push_back(negative_flow);
     148             : 
     149             :       // make a gap size map
     150        2988 :       if (ix == 0 || ix == _nx - 1)
     151         564 :         _gij_map[i_gap] = (_assembly_pitch - _assembly_side_y) / 2 + _side_bypass_length;
     152             :       else
     153        2424 :         _gij_map[i_gap] = (_assembly_pitch - _assembly_side_y);
     154        2988 :       ++i_gap;
     155             :     }
     156             :   }
     157             : 
     158             :   // Make assembly to channel map
     159         324 :   for (unsigned int iy = 0; iy < _ny - 1; iy++)
     160             :   {
     161        2988 :     for (unsigned int ix = 0; ix < _nx - 1; ix++)
     162             :     {
     163        2706 :       unsigned int i_pin = (_nx - 1) * iy + ix;
     164        2706 :       unsigned int i_chan_1 = _nx * iy + ix;
     165        2706 :       unsigned int i_chan_2 = _nx * (iy + 1) + ix;
     166        2706 :       unsigned int i_chan_3 = _nx * (iy + 1) + (ix + 1);
     167        2706 :       unsigned int i_chan_4 = _nx * iy + (ix + 1);
     168        2706 :       _pin_to_chan_map[i_pin].push_back(i_chan_1);
     169        2706 :       _pin_to_chan_map[i_pin].push_back(i_chan_2);
     170        2706 :       _pin_to_chan_map[i_pin].push_back(i_chan_3);
     171        2706 :       _pin_to_chan_map[i_pin].push_back(i_chan_4);
     172             :     }
     173             :   }
     174             : 
     175             :   // Make channel to assembly map
     176         366 :   for (unsigned int iy = 0; iy < _ny; iy++) // row
     177             :   {
     178        3636 :     for (unsigned int ix = 0; ix < _nx; ix++) // column
     179             :     {
     180        3312 :       unsigned int i_ch = _nx * iy + ix;
     181             :       // Corners contact 1/4 of one pin
     182        3312 :       if (iy == 0 && ix == 0)
     183             :       {
     184          42 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix);
     185             :       }
     186        3270 :       else if (iy == _ny - 1 && ix == 0)
     187             :       {
     188          42 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix);
     189             :       }
     190        3228 :       else if (iy == 0 && ix == _nx - 1)
     191             :       {
     192          42 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix - 1);
     193             :       }
     194        3186 :       else if (iy == _ny - 1 && ix == _nx - 1)
     195             :       {
     196          42 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix - 1);
     197             :       }
     198             :       // Sides contact 1/4 of two pins
     199        3144 :       else if (iy == 0)
     200             :       {
     201         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix);
     202         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix - 1);
     203             :       }
     204        2904 :       else if (iy == _ny - 1)
     205             :       {
     206         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix);
     207         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix - 1);
     208             :       }
     209        2664 :       else if (ix == 0)
     210             :       {
     211         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix);
     212         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix);
     213             :       }
     214        2424 :       else if (ix == _nx - 1)
     215             :       {
     216         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix - 1);
     217         240 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix - 1);
     218             :       }
     219             :       // interior contacts 1/4 of 4 pins
     220             :       else
     221             :       {
     222        2184 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix);
     223        2184 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * iy + ix - 1);
     224        2184 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix);
     225        2184 :         _chan_to_pin_map[i_ch].push_back((_nx - 1) * (iy - 1) + ix - 1);
     226             :       }
     227             :     }
     228             :   }
     229             : 
     230             :   // Reduce reserved memory in the channel-to-gap map.
     231        3354 :   for (auto & gap : _chan_to_gap_map)
     232             :     gap.shrink_to_fit();
     233             : 
     234             :   // Reduce reserved memory in the channel-to-pin map.
     235        3354 :   for (auto & pin : _chan_to_pin_map)
     236             :     pin.shrink_to_fit();
     237             : 
     238             :   // Reduce reserved memory in the pin-to-channel map.
     239        2748 :   for (auto & pin : _pin_to_chan_map)
     240             :     pin.shrink_to_fit();
     241             : 
     242          42 :   _console << "Inter-wrapper quad mesh initialized" << std::endl;
     243          42 : }
     244             : 
     245             : std::unique_ptr<MeshBase>
     246          42 : SCMQuadInterWrapperMeshGenerator::generate()
     247             : {
     248          42 :   auto mesh_base = buildMeshBaseObject();
     249             :   BoundaryInfo & boundary_info = mesh_base->get_boundary_info();
     250          42 :   mesh_base->set_spatial_dimension(3);
     251          42 :   mesh_base->reserve_elem(_n_cells * _ny * _nx);
     252          42 :   mesh_base->reserve_nodes((_n_cells + 1) * _ny * _nx);
     253          42 :   _nodes.resize(_nx * _ny);
     254             :   // Add the points in the shape of a rectilinear grid.  The grid is regular
     255             :   // on the xy-plane with a spacing of `pitch` between points.  The grid along
     256             :   // z is irregular to account for Pin spacers.  Store pointers in the _nodes
     257             :   // array so we can keep track of which points are in which channels.
     258          42 :   Real offset_x = (_nx - 1) * _assembly_pitch / 2.0;
     259          42 :   Real offset_y = (_ny - 1) * _assembly_pitch / 2.0;
     260             :   unsigned int node_id = 0;
     261         366 :   for (unsigned int iy = 0; iy < _ny; iy++)
     262             :   {
     263        3636 :     for (unsigned int ix = 0; ix < _nx; ix++)
     264             :     {
     265        3312 :       int i_ch = _nx * iy + ix;
     266        3312 :       _nodes[i_ch].reserve(_n_cells);
     267      131904 :       for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
     268             :       {
     269      128592 :         _nodes[i_ch].push_back(mesh_base->add_point(
     270      128592 :             Point(_assembly_pitch * ix - offset_x, _assembly_pitch * iy - offset_y, _z_grid[iz]),
     271      128592 :             node_id++));
     272             :       }
     273             :     }
     274             :   }
     275             : 
     276             :   // Add the elements which in this case are 2-node edges that link each
     277             :   // subchannel's nodes vertically.
     278             :   unsigned int elem_id = 0;
     279         366 :   for (unsigned int iy = 0; iy < _ny; iy++)
     280             :   {
     281        3636 :     for (unsigned int ix = 0; ix < _nx; ix++)
     282             :     {
     283      128592 :       for (unsigned int iz = 0; iz < _n_cells; iz++)
     284             :       {
     285      125280 :         Elem * elem = new Edge2;
     286      125280 :         elem->subdomain_id() = _block_id;
     287      125280 :         elem->set_id(elem_id++);
     288      125280 :         elem = mesh_base->add_elem(elem);
     289      125280 :         const int indx1 = ((_n_cells + 1) * _nx) * iy + (_n_cells + 1) * ix + iz;
     290      125280 :         const int indx2 = ((_n_cells + 1) * _nx) * iy + (_n_cells + 1) * ix + (iz + 1);
     291      125280 :         elem->set_node(0, mesh_base->node_ptr(indx1));
     292      125280 :         elem->set_node(1, mesh_base->node_ptr(indx2));
     293             : 
     294      125280 :         if (iz == 0)
     295        3312 :           boundary_info.add_side(elem, 0, 0);
     296      125280 :         if (iz == _n_cells - 1)
     297        3312 :           boundary_info.add_side(elem, 1, 1);
     298             :       }
     299             :     }
     300             :   }
     301             : 
     302          42 :   boundary_info.sideset_name(0) = "inlet";
     303          42 :   boundary_info.sideset_name(1) = "outlet";
     304          42 :   boundary_info.nodeset_name(0) = "inlet";
     305          42 :   boundary_info.nodeset_name(1) = "outlet";
     306          42 :   mesh_base->subdomain_name(_block_id) = name();
     307          42 :   mesh_base->prepare_for_use();
     308             : 
     309             :   // move the meta data into QuadInterWrapperMesh
     310          42 :   auto & sch_mesh = static_cast<QuadInterWrapperMesh &>(*_mesh);
     311          42 :   sch_mesh._unheated_length_entry = _unheated_length_entry;
     312             : 
     313          42 :   sch_mesh._assembly_pitch = _assembly_pitch;
     314          42 :   sch_mesh._assembly_side_x = _assembly_side_x;
     315          42 :   sch_mesh._assembly_side_y = _assembly_side_y;
     316          42 :   sch_mesh._heated_length = _heated_length;
     317          42 :   sch_mesh._unheated_length_exit = _unheated_length_exit;
     318          42 :   sch_mesh._z_grid = _z_grid;
     319          42 :   sch_mesh._k_grid = _k_grid;
     320          42 :   sch_mesh._kij = _kij;
     321          42 :   sch_mesh._n_cells = _n_cells;
     322          42 :   sch_mesh._nx = _nx;
     323          42 :   sch_mesh._ny = _ny;
     324          42 :   sch_mesh._side_bypass_length = _side_bypass_length;
     325          42 :   sch_mesh._n_channels = _n_channels;
     326          42 :   sch_mesh._n_gaps = _n_gaps;
     327          42 :   sch_mesh._n_assemblies = _n_assemblies;
     328          42 :   sch_mesh._nodes = _nodes;
     329          42 :   sch_mesh._gapnodes = _gapnodes;
     330          42 :   sch_mesh._gap_to_chan_map = _gap_to_chan_map;
     331          42 :   sch_mesh._chan_to_gap_map = _chan_to_gap_map;
     332          42 :   sch_mesh._chan_to_pin_map = _chan_to_pin_map;
     333          42 :   sch_mesh._pin_to_chan_map = _pin_to_chan_map;
     334          42 :   sch_mesh._sign_id_crossflow_map = _sign_id_crossflow_map;
     335          42 :   sch_mesh._gij_map = _gij_map;
     336          42 :   sch_mesh._subch_type = _subch_type;
     337             : 
     338          42 :   _console << "Inter-wrapper quad mesh generated" << std::endl;
     339             : 
     340          42 :   return mesh_base;
     341           0 : }

Generated by: LCOV version 1.14