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),
49  AdvectionSystem(pSession, pGraph)
50  {
51  }
52 
53  /**
54  * @brief Initialization object for CompressibleFlowSystem class.
55  */
57  {
59 
60  for (int i = 0; i < m_fields.size(); i++)
61  {
62  // Use BwdTrans to make sure initial condition is in solution space
63  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
64  m_fields[i]->UpdatePhys());
65  }
66 
69 
70  ASSERTL0(m_session->DefinesSolverInfo("UPWINDTYPE"),
71  "No UPWINDTYPE defined in session.");
72 
73  // Do not forwards transform initial condition
74  m_homoInitialFwd = false;
75 
76  // Set up locations of velocity vector.
79  for (int i = 0; i < m_spacedim; ++i)
80  {
81  m_vecLocs[0][i] = 1 + i;
82  }
83 
84  // Loading parameters from session file
86 
87  // Setting up advection and diffusion operators
88  InitAdvection();
89 
90  // Create artificial diffusion
91  if (m_shockCaptureType != "Off")
92  {
93  if (m_shockCaptureType == "Physical")
94  {
95  int nPts = m_fields[0]->GetTotPoints();
96  m_muav = Array<OneD, NekDouble>(nPts, 0.0);
97 
98  int nTracePts = m_fields[0]->GetTrace()->GetTotPoints();
99  m_muavTrace = Array<OneD, NekDouble> (nTracePts,0.0);
100  }
101  else
102  {
105  m_session,
106  m_fields,
107  m_spacedim);
108  }
109  }
110 
111  // Forcing terms for the sponge region
112  m_forcing = SolverUtils::Forcing::Load(m_session, shared_from_this(),
113  m_fields, m_fields.size());
114 
115  // User-defined boundary conditions
116  int cnt = 0;
117  for (int n = 0; n < m_fields[0]->GetBndConditions().size(); ++n)
118  {
119  std::string type =
120  m_fields[0]->GetBndConditions()[n]->GetUserDefined();
121 
122  if (m_fields[0]->GetBndConditions()[n]->GetBoundaryConditionType()
124  {
125  continue;
126  }
127 
128  if (!type.empty())
129  {
130  m_bndConds.push_back(GetCFSBndCondFactory().CreateInstance(
131  type,
132  m_session,
133  m_fields,
135  m_spacedim,
136  n,
137  cnt));
138  }
139  cnt += m_fields[0]->GetBndCondExpansions()[n]->GetExpSize();
140  }
141 
145 
147  }
148 
149 
150  /**
151  * @brief Destructor for CompressibleFlowSystem class.
152  */
154  {
155 
156  }
157 
158  /**
159  * @brief Load CFS parameters from the session file
160  */
162  {
163  // Get gamma parameter from session file.
164  m_session->LoadParameter("Gamma", m_gamma, 1.4);
165 
166  // Shock capture
167  m_session->LoadSolverInfo("ShockCaptureType",
168  m_shockCaptureType, "Off");
169 
170  // Load parameters for exponential filtering
171  m_session->MatchSolverInfo("ExponentialFiltering","True",
172  m_useFiltering, false);
173  if (m_useFiltering)
174  {
175  m_session->LoadParameter ("FilterAlpha", m_filterAlpha, 36);
176  m_session->LoadParameter ("FilterExponent", m_filterExponent, 16);
177  m_session->LoadParameter ("FilterCutoff", m_filterCutoff, 0);
178  }
179 
180  // Load CFL for local time-stepping (for steady state)
181  m_session->MatchSolverInfo("LocalTimeStep","True",
182  m_useLocalTimeStep, false);
183  if (m_useLocalTimeStep)
184  {
186  "Local time stepping requires CFL parameter.");
187  }
188 
189  }
190 
191  /**
192  * @brief Create advection and diffusion objects for CFS
193  */
195  {
196  // Check if projection type is correct
198  "Unsupported projection type.");
199 
200  string advName, riemName;
201  m_session->LoadSolverInfo("AdvectionType", advName, "WeakDG");
202 
204  .CreateInstance(advName, advName);
205 
207  {
208  m_advObject->SetFluxVector(&CompressibleFlowSystem::
209  GetFluxVectorDeAlias, this);
210  }
211  else
212  {
213  m_advObject->SetFluxVector(&CompressibleFlowSystem::
214  GetFluxVector, this);
215  }
216 
217  // Setting up Riemann solver for advection operator
218  m_session->LoadSolverInfo("UpwindType", riemName, "Average");
219 
221  riemannSolver = SolverUtils::GetRiemannSolverFactory()
222  .CreateInstance(riemName, m_session);
223 
224  // Setting up parameters for advection operator Riemann solver
225  riemannSolver->SetParam (
226  "gamma", &CompressibleFlowSystem::GetGamma, this);
227  riemannSolver->SetAuxVec(
228  "vecLocs", &CompressibleFlowSystem::GetVecLocs, this);
229  riemannSolver->SetVector(
231 
232  // Concluding initialisation of advection / diffusion operators
233  m_advObject->SetRiemannSolver(riemannSolver);
234  m_advObject->InitObject (m_session, m_fields);
235  }
236 
237  /**
238  * @brief Compute the right-hand side.
239  */
241  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
242  Array<OneD, Array<OneD, NekDouble>> &outarray,
243  const NekDouble time)
244  {
245  int nvariables = inarray.size();
246  int npoints = GetNpoints();
247  int nTracePts = GetTraceTotPoints();
248 
249  m_bndEvaluateTime = time;
250 
251  // Store forwards/backwards space along trace space
252  Array<OneD, Array<OneD, NekDouble>> Fwd(nvariables);
253  Array<OneD, Array<OneD, NekDouble>> Bwd(nvariables);
254 
256  {
259  }
260  else
261  {
262  for (int i = 0; i < nvariables; ++i)
263  {
264  Fwd[i] = Array<OneD, NekDouble>(nTracePts, 0.0);
265  Bwd[i] = Array<OneD, NekDouble>(nTracePts, 0.0);
266  m_fields[i]->GetFwdBwdTracePhys(inarray[i], Fwd[i], Bwd[i]);
267  }
268  }
269 
270  // Calculate advection
271  LibUtilities::Timer timer;
272  timer.Start();
273  DoAdvection(inarray, outarray, time, Fwd, Bwd);
274  timer.Stop();
275  timer.AccumulateRegion("DoAdvection");
276 
277  // Negate results
278  for (int i = 0; i < nvariables; ++i)
279  {
280  Vmath::Neg(npoints, outarray[i], 1);
281  }
282 
283  // Add diffusion terms
284  timer.Start();
285  DoDiffusion(inarray, outarray, Fwd, Bwd);
286  timer.Stop();
287  timer.AccumulateRegion("DoDiffusion");
288 
289  // Add forcing terms
290  for (auto &x : m_forcing)
291  {
292  x->Apply(m_fields, inarray, outarray, time);
293  }
294 
295  if (m_useLocalTimeStep)
296  {
297  int nElements = m_fields[0]->GetExpSize();
298  int nq, offset;
299  NekDouble fac;
301 
302  Array<OneD, NekDouble> tstep (nElements, 0.0);
303  GetElmtTimeStep(inarray, tstep);
304 
305  // Loop over elements
306  for (int n = 0; n < nElements; ++n)
307  {
308  nq = m_fields[0]->GetExp(n)->GetTotPoints();
309  offset = m_fields[0]->GetPhys_Offset(n);
310  fac = tstep[n] / m_timestep;
311  for (int i = 0; i < nvariables; ++i)
312  {
313  Vmath::Smul(nq, fac, outarray[i] + offset, 1,
314  tmp = outarray[i] + offset, 1);
315  }
316  }
317  }
318  }
319 
320  /**
321  * @brief Compute the projection and call the method for imposing the
322  * boundary conditions in case of discontinuous projection.
323  */
325  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
326  Array<OneD, Array<OneD, NekDouble>> &outarray,
327  const NekDouble time)
328  {
329  int nvariables = inarray.size();
330 
331  switch(m_projectionType)
332  {
334  {
335  // Just copy over array
336  int npoints = GetNpoints();
337 
338  for (int i = 0; i < nvariables; ++i)
339  {
340  Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
341  if (m_useFiltering)
342  {
343  m_fields[i]->ExponentialFilter(outarray[i],
345  }
346  }
347  SetBoundaryConditions(outarray, time);
348  break;
349  }
352  {
353  NEKERROR(ErrorUtil::efatal, "No Continuous Galerkin for full "
354  "compressible Navier-Stokes equations");
355  break;
356  }
357  default:
358  NEKERROR(ErrorUtil::efatal, "Unknown projection scheme");
359  break;
360  }
361  }
362 
363 
364  /**
365  * @brief Compute the advection terms for the right-hand side
366  */
368  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
369  Array<OneD, Array<OneD, NekDouble>> &outarray,
370  const NekDouble time,
371  const Array<OneD, const Array<OneD, NekDouble>> &pFwd,
372  const Array<OneD, const Array<OneD, NekDouble>> &pBwd)
373  {
374  int nvariables = inarray.size();
376 
377  m_advObject->Advect(nvariables, m_fields, advVel, inarray,
378  outarray, time, pFwd, pBwd);
379  }
380 
381  /**
382  * @brief Add the diffusions terms to the right-hand side
383  */
385  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
386  Array<OneD, Array<OneD, NekDouble>> &outarray,
387  const Array<OneD, const Array<OneD, NekDouble>> &pFwd,
388  const Array<OneD, const Array<OneD, NekDouble>> &pBwd)
389  {
390  v_DoDiffusion(inarray, outarray, pFwd, pBwd);
391 
392  if (m_shockCaptureType != "Off" && m_shockCaptureType != "Physical")
393  {
394  m_artificialDiffusion->DoArtificialDiffusion(inarray, outarray);
395  }
396  }
397 
398 
400  Array<OneD, Array<OneD, NekDouble>> &physarray,
401  NekDouble time)
402  {
403  int nTracePts = GetTraceTotPoints();
404  int nvariables = physarray.size();
405 
406  Array<OneD, Array<OneD, NekDouble>> Fwd(nvariables);
407  for (int i = 0; i < nvariables; ++i)
408  {
409  Fwd[i] = Array<OneD, NekDouble>(nTracePts);
410  m_fields[i]->ExtractTracePhys(physarray[i], Fwd[i]);
411  }
412 
413  if (m_bndConds.size())
414  {
415  // Loop over user-defined boundary conditions
416  for (auto &x : m_bndConds)
417  {
418  x->Apply(Fwd, physarray, time);
419  }
420  }
421  }
422  /**
423  * @brief Set up a weight on physical boundaries for boundary condition
424  * applications
425  */
427  {
428  if (m_bndConds.size())
429  {
430  // Loop over user-defined boundary conditions
431  for (auto &x : m_bndConds)
432  {
433  x->ApplyBwdWeight();
434  }
435  }
436  }
437 
438  /**
439  * @brief Return the flux vector for the compressible Euler equations.
440  *
441  * @param physfield Fields.
442  * @param flux Resulting flux.
443  */
445  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
447  {
448  auto nVariables = physfield.size();
449  auto nPts = physfield[0].size();
450 
451  constexpr unsigned short maxVel = 3;
452  constexpr unsigned short maxFld = 5;
453 
454  // hardcoding done for performance reasons
455  ASSERTL1(nVariables <= maxFld, "GetFluxVector, hard coded max fields");
456 
457  for (size_t p = 0; p < nPts; ++p)
458  {
459  // local storage
460  std::array<NekDouble, maxFld> fieldTmp;
461  std::array<NekDouble, maxVel> velocity;
462 
463  // rearrenge and load data
464  for (size_t f = 0; f < nVariables; ++f)
465  {
466  fieldTmp[f] = physfield[f][p]; // load
467  }
468 
469  // 1 / rho
470  NekDouble oneOrho = 1.0 / fieldTmp[0];
471 
472  for (size_t d = 0; d < m_spacedim; ++d)
473  {
474  // Flux vector for the rho equation
475  flux[0][d][p] = fieldTmp[d+1]; // store
476  // compute velocity
477  velocity[d] = fieldTmp[d+1] * oneOrho;
478  }
479 
480  NekDouble pressure = m_varConv->GetPressure(fieldTmp.data());
481  NekDouble ePlusP = fieldTmp[m_spacedim+1] + pressure;
482  for (size_t f = 0; f < m_spacedim; ++f)
483  {
484  // Flux vector for the velocity fields
485  for (size_t d = 0; d < m_spacedim; ++d)
486  {
487  flux[f+1][d][p] = velocity[d] * fieldTmp[f+1]; // store
488  }
489 
490  // Add pressure to appropriate field
491  flux[f+1][f][p] += pressure;
492 
493  // Flux vector for energy
494  flux[m_spacedim+1][f][p] = ePlusP * velocity[f]; // store
495  }
496 
497  }
498  }
499 
500  /**
501  * @brief Return the flux vector for the compressible Euler equations
502  * by using the de-aliasing technique.
503  *
504  * @param physfield Fields.
505  * @param flux Resulting flux.
506  */
508  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
510  {
511  int i, j;
512  int nq = physfield[0].size();
513  int nVariables = m_fields.size();
514 
515  // Factor to rescale 1d points in dealiasing
516  NekDouble OneDptscale = 2;
517  nq = m_fields[0]->Get1DScaledTotPoints(OneDptscale);
518 
521 
522  Array<OneD, Array<OneD, NekDouble>> physfield_interp(nVariables);
523  TensorOfArray3D<NekDouble> flux_interp(nVariables);
524 
525  for (i = 0; i < nVariables; ++ i)
526  {
527  physfield_interp[i] = Array<OneD, NekDouble>(nq);
529  m_fields[0]->PhysInterp1DScaled(
530  OneDptscale, physfield[i], physfield_interp[i]);
531 
532  for (j = 0; j < m_spacedim; ++j)
533  {
534  flux_interp[i][j] = Array<OneD, NekDouble>(nq);
535  }
536  }
537 
538  // Flux vector for the rho equation
539  for (i = 0; i < m_spacedim; ++i)
540  {
541  velocity[i] = Array<OneD, NekDouble>(nq);
542 
543  // Galerkin project solution back to original space
544  m_fields[0]->PhysGalerkinProjection1DScaled(
545  OneDptscale, physfield_interp[i+1], flux[0][i]);
546  }
547 
548  m_varConv->GetVelocityVector(physfield_interp, velocity);
549  m_varConv->GetPressure (physfield_interp, pressure);
550 
551  // Evaluation of flux vector for the velocity fields
552  for (i = 0; i < m_spacedim; ++i)
553  {
554  for (j = 0; j < m_spacedim; ++j)
555  {
556  Vmath::Vmul(nq, velocity[j], 1, physfield_interp[i+1], 1,
557  flux_interp[i+1][j], 1);
558  }
559 
560  // Add pressure to appropriate field
561  Vmath::Vadd(nq, flux_interp[i+1][i], 1, pressure,1,
562  flux_interp[i+1][i], 1);
563  }
564 
565  // Galerkin project solution back to original space
566  for (i = 0; i < m_spacedim; ++i)
567  {
568  for (j = 0; j < m_spacedim; ++j)
569  {
570  m_fields[0]->PhysGalerkinProjection1DScaled(
571  OneDptscale, flux_interp[i+1][j], flux[i+1][j]);
572  }
573  }
574 
575  // Evaluation of flux vector for energy
576  Vmath::Vadd(nq, physfield_interp[m_spacedim+1], 1, pressure, 1,
577  pressure, 1);
578 
579  for (j = 0; j < m_spacedim; ++j)
580  {
581  Vmath::Vmul(nq, velocity[j], 1, pressure, 1,
582  flux_interp[m_spacedim+1][j], 1);
583 
584  // Galerkin project solution back to original space
585  m_fields[0]->PhysGalerkinProjection1DScaled(
586  OneDptscale,
587  flux_interp[m_spacedim+1][j],
588  flux[m_spacedim+1][j]);
589  }
590  }
591 
592  /**
593  * @brief Calculate the maximum timestep on each element
594  * subject to CFL restrictions.
595  */
597  const Array<OneD, const Array<OneD, NekDouble>> &inarray,
598  Array<OneD, NekDouble> &tstep)
599  {
600  boost::ignore_unused(inarray);
601 
602  int nElements = m_fields[0]->GetExpSize();
603 
604  // Change value of m_timestep (in case it is set to zero)
605  NekDouble tmp = m_timestep;
606  m_timestep = 1.0;
607 
608  Array<OneD, NekDouble> cfl(nElements);
609  cfl = GetElmtCFLVals();
610 
611  // Factors to compute the time-step limit
613 
614  // Loop over elements to compute the time-step limit for each element
615  for (int n = 0; n < nElements; ++n)
616  {
617  tstep[n] = m_cflSafetyFactor * alpha / cfl[n];
618  }
619 
620  // Restore value of m_timestep
621  m_timestep = tmp;
622  }
623 
624  /**
625  * @brief Calculate the maximum timestep subject to CFL restrictions.
626  */
628  const Array<OneD, const Array<OneD, NekDouble> > &inarray)
629  {
630  int nElements = m_fields[0]->GetExpSize();
631  Array<OneD, NekDouble> tstep (nElements, 0.0);
632 
633  GetElmtTimeStep(inarray, tstep);
634 
635  // Get the minimum time-step limit and return the time-step
636  NekDouble TimeStep = Vmath::Vmin(nElements, tstep, 1);
637  m_comm->AllReduce(TimeStep, LibUtilities::ReduceMin);
638 
639  NekDouble tmp = m_timestep;
640  m_timestep = TimeStep;
641 
642  Array<OneD, NekDouble> cflNonAcoustic(nElements,0.0);
643  cflNonAcoustic = GetElmtCFLVals(false);
644 
645  // Get the minimum time-step limit and return the time-step
646  NekDouble MaxcflNonAcoustic = Vmath::Vmax(nElements, cflNonAcoustic, 1);
647  m_comm->AllReduce(MaxcflNonAcoustic, LibUtilities::ReduceMax);
648 
649  m_cflNonAcoustic = MaxcflNonAcoustic;
650  m_timestep = tmp;
651 
652  return TimeStep;
653  }
654 
655  /**
656  * @brief Set up logic for residual calculation.
657  */
659  NekDouble initialtime,
660  bool dumpInitialConditions,
661  const int domain)
662  {
663  boost::ignore_unused(domain);
664 
665  EquationSystem::v_SetInitialConditions(initialtime, false);
666 
667  // insert white noise in initial condition
668  NekDouble Noise;
669  int phystot = m_fields[0]->GetTotPoints();
670  Array<OneD, NekDouble> noise(phystot);
671 
672  m_session->LoadParameter("Noise", Noise,0.0);
673  int m_nConvectiveFields = m_fields.size();
674 
675  if (Noise > 0.0)
676  {
677  int seed = - m_comm->GetRank()*m_nConvectiveFields;
678  for (int i = 0; i < m_nConvectiveFields; i++)
679  {
680  Vmath::FillWhiteNoise(phystot, Noise, noise, 1,
681  seed);
682  --seed;
683  Vmath::Vadd(phystot, m_fields[i]->GetPhys(), 1,
684  noise, 1, m_fields[i]->UpdatePhys(), 1);
685  m_fields[i]->FwdTrans_IterPerExp(m_fields[i]->GetPhys(),
686  m_fields[i]->UpdateCoeffs());
687  }
688  }
689 
690  if (dumpInitialConditions && m_checksteps)
691  {
693  m_nchk++;
694  }
695  }
696 
697  /**
698  * @brief Compute the advection velocity in the standard space
699  * for each element of the expansion.
700  */
702  const NekDouble SpeedSoundFactor)
703  {
704  int nTotQuadPoints = GetTotPoints();
705  int n_element = m_fields[0]->GetExpSize();
706  int expdim = m_fields[0]->GetGraph()->GetMeshDimension();
707  int nfields = m_fields.size();
708  int offset;
710 
711  Array<OneD, Array<OneD, NekDouble>> physfields(nfields);
712  for (int i = 0; i < nfields; ++i)
713  {
714  physfields[i] = m_fields[i]->GetPhys();
715  }
716 
717  Array<OneD, NekDouble> stdV(n_element, 0.0);
718 
719  // Getting the velocity vector on the 2D normal space
723  Array<OneD, NekDouble> soundspeed (nTotQuadPoints);
725 
726  for (int i = 0; i < m_spacedim; ++i)
727  {
728  velocity [i] = Array<OneD, NekDouble>(nTotQuadPoints);
729  stdVelocity[i] = Array<OneD, NekDouble>(nTotQuadPoints, 0.0);
730  stdSoundSpeed[i] = Array<OneD, NekDouble>(nTotQuadPoints, 0.0);
731  }
732 
733  m_varConv->GetVelocityVector(physfields, velocity);
734  m_varConv->GetSoundSpeed (physfields, soundspeed);
735 
736  for (int el = 0; el < n_element; ++el)
737  {
738  ptsKeys = m_fields[0]->GetExp(el)->GetPointsKeys();
739  offset = m_fields[0]->GetPhys_Offset(el);
740  int nq = m_fields[0]->GetExp(el)->GetTotPoints();
741 
742  const SpatialDomains::GeomFactorsSharedPtr metricInfo =
743  m_fields[0]->GetExp(el)->GetGeom()->GetMetricInfo();
744  const Array<TwoD, const NekDouble> &gmat =
745  m_fields[0]->GetExp(el)->GetGeom()->GetMetricInfo()
746  ->GetDerivFactors(ptsKeys);
747 
748  // Convert to standard element
749  // consider soundspeed in all directions
750  // (this might overestimate the cfl)
751  if (metricInfo->GetGtype() == SpatialDomains::eDeformed)
752  {
753  // d xi/ dx = gmat = 1/J * d x/d xi
754  for (int i = 0; i < expdim; ++i)
755  {
756  Vmath::Vmul(nq, gmat[i], 1,
757  velocity[0] + offset, 1,
758  tmp = stdVelocity[i] + offset, 1);
759  Vmath::Vmul(nq, gmat[i], 1,
760  soundspeed + offset, 1,
761  tmp = stdSoundSpeed[i] + offset, 1);
762  for (int j = 1; j < expdim; ++j)
763  {
764  Vmath::Vvtvp(nq, gmat[expdim*j+i], 1,
765  velocity[j] + offset, 1,
766  stdVelocity[i] + offset, 1,
767  tmp = stdVelocity[i] + offset, 1);
768  Vmath::Vvtvp(nq, gmat[expdim*j+i], 1,
769  soundspeed + offset, 1,
770  stdSoundSpeed[i] + offset, 1,
771  tmp = stdSoundSpeed[i] + offset, 1);
772  }
773  }
774  }
775  else
776  {
777  for (int i = 0; i < expdim; ++i)
778  {
779  Vmath::Smul(nq, gmat[i][0],
780  velocity[0] + offset, 1,
781  tmp = stdVelocity[i] + offset, 1);
782  Vmath::Smul(nq, gmat[i][0],
783  soundspeed + offset, 1,
784  tmp = stdSoundSpeed[i] + offset, 1);
785  for (int j = 1; j < expdim; ++j)
786  {
787  Vmath::Svtvp(nq, gmat[expdim*j+i][0],
788  velocity[j] + offset, 1,
789  stdVelocity[i] + offset, 1,
790  tmp = stdVelocity[i] + offset, 1);
791  Vmath::Svtvp(nq, gmat[expdim*j+i][0],
792  soundspeed + offset, 1,
793  stdSoundSpeed[i] + offset, 1,
794  tmp = stdSoundSpeed[i] + offset, 1);
795  }
796  }
797  }
798 
799  NekDouble vel;
800  for (int i = 0; i < nq; ++i)
801  {
802  NekDouble pntVelocity = 0.0;
803  for (int j = 0; j < expdim; ++j)
804  {
805  // Add sound speed
806  vel = std::abs(stdVelocity[j][offset + i]) +
807  SpeedSoundFactor *
808  std::abs(stdSoundSpeed[j][offset + i]);
809  pntVelocity += vel * vel;
810  }
811  pntVelocity = sqrt(pntVelocity);
812  if (pntVelocity > stdV[el])
813  {
814  stdV[el] = pntVelocity;
815  }
816  }
817  }
818 
819  return stdV;
820  }
821 
822  /**
823  * @brief Set the denominator to compute the time step when a cfl
824  * control is employed. This function is no longer used but is still
825  * here for being utilised in the future.
826  *
827  * @param n Order of expansion element by element.
828  */
830  {
831  ASSERTL0(n <= 20, "Illegal modes dimension for CFL calculation "
832  "(P has to be less then 20)");
833 
834  NekDouble CFLDG[21] = { 2.0000, 6.0000, 11.8424, 19.1569,
835  27.8419, 37.8247, 49.0518, 61.4815,
836  75.0797, 89.8181, 105.6700, 122.6200,
837  140.6400, 159.7300, 179.8500, 201.0100,
838  223.1800, 246.3600, 270.5300, 295.6900,
839  321.8300}; //CFLDG 1D [0-20]
840  NekDouble CFL = 0.0;
841 
843  {
844  CFL = CFLDG[n];
845  }
846  else
847  {
848  NEKERROR(ErrorUtil::efatal, "Continuous Galerkin stability "
849  "coefficients not introduced yet.");
850  }
851 
852  return CFL;
853  }
854 
855  /**
856  * @brief Compute the vector of denominators to compute the time step
857  * when a cfl control is employed. This function is no longer used but
858  * is still here for being utilised in the future.
859  *
860  * @param ExpOrder Order of expansion element by element.
861  */
863  const Array<OneD,int> &ExpOrder)
864  {
865  int i;
866  Array<OneD,NekDouble> returnval(m_fields[0]->GetExpSize(), 0.0);
867  for (i =0; i<m_fields[0]->GetExpSize(); i++)
868  {
869  returnval[i] = GetStabilityLimit(ExpOrder[i]);
870  }
871  return returnval;
872  }
873 
875  std::vector<Array<OneD, NekDouble> > &fieldcoeffs,
876  std::vector<std::string> &variables)
877  {
878  bool extraFields;
879  m_session->MatchSolverInfo("OutputExtraFields","True",
880  extraFields, true);
881  if (extraFields)
882  {
883  const int nPhys = m_fields[0]->GetNpoints();
884  const int nCoeffs = m_fields[0]->GetNcoeffs();
886 
887  for (int i = 0; i < m_fields.size(); ++i)
888  {
889  tmp[i] = m_fields[i]->GetPhys();
890  }
891 
894  for (int i = 0; i < m_spacedim; ++i)
895  {
896  velocity[i] = Array<OneD, NekDouble> (nPhys);
897  velFwd[i] = Array<OneD, NekDouble> (nCoeffs);
898  }
899 
900  Array<OneD, NekDouble> pressure(nPhys), temperature(nPhys);
901  Array<OneD, NekDouble> entropy(nPhys);
902  Array<OneD, NekDouble> soundspeed(nPhys), mach(nPhys);
903  Array<OneD, NekDouble> sensor(nPhys), SensorKappa(nPhys);
904 
905  m_varConv->GetVelocityVector(tmp, velocity);
906  m_varConv->GetPressure (tmp, pressure);
907  m_varConv->GetTemperature(tmp, temperature);
908  m_varConv->GetEntropy (tmp, entropy);
909  m_varConv->GetSoundSpeed(tmp, soundspeed);
910  m_varConv->GetMach (tmp, soundspeed, mach);
911 
912  int sensorOffset;
913  m_session->LoadParameter ("SensorOffset", sensorOffset, 1);
914  m_varConv->GetSensor (m_fields[0], tmp, sensor, SensorKappa,
915  sensorOffset);
916 
917  Array<OneD, NekDouble> pFwd(nCoeffs), TFwd(nCoeffs);
918  Array<OneD, NekDouble> sFwd(nCoeffs);
919  Array<OneD, NekDouble> aFwd(nCoeffs), mFwd(nCoeffs);
920  Array<OneD, NekDouble> sensFwd(nCoeffs);
921 
922  string velNames[3] = {"u", "v", "w"};
923  for (int i = 0; i < m_spacedim; ++i)
924  {
925  m_fields[0]->FwdTrans_IterPerExp(velocity[i], velFwd[i]);
926  variables.push_back(velNames[i]);
927  fieldcoeffs.push_back(velFwd[i]);
928  }
929 
930  m_fields[0]->FwdTrans_IterPerExp(pressure, pFwd);
931  m_fields[0]->FwdTrans_IterPerExp(temperature,TFwd);
932  m_fields[0]->FwdTrans_IterPerExp(entropy, sFwd);
933  m_fields[0]->FwdTrans_IterPerExp(soundspeed, aFwd);
934  m_fields[0]->FwdTrans_IterPerExp(mach, mFwd);
935  m_fields[0]->FwdTrans_IterPerExp(sensor, sensFwd);
936 
937  variables.push_back ("p");
938  variables.push_back ("T");
939  variables.push_back ("s");
940  variables.push_back ("a");
941  variables.push_back ("Mach");
942  variables.push_back ("Sensor");
943  fieldcoeffs.push_back(pFwd);
944  fieldcoeffs.push_back(TFwd);
945  fieldcoeffs.push_back(sFwd);
946  fieldcoeffs.push_back(aFwd);
947  fieldcoeffs.push_back(mFwd);
948  fieldcoeffs.push_back(sensFwd);
949 
951  {
952  // Get min h/p
953  m_artificialDiffusion->SetElmtHP(GetElmtMinHP());
954  // reuse pressure
955  Array<OneD, NekDouble> sensorFwd(nCoeffs);
956  m_artificialDiffusion->GetArtificialViscosity(tmp, pressure);
957  m_fields[0]->FwdTrans_IterPerExp(pressure, sensorFwd);
958 
959  variables.push_back ("ArtificialVisc");
960  fieldcoeffs.push_back(sensorFwd);
961  }
962  }
963  }
964 
965  /**
966  *
967  */
969  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
971  {
972  m_varConv->GetPressure(physfield, pressure);
973  }
974 
975  /**
976  *
977  */
979  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
980  Array<OneD, NekDouble> &density)
981  {
982  density = physfield[0];
983  }
984 
985  /**
986  *
987  */
989  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
990  Array<OneD, Array<OneD, NekDouble>> &velocity)
991  {
992  m_varConv->GetVelocityVector(physfield, velocity);
993  }
994 
996  int step,
998  {
999  boost::ignore_unused(step);
1000  const int nPoints = GetTotPoints();
1001  const int nFields = m_fields.size();
1002  Array<OneD, Array<OneD, NekDouble>> rhs (nFields);
1003  Array<OneD, Array<OneD, NekDouble>> inarray (nFields);
1004  for (int i = 0; i < nFields; ++i)
1005  {
1006  rhs[i] = Array<OneD, NekDouble> (nPoints,0.0);
1007  inarray[i] = m_fields[i]->UpdatePhys();
1008  }
1009 
1010  DoOdeRhs(inarray,rhs,m_time);
1011 
1012  // Holds L2 errors.
1014  Array<OneD, NekDouble> RHSL2 (nFields);
1015  Array<OneD, NekDouble> residual(nFields);
1016 
1017  for (int i = 0; i < nFields; ++i)
1018  {
1019  tmp = rhs[i];
1020 
1021  Vmath::Vmul(nPoints, tmp, 1, tmp, 1, tmp, 1);
1022  residual[i] = Vmath::Vsum(nPoints, tmp, 1);
1023  }
1024 
1025  m_comm->AllReduce(residual , LibUtilities::ReduceSum);
1026 
1027  NekDouble onPoints = 1.0/NekDouble(nPoints);
1028  for (int i = 0; i < nFields; ++i)
1029  {
1030  L2[i] = sqrt(residual[i]*onPoints);
1031  }
1032  }
1033 
1034 
1035 /**
1036  * @brief Compute an estimate of minimum h/p
1037  * for each element of the expansion.
1038  */
1040 {
1041  int nElements = m_fields[0]->GetExpSize();
1042  Array<OneD, NekDouble> hOverP(nElements, 1.0);
1043 
1044  // Determine h/p scaling
1045  Array<OneD, int> pOrderElmt = m_fields[0]->EvalBasisNumModesMaxPerExp();
1046  for (int e = 0; e < nElements; e++)
1047  {
1048  NekDouble h = 1.0e+10;
1049  switch(m_expdim)
1050  {
1051  case 3:
1052  {
1054  exp3D = m_fields[0]->GetExp(e)->as<LocalRegions::Expansion3D>();
1055  for (int i = 0; i < exp3D->GetNtraces(); ++i)
1056  {
1057  h = min(h, exp3D->GetGeom3D()->GetEdge(i)->GetVertex(0)->
1058  dist(*(exp3D->GetGeom3D()->GetEdge(i)->GetVertex(1))));
1059  }
1060  break;
1061  }
1062 
1063  case 2:
1064  {
1066  exp2D = m_fields[0]->GetExp(e)->as<LocalRegions::Expansion2D>();
1067  for (int i = 0; i < exp2D->GetNtraces(); ++i)
1068  {
1069  h = min(h, exp2D->GetGeom2D()->GetEdge(i)->GetVertex(0)->
1070  dist(*(exp2D->GetGeom2D()->GetEdge(i)->GetVertex(1))));
1071  }
1072  break;
1073  }
1074  case 1:
1075  {
1077  exp1D = m_fields[0]->GetExp(e)->as<LocalRegions::Expansion1D>();
1078 
1079  h = min(h, exp1D->GetGeom1D()->GetVertex(0)->
1080  dist(*(exp1D->GetGeom1D()->GetVertex(1))));
1081 
1082  break;
1083  }
1084  default:
1085  {
1086  NEKERROR(ErrorUtil::efatal,"Dimension out of bound.")
1087  }
1088  }
1089 
1090  // Determine h/p scaling
1091  hOverP[e] = h/max(pOrderElmt[e]-1,1);
1092 
1093  }
1094  return hOverP;
1095 }
1096 
1097 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#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:250
virtual void v_DoDiffusion(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const Array< OneD, const Array< OneD, NekDouble >> &pFwd, const Array< OneD, const Array< OneD, NekDouble >> &pBwd)
virtual void GetVelocity(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, Array< OneD, NekDouble >> &velocity)
void DoOdeRhs(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time)
Compute the right-hand side.
Array< OneD, NekDouble > m_muavTrace
void DoDiffusion(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const Array< OneD, const Array< OneD, NekDouble >> &pFwd, const Array< OneD, const Array< OneD, NekDouble >> &pBwd)
Add the diffusions terms to the right-hand side.
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.
virtual Array< OneD, NekDouble > v_GetMaxStdVelocity(const NekDouble SpeedSoundFactor)
Compute the advection velocity in the standard space for each element of the expansion.
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)
Set up logic for residual calculation.
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
Array< OneD, NekDouble > GetElmtMinHP(void)
Function to get estimate of min h/p factor per element.
virtual void v_SteadyStateResidual(int step, Array< OneD, NekDouble > &L2)
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.
virtual void v_InitObject()
Initialization object for CompressibleFlowSystem class.
std::vector< SolverUtils::ForcingSharedPtr > m_forcing
ArtificialDiffusionSharedPtr m_artificialDiffusion
virtual void GetDensity(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &density)
const Array< OneD, const Array< OneD, NekDouble > > & GetNormals()
void InitialiseParameters()
Load CFS parameters from the session file.
void DoAdvection(const Array< OneD, const Array< OneD, NekDouble >> &inarray, Array< OneD, Array< OneD, NekDouble >> &outarray, const NekDouble time, const Array< OneD, const Array< OneD, NekDouble >> &pFwd, const Array< OneD, const Array< OneD, NekDouble >> &pBwd)
Compute the advection terms for the right-hand side.
virtual void v_ExtraFldOutput(std::vector< Array< OneD, NekDouble > > &fieldcoeffs, std::vector< std::string > &variables)
const Array< OneD, const Array< OneD, NekDouble > > & GetVecLocs()
virtual NekDouble v_GetTimeStep(const Array< OneD, const Array< OneD, NekDouble > > &inarray)
Calculate the maximum timestep subject to CFL restrictions.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
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:67
SpatialDomains::Geometry1DSharedPtr GetGeom1D() const
Definition: Expansion1D.h:113
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.
virtual SOLVER_UTILS_EXPORT void v_InitObject()
Init object for UnsteadySystem class.
SOLVER_UTILS_EXPORT Array< OneD, NekDouble > GetElmtCFLVals(const bool FlagAcousticCFL=true)
int m_spacedim
Spatial dimension (>= expansion dim).
int m_expdim
Expansion dimension.
virtual SOLVER_UTILS_EXPORT void v_SetInitialConditions(NekDouble initialtime=0.0, bool dumpInitialConditions=true, const int domain=0)
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.
SOLVER_UTILS_EXPORT int GetExpSize()
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.
SOLVER_UTILS_EXPORT MultiRegions::ExpListSharedPtr GetPressure()
Get pressure field if available.
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:128
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:246
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:51
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition: Expansion2D.h:49
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:174
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
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:192
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:565
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:461
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:992
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:513
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:846
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:322
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:225
void FillWhiteNoise(int n, const T eps, T *x, const int incx, int outseed)
Fills a vector with white noise.
Definition: Vmath.cpp:142
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:892
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1199
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:272
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267