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