Nektar++
VariableConverter.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File VariableConverter.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: Auxiliary functions to convert variables in
32 // the compressible flow system
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 #include <iomanip>
36 #include <iostream>
37 
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47 VariableConverter::VariableConverter(
48  const LibUtilities::SessionReaderSharedPtr &pSession, const int spaceDim,
50  : m_session(pSession), m_spacedim(spaceDim)
51 {
52  // Create equation of state object
53  std::string eosType;
54  m_session->LoadSolverInfo("EquationOfState", eosType, "IdealGas");
56 
57  // Parameters for dynamic viscosity
58  m_session->LoadParameter("pInf", m_pInf, 101325);
59  m_session->LoadParameter("rhoInf", m_rhoInf, 1.225);
60  m_session->LoadParameter("GasConstant", m_gasConstant, 287.058);
61  m_session->LoadParameter("mu", m_mu, 1.78e-05);
63 
64  // Parameters for sensor
65  m_session->LoadParameter("Skappa", m_Skappa, -1.0);
66  m_session->LoadParameter("Kappa", m_Kappa, 0.25);
67 
69 
70  // Shock sensor
71  m_session->LoadSolverInfo("ShockCaptureType", m_shockCaptureType, "Off");
72  if (m_shockCaptureType == "Physical")
73  {
74  // Artificial viscosity scaling constant
75  m_session->LoadParameter("mu0", m_mu0, 1.0);
76 
79 
80  // Check for Modal/Dilatation sensor
81  m_session->LoadSolverInfo("ShockSensorType", m_shockSensorType,
82  "Dilatation");
83 
84  // Check for Ducros sensor
85  m_session->LoadSolverInfo("DucrosSensor", m_ducrosSensor, "Off");
86  }
87  // Load smoothing tipe
88  m_session->LoadSolverInfo("Smoothing", m_smoothing, "Off");
89  if (m_smoothing == "C0")
90  {
93  m_session, pGraph, m_session->GetVariable(0));
94  }
95 
96  std::string viscosityType;
97  m_session->LoadSolverInfo("ViscosityType", viscosityType, "Constant");
98  if ("Variable" == viscosityType)
99  {
100  WARNINGL0(
101  m_session->DefinesParameter("Tref"),
102  "The Tref should be given in Kelvin for using the Sutherland's law "
103  "of dynamic viscosity. The default is 288.15. Note the mu or "
104  "Reynolds number should coorespond to this temperature.");
105  m_session->LoadParameter("Tref", m_Tref, 288.15);
106  m_TRatioSutherland = 110.0 / m_Tref;
107  }
108 }
109 
110 /**
111  * @brief Destructor for VariableConverter class.
112  */
114 {
115 }
116 
117 /**
118  * @brief Compute the dynamic energy
119  * \f$ e = rho*V^2/2 \f$.
120  */
122  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
123  Array<OneD, NekDouble> &energy)
124 {
125  size_t nPts = physfield[m_spacedim + 1].size();
126  Vmath::Zero(nPts, energy, 1);
127 
128  // tmp = (rho * u_i)^2
129  for (int i = 0; i < m_spacedim; ++i)
130  {
131  Vmath::Vvtvp(nPts, physfield[i + 1], 1, physfield[i + 1], 1, energy, 1,
132  energy, 1);
133  }
134  // Divide by rho and multiply by 0.5 --> tmp = 0.5 * rho * u^2
135  Vmath::Vdiv(nPts, energy, 1, physfield[0], 1, energy, 1);
136  Vmath::Smul(nPts, 0.5, energy, 1, energy, 1);
137 }
138 
139 /**
140  * @brief Compute the specific internal energy
141  * \f$ e = (E - rho*V^2/2)/rho \f$.
142  */
144  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
145  Array<OneD, NekDouble> &energy)
146 {
147  int nPts = physfield[0].size();
148  Array<OneD, NekDouble> tmp(nPts);
149 
150  GetDynamicEnergy(physfield, tmp);
151 
152  // Calculate rhoe = E - rho*V^2/2
153  Vmath::Vsub(nPts, physfield[m_spacedim + 1], 1, tmp, 1, energy, 1);
154  // Divide by rho
155  Vmath::Vdiv(nPts, energy, 1, physfield[0], 1, energy, 1);
156 }
157 
158 /**
159  * @brief Compute the specific enthalpy \f$ h = e + p/rho \f$.
160  */
162  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
163  Array<OneD, NekDouble> &enthalpy)
164 {
165  int nPts = physfield[0].size();
166  Array<OneD, NekDouble> energy(nPts, 0.0);
167  Array<OneD, NekDouble> pressure(nPts, 0.0);
168 
169  GetInternalEnergy(physfield, energy);
170  GetPressure(physfield, pressure);
171 
172  // Calculate p/rho
173  Vmath::Vdiv(nPts, pressure, 1, physfield[0], 1, enthalpy, 1);
174  // Calculate h = e + p/rho
175  Vmath::Vadd(nPts, energy, 1, enthalpy, 1, enthalpy, 1);
176 }
177 
178 /**
179  * @brief Compute the velocity field \f$ \mathbf{v} \f$ given the momentum
180  * \f$ \rho\mathbf{v} \f$.
181  *
182  * @param physfield Momentum field.
183  * @param velocity Velocity field.
184  */
186  const Array<OneD, Array<OneD, NekDouble>> &physfield,
187  Array<OneD, Array<OneD, NekDouble>> &velocity)
188 {
189  const int nPts = physfield[0].size();
190 
191  for (int i = 0; i < m_spacedim; ++i)
192  {
193  Vmath::Vdiv(nPts, physfield[1 + i], 1, physfield[0], 1, velocity[i], 1);
194  }
195 }
196 
197 /**
198  * @brief Compute the mach number \f$ M = \| \mathbf{v} \|^2 / c \f$.
199  *
200  * @param physfield Input physical field.
201  * @param soundfield The speed of sound corresponding to physfield.
202  * @param mach The resulting mach number \f$ M \f$.
203  */
205  Array<OneD, NekDouble> &soundspeed,
207 {
208  const int nPts = physfield[0].size();
209 
210  Vmath::Vmul(nPts, physfield[1], 1, physfield[1], 1, mach, 1);
211 
212  for (int i = 1; i < m_spacedim; ++i)
213  {
214  Vmath::Vvtvp(nPts, physfield[1 + i], 1, physfield[1 + i], 1, mach, 1,
215  mach, 1);
216  }
217 
218  Vmath::Vdiv(nPts, mach, 1, physfield[0], 1, mach, 1);
219  Vmath::Vdiv(nPts, mach, 1, physfield[0], 1, mach, 1);
220  Vmath::Vsqrt(nPts, mach, 1, mach, 1);
221 
222  Vmath::Vdiv(nPts, mach, 1, soundspeed, 1, mach, 1);
223 }
224 
225 /**
226  * @brief Compute the dynamic viscosity using the Sutherland's law
227  * \f$ \mu = \mu_star * (T / T_star)^3/2 * (1 + C) / (T/T_star + C) \f$,
228  * C : 110. /Tref
229  * Tref : the reference temperature, Tref, should always given in Kelvin,
230  * if non-dimensional should be the reference for non-dimensionalizing
231  * muref : the dynamic viscosity or the 1/Re corresponding to Tref
232  * T_star : m_pInf / (m_rhoInf * m_gasConstant),non-dimensional or dimensional
233  *
234  * WARNING, if this routine is modified the same must be done in the
235  * FieldConvert utility ProcessWSS.cpp (this class should be restructured).
236  *
237  * @param temperature Input temperature.
238  * @param mu The resulting dynamic viscosity.
239  */
242 {
243  const int nPts = temperature.size();
244 
245  for (int i = 0; i < nPts; ++i)
246  {
247  mu[i] = GetDynamicViscosity(temperature[i]);
248  }
249 }
250 
251 /**
252  * @brief Compute the dynamic viscosity using the Sutherland's law
253  * \f$ \mu = \mu_star * (T / T_star)^3/2 * (T_star + 110) / (T + 110) \f$,
254  */
256  const Array<OneD, const NekDouble> &temperature,
258 {
259  const int nPts = temperature.size();
260  NekDouble tmp = 0.0;
261  NekDouble ratio;
262 
263  for (int i = 0; i < nPts; ++i)
264  {
265  ratio = temperature[i] * m_oneOverT_star;
266  tmp = 0.5 * (ratio + 3.0 * m_TRatioSutherland) /
267  (ratio * (ratio + m_TRatioSutherland));
268  DmuDT[i] = mu[i] * tmp * m_oneOverT_star;
269  }
270 }
271 
273  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
275 {
276  const int nPts = physfield[0].size();
277 
278  // Getting the velocity vector on the 2D normal space
280 
281  Vmath::Zero(Vtot.size(), Vtot, 1);
282 
283  for (int i = 0; i < m_spacedim; ++i)
284  {
285  velocity[i] = Array<OneD, NekDouble>(nPts);
286  }
287 
288  GetVelocityVector(physfield, velocity);
289 
290  for (int i = 0; i < m_spacedim; ++i)
291  {
292  Vmath::Vvtvp(nPts, velocity[i], 1, velocity[i], 1, Vtot, 1, Vtot, 1);
293  }
294 
295  Vmath::Vsqrt(nPts, Vtot, 1, Vtot, 1);
296 }
297 
298 /**
299  * @brief Calculate the pressure using the equation of state.
300  *
301  * @param physfield Input momentum.
302  * @param pressure Computed pressure field.
303  */
305  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
307 {
308  int nPts = physfield[0].size();
309 
310  Array<OneD, NekDouble> energy(nPts);
311  GetInternalEnergy(physfield, energy);
312 
313  for (int i = 0; i < nPts; ++i)
314  {
315  pressure[i] = m_eos->GetPressure(physfield[0][i], energy[i]);
316  }
317 }
318 
319 /**
320  * @brief Compute the temperature using the equation of state.
321  *
322  * @param physfield Input physical field.
323  * @param temperature The resulting temperature \f$ T \f$.
324  */
326  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
327  Array<OneD, NekDouble> &temperature)
328 {
329  int nPts = physfield[0].size();
330 
331  Array<OneD, NekDouble> energy(nPts);
332  GetInternalEnergy(physfield, energy);
333 
334  for (int i = 0; i < nPts; ++i)
335  {
336  temperature[i] = m_eos->GetTemperature(physfield[0][i], energy[i]);
337  }
338 }
339 
340 /**
341  * @brief Compute the sound speed using the equation of state.
342  *
343  * @param physfield Input physical field
344  * @param soundspeed The resulting sound speed \f$ c \f$.
345  */
347  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
348  Array<OneD, NekDouble> &soundspeed)
349 {
350  int nPts = physfield[0].size();
351 
352  Array<OneD, NekDouble> energy(nPts);
353  GetInternalEnergy(physfield, energy);
354 
355  for (int i = 0; i < nPts; ++i)
356  {
357  soundspeed[i] = m_eos->GetSoundSpeed(physfield[0][i], energy[i]);
358  }
359 }
360 
361 /**
362  * @brief Compute the entropy using the equation of state.
363  *
364  * @param physfield Input physical field
365  * @param soundspeed The resulting sound speed \f$ c \f$.
366  */
368  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
369  Array<OneD, NekDouble> &entropy)
370 {
371  int nPts = physfield[0].size();
372 
373  Array<OneD, NekDouble> energy(nPts);
374  GetInternalEnergy(physfield, energy);
375 
376  for (int i = 0; i < nPts; ++i)
377  {
378  entropy[i] = m_eos->GetEntropy(physfield[0][i], energy[i]);
379  }
380 }
381 
382 /**
383  * @brief Compute \f$ e(rho,p) \f$ using the equation of state.
384  *
385  * @param rho Input density
386  * @param pressure Input pressure
387  * @param energy The resulting internal energy.
388  */
391  Array<OneD, NekDouble> &energy)
392 {
393  int nPts = rho.size();
394 
395  for (int i = 0; i < nPts; ++i)
396  {
397  energy[i] = m_eos->GetEFromRhoP(rho[i], pressure[i]);
398  }
399 }
400 
401 /**
402  * @brief Compute \f$ rho(p,T) \f$ using the equation of state.
403  *
404  * @param pressure Input pressure
405  * @param temperature Input temperature
406  * @param rho The resulting density
407  */
409  const Array<OneD, NekDouble> &temperature,
411 {
412  int nPts = pressure.size();
413 
414  for (int i = 0; i < nPts; ++i)
415  {
416  rho[i] = m_eos->GetRhoFromPT(pressure[i], temperature[i]);
417  }
418 }
419 
422  const Array<OneD, const Array<OneD, NekDouble>> &consVar,
423  const Array<OneD, NekDouble> &div,
424  const Array<OneD, NekDouble> &curlSquared)
425 {
426  auto nTracePts = fields[0]->GetTrace()->GetTotPoints();
428  {
429  auto nPts = fields[0]->GetTotPoints();
430  m_muAv = Array<OneD, NekDouble>(nPts, 0.0);
431  m_muAvTrace = Array<OneD, NekDouble>(nTracePts, 0.0);
432  SetElmtMinHP(fields);
433  }
434 
435  if (m_shockSensorType == "Modal")
436  {
437  // Get viscosity based on modal sensor
438  GetMuAv(fields, consVar, m_muAv);
439  }
440  else
441  {
442  // Get viscosity based on dilatation sensor
443  GetMuAv(fields, consVar, div, m_muAv);
444  }
445 
446  // Apply Ducros sensor
447  if (m_ducrosSensor != "Off")
448  {
449  ApplyDucros(div, curlSquared, m_muAv);
450  }
451 
452  // Apply approximate C0 smoothing
453  if (m_smoothing == "C0")
454  {
456  }
457 
458  // Set trace AV
459  Array<OneD, NekDouble> muFwd(nTracePts, 0.0), muBwd(nTracePts, 0.0);
460  fields[0]->GetFwdBwdTracePhys(m_muAv, muFwd, muBwd, false, false, false);
461  for (size_t p = 0; p < nTracePts; ++p)
462  {
463  m_muAvTrace[p] = 0.5 * (muFwd[p] + muBwd[p]);
464  }
465 }
466 
468 {
469  ASSERTL1(m_muAv != NullNekDouble1DArray, "m_muAv not set");
470  return m_muAv;
471 }
472 
474 {
475  ASSERTL1(m_muAvTrace != NullNekDouble1DArray, "m_muAvTrace not set");
476  return m_muAvTrace;
477 }
478 
479 /**
480  * @brief Compute an estimate of minimum h/p
481  * for each element of the expansion.
482  */
485 {
486  auto nElements = fields[0]->GetExpSize();
488  {
489  m_hOverP = Array<OneD, NekDouble>(nElements, 1.0);
490  }
491 
492  // Determine h/p scaling
493  Array<OneD, int> pOrderElmt = fields[0]->EvalBasisNumModesMaxPerExp();
494  auto expdim = fields[0]->GetGraph()->GetMeshDimension();
495  for (size_t e = 0; e < nElements; e++)
496  {
497  NekDouble h = 1.0e+10;
498  switch (expdim)
499  {
500  case 3:
501  {
503  exp3D = fields[0]->GetExp(e)->as<LocalRegions::Expansion3D>();
504  for (size_t i = 0; i < exp3D->GetNtraces(); ++i)
505  {
506  h = min(
507  h, exp3D->GetGeom3D()->GetEdge(i)->GetVertex(0)->dist(*(
508  exp3D->GetGeom3D()->GetEdge(i)->GetVertex(1))));
509  }
510  break;
511  }
512 
513  case 2:
514  {
516  exp2D = fields[0]->GetExp(e)->as<LocalRegions::Expansion2D>();
517  for (size_t i = 0; i < exp2D->GetNtraces(); ++i)
518  {
519  h = min(
520  h, exp2D->GetGeom2D()->GetEdge(i)->GetVertex(0)->dist(*(
521  exp2D->GetGeom2D()->GetEdge(i)->GetVertex(1))));
522  }
523  break;
524  }
525  case 1:
526  {
528  exp1D = fields[0]->GetExp(e)->as<LocalRegions::Expansion1D>();
529 
530  h = min(h, exp1D->GetGeom1D()->GetVertex(0)->dist(
531  *(exp1D->GetGeom1D()->GetVertex(1))));
532 
533  break;
534  }
535  default:
536  {
537  ASSERTL0(false, "Dimension out of bound.")
538  }
539  }
540 
541  // Store h/p scaling
542  m_hOverP[e] = h / max(pOrderElmt[e] - 1, 1);
543  }
544 }
545 
547 {
548  ASSERTL1(m_hOverP != NullNekDouble1DArray, "m_hOverP not set");
549  return m_hOverP;
550 }
551 
553  const MultiRegions::ExpListSharedPtr &field,
554  const Array<OneD, const Array<OneD, NekDouble>> &physarray,
555  Array<OneD, NekDouble> &Sensor, Array<OneD, NekDouble> &SensorKappa,
556  int offset)
557 {
558  NekDouble Skappa;
559  NekDouble order;
561  Array<OneD, int> expOrderElement = field->EvalBasisNumModesMaxPerExp();
562 
563  for (int e = 0; e < field->GetExpSize(); e++)
564  {
565  int numModesElement = expOrderElement[e];
566  int nElmtPoints = field->GetExp(e)->GetTotPoints();
567  int physOffset = field->GetPhys_Offset(e);
568  int nElmtCoeffs = field->GetExp(e)->GetNcoeffs();
569  int numCutOff = numModesElement - offset;
570 
571  if (numModesElement <= offset)
572  {
573  Vmath::Fill(nElmtPoints, 0.0, tmp = Sensor + physOffset, 1);
574  Vmath::Fill(nElmtPoints, 0.0, tmp = SensorKappa + physOffset, 1);
575  continue;
576  }
577 
578  // create vector to save the solution points per element at P = p;
579  Array<OneD, NekDouble> elmtPhys(nElmtPoints,
580  tmp = physarray[0] + physOffset);
581  // Compute coefficients
582  Array<OneD, NekDouble> elmtCoeffs(nElmtCoeffs, 0.0);
583  field->GetExp(e)->FwdTrans(elmtPhys, elmtCoeffs);
584 
585  // ReduceOrderCoeffs reduces the polynomial order of the solution
586  // that is represented by the coeffs given as an inarray. This is
587  // done by projecting the higher order solution onto the orthogonal
588  // basis and padding the higher order coefficients with zeros.
589  Array<OneD, NekDouble> reducedElmtCoeffs(nElmtCoeffs, 0.0);
590  field->GetExp(e)->ReduceOrderCoeffs(numCutOff, elmtCoeffs,
591  reducedElmtCoeffs);
592 
593  Array<OneD, NekDouble> reducedElmtPhys(nElmtPoints, 0.0);
594  field->GetExp(e)->BwdTrans(reducedElmtCoeffs, reducedElmtPhys);
595 
596  NekDouble numerator = 0.0;
597  NekDouble denominator = 0.0;
598 
599  // Determining the norm of the numerator of the Sensor
600  Array<OneD, NekDouble> difference(nElmtPoints, 0.0);
601  Vmath::Vsub(nElmtPoints, elmtPhys, 1, reducedElmtPhys, 1, difference,
602  1);
603 
604  numerator = Vmath::Dot(nElmtPoints, difference, difference);
605  denominator = Vmath::Dot(nElmtPoints, elmtPhys, elmtPhys);
606 
607  NekDouble elmtSensor = sqrt(numerator / denominator);
608  elmtSensor = log10(max(elmtSensor, NekConstants::kNekSqrtTol));
609 
610  Vmath::Fill(nElmtPoints, elmtSensor, tmp = Sensor + physOffset, 1);
611 
612  // Compute reference value for sensor
613  order = max(numModesElement - 1, 1);
614  if (order > 0)
615  {
616  Skappa = m_Skappa - 4.25 * log10(static_cast<NekDouble>(order));
617  }
618  else
619  {
620  Skappa = 0.0;
621  }
622 
623  // Compute artificial viscosity
624  NekDouble elmtSensorKappa;
625  if (elmtSensor < (Skappa - m_Kappa))
626  {
627  elmtSensorKappa = 0;
628  }
629  else if (elmtSensor > (Skappa + m_Kappa))
630  {
631  elmtSensorKappa = 1.0;
632  }
633  else
634  {
635  elmtSensorKappa =
636  0.5 * (1 + sin(M_PI * (elmtSensor - Skappa) / (2 * m_Kappa)));
637  }
638  Vmath::Fill(nElmtPoints, elmtSensorKappa,
639  tmp = SensorKappa + physOffset, 1);
640  }
641 }
642 
643 /**
644  * @brief Calculate the physical artificial viscosity based on modal sensor.
645  *
646  * @param consVar Input field.
647  */
650  const Array<OneD, const Array<OneD, NekDouble>> &consVar,
652 {
653  auto nPts = consVar[0].size();
654  // Determine the maximum wavespeed
655  Array<OneD, NekDouble> Lambdas(nPts, 0.0);
656  Array<OneD, NekDouble> soundspeed(nPts, 0.0);
657  Array<OneD, NekDouble> absVelocity(nPts, 0.0);
658  GetSoundSpeed(consVar, soundspeed);
659  GetAbsoluteVelocity(consVar, absVelocity);
660  Vmath::Vadd(nPts, absVelocity, 1, soundspeed, 1, Lambdas, 1);
661 
662  // Compute sensor based on rho
663  Array<OneD, NekDouble> Sensor(nPts, 0.0);
664  GetSensor(fields[0], consVar, Sensor, muAv, 1);
665 
667  auto nElmt = fields[0]->GetExpSize();
668  for (size_t e = 0; e < nElmt; ++e)
669  {
670  auto physOffset = fields[0]->GetPhys_Offset(e);
671  auto nElmtPoints = fields[0]->GetExp(e)->GetTotPoints();
672 
673  // Compute the maximum wave speed
674  NekDouble LambdaElmt = 0.0;
675  LambdaElmt = Vmath::Vmax(nElmtPoints, tmp = Lambdas + physOffset, 1);
676 
677  // Compute average bounded density
678  NekDouble rhoAve =
679  Vmath::Vsum(nElmtPoints, tmp = consVar[0] + physOffset, 1);
680  rhoAve = rhoAve / nElmtPoints;
681  rhoAve = Smath::Smax(rhoAve, 1.0e-4, 1.0e+4);
682 
683  // Scale sensor by coeff, h/p, and density
684  LambdaElmt *= m_mu0 * m_hOverP[e] * rhoAve;
685  Vmath::Smul(nElmtPoints, LambdaElmt, tmp = muAv + physOffset, 1,
686  tmp = muAv + physOffset, 1);
687  }
688 }
689 
690 /**
691  * @brief Calculate the physical artificial viscosity based on dilatation of
692  * velocity vector.
693  *
694  * @param
695  */
698  const Array<OneD, const Array<OneD, NekDouble>> &consVar,
700 {
701  auto nPts = consVar[0].size();
702 
703  // Get sound speed
704  // theoretically it should be used the critical sound speed, this
705  // matters for large Mach numbers (above 3.0)
706  Array<OneD, NekDouble> soundSpeed(nPts, 0.0);
707  GetSoundSpeed(consVar, soundSpeed);
708 
709  // Get abosolute velocity to compute lambda
710  Array<OneD, NekDouble> absVelocity(nPts, 0.0);
711  GetAbsoluteVelocity(consVar, absVelocity);
712 
713  // Loop over elements
714  auto nElmt = fields[0]->GetExpSize();
715  for (size_t e = 0; e < nElmt; ++e)
716  {
717  auto nElmtPoints = fields[0]->GetExp(e)->GetTotPoints();
718  auto physOffset = fields[0]->GetPhys_Offset(e);
719  auto physEnd = physOffset + nElmtPoints;
720 
721  NekDouble hOpTmp = m_hOverP[e];
722 
723  // Loop over the points
724  for (size_t p = physOffset; p < physEnd; ++p)
725  {
726  // Get non-dimensional sensor based on dilatation
727  NekDouble sSpeedTmp = soundSpeed[p];
728  // (only compression waves)
729  NekDouble divTmp = -div[p];
730  divTmp = std::max(divTmp, 0.0);
731  NekDouble sensor = m_mu0 * hOpTmp * divTmp / sSpeedTmp;
732  // Scale to viscosity scale
733  NekDouble rho = consVar[0][p];
734  NekDouble lambda = sSpeedTmp + absVelocity[p];
735  muAv[p] = sensor * rho * lambda * hOpTmp;
736  }
737  }
738 }
739 
740 /**
741  * @brief Apply Ducros (anti-vorticity) sensor averaged over the element.
742  *
743  * @param field Input Field
744  */
746  const Array<OneD, NekDouble> &curlSquare,
748 {
749  // machine eps**2
750  NekDouble eps = std::numeric_limits<NekDouble>::epsilon();
751  eps *= eps;
752 
753  // loop over points
754  auto nPts = div.size();
755  for (size_t p = 0; p < nPts; ++p)
756  {
757  NekDouble tmpDiv2 = div[p];
758  tmpDiv2 *= tmpDiv2;
759  NekDouble denDuc = tmpDiv2 + curlSquare[p] + eps;
760  NekDouble Duc = tmpDiv2 / denDuc;
761  // apply
762  muAv[p] *= Duc;
763  }
764 }
765 
766 /**
767  * @brief Make field C0.
768  *
769  * @param field Input Field
770  */
772 {
773  auto nCoeffs = m_C0ProjectExp->GetNcoeffs();
774  Array<OneD, NekDouble> muFwd(nCoeffs);
775  Array<OneD, NekDouble> weights(nCoeffs, 1.0);
776  // Assemble global expansion coefficients for viscosity
777  m_C0ProjectExp->FwdTransLocalElmt(field, m_C0ProjectExp->UpdateCoeffs());
778  m_C0ProjectExp->Assemble();
779  Vmath::Vcopy(nCoeffs, m_C0ProjectExp->GetCoeffs(), 1, muFwd, 1);
780  // Global coefficients
781  Vmath::Vcopy(nCoeffs, weights, 1, m_C0ProjectExp->UpdateCoeffs(), 1);
782  // This is the sign vector
783  m_C0ProjectExp->GlobalToLocal();
784  // Get weights
785  m_C0ProjectExp->Assemble();
786  // Divide
787  Vmath::Vdiv(nCoeffs, muFwd, 1, m_C0ProjectExp->GetCoeffs(), 1,
788  m_C0ProjectExp->UpdateCoeffs(), 1);
789  // Get local coefficients
790  m_C0ProjectExp->GlobalToLocal();
791  // Get C0 field
792  m_C0ProjectExp->BwdTrans(m_C0ProjectExp->GetCoeffs(), field);
793 }
794 
795 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:222
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
SpatialDomains::Geometry1DSharedPtr GetGeom1D() const
Definition: Expansion1D.h:109
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
void ApplyC0Smooth(Array< OneD, NekDouble > &field)
Make field C0.
Array< OneD, NekDouble > & GetAvTrace()
EquationOfStateSharedPtr m_eos
void GetDynamicEnergy(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &energy)
Compute the dynamic energy .
Array< OneD, NekDouble > m_hOverP
h/p scaling
void GetRhoFromPT(const Array< OneD, NekDouble > &pressure, const Array< OneD, NekDouble > &temperature, Array< OneD, NekDouble > &rho)
Compute using the equation of state.
void GetTemperature(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &temperature)
Compute the temperature using the equation of state.
Array< OneD, NekDouble > m_muAvTrace
void SetAv(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const Array< OneD, const Array< OneD, NekDouble >> &consVar, const Array< OneD, NekDouble > &div, const Array< OneD, NekDouble > &curlSquared)
void GetDmuDT(const Array< OneD, const NekDouble > &temperature, const Array< OneD, const NekDouble > &mu, Array< OneD, NekDouble > &DmuDT)
Compute the dynamic viscosity using the Sutherland's law ,.
void GetEnthalpy(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &enthalpy)
Compute the specific enthalpy .
void GetEFromRhoP(const Array< OneD, NekDouble > &rho, const Array< OneD, NekDouble > &pressure, Array< OneD, NekDouble > &energy)
Compute using the equation of state.
void SetElmtMinHP(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields)
Compute an estimate of minimum h/p for each element of the expansion.
MultiRegions::ContFieldSharedPtr m_C0ProjectExp
LibUtilities::SessionReaderSharedPtr m_session
NekDouble m_mu0
Shock sensor.
void GetPressure(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &pressure)
Calculate the pressure using the equation of state.
void ApplyDucros(const Array< OneD, NekDouble > &div, const Array< OneD, NekDouble > &curlSquare, Array< OneD, NekDouble > &muAv)
Apply Ducros (anti-vorticity) sensor averaged over the element.
void GetSoundSpeed(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &soundspeed)
Compute the sound speed using the equation of state.
void GetAbsoluteVelocity(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &Vtot)
void GetEntropy(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &entropy)
Compute the entropy using the equation of state.
void GetVelocityVector(const Array< OneD, Array< OneD, NekDouble >> &physfield, Array< OneD, Array< OneD, NekDouble >> &velocity)
Compute the velocity field given the momentum .
void GetMach(Array< OneD, Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &soundspeed, Array< OneD, NekDouble > &mach)
Compute the mach number .
void GetSensor(const MultiRegions::ExpListSharedPtr &field, const Array< OneD, const Array< OneD, NekDouble >> &physarray, Array< OneD, NekDouble > &Sensor, Array< OneD, NekDouble > &SensorKappa, int offset=1)
void GetMuAv(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &muAv)
Calculate the physical artificial viscosity based on modal sensor.
~VariableConverter()
Destructor for VariableConverter class.
Array< OneD, NekDouble > & GetElmtMinHP()
Array< OneD, NekDouble > m_muAv
storage
Array< OneD, NekDouble > & GetAv()
void GetInternalEnergy(const Array< OneD, const Array< OneD, NekDouble >> &physfield, Array< OneD, NekDouble > &energy)
Compute the specific internal energy .
void GetDynamicViscosity(const Array< OneD, const NekDouble > &temperature, Array< OneD, NekDouble > &mu)
Compute the dynamic viscosity using the Sutherland's law , C : 110. /Tref Tref : the reference temper...
std::shared_ptr< SessionReader > SessionReaderSharedPtr
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:50
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
static const NekDouble kNekSqrtTol
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:172
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
EquationOfStateFactory & GetEquationOfStateFactory()
Declaration of the equation of state factory singleton.
static Array< OneD, NekDouble > NullNekDouble1DArray
double NekDouble
T Smax(const T a, const T b, const T k)
Return the soft max of between two scalars.
Definition: Smath.hpp:53
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.cpp:534
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 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
T Dot(int n, const T *w, const T *x)
vvtvp (vector times vector times vector): z = w*x*y
Definition: Vmath.cpp:1100
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 Vdiv(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:284
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:492
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
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
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:419
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:291