LCOV - code coverage report
Current view: top level - src/mesh - QuadSubChannelMesh.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #32971 (54bef8) with base c6cf66 Lines: 78 103 75.7 %
Date: 2026-05-29 20:40:47 Functions: 11 13 84.6 %
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 "QuadSubChannelMesh.h"
      11             : #include <cmath>
      12             : #include <limits>
      13             : #include "libmesh/edge_edge2.h"
      14             : #include "libmesh/unstructured_mesh.h"
      15             : 
      16             : registerMooseObject("SubChannelApp", QuadSubChannelMesh);
      17             : 
      18             : InputParameters
      19         450 : QuadSubChannelMesh::validParams()
      20             : {
      21         450 :   InputParameters params = SubChannelMesh::validParams();
      22         450 :   params.addClassDescription("Creates an subchannel mesh container for a square "
      23             :                              "lattice arrangement");
      24         450 :   return params;
      25           0 : }
      26             : 
      27         225 : QuadSubChannelMesh::QuadSubChannelMesh(const InputParameters & params) : SubChannelMesh(params) {}
      28             : 
      29           0 : QuadSubChannelMesh::QuadSubChannelMesh(const QuadSubChannelMesh & other_mesh)
      30             :   : SubChannelMesh(other_mesh),
      31           0 :     _nx(other_mesh._nx),
      32           0 :     _ny(other_mesh._ny),
      33           0 :     _n_channels(other_mesh._n_channels),
      34           0 :     _n_gaps(other_mesh._n_gaps),
      35           0 :     _n_pins(other_mesh._n_pins),
      36           0 :     _side_gap(other_mesh._side_gap),
      37           0 :     _nodes(other_mesh._nodes),
      38           0 :     _pin_nodes(other_mesh._pin_nodes),
      39           0 :     _gapnodes(other_mesh._gapnodes),
      40           0 :     _gap_to_chan_map(other_mesh._gap_to_chan_map),
      41           0 :     _gap_to_pin_map(other_mesh._gap_to_pin_map),
      42           0 :     _chan_to_gap_map(other_mesh._chan_to_gap_map),
      43           0 :     _chan_to_pin_map(other_mesh._chan_to_pin_map),
      44           0 :     _pin_to_chan_map(other_mesh._pin_to_chan_map),
      45           0 :     _sign_id_crossflow_map(other_mesh._sign_id_crossflow_map),
      46           0 :     _gij_map(other_mesh._gij_map),
      47           0 :     _subch_type(other_mesh._subch_type)
      48             : {
      49           0 :   if (_nx < 2 && _ny < 2)
      50           0 :     mooseError(name(),
      51             :                ": The number of subchannels cannot be less than 2 in both directions (x and y). "
      52             :                "Smallest assembly allowed is either 2X1 or 1X2. ");
      53           0 : }
      54             : 
      55             : std::unique_ptr<MooseMesh>
      56           0 : QuadSubChannelMesh::safeClone() const
      57             : {
      58           0 :   return _app.getFactory().copyConstruct(*this);
      59             : }
      60             : 
      61             : void
      62         225 : QuadSubChannelMesh::buildMesh()
      63             : {
      64         225 : }
      65             : 
      66             : void
      67         223 : QuadSubChannelMesh::computeAssemblyHydraulicParameters()
      68             : {
      69         223 :   _assembly_flow_area = 0.0;
      70         223 :   _assembly_wetted_perimeter = 0.0;
      71         223 :   _assembly_hydraulic_diameter = 0.0;
      72             : 
      73         223 :   const Real z = _z_grid.empty() ? 0.0 : _z_grid.front();
      74             : 
      75        3937 :   for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
      76             :   {
      77        3714 :     _assembly_flow_area += getSubchannelFlowArea(i_ch, z);
      78        3714 :     _assembly_wetted_perimeter += getSubchannelWettedPerimeter(i_ch);
      79             :   }
      80             : 
      81         223 :   if (_assembly_wetted_perimeter == 0.0)
      82           0 :     mooseError(name(), ": Assembly wetted perimeter is zero; cannot compute hydraulic diameter.");
      83             : 
      84         223 :   _assembly_hydraulic_diameter = 4.0 * _assembly_flow_area / _assembly_wetted_perimeter;
      85         223 : }
      86             : 
      87             : Real
      88       54188 : QuadSubChannelMesh::getSubchannelFlowArea(unsigned int i_chan, Real z) const
      89             : {
      90             :   Real standard_area = 0.0;
      91             :   Real rod_area = 0.0;
      92             :   Real additional_area = 0.0;
      93             : 
      94       54188 :   const auto subch_type = getSubchannelType(i_chan);
      95       54188 :   if (subch_type == EChannelType::CORNER)
      96             :   {
      97       13472 :     standard_area = 0.25 * _pitch * _pitch;
      98       13472 :     rod_area = 0.25 * 0.25 * libMesh::pi * _pin_diameter * _pin_diameter;
      99       13472 :     additional_area = _pitch * _side_gap + _side_gap * _side_gap;
     100             :   }
     101       40716 :   else if (subch_type == EChannelType::EDGE)
     102             :   {
     103       25162 :     standard_area = 0.5 * _pitch * _pitch;
     104       25162 :     rod_area = 0.5 * 0.25 * libMesh::pi * _pin_diameter * _pin_diameter;
     105       25162 :     additional_area = _pitch * _side_gap;
     106             :   }
     107             :   else
     108             :   {
     109       15554 :     standard_area = _pitch * _pitch;
     110       15554 :     rod_area = 0.25 * libMesh::pi * _pin_diameter * _pin_diameter;
     111             :   }
     112             : 
     113       54188 :   Real flow_area = standard_area + additional_area - rod_area;
     114             : 
     115             :   unsigned int blockage_index = 0;
     116      108376 :   for (const auto & i_blockage : _index_blockage)
     117             :   {
     118       54188 :     if (i_chan == i_blockage && z >= _z_blockage.front() && z <= _z_blockage.back())
     119         320 :       flow_area *= _reduction_blockage[blockage_index];
     120       54188 :     blockage_index++;
     121             :   }
     122             : 
     123       54188 :   return flow_area;
     124             : }
     125             : 
     126             : Real
     127       53288 : QuadSubChannelMesh::getSubchannelWettedPerimeter(unsigned int i_chan) const
     128             : {
     129       53288 :   const Real rod_circumference = libMesh::pi * _pin_diameter;
     130       53288 :   const auto subch_type = getSubchannelType(i_chan);
     131             : 
     132       53288 :   if (subch_type == EChannelType::CORNER)
     133       13072 :     return 0.25 * rod_circumference + _pitch + 2.0 * _side_gap;
     134       40216 :   else if (subch_type == EChannelType::EDGE)
     135       24762 :     return 0.5 * rod_circumference + _pitch;
     136             :   else
     137             :     return rod_circumference;
     138             : }
     139             : 
     140             : unsigned int
     141      112300 : QuadSubChannelMesh::getSubchannelIndexFromPoint(const Point & p) const
     142             : {
     143      112300 :   Real offset_x = (_nx - 1) * _pitch / 2.0;
     144      112300 :   Real offset_y = (_ny - 1) * _pitch / 2.0;
     145      112300 :   unsigned int i = (p(0) + offset_x + 0.5 * _pitch) / _pitch;
     146      112300 :   unsigned int j = (p(1) + offset_y + 0.5 * _pitch) / _pitch;
     147      112300 :   return j * _nx + i;
     148             : }
     149             : 
     150             : unsigned int
     151      559400 : QuadSubChannelMesh::channelIndex(const Point & pt) const
     152             : {
     153             :   // this is identical to getSubchannelIndexFromPoint, but when it is given a point "outside" the
     154             :   // normal subchannel geometry (i.e. a point that lies in a gap around the lattice) we still report
     155             :   // a valid subchannel index this is needed for transferring the solution onto a visualization mesh
     156             : 
     157      559400 :   Real offset_x = (_nx - 1) * _pitch / 2.0;
     158      559400 :   Real offset_y = (_ny - 1) * _pitch / 2.0;
     159      559400 :   int i = (pt(0) + offset_x + 0.5 * _pitch) / _pitch;
     160      559400 :   int j = (pt(1) + offset_y + 0.5 * _pitch) / _pitch;
     161             : 
     162      559400 :   i = std::max(0, i);
     163      559400 :   i = std::min(i, (int)(_nx - 1));
     164             : 
     165      559400 :   j = std::max(0, j);
     166      559400 :   j = std::min(j, (int)(_ny - 1));
     167             : 
     168      559400 :   return j * _nx + i;
     169             : }
     170             : 
     171             : unsigned int
     172       20088 : QuadSubChannelMesh::getPinIndexFromPoint(const Point & p) const
     173             : {
     174       20088 :   Real offset_x = (_nx - 2) * _pitch / 2.0;
     175       20088 :   Real offset_y = (_ny - 2) * _pitch / 2.0;
     176       20088 :   unsigned int i = (p(0) + offset_x) / _pitch;
     177       20088 :   unsigned int j = (p(1) + offset_y) / _pitch;
     178       20088 :   return j * (_nx - 1) + i;
     179             : }
     180             : 
     181             : unsigned int
     182       82014 : QuadSubChannelMesh::pinIndex(const Point & p) const
     183             : {
     184       82014 :   Real offset_x = (_nx - 2) * _pitch / 2.0;
     185       82014 :   Real offset_y = (_ny - 2) * _pitch / 2.0;
     186       82014 :   unsigned int i = (p(0) + offset_x) / _pitch;
     187       82014 :   unsigned int j = (p(1) + offset_y) / _pitch;
     188       82014 :   return j * (_nx - 1) + i;
     189             : }
     190             : 
     191             : void
     192          22 : QuadSubChannelMesh::generatePinCenters(
     193             :     unsigned int nx, unsigned int ny, Real pitch, Real elev, std::vector<Point> & pin_centers)
     194             : {
     195             :   mooseAssert(nx >= 2, "Number of channels in x-direction must be 2 or more.");
     196             :   mooseAssert(ny >= 2, "Number of channels in y-direction must be 2 or more.");
     197             : 
     198          22 :   Real offset_x = (nx - 2) * pitch / 2.0;
     199          22 :   Real offset_y = (ny - 2) * pitch / 2.0;
     200          62 :   for (unsigned int iy = 0; iy < ny - 1; iy++)
     201         164 :     for (unsigned int ix = 0; ix < nx - 1; ix++)
     202         124 :       pin_centers.push_back(Point(pitch * ix - offset_x, pitch * iy - offset_y, elev));
     203          22 : }

Generated by: LCOV version 1.14