https://mooseframework.inl.gov
SCMTriPowerIC.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 "SCMTriPowerIC.h"
11 #include "Function.h"
12 #include "TriSubChannelMesh.h"
13 
14 registerMooseObject("SubChannelApp", SCMTriPowerIC);
15 
18 {
20  params.addClassDescription(
21  "Computes axial power rate (W/m) that goes into the subchannel cells "
22  "or is assigned to the fuel pins, in a triangular lattice arrangement");
23  params.addRequiredParam<PostprocessorName>(
24  "power", "The postprocessor or Real to use for the total power of the subassembly [W]");
25  params.addRequiredParam<std::string>(
26  "filename", "name of radial power profile .txt file (should be a single column) [UnitLess].");
27  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  return params;
32 }
33 
35  : TriSubChannelBaseIC(params),
36  _power(getPostprocessorValue("power")),
37  _numberoflines(0),
38  _filename(getParam<std::string>("filename")),
39  _axial_heat_rate(getFunction("axial_heat_rate"))
40 {
41  if (processor_id() > 0)
42  return;
43 
44  auto n_pins = _mesh.getNumOfPins();
45  auto heated_length = _mesh.getHeatedLength();
46 
47  _power_dis.resize(n_pins, 1);
48  _power_dis.setZero();
49  _pin_power_correction.resize(n_pins, 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 != n_pins)
66  mooseError(name(), ": Radial profile file doesn't have correct size: ", n_pins);
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 
78  auto sum = _power_dis.sum();
79  // full (100%) power of one pin [W]
80  auto fpin_power = _power / sum;
81  // actual pin power [W]
82  _ref_power = _power_dis * fpin_power;
83  // Convert the actual pin power to a linear heat rate [W/m]
84  _ref_qprime = _ref_power / heated_length;
85 }
86 
87 void
89 {
90  if (processor_id() > 0)
91  return;
92  auto n_pins = _mesh.getNumOfPins();
93  auto nz = _mesh.getNumOfAxialCells();
94  auto z_grid = _mesh.getZGrid();
95  auto heated_length = _mesh.getHeatedLength();
96  auto unheated_length_entry = _mesh.getHeatedLengthEntry();
97 
98  _estimate_power.resize(n_pins, 1);
99  _estimate_power.setZero();
100  for (unsigned int iz = 1; iz < nz + 1; iz++)
101  {
102  // Compute axial location of nodes.
103  auto z2 = z_grid[iz];
104  auto z1 = z_grid[iz - 1];
105  Point p1(0, 0, z1 - unheated_length_entry);
106  Point p2(0, 0, z2 - unheated_length_entry);
107  auto heat1 = _axial_heat_rate.value(_t, p1);
108  auto heat2 = _axial_heat_rate.value(_t, p2);
109  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
110  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
111  {
112  // cycle through pins
113  for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
114  {
115  // Compute the height of this element.
116  auto dz = z2 - z1;
117 
118  // calculation of power for the first heated segment if nodes don't align
119  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
120  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry))
121  {
122  heat1 = 0.0;
123  }
124 
125  // calculation of power for the last heated segment if nodes don't align
126  if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry + heated_length) &&
127  MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
128  {
129  heat2 = 0.0;
130  }
131  _estimate_power(i_pin) += _ref_qprime(i_pin) * (heat1 + heat2) * dz / 2.0;
132  }
133  }
134  }
135 
136  // if a Pin has zero power (_ref_qprime(i_pin) = 0) then I need to avoid dividing by zero. I
137  // divide by a wrong non-zero number which is not correct but this error doesn't mess things cause
138  // _ref_qprime(i_pin) = 0.0
139  auto total_power = 0.0;
140  for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
141  {
142  total_power += _estimate_power(i_pin);
143  if (_estimate_power(i_pin) == 0.0)
144  _estimate_power(i_pin) = 1.0;
145  }
146  // We need to correct the linear power assigned to the nodes of each pin
147  // so that the total power calculated by the trapezoidal rule agrees with the power assigned by
148  // the user.
150  _console << "###########################################" << std::endl;
151  _console << "Total power estimation by IC kernel before correction: " << total_power << " [W] "
152  << std::endl;
153  _console << "IC Power correction vector :\n" << _pin_power_correction << " \n";
154 }
155 
156 Real
157 SCMTriPowerIC::value(const Point & p)
158 {
159  auto heat_rate = 0.0;
160  auto heated_length = _mesh.getHeatedLength();
161  auto unheated_length_entry = _mesh.getHeatedLengthEntry();
162  Point p1(0, 0, unheated_length_entry);
163  Point P = p - p1;
164  auto pin_mesh_exist = _mesh.pinMeshExist();
165 
167  if (MooseUtils::absoluteFuzzyGreaterEqual(p(2), unheated_length_entry) &&
168  MooseUtils::absoluteFuzzyLessEqual(p(2), unheated_length_entry + heated_length))
169  {
170  if (pin_mesh_exist)
171  {
172  // project axial heat rate on pins
173  auto i_pin = _mesh.getPinIndexFromPoint(p);
174  return _ref_qprime(i_pin) * _pin_power_correction(i_pin) * _axial_heat_rate.value(_t, P);
175  }
176  else
177  {
178  // Determine which subchannel this point is in.
179  auto i_ch = _mesh.getSubchannelIndexFromPoint(p);
180  auto subch_type = _mesh.getSubchannelType(i_ch);
181  // project axial heat rate on subchannels
182  {
183  double factor;
184  switch (subch_type)
185  {
187  factor = 1.0 / 6.0;
188  break;
189  case EChannelType::EDGE:
190  factor = 1.0 / 4.0;
191  break;
193  factor = 1.0 / 6.0;
194  break;
195  default:
196  return 0.0; // handle invalid subch_type if needed
197  }
198  for (auto i_pin : _mesh.getChannelPins(i_ch))
199  {
200  heat_rate += factor * _ref_qprime(i_pin) * _pin_power_correction(i_pin) *
202  }
203  return heat_rate;
204  }
205  }
206  }
207  else
208  return 0.0;
209 }
unsigned int _numberoflines
The number of lines associated with the radial power profile .txt file.
Definition: SCMTriPowerIC.h:32
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
registerMooseObject("SubChannelApp", SCMTriPowerIC)
virtual const std::vector< Real > & getZGrid() const
Get axial location of layers.
unsigned int getSubchannelIndexFromPoint(const Point &p) const override
Return a subchannel index for a given physical point p
Eigen::MatrixXd _ref_qprime
Average linear heat rate over the whole pin [W/m].
Definition: SCMTriPowerIC.h:39
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual void initialSetup() override
Definition: SCMTriPowerIC.C:88
Eigen::MatrixXd _estimate_power
Matrix which will hold the total estimated power of each pin [W].
Definition: SCMTriPowerIC.h:45
An abstract class for ICs for hexagonal fuel assemblies.
const std::string & name() const
Eigen::MatrixXd _pin_power_correction
The correction that will be applied to the estimated calculation [unitless].
Definition: SCMTriPowerIC.h:43
SCMTriPowerIC(const InputParameters &params)
Definition: SCMTriPowerIC.C:34
virtual const Real & getHeatedLength() const
Return heated length.
const std::vector< unsigned int > & getChannelPins(unsigned int i_chan) const override
Return a vector of pin indices for a given channel index.
const PostprocessorValue & _power
The total power of the assembly.
Definition: SCMTriPowerIC.h:30
bool pinMeshExist() const
Return if Pin Mesh exists or not.
unsigned int getPinIndexFromPoint(const Point &p) const override
Return a pin index for a given physical point p
const Function & _axial_heat_rate
Definition: SCMTriPowerIC.h:37
Real value(const Point &p) override
virtual unsigned int getNumOfAxialCells() const
Return the number of axial cells.
Eigen::MatrixXd _power_dis
matrix that holds the values of the relative pin power
Definition: SCMTriPowerIC.h:36
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real p
const TriSubChannelMesh & _mesh
void mooseError(Args &&... args) const
static InputParameters validParams()
void addClassDescription(const std::string &doc_string)
const ConsoleStream _console
std::string _filename
The name of the radial power profile file.
Definition: SCMTriPowerIC.h:34
EChannelType getSubchannelType(unsigned int index) const override
Return the type of the subchannel for given subchannel index.
virtual Real value(Real t, const Point &p) const
static InputParameters validParams()
Definition: SCMTriPowerIC.C:17
processor_id_type processor_id() const
unsigned int getNumOfPins() const override
Return the number of pins.
Sets the axial heat rate for each pin according to a radial power distribution and a user defined axi...
Definition: SCMTriPowerIC.h:20
virtual const Real & getHeatedLengthEntry() const
Return unheated length at entry.
Eigen::MatrixXd _ref_power
Actual pin power [W].
Definition: SCMTriPowerIC.h:41