LCOV - code coverage report
Current view: top level - src/ics - QuadInterWrapperPowerIC.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #31405 (292dce) with base fef103 Lines: 64 85 75.3 %
Date: 2025-09-04 07:58:06 Functions: 4 4 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 "QuadInterWrapperPowerIC.h"
      11             : #include "Function.h"
      12             : #include "QuadInterWrapperMesh.h"
      13             : 
      14             : using namespace std;
      15             : using namespace Eigen;
      16             : 
      17             : registerMooseObject("SubChannelApp", QuadInterWrapperPowerIC);
      18             : 
      19             : InputParameters
      20          68 : QuadInterWrapperPowerIC::validParams()
      21             : {
      22          68 :   InputParameters params = QuadInterWrapperBaseIC::validParams();
      23          68 :   params.addClassDescription("Computes axial power rate, W/m that goes into the inter-wrapper "
      24             :                              "cells in a square lattice subchannel arrangement");
      25         136 :   params.addParam<Real>(
      26         136 :       "power", 0.0, "The power of all the sub-assemblies that the inter-wrapper wraps around[W]");
      27         136 :   params.addParam<std::string>("filename",
      28             :                                "file_was_not_found",
      29             :                                "name of power profile .txt file (should be a single column). It's "
      30             :                                "a Radial Power Profile. [UnitLess]");
      31         136 :   params.addParam<FunctionName>(
      32             :       "axial_heat_rate",
      33             :       "1.0",
      34             :       "user provided normalized function of axial heat rate [Unitless]. "
      35             :       "The integral over pin heated length should equal the heated length."
      36             :       "Zero is considered the inlet of the heated length.");
      37          68 :   return params;
      38           0 : }
      39             : 
      40          35 : QuadInterWrapperPowerIC::QuadInterWrapperPowerIC(const InputParameters & params)
      41             :   : QuadInterWrapperBaseIC(params),
      42          35 :     _power(getParam<Real>("power")),
      43          35 :     _numberoflines(0),
      44         105 :     _filename(getParam<std::string>("filename")),
      45          70 :     _axial_heat_rate(getFunction("axial_heat_rate"))
      46             : {
      47          35 :   auto nx = _mesh.getNx();
      48          35 :   auto ny = _mesh.getNy();
      49          35 :   auto heated_length = _mesh.getHeatedLength();
      50             : 
      51          35 :   _power_dis.resize((ny - 1) * (nx - 1), 1);
      52          35 :   _power_dis.setZero();
      53          35 :   _assembly_power_correction.resize((ny - 1) * (nx - 1), 1);
      54          35 :   _assembly_power_correction.setOnes();
      55             :   Real vin;
      56          35 :   ifstream inFile;
      57             : 
      58          35 :   _console << "Power file: " << _filename << std::endl;
      59             : 
      60          35 :   if (_filename.compare("file_was_not_found"))
      61             :   {
      62           0 :     inFile.open(_filename);
      63           0 :     if (!inFile)
      64           0 :       mooseError(name(), "unable to open file : ", _filename);
      65             : 
      66           0 :     while (inFile >> vin)
      67           0 :       _numberoflines += 1;
      68             : 
      69           0 :     if (inFile.fail() && !inFile.eof())
      70           0 :       mooseError(name(), " non numerical input at line : ", _numberoflines);
      71             : 
      72           0 :     if (_numberoflines != (ny - 1) * (nx - 1))
      73           0 :       mooseError(name(), " Radial profile file doesn't have correct size : ", (ny - 1) * (nx - 1));
      74           0 :     inFile.close();
      75             :   }
      76             :   else
      77             :   {
      78          35 :     _numberoflines = (ny - 1) * (nx - 1);
      79             :   }
      80             : 
      81          35 :   if (_filename.compare("file_was_not_found"))
      82             :   {
      83           0 :     inFile.open(_filename);
      84             :     int i(0);
      85           0 :     while (inFile >> vin)
      86             :     {
      87           0 :       _power_dis(i, 0) = vin;
      88           0 :       i++;
      89             :     }
      90           0 :     inFile.close();
      91             :   }
      92             : 
      93          35 :   _console << " Power distribution matrix :\n" << _power_dis << " \n";
      94          35 :   auto sum = _power_dis.sum();
      95             :   // full (100%) power of one pin [W]
      96          35 :   auto fpin_power = _power / sum;
      97             :   // actual pin power [W]
      98          35 :   _ref_power = _power_dis * fpin_power;
      99             :   // Convert the actual pin power to a linear heat rate [W/m]
     100          35 :   _ref_qprime = _ref_power / heated_length;
     101          35 : }
     102             : 
     103             : void
     104          24 : QuadInterWrapperPowerIC::initialSetup()
     105             : {
     106             : 
     107          24 :   auto nx = _mesh.getNx();
     108          24 :   auto ny = _mesh.getNy();
     109          24 :   auto nz = _mesh.getNumOfAxialCells();
     110          24 :   auto z_grid = _mesh.getZGrid();
     111          24 :   auto heated_length = _mesh.getHeatedLength();
     112          24 :   auto unheated_length_entry = _mesh.getHeatedLengthEntry();
     113             : 
     114          24 :   _estimate_power.resize((ny - 1) * (nx - 1), 1);
     115          24 :   _estimate_power.setZero();
     116         264 :   for (unsigned int iz = 1; iz < nz + 1; iz++)
     117             :   {
     118             :     // Compute the height of this element.
     119         240 :     auto dz = z_grid[iz] - z_grid[iz - 1];
     120             :     // Compute axial location of nodes.
     121             :     auto z2 = z_grid[iz];
     122             :     auto z1 = z_grid[iz - 1];
     123         240 :     Point p1(0, 0, z1 - unheated_length_entry);
     124         240 :     Point p2(0, 0, z2 - unheated_length_entry);
     125             :     // cycle through pins to estimate the total power of each pin
     126         240 :     if (z2 > unheated_length_entry && z2 <= unheated_length_entry + heated_length)
     127             :     {
     128        6240 :       for (unsigned int i_pin = 0; i_pin < (ny - 1) * (nx - 1); i_pin++)
     129             :       {
     130             :         // use of trapezoidal rule to add to total power of pin
     131        6000 :         _estimate_power(i_pin) +=
     132        6000 :             _ref_qprime(i_pin) * (_axial_heat_rate.value(_t, p1) + _axial_heat_rate.value(_t, p2)) *
     133        6000 :             dz / 2.0;
     134             :       }
     135             :     }
     136             :   }
     137             : 
     138             :   // if a Pin has zero power (_ref_qprime(j, i) = 0) then I need to avoid dividing by zero. I
     139             :   // divide by a wrong non-zero number which is not correct but this error doesn't mess things cause
     140             :   // _ref_qprime(j, i) = 0.0
     141         624 :   for (unsigned int i_pin = 0; i_pin < (ny - 1) * (nx - 1); i_pin++)
     142             :   {
     143         600 :     if (_estimate_power(i_pin) == 0.0)
     144           0 :       _estimate_power(i_pin) = 1.0;
     145             :   }
     146          24 :   _assembly_power_correction = _ref_power.cwiseQuotient(_estimate_power);
     147          24 : }
     148             : 
     149             : Real
     150       17280 : QuadInterWrapperPowerIC::value(const Point & p)
     151             : {
     152       17280 :   auto heated_length = _mesh.getHeatedLength();
     153       17280 :   auto unheated_length_entry = _mesh.getHeatedLengthEntry();
     154             :   Point p1(0, 0, unheated_length_entry);
     155             :   Point P = p - p1;
     156       17280 :   auto pin_mesh_exist = _mesh.pinMeshExist();
     157             : 
     158       17280 :   if (pin_mesh_exist)
     159             :   {
     160             :     // project axial heat rate on pins
     161           0 :     auto i_pin = _mesh.getPinIndexFromPoint(p);
     162             :     {
     163           0 :       if (p(2) >= unheated_length_entry && p(2) <= unheated_length_entry + heated_length)
     164           0 :         return _ref_qprime(i_pin) * _assembly_power_correction(i_pin) *
     165           0 :                _axial_heat_rate.value(_t, P);
     166             :       else
     167             :         return 0.0;
     168             :     }
     169             :   }
     170             :   else
     171             :   {
     172             :     // project axial heat rate on subchannels
     173       17280 :     auto i_ch = _mesh.getSubchannelIndexFromPoint(p);
     174             :     // if we are adjacent to the heated part of the fuel Pin
     175       17280 :     if (p(2) >= unheated_length_entry && p(2) <= unheated_length_entry + heated_length)
     176             :     {
     177             :       auto heat_rate = 0.0;
     178       65280 :       for (auto i_pin : _mesh.getChannelPins(i_ch))
     179             :       {
     180       48000 :         heat_rate += 0.25 * _ref_qprime(i_pin) * _assembly_power_correction(i_pin) *
     181       48000 :                      _axial_heat_rate.value(_t, P);
     182             :       }
     183       17280 :       return heat_rate;
     184             :     }
     185             :     else
     186             :       return 0.0;
     187             :   }
     188             : }

Generated by: LCOV version 1.14