Line data Source code
1 : /********************************************************************/
2 : /* SOFTWARE COPYRIGHT NOTIFICATION */
3 : /* Cardinal */
4 : /* */
5 : /* (c) 2021 UChicago Argonne, LLC */
6 : /* ALL RIGHTS RESERVED */
7 : /* */
8 : /* Prepared by UChicago Argonne, LLC */
9 : /* Under Contract No. DE-AC02-06CH11357 */
10 : /* With the U. S. Department of Energy */
11 : /* */
12 : /* Prepared by Battelle Energy Alliance, LLC */
13 : /* Under Contract No. DE-AC07-05ID14517 */
14 : /* With the U. S. Department of Energy */
15 : /* */
16 : /* See LICENSE for full restrictions */
17 : /********************************************************************/
18 :
19 : #pragma once
20 :
21 : #include "CardinalProblem.h"
22 : #include "NekInterface.h"
23 : #include "NekTimeStepper.h"
24 : #include "NekScalarValue.h"
25 : #include "NekRSMesh.h"
26 : #include "Transient.h"
27 :
28 : class FieldTransferBase;
29 :
30 : /**
31 : * \brief Solve nekRS wrapped as a MOOSE app.
32 : *
33 : * This object controls all of the execution of and data transfers to/from nekRS.
34 : * Any number of data transfers can be added using the [FieldTransfers] block.
35 : */
36 : class NekRSProblem : public CardinalProblem
37 : {
38 : public:
39 : NekRSProblem(const InputParameters & params);
40 :
41 : static InputParameters validParams();
42 :
43 : ~NekRSProblem();
44 :
45 : /**
46 : * The number of points (DOFs) on the mesh mirror for this rank; this is used to define the
47 : * size of various allocated terms
48 : * @return number of points on this rank
49 : */
50 1211 : int nPoints() const { return _n_points; }
51 :
52 : /**
53 : * Whether a data transfer to/from Nek is occurring
54 : * @param[in] direction direction of data transfer
55 : * @return whether a data transfer to Nek is about to occur
56 : */
57 : bool isDataTransferHappening(ExternalProblem::Direction direction);
58 :
59 537600 : Transient * transientExecutioner() const { return _transient_executioner; }
60 :
61 : /**
62 : * Whether a given slot space is reserved for coupling
63 : * @param[in] slot slot in usrwrk array
64 : * @return whether a usrwrk slot space is reserved by Cardinal
65 : */
66 : bool isUsrWrkSlotReservedForCoupling(const unsigned int & slot) const;
67 :
68 : /**
69 : * Copy an individual slice in the usrwrk array from host to device
70 : * @param[in] slot slot in usrwrk array
71 : */
72 : void copyIndividualScratchSlot(const unsigned int & slot) const;
73 :
74 : /**
75 : * Write NekRS solution field file
76 : * @param[in] time solution time in NekRS (if NekRS is non-dimensional, this will be
77 : * non-dimensional)
78 : * @param[in] step time step index
79 : */
80 : void writeFieldFile(const Real & time, const int & step) const;
81 :
82 : /**
83 : * \brief Whether nekRS should write an output file for the current time step
84 : *
85 : * A nekRS output file (suffix .f000xx) is written if the time step is an integer
86 : * multiple of the output writing interval or if the time step is the last time step.
87 : * \return whether to write a nekRS output file
88 : **/
89 : virtual bool isOutputStep() const;
90 :
91 : virtual void initialSetup() override;
92 :
93 : virtual void externalSolve() override;
94 :
95 33618 : virtual bool converged(unsigned int) override { return true; }
96 :
97 : virtual void addExternalVariables() override;
98 :
99 : virtual void syncSolutions(ExternalProblem::Direction direction) override;
100 :
101 : /**
102 : * Whether the solve is in nondimensional form
103 : * @return whether solve is in nondimensional form
104 : */
105 252 : virtual bool nondimensional() const { return _nondimensional; }
106 :
107 : /**
108 : * Whether the mesh is moving
109 : * @return whether the mesh is moving
110 : */
111 0 : virtual const bool hasMovingNekMesh() const { return false; }
112 :
113 : /**
114 : * Whether data should be synchronized in to nekRS
115 : * \return whether inward data synchronization should occur
116 : */
117 : virtual bool synchronizeIn();
118 :
119 : /**
120 : * Whether data should be synchronized out of nekRS
121 : * \return whether outward data synchronization should occur
122 : */
123 : virtual bool synchronizeOut();
124 :
125 : /**
126 : * Get the number of usrwrk slots allocated
127 : * @return number of allocated usrwrk slots
128 : */
129 614 : unsigned int nUsrWrkSlots() const { return _n_usrwrk_slots; }
130 :
131 : /**
132 : * Interpolate the NekRS volume solution onto the volume MOOSE mesh mirror (re2 -> mirror)
133 : * @param[in] f field to interpolate
134 : * @param[out] s interpolated volume value
135 : */
136 : template <typename T>
137 68034 : void volumeSolution(const T & field, double * s)
138 : {
139 68034 : mesh_t * mesh = nekrs::entireMesh();
140 68034 : auto vc = _nek_mesh->volumeCoupling();
141 :
142 : double (*f)(int, int);
143 68034 : f = nekrs::solutionPointer(field);
144 :
145 68034 : int start_1d = mesh->Nq;
146 68034 : int end_1d = _moose_Nq;
147 68034 : int start_3d = start_1d * start_1d * start_1d;
148 68034 : int end_3d = end_1d * end_1d * end_1d;
149 68034 : int n_to_write = vc.n_elems * end_3d * _nek_mesh->nBuildPerVolumeElem();
150 :
151 : // allocate temporary space:
152 : // - Ttmp: results of the search for each process
153 : // - Telem: scratch space for volume interpolation to avoid reallocating a bunch (only used if
154 : // interpolating)
155 68034 : double * Ttmp = (double *)calloc(n_to_write, sizeof(double));
156 68034 : double * Telem = (double *)calloc(start_3d, sizeof(double));
157 : auto indices = _nek_mesh->cornerIndices();
158 :
159 : int c = 0;
160 3367846 : for (int k = 0; k < mesh->Nelements; ++k)
161 : {
162 3299812 : int offset = k * start_3d;
163 :
164 7216664 : for (int build = 0; build < _nek_mesh->nBuildPerVolumeElem(); ++build)
165 : {
166 3916852 : if (_needs_interpolation)
167 : {
168 : // get the solution on the element
169 574516016 : for (int v = 0; v < start_3d; ++v)
170 572841440 : Telem[v] = f(offset + v, 0 /* unused for volumes */);
171 :
172 : // and then interpolate it
173 1674576 : nekrs::interpolateVolumeHex3D(
174 1674576 : _interpolation_outgoing, Telem, start_1d, &(Ttmp[c]), end_1d);
175 1674576 : c += end_3d;
176 : }
177 : else
178 : {
179 : // get the solution on the element - no need to interpolate
180 20180484 : for (int v = 0; v < end_3d; ++v, ++c)
181 17938208 : Ttmp[c] = f(offset + indices[build][v], 0 /* unused for volumes */);
182 : }
183 : }
184 : }
185 :
186 : // dimensionalize the solution if needed
187 63219794 : for (int v = 0; v < n_to_write; ++v)
188 63151760 : Ttmp[v] =
189 63151760 : Ttmp[v] * nekrs::nondimensionalDivisor(field) + nekrs::nondimensionalAdditive(field);
190 :
191 68034 : nekrs::allgatherv(vc.mirror_counts, Ttmp, s, end_3d);
192 :
193 : freePointer(Ttmp);
194 : freePointer(Telem);
195 68034 : }
196 :
197 : /**
198 : * Interpolate the NekRS boundary solution onto the boundary MOOSE mesh mirror (re2 -> mirror)
199 : * @param[in] f field to interpolate
200 : * @param[out] s interpolated boundary value
201 : */
202 : template <typename T>
203 20658 : void boundarySolution(const T & field, double * s)
204 : {
205 20658 : mesh_t * mesh = nekrs::entireMesh();
206 20658 : auto bc = _nek_mesh->boundaryCoupling();
207 :
208 : double (*f)(int, int);
209 20658 : f = nekrs::solutionPointer(field);
210 :
211 20658 : int start_1d = mesh->Nq;
212 20658 : int end_1d = _moose_Nq;
213 20658 : int start_2d = start_1d * start_1d;
214 20658 : int end_2d = end_1d * end_1d;
215 :
216 20658 : int n_to_write = bc.n_faces * end_2d * _nek_mesh->nBuildPerSurfaceElem();
217 :
218 : // allocate temporary space:
219 : // - Ttmp: results of the search for each process
220 : // - Tface: scratch space for face solution to avoid reallocating a bunch (only used if
221 : // interpolating)
222 : // - scratch: scratch for the interpolatino process to avoid reallocating a bunch (only used if
223 : // interpolating0
224 20658 : double * Ttmp = (double *)calloc(n_to_write, sizeof(double));
225 20658 : double * Tface = (double *)calloc(start_2d, sizeof(double));
226 20658 : double * scratch = (double *)calloc(start_1d * end_1d, sizeof(double));
227 :
228 : auto indices = _nek_mesh->cornerIndices();
229 :
230 : int c = 0;
231 2179446 : for (int k = 0; k < bc.total_n_faces; ++k)
232 : {
233 2158788 : if (bc.process[k] == nekrs::commRank())
234 : {
235 383682 : int i = bc.element[k];
236 383682 : int j = bc.face[k];
237 383682 : int offset = i * mesh->Nfaces * start_2d + j * start_2d;
238 :
239 1135652 : for (int build = 0; build < _nek_mesh->nBuildPerSurfaceElem(); ++build)
240 : {
241 751970 : if (_needs_interpolation)
242 : {
243 : // get the solution on the face
244 3623648 : for (int v = 0; v < start_2d; ++v)
245 : {
246 3529344 : int id = mesh->vmapM[offset + v];
247 3529344 : Tface[v] = f(id, mesh->Nsgeo * (offset + v));
248 : }
249 :
250 : // and then interpolate it
251 94304 : nekrs::interpolateSurfaceFaceHex3D(
252 94304 : scratch, _interpolation_outgoing, Tface, start_1d, &(Ttmp[c]), end_1d);
253 94304 : c += end_2d;
254 : }
255 : else
256 : {
257 : // get the solution on the face - no need to interpolate
258 3288330 : for (int v = 0; v < end_2d; ++v, ++c)
259 : {
260 2630664 : int id = mesh->vmapM[offset + indices[build][v]];
261 2630664 : Ttmp[c] = f(id, mesh->Nsgeo * (offset + v));
262 : }
263 : }
264 : }
265 : }
266 : }
267 :
268 : // dimensionalize the solution if needed
269 3500058 : for (int v = 0; v < n_to_write; ++v)
270 3479400 : Ttmp[v] =
271 3479400 : Ttmp[v] * nekrs::nondimensionalDivisor(field) + nekrs::nondimensionalAdditive(field);
272 :
273 20658 : nekrs::allgatherv(bc.mirror_counts, Ttmp, s, end_2d);
274 :
275 : freePointer(Ttmp);
276 : freePointer(Tface);
277 : freePointer(scratch);
278 20658 : }
279 :
280 : /**
281 : * Write into the NekRS solution space for coupling volumes; for setting a mesh position in terms
282 : * of a displacement, we need to add the displacement to the initial mesh coordinates. For this,
283 : * the 'add' parameter lets you pass in a vector of values (in NekRS's mesh order, i.e. the re2
284 : * order) to add.
285 : * @param[in] elem_id element ID
286 : * @param[in] field field to write
287 : * @param[in] s solution values to write for the field for the given element
288 : * @param[in] add optional vector of values to add to each value set on the NekRS end
289 : */
290 : template <typename T>
291 1441294 : void writeVolumeSolution(const int elem_id,
292 : const T & field,
293 : double * s,
294 : const std::vector<double> * add = nullptr)
295 : {
296 1441294 : mesh_t * mesh = nekrs::entireMesh();
297 : void (*write_solution)(int, dfloat);
298 1441294 : write_solution = nekrs::solutionWritePointer(field);
299 :
300 1441294 : auto vc = _nek_mesh->volumeCoupling();
301 1441294 : int id = vc.element[elem_id] * mesh->Np;
302 :
303 1441294 : if (_nek_mesh->exactMirror())
304 : {
305 : // can write directly into the NekRS solution
306 3807400 : for (int v = 0; v < mesh->Np; ++v)
307 : {
308 3681792 : double extra = (add == nullptr) ? 0.0 : (*add)[id + v];
309 3681792 : write_solution(id + v, s[v] + extra);
310 : }
311 : }
312 : else
313 : {
314 : // need to interpolate onto the higher-order Nek mesh
315 1315686 : double * tmp = (double *)calloc(mesh->Np, sizeof(double));
316 :
317 1315686 : interpolateVolumeSolutionToNek(elem_id, s, tmp);
318 :
319 185380790 : for (int v = 0; v < mesh->Np; ++v)
320 : {
321 184065104 : double extra = (add == nullptr) ? 0.0 : (*add)[id + v];
322 184065104 : write_solution(id + v, tmp[v] + extra);
323 : }
324 :
325 : freePointer(tmp);
326 : }
327 1441294 : }
328 :
329 : /**
330 : * Write into the NekRS solution space for coupling boundaries; for setting a mesh position in
331 : * terms of a displacement, we need to add the displacement to the initial mesh coordinates.
332 : * @param[in] elem_id element ID
333 : * @param[in] field field to write
334 : * @param[in] s solution values to write for the field for the given element
335 : */
336 : template <typename T>
337 424202 : void writeBoundarySolution(const int elem_id, const T & field, double * s)
338 : {
339 424202 : mesh_t * mesh = nekrs::temperatureMesh();
340 : void (*write_solution)(int, dfloat);
341 424202 : write_solution = nekrs::solutionWritePointer(field);
342 :
343 424202 : const auto & bc = _nek_mesh->boundaryCoupling();
344 424202 : int offset = bc.element[elem_id] * mesh->Nfaces * mesh->Nfp + bc.face[elem_id] * mesh->Nfp;
345 :
346 424202 : if (_nek_mesh->exactMirror())
347 : {
348 : // can write directly into the NekRS solution
349 638144 : for (int i = 0; i < mesh->Nfp; ++i)
350 613600 : write_solution(mesh->vmapM[offset + i], s[i]);
351 : }
352 : else
353 : {
354 : // need to interpolate onto the higher-order Nek mesh
355 399658 : double * tmp = (double *)calloc(mesh->Nfp, sizeof(double));
356 399658 : interpolateBoundarySolutionToNek(s, tmp);
357 :
358 7328042 : for (int i = 0; i < mesh->Nfp; ++i)
359 6928384 : write_solution(mesh->vmapM[offset + i], tmp[i]);
360 :
361 : freePointer(tmp);
362 : }
363 424202 : }
364 :
365 : /**
366 : * The casename (prefix) of the NekRS files
367 : * @return casename
368 : */
369 34 : std::string casename() const { return _casename; }
370 :
371 : /**
372 : * Map nodal points on a MOOSE face element to the GLL points on a Nek face element.
373 : * @param[in] e MOOSE element ID
374 : * @param[in] var_num variable index to fetch MOOSE data from
375 : * @param[in] divisor number to divide MOOSE data by before sending to Nek (to non-dimensionalize
376 : * it)
377 : * @param[in] additive number to subtract from MOOSE data, before dividing by divisor and sending
378 : * to Nek (to non-dimensionalize)
379 : * @param[out] outgoing_data data represented on Nek's GLL points, ready to be applied in Nek
380 : */
381 : void mapFaceDataToNekFace(const unsigned int & e,
382 : const unsigned int & var_num,
383 : const Real & divisor,
384 : const Real & additive,
385 : double ** outgoing_data);
386 :
387 : /**
388 : * Map nodal points on a MOOSE volume element to the GLL points on a Nek volume element.
389 : * @param[in] e MOOSE element ID
390 : * @param[in] var_num variable index to fetch MOOSE data from
391 : * @param[in] divisor number to divide MOOSE data by before sending to Nek (to non-dimensionalize
392 : * it)
393 : * @param[in] additive number to subtract from MOOSE data, before dividing by divisor and sending
394 : * to Nek (to non-dimensionalize)
395 : * @param[out] outgoing_data data represented on Nek's GLL points, ready to be applied in Nek
396 : */
397 : void mapVolumeDataToNekVolume(const unsigned int & e,
398 : const unsigned int & var_num,
399 : const Real & divisor,
400 : const Real & additive,
401 : double ** outgoing_data);
402 :
403 : /**
404 : * \brief Map nodal points on a MOOSE face element to the GLL points on a Nek volume element.
405 : *
406 : * This function is to be used when MOOSE variables are defined over the entire volume
407 : * (maybe the MOOSE transfer only sent meaningful values to the coupling boundaries), so we
408 : * need to do a volume interpolation of the incoming MOOSE data into nrs->usrwrk, rather
409 : * than a face interpolation. This could be optimized in the future to truly only just write
410 : * the boundary values into the nekRS scratch space rather than the volume values, but it
411 : * looks right now that our biggest expense occurs in the MOOSE transfer system, not these
412 : * transfers internally to nekRS.
413 : *
414 : * @param[in] e MOOSE element ID
415 : * @param[in] var_num variable index to fetch MOOSE data from
416 : * @param[in] divisor number to divide MOOSE data by before sending to Nek (to non-dimensionalize
417 : * it)
418 : * @param[in] additive number to subtract from MOOSE data, before dividing by divisor and sending
419 : * to Nek (to non-dimensionalize)
420 : * @param[out] outgoing_data data represented on Nek's GLL points, ready to be applied in Nek
421 : */
422 : void mapFaceDataToNekVolume(const unsigned int & e,
423 : const unsigned int & var_num,
424 : const Real & divisor,
425 : const Real & additive,
426 : double ** outgoing_data);
427 :
428 : protected:
429 : /// Copy the data sent from MOOSE->Nek from host to device.
430 : void copyScratchToDevice();
431 :
432 : /**
433 : * Interpolate the MOOSE mesh mirror solution onto the NekRS boundary mesh (mirror -> re2)
434 : * @param[in] incoming_moose_value MOOSE face values
435 : * @param[out] outgoing_nek_value interpolated MOOSE face values onto the NekRS boundary mesh
436 : */
437 : void interpolateBoundarySolutionToNek(double * incoming_moose_value, double * outgoing_nek_value);
438 :
439 : /**
440 : * Interpolate the MOOSE mesh mirror solution onto the NekRS volume mesh (mirror -> re2)
441 : * @param[in] elem_id element ID
442 : * @param[in] incoming_moose_value MOOSE face values
443 : * @param[out] outgoing_nek_value interpolated MOOSE face values onto the NekRS volume mesh
444 : */
445 : void interpolateVolumeSolutionToNek(const int elem_id,
446 : double * incoming_moose_value,
447 : double * outgoing_nek_value);
448 :
449 : /// Initialize interpolation matrices for transfers in/out of nekRS
450 : void initializeInterpolationMatrices();
451 :
452 : std::unique_ptr<NumericVector<Number>> _serialized_solution;
453 :
454 : /**
455 : * Get a three-character prefix for use in writing output files for repeated
456 : * Nek sibling apps.
457 : * @param[in] number multi-app number
458 : */
459 : std::string fieldFilePrefix(const int & number) const;
460 :
461 : /// NekRS casename
462 : const std::string & _casename;
463 :
464 : /**
465 : * Whether to disable output file writing by NekRS and replace it by output
466 : * file writing in Cardinal. Suppose the case name is 'channel'. If this parameter
467 : * is false, then NekRS will write output files as usual, with names like
468 : * channel0.f00001 for write step 1, channel0.f00002 for write step 2, and so on.
469 : * If true, then NekRS itself does not output any files like this, and instead
470 : * output files are written with names a01channel0.f00001, a01channel0.f00002 (for
471 : * first Nek app), a02channel0.f00001, a02channel0.f00002 (for second Nek app),
472 : * and so on. This feature should only be used when running repeated Nek sub
473 : * apps so that the output from each app is retained. Otherwise, if running N
474 : * repeated Nek sub apps, only a single output file is obtained because each app
475 : * overwrites the output files of the other apps in the order that the apps
476 : * reach the nekrs::outfld function.
477 : */
478 : const bool & _write_fld_files;
479 :
480 : /// Whether to turn off all field file writing
481 : const bool & _disable_fld_file_output;
482 :
483 : /// Whether a dimensionalization action has been added
484 : bool _nondimensional;
485 :
486 : /**
487 : * Number of slices/slots to allocate in nrs->usrwrk to hold fields
488 : * for coupling (i.e. data going into NekRS, written by Cardinal), or
489 : * used for custom user actions, but not for coupling. By default, we just
490 : * allocate 7 slots (no inherent reason, just a fairly big amount). For
491 : * memory-limited cases, you can reduce this number to just the bare
492 : * minimum necessary for your use case.
493 : */
494 : unsigned int _n_usrwrk_slots;
495 :
496 : /// For constant synchronization intervals, the desired frequency (in units of Nek time steps)
497 : const unsigned int & _constant_interval;
498 :
499 : /// Whether to skip writing a field file on NekRS's last time steo
500 : const bool & _skip_final_field_file;
501 :
502 : /// Number of surface elements in the data transfer mesh, across all processes
503 : int _n_surface_elems;
504 :
505 : /// Number of vertices per surface element of the transfer mesh
506 : int _n_vertices_per_surface;
507 :
508 : /// Number of volume elements in the data transfer mesh, across all processes
509 : int _n_volume_elems;
510 :
511 : /// Number of vertices per volume element of the transfer mesh
512 : int _n_vertices_per_volume;
513 :
514 : /// Start time of the simulation based on NekRS's .par file
515 : double _start_time;
516 :
517 : /// Whether the most recent time step was an output file writing step
518 : bool _is_output_step;
519 :
520 : /**
521 : * Underlying mesh object on which NekRS exchanges fields with MOOSE
522 : * or extracts NekRS's solution for I/O features
523 : */
524 : NekRSMesh * _nek_mesh;
525 :
526 : /// The time stepper used for selection of time step size
527 : NekTimeStepper * _timestepper = nullptr;
528 :
529 : /// Underlying executioner
530 : Transient * _transient_executioner = nullptr;
531 :
532 : /**
533 : * Whether an interpolation needs to be performed on the nekRS temperature solution, or
534 : * if we can just grab the solution at specified points
535 : */
536 : bool _needs_interpolation;
537 :
538 : /// Number of points for interpolated fields on the MOOSE mesh
539 : int _n_points;
540 :
541 : /// Postprocessor containing the signal of when a synchronization has occurred
542 : const PostprocessorValue * _transfer_in = nullptr;
543 :
544 : /// Vandermonde interpolation matrix (for outgoing transfers)
545 : double * _interpolation_outgoing = nullptr;
546 :
547 : /// Vandermonde interpolation matrix (for incoming transfers)
548 : double * _interpolation_incoming = nullptr;
549 :
550 : /// For the MOOSE mesh, the number of quadrature points in each coordinate direction
551 : int _moose_Nq;
552 :
553 : /// Slots in the nrs->o_usrwrk array to write to a field file
554 : const std::vector<unsigned int> * _usrwrk_output = nullptr;
555 :
556 : /// Filename prefix to use for naming the field files containing the nrs->o_usrwrk array slots
557 : const std::vector<std::string> * _usrwrk_output_prefix = nullptr;
558 :
559 : /// Sum of the elapsed time in NekRS solves
560 : double _elapsedStepSum;
561 :
562 : /// Sum of the total elapsed time in NekRS solves
563 : double _elapsedTime;
564 :
565 : /// Minimum step solve time
566 : double _tSolveStepMin;
567 :
568 : /// Maximum step solve time
569 : double _tSolveStepMax;
570 :
571 : /**
572 : * \brief When to synchronize the NekRS solution with the mesh mirror
573 : *
574 : * This parameter determines when to synchronize the NekRS solution with the mesh
575 : * mirror - this entails:
576 : *
577 : * - Mapping from the NekRS spectral element mesh to the finite element mesh mirror,
578 : * to extract information from NekRS and make it available to MOOSE
579 : * - Mapping from the finite element mesh mirror into the NekRS spectral element mesh,
580 : * to send information from MOOSE into NekRS
581 : *
582 : * Several options are available:
583 : * - 'constant' will simply keep the NekRS solution and the mesh mirror entirely
584 : * consistent with one another on a given constant frequency of time steps. By
585 : * default, the 'constant_interval' is 1, so that NekRS and MOOSE communicate
586 : * with each other on every single time step
587 : *
588 : * - 'parent_app' will only send data between NekRS and a parent application
589 : * when (1) the main application has just sent "new" information to NekRS, and
590 : * when (2) the main application is just about to run a new time step (with
591 : * updated BCs/source terms from NekRS).
592 : *
593 : * nekRS is often subcycled relative to the application controlling it -
594 : * that is, nekRS may be run with a time step 10x smaller than a conduction MOOSE app.
595 : * If 'interpolate_transfers = false'
596 : * in the master application, then the data going into nekRS is fixed for each
597 : * of the subcycled time steps it takes, so these extra data transfers are
598 : * completely unnecssary. This flag indicates that the information sent from MOOSE
599 : * to NekRS should only be updated if the data from MOOSE is "new", and likewise
600 : * whether the NekRS solution should only be interpolated to the mesh mirror once
601 : * MOOSE is actually "ready" to solve a time step using it.
602 : *
603 : * NOTE: if 'interpolate_transfers = true' in the master application, then the data
604 : * coming into nekRS is _unique_ on each subcycled time step, so setting this to
605 : * true will in effect override `interpolate_transfers` to be false. For the best
606 : * performance, you should set `interpolate_transfers` to false so that you don't
607 : * even bother computing the interpolated data, since it's not used if this parameter
608 : * is set to true.
609 : */
610 : synchronization::SynchronizationEnum _sync_interval;
611 :
612 : /// flag to indicate whether this is the first pass to serialize the solution
613 : static bool _first;
614 :
615 : /// All of the FieldTransfer objects which pass data in/out of NekRS
616 : std::vector<FieldTransferBase *> _field_transfers;
617 :
618 : /// All of the ScalarTransfer objecst which pass data in/out of NekRS
619 : std::vector<ScalarTransferBase *> _scalar_transfers;
620 :
621 : /// Usrwrk slots managed by Cardinal
622 : std::set<unsigned int> _usrwrk_slots;
623 : };
|