Nektar++
NavierStokesCFE.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NavierStokesCFE.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: Navier Stokes equations in conservative variables
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
36 
37 using namespace std;
38 
39 namespace Nektar
40 {
41 string NavierStokesCFE::className =
43  "NavierStokesCFE", NavierStokesCFE::create,
44  "NavierStokes equations in conservative variables.");
45 
46 NavierStokesCFE::NavierStokesCFE(
49  : UnsteadySystem(pSession, pGraph), CompressibleFlowSystem(pSession, pGraph)
50 {
51 }
52 
54 {
55 }
56 
57 /**
58  * @brief Initialization object for CompressibleFlowSystem class.
59  */
60 void NavierStokesCFE::v_InitObject(bool DeclareFields)
61 {
63 
64  // rest of initialisation is in this routine so it can also be called
65  // in NavierStokesImplicitCFE initialisation
67 }
68 
70 {
71  // Get gas constant from session file and compute Cp
72  NekDouble gasConstant;
73  m_session->LoadParameter("GasConstant", gasConstant, 287.058);
74  m_Cp = m_gamma / (m_gamma - 1.0) * gasConstant;
75  m_Cv = m_Cp / m_gamma;
76 
77  m_session->LoadParameter("Twall", m_Twall, 300.15);
78 
79  // Viscosity
80  m_session->LoadSolverInfo("ViscosityType", m_ViscosityType, "Constant");
81  m_session->LoadParameter("mu", m_muRef, 1.78e-05);
82  if (m_ViscosityType == "Variable")
83  {
84  m_is_mu_variable = true;
85  }
86 
87  // Thermal conductivity or Prandtl
88  if (m_session->DefinesParameter("thermalConductivity"))
89  {
90  ASSERTL0(!m_session->DefinesParameter("Pr"),
91  "Cannot define both Pr and thermalConductivity.");
92 
93  m_session->LoadParameter("thermalConductivity",
96  }
97  else
98  {
99  m_session->LoadParameter("Pr", m_Prandtl, 0.72);
101  }
102 
103  if (m_shockCaptureType == "Physical")
104  {
105  m_is_shockCaptPhys = true;
106  }
107 
108  string diffName;
109  m_session->LoadSolverInfo("DiffusionType", diffName, "LDGNS");
110 
111  m_diffusion =
112  SolverUtils::GetDiffusionFactory().CreateInstance(diffName, diffName);
113  if ("InteriorPenalty" == diffName)
114  {
115  m_is_diffIP = true;
117  }
118 
119  if ("LDGNS" == diffName || "LDGNS3DHomogeneous1D" == diffName)
120  {
121  m_diffusion->SetFluxPenaltyNS(&NavierStokesCFE::v_GetFluxPenalty, this);
122  }
123 
125  {
126  m_diffusion->SetFluxVectorNS(
128  }
129  else
130  {
132  this);
133  }
134 
135  m_diffusion->SetDiffusionFluxCons(
136  &NavierStokesCFE::GetViscousFluxVectorConservVar<false>, this);
137 
138  m_diffusion->SetDiffusionFluxConsTrace(
139  &NavierStokesCFE::GetViscousFluxVectorConservVar<true>, this);
140 
141  m_diffusion->SetSpecialBndTreat(&NavierStokesCFE::SpecialBndTreat, this);
142 
143  m_diffusion->SetDiffusionSymmFluxCons(
145 
146  // Concluding initialisation of diffusion operator
147  m_diffusion->InitObject(m_session, m_fields);
148 }
149 
151  const Array<OneD, Array<OneD, NekDouble>> &inarray,
152  Array<OneD, Array<OneD, NekDouble>> &outarray,
153  const Array<OneD, Array<OneD, NekDouble>> &pFwd,
154  const Array<OneD, Array<OneD, NekDouble>> &pBwd)
155 {
156  size_t nvariables = inarray.size();
157  size_t npoints = GetNpoints();
158  size_t nTracePts = GetTraceTotPoints();
159 
160  // this should be preallocated
161  Array<OneD, Array<OneD, NekDouble>> outarrayDiff(nvariables);
162  for (size_t i = 0; i < nvariables; ++i)
163  {
164  outarrayDiff[i] = Array<OneD, NekDouble>(npoints, 0.0);
165  }
166 
167  // Set artificial viscosity based on NS viscous tensor
168  if (m_is_shockCaptPhys)
169  {
170  if (m_varConv->GetFlagCalcDivCurl())
171  {
172  Array<OneD, NekDouble> div(npoints), curlSquare(npoints);
173  GetDivCurlSquared(m_fields, inarray, div, curlSquare, pFwd, pBwd);
174 
175  // Set volume and trace artificial viscosity
176  m_varConv->SetAv(m_fields, inarray, div, curlSquare);
177  }
178  else
179  {
180  m_varConv->SetAv(m_fields, inarray);
181  }
182  }
183 
184  if (m_is_diffIP)
185  {
186  if (m_bndEvaluateTime < 0.0)
187  {
188  NEKERROR(ErrorUtil::efatal, "m_bndEvaluateTime not setup");
189  }
190  m_diffusion->Diffuse(nvariables, m_fields, inarray, outarrayDiff,
191  m_bndEvaluateTime, pFwd, pBwd);
192  for (size_t i = 0; i < nvariables; ++i)
193  {
194  Vmath::Vadd(npoints, outarrayDiff[i], 1, outarray[i], 1,
195  outarray[i], 1);
196  }
197  }
198  else
199  {
200  // Get primitive variables [u,v,w,T]
201  Array<OneD, Array<OneD, NekDouble>> inarrayDiff(nvariables - 1);
202  Array<OneD, Array<OneD, NekDouble>> inFwd(nvariables - 1);
203  Array<OneD, Array<OneD, NekDouble>> inBwd(nvariables - 1);
204 
205  for (size_t i = 0; i < nvariables - 1; ++i)
206  {
207  inarrayDiff[i] = Array<OneD, NekDouble>{npoints};
208  inFwd[i] = Array<OneD, NekDouble>{nTracePts};
209  inBwd[i] = Array<OneD, NekDouble>{nTracePts};
210  }
211 
212  // Extract pressure
213  // (use inarrayDiff[0] as a temporary storage for the pressure)
214  m_varConv->GetPressure(inarray, inarrayDiff[0]);
215 
216  // Extract temperature
217  m_varConv->GetTemperature(inarray, inarrayDiff[nvariables - 2]);
218 
219  // Extract velocities
220  m_varConv->GetVelocityVector(inarray, inarrayDiff);
221 
222  // Repeat calculation for trace space
223  if (pFwd == NullNekDoubleArrayOfArray ||
225  {
228  }
229  else
230  {
231  m_varConv->GetPressure(pFwd, inFwd[0]);
232  m_varConv->GetPressure(pBwd, inBwd[0]);
233 
234  m_varConv->GetTemperature(pFwd, inFwd[nvariables - 2]);
235  m_varConv->GetTemperature(pBwd, inBwd[nvariables - 2]);
236 
237  m_varConv->GetVelocityVector(pFwd, inFwd);
238  m_varConv->GetVelocityVector(pBwd, inBwd);
239  }
240 
241  // Diffusion term in physical rhs form
242  m_diffusion->Diffuse(nvariables, m_fields, inarrayDiff, outarrayDiff,
243  inFwd, inBwd);
244 
245  for (size_t i = 0; i < nvariables; ++i)
246  {
247  Vmath::Vadd(npoints, outarrayDiff[i], 1, outarray[i], 1,
248  outarray[i], 1);
249  }
250  }
251 
252  // Add artificial diffusion through Laplacian operator
254  {
255  m_artificialDiffusion->DoArtificialDiffusion(inarray, outarray);
256  }
257 }
258 
259 /**
260  * @brief Return the flux vector for the LDG diffusion problem.
261  * \todo Complete the viscous flux vector
262  */
264  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
265  TensorOfArray3D<NekDouble> &derivativesO1,
266  TensorOfArray3D<NekDouble> &viscousTensor)
267 {
268  // Auxiliary variables
269  size_t nScalar = physfield.size();
270  size_t nPts = physfield[0].size();
271  Array<OneD, NekDouble> divVel(nPts, 0.0);
272 
273  // Stokes hypothesis
274  const NekDouble lambda = -2.0 / 3.0;
275 
276  // Update viscosity and thermal conductivity
277  Array<OneD, NekDouble> mu(nPts, 0.0);
278  Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
279  GetViscosityAndThermalCondFromTemp(physfield[nScalar - 1], mu,
280  thermalConductivity);
281 
282  // Velocity divergence
283  for (int j = 0; j < m_spacedim; ++j)
284  {
285  Vmath::Vadd(nPts, divVel, 1, derivativesO1[j][j], 1, divVel, 1);
286  }
287 
288  // Velocity divergence scaled by lambda * mu
289  Vmath::Smul(nPts, lambda, divVel, 1, divVel, 1);
290  Vmath::Vmul(nPts, mu, 1, divVel, 1, divVel, 1);
291 
292  // Viscous flux vector for the rho equation = 0
293  for (int i = 0; i < m_spacedim; ++i)
294  {
295  Vmath::Zero(nPts, viscousTensor[i][0], 1);
296  }
297 
298  // Viscous stress tensor (for the momentum equations)
299  for (int i = 0; i < m_spacedim; ++i)
300  {
301  for (int j = i; j < m_spacedim; ++j)
302  {
303  Vmath::Vadd(nPts, derivativesO1[i][j], 1, derivativesO1[j][i], 1,
304  viscousTensor[i][j + 1], 1);
305 
306  Vmath::Vmul(nPts, mu, 1, viscousTensor[i][j + 1], 1,
307  viscousTensor[i][j + 1], 1);
308 
309  if (i == j)
310  {
311  // Add divergence term to diagonal
312  Vmath::Vadd(nPts, viscousTensor[i][j + 1], 1, divVel, 1,
313  viscousTensor[i][j + 1], 1);
314  }
315  else
316  {
317  // Copy to make symmetric
318  Vmath::Vcopy(nPts, viscousTensor[i][j + 1], 1,
319  viscousTensor[j][i + 1], 1);
320  }
321  }
322  }
323 
324  // Terms for the energy equation
325  for (int i = 0; i < m_spacedim; ++i)
326  {
327  Vmath::Zero(nPts, viscousTensor[i][m_spacedim + 1], 1);
328  // u_j * tau_ij
329  for (int j = 0; j < m_spacedim; ++j)
330  {
331  Vmath::Vvtvp(nPts, physfield[j], 1, viscousTensor[i][j + 1], 1,
332  viscousTensor[i][m_spacedim + 1], 1,
333  viscousTensor[i][m_spacedim + 1], 1);
334  }
335  // Add k*T_i
336  Vmath::Vvtvp(nPts, thermalConductivity, 1, derivativesO1[i][m_spacedim],
337  1, viscousTensor[i][m_spacedim + 1], 1,
338  viscousTensor[i][m_spacedim + 1], 1);
339  }
340 }
341 
342 /**
343  * @brief Return the flux vector for the LDG diffusion problem.
344  * \todo Complete the viscous flux vector
345  */
347  const Array<OneD, const Array<OneD, NekDouble>> &physfield,
348  TensorOfArray3D<NekDouble> &derivativesO1,
349  TensorOfArray3D<NekDouble> &viscousTensor)
350 {
351  // Factor to rescale 1d points in dealiasing.
352  NekDouble OneDptscale = 2;
353  // Get number of points to dealias a cubic non-linearity
354  size_t nScalar = physfield.size();
355  size_t nPts = m_fields[0]->Get1DScaledTotPoints(OneDptscale);
356  size_t nPts_orig = physfield[0].size();
357 
358  // Auxiliary variables
359  Array<OneD, NekDouble> divVel(nPts, 0.0);
360 
361  // Stokes hypothesis
362  const NekDouble lambda = -2.0 / 3.0;
363 
364  // Update viscosity and thermal conductivity
365  Array<OneD, NekDouble> mu(nPts, 0.0);
366  Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
367  GetViscosityAndThermalCondFromTemp(physfield[nScalar - 1], mu,
368  thermalConductivity);
369 
370  // Interpolate inputs and initialise interpolated output
374  for (int i = 0; i < m_spacedim; ++i)
375  {
376  // Interpolate velocity
377  vel_interp[i] = Array<OneD, NekDouble>(nPts);
378  m_fields[0]->PhysInterp1DScaled(OneDptscale, physfield[i],
379  vel_interp[i]);
380 
381  // Interpolate derivatives
382  deriv_interp[i] = Array<OneD, Array<OneD, NekDouble>>(m_spacedim + 1);
383  for (int j = 0; j < m_spacedim + 1; ++j)
384  {
385  deriv_interp[i][j] = Array<OneD, NekDouble>(nPts);
386  m_fields[0]->PhysInterp1DScaled(OneDptscale, derivativesO1[i][j],
387  deriv_interp[i][j]);
388  }
389 
390  // Output (start from j=1 since flux is zero for rho)
391  out_interp[i] = Array<OneD, Array<OneD, NekDouble>>(m_spacedim + 2);
392  for (int j = 1; j < m_spacedim + 2; ++j)
393  {
394  out_interp[i][j] = Array<OneD, NekDouble>(nPts);
395  }
396  }
397 
398  // Velocity divergence
399  for (int j = 0; j < m_spacedim; ++j)
400  {
401  Vmath::Vadd(nPts, divVel, 1, deriv_interp[j][j], 1, divVel, 1);
402  }
403 
404  // Velocity divergence scaled by lambda * mu
405  Vmath::Smul(nPts, lambda, divVel, 1, divVel, 1);
406  Vmath::Vmul(nPts, mu, 1, divVel, 1, divVel, 1);
407 
408  // Viscous flux vector for the rho equation = 0 (no need to dealias)
409  for (int i = 0; i < m_spacedim; ++i)
410  {
411  Vmath::Zero(nPts_orig, viscousTensor[i][0], 1);
412  }
413 
414  // Viscous stress tensor (for the momentum equations)
415  for (int i = 0; i < m_spacedim; ++i)
416  {
417  for (int j = i; j < m_spacedim; ++j)
418  {
419  Vmath::Vadd(nPts, deriv_interp[i][j], 1, deriv_interp[j][i], 1,
420  out_interp[i][j + 1], 1);
421 
422  Vmath::Vmul(nPts, mu, 1, out_interp[i][j + 1], 1,
423  out_interp[i][j + 1], 1);
424 
425  if (i == j)
426  {
427  // Add divergence term to diagonal
428  Vmath::Vadd(nPts, out_interp[i][j + 1], 1, divVel, 1,
429  out_interp[i][j + 1], 1);
430  }
431  else
432  {
433  // Make symmetric
434  out_interp[j][i + 1] = out_interp[i][j + 1];
435  }
436  }
437  }
438 
439  // Terms for the energy equation
440  for (int i = 0; i < m_spacedim; ++i)
441  {
442  Vmath::Zero(nPts, out_interp[i][m_spacedim + 1], 1);
443  // u_j * tau_ij
444  for (int j = 0; j < m_spacedim; ++j)
445  {
446  Vmath::Vvtvp(nPts, vel_interp[j], 1, out_interp[i][j + 1], 1,
447  out_interp[i][m_spacedim + 1], 1,
448  out_interp[i][m_spacedim + 1], 1);
449  }
450  // Add k*T_i
451  Vmath::Vvtvp(nPts, thermalConductivity, 1, deriv_interp[i][m_spacedim],
452  1, out_interp[i][m_spacedim + 1], 1,
453  out_interp[i][m_spacedim + 1], 1);
454  }
455 
456  // Project to original space
457  for (int i = 0; i < m_spacedim; ++i)
458  {
459  for (int j = 1; j < m_spacedim + 2; ++j)
460  {
461  m_fields[0]->PhysGalerkinProjection1DScaled(
462  OneDptscale, out_interp[i][j], viscousTensor[i][j]);
463  }
464  }
465 }
466 
467 /**
468  * @brief For very special treatment. For general boundaries it does nothing
469  * But for WallViscous and WallAdiabatic, special treatment is needed
470  * because they get the same Bwd value, special treatment is needed for
471  * boundary treatment of diffusion flux
472  * Note: This special treatment could be removed by seperating
473  * WallViscous and WallAdiabatic into two different classes.
474  *
475  */
477  Array<OneD, Array<OneD, NekDouble>> &consvar)
478 {
479  size_t nConvectiveFields = consvar.size();
480  size_t ndens = 0;
481  size_t nengy = nConvectiveFields - 1;
482 
483  Array<OneD, Array<OneD, NekDouble>> bndCons{nConvectiveFields};
484  Array<OneD, NekDouble> bndTotEngy;
485  Array<OneD, NekDouble> bndPressure;
486  Array<OneD, NekDouble> bndRho;
487  Array<OneD, NekDouble> bndIntEndy;
488  size_t nLengthArray = 0;
489 
490  size_t cnt = 0;
491  size_t nBndRegions = m_fields[nengy]->GetBndCondExpansions().size();
492  for (size_t j = 0; j < nBndRegions; ++j)
493  {
494  if (m_fields[nengy]
495  ->GetBndConditions()[j]
496  ->GetBoundaryConditionType() == SpatialDomains::ePeriodic)
497  {
498  continue;
499  }
500 
501  size_t nBndEdges =
502  m_fields[nengy]->GetBndCondExpansions()[j]->GetExpSize();
503  for (size_t e = 0; e < nBndEdges; ++e)
504  {
505  size_t nBndEdgePts = m_fields[nengy]
506  ->GetBndCondExpansions()[j]
507  ->GetExp(e)
508  ->GetTotPoints();
509 
510  int id2 = m_fields[0]->GetTrace()->GetPhys_Offset(
511  m_fields[0]->GetTraceMap()->GetBndCondIDToGlobalTraceID(cnt++));
512 
513  // Imposing Temperature Twall at the wall
514  if (boost::iequals(
515  m_fields[nengy]->GetBndConditions()[j]->GetUserDefined(),
516  "WallViscous"))
517  {
518  if (nBndEdgePts != nLengthArray)
519  {
520  for (size_t i = 0; i < nConvectiveFields; ++i)
521  {
522  bndCons[i] = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
523  }
524  bndTotEngy = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
525  bndPressure = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
526  bndRho = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
527  bndIntEndy = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
528  nLengthArray = nBndEdgePts;
529  }
530  else
531  {
532  Vmath::Zero(nLengthArray, bndPressure, 1);
533  Vmath::Zero(nLengthArray, bndRho, 1);
534  Vmath::Zero(nLengthArray, bndIntEndy, 1);
535  }
536 
538 
539  for (size_t k = 0; k < nConvectiveFields; ++k)
540  {
541  Vmath::Vcopy(nBndEdgePts, tmp = consvar[k] + id2, 1,
542  bndCons[k], 1);
543  }
544 
545  m_varConv->GetPressure(bndCons, bndPressure);
546  Vmath::Fill(nLengthArray, m_Twall, bndTotEngy, 1);
547  m_varConv->GetRhoFromPT(bndPressure, bndTotEngy, bndRho);
548  m_varConv->GetEFromRhoP(bndRho, bndPressure, bndIntEndy);
549  m_varConv->GetDynamicEnergy(bndCons, bndTotEngy);
550 
551  Vmath::Vvtvp(nBndEdgePts, bndIntEndy, 1, bndCons[ndens], 1,
552  bndTotEngy, 1, bndTotEngy, 1);
553 
554  Vmath::Vcopy(nBndEdgePts, bndTotEngy, 1,
555  tmp = consvar[nengy] + id2, 1);
556  }
557  }
558  }
559 }
560 
561 /**
562  *
563  * @brief Calculate and return the Symmetric flux in IP method.
564  */
566  const size_t nDim, const Array<OneD, Array<OneD, NekDouble>> &inaverg,
567  const Array<OneD, Array<OneD, NekDouble>> &inarray,
568  TensorOfArray3D<NekDouble> &outarray, Array<OneD, int> &nonZeroIndex,
569  const Array<OneD, Array<OneD, NekDouble>> &normal)
570 {
571  size_t nConvectiveFields = inarray.size();
572  size_t nPts = inaverg[nConvectiveFields - 1].size();
573  nonZeroIndex = Array<OneD, int>{nConvectiveFields - 1, 0};
574  for (size_t i = 0; i < nConvectiveFields - 1; ++i)
575  {
576  nonZeroIndex[i] = i + 1;
577  }
578 
579  Array<OneD, NekDouble> mu(nPts, 0.0);
580  Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
581  Array<OneD, NekDouble> temperature(nPts, 0.0);
582  m_varConv->GetTemperature(inaverg, temperature);
583  GetViscosityAndThermalCondFromTemp(temperature, mu, thermalConductivity);
584 
585  std::vector<NekDouble> inAvgTmp(nConvectiveFields);
586  std::vector<NekDouble> inTmp(nConvectiveFields);
587  std::vector<NekDouble> outTmp(nConvectiveFields);
588  for (size_t d = 0; d < nDim; ++d)
589  {
590  for (size_t nderiv = 0; nderiv < nDim; ++nderiv)
591  {
592  for (size_t p = 0; p < nPts; ++p)
593  {
594  // rearrenge data
595  for (size_t f = 0; f < nConvectiveFields; ++f)
596  {
597  inAvgTmp[f] = inaverg[f][p];
598  inTmp[f] = inarray[f][p];
599  }
600 
601  GetViscousFluxBilinearFormKernel(nDim, d, nderiv,
602  inAvgTmp.data(), inTmp.data(),
603  mu[p], outTmp.data());
604 
605  for (size_t f = 0; f < nConvectiveFields; ++f)
606  {
607  outarray[d][f][p] += normal[nderiv][p] * outTmp[f];
608  }
609  }
610  }
611  }
612 }
613 
614 /**
615  * @brief Return the penalty vector for the LDGNS diffusion problem.
616  */
618  const Array<OneD, const Array<OneD, NekDouble>> &uFwd,
619  const Array<OneD, const Array<OneD, NekDouble>> &uBwd,
620  Array<OneD, Array<OneD, NekDouble>> &penaltyCoeff)
621 {
622  size_t nTracePts = uFwd[0].size();
623 
624  // Compute average temperature
625  size_t nVariables = uFwd.size();
626  Array<OneD, NekDouble> tAve{nTracePts, 0.0};
627  Vmath::Svtsvtp(nTracePts, 0.5, uFwd[nVariables - 1], 1, 0.5,
628  uBwd[nVariables - 1], 1, tAve, 1);
629 
630  // Get average viscosity and thermal conductivity
631  Array<OneD, NekDouble> muAve{nTracePts, 0.0};
632  Array<OneD, NekDouble> tcAve{nTracePts, 0.0};
633 
634  GetViscosityAndThermalCondFromTemp(tAve, muAve, tcAve);
635 
636  // Compute penalty term
637  for (size_t i = 0; i < nVariables; ++i)
638  {
639  // Get jump of u variables
640  Vmath::Vsub(nTracePts, uFwd[i], 1, uBwd[i], 1, penaltyCoeff[i], 1);
641  // Multiply by variable coefficient = {coeff} ( u^+ - u^- )
642  if (i < nVariables - 1)
643  {
644  Vmath::Vmul(nTracePts, muAve, 1, penaltyCoeff[i], 1,
645  penaltyCoeff[i], 1);
646  }
647  else
648  {
649  Vmath::Vmul(nTracePts, tcAve, 1, penaltyCoeff[i], 1,
650  penaltyCoeff[i], 1);
651  }
652  }
653 }
654 
655 /**
656  * @brief Update viscosity
657  * todo: add artificial viscosity here
658  */
660  const Array<OneD, NekDouble> &temperature, Array<OneD, NekDouble> &mu,
661  Array<OneD, NekDouble> &thermalCond)
662 {
663  size_t nPts = temperature.size();
664 
665  for (size_t p = 0; p < nPts; ++p)
666  {
667  GetViscosityAndThermalCondFromTempKernel(temperature[p], mu[p],
668  thermalCond[p]);
669  }
670 
671  // Add artificial viscosity if wanted
672  // move this above and add in kernel
673  if (m_is_shockCaptPhys)
674  {
675  size_t nTracePts = m_fields[0]->GetTrace()->GetTotPoints();
676  if (nPts != nTracePts)
677  {
678  Vmath::Vadd(nPts, mu, 1, m_varConv->GetAv(), 1, mu, 1);
679  }
680  else
681  {
682  Vmath::Vadd(nPts, mu, 1, m_varConv->GetAvTrace(), 1, mu, 1);
683  }
684 
685  // Update thermal conductivity
686  NekDouble tRa = m_Cp / m_Prandtl;
687  Vmath::Smul(nPts, tRa, mu, 1, thermalCond, 1);
688  }
689 }
690 
691 /**
692  * @brief Get divergence and curl squared
693  *
694  * @param input
695  * fields -> expansion list pointer
696  * cnsVar -> conservative variables
697  * cnsVarFwd -> forward trace of conservative variables
698  * cnsVarBwd -> backward trace of conservative variables
699  * @paran output
700  * divSquare -> divergence
701  * curlSquare -> curl squared
702  *
703  */
706  const Array<OneD, Array<OneD, NekDouble>> &cnsVar,
708  const Array<OneD, Array<OneD, NekDouble>> &cnsVarFwd,
709  const Array<OneD, Array<OneD, NekDouble>> &cnsVarBwd)
710 {
711  size_t nDim = fields[0]->GetCoordim(0);
712  size_t nVar = cnsVar.size();
713  size_t nPts = cnsVar[0].size();
714  size_t nPtsTrc = cnsVarFwd[0].size();
715 
716  // These should be allocated once
717  Array<OneD, Array<OneD, NekDouble>> primVar(nVar - 1), primVarFwd(nVar - 1),
718  primVarBwd(nVar - 1);
719 
720  for (unsigned short d = 0; d < nVar - 2; ++d)
721  {
722  primVar[d] = Array<OneD, NekDouble>(nPts, 0.0);
723  primVarFwd[d] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
724  primVarBwd[d] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
725  }
726  size_t ergLoc = nVar - 2;
727  primVar[ergLoc] = Array<OneD, NekDouble>(nPts, 0.0);
728  primVarFwd[ergLoc] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
729  primVarBwd[ergLoc] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
730 
731  // Get primitive variables [u,v,w,T=0]
732  // Possibly should be changed to [rho,u,v,w,T] to make IP and LDGNS more
733  // consistent with each other
734  for (unsigned short d = 0; d < nVar - 2; ++d)
735  {
736  // Volume
737  for (size_t p = 0; p < nPts; ++p)
738  {
739  primVar[d][p] = cnsVar[d + 1][p] / cnsVar[0][p];
740  }
741  // Trace
742  for (size_t p = 0; p < nPtsTrc; ++p)
743  {
744  primVarFwd[d][p] = cnsVarFwd[d + 1][p] / cnsVarFwd[0][p];
745  primVarBwd[d][p] = cnsVarBwd[d + 1][p] / cnsVarBwd[0][p];
746  }
747  }
748 
749  // this should be allocated once
751  for (unsigned short j = 0; j < nDim; ++j)
752  {
753  primVarDer[j] = Array<OneD, Array<OneD, NekDouble>>(nVar - 1);
754  for (unsigned short i = 0; i < nVar - 1; ++i)
755  {
756  primVarDer[j][i] = Array<OneD, NekDouble>(nPts, 0.0);
757  }
758  }
759 
760  // Get derivative tensor
761  m_diffusion->DiffuseCalcDerivative(fields, primVar, primVarDer, primVarFwd,
762  primVarBwd);
763 
764  // Get div curl squared
765  GetDivCurlFromDvelT(primVarDer, div, curlSquare);
766 }
767 
768 /**
769  * @brief Get divergence and curl from velocity derivative tensor
770  *
771  */
774  Array<OneD, NekDouble> &curlSquare)
775 {
776  size_t nDim = pVarDer.size();
777  size_t nPts = div.size();
778 
779  // div velocity
780  for (size_t p = 0; p < nPts; ++p)
781  {
782  NekDouble divTmp = 0;
783  for (unsigned short j = 0; j < nDim; ++j)
784  {
785  divTmp += pVarDer[j][j][p];
786  }
787  div[p] = divTmp;
788  }
789 
790  // |curl velocity| ** 2
791  if (nDim > 2)
792  {
793  for (size_t p = 0; p < nPts; ++p)
794  {
795  // curl[0] 3/2 - 2/3
796  NekDouble curl032 = pVarDer[2][1][p]; // load 1x
797  NekDouble curl023 = pVarDer[1][2][p]; // load 1x
798  NekDouble curl0 = curl032 - curl023;
799  // square curl[0]
800  NekDouble curl0sqr = curl0 * curl0;
801 
802  // curl[1] 3/1 - 1/3
803  NekDouble curl131 = pVarDer[2][0][p]; // load 1x
804  NekDouble curl113 = pVarDer[0][2][p]; // load 1x
805  NekDouble curl1 = curl131 - curl113;
806  // square curl[1]
807  NekDouble curl1sqr = curl1 * curl1;
808 
809  // curl[2] 1/2 - 2/1
810  NekDouble curl212 = pVarDer[0][1][p]; // load 1x
811  NekDouble curl221 = pVarDer[1][0][p]; // load 1x
812  NekDouble curl2 = curl212 - curl221;
813  // square curl[2]
814  NekDouble curl2sqr = curl2 * curl2;
815 
816  // reduce
817  curl0sqr += curl1sqr + curl2sqr;
818  // store
819  curlSquare[p] = curl0sqr; // store 1x
820  }
821  }
822  else if (nDim > 1)
823  {
824  for (size_t p = 0; p < nPts; ++p)
825  {
826  // curl[2] 1/2
827  NekDouble c212 = pVarDer[0][1][p]; // load 1x
828  // curl[2] 2/1
829  NekDouble c221 = pVarDer[1][0][p]; // load 1x
830  // curl[2] 1/2 - 2/1
831  NekDouble curl = c212 - c221;
832  // square curl[2]
833  curlSquare[p] = curl * curl; // store 1x
834  }
835  }
836  else
837  {
838  Vmath::Fill(nPts, 0.0, curlSquare, 1);
839  }
840 }
841 
843  std::vector<Array<OneD, NekDouble>> &fieldcoeffs,
844  std::vector<std::string> &variables)
845 {
846  bool extraFields;
847  m_session->MatchSolverInfo("OutputExtraFields", "True", extraFields, true);
848  if (extraFields)
849  {
850  const int nPhys = m_fields[0]->GetNpoints();
851  const int nCoeffs = m_fields[0]->GetNcoeffs();
853 
854  for (size_t i = 0; i < m_fields.size(); ++i)
855  {
856  cnsVar[i] = m_fields[i]->GetPhys();
857  }
858 
861  for (int i = 0; i < m_spacedim; ++i)
862  {
863  velocity[i] = Array<OneD, NekDouble>(nPhys);
864  velFwd[i] = Array<OneD, NekDouble>(nCoeffs);
865  }
866 
867  Array<OneD, NekDouble> pressure(nPhys), temperature(nPhys);
868  Array<OneD, NekDouble> entropy(nPhys);
869  Array<OneD, NekDouble> soundspeed(nPhys), mach(nPhys);
870  Array<OneD, NekDouble> sensor(nPhys), SensorKappa(nPhys);
871 
872  m_varConv->GetVelocityVector(cnsVar, velocity);
873  m_varConv->GetPressure(cnsVar, pressure);
874  m_varConv->GetTemperature(cnsVar, temperature);
875  m_varConv->GetEntropy(cnsVar, entropy);
876  m_varConv->GetSoundSpeed(cnsVar, soundspeed);
877  m_varConv->GetMach(cnsVar, soundspeed, mach);
878 
879  int sensorOffset;
880  m_session->LoadParameter("SensorOffset", sensorOffset, 1);
881  m_varConv->GetSensor(m_fields[0], cnsVar, sensor, SensorKappa,
882  sensorOffset);
883 
884  Array<OneD, NekDouble> pFwd(nCoeffs), TFwd(nCoeffs);
885  Array<OneD, NekDouble> sFwd(nCoeffs);
886  Array<OneD, NekDouble> aFwd(nCoeffs), mFwd(nCoeffs);
887  Array<OneD, NekDouble> sensFwd(nCoeffs);
888 
889  string velNames[3] = {"u", "v", "w"};
890  for (int i = 0; i < m_spacedim; ++i)
891  {
892  m_fields[0]->FwdTransLocalElmt(velocity[i], velFwd[i]);
893  variables.push_back(velNames[i]);
894  fieldcoeffs.push_back(velFwd[i]);
895  }
896 
897  m_fields[0]->FwdTransLocalElmt(pressure, pFwd);
898  m_fields[0]->FwdTransLocalElmt(temperature, TFwd);
899  m_fields[0]->FwdTransLocalElmt(entropy, sFwd);
900  m_fields[0]->FwdTransLocalElmt(soundspeed, aFwd);
901  m_fields[0]->FwdTransLocalElmt(mach, mFwd);
902  m_fields[0]->FwdTransLocalElmt(sensor, sensFwd);
903 
904  variables.push_back("p");
905  variables.push_back("T");
906  variables.push_back("s");
907  variables.push_back("a");
908  variables.push_back("Mach");
909  variables.push_back("Sensor");
910  fieldcoeffs.push_back(pFwd);
911  fieldcoeffs.push_back(TFwd);
912  fieldcoeffs.push_back(sFwd);
913  fieldcoeffs.push_back(aFwd);
914  fieldcoeffs.push_back(mFwd);
915  fieldcoeffs.push_back(sensFwd);
916 
918  {
919  // reuse pressure
920  Array<OneD, NekDouble> sensorFwd(nCoeffs);
921  m_artificialDiffusion->GetArtificialViscosity(cnsVar, pressure);
922  m_fields[0]->FwdTransLocalElmt(pressure, sensorFwd);
923 
924  variables.push_back("ArtificialVisc");
925  fieldcoeffs.push_back(sensorFwd);
926  }
927 
928  if (m_is_shockCaptPhys)
929  {
930 
931  Array<OneD, Array<OneD, NekDouble>> cnsVarFwd(m_fields.size()),
932  cnsVarBwd(m_fields.size());
933 
934  for (size_t i = 0; i < m_fields.size(); ++i)
935  {
936  cnsVarFwd[i] = Array<OneD, NekDouble>(GetTraceTotPoints());
937  cnsVarBwd[i] = Array<OneD, NekDouble>(GetTraceTotPoints());
938  m_fields[i]->GetFwdBwdTracePhys(cnsVar[i], cnsVarFwd[i],
939  cnsVarBwd[i]);
940  }
941 
942  Array<OneD, NekDouble> div(nPhys), curlSquare(nPhys);
943  GetDivCurlSquared(m_fields, cnsVar, div, curlSquare, cnsVarFwd,
944  cnsVarBwd);
945 
946  Array<OneD, NekDouble> divFwd(nCoeffs, 0.0);
947  m_fields[0]->FwdTransLocalElmt(div, divFwd);
948  variables.push_back("div");
949  fieldcoeffs.push_back(divFwd);
950 
951  Array<OneD, NekDouble> curlFwd(nCoeffs, 0.0);
952  m_fields[0]->FwdTransLocalElmt(curlSquare, curlFwd);
953  variables.push_back("curl^2");
954  fieldcoeffs.push_back(curlFwd);
955 
956  m_varConv->SetAv(m_fields, cnsVar, div, curlSquare);
957 
958  Array<OneD, NekDouble> muavFwd(nCoeffs);
959  m_fields[0]->FwdTransLocalElmt(m_varConv->GetAv(), muavFwd);
960  variables.push_back("ArtificialVisc");
961  fieldcoeffs.push_back(muavFwd);
962  }
963  }
964 }
965 
966 bool NavierStokesCFE::v_SupportsShockCaptType(const std::string type) const
967 {
968  if (type == "NonSmooth" || type == "Physical" || type == "Off")
969  {
970  return true;
971  }
972  else
973  {
974  return false;
975  }
976 }
977 } // 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
SolverUtils::DiffusionSharedPtr m_diffusion
virtual void v_InitObject(bool DeclareFields=true) override
Initialization object for CompressibleFlowSystem class.
VariableConverterSharedPtr m_varConv
void SetBoundaryConditionsBwdWeight()
Set up a weight on physical boundaries for boundary condition applications.
ArtificialDiffusionSharedPtr m_artificialDiffusion
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
virtual void v_GetViscousFluxVector(const Array< OneD, const Array< OneD, NekDouble >> &physfield, TensorOfArray3D< NekDouble > &derivatives, TensorOfArray3D< NekDouble > &viscousTensor)
Return the flux vector for the LDG diffusion problem.
void GetDivCurlFromDvelT(const TensorOfArray3D< NekDouble > &pVarDer, Array< OneD, NekDouble > &div, Array< OneD, NekDouble > &curlSquare)
Get divergence and curl from velocity derivative tensor.
virtual void v_InitObject(bool DeclareField=true) override
Initialization object for CompressibleFlowSystem class.
void SpecialBndTreat(Array< OneD, Array< OneD, NekDouble >> &consvar)
For very special treatment. For general boundaries it does nothing But for WallViscous and WallAdiaba...
void GetDivCurlSquared(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const Array< OneD, Array< OneD, NekDouble >> &cnsVar, Array< OneD, NekDouble > &div, Array< OneD, NekDouble > &curlSquare, const Array< OneD, Array< OneD, NekDouble >> &cnsVarFwd, const Array< OneD, Array< OneD, NekDouble >> &cnsVarBwd)
Get divergence and curl squared.
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) override
void GetViscousSymmtrFluxConservVar(const size_t nSpaceDim, const Array< OneD, Array< OneD, NekDouble >> &inaverg, const Array< OneD, Array< OneD, NekDouble >> &inarray, TensorOfArray3D< NekDouble > &outarray, Array< OneD, int > &nonZeroIndex, const Array< OneD, Array< OneD, NekDouble >> &normals)
Calculate and return the Symmetric flux in IP method.
NekDouble m_thermalConductivityRef
bool m_is_mu_variable
flag to switch between constant viscosity and Sutherland an enum could be added for more options
bool m_is_shockCaptPhys
flag for shock capturing switch on/off an enum could be added for more options
virtual void v_GetViscousFluxVectorDeAlias(const Array< OneD, const Array< OneD, NekDouble >> &physfield, TensorOfArray3D< NekDouble > &derivatives, TensorOfArray3D< NekDouble > &viscousTensor)
Return the flux vector for the LDG diffusion problem.
virtual bool v_SupportsShockCaptType(const std::string type) const override
void GetViscosityAndThermalCondFromTemp(const Array< OneD, NekDouble > &temperature, Array< OneD, NekDouble > &mu, Array< OneD, NekDouble > &thermalCond)
Update viscosity todo: add artificial viscosity here.
bool m_is_diffIP
flag to switch between IP and LDG an enum could be added for more options
virtual void v_ExtraFldOutput(std::vector< Array< OneD, NekDouble >> &fieldcoeffs, std::vector< std::string > &variables) override
void GetViscousFluxBilinearFormKernel(const unsigned short nDim, const unsigned short FluxDirection, const unsigned short DerivDirection, const T *inaverg, const T *injumpp, const T &mu, T *outarray)
Calculate diffusion flux using the Jacobian form.
virtual void v_GetFluxPenalty(const Array< OneD, const Array< OneD, NekDouble >> &uFwd, const Array< OneD, const Array< OneD, NekDouble >> &uBwd, Array< OneD, Array< OneD, NekDouble >> &penaltyCoeff)
Return the penalty vector for the LDGNS diffusion problem.
void GetViscosityAndThermalCondFromTempKernel(const T &temperature, T &mu, T &thermalCond)
int m_spacedim
Spatial dimension (>= expansion dim).
SOLVER_UTILS_EXPORT int GetTraceTotPoints()
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
bool m_specHP_dealiasing
Flag to determine if dealisising is usde for the Spectral/hp element discretisation.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
SOLVER_UTILS_EXPORT int GetNpoints()
Base class for unsteady solvers.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
DiffusionFactory & GetDiffusionFactory()
Definition: Diffusion.cpp:41
EquationSystemFactory & GetEquationSystemFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:172
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
static Array< OneD, Array< OneD, NekDouble > > NullNekDoubleArrayOfArray
double NekDouble
void Svtsvtp(int n, const T alpha, const T *x, int incx, const T beta, const T *y, int incy, T *z, int incz)
svtvvtp (scalar times vector plus scalar times vector):
Definition: Vmath.cpp:751
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
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 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
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