https://mooseframework.inl.gov
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 {
21  params.addClassDescription(
22  "Solver class for subchannels in a square lattice assembly and bare fuel pins");
23  return params;
24 }
25 
27  : SubChannel1PhaseProblem(params), _subchannel_mesh(SCM::getMesh<QuadSubChannelMesh>(_mesh))
28 {
29 }
30 
31 void
33 {
35 
37  if (_deformation)
38  {
39  _console << " =========== DEFORMATION RECALCULATION ACTIVATED ============== " << std::endl;
40  Real standard_area, additional_area, wetted_perimeter, displaced_area;
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;
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 
196 Real
197 QuadSubChannel1PhaseProblem::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 
227 Real
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 
242 void
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  {
255  mooseError(
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  {
306  mooseError(name(),
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
342 
344  if (iz == first_node)
345  {
346  PetscScalar value_vec_tt =
347  -1.0 * _TR * alpha * (*_rho_soln)(node_in) * (*_h_soln)(node_in)*volume / _dt;
348  PetscInt row_vec_tt = i_ch + _n_channels * iz_ind;
349  LibmeshPetscCall(
350  VecSetValues(_hc_time_derivative_rhs, 1, &row_vec_tt, &value_vec_tt, ADD_VALUES));
351  }
352  else
353  {
354  PetscInt row_tt = i_ch + _n_channels * iz_ind;
355  PetscInt col_tt = i_ch + _n_channels * (iz_ind - 1);
356  PetscScalar value_tt = _TR * alpha * (*_rho_soln)(node_in)*volume / _dt;
357  LibmeshPetscCall(MatSetValues(
358  _hc_time_derivative_mat, 1, &row_tt, 1, &col_tt, &value_tt, INSERT_VALUES));
359  }
360 
361  // Adding diagonal elements
362  PetscInt row_tt = i_ch + _n_channels * iz_ind;
363  PetscInt col_tt = i_ch + _n_channels * iz_ind;
364  PetscScalar value_tt = _TR * (1.0 - alpha) * (*_rho_soln)(node_out)*volume / _dt;
365  LibmeshPetscCall(MatSetValues(
366  _hc_time_derivative_mat, 1, &row_tt, 1, &col_tt, &value_tt, INSERT_VALUES));
367 
368  // Adding RHS elements
369  PetscScalar rho_old_interp =
370  computeInterpolatedValue(_rho_soln->old(node_out), _rho_soln->old(node_in), 0.5);
371  PetscScalar h_old_interp =
372  computeInterpolatedValue(_h_soln->old(node_out), _h_soln->old(node_in), 0.5);
373  PetscScalar value_vec_tt = _TR * rho_old_interp * h_old_interp * volume / _dt;
374  PetscInt row_vec_tt = i_ch + _n_channels * iz_ind;
375  LibmeshPetscCall(
376  VecSetValues(_hc_time_derivative_rhs, 1, &row_vec_tt, &value_vec_tt, ADD_VALUES));
377 
379  if (iz == first_node)
380  {
381  PetscScalar value_vec_at = (*_mdot_soln)(node_in) * (*_h_soln)(node_in);
382  PetscInt row_vec_at = i_ch + _n_channels * iz_ind;
383  LibmeshPetscCall(VecSetValues(
384  _hc_advective_derivative_rhs, 1, &row_vec_at, &value_vec_at, ADD_VALUES));
385  }
386  else
387  {
388  PetscInt row_at = i_ch + _n_channels * iz_ind;
389  PetscInt col_at = i_ch + _n_channels * (iz_ind - 1);
390  PetscScalar value_at = -1.0 * (*_mdot_soln)(node_in);
391  LibmeshPetscCall(MatSetValues(
392  _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
393  }
394 
395  // Adding diagonal elements
396  PetscInt row_at = i_ch + _n_channels * iz_ind;
397  PetscInt col_at = i_ch + _n_channels * iz_ind;
398  PetscScalar value_at = (*_mdot_soln)(node_out);
399  LibmeshPetscCall(MatSetValues(
400  _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
401 
403  unsigned int counter = 0;
404  unsigned int cross_index = iz; // iz-1;
405  for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
406  {
407  auto chans = _subchannel_mesh.getGapChannels(i_gap);
408  unsigned int ii_ch = chans.first;
409  unsigned int jj_ch = chans.second;
410  auto * node_in_i = _subchannel_mesh.getChannelNode(ii_ch, iz - 1);
411  auto * node_in_j = _subchannel_mesh.getChannelNode(jj_ch, iz - 1);
412  PetscScalar h_star;
413  // figure out donor axial velocity
414  if (_Wij(i_gap, cross_index) > 0.0)
415  {
416  if (iz == first_node)
417  {
418  h_star = (*_h_soln)(node_in_i);
419  PetscScalar value_vec_ct = -1.0 * alpha *
420  _subchannel_mesh.getCrossflowSign(i_ch, counter) *
421  _Wij(i_gap, cross_index) * h_star;
422  PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
423  LibmeshPetscCall(VecSetValues(
424  _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
425  }
426  else
427  {
428  PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
429  _Wij(i_gap, cross_index);
430  PetscInt row_ct = i_ch + _n_channels * iz_ind;
431  PetscInt col_ct = ii_ch + _n_channels * (iz_ind - 1);
432  LibmeshPetscCall(MatSetValues(
433  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
434  }
435  PetscScalar value_ct = (1.0 - alpha) *
436  _subchannel_mesh.getCrossflowSign(i_ch, counter) *
437  _Wij(i_gap, cross_index);
438  PetscInt row_ct = i_ch + _n_channels * iz_ind;
439  PetscInt col_ct = ii_ch + _n_channels * iz_ind;
440  LibmeshPetscCall(MatSetValues(
441  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
442  }
443  else if (_Wij(i_gap, cross_index) < 0.0) // _Wij=0 operations not necessary
444  {
445  if (iz == first_node)
446  {
447  h_star = (*_h_soln)(node_in_j);
448  PetscScalar value_vec_ct = -1.0 * alpha *
449  _subchannel_mesh.getCrossflowSign(i_ch, counter) *
450  _Wij(i_gap, cross_index) * h_star;
451  PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
452  LibmeshPetscCall(VecSetValues(
453  _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
454  }
455  else
456  {
457  PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
458  _Wij(i_gap, cross_index);
459  PetscInt row_ct = i_ch + _n_channels * iz_ind;
460  PetscInt col_ct = jj_ch + _n_channels * (iz_ind - 1);
461  LibmeshPetscCall(MatSetValues(
462  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
463  }
464  PetscScalar value_ct = (1.0 - alpha) *
465  _subchannel_mesh.getCrossflowSign(i_ch, counter) *
466  _Wij(i_gap, cross_index);
467  PetscInt row_ct = i_ch + _n_channels * iz_ind;
468  PetscInt col_ct = jj_ch + _n_channels * iz_ind;
469  LibmeshPetscCall(MatSetValues(
470  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
471  }
472 
473  // Turbulent cross flows
474  if (iz == first_node)
475  {
476  PetscScalar value_vec_ct =
477  -2.0 * alpha * (*_h_soln)(node_in)*_WijPrime(i_gap, cross_index);
478  value_vec_ct += alpha * (*_h_soln)(node_in_j)*_WijPrime(i_gap, cross_index);
479  value_vec_ct += alpha * (*_h_soln)(node_in_i)*_WijPrime(i_gap, cross_index);
480  PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
481  LibmeshPetscCall(
482  VecSetValues(_hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
483  }
484  else
485  {
486  PetscScalar value_center_ct = 2.0 * alpha * _WijPrime(i_gap, cross_index);
487  PetscInt row_ct = i_ch + _n_channels * iz_ind;
488  PetscInt col_ct = i_ch + _n_channels * (iz_ind - 1);
489  LibmeshPetscCall(MatSetValues(
490  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
491 
492  PetscScalar value_left_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
493  row_ct = i_ch + _n_channels * iz_ind;
494  col_ct = jj_ch + _n_channels * (iz_ind - 1);
495  LibmeshPetscCall(MatSetValues(
496  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
497 
498  PetscScalar value_right_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
499  row_ct = i_ch + _n_channels * iz_ind;
500  col_ct = ii_ch + _n_channels * (iz_ind - 1);
501  LibmeshPetscCall(MatSetValues(
502  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
503  }
504  PetscScalar value_center_ct = 2.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
505  PetscInt row_ct = i_ch + _n_channels * iz_ind;
506  PetscInt col_ct = i_ch + _n_channels * iz_ind;
507  LibmeshPetscCall(MatSetValues(
508  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
509 
510  PetscScalar value_left_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
511  row_ct = i_ch + _n_channels * iz_ind;
512  col_ct = jj_ch + _n_channels * iz_ind;
513  LibmeshPetscCall(MatSetValues(
514  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
515 
516  PetscScalar value_right_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
517  row_ct = i_ch + _n_channels * iz_ind;
518  col_ct = ii_ch + _n_channels * iz_ind;
519  LibmeshPetscCall(MatSetValues(
520  _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
521  counter++;
522  }
523 
525  PetscScalar added_enthalpy = computeAddedHeatPin(i_ch, iz);
526  PetscInt row_vec_ht = i_ch + _n_channels * iz_ind;
527  LibmeshPetscCall(
528  VecSetValues(_hc_added_heat_rhs, 1, &row_vec_ht, &added_enthalpy, ADD_VALUES));
529  }
530  }
532  LibmeshPetscCall(MatAssemblyBegin(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
533  LibmeshPetscCall(MatAssemblyEnd(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
534  LibmeshPetscCall(MatAssemblyBegin(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
535  LibmeshPetscCall(MatAssemblyEnd(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
536  LibmeshPetscCall(MatAssemblyBegin(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
537  LibmeshPetscCall(MatAssemblyEnd(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
538  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
539  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
540  // Matrix
541 #if !PETSC_VERSION_LESS_THAN(3, 15, 0)
542  LibmeshPetscCall(MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, UNKNOWN_NONZERO_PATTERN));
543  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
544  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
545  LibmeshPetscCall(
546  MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, UNKNOWN_NONZERO_PATTERN));
547  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
548  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
549  LibmeshPetscCall(
550  MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, UNKNOWN_NONZERO_PATTERN));
551 #else
552  LibmeshPetscCall(
553  MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, DIFFERENT_NONZERO_PATTERN));
554  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
555  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
556  LibmeshPetscCall(
557  MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, DIFFERENT_NONZERO_PATTERN));
558  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
559  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
560  LibmeshPetscCall(
561  MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, DIFFERENT_NONZERO_PATTERN));
562 #endif
563  LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
564  LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
566  _console << "Block: " << iblock << " - Enthalpy conservation matrix assembled" << std::endl;
567  // RHS
568  LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_time_derivative_rhs));
569  LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_advective_derivative_rhs));
570  LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_cross_derivative_rhs));
571  LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_added_heat_rhs));
572 
573  // Use system to solve for and populate enthalpy
574  LibmeshPetscCall(this->solveAndPopulateEnthalpy(
575  _hc_sys_h_mat, _hc_sys_h_rhs, first_node, last_node, "h_sys_"));
576  }
577 }
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 bool _pin_mesh_exist
Flag that informs if there is a pin mesh or not.
EChannelType getSubchannelType(unsigned int index) const override
Return the type of the subchannel for given subchannel index.
std::unique_ptr< SolutionHandle > _T_soln
std::unique_ptr< SolutionHandle > _h_soln
const std::vector< unsigned int > & getPinChannels(unsigned int i_pin) const override
Return a vector of channel indices for a given Pin index.
T & getMesh(MooseMesh &mesh)
function to cast mesh
Definition: SCM.h:35
Real _TR
Flag that activates or deactivates the transient parts of the equations we solve by multiplication...
const PostprocessorValue & _P_out
Outlet pressure postprocessor value.
static InputParameters validParams()
Node * getChannelNode(unsigned int i_chan, unsigned int iz) const override
Get the subchannel mesh node for a given channel index and elevation index.
std::unique_ptr< SolutionHandle > _S_flow_soln
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...
virtual void computeh(int iblock) override
Computes Enthalpy per channel for block iblock.
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.
static InputParameters validParams()
virtual Real computeAddedHeatPin(unsigned int i_ch, unsigned int iz) const override
Pure virtual: daughters provide different implementations.
const std::vector< unsigned int > & getChannelPins(unsigned int i_chan) const override
Return a vector of pin indices for a given channel index.
Creates the mesh of subchannels in a quadrilateral lattice.
PetscScalar computeInterpolatedValue(PetscScalar topValue, PetscScalar botValue, PetscScalar Peclet=0.0)
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...
registerMooseObject("SubChannelApp", QuadSubChannel1PhaseProblem)
const std::vector< unsigned int > & getChannelGaps(unsigned int i_chan) const override
Return a vector of gap indices for a given channel index.
std::unique_ptr< SolutionHandle > _rho_soln
Vec _hc_added_heat_rhs
Enthalpy conservation - source and sink.
std::vector< Real > _z_grid
axial location of nodes
const std::string & name() const
virtual const Real & getHeatedLength() const
Return heated length.
static const std::string pitch
PetscScalar computeInterpolationCoefficients(PetscScalar Peclet=0.0)
Functions that computes the interpolation scheme given the Peclet number.
const Real & getPitch() const override
Return the undeformed pitch between 2 subchannels.
std::shared_ptr< AuxiliarySystem > _aux
Mat _hc_cross_derivative_mat
Enthalpy conservation - cross flux derivative.
std::unique_ptr< SolutionHandle > _Dpin_soln
bool _deformation
Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement...
virtual const std::vector< Real > & getReductionBlockage() const
Get area reduction of blocked subchannels.
Real volume(const MeshBase &mesh, unsigned int dim=libMesh::invalid_uint)
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.
Quadrilateral subchannel solver.
Base class for the 1-phase steady-state/transient subchannel solver.
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.
std::unique_ptr< SolutionHandle > _mdot_soln
Solutions handles and link to TH tables properties.
Node * getPinNode(unsigned int i_pin, unsigned int iz) const override
Get the pin mesh node for a given pin index and elevation index.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::unique_ptr< SolutionHandle > _displacement_soln
virtual const std::vector< Real > & getZBlockage() const
Get axial location of blockage (in,out) [m].
libMesh::DenseMatrix< Real > & _Wij
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
static const std::string alpha
Definition: NS.h:138
void detectDeformation()
Detects whether pin diameter or duct displacement fields require geometry recalculation.
Real getGapWidth(unsigned int axial_index, unsigned int gap_index) const override
Return gap width for a given gap index.
void mooseWarning(Args &&... args) const
const bool _verbose_subchannel
Boolean to printout information related to subchannel solve.
void mooseError(Args &&... args) const
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.
void addClassDescription(const std::string &doc_string)
Mat _hc_advective_derivative_mat
Enthalpy conservation - advective (Eulerian) derivative;.
virtual const std::vector< unsigned int > & getIndexBlockage() const
Get index of blocked subchannels.
const bool _implicit_bool
Flag to define the usage of a implicit or explicit solution.
const ConsoleStream _console
Mat _hc_time_derivative_mat
Enthalpy Enthalpy conservation - time derivative.
libMesh::DenseMatrix< Real > _WijPrime
QuadSubChannel1PhaseProblem(const InputParameters &params)
std::unique_ptr< SolutionHandle > _P_soln
virtual void initializeSolution() override
Function to initialize the solution & geometry fields.
std::unique_ptr< SolutionHandle > _w_perim_soln
Definition: SCM.h:16
virtual const Real & getHeatedLengthEntry() const
Return unheated length at entry.
const SinglePhaseFluidProperties * _fp
Non-owning pointer to fluid properties user object.
Mat _hc_sys_h_mat
System matrices.