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