https://mooseframework.inl.gov
SCMQuadPowerAux.C
Go to the documentation of this file.
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 "SCMQuadPowerAux.h"
11 #include "Function.h"
12 #include "QuadSubChannelMesh.h"
13 #include "SCM.h"
14 
15 registerMooseObject("SubChannelApp", SCMQuadPowerAux);
16 registerMooseObjectRenamed("SubChannelApp", QuadPowerAux, "06/30/2025 24:00", SCMQuadPowerAux);
17 
20 {
22  params.addClassDescription(
23  "Computes axial power rate (W/m) that goes into the subchannel cells "
24  "or is assigned to the fuel pins, in a quadrilateral lattice arrangement");
25  params.addRequiredParam<PostprocessorName>(
26  "power", "The postprocessor or Real to use for the total power of the subassembly [W]");
27  params.addRequiredParam<std::string>(
28  "filename", "name of radial power profile .txt file (should be a single column) [UnitLess].");
29  params.addParam<FunctionName>("axial_heat_rate",
30  "1.0",
31  "user provided normalized function of axial heat rate [Unitless]. "
32  "The integral over pin length should equal the heated length");
33  return params;
34 }
35 
37  : AuxKernel(parameters),
38  _quadMesh(SCM::getConstMesh<QuadSubChannelMesh>(_mesh)),
39  _power(getPostprocessorValue("power")),
40  _numberoflines(0),
41  _filename(getParam<std::string>("filename")),
42  _axial_heat_rate(getFunction("axial_heat_rate"))
43 {
44  auto nx = _quadMesh.getNx();
45  auto ny = _quadMesh.getNy();
46  // Matrix sizing
47  _power_dis.resize((ny - 1) * (nx - 1), 1);
48  _power_dis.setZero();
49  _pin_power_correction.resize((ny - 1) * (nx - 1), 1);
50  _pin_power_correction.setOnes();
51 
52  Real vin;
53  std::ifstream inFile;
54 
55  inFile.open(_filename);
56  if (!inFile)
57  mooseError(name(), "unable to open file : ", _filename);
58 
59  while (inFile >> vin)
60  _numberoflines += 1;
61 
62  if (inFile.fail() && !inFile.eof())
63  mooseError(name(), " non numerical input at line : ", _numberoflines);
64 
65  if (_numberoflines != (ny - 1) * (nx - 1))
66  mooseError(name(), " Radial profile file doesn't have correct size : ", (ny - 1) * (nx - 1));
67  inFile.close();
68 
69  inFile.open(_filename);
70  int i(0);
71  while (inFile >> vin)
72  {
73  _power_dis(i, 0) = vin;
74  i++;
75  }
76  inFile.close();
77  _console << " Power distribution matrix :\n" << _power_dis << " \n";
78 }
79 
80 void
82 {
83  auto nx = _quadMesh.getNx();
84  auto ny = _quadMesh.getNy();
85  auto n_pins = (nx - 1) * (ny - 1);
86  auto nz = _quadMesh.getNumOfAxialCells();
87  auto z_grid = _quadMesh.getZGrid();
88  auto heated_length = _quadMesh.getHeatedLength();
89  auto unheated_length_entry = _quadMesh.getHeatedLengthEntry();
90  auto sum = _power_dis.sum();
91 
92  // full (100%) power of one pin [W]
93  auto fpin_power = _power / sum;
94  // actual pin power [W]
95  _ref_power = _power_dis * fpin_power;
96  // Convert the actual pin power to a linear heat rate [W/m]
97  _ref_qprime = _ref_power / heated_length;
98 
99  _estimate_power.resize(n_pins, 1);
100  _estimate_power.setZero();
101  for (unsigned int iz = 1; iz < nz + 1; iz++)
102  {
103  // Compute axial location of nodes.
104  auto z2 = z_grid[iz];
105  auto z1 = z_grid[iz - 1];
106  Point p1(0, 0, z1 - unheated_length_entry);
107  Point p2(0, 0, z2 - unheated_length_entry);
108  auto heat1 = _axial_heat_rate.value(_t, p1);
109  auto heat2 = _axial_heat_rate.value(_t, p2);
110  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
111  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
112  {
113  // cycle through pins
114  for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
115  {
116  // Compute the height of this element.
117  auto dz = z2 - z1;
118 
119  // calculation of power for the first heated segment if nodes don't align
120  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
121  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry))
122  {
123  heat1 = 0.0;
124  }
125 
126  // calculation of power for the last heated segment if nodes don't align
127  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry + heated_length) &&
128  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
129  {
130  heat2 = 0.0;
131  }
132 
133  _estimate_power(i_pin) += _ref_qprime(i_pin) * (heat1 + heat2) * dz / 2.0;
134  }
135  }
136  }
137 
138  // if a Pin has zero power (_ref_qprime(i_pin) = 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
140  // cause _ref_qprime(i_pin) = 0.0
141  auto total_power = 0.0;
142  for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
143  {
144  total_power += _estimate_power(i_pin);
145  if (_estimate_power(i_pin) == 0.0)
146  _estimate_power(i_pin) = 1.0;
147  }
148  // We need to correct the linear power assigned to the nodes of each pin
149  // so that the total power calculated by the trapezoidal rule agrees with the power assigned
150  // by the user.
152  _console << "###########################################" << std::endl;
153  _console << "Total power estimation by Aux kernel before correction: " << total_power << " [W] "
154  << std::endl;
155  _console << "Aux Power correction vector :\n" << _pin_power_correction << " \n";
156 }
157 
158 Real
160 {
161  Point p = *_current_node;
162  auto heated_length = _quadMesh.getHeatedLength();
163  auto unheated_length_entry = _quadMesh.getHeatedLengthEntry();
164  Point p1(0, 0, unheated_length_entry);
165  Point P = p - p1;
166  auto pin_mesh_exist = _quadMesh.pinMeshExist();
167 
169  if (MooseUtils::absoluteFuzzyGreaterEqual(p(2), unheated_length_entry) &&
170  MooseUtils::absoluteFuzzyLessEqual(p(2), unheated_length_entry + heated_length))
171  {
172  if (pin_mesh_exist)
173  {
174  // project axial heat rate on pins
175  auto i_pin = _quadMesh.getPinIndexFromPoint(p);
176  return _ref_qprime(i_pin) * _pin_power_correction(i_pin) * _axial_heat_rate.value(_t, P);
177  }
178  else
179  {
180  // project axial heat rate on subchannels
181  auto i_ch = _quadMesh.getSubchannelIndexFromPoint(p);
182  // if we are adjacent to the heated part of the fuel Pin
183  auto heat_rate = 0.0;
184  for (auto i_pin : _quadMesh.getChannelPins(i_ch))
185  {
186  heat_rate += 0.25 * _ref_qprime(i_pin) * _pin_power_correction(i_pin) *
188  }
189  return heat_rate;
190  }
191  }
192  else
193  return 0.0;
194 }
Eigen::MatrixXd _pin_power_correction
The correction that will be applied to the estimated calculation [unitless].
const QuadSubChannelMesh & _quadMesh
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual const std::vector< Real > & getZGrid() const
Get axial location of layers.
Eigen::MatrixXd _estimate_power
Matrix which will hold the total estimated power of each pin [W].
const Node *const & _current_node
static InputParameters validParams()
Creates the mesh of subchannels in a quadrilateral lattice.
Eigen::MatrixXd _ref_power
Actual pin power [W].
Eigen::MatrixXd _ref_qprime
Average linear heat rate over the whole pin [W/m].
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
unsigned int _numberoflines
The number of lines associated with the radial power profile .txt file.
Sets the axial heat rate for each pin according to a radial power distribution and a user defined axi...
unsigned int getSubchannelIndexFromPoint(const Point &p) const override
Return a subchannel index for a given physical point p
virtual const Real & getHeatedLength() const
Return heated length.
virtual bool pinMeshExist() const override
Return if Pin Mesh exists or not.
const T & getConstMesh(const MooseMesh &mesh)
function to cast const mesh
Definition: SCM.h:21
Eigen::MatrixXd _power_dis
matrix that holds the values of the relative pin power
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
const PostprocessorValue & _power
The total power of the assembly.
virtual void initialSetup() override
virtual Real computeValue() override
virtual const unsigned int & getNumOfAxialCells() const
Return the number of axial cells.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const unsigned int & getNy() const
Number of subchannels in the -y direction.
registerMooseObjectRenamed("SubChannelApp", QuadPowerAux, "06/30/2025 24:00", SCMQuadPowerAux)
bool absoluteFuzzyLessEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
std::string _filename
The name of the radial power profile file.
bool absoluteFuzzyGreaterEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
unsigned int getPinIndexFromPoint(const Point &p) const override
Return a pin index for a given physical point p
static InputParameters validParams()
virtual const unsigned int & getNx() const
Number of subchannels in the -x direction.
const ConsoleStream _console
virtual Real value(Real t, const Point &p) const
virtual const std::vector< unsigned int > & getChannelPins(unsigned int i_chan) const override
Return a vector of pin indices for a given channel index.
const Function & _axial_heat_rate
Definition: SCM.h:16
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
virtual const Real & getHeatedLengthEntry() const
Return unheated length at entry.
registerMooseObject("SubChannelApp", SCMQuadPowerAux)
SCMQuadPowerAux(const InputParameters &params)