LCOV - code coverage report
Current view: top level - src/ics - SCMTriPowerIC.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #33187 (5aa0b2) with base d7c4bd Lines: 81 86 94.2 %
Date: 2026-06-30 12:24:57 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 "SCMTriPowerIC.h"
      11             : #include "Function.h"
      12             : #include "TriSubChannelMesh.h"
      13             : 
      14             : registerMooseObject("SubChannelApp", SCMTriPowerIC);
      15             : 
      16             : InputParameters
      17         277 : SCMTriPowerIC::validParams()
      18             : {
      19         277 :   InputParameters params = TriSubChannelBaseIC::validParams();
      20         277 :   params.addClassDescription(
      21             :       "Computes axial power rate (W/m) assigned to the fuel pins in a triangular lattice "
      22             :       "arrangement");
      23         554 :   params.addRequiredParam<PostprocessorName>(
      24             :       "power", "The postprocessor or Real to use for the total power of the subassembly [W]");
      25         554 :   params.addRequiredParam<std::string>(
      26             :       "filename", "name of radial power profile .txt file (should be a single column) [UnitLess].");
      27         554 :   params.addParam<FunctionName>("axial_heat_rate",
      28             :                                 "1.0",
      29             :                                 "user provided normalized function of axial heat rate [Unitless]. "
      30             :                                 "The integral over pin length should equal the heated length");
      31         277 :   return params;
      32           0 : }
      33             : 
      34         148 : SCMTriPowerIC::SCMTriPowerIC(const InputParameters & params)
      35             :   : TriSubChannelBaseIC(params),
      36         148 :     _power(getPostprocessorValue("power")),
      37         148 :     _numberoflines(0),
      38         444 :     _filename(getParam<std::string>("filename")),
      39         296 :     _axial_heat_rate(getFunction("axial_heat_rate"))
      40             : {
      41         148 :   if (processor_id() > 0)
      42          28 :     return;
      43             : 
      44         120 :   if (!_mesh.pinMeshExist())
      45           0 :     mooseError(name(), ": This object requires a pin mesh.");
      46             : 
      47         120 :   auto n_pins = _mesh.getNumOfPins();
      48         120 :   auto heated_length = _mesh.getHeatedLength();
      49             : 
      50         120 :   _power_dis.resize(n_pins, 1);
      51         120 :   _power_dis.setZero();
      52         120 :   _pin_power_correction.resize(n_pins, 1);
      53         120 :   _pin_power_correction.setOnes();
      54             : 
      55             :   Real vin;
      56         120 :   std::ifstream inFile;
      57             : 
      58         120 :   inFile.open(_filename);
      59         120 :   if (!inFile)
      60           0 :     mooseError(name(), ": Unable to open file: ", _filename);
      61             : 
      62        5556 :   while (inFile >> vin)
      63        5436 :     _numberoflines += 1;
      64             : 
      65         120 :   if (inFile.fail() && !inFile.eof())
      66           0 :     mooseError(name(), ": Non numerical input at line: ", _numberoflines);
      67             : 
      68         120 :   if (_numberoflines != n_pins)
      69           0 :     mooseError(name(), ": Radial profile file doesn't have correct size: ", n_pins);
      70         120 :   inFile.close();
      71             : 
      72         120 :   inFile.open(_filename);
      73             :   int i = 0;
      74        5556 :   while (inFile >> vin)
      75             :   {
      76        5436 :     _power_dis(i, 0) = vin;
      77        5436 :     i++;
      78             :   }
      79         120 :   inFile.close();
      80             : 
      81         120 :   auto sum = _power_dis.sum();
      82             :   // full (100%) power of one pin [W]
      83         120 :   auto fpin_power = _power / sum;
      84             :   // actual pin power [W]
      85         120 :   _ref_power = _power_dis * fpin_power;
      86             :   // Convert the actual pin power to a linear heat rate [W/m]
      87         120 :   _ref_qprime = _ref_power / heated_length;
      88         120 : }
      89             : 
      90             : void
      91         148 : SCMTriPowerIC::initialSetup()
      92             : {
      93         148 :   if (processor_id() > 0)
      94          28 :     return;
      95         120 :   auto n_pins = _mesh.getNumOfPins();
      96         120 :   auto nz = _mesh.getNumOfAxialCells();
      97         120 :   auto z_grid = _mesh.getZGrid();
      98         120 :   auto heated_length = _mesh.getHeatedLength();
      99         120 :   auto unheated_length_entry = _mesh.getHeatedLengthEntry();
     100             : 
     101         120 :   _estimate_power.resize(n_pins, 1);
     102         120 :   _estimate_power.setZero();
     103        3172 :   for (unsigned int iz = 1; iz < nz + 1; iz++)
     104             :   {
     105             :     // Compute axial location of nodes.
     106        3052 :     auto z2 = z_grid[iz];
     107        3052 :     auto z1 = z_grid[iz - 1];
     108        3052 :     Point p1(0, 0, z1 - unheated_length_entry);
     109        3052 :     Point p2(0, 0, z2 - unheated_length_entry);
     110        3052 :     auto heat1 = _axial_heat_rate.value(_t, p1);
     111        3052 :     auto heat2 = _axial_heat_rate.value(_t, p2);
     112        3052 :     if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
     113        2616 :         MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
     114             :     {
     115             :       // cycle through pins
     116       75888 :       for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
     117             :       {
     118             :         // Compute the height of this element.
     119       74010 :         auto dz = z2 - z1;
     120             : 
     121             :         // calculation of power for the first heated segment if nodes don't align
     122       74010 :         if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
     123             :             MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry))
     124             :         {
     125             :           heat1 = 0.0;
     126             :         }
     127             : 
     128             :         // calculation of power for the last heated segment if nodes don't align
     129       74010 :         if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry + heated_length) &&
     130             :             MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
     131             :         {
     132             :           heat2 = 0.0;
     133             :         }
     134       74010 :         _estimate_power(i_pin) += _ref_qprime(i_pin) * (heat1 + heat2) * dz / 2.0;
     135             :       }
     136             :     }
     137             :   }
     138             : 
     139             :   // if a Pin has zero power (_ref_qprime(i_pin) = 0) then I need to avoid dividing by zero. I
     140             :   // divide by a wrong non-zero number which is not correct but this error doesn't mess things cause
     141             :   // _ref_qprime(i_pin) = 0.0
     142         120 :   auto total_power = 0.0;
     143        5556 :   for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
     144             :   {
     145        5436 :     total_power += _estimate_power(i_pin);
     146        5436 :     if (_estimate_power(i_pin) == 0.0)
     147         172 :       _estimate_power(i_pin) = 1.0;
     148             :   }
     149             :   // We need to correct the linear power assigned to the nodes of each pin
     150             :   // so that the total power calculated  by the trapezoidal rule agrees with the power assigned by
     151             :   // the user.
     152         120 :   _pin_power_correction = _ref_power.cwiseQuotient(_estimate_power);
     153         120 :   _console << "###########################################" << std::endl;
     154         120 :   _console << "Total power estimation by IC kernel before correction: " << total_power << " [W] "
     155         120 :            << std::endl;
     156         120 :   _console << "IC Power correction vector :\n" << _pin_power_correction << " \n";
     157         120 : }
     158             : 
     159             : Real
     160      195260 : SCMTriPowerIC::value(const Point & p)
     161             : {
     162      195260 :   auto heated_length = _mesh.getHeatedLength();
     163      195260 :   auto unheated_length_entry = _mesh.getHeatedLengthEntry();
     164             :   Point p1(0, 0, unheated_length_entry);
     165             :   Point P = p - p1;
     166             : 
     167             :   /// assign power to the nodes located inside the heated section
     168      195260 :   if (MooseUtils::absoluteFuzzyGreaterEqual(p(2), unheated_length_entry) &&
     169      179986 :       MooseUtils::absoluteFuzzyLessEqual(p(2), unheated_length_entry + heated_length))
     170             :   {
     171      122479 :     auto i_pin = _mesh.getPinIndexFromPoint(p);
     172      122479 :     return _ref_qprime(i_pin) * _pin_power_correction(i_pin) * _axial_heat_rate.value(_t, P);
     173             :   }
     174             :   else
     175             :     return 0.0;
     176             : }

Generated by: LCOV version 1.14