Cardinal
NekRSProblem.h
Go to the documentation of this file.
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 
37 {
38 public:
39  NekRSProblem(const InputParameters & params);
40 
41  static InputParameters validParams();
42 
43  ~NekRSProblem();
44 
50  int nPoints() const { return _n_points; }
51 
57  bool isDataTransferHappening(ExternalProblem::Direction direction);
58 
59  Transient * transientExecutioner() const { return _transient_executioner; }
60 
66  bool isUsrWrkSlotReservedForCoupling(const unsigned int & slot) const;
67 
72  void copyIndividualScratchSlot(const unsigned int & slot) const;
73 
80  void writeFieldFile(const Real & time, const int & step) const;
81 
89  virtual bool isOutputStep() const;
90 
91  virtual void initialSetup() override;
92 
93  virtual void externalSolve() override;
94 
95  virtual bool converged(unsigned int) override { return true; }
96 
97  virtual void addExternalVariables() override;
98 
99  virtual void syncSolutions(ExternalProblem::Direction direction) override;
100 
105  virtual bool nondimensional() const { return _nondimensional; }
106 
111  virtual const bool hasMovingNekMesh() const { return false; }
112 
117  virtual bool synchronizeIn();
118 
123  virtual bool synchronizeOut();
124 
129  unsigned int nUsrWrkSlots() const { return _n_usrwrk_slots; }
130 
136  template <typename T>
137  void volumeSolution(const T & field, double * s)
138  {
139  mesh_t * mesh = nekrs::entireMesh();
140  auto vc = _nek_mesh->volumeCoupling();
141 
142  double (*f)(int, int);
144 
145  int start_1d = mesh->Nq;
146  int end_1d = _moose_Nq;
147  int start_3d = start_1d * start_1d * start_1d;
148  int end_3d = end_1d * end_1d * end_1d;
149  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  double * Ttmp = (double *)calloc(n_to_write, sizeof(double));
156  double * Telem = (double *)calloc(start_3d, sizeof(double));
157  auto indices = _nek_mesh->cornerIndices();
158 
159  int c = 0;
160  for (int k = 0; k < mesh->Nelements; ++k)
161  {
162  int offset = k * start_3d;
163 
164  for (int build = 0; build < _nek_mesh->nBuildPerVolumeElem(); ++build)
165  {
167  {
168  // get the solution on the element
169  for (int v = 0; v < start_3d; ++v)
170  Telem[v] = f(offset + v, 0 /* unused for volumes */);
171 
172  // and then interpolate it
174  _interpolation_outgoing, Telem, start_1d, &(Ttmp[c]), end_1d);
175  c += end_3d;
176  }
177  else
178  {
179  // get the solution on the element - no need to interpolate
180  for (int v = 0; v < end_3d; ++v, ++c)
181  Ttmp[c] = f(offset + indices[build][v], 0 /* unused for volumes */);
182  }
183  }
184  }
185 
186  // dimensionalize the solution if needed
187  for (int v = 0; v < n_to_write; ++v)
188  Ttmp[v] =
190 
191  nekrs::allgatherv(vc.mirror_counts, Ttmp, s, end_3d);
192 
193  freePointer(Ttmp);
194  freePointer(Telem);
195  }
196 
202  template <typename T>
203  void boundarySolution(const T & field, double * s)
204  {
205  mesh_t * mesh = nekrs::entireMesh();
206  auto bc = _nek_mesh->boundaryCoupling();
207 
208  double (*f)(int, int);
210 
211  int start_1d = mesh->Nq;
212  int end_1d = _moose_Nq;
213  int start_2d = start_1d * start_1d;
214  int end_2d = end_1d * end_1d;
215 
216  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  double * Ttmp = (double *)calloc(n_to_write, sizeof(double));
225  double * Tface = (double *)calloc(start_2d, sizeof(double));
226  double * scratch = (double *)calloc(start_1d * end_1d, sizeof(double));
227 
228  auto indices = _nek_mesh->cornerIndices();
229 
230  int c = 0;
231  for (int k = 0; k < bc.total_n_faces; ++k)
232  {
233  if (bc.process[k] == nekrs::commRank())
234  {
235  int i = bc.element[k];
236  int j = bc.face[k];
237  int offset = i * mesh->Nfaces * start_2d + j * start_2d;
238 
239  for (int build = 0; build < _nek_mesh->nBuildPerSurfaceElem(); ++build)
240  {
242  {
243  // get the solution on the face
244  for (int v = 0; v < start_2d; ++v)
245  {
246  int id = mesh->vmapM[offset + v];
247  Tface[v] = f(id, mesh->Nsgeo * (offset + v));
248  }
249 
250  // and then interpolate it
252  scratch, _interpolation_outgoing, Tface, start_1d, &(Ttmp[c]), end_1d);
253  c += end_2d;
254  }
255  else
256  {
257  // get the solution on the face - no need to interpolate
258  for (int v = 0; v < end_2d; ++v, ++c)
259  {
260  int id = mesh->vmapM[offset + indices[build][v]];
261  Ttmp[c] = f(id, mesh->Nsgeo * (offset + v));
262  }
263  }
264  }
265  }
266  }
267 
268  // dimensionalize the solution if needed
269  for (int v = 0; v < n_to_write; ++v)
270  Ttmp[v] =
272 
273  nekrs::allgatherv(bc.mirror_counts, Ttmp, s, end_2d);
274 
275  freePointer(Ttmp);
276  freePointer(Tface);
277  freePointer(scratch);
278  }
279 
290  template <typename T>
291  void writeVolumeSolution(const int elem_id,
292  const T & field,
293  double * s,
294  const std::vector<double> * add = nullptr)
295  {
296  mesh_t * mesh = nekrs::entireMesh();
297  void (*write_solution)(int, dfloat);
298  write_solution = nekrs::solutionWritePointer(field);
299 
300  auto vc = _nek_mesh->volumeCoupling();
301  int id = vc.element[elem_id] * mesh->Np;
302 
303  if (_nek_mesh->exactMirror())
304  {
305  // can write directly into the NekRS solution
306  for (int v = 0; v < mesh->Np; ++v)
307  {
308  double extra = (add == nullptr) ? 0.0 : (*add)[id + v];
309  write_solution(id + v, s[v] + extra);
310  }
311  }
312  else
313  {
314  // need to interpolate onto the higher-order Nek mesh
315  double * tmp = (double *)calloc(mesh->Np, sizeof(double));
316 
317  interpolateVolumeSolutionToNek(elem_id, s, tmp);
318 
319  for (int v = 0; v < mesh->Np; ++v)
320  {
321  double extra = (add == nullptr) ? 0.0 : (*add)[id + v];
322  write_solution(id + v, tmp[v] + extra);
323  }
324 
325  freePointer(tmp);
326  }
327  }
328 
336  template <typename T>
337  void writeBoundarySolution(const int elem_id, const T & field, double * s)
338  {
339  mesh_t * mesh = nekrs::temperatureMesh();
340  void (*write_solution)(int, dfloat);
341  write_solution = nekrs::solutionWritePointer(field);
342 
343  const auto & bc = _nek_mesh->boundaryCoupling();
344  int offset = bc.element[elem_id] * mesh->Nfaces * mesh->Nfp + bc.face[elem_id] * mesh->Nfp;
345 
346  if (_nek_mesh->exactMirror())
347  {
348  // can write directly into the NekRS solution
349  for (int i = 0; i < mesh->Nfp; ++i)
350  write_solution(mesh->vmapM[offset + i], s[i]);
351  }
352  else
353  {
354  // need to interpolate onto the higher-order Nek mesh
355  double * tmp = (double *)calloc(mesh->Nfp, sizeof(double));
357 
358  for (int i = 0; i < mesh->Nfp; ++i)
359  write_solution(mesh->vmapM[offset + i], tmp[i]);
360 
361  freePointer(tmp);
362  }
363  }
364 
369  std::string casename() const { return _casename; }
370 
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 
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 
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:
430  void copyScratchToDevice();
431 
437  void interpolateBoundarySolutionToNek(double * incoming_moose_value, double * outgoing_nek_value);
438 
445  void interpolateVolumeSolutionToNek(const int elem_id,
446  double * incoming_moose_value,
447  double * outgoing_nek_value);
448 
451 
452  std::unique_ptr<NumericVector<Number>> _serialized_solution;
453 
459  std::string fieldFilePrefix(const int & number) const;
460 
462  const std::string & _casename;
463 
478  const bool & _write_fld_files;
479 
482 
485 
494  unsigned int _n_usrwrk_slots;
495 
497  const unsigned int & _constant_interval;
498 
501 
504 
507 
510 
513 
515  double _start_time;
516 
519 
525 
528 
530  Transient * _transient_executioner = nullptr;
531 
537 
540 
542  const PostprocessorValue * _transfer_in = nullptr;
543 
545  double * _interpolation_outgoing = nullptr;
546 
548  double * _interpolation_incoming = nullptr;
549 
552 
554  const std::vector<unsigned int> * _usrwrk_output = nullptr;
555 
557  const std::vector<std::string> * _usrwrk_output_prefix = nullptr;
558 
561 
563  double _elapsedTime;
564 
567 
570 
611 
613  static bool _first;
614 
616  std::vector<FieldTransferBase *> _field_transfers;
617 
619  std::vector<ScalarTransferBase *> _scalar_transfers;
620 
622  std::set<unsigned int> _usrwrk_slots;
623 };
std::string fieldFilePrefix(const int &number) const
synchronization::SynchronizationEnum _sync_interval
When to synchronize the NekRS solution with the mesh mirror.
Definition: NekRSProblem.h:610
const bool & _disable_fld_file_output
Whether to turn off all field file writing.
Definition: NekRSProblem.h:481
virtual bool synchronizeOut()
void(*)(int, dfloat) solutionWritePointer(const field::NekWriteEnum &field)
Definition: NekInterface.h:736
Transient * transientExecutioner() const
Definition: NekRSProblem.h:59
int _n_vertices_per_volume
Number of vertices per volume element of the transfer mesh.
Definition: NekRSProblem.h:512
Definition: NekRSMesh.h:50
NekRSMesh * _nek_mesh
Definition: NekRSProblem.h:524
const NekVolumeCoupling & volumeCoupling() const
Definition: NekRSMesh.h:131
void freePointer(T *ptr)
Definition: CardinalUtils.h:23
void copyScratchToDevice()
Copy the data sent from MOOSE->Nek from host to device.
const NekBoundaryCoupling & boundaryCoupling() const
Definition: NekRSMesh.h:125
int commRank()
bool _is_output_step
Whether the most recent time step was an output file writing step.
Definition: NekRSProblem.h:518
NekTimeStepper * _timestepper
The time stepper used for selection of time step size.
Definition: NekRSProblem.h:527
Transient * _transient_executioner
Underlying executioner.
Definition: NekRSProblem.h:530
double * _interpolation_incoming
Vandermonde interpolation matrix (for incoming transfers)
Definition: NekRSProblem.h:548
virtual void initialSetup() override
const bool & _write_fld_files
Definition: NekRSProblem.h:478
int nBuildPerSurfaceElem() const
Definition: NekRSMesh.h:83
int _n_surface_elems
Number of surface elements in the data transfer mesh, across all processes.
Definition: NekRSProblem.h:503
int _n_vertices_per_surface
Number of vertices per surface element of the transfer mesh.
Definition: NekRSProblem.h:506
void writeVolumeSolution(const int elem_id, const T &field, double *s, const std::vector< double > *add=nullptr)
Definition: NekRSProblem.h:291
Definition: CardinalEnums.h:91
unsigned int _n_usrwrk_slots
Definition: NekRSProblem.h:494
virtual bool converged(unsigned int) override
Definition: NekRSProblem.h:95
Real nondimensionalAdditive(const field::NekFieldEnum &field)
bool _nondimensional
Whether a dimensionalization action has been added.
Definition: NekRSProblem.h:484
double(*)(int, int) solutionPointer(const field::NekFieldEnum &field)
Definition: NekInterface.h:729
void copyIndividualScratchSlot(const unsigned int &slot) const
virtual bool synchronizeIn()
std::vector< ScalarTransferBase * > _scalar_transfers
All of the ScalarTransfer objecst which pass data in/out of NekRS.
Definition: NekRSProblem.h:619
void interpolateSurfaceFaceHex3D(double *scratch, const double *I, double *x, int N, double *Ix, int M)
virtual bool nondimensional() const
Definition: NekRSProblem.h:105
virtual void externalSolve() override
void interpolateVolumeSolutionToNek(const int elem_id, double *incoming_moose_value, double *outgoing_nek_value)
void mapVolumeDataToNekVolume(const unsigned int &e, const unsigned int &var_num, const Real &divisor, const Real &additive, double **outgoing_data)
virtual bool isOutputStep() const
Whether nekRS should write an output file for the current time step.
SynchronizationEnum
Definition: CardinalEnums.h:64
double _tSolveStepMax
Maximum step solve time.
Definition: NekRSProblem.h:569
const std::vector< std::string > * _usrwrk_output_prefix
Filename prefix to use for naming the field files containing the nrs->o_usrwrk array slots.
Definition: NekRSProblem.h:557
std::vector< int > element
Definition: NekVolumeCoupling.h:40
double _elapsedTime
Sum of the total elapsed time in NekRS solves.
Definition: NekRSProblem.h:563
Definition: CardinalProblem.h:26
int _n_points
Number of points for interpolated fields on the MOOSE mesh.
Definition: NekRSProblem.h:539
const unsigned int & _constant_interval
For constant synchronization intervals, the desired frequency (in units of Nek time steps)
Definition: NekRSProblem.h:497
double _elapsedStepSum
Sum of the elapsed time in NekRS solves.
Definition: NekRSProblem.h:560
void allgatherv(const std::vector< int > &base_counts, const T *input, T *output, const int multiplier=1)
Definition: NekInterface.h:987
static bool _first
flag to indicate whether this is the first pass to serialize the solution
Definition: NekRSProblem.h:613
void mapFaceDataToNekFace(const unsigned int &e, const unsigned int &var_num, const Real &divisor, const Real &additive, double **outgoing_data)
int _moose_Nq
For the MOOSE mesh, the number of quadrature points in each coordinate direction.
Definition: NekRSProblem.h:551
int nBuildPerVolumeElem() const
Definition: NekRSMesh.h:77
unsigned int nUsrWrkSlots() const
Definition: NekRSProblem.h:129
mesh_t * temperatureMesh()
bool isDataTransferHappening(ExternalProblem::Direction direction)
void writeBoundarySolution(const int elem_id, const T &field, double *s)
Definition: NekRSProblem.h:337
void mapFaceDataToNekVolume(const unsigned int &e, const unsigned int &var_num, const Real &divisor, const Real &additive, double **outgoing_data)
Map nodal points on a MOOSE face element to the GLL points on a Nek volume element.
const std::string & _casename
NekRS casename.
Definition: NekRSProblem.h:462
bool isUsrWrkSlotReservedForCoupling(const unsigned int &slot) const
Solve nekRS wrapped as a MOOSE app.
Definition: NekRSProblem.h:36
void boundarySolution(const T &field, double *s)
Definition: NekRSProblem.h:203
Real nondimensionalDivisor(const field::NekFieldEnum &field)
Return the reference divisor scale that defines the non-dimensional field.
static InputParameters validParams()
const bool & _skip_final_field_file
Whether to skip writing a field file on NekRS's last time steo.
Definition: NekRSProblem.h:500
const std::vector< unsigned int > * _usrwrk_output
Slots in the nrs->o_usrwrk array to write to a field file.
Definition: NekRSProblem.h:554
int _n_volume_elems
Number of volume elements in the data transfer mesh, across all processes.
Definition: NekRSProblem.h:509
void initializeInterpolationMatrices()
Initialize interpolation matrices for transfers in/out of nekRS.
virtual void addExternalVariables() override
NekRSProblem(const InputParameters &params)
Definition: FieldTransferBase.h:28
int nPoints() const
Definition: NekRSProblem.h:50
double * _interpolation_outgoing
Vandermonde interpolation matrix (for outgoing transfers)
Definition: NekRSProblem.h:545
std::vector< std::vector< int > > cornerIndices() const
Definition: NekRSMesh.h:308
Definition: CardinalEnums.h:286
std::unique_ptr< NumericVector< Number > > _serialized_solution
Definition: NekRSProblem.h:452
double _tSolveStepMin
Minimum step solve time.
Definition: NekRSProblem.h:566
void writeFieldFile(const Real &time, const int &step) const
void volumeSolution(const T &field, double *s)
Definition: NekRSProblem.h:137
std::vector< FieldTransferBase * > _field_transfers
All of the FieldTransfer objects which pass data in/out of NekRS.
Definition: NekRSProblem.h:616
virtual void syncSolutions(ExternalProblem::Direction direction) override
const PostprocessorValue * _transfer_in
Postprocessor containing the signal of when a synchronization has occurred.
Definition: NekRSProblem.h:542
double _start_time
Start time of the simulation based on NekRS's .par file.
Definition: NekRSProblem.h:515
bool exactMirror() const
Definition: NekRSMesh.h:302
void interpolateVolumeHex3D(const double *I, double *x, int N, double *Ix, int M)
void interpolateBoundarySolutionToNek(double *incoming_moose_value, double *outgoing_nek_value)
std::vector< int > element
Definition: NekBoundaryCoupling.h:40
Time stepper that reads time step information directly from nekRS.
Definition: NekTimeStepper.h:37
std::set< unsigned int > _usrwrk_slots
Usrwrk slots managed by Cardinal.
Definition: NekRSProblem.h:622
std::string casename() const
Definition: NekRSProblem.h:369
mesh_t * entireMesh()
virtual const bool hasMovingNekMesh() const
Definition: NekRSProblem.h:111
bool _needs_interpolation
Definition: NekRSProblem.h:536