https://mooseframework.inl.gov
Loading...
Searching...
No Matches
QuadSubChannel1PhaseProblem.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
11#include "AuxiliarySystem.h"
12#include "SCM.h"
14
16
19{
22 "Solver class for subchannels in a square lattice assembly and bare fuel pins");
23 return params;
24}
25
30
31void
33{
35
37 if (_deformation)
38 {
39 _console << " =========== DEFORMATION RECALCULATION ACTIVATED ============== " << std::endl;
40 Real standard_area, additional_area, wetted_perimeter, displaced_area;
41 auto pitch = _subchannel_mesh.getPitch();
42 auto side_gap = _subchannel_mesh.getSideGap();
43 auto z_blockage = _subchannel_mesh.getZBlockage();
44 auto index_blockage = _subchannel_mesh.getIndexBlockage();
45 auto reduction_blockage = _subchannel_mesh.getReductionBlockage();
46 for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
47 {
48 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
49 {
50 auto * node = _subchannel_mesh.getChannelNode(i_ch, iz);
51 auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
52 auto Z = _z_grid[iz];
53 Real rod_area = 0.0;
54 Real rod_perimeter = 0.0;
55 for (auto i_pin : _subchannel_mesh.getChannelPins(i_ch))
56 {
57 auto * pin_node = _subchannel_mesh.getPinNode(i_pin, iz);
58 rod_area += 0.25 * 0.25 * M_PI * (*_Dpin_soln)(pin_node) * (*_Dpin_soln)(pin_node);
59 rod_perimeter += 0.25 * M_PI * (*_Dpin_soln)(pin_node);
60 }
61
62 if (subch_type == EChannelType::CORNER)
63 {
64 standard_area = 0.25 * pitch * pitch;
65 displaced_area = (2 * side_gap + pitch) * (*_displacement_soln)(node) / sqrt(2) +
66 (*_displacement_soln)(node) * (*_displacement_soln)(node) / 2;
67 additional_area = pitch * side_gap + side_gap * side_gap;
68 wetted_perimeter =
69 rod_perimeter + pitch + 2 * side_gap + 2 * (*_displacement_soln)(node) / sqrt(2);
70 }
71 else if (subch_type == EChannelType::EDGE)
72 {
73 standard_area = 0.5 * pitch * pitch;
74 additional_area = pitch * side_gap;
75 displaced_area = pitch * (*_displacement_soln)(node);
76 wetted_perimeter = rod_perimeter + pitch;
77 }
78 else
79 {
80 standard_area = pitch * pitch;
81 displaced_area = 0.0;
82 additional_area = 0.0;
83 wetted_perimeter = rod_perimeter;
84 }
85
87 auto subchannel_area = displaced_area + standard_area + additional_area - rod_area;
88
90 auto overlapping_pin_area = 0.0;
91 auto overlapping_wetted_perimeter = 0.0;
92 for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
93 {
94 auto gap_pins = _subchannel_mesh.getGapPins(i_gap);
95 auto pin_1 = gap_pins.first;
96 auto pin_2 = gap_pins.second;
97 auto * pin_node_1 = _subchannel_mesh.getPinNode(pin_1, iz);
98 auto * pin_node_2 = _subchannel_mesh.getPinNode(pin_2, iz);
99 auto Diameter1 = (*_Dpin_soln)(pin_node_1);
100 auto Radius1 = Diameter1 / 2.0;
101 auto Diameter2 = (*_Dpin_soln)(pin_node_2);
102 auto Radius2 = Diameter2 / 2.0;
103 auto pitch = _subchannel_mesh.getPitch();
104
105 if (pitch < (Radius1 + Radius2)) // overlapping pins
106 {
107 mooseWarning(" The gap of index : '", i_gap, " at axial cell ", iz, " ' is blocked.");
108 auto cos1 =
109 (pitch * pitch + Radius1 * Radius1 - Radius2 * Radius2) / (2 * pitch * Radius1);
110 auto cos2 =
111 (pitch * pitch + Radius2 * Radius2 - Radius1 * Radius1) / (2 * pitch * Radius2);
112 auto angle1 = 2.0 * acos(cos1);
113 auto angle2 = 2.0 * acos(cos2);
114 // half of the intersecting arc-length
115 overlapping_wetted_perimeter += 0.5 * angle1 * Radius1 + 0.5 * angle2 * Radius2;
116 // Half of the overlapping area
117 overlapping_pin_area +=
118 0.5 * Radius1 * Radius1 * acos(cos1) + 0.5 * Radius2 * Radius2 * acos(cos2) -
119 0.25 * sqrt((-pitch + Radius1 + Radius2) * (pitch + Radius1 - Radius2) *
120 (pitch - Radius1 + Radius2) * (pitch + Radius1 + Radius2));
121 }
122 }
123 subchannel_area += overlapping_pin_area; // correct surface area
124 wetted_perimeter += -overlapping_wetted_perimeter; // correct wetted perimeter
125
127 auto index = 0;
128 for (const auto & i_blockage : index_blockage)
129 {
130 if (i_ch == i_blockage && (Z >= z_blockage.front() && Z <= z_blockage.back()))
131 {
132 subchannel_area *= reduction_blockage[index];
133 }
134 index++;
135 }
136
137 _S_flow_soln->set(node, subchannel_area);
138 _w_perim_soln->set(node, wetted_perimeter);
139 }
140 }
142 for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
143 {
144 for (unsigned int i_gap = 0; i_gap < _n_gaps; i_gap++)
145 {
146 auto gap_pins = _subchannel_mesh.getGapPins(i_gap);
147 auto pin_1 = gap_pins.first;
148 auto pin_2 = gap_pins.second;
149 auto * pin_node_1 = _subchannel_mesh.getPinNode(pin_1, iz);
150 auto * pin_node_2 = _subchannel_mesh.getPinNode(pin_2, iz);
151 if (pin_1 == pin_2) // Corner or edge gap
152 {
153 auto displacement = 0.0;
154 auto counter = 0.0;
155 for (auto i_ch : _subchannel_mesh.getPinChannels(pin_1))
156 {
157 auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
158 auto * node = _subchannel_mesh.getChannelNode(i_ch, iz);
159 if (subch_type == EChannelType::EDGE || subch_type == EChannelType::CORNER)
160 {
161 displacement += (*_displacement_soln)(node);
162 counter += 1.0;
163 }
164 }
165 displacement = displacement / counter;
167 iz, i_gap, (pitch - (*_Dpin_soln)(pin_node_1)) / 2.0 + side_gap + displacement);
168 }
169 else // center gap
170 {
172 iz, i_gap, pitch - (*_Dpin_soln)(pin_node_1) / 2.0 - (*_Dpin_soln)(pin_node_2) / 2.0);
173 }
174 // if pins come in contact, the gap is zero
175 if (_subchannel_mesh.getGapWidth(iz, i_gap) <= 0.0)
176 _subchannel_mesh.setGapWidth(iz, i_gap, 0.0);
177 }
178 }
179 }
180
181 for (unsigned int iz = 1; iz < _n_cells + 1; iz++)
182 {
183 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
184 {
185 auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
186 auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
187 _mdot_soln->set(node_out, (*_mdot_soln)(node_in));
188 }
189 }
190
191 // We must do a global assembly to make sure data is parallel consistent before we do things
192 // like compute L2 norms
193 _aux->solution().close();
194}
195
196Real
197QuadSubChannel1PhaseProblem::computeAddedHeatPin(unsigned int i_ch, unsigned int iz) const
198{
199 if (!_pin_mesh_exist)
200 return 0.0;
201
202 // Compute axial location of nodes.
203 auto z2 = _z_grid[iz];
204 auto z1 = _z_grid[iz - 1];
205 auto heated_length = _subchannel_mesh.getHeatedLength();
206 auto unheated_length_entry = _subchannel_mesh.getHeatedLengthEntry();
207 if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
208 MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
209 {
210 // Compute the height of this element.
211 auto dz = z2 - z1;
212 auto heat_rate_in = 0.0;
213 auto heat_rate_out = 0.0;
214 for (auto i_pin : _subchannel_mesh.getChannelPins(i_ch))
215 {
216 auto * node_in = _subchannel_mesh.getPinNode(i_pin, iz - 1);
217 auto * node_out = _subchannel_mesh.getPinNode(i_pin, iz);
218 heat_rate_out += 0.25 * (*_q_prime_soln)(node_out);
219 heat_rate_in += 0.25 * (*_q_prime_soln)(node_in);
220 }
221 return (heat_rate_in + heat_rate_out) * dz / 2.0;
222 }
223 else
224 return 0.0;
225}
226
227Real
229{
230 auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
231 if (subch_type == EChannelType::EDGE || subch_type == EChannelType::CORNER)
232 {
233 auto width = _subchannel_mesh.getPitch();
234 if (subch_type == EChannelType::CORNER)
235 width += 2.0 * _subchannel_mesh.getSideGap();
236 return width;
237 }
238 else
239 mooseError("Channel is not a perimetric subchannel ");
240}
241
242void
244{
245 unsigned int last_node = (iblock + 1) * _block_size;
246 unsigned int first_node = iblock * _block_size + 1;
247 if (iblock == 0)
248 {
249 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
250 {
251 auto * node = _subchannel_mesh.getChannelNode(i_ch, 0);
252 auto h_out = _fp->h_from_p_T((*_P_soln)(node) + _P_out, (*_T_soln)(node));
253 if (h_out < 0)
254 {
256 name(), " : Calculation of negative Enthalpy h_out = : ", h_out, " Axial Level= : ", 0);
257 }
258 _h_soln->set(node, h_out);
259 }
260 }
261
262 if (!_implicit_bool)
263 {
264 for (unsigned int iz = first_node; iz < last_node + 1; iz++)
265 {
266 auto dz = _z_grid[iz] - _z_grid[iz - 1];
267 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
268 {
269 auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
270 auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
271 auto mdot_in = (*_mdot_soln)(node_in);
272 auto h_in = (*_h_soln)(node_in); // J/kg
273 auto volume = dz * (*_S_flow_soln)(node_in);
274 auto mdot_out = (*_mdot_soln)(node_out);
275 auto h_out = 0.0;
276 Real sumWijh = 0.0;
277 Real sumWijPrimeDhij = 0.0;
278 Real added_enthalpy = computeAddedHeatPin(i_ch, iz);
279 // Calculate sum of crossflow into channel i from channels j around i
280 unsigned int counter = 0;
281 for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
282 {
283 auto chans = _subchannel_mesh.getGapChannels(i_gap);
284 unsigned int ii_ch = chans.first;
285 // i is always the smallest and first index in the mapping
286 unsigned int jj_ch = chans.second;
287 auto * node_in_i = _subchannel_mesh.getChannelNode(ii_ch, iz - 1);
288 auto * node_in_j = _subchannel_mesh.getChannelNode(jj_ch, iz - 1);
289 // Define donor enthalpy
290 Real h_star = 0.0;
291 if (_Wij(i_gap, iz) > 0.0)
292 h_star = (*_h_soln)(node_in_i);
293 else if (_Wij(i_gap, iz) < 0.0)
294 h_star = (*_h_soln)(node_in_j);
295 // take care of the sign by applying the map, use donor cell
296 sumWijh += _subchannel_mesh.getCrossflowSign(i_ch, counter) * _Wij(i_gap, iz) * h_star;
297 sumWijPrimeDhij += _WijPrime(i_gap, iz) * (2 * (*_h_soln)(node_in) -
298 (*_h_soln)(node_in_j) - (*_h_soln)(node_in_i));
299 counter++;
300 }
301 h_out = (mdot_in * h_in - sumWijh - sumWijPrimeDhij + added_enthalpy +
302 _TR * _rho_soln->old(node_out) * _h_soln->old(node_out) * volume / _dt) /
303 (mdot_out + _TR * (*_rho_soln)(node_out)*volume / _dt);
304 if (h_out < 0)
305 {
307 " : Calculation of negative Enthalpy h_out = : ",
308 h_out,
309 " Axial Level= : ",
310 iz);
311 }
312 _h_soln->set(node_out, h_out); // J/kg
313 }
314 }
315 }
316 else
317 {
318 LibmeshPetscCall(MatZeroEntries(_hc_time_derivative_mat));
319 LibmeshPetscCall(MatZeroEntries(_hc_advective_derivative_mat));
320 LibmeshPetscCall(MatZeroEntries(_hc_cross_derivative_mat));
321 LibmeshPetscCall(VecZeroEntries(_hc_time_derivative_rhs));
322 LibmeshPetscCall(VecZeroEntries(_hc_advective_derivative_rhs));
323 LibmeshPetscCall(VecZeroEntries(_hc_cross_derivative_rhs));
324 LibmeshPetscCall(VecZeroEntries(_hc_added_heat_rhs));
325 LibmeshPetscCall(MatZeroEntries(_hc_sys_h_mat));
326 LibmeshPetscCall(VecZeroEntries(_hc_sys_h_rhs));
327 for (unsigned int iz = first_node; iz < last_node + 1; iz++)
328 {
329 auto dz = _z_grid[iz] - _z_grid[iz - 1];
330 auto iz_ind = iz - first_node;
331 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
332 {
333 auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
334 auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
335 auto S_in = (*_S_flow_soln)(node_in);
336 auto S_out = (*_S_flow_soln)(node_out);
337 auto S_interp = computeInterpolatedValue(S_out, S_in, 0.5);
338 auto volume = dz * S_interp;
339
340 // interpolation weight coefficient
341 auto alpha = computeInterpolationCoefficients(0.5);
342
343 // Keep temporal storage independent of the spatial interpolation scheme. Applying the
344 // upwind coefficient to this term puts the storage on the upstream node and makes the
345 // small-timestep matrix singular in the upwind limit.
346 PetscInt row_tt = i_ch + _n_channels * iz_ind;
347 PetscInt col_tt = i_ch + _n_channels * iz_ind;
348 PetscScalar value_tt = _TR * (*_rho_soln)(node_out)*volume / _dt;
349 LibmeshPetscCall(MatSetValues(
350 _hc_time_derivative_mat, 1, &row_tt, 1, &col_tt, &value_tt, INSERT_VALUES));
351
352 PetscScalar value_vec_tt =
353 _TR * _rho_soln->old(node_out) * _h_soln->old(node_out) * volume / _dt;
354 PetscInt row_vec_tt = i_ch + _n_channels * iz_ind;
355 LibmeshPetscCall(
356 VecSetValues(_hc_time_derivative_rhs, 1, &row_vec_tt, &value_vec_tt, ADD_VALUES));
357
359 if (iz == first_node)
360 {
361 PetscScalar value_vec_at = (*_mdot_soln)(node_in) * (*_h_soln)(node_in);
362 PetscInt row_vec_at = i_ch + _n_channels * iz_ind;
363 LibmeshPetscCall(VecSetValues(
364 _hc_advective_derivative_rhs, 1, &row_vec_at, &value_vec_at, ADD_VALUES));
365 }
366 else
367 {
368 PetscInt row_at = i_ch + _n_channels * iz_ind;
369 PetscInt col_at = i_ch + _n_channels * (iz_ind - 1);
370 PetscScalar value_at = -1.0 * (*_mdot_soln)(node_in);
371 LibmeshPetscCall(MatSetValues(
372 _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
373 }
374
375 // Adding diagonal elements
376 PetscInt row_at = i_ch + _n_channels * iz_ind;
377 PetscInt col_at = i_ch + _n_channels * iz_ind;
378 PetscScalar value_at = (*_mdot_soln)(node_out);
379 LibmeshPetscCall(MatSetValues(
380 _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
381
383 unsigned int counter = 0;
384 unsigned int cross_index = iz; // iz-1;
385 for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
386 {
387 auto chans = _subchannel_mesh.getGapChannels(i_gap);
388 unsigned int ii_ch = chans.first;
389 unsigned int jj_ch = chans.second;
390 auto * node_in_i = _subchannel_mesh.getChannelNode(ii_ch, iz - 1);
391 auto * node_in_j = _subchannel_mesh.getChannelNode(jj_ch, iz - 1);
392 PetscScalar h_star;
393 // figure out donor axial velocity
394 if (_Wij(i_gap, cross_index) > 0.0)
395 {
396 if (iz == first_node)
397 {
398 h_star = (*_h_soln)(node_in_i);
399 PetscScalar value_vec_ct = -1.0 * alpha *
400 _subchannel_mesh.getCrossflowSign(i_ch, counter) *
401 _Wij(i_gap, cross_index) * h_star;
402 PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
403 LibmeshPetscCall(VecSetValues(
404 _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
405 }
406 else
407 {
408 PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
409 _Wij(i_gap, cross_index);
410 PetscInt row_ct = i_ch + _n_channels * iz_ind;
411 PetscInt col_ct = ii_ch + _n_channels * (iz_ind - 1);
412 LibmeshPetscCall(MatSetValues(
413 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
414 }
415 PetscScalar value_ct = (1.0 - alpha) *
416 _subchannel_mesh.getCrossflowSign(i_ch, counter) *
417 _Wij(i_gap, cross_index);
418 PetscInt row_ct = i_ch + _n_channels * iz_ind;
419 PetscInt col_ct = ii_ch + _n_channels * iz_ind;
420 LibmeshPetscCall(MatSetValues(
421 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
422 }
423 else if (_Wij(i_gap, cross_index) < 0.0) // _Wij=0 operations not necessary
424 {
425 if (iz == first_node)
426 {
427 h_star = (*_h_soln)(node_in_j);
428 PetscScalar value_vec_ct = -1.0 * alpha *
429 _subchannel_mesh.getCrossflowSign(i_ch, counter) *
430 _Wij(i_gap, cross_index) * h_star;
431 PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
432 LibmeshPetscCall(VecSetValues(
433 _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
434 }
435 else
436 {
437 PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
438 _Wij(i_gap, cross_index);
439 PetscInt row_ct = i_ch + _n_channels * iz_ind;
440 PetscInt col_ct = jj_ch + _n_channels * (iz_ind - 1);
441 LibmeshPetscCall(MatSetValues(
442 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
443 }
444 PetscScalar value_ct = (1.0 - alpha) *
445 _subchannel_mesh.getCrossflowSign(i_ch, counter) *
446 _Wij(i_gap, cross_index);
447 PetscInt row_ct = i_ch + _n_channels * iz_ind;
448 PetscInt col_ct = jj_ch + _n_channels * iz_ind;
449 LibmeshPetscCall(MatSetValues(
450 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
451 }
452
453 // Turbulent cross flows
454 if (iz == first_node)
455 {
456 PetscScalar value_vec_ct =
457 -2.0 * alpha * (*_h_soln)(node_in)*_WijPrime(i_gap, cross_index);
458 value_vec_ct += alpha * (*_h_soln)(node_in_j)*_WijPrime(i_gap, cross_index);
459 value_vec_ct += alpha * (*_h_soln)(node_in_i)*_WijPrime(i_gap, cross_index);
460 PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
461 LibmeshPetscCall(
462 VecSetValues(_hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
463 }
464 else
465 {
466 PetscScalar value_center_ct = 2.0 * alpha * _WijPrime(i_gap, cross_index);
467 PetscInt row_ct = i_ch + _n_channels * iz_ind;
468 PetscInt col_ct = i_ch + _n_channels * (iz_ind - 1);
469 LibmeshPetscCall(MatSetValues(
470 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
471
472 PetscScalar value_left_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
473 row_ct = i_ch + _n_channels * iz_ind;
474 col_ct = jj_ch + _n_channels * (iz_ind - 1);
475 LibmeshPetscCall(MatSetValues(
476 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
477
478 PetscScalar value_right_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
479 row_ct = i_ch + _n_channels * iz_ind;
480 col_ct = ii_ch + _n_channels * (iz_ind - 1);
481 LibmeshPetscCall(MatSetValues(
482 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
483 }
484 PetscScalar value_center_ct = 2.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
485 PetscInt row_ct = i_ch + _n_channels * iz_ind;
486 PetscInt col_ct = i_ch + _n_channels * iz_ind;
487 LibmeshPetscCall(MatSetValues(
488 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
489
490 PetscScalar value_left_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
491 row_ct = i_ch + _n_channels * iz_ind;
492 col_ct = jj_ch + _n_channels * iz_ind;
493 LibmeshPetscCall(MatSetValues(
494 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
495
496 PetscScalar value_right_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
497 row_ct = i_ch + _n_channels * iz_ind;
498 col_ct = ii_ch + _n_channels * iz_ind;
499 LibmeshPetscCall(MatSetValues(
500 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
501 counter++;
502 }
503
505 PetscScalar added_enthalpy = computeAddedHeatPin(i_ch, iz);
506 PetscInt row_vec_ht = i_ch + _n_channels * iz_ind;
507 LibmeshPetscCall(
508 VecSetValues(_hc_added_heat_rhs, 1, &row_vec_ht, &added_enthalpy, ADD_VALUES));
509 }
510 }
512 LibmeshPetscCall(MatAssemblyBegin(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
513 LibmeshPetscCall(MatAssemblyEnd(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
514 LibmeshPetscCall(MatAssemblyBegin(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
515 LibmeshPetscCall(MatAssemblyEnd(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
516 LibmeshPetscCall(MatAssemblyBegin(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
517 LibmeshPetscCall(MatAssemblyEnd(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
518 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
519 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
520 // Matrix
521#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
522 LibmeshPetscCall(MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, UNKNOWN_NONZERO_PATTERN));
523 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
524 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
525 LibmeshPetscCall(
526 MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, UNKNOWN_NONZERO_PATTERN));
527 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
528 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
529 LibmeshPetscCall(
530 MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, UNKNOWN_NONZERO_PATTERN));
531#else
532 LibmeshPetscCall(
533 MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, DIFFERENT_NONZERO_PATTERN));
534 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
535 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
536 LibmeshPetscCall(
537 MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, DIFFERENT_NONZERO_PATTERN));
538 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
539 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
540 LibmeshPetscCall(
541 MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, DIFFERENT_NONZERO_PATTERN));
542#endif
543 LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
544 LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
546 _console << "Block: " << iblock << " - Enthalpy conservation matrix assembled" << std::endl;
547 // RHS
548 LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_time_derivative_rhs));
549 LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_advective_derivative_rhs));
550 LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_cross_derivative_rhs));
551 LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_added_heat_rhs));
552
553 // Use system to solve for and populate enthalpy
554 LibmeshPetscCall(this->solveAndPopulateEnthalpy(
555 _hc_sys_h_mat, _hc_sys_h_rhs, first_node, last_node, "h_sys_"));
556 }
557}
registerMooseObject("SubChannelApp", QuadSubChannel1PhaseProblem)
const ConsoleStream _console
std::shared_ptr< AuxiliarySystem > _aux
void addClassDescription(const std::string &doc_string)
const std::string & name() const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
Quadrilateral subchannel solver.
virtual void computeh(int iblock) override
Computes Enthalpy per channel for block iblock.
virtual Real getSubChannelPeripheralDuctWidth(unsigned int i_ch) const override
Function that computes the width of the duct cell that the peripheral subchannel i_ch sees.
QuadSubChannel1PhaseProblem(const InputParameters &params)
virtual void initializeSolution() override
Function to initialize the solution & geometry fields.
virtual Real computeAddedHeatPin(unsigned int i_ch, unsigned int iz) const override
Pure virtual: daughters provide different implementations.
Creates the mesh of subchannels in a quadrilateral lattice.
void setGapWidth(unsigned int axial_index, unsigned int gap_index, Real gap_width)
Set the gap width for a given axial cell and gap index.
Real getGapWidth(unsigned int axial_index, unsigned int gap_index) const override
Return gap width for a given gap index.
const std::vector< unsigned int > & getChannelGaps(unsigned int i_chan) const override
Return a vector of gap indices for a given channel index.
const Real & getCrossflowSign(unsigned int i_chan, unsigned int i_local) const override
Return a sign for the crossflow given a subchannel index and local neighbor index.
const std::pair< unsigned int, unsigned int > & getGapPins(unsigned int i_gap) const override
Return a pair of pin indices for a given gap index.
const Real & getPitch() const override
Return the undeformed pitch between 2 subchannels.
const std::vector< unsigned int > & getPinChannels(unsigned int i_pin) const override
Return a vector of channel indices for a given Pin index.
EChannelType getSubchannelType(unsigned int index) const override
Return the type of the subchannel for given subchannel index.
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 Real & getSideGap() const
Returns the side gap, not to be confused with the gap between pins, this refers to the gap next to th...
const std::vector< unsigned int > & getChannelPins(unsigned int i_chan) const override
Return a vector of pin indices for a given channel index.
Node * getChannelNode(unsigned int i_chan, unsigned int iz) const override
Get the subchannel mesh node for a given channel index and elevation index.
const std::pair< unsigned int, unsigned int > & getGapChannels(unsigned int i_gap) const override
Return a pair of subchannel indices for a given gap index.
Base class for the 1-phase steady-state/transient subchannel solver.
PetscScalar computeInterpolatedValue(PetscScalar topValue, PetscScalar botValue, PetscScalar Peclet=0.0)
std::unique_ptr< SolutionHandle > _w_perim_soln
std::unique_ptr< SolutionHandle > _displacement_soln
Mat _hc_time_derivative_mat
Enthalpy Enthalpy conservation - time derivative.
static InputParameters validParams()
PetscErrorCode solveAndPopulateEnthalpy(Mat A, Vec rhs, unsigned int first_node, unsigned int last_node, const char *ksp_prefix)
Solve a linear system (A * x = rhs) with a simple PCJACOBI KSP and populate the enthalpy solution int...
const SinglePhaseFluidProperties * _fp
Non-owning pointer to fluid properties user object.
libMesh::DenseMatrix< Real > _WijPrime
std::unique_ptr< SolutionHandle > _rho_soln
std::unique_ptr< SolutionHandle > _S_flow_soln
const PostprocessorValue & _P_out
Outlet pressure postprocessor value.
std::unique_ptr< SolutionHandle > _Dpin_soln
std::unique_ptr< SolutionHandle > _P_soln
void detectDeformation()
Detects whether pin diameter or duct displacement fields require geometry recalculation.
libMesh::DenseMatrix< Real > & _Wij
bool _deformation
Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement,...
std::unique_ptr< SolutionHandle > _h_soln
std::unique_ptr< SolutionHandle > _T_soln
Real _TR
Flag that activates or deactivates the transient parts of the equations we solve by multiplication.
PetscScalar computeInterpolationCoefficients(PetscScalar Peclet=0.0)
Functions that computes the interpolation scheme given the Peclet number.
Vec _hc_added_heat_rhs
Enthalpy conservation - source and sink.
Mat _hc_advective_derivative_mat
Enthalpy conservation - advective (Eulerian) derivative;.
const bool _pin_mesh_exist
Flag that informs if there is a pin mesh or not.
const bool _implicit_bool
Flag to define the usage of a implicit or explicit solution.
std::vector< Real > _z_grid
axial location of nodes
std::unique_ptr< SolutionHandle > _mdot_soln
Solutions handles and link to TH tables properties.
const bool _verbose_subchannel
Boolean to printout information related to subchannel solve.
Mat _hc_cross_derivative_mat
Enthalpy conservation - cross flux derivative.
virtual const Real & getHeatedLength() const
Return heated length.
virtual const std::vector< Real > & getZBlockage() const
Get axial location of blockage (in,out) [m].
virtual const Real & getHeatedLengthEntry() const
Return unheated length at entry.
virtual const std::vector< Real > & getReductionBlockage() const
Get area reduction of blocked subchannels.
virtual const std::vector< unsigned int > & getIndexBlockage() const
Get index of blocked subchannels.
Definition SCM.h:17