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