Nektar++
CompressibleFlowSystem.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: CompressibleFlowSystem.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Compressible flow system base class with auxiliary functions
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <boost/core/ignore_unused.hpp>
36 
38 
40 
41 using namespace std;
42 
43 namespace Nektar
44 {
45 CompressibleFlowSystem::CompressibleFlowSystem(
48  : UnsteadySystem(pSession, pGraph), AdvectionSystem(pSession, pGraph)
49 {
50 }
51 
52 /**
53  * @brief Initialization object for CompressibleFlowSystem class.
54  */
55 void CompressibleFlowSystem::v_InitObject(bool DeclareFields)
56 {
57  AdvectionSystem::v_InitObject(DeclareFields);
58 
59  for (size_t i = 0; i < m_fields.size(); i++)
60  {
61  // Use BwdTrans to make sure initial condition is in solution space
62  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
63  m_fields[i]->UpdatePhys());
64  }
65 
68 
69  ASSERTL0(m_session->DefinesSolverInfo("UPWINDTYPE"),
70  "No UPWINDTYPE defined in session.");
71 
72  // Do not forwards transform initial condition
73  m_homoInitialFwd = false;
74 
75  // Set up locations of velocity vector.
78  for (int i = 0; i < m_spacedim; ++i)
79  {
80  m_vecLocs[0][i] = 1 + i;
81  }
82 
83  // Loading parameters from session file
85 
86  // Setting up advection and diffusion operators
87  InitAdvection();
88 
89  // Create artificial diffusion with laplacian operator
90  if (m_shockCaptureType == "NonSmooth")
91  {
94  }
95 
96  // Forcing terms for the sponge region
97  m_forcing = SolverUtils::Forcing::Load(m_session, shared_from_this(),
98  m_fields, m_fields.size());
99 
100  // User-defined boundary conditions
101  size_t cnt = 0;
102  for (size_t n = 0; n < (size_t)m_fields[0]->GetBndConditions().size(); ++n)
103  {
104  std::string type = m_fields[0]->GetBndConditions()[n]->GetUserDefined();
105 
106  if (m_fields[0]->GetBndConditions()[n]->GetBoundaryConditionType() ==
108  {
109  continue;
110  }
111 
112  if (!type.empty())
113  {
115  type, m_session, m_fields, m_traceNormals, m_spacedim, n, cnt));
116  }
117  cnt += m_fields[0]->GetBndCondExpansions()[n]->GetExpSize();
118  }
119 
122 
124 }
125 
126 /**
127  * @brief Destructor for CompressibleFlowSystem class.
128  */
130 {
131 }
132 
133 /**
134  * @brief Load CFS parameters from the session file
135  */
137 {
138  // Get gamma parameter from session file.
139  m_session->LoadParameter("Gamma", m_gamma, 1.4);
140 
141  // Shock capture
142  m_session->LoadSolverInfo("ShockCaptureType", m_shockCaptureType, "Off");
143 
144  // Check if the shock capture type is supported
145  std::string err_msg = "Warning, ShockCaptureType = " + m_shockCaptureType +
146  " is not supported by this solver";
148 
149  // Load parameters for exponential filtering
150  m_session->MatchSolverInfo("ExponentialFiltering", "True", m_useFiltering,
151  false);
152  if (m_useFiltering)
153  {
154  m_session->LoadParameter("FilterAlpha", m_filterAlpha, 36);
155  m_session->LoadParameter("FilterExponent", m_filterExponent, 16);
156  m_session->LoadParameter("FilterCutoff", m_filterCutoff, 0);
157  }
158 
159  // Load CFL for local time-stepping (for steady state)
160  m_session->MatchSolverInfo("LocalTimeStep", "True", m_useLocalTimeStep,
161  false);
162  if (m_useLocalTimeStep)
163  {
165  "Local time stepping requires CFL parameter.");
166  }
167 }
168 
169 /**
170  * @brief Create advection and diffusion objects for CFS
171  */
173 {
174  // Check if projection type is correct
176  "Unsupported projection type.");
177 
178  string advName, riemName;
179  m_session->LoadSolverInfo("AdvectionType", advName, "WeakDG");
180 
181  m_advObject =
183 
185  {
186  m_advObject->SetFluxVector(
188  }
189  else
190  {
192  this);
193  }
194 
195  // Setting up Riemann solver for advection operator
196  m_session->LoadSolverInfo("UpwindType", riemName, "Average");
197 
200  riemName, m_session);
201 
202  // Setting up parameters for advection operator Riemann solver
203  riemannSolver->SetParam("gamma", &CompressibleFlowSystem::GetGamma, this);
204  riemannSolver->SetAuxVec("vecLocs", &CompressibleFlowSystem::GetVecLocs,
205  this);
206  riemannSolver->SetVector("N", &CompressibleFlowSystem::GetNormals, this);
207 
208  // Concluding initialisation of advection / diffusion operators
209  m_advObject->SetRiemannSolver(riemannSolver);
210  m_advObject->InitObject(m_session, m_fields);
211 }
212 
213 /**
214  * @brief Compute the right-hand side.
215  */
217  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
218  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
219 {
220  size_t nvariables = inarray.size();
221  size_t npoints = GetNpoints();
222  size_t nTracePts = GetTraceTotPoints();
223 
224  m_bndEvaluateTime = time;
225 
226  // Store forwards/backwards space along trace space
227  Array<OneD, Array<OneD, NekDouble>> Fwd(nvariables);
228  Array<OneD, Array<OneD, NekDouble>> Bwd(nvariables);
229 
231  {
234  }
235  else
236  {
237  for (size_t i = 0; i < nvariables; ++i)
238  {
239  Fwd[i] = Array<OneD, NekDouble>(nTracePts, 0.0);
240  Bwd[i] = Array<OneD, NekDouble>(nTracePts, 0.0);
241  m_fields[i]->GetFwdBwdTracePhys(inarray[i], Fwd[i], Bwd[i]);
242  }
243  }
244 
245  // Calculate advection
246  LibUtilities::Timer timer;
247  timer.Start();
248  DoAdvection(inarray, outarray, time, Fwd, Bwd);
249  timer.Stop();
250  timer.AccumulateRegion("DoAdvection");
251 
252  // Negate results
253  for (size_t i = 0; i < nvariables; ++i)
254  {
255  Vmath::Neg(npoints, outarray[i], 1);
256  }
257 
258  // Add diffusion terms
259  timer.Start();
260  DoDiffusion(inarray, outarray, Fwd, Bwd);
261  timer.Stop();
262  timer.AccumulateRegion("DoDiffusion");
263 
264  // Add forcing terms
265  for (auto &x : m_forcing)
266  {
267  x->Apply(m_fields, inarray, outarray, time);
268  }
269 
270  if (m_useLocalTimeStep)
271  {
272  size_t nElements = m_fields[0]->GetExpSize();
273  int nq, offset;
274  NekDouble fac;
276 
277  Array<OneD, NekDouble> tstep(nElements, 0.0);
278  GetElmtTimeStep(inarray, tstep);
279 
280  // Loop over elements
281  for (size_t n = 0; n < nElements; ++n)
282  {
283  nq = m_fields[0]->GetExp(n)->GetTotPoints();
284  offset = m_fields[0]->GetPhys_Offset(n);
285  fac = tstep[n] / m_timestep;
286  for (size_t i = 0; i < nvariables; ++i)
287  {
288  Vmath::Smul(nq, fac, outarray[i] + offset, 1,
289  tmp = outarray[i] + offset, 1);
290  }
291  }
292  }
293 }
294 
295 /**
296  * @brief Compute the projection and call the method for imposing the
297  * boundary conditions in case of discontinuous projection.
298  */
300  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
301  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
302 {
303  size_t nvariables = inarray.size();
304 
305  switch (m_projectionType)
306  {
308  {
309  // Just copy over array
310  int npoints = GetNpoints();
311 
312  for (size_t i = 0; i < nvariables; ++i)
313  {
314  Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
315  if (m_useFiltering)
316  {
317  m_fields[i]->ExponentialFilter(outarray[i], m_filterAlpha,
320  }
321  }
322  SetBoundaryConditions(outarray, time);
323  break;
324  }
327  {
328  NEKERROR(ErrorUtil::efatal, "No Continuous Galerkin for full "
329  "compressible Navier-Stokes equations");
330  break;
331  }
332  default:
333  NEKERROR(ErrorUtil::efatal, "Unknown projection scheme");
334  break;
335  }
336 }
337 
338 /**
339  * @brief Compute the advection terms for the right-hand side
340  */
342  const Array<OneD, Array<OneD, NekDouble>> &inarray,
343  Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time,
344  const Array<OneD, Array<OneD, NekDouble>> &pFwd,
345  const Array<OneD, Array<OneD, NekDouble>> &pBwd)
346 {
347  int nvariables = inarray.size();
349 
350  m_advObject->Advect(nvariables, m_fields, advVel, inarray, outarray, time,
351  pFwd, pBwd);
352 }
353 
354 /**
355  * @brief Add the diffusions terms to the right-hand side
356  */
358  const Array<OneD, Array<OneD, NekDouble>> &inarray,
359  Array<OneD, Array<OneD, NekDouble>> &outarray,
360  const Array<OneD, Array<OneD, NekDouble>> &pFwd,
361  const Array<OneD, Array<OneD, NekDouble>> &pBwd)
362 {
363  v_DoDiffusion(inarray, outarray, pFwd, pBwd);
364 }
365 
367  Array<OneD, Array<OneD, NekDouble>> &physarray, NekDouble time)
368 {
369  size_t nTracePts = GetTraceTotPoints();
370  size_t nvariables = physarray.size();
371 
372  Array<OneD, Array<OneD, NekDouble>> Fwd(nvariables);
373  for (size_t i = 0; i < nvariables; ++i)
374  {
375  Fwd[i] = Array<OneD, NekDouble>(nTracePts);
376  m_fields[i]->ExtractTracePhys(physarray[i], Fwd[i]);
377  }
378 
379  if (m_bndConds.size())
380  {
381  // Loop over user-defined boundary conditions
382  for (auto &x : m_bndConds)
383  {
384  x->Apply(Fwd, physarray, time);
385  }
386  }
387 }
388 /**
389  * @brief Set up a weight on physical boundaries for boundary condition
390  * applications
391  */
393 {
394  if (m_bndConds.size())
395  {
396  // Loop over user-defined boundary conditions
397  for (auto &x : m_bndConds)
398  {
399  x->ApplyBwdWeight();
400  }
401  }
402 }
403 
404 /**
405  * @brief Return the flux vector for the compressible Euler equations.
406  *
407  * @param physfield Fields.
408  * @param flux Resulting flux.
409  */
411  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
413 {
414  size_t nVariables = physfield.size();
415  size_t nPts = physfield[0].size();
416 
417  constexpr unsigned short maxVel = 3;
418  constexpr unsigned short maxFld = 5;
419 
420  // hardcoding done for performance reasons
421  ASSERTL1(nVariables <= maxFld, "GetFluxVector, hard coded max fields");
422 
423  for (size_t p = 0; p < nPts; ++p)
424  {
425  // local storage
426  std::array<NekDouble, maxFld> fieldTmp;
427  std::array<NekDouble, maxVel> velocity;
428 
429  // rearrenge and load data
430  for (size_t f = 0; f < nVariables; ++f)
431  {
432  fieldTmp[f] = physfield[f][p]; // load
433  }
434 
435  // 1 / rho
436  NekDouble oneOrho = 1.0 / fieldTmp[0];
437 
438  for (size_t d = 0; d < m_spacedim; ++d)
439  {
440  // Flux vector for the rho equation
441  flux[0][d][p] = fieldTmp[d + 1]; // store
442  // compute velocity
443  velocity[d] = fieldTmp[d + 1] * oneOrho;
444  }
445 
446  NekDouble pressure = m_varConv->GetPressure(fieldTmp.data());
447  NekDouble ePlusP = fieldTmp[m_spacedim + 1] + pressure;
448  for (size_t f = 0; f < m_spacedim; ++f)
449  {
450  // Flux vector for the velocity fields
451  for (size_t d = 0; d < m_spacedim; ++d)
452  {
453  flux[f + 1][d][p] = velocity[d] * fieldTmp[f + 1]; // store
454  }
455 
456  // Add pressure to appropriate field
457  flux[f + 1][f][p] += pressure;
458 
459  // Flux vector for energy
460  flux[m_spacedim + 1][f][p] = ePlusP * velocity[f]; // store
461  }
462  }
463 }
464 
465 /**
466  * @brief Return the flux vector for the compressible Euler equations
467  * by using the de-aliasing technique.
468  *
469  * @param physfield Fields.
470  * @param flux Resulting flux.
471  */
473  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
475 {
476  int i, j;
477  size_t nq = physfield[0].size();
478  size_t nVariables = m_fields.size();
479 
480  // Factor to rescale 1d points in dealiasing
481  NekDouble OneDptscale = 2;
482  nq = m_fields[0]->Get1DScaledTotPoints(OneDptscale);
483 
486 
487  Array<OneD, Array<OneD, NekDouble>> physfield_interp(nVariables);
488  TensorOfArray3D<NekDouble> flux_interp(nVariables);
489 
490  for (size_t i = 0; i < nVariables; ++i)
491  {
492  physfield_interp[i] = Array<OneD, NekDouble>(nq);
494  m_fields[0]->PhysInterp1DScaled(OneDptscale, physfield[i],
495  physfield_interp[i]);
496 
497  for (j = 0; j < m_spacedim; ++j)
498  {
499  flux_interp[i][j] = Array<OneD, NekDouble>(nq);
500  }
501  }
502 
503  // Flux vector for the rho equation
504  for (i = 0; i < m_spacedim; ++i)
505  {
506  velocity[i] = Array<OneD, NekDouble>(nq);
507 
508  // Galerkin project solution back to original space
509  m_fields[0]->PhysGalerkinProjection1DScaled(
510  OneDptscale, physfield_interp[i + 1], flux[0][i]);
511  }
512 
513  m_varConv->GetVelocityVector(physfield_interp, velocity);
514  m_varConv->GetPressure(physfield_interp, pressure);
515 
516  // Evaluation of flux vector for the velocity fields
517  for (i = 0; i < m_spacedim; ++i)
518  {
519  for (j = 0; j < m_spacedim; ++j)
520  {
521  Vmath::Vmul(nq, velocity[j], 1, physfield_interp[i + 1], 1,
522  flux_interp[i + 1][j], 1);
523  }
524 
525  // Add pressure to appropriate field
526  Vmath::Vadd(nq, flux_interp[i + 1][i], 1, pressure, 1,
527  flux_interp[i + 1][i], 1);
528  }
529 
530  // Galerkin project solution back to original space
531  for (i = 0; i < m_spacedim; ++i)
532  {
533  for (j = 0; j < m_spacedim; ++j)
534  {
535  m_fields[0]->PhysGalerkinProjection1DScaled(
536  OneDptscale, flux_interp[i + 1][j], flux[i + 1][j]);
537  }
538  }
539 
540  // Evaluation of flux vector for energy
541  Vmath::Vadd(nq, physfield_interp[m_spacedim + 1], 1, pressure, 1, pressure,
542  1);
543 
544  for (j = 0; j < m_spacedim; ++j)
545  {
546  Vmath::Vmul(nq, velocity[j], 1, pressure, 1,
547  flux_interp[m_spacedim + 1][j], 1);
548 
549  // Galerkin project solution back to original space
550  m_fields[0]->PhysGalerkinProjection1DScaled(
551  OneDptscale, flux_interp[m_spacedim + 1][j],
552  flux[m_spacedim + 1][j]);
553  }
554 }
555 
556 /**
557  * @brief Calculate the maximum timestep on each element
558  * subject to CFL restrictions.
559  */
561  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
562  Array<OneD, NekDouble> &tstep)
563 {
564  boost::ignore_unused(inarray);
565 
566  size_t nElements = m_fields[0]->GetExpSize();
567 
568  // Change value of m_timestep (in case it is set to zero)
569  NekDouble tmp = m_timestep;
570  m_timestep = 1.0;
571 
572  Array<OneD, NekDouble> cfl(nElements);
573  cfl = GetElmtCFLVals();
574 
575  // Factors to compute the time-step limit
577 
578  // Loop over elements to compute the time-step limit for each element
579  for (size_t n = 0; n < nElements; ++n)
580  {
581  tstep[n] = m_cflSafetyFactor * alpha / cfl[n];
582  }
583 
584  // Restore value of m_timestep
585  m_timestep = tmp;
586 }
587 
588 /**
589  * @brief Calculate the maximum timestep subject to CFL restrictions.
590  */
592  const Array<OneD, const Array<OneD, NekDouble>> &inarray)
593 {
594  int nElements = m_fields[0]->GetExpSize();
595  Array<OneD, NekDouble> tstep(nElements, 0.0);
596 
597  GetElmtTimeStep(inarray, tstep);
598 
599  // Get the minimum time-step limit and return the time-step
600  NekDouble TimeStep = Vmath::Vmin(nElements, tstep, 1);
601  m_comm->AllReduce(TimeStep, LibUtilities::ReduceMin);
602 
603  NekDouble tmp = m_timestep;
604  m_timestep = TimeStep;
605 
606  Array<OneD, NekDouble> cflNonAcoustic(nElements, 0.0);
607  cflNonAcoustic = GetElmtCFLVals(false);
608 
609  // Get the minimum time-step limit and return the time-step
610  NekDouble MaxcflNonAcoustic = Vmath::Vmax(nElements, cflNonAcoustic, 1);
611  m_comm->AllReduce(MaxcflNonAcoustic, LibUtilities::ReduceMax);
612 
613  m_cflNonAcoustic = MaxcflNonAcoustic;
614  m_timestep = tmp;
615 
616  return TimeStep;
617 }
618 
619 /**
620  * @brief Set up logic for residual calculation.
621  */
623  bool dumpInitialConditions,
624  const int domain)
625 {
626  boost::ignore_unused(domain);
627 
628  EquationSystem::v_SetInitialConditions(initialtime, false);
629 
630  // insert white noise in initial condition
631  NekDouble Noise;
632  int phystot = m_fields[0]->GetTotPoints();
633  Array<OneD, NekDouble> noise(phystot);
634 
635  m_session->LoadParameter("Noise", Noise, 0.0);
636  int m_nConvectiveFields = m_fields.size();
637 
638  if (Noise > 0.0)
639  {
640  int seed = -m_comm->GetRank() * m_nConvectiveFields;
641  for (int i = 0; i < m_nConvectiveFields; i++)
642  {
643  Vmath::FillWhiteNoise(phystot, Noise, noise, 1, seed);
644  --seed;
645  Vmath::Vadd(phystot, m_fields[i]->GetPhys(), 1, noise, 1,
646  m_fields[i]->UpdatePhys(), 1);
647  m_fields[i]->FwdTransLocalElmt(m_fields[i]->GetPhys(),
648  m_fields[i]->UpdateCoeffs());
649  }
650  }
651 
652  if (dumpInitialConditions && m_checksteps && !ParallelInTime())
653  {
655  m_nchk++;
656  }
657  else if (dumpInitialConditions && m_useInitialCondition && m_nchk == 0 &&
658  ParallelInTime())
659  {
660  std::string newdir = m_sessionName + ".pit";
661  if (!fs::is_directory(newdir))
662  {
663  fs::create_directory(newdir);
664  }
665  if (m_comm->GetTimeComm()->GetRank() == 0)
666  {
667  WriteFld(newdir + "/" + m_sessionName + "_0.fld");
668  }
669  m_nchk++;
670  }
671 }
672 
673 /**
674  * @brief Compute the advection velocity in the standard space
675  * for each element of the expansion.
676  */
678  const NekDouble SpeedSoundFactor)
679 {
680  size_t nTotQuadPoints = GetTotPoints();
681  size_t n_element = m_fields[0]->GetExpSize();
682  size_t expdim = m_fields[0]->GetGraph()->GetMeshDimension();
683  size_t nfields = m_fields.size();
684  int offset;
686 
687  Array<OneD, Array<OneD, NekDouble>> physfields(nfields);
688  for (size_t i = 0; i < nfields; ++i)
689  {
690  physfields[i] = m_fields[i]->GetPhys();
691  }
692 
693  Array<OneD, NekDouble> stdV(n_element, 0.0);
694 
695  // Getting the velocity vector on the 2D normal space
699  Array<OneD, NekDouble> soundspeed(nTotQuadPoints);
701 
702  for (int i = 0; i < m_spacedim; ++i)
703  {
704  velocity[i] = Array<OneD, NekDouble>(nTotQuadPoints);
705  stdVelocity[i] = Array<OneD, NekDouble>(nTotQuadPoints, 0.0);
706  stdSoundSpeed[i] = Array<OneD, NekDouble>(nTotQuadPoints, 0.0);
707  }
708 
709  m_varConv->GetVelocityVector(physfields, velocity);
710  m_varConv->GetSoundSpeed(physfields, soundspeed);
711 
712  for (size_t el = 0; el < n_element; ++el)
713  {
714  ptsKeys = m_fields[0]->GetExp(el)->GetPointsKeys();
715  offset = m_fields[0]->GetPhys_Offset(el);
716  int nq = m_fields[0]->GetExp(el)->GetTotPoints();
717 
718  const SpatialDomains::GeomFactorsSharedPtr metricInfo =
719  m_fields[0]->GetExp(el)->GetGeom()->GetMetricInfo();
720  const Array<TwoD, const NekDouble> &gmat =
721  m_fields[0]
722  ->GetExp(el)
723  ->GetGeom()
724  ->GetMetricInfo()
725  ->GetDerivFactors(ptsKeys);
726 
727  // Convert to standard element
728  // consider soundspeed in all directions
729  // (this might overestimate the cfl)
730  if (metricInfo->GetGtype() == SpatialDomains::eDeformed)
731  {
732  // d xi/ dx = gmat = 1/J * d x/d xi
733  for (size_t i = 0; i < expdim; ++i)
734  {
735  Vmath::Vmul(nq, gmat[i], 1, velocity[0] + offset, 1,
736  tmp = stdVelocity[i] + offset, 1);
737  Vmath::Vmul(nq, gmat[i], 1, soundspeed + offset, 1,
738  tmp = stdSoundSpeed[i] + offset, 1);
739  for (size_t j = 1; j < expdim; ++j)
740  {
741  Vmath::Vvtvp(nq, gmat[expdim * j + i], 1,
742  velocity[j] + offset, 1,
743  stdVelocity[i] + offset, 1,
744  tmp = stdVelocity[i] + offset, 1);
745  Vmath::Vvtvp(nq, gmat[expdim * j + i], 1,
746  soundspeed + offset, 1,
747  stdSoundSpeed[i] + offset, 1,
748  tmp = stdSoundSpeed[i] + offset, 1);
749  }
750  }
751  }
752  else
753  {
754  for (size_t i = 0; i < expdim; ++i)
755  {
756  Vmath::Smul(nq, gmat[i][0], velocity[0] + offset, 1,
757  tmp = stdVelocity[i] + offset, 1);
758  Vmath::Smul(nq, gmat[i][0], soundspeed + offset, 1,
759  tmp = stdSoundSpeed[i] + offset, 1);
760  for (size_t j = 1; j < expdim; ++j)
761  {
762  Vmath::Svtvp(nq, gmat[expdim * j + i][0],
763  velocity[j] + offset, 1,
764  stdVelocity[i] + offset, 1,
765  tmp = stdVelocity[i] + offset, 1);
766  Vmath::Svtvp(nq, gmat[expdim * j + i][0],
767  soundspeed + offset, 1,
768  stdSoundSpeed[i] + offset, 1,
769  tmp = stdSoundSpeed[i] + offset, 1);
770  }
771  }
772  }
773 
774  NekDouble vel;
775  for (size_t i = 0; i < nq; ++i)
776  {
777  NekDouble pntVelocity = 0.0;
778  for (size_t j = 0; j < expdim; ++j)
779  {
780  // Add sound speed
781  vel = std::abs(stdVelocity[j][offset + i]) +
782  SpeedSoundFactor * std::abs(stdSoundSpeed[j][offset + i]);
783  pntVelocity += vel * vel;
784  }
785  pntVelocity = sqrt(pntVelocity);
786  if (pntVelocity > stdV[el])
787  {
788  stdV[el] = pntVelocity;
789  }
790  }
791  }
792 
793  return stdV;
794 }
795 
796 /**
797  * @brief Set the denominator to compute the time step when a cfl
798  * control is employed. This function is no longer used but is still
799  * here for being utilised in the future.
800  *
801  * @param n Order of expansion element by element.
802  */
804 {
805  ASSERTL0(n <= 20, "Illegal modes dimension for CFL calculation "
806  "(P has to be less then 20)");
807 
808  NekDouble CFLDG[21] = {2.0000, 6.0000, 11.8424, 19.1569, 27.8419,
809  37.8247, 49.0518, 61.4815, 75.0797, 89.8181,
810  105.6700, 122.6200, 140.6400, 159.7300, 179.8500,
811  201.0100, 223.1800, 246.3600, 270.5300, 295.6900,
812  321.8300}; // CFLDG 1D [0-20]
813  NekDouble CFL = 0.0;
814 
816  {
817  CFL = CFLDG[n];
818  }
819  else
820  {
821  NEKERROR(ErrorUtil::efatal, "Continuous Galerkin stability "
822  "coefficients not introduced yet.");
823  }
824 
825  return CFL;
826 }
827 
828 /**
829  * @brief Compute the vector of denominators to compute the time step
830  * when a cfl control is employed. This function is no longer used but
831  * is still here for being utilised in the future.
832  *
833  * @param ExpOrder Order of expansion element by element.
834  */
836  const Array<OneD, int> &ExpOrder)
837 {
838  int i;
839  Array<OneD, NekDouble> returnval(m_fields[0]->GetExpSize(), 0.0);
840  for (i = 0; i < m_fields[0]->GetExpSize(); i++)
841  {
842  returnval[i] = GetStabilityLimit(ExpOrder[i]);
843  }
844  return returnval;
845 }
846 
848  std::vector<Array<OneD, NekDouble>> &fieldcoeffs,
849  std::vector<std::string> &variables)
850 {
851  bool extraFields;
852  m_session->MatchSolverInfo("OutputExtraFields", "True", extraFields, true);
853  if (extraFields)
854  {
855  const int nPhys = m_fields[0]->GetNpoints();
856  const int nCoeffs = m_fields[0]->GetNcoeffs();
858 
859  for (int i = 0; i < m_fields.size(); ++i)
860  {
861  tmp[i] = m_fields[i]->GetPhys();
862  }
863 
866  for (int i = 0; i < m_spacedim; ++i)
867  {
868  velocity[i] = Array<OneD, NekDouble>(nPhys);
869  velFwd[i] = Array<OneD, NekDouble>(nCoeffs);
870  }
871 
872  Array<OneD, NekDouble> pressure(nPhys), temperature(nPhys);
873  Array<OneD, NekDouble> entropy(nPhys);
874  Array<OneD, NekDouble> soundspeed(nPhys), mach(nPhys);
875  Array<OneD, NekDouble> sensor(nPhys), SensorKappa(nPhys);
876 
877  m_varConv->GetVelocityVector(tmp, velocity);
878  m_varConv->GetPressure(tmp, pressure);
879  m_varConv->GetTemperature(tmp, temperature);
880  m_varConv->GetEntropy(tmp, entropy);
881  m_varConv->GetSoundSpeed(tmp, soundspeed);
882  m_varConv->GetMach(tmp, soundspeed, mach);
883 
884  int sensorOffset;
885  m_session->LoadParameter("SensorOffset", sensorOffset, 1);
886  m_varConv->GetSensor(m_fields[0], tmp, sensor, SensorKappa,
887  sensorOffset);
888 
889  Array<OneD, NekDouble> pFwd(nCoeffs), TFwd(nCoeffs);
890  Array<OneD, NekDouble> sFwd(nCoeffs);
891  Array<OneD, NekDouble> aFwd(nCoeffs), mFwd(nCoeffs);
892  Array<OneD, NekDouble> sensFwd(nCoeffs);
893 
894  string velNames[3] = {"u", "v", "w"};
895  for (int i = 0; i < m_spacedim; ++i)
896  {
897  m_fields[0]->FwdTransLocalElmt(velocity[i], velFwd[i]);
898  variables.push_back(velNames[i]);
899  fieldcoeffs.push_back(velFwd[i]);
900  }
901 
902  m_fields[0]->FwdTransLocalElmt(pressure, pFwd);
903  m_fields[0]->FwdTransLocalElmt(temperature, TFwd);
904  m_fields[0]->FwdTransLocalElmt(entropy, sFwd);
905  m_fields[0]->FwdTransLocalElmt(soundspeed, aFwd);
906  m_fields[0]->FwdTransLocalElmt(mach, mFwd);
907  m_fields[0]->FwdTransLocalElmt(sensor, sensFwd);
908 
909  variables.push_back("p");
910  variables.push_back("T");
911  variables.push_back("s");
912  variables.push_back("a");
913  variables.push_back("Mach");
914  variables.push_back("Sensor");
915  fieldcoeffs.push_back(pFwd);
916  fieldcoeffs.push_back(TFwd);
917  fieldcoeffs.push_back(sFwd);
918  fieldcoeffs.push_back(aFwd);
919  fieldcoeffs.push_back(mFwd);
920  fieldcoeffs.push_back(sensFwd);
921 
923  {
924  // reuse pressure
925  Array<OneD, NekDouble> sensorFwd(nCoeffs);
926  m_artificialDiffusion->GetArtificialViscosity(tmp, pressure);
927  m_fields[0]->FwdTransLocalElmt(pressure, sensorFwd);
928 
929  variables.push_back("ArtificialVisc");
930  fieldcoeffs.push_back(sensorFwd);
931  }
932  }
933 }
934 
935 /**
936  *
937  */
939  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
941 {
942  m_varConv->GetPressure(physfield, pressure);
943 }
944 
945 /**
946  *
947  */
949  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
950  Array<OneD, NekDouble> &density)
951 {
952  density = physfield[0];
953 }
954 
955 /**
956  *
957  */
959  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
960  Array<OneD, Array<OneD, NekDouble>> &velocity)
961 {
962  m_varConv->GetVelocityVector(physfield, velocity);
963 }
964 
967 {
968  boost::ignore_unused(step);
969  const size_t nPoints = GetTotPoints();
970  const size_t nFields = m_fields.size();
972  Array<OneD, Array<OneD, NekDouble>> inarray(nFields);
973  for (size_t i = 0; i < nFields; ++i)
974  {
975  rhs[i] = Array<OneD, NekDouble>(nPoints, 0.0);
976  inarray[i] = m_fields[i]->UpdatePhys();
977  }
978 
979  DoOdeRhs(inarray, rhs, m_time);
980 
981  // Holds L2 errors.
983  Array<OneD, NekDouble> RHSL2(nFields);
984  Array<OneD, NekDouble> residual(nFields);
985 
986  for (size_t i = 0; i < nFields; ++i)
987  {
988  tmp = rhs[i];
989 
990  Vmath::Vmul(nPoints, tmp, 1, tmp, 1, tmp, 1);
991  residual[i] = Vmath::Vsum(nPoints, tmp, 1);
992  }
993 
994  m_comm->AllReduce(residual, LibUtilities::ReduceSum);
995 
996  NekDouble onPoints = 1.0 / NekDouble(nPoints);
997  for (size_t i = 0; i < nFields; ++i)
998  {
999  L2[i] = sqrt(residual[i] * onPoints);
1000  }
1001 }
1002 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
virtual void v_DoDiffusion(const Array< OneD, Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const Array< OneD, Array< OneD, NekDouble >> &pFwd, const Array< OneD, Array< OneD, NekDouble >> &pBwd)=0
virtual MultiRegions::ExpListSharedPtr v_GetPressure() override
virtual NekDouble v_GetTimeStep(const Array< OneD, const Array< OneD, NekDouble >> &inarray) override
Calculate the maximum timestep subject to CFL restrictions.
void DoAdvection(const Array< OneD, Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time, const Array< OneD, Array< OneD, NekDouble >> &pFwd, const Array< OneD, Array< OneD, NekDouble >> &pBwd)
Compute the advection terms for the right-hand side.
virtual void v_GetVelocity(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, Array< OneD, NekDouble >> &velocity) override
void DoOdeRhs(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time)
Compute the right-hand side.
virtual void v_GetDensity(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &density) override
void DoDiffusion(const Array< OneD, Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const Array< OneD, Array< OneD, NekDouble >> &pFwd, const Array< OneD, Array< OneD, NekDouble >> &pBwd)
Add the diffusions terms to the right-hand side.
virtual bool v_SupportsShockCaptType(const std::string type) const =0
void GetFluxVector(const Array< OneD, const Array< OneD, NekDouble >> &physfield, TensorOfArray3D< NekDouble > &flux)
Return the flux vector for the compressible Euler equations.
Array< OneD, NekDouble > GetStabilityLimitVector(const Array< OneD, int > &ExpOrder)
Function to calculate the stability limit for DG/CG (a vector of them).
void InitAdvection()
Create advection and diffusion objects for CFS.
virtual ~CompressibleFlowSystem()
Destructor for CompressibleFlowSystem class.
void GetFluxVectorDeAlias(const Array< OneD, const Array< OneD, NekDouble >> &physfield, TensorOfArray3D< NekDouble > &flux)
Return the flux vector for the compressible Euler equations by using the de-aliasing technique.
void SetBoundaryConditions(Array< OneD, Array< OneD, NekDouble >> &physarray, NekDouble time)
virtual void v_SetInitialConditions(NekDouble initialtime=0.0, bool dumpInitialConditions=true, const int domain=0) override
Set up logic for residual calculation.
virtual void v_InitObject(bool DeclareFields=true) override
Initialization object for CompressibleFlowSystem class.
NekDouble GetStabilityLimit(int n)
Function to calculate the stability limit for DG/CG.
std::vector< CFSBndCondSharedPtr > m_bndConds
void GetElmtTimeStep(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, NekDouble > &tstep)
Calculate the maximum timestep on each element subject to CFL restrictions.
Array< OneD, Array< OneD, NekDouble > > m_vecLocs
void DoOdeProjection(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time)
Compute the projection and call the method for imposing the boundary conditions in case of discontinu...
VariableConverterSharedPtr m_varConv
void SetBoundaryConditionsBwdWeight()
Set up a weight on physical boundaries for boundary condition applications.
std::vector< SolverUtils::ForcingSharedPtr > m_forcing
ArtificialDiffusionSharedPtr m_artificialDiffusion
virtual Array< OneD, NekDouble > v_GetMaxStdVelocity(const NekDouble SpeedSoundFactor) override
Compute the advection velocity in the standard space for each element of the expansion.
const Array< OneD, const Array< OneD, NekDouble > > & GetNormals()
void InitialiseParameters()
Load CFS parameters from the session file.
virtual void v_ExtraFldOutput(std::vector< Array< OneD, NekDouble >> &fieldcoeffs, std::vector< std::string > &variables) override
virtual void v_SteadyStateResidual(int step, Array< OneD, NekDouble > &L2) override
const Array< OneD, const Array< OneD, NekDouble > > & GetVecLocs()
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
void DefineProjection(FuncPointerT func, ObjectPointerT obj)
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:73
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
A base class for PDEs which include an advection component.
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
SOLVER_UTILS_EXPORT Array< OneD, NekDouble > GetElmtCFLVals(const bool FlagAcousticCFL=true)
virtual SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareField=true) override
Init object for UnsteadySystem class.
int m_spacedim
Spatial dimension (>= expansion dim).
SOLVER_UTILS_EXPORT bool ParallelInTime()
Check if solver use Parallel-in-Time.
virtual SOLVER_UTILS_EXPORT void v_SetInitialConditions(NekDouble initialtime=0.0, bool dumpInitialConditions=true, const int domain=0)
SpatialDomains::MeshGraphSharedPtr m_graph
Pointer to graph defining mesh.
LibUtilities::CommSharedPtr m_comm
Communicator.
NekDouble m_timestep
Time step size.
NekDouble m_time
Current time of simulation.
SOLVER_UTILS_EXPORT int GetTraceTotPoints()
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
SOLVER_UTILS_EXPORT void Checkpoint_Output(const int n)
Write checkpoint file of m_fields.
bool m_useInitialCondition
Flag to determine if IC are used.
SOLVER_UTILS_EXPORT void WriteFld(const std::string &outname)
Write field data to the given filename.
SOLVER_UTILS_EXPORT int GetExpSize()
std::string m_sessionName
Name of the session.
bool m_specHP_dealiasing
Flag to determine if dealisising is usde for the Spectral/hp element discretisation.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
Array< OneD, Array< OneD, NekDouble > > m_traceNormals
Array holding trace normals for DG simulations in the forwards direction.
enum HomogeneousType m_HomogeneousType
SOLVER_UTILS_EXPORT int GetNpoints()
int m_nchk
Number of checkpoints written so far.
enum MultiRegions::ProjectionType m_projectionType
Type of projection; e.g continuous or discontinuous.
int m_checksteps
Number of steps between checkpoints.
SOLVER_UTILS_EXPORT int GetTotPoints()
static SOLVER_UTILS_EXPORT std::vector< ForcingSharedPtr > Load(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields=0)
Definition: Forcing.cpp:120
Base class for unsteady solvers.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
NekDouble m_cflSafetyFactor
CFL safety factor (comprise between 0 to 1).
SOLVER_UTILS_EXPORT NekDouble MaxTimeStepEstimator()
Get the maximum timestep estimator for cfl control.
bool m_homoInitialFwd
Flag to determine if simulation should start in homogeneous forward transformed state.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::vector< PointsKey > PointsKeyVector
Definition: Points.h:250
std::shared_ptr< RiemannSolver > RiemannSolverSharedPtr
A shared pointer to an EquationSystem object.
AdvectionFactory & GetAdvectionFactory()
Gets the factory for initialising advection objects.
Definition: Advection.cpp:47
RiemannSolverFactory & GetRiemannSolverFactory()
std::shared_ptr< GeomFactors > GeomFactorsSharedPtr
Pointer to a GeomFactors object.
Definition: GeomFactors.h:62
@ eDeformed
Geometry is curved or has non-constant factors.
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:172
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
CFSBndCondFactory & GetCFSBndCondFactory()
Declaration of the boundary condition factory singleton.
Definition: CFSBndCond.cpp:41
static Array< OneD, Array< OneD, NekDouble > > NullNekDoubleArrayOfArray
ArtificialDiffusionFactory & GetArtificialDiffusionFactory()
Declaration of the artificial diffusion factory singleton.
double NekDouble
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:209
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector plus vector): z = alpha*x + y
Definition: Vmath.cpp:622
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:518
T Vmin(int n, const T *x, const int incx)
Return the minimum element in x - called vmin to avoid conflict with min.
Definition: Vmath.cpp:1050
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition: Vmath.cpp:574
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:895
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:359
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.cpp:248
void FillWhiteNoise(int n, const T eps, T *x, const int incx, int outseed)
Fills a vector with white noise.
Definition: Vmath.cpp:155
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition: Vmath.cpp:945
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1255
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294