https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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 "Receiver.h"
13#include "TriSubChannelMesh.h"
14
16
19{
22 "Computes axial power rate (W/m) assigned to the fuel pins in a triangular lattice "
23 "arrangement");
24 params.addRequiredParam<PostprocessorName>(
25 "power", "The postprocessor or Real to use for the total power of the subassembly [W]");
26 params.addRequiredParam<std::string>(
27 "filename", "name of radial power profile .txt file (should be a single column) [UnitLess].");
28 params.addParam<FunctionName>(
29 "axial_heat_rate",
30 "1.0",
31 "Axial shape of the heat rate as a function of the distance from the start of the "
32 "heated section [Unitless]. Its magnitude does not matter because each pin is "
33 "rescaled to its assigned power");
34 return params;
35}
36
38 : TriSubChannelBaseIC(params),
39 _power(getPostprocessorValue("power")),
40 _numberoflines(0),
41 _filename(getParam<std::string>("filename")),
42 _axial_heat_rate(getFunction("axial_heat_rate"))
43{
44 if (processor_id() > 0)
45 return;
46
47 if (!_mesh.pinMeshExist())
48 mooseError(name(), ": This object requires a pin mesh.");
49
50 auto n_pins = _mesh.getNumOfPins();
51
52 _power_dis.resize(n_pins, 1);
53 _power_dis.setZero();
54 _pin_power_correction.resize(n_pins, 1);
55 _pin_power_correction.setOnes();
56
57 Real vin;
58 std::ifstream inFile;
59
60 inFile.open(_filename);
61 if (!inFile)
62 mooseError(name(), ": Unable to open file: ", _filename);
63
64 while (inFile >> vin)
65 _numberoflines += 1;
66
67 if (inFile.fail() && !inFile.eof())
68 mooseError(name(), ": Non numerical input at line: ", _numberoflines);
69
70 if (_numberoflines != n_pins)
71 mooseError(name(), ": Radial profile file doesn't have correct size: ", n_pins);
72 inFile.close();
73
74 inFile.open(_filename);
75 int i = 0;
76 while (inFile >> vin)
77 {
78 _power_dis(i, 0) = vin;
79 i++;
80 }
81 inFile.close();
82}
83
84void
86{
87 // A power postprocessor executes before initial conditions only if it executes on INITIAL;
88 // otherwise it still holds its default of zero here. A Receiver is set by a transfer instead,
89 // so its execute_on does not control its value.
90 if (!isDefaultPostprocessorValue("power") &&
91 !dynamic_cast<const Receiver *>(&getUserObjectBase("power")) &&
92 !getUserObjectBase("power").getExecuteOnEnum().isValueSet(EXEC_INITIAL))
93 paramError("power",
94 "The 'execute_on' parameter of the power postprocessor must include 'initial'");
95
96 if (processor_id() > 0)
97 return;
98 auto n_pins = _mesh.getNumOfPins();
99 auto nz = _mesh.getNumOfAxialCells();
100 auto z_grid = _mesh.getZGrid();
101 auto heated_length = _mesh.getHeatedLength();
102 auto unheated_length_entry = _mesh.getHeatedLengthEntry();
103
104 // The power postprocessor executes on INITIAL before initial conditions are set up, so its
105 // value is only available here, not in the constructor
106 auto sum = _power_dis.sum();
107 // full (100%) power of one pin [W]
108 auto fpin_power = _power / sum;
109 // actual pin power [W]
110 _ref_power = _power_dis * fpin_power;
111 // Convert the actual pin power to a linear heat rate [W/m]
112 _ref_qprime = _ref_power / heated_length;
113
114 _estimate_power.resize(n_pins, 1);
115 _estimate_power.setZero();
116 for (unsigned int iz = 1; iz < nz + 1; iz++)
117 {
118 // Compute axial location of nodes.
119 auto z2 = z_grid[iz];
120 auto z1 = z_grid[iz - 1];
121 if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
122 MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
123 {
124 // cycle through pins
125 for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
126 {
127 // Evaluate the axial shape at this pin's nodes, where value() assigns q_prime and the
128 // solver integrates it, so the correction also holds for shapes that vary between pins
129 const Point shift(0, 0, unheated_length_entry);
130 auto heat1 = _axial_heat_rate.value(_t, Point(*_mesh.getPinNode(i_pin, iz - 1) - shift));
131 auto heat2 = _axial_heat_rate.value(_t, Point(*_mesh.getPinNode(i_pin, iz) - shift));
132
133 // Compute the height of this element.
134 auto dz = z2 - z1;
135
136 // calculation of power for the first heated segment if nodes don't align
137 if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
138 MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry))
139 {
140 heat1 = 0.0;
141 }
142
143 // calculation of power for the last heated segment if nodes don't align
144 if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry + heated_length) &&
145 MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
146 {
147 heat2 = 0.0;
148 }
149 _estimate_power(i_pin) += _ref_qprime(i_pin) * (heat1 + heat2) * dz / 2.0;
150 }
151 }
152 }
153
154 // if a Pin has zero power (_ref_qprime(i_pin) = 0) then I need to avoid dividing by zero. I
155 // divide by a wrong non-zero number which is not correct but this error doesn't mess things cause
156 // _ref_qprime(i_pin) = 0.0
157 auto total_power = 0.0;
158 for (unsigned int i_pin = 0; i_pin < n_pins; i_pin++)
159 {
160 total_power += _estimate_power(i_pin);
161 if (_estimate_power(i_pin) == 0.0)
162 _estimate_power(i_pin) = 1.0;
163 }
164 // We need to correct the linear power assigned to the nodes of each pin
165 // so that the total power calculated by the trapezoidal rule agrees with the power assigned by
166 // the user.
168 _console << "###########################################" << std::endl;
169 _console << "Total power estimation by IC kernel before correction: " << total_power << " [W] "
170 << std::endl;
171 _console << "IC Power correction vector :\n" << _pin_power_correction << " \n";
172}
173
174Real
176{
177 auto heated_length = _mesh.getHeatedLength();
178 auto unheated_length_entry = _mesh.getHeatedLengthEntry();
179 Point p1(0, 0, unheated_length_entry);
180 Point P = p - p1;
181
183 if (MooseUtils::absoluteFuzzyGreaterEqual(p(2), unheated_length_entry) &&
184 MooseUtils::absoluteFuzzyLessEqual(p(2), unheated_length_entry + heated_length))
185 {
186 auto i_pin = _mesh.getPinIndexFromPoint(p);
187 return _ref_qprime(i_pin) * _pin_power_correction(i_pin) * _axial_heat_rate.value(_t, P);
188 }
189 else
190 return 0.0;
191}
const Real p
const ExecFlagType EXEC_INITIAL
registerMooseObject("SubChannelApp", SCMTriPowerIC)
const ConsoleStream _console
virtual Real value(Real t, const Point &p) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
bool isDefaultPostprocessorValue(const std::string &param_name, const unsigned int index=0) const
Sets the axial heat rate for each pin according to a radial power distribution and a user defined axi...
static InputParameters validParams()
virtual void initialSetup() override
const Function & _axial_heat_rate
Eigen::MatrixXd _ref_power
Actual pin power [W].
SCMTriPowerIC(const InputParameters &params)
Eigen::MatrixXd _power_dis
matrix that holds the values of the relative pin power
std::string _filename
The name of the radial power profile file.
const PostprocessorValue & _power
The total power of the assembly.
Eigen::MatrixXd _pin_power_correction
The correction that will be applied to the estimated calculation [unitless].
Real value(const Point &p) override
Eigen::MatrixXd _estimate_power
Matrix which will hold the total estimated power of each pin [W].
Eigen::MatrixXd _ref_qprime
Average linear heat rate over the whole pin [W/m].
unsigned int _numberoflines
The number of lines associated with the radial power profile .txt file.
virtual const Real & getHeatedLength() const
Return heated length.
virtual const Real & getHeatedLengthEntry() const
Return unheated length at entry.
virtual const std::vector< Real > & getZGrid() const
Get axial location of layers.
bool pinMeshExist() const
Return if Pin Mesh exists or not.
virtual unsigned int getNumOfAxialCells() const
Return the number of axial cells.
An abstract class for ICs for hexagonal fuel assemblies.
static InputParameters validParams()
const TriSubChannelMesh & _mesh
unsigned int getNumOfPins() const override
Return the number of pins.
unsigned int getPinIndexFromPoint(const Point &p) const override
Return a pin index for a given physical point p
Node * getPinNode(unsigned int i_pin, unsigned int iz) const override
Get the pin mesh node for a given pin index and elevation index.
const UserObjectBase & getUserObjectBase(const std::string &param_name, bool is_dependency=true) const
processor_id_type processor_id() const