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}
145
147 const Array<OneD, Array<OneD, NekDouble>> &inarray,
149 const Array<OneD, Array<OneD, NekDouble>> &pFwd,
150 const Array<OneD, Array<OneD, NekDouble>> &pBwd)
151{
152 size_t nvariables = inarray.size();
153 size_t npoints = GetNpoints();
154 size_t nTracePts = GetTraceTotPoints();
155
156 // this should be preallocated
157 Array<OneD, Array<OneD, NekDouble>> outarrayDiff(nvariables);
158 for (size_t i = 0; i < nvariables; ++i)
159 {
160 outarrayDiff[i] = Array<OneD, NekDouble>(npoints, 0.0);
161 }
162
163 // Set artificial viscosity based on NS viscous tensor
165 {
166 if (m_varConv->GetFlagCalcDivCurl())
167 {
168 Array<OneD, NekDouble> div(npoints), curlSquare(npoints);
169 GetDivCurlSquared(m_fields, inarray, div, curlSquare, pFwd, pBwd);
170
171 // Set volume and trace artificial viscosity
172 m_varConv->SetAv(m_fields, inarray, div, curlSquare);
173 }
174 else
175 {
176 m_varConv->SetAv(m_fields, inarray);
177 }
178 }
179
180 if (m_is_diffIP)
181 {
182 if (m_bndEvaluateTime < 0.0)
183 {
184 NEKERROR(ErrorUtil::efatal, "m_bndEvaluateTime not setup");
185 }
186 m_diffusion->Diffuse(nvariables, m_fields, inarray, outarrayDiff,
187 m_bndEvaluateTime, pFwd, pBwd);
188 for (size_t i = 0; i < nvariables; ++i)
189 {
190 Vmath::Vadd(npoints, outarrayDiff[i], 1, outarray[i], 1,
191 outarray[i], 1);
192 }
193 }
194 else
195 {
196 // Get primitive variables [u,v,w,T]
197 Array<OneD, Array<OneD, NekDouble>> inarrayDiff(nvariables - 1);
198 Array<OneD, Array<OneD, NekDouble>> inFwd(nvariables - 1);
199 Array<OneD, Array<OneD, NekDouble>> inBwd(nvariables - 1);
200
201 for (size_t i = 0; i < nvariables - 1; ++i)
202 {
203 inarrayDiff[i] = Array<OneD, NekDouble>{npoints};
204 inFwd[i] = Array<OneD, NekDouble>{nTracePts};
205 inBwd[i] = Array<OneD, NekDouble>{nTracePts};
206 }
207
208 // Extract pressure
209 // (use inarrayDiff[0] as a temporary storage for the pressure)
210 m_varConv->GetPressure(inarray, inarrayDiff[0]);
211
212 // Extract temperature
213 m_varConv->GetTemperature(inarray, inarrayDiff[nvariables - 2]);
214
215 // Extract velocities
216 m_varConv->GetVelocityVector(inarray, inarrayDiff);
217
218 // Repeat calculation for trace space
219 if (pFwd == NullNekDoubleArrayOfArray ||
221 {
224 }
225 else
226 {
227 m_varConv->GetPressure(pFwd, inFwd[0]);
228 m_varConv->GetPressure(pBwd, inBwd[0]);
229
230 m_varConv->GetTemperature(pFwd, inFwd[nvariables - 2]);
231 m_varConv->GetTemperature(pBwd, inBwd[nvariables - 2]);
232
233 m_varConv->GetVelocityVector(pFwd, inFwd);
234 m_varConv->GetVelocityVector(pBwd, inBwd);
235 }
236
237 // Diffusion term in physical rhs form
238 m_diffusion->Diffuse(nvariables, m_fields, inarrayDiff, outarrayDiff,
239 inFwd, inBwd);
240
241 for (size_t i = 0; i < nvariables; ++i)
242 {
243 Vmath::Vadd(npoints, outarrayDiff[i], 1, outarray[i], 1,
244 outarray[i], 1);
245 }
246 }
247
248 // Add artificial diffusion through Laplacian operator
250 {
251 m_artificialDiffusion->DoArtificialDiffusion(inarray, outarray);
252 }
253}
254
255/**
256 * @brief Return the flux vector for the LDG diffusion problem.
257 * \todo Complete the viscous flux vector
258 */
260 const Array<OneD, const Array<OneD, NekDouble>> &physfield,
261 TensorOfArray3D<NekDouble> &derivativesO1,
262 TensorOfArray3D<NekDouble> &viscousTensor)
263{
264 // Auxiliary variables
265 size_t nScalar = physfield.size();
266 size_t nPts = physfield[0].size();
267 Array<OneD, NekDouble> divVel(nPts, 0.0);
268
269 // Stokes hypothesis
270 const NekDouble lambda = -2.0 / 3.0;
271
272 // Update viscosity and thermal conductivity
273 Array<OneD, NekDouble> mu(nPts, 0.0);
274 Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
275 GetViscosityAndThermalCondFromTemp(physfield[nScalar - 1], mu,
276 thermalConductivity);
277
278 // Velocity divergence
279 for (int j = 0; j < m_spacedim; ++j)
280 {
281 Vmath::Vadd(nPts, divVel, 1, derivativesO1[j][j], 1, divVel, 1);
282 }
283
284 // Velocity divergence scaled by lambda * mu
285 Vmath::Smul(nPts, lambda, divVel, 1, divVel, 1);
286 Vmath::Vmul(nPts, mu, 1, divVel, 1, divVel, 1);
287
288 // Viscous flux vector for the rho equation = 0
289 for (int i = 0; i < m_spacedim; ++i)
290 {
291 Vmath::Zero(nPts, viscousTensor[i][0], 1);
292 }
293
294 // Viscous stress tensor (for the momentum equations)
295 for (int i = 0; i < m_spacedim; ++i)
296 {
297 for (int j = i; j < m_spacedim; ++j)
298 {
299 Vmath::Vadd(nPts, derivativesO1[i][j], 1, derivativesO1[j][i], 1,
300 viscousTensor[i][j + 1], 1);
301
302 Vmath::Vmul(nPts, mu, 1, viscousTensor[i][j + 1], 1,
303 viscousTensor[i][j + 1], 1);
304
305 if (i == j)
306 {
307 // Add divergence term to diagonal
308 Vmath::Vadd(nPts, viscousTensor[i][j + 1], 1, divVel, 1,
309 viscousTensor[i][j + 1], 1);
310 }
311 else
312 {
313 // Copy to make symmetric
314 Vmath::Vcopy(nPts, viscousTensor[i][j + 1], 1,
315 viscousTensor[j][i + 1], 1);
316 }
317 }
318 }
319
320 // Terms for the energy equation
321 for (int i = 0; i < m_spacedim; ++i)
322 {
323 Vmath::Zero(nPts, viscousTensor[i][m_spacedim + 1], 1);
324 // u_j * tau_ij
325 for (int j = 0; j < m_spacedim; ++j)
326 {
327 Vmath::Vvtvp(nPts, physfield[j], 1, viscousTensor[i][j + 1], 1,
328 viscousTensor[i][m_spacedim + 1], 1,
329 viscousTensor[i][m_spacedim + 1], 1);
330 }
331 // Add k*T_i
332 Vmath::Vvtvp(nPts, thermalConductivity, 1, derivativesO1[i][m_spacedim],
333 1, viscousTensor[i][m_spacedim + 1], 1,
334 viscousTensor[i][m_spacedim + 1], 1);
335 }
336}
337
338/**
339 * @brief Return the flux vector for the LDG diffusion problem.
340 * \todo Complete the viscous flux vector
341 */
343 const Array<OneD, const Array<OneD, NekDouble>> &physfield,
344 TensorOfArray3D<NekDouble> &derivativesO1,
345 TensorOfArray3D<NekDouble> &viscousTensor)
346{
347 // Factor to rescale 1d points in dealiasing.
348 NekDouble OneDptscale = 2;
349 // Get number of points to dealias a cubic non-linearity
350 size_t nScalar = physfield.size();
351 size_t nPts = m_fields[0]->Get1DScaledTotPoints(OneDptscale);
352 size_t nPts_orig = physfield[0].size();
353
354 // Auxiliary variables
355 Array<OneD, NekDouble> divVel(nPts, 0.0);
356
357 // Stokes hypothesis
358 const NekDouble lambda = -2.0 / 3.0;
359
360 // Update viscosity and thermal conductivity
361 Array<OneD, NekDouble> mu(nPts, 0.0);
362 Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
363 GetViscosityAndThermalCondFromTemp(physfield[nScalar - 1], mu,
364 thermalConductivity);
365
366 // Interpolate inputs and initialise interpolated output
370 for (int i = 0; i < m_spacedim; ++i)
371 {
372 // Interpolate velocity
373 vel_interp[i] = Array<OneD, NekDouble>(nPts);
374 m_fields[0]->PhysInterp1DScaled(OneDptscale, physfield[i],
375 vel_interp[i]);
376
377 // Interpolate derivatives
378 deriv_interp[i] = Array<OneD, Array<OneD, NekDouble>>(m_spacedim + 1);
379 for (int j = 0; j < m_spacedim + 1; ++j)
380 {
381 deriv_interp[i][j] = Array<OneD, NekDouble>(nPts);
382 m_fields[0]->PhysInterp1DScaled(OneDptscale, derivativesO1[i][j],
383 deriv_interp[i][j]);
384 }
385
386 // Output (start from j=1 since flux is zero for rho)
388 for (int j = 1; j < m_spacedim + 2; ++j)
389 {
390 out_interp[i][j] = Array<OneD, NekDouble>(nPts);
391 }
392 }
393
394 // Velocity divergence
395 for (int j = 0; j < m_spacedim; ++j)
396 {
397 Vmath::Vadd(nPts, divVel, 1, deriv_interp[j][j], 1, divVel, 1);
398 }
399
400 // Velocity divergence scaled by lambda * mu
401 Vmath::Smul(nPts, lambda, divVel, 1, divVel, 1);
402 Vmath::Vmul(nPts, mu, 1, divVel, 1, divVel, 1);
403
404 // Viscous flux vector for the rho equation = 0 (no need to dealias)
405 for (int i = 0; i < m_spacedim; ++i)
406 {
407 Vmath::Zero(nPts_orig, viscousTensor[i][0], 1);
408 }
409
410 // Viscous stress tensor (for the momentum equations)
411 for (int i = 0; i < m_spacedim; ++i)
412 {
413 for (int j = i; j < m_spacedim; ++j)
414 {
415 Vmath::Vadd(nPts, deriv_interp[i][j], 1, deriv_interp[j][i], 1,
416 out_interp[i][j + 1], 1);
417
418 Vmath::Vmul(nPts, mu, 1, out_interp[i][j + 1], 1,
419 out_interp[i][j + 1], 1);
420
421 if (i == j)
422 {
423 // Add divergence term to diagonal
424 Vmath::Vadd(nPts, out_interp[i][j + 1], 1, divVel, 1,
425 out_interp[i][j + 1], 1);
426 }
427 else
428 {
429 // Make symmetric
430 out_interp[j][i + 1] = out_interp[i][j + 1];
431 }
432 }
433 }
434
435 // Terms for the energy equation
436 for (int i = 0; i < m_spacedim; ++i)
437 {
438 Vmath::Zero(nPts, out_interp[i][m_spacedim + 1], 1);
439 // u_j * tau_ij
440 for (int j = 0; j < m_spacedim; ++j)
441 {
442 Vmath::Vvtvp(nPts, vel_interp[j], 1, out_interp[i][j + 1], 1,
443 out_interp[i][m_spacedim + 1], 1,
444 out_interp[i][m_spacedim + 1], 1);
445 }
446 // Add k*T_i
447 Vmath::Vvtvp(nPts, thermalConductivity, 1, deriv_interp[i][m_spacedim],
448 1, out_interp[i][m_spacedim + 1], 1,
449 out_interp[i][m_spacedim + 1], 1);
450 }
451
452 // Project to original space
453 for (int i = 0; i < m_spacedim; ++i)
454 {
455 for (int j = 1; j < m_spacedim + 2; ++j)
456 {
457 m_fields[0]->PhysGalerkinProjection1DScaled(
458 OneDptscale, out_interp[i][j], viscousTensor[i][j]);
459 }
460 }
461}
462
463/**
464 * @brief For very special treatment. For general boundaries it does nothing
465 * But for WallViscous and WallAdiabatic, special treatment is needed
466 * because they get the same Bwd value, special treatment is needed for
467 * boundary treatment of diffusion flux
468 * Note: This special treatment could be removed by seperating
469 * WallViscous and WallAdiabatic into two different classes.
470 *
471 */
474{
475 size_t nConvectiveFields = consvar.size();
476 size_t ndens = 0;
477 size_t nengy = nConvectiveFields - 1;
478
479 Array<OneD, Array<OneD, NekDouble>> bndCons{nConvectiveFields};
480 Array<OneD, NekDouble> bndTotEngy;
481 Array<OneD, NekDouble> bndPressure;
483 Array<OneD, NekDouble> bndIntEndy;
484 size_t nLengthArray = 0;
485
486 size_t cnt = 0;
487 size_t nBndRegions = m_fields[nengy]->GetBndCondExpansions().size();
488 for (size_t j = 0; j < nBndRegions; ++j)
489 {
490 if (m_fields[nengy]
491 ->GetBndConditions()[j]
492 ->GetBoundaryConditionType() == SpatialDomains::ePeriodic)
493 {
494 continue;
495 }
496
497 size_t nBndEdges =
498 m_fields[nengy]->GetBndCondExpansions()[j]->GetExpSize();
499 for (size_t e = 0; e < nBndEdges; ++e)
500 {
501 size_t nBndEdgePts = m_fields[nengy]
502 ->GetBndCondExpansions()[j]
503 ->GetExp(e)
504 ->GetTotPoints();
505
506 int id2 = m_fields[0]->GetTrace()->GetPhys_Offset(
507 m_fields[0]->GetTraceMap()->GetBndCondIDToGlobalTraceID(cnt++));
508
509 // Imposing Temperature Twall at the wall
510 if (boost::iequals(
511 m_fields[nengy]->GetBndConditions()[j]->GetUserDefined(),
512 "WallViscous"))
513 {
514 if (nBndEdgePts != nLengthArray)
515 {
516 for (size_t i = 0; i < nConvectiveFields; ++i)
517 {
518 bndCons[i] = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
519 }
520 bndTotEngy = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
521 bndPressure = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
522 bndRho = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
523 bndIntEndy = Array<OneD, NekDouble>{nBndEdgePts, 0.0};
524 nLengthArray = nBndEdgePts;
525 }
526 else
527 {
528 Vmath::Zero(nLengthArray, bndPressure, 1);
529 Vmath::Zero(nLengthArray, bndRho, 1);
530 Vmath::Zero(nLengthArray, bndIntEndy, 1);
531 }
532
534
535 for (size_t k = 0; k < nConvectiveFields; ++k)
536 {
537 Vmath::Vcopy(nBndEdgePts, tmp = consvar[k] + id2, 1,
538 bndCons[k], 1);
539 }
540
541 m_varConv->GetPressure(bndCons, bndPressure);
542 Vmath::Fill(nLengthArray, m_Twall, bndTotEngy, 1);
543 m_varConv->GetRhoFromPT(bndPressure, bndTotEngy, bndRho);
544 m_varConv->GetEFromRhoP(bndRho, bndPressure, bndIntEndy);
545 m_varConv->GetDynamicEnergy(bndCons, bndTotEngy);
546
547 Vmath::Vvtvp(nBndEdgePts, bndIntEndy, 1, bndCons[ndens], 1,
548 bndTotEngy, 1, bndTotEngy, 1);
549
550 Vmath::Vcopy(nBndEdgePts, bndTotEngy, 1,
551 tmp = consvar[nengy] + id2, 1);
552 }
553 }
554 }
555}
556
557/**
558 *
559 * @brief Calculate and return the Symmetric flux in IP method.
560 */
562 const size_t nDim, const Array<OneD, Array<OneD, NekDouble>> &inaverg,
563 const Array<OneD, Array<OneD, NekDouble>> &inarray,
564 TensorOfArray3D<NekDouble> &outarray, Array<OneD, int> &nonZeroIndex,
565 const Array<OneD, Array<OneD, NekDouble>> &normal)
566{
567 size_t nConvectiveFields = inarray.size();
568 size_t nPts = inaverg[nConvectiveFields - 1].size();
569 nonZeroIndex = Array<OneD, int>{nConvectiveFields - 1, 0};
570 for (size_t i = 0; i < nConvectiveFields - 1; ++i)
571 {
572 nonZeroIndex[i] = i + 1;
573 }
574
575 Array<OneD, NekDouble> mu(nPts, 0.0);
576 Array<OneD, NekDouble> thermalConductivity(nPts, 0.0);
577 Array<OneD, NekDouble> temperature(nPts, 0.0);
578 m_varConv->GetTemperature(inaverg, temperature);
579 GetViscosityAndThermalCondFromTemp(temperature, mu, thermalConductivity);
580
581 std::vector<NekDouble> inAvgTmp(nConvectiveFields);
582 std::vector<NekDouble> inTmp(nConvectiveFields);
583 std::vector<NekDouble> outTmp(nConvectiveFields);
584 for (size_t d = 0; d < nDim; ++d)
585 {
586 for (size_t nderiv = 0; nderiv < nDim; ++nderiv)
587 {
588 for (size_t p = 0; p < nPts; ++p)
589 {
590 // rearrenge data
591 for (size_t f = 0; f < nConvectiveFields; ++f)
592 {
593 inAvgTmp[f] = inaverg[f][p];
594 inTmp[f] = inarray[f][p];
595 }
596
598 inAvgTmp.data(), inTmp.data(),
599 mu[p], outTmp.data());
600
601 for (size_t f = 0; f < nConvectiveFields; ++f)
602 {
603 outarray[d][f][p] += normal[nderiv][p] * outTmp[f];
604 }
605 }
606 }
607 }
608}
609
610/**
611 * @brief Return the penalty vector for the LDGNS diffusion problem.
612 */
614 const Array<OneD, const Array<OneD, NekDouble>> &uFwd,
615 const Array<OneD, const Array<OneD, NekDouble>> &uBwd,
616 Array<OneD, Array<OneD, NekDouble>> &penaltyCoeff)
617{
618 size_t nTracePts = uFwd[0].size();
619
620 // Compute average temperature
621 size_t nVariables = uFwd.size();
622 Array<OneD, NekDouble> tAve{nTracePts, 0.0};
623 Vmath::Svtsvtp(nTracePts, 0.5, uFwd[nVariables - 1], 1, 0.5,
624 uBwd[nVariables - 1], 1, tAve, 1);
625
626 // Get average viscosity and thermal conductivity
627 Array<OneD, NekDouble> muAve{nTracePts, 0.0};
628 Array<OneD, NekDouble> tcAve{nTracePts, 0.0};
629
630 GetViscosityAndThermalCondFromTemp(tAve, muAve, tcAve);
631
632 // Compute penalty term
633 for (size_t i = 0; i < nVariables; ++i)
634 {
635 // Get jump of u variables
636 Vmath::Vsub(nTracePts, uFwd[i], 1, uBwd[i], 1, penaltyCoeff[i], 1);
637 // Multiply by variable coefficient = {coeff} ( u^+ - u^- )
638 if (i < nVariables - 1)
639 {
640 Vmath::Vmul(nTracePts, muAve, 1, penaltyCoeff[i], 1,
641 penaltyCoeff[i], 1);
642 }
643 else
644 {
645 Vmath::Vmul(nTracePts, tcAve, 1, penaltyCoeff[i], 1,
646 penaltyCoeff[i], 1);
647 }
648 }
649}
650
651/**
652 * @brief Update viscosity
653 * todo: add artificial viscosity here
654 */
656 const Array<OneD, NekDouble> &temperature, Array<OneD, NekDouble> &mu,
657 Array<OneD, NekDouble> &thermalCond)
658{
659 size_t nPts = temperature.size();
660
661 for (size_t p = 0; p < nPts; ++p)
662 {
664 thermalCond[p]);
665 }
666
667 // Add artificial viscosity if wanted
668 // move this above and add in kernel
670 {
671 size_t nTracePts = m_fields[0]->GetTrace()->GetTotPoints();
672 if (nPts != nTracePts)
673 {
674 Vmath::Vadd(nPts, mu, 1, m_varConv->GetAv(), 1, mu, 1);
675 }
676 else
677 {
678 Vmath::Vadd(nPts, mu, 1, m_varConv->GetAvTrace(), 1, mu, 1);
679 }
680
681 // Update thermal conductivity
682 NekDouble tRa = m_Cp / m_Prandtl;
683 Vmath::Smul(nPts, tRa, mu, 1, thermalCond, 1);
684 }
685}
686
687/**
688 * @brief Get divergence and curl squared
689 *
690 * @param input
691 * fields -> expansion list pointer
692 * cnsVar -> conservative variables
693 * cnsVarFwd -> forward trace of conservative variables
694 * cnsVarBwd -> backward trace of conservative variables
695 * @paran output
696 * divSquare -> divergence
697 * curlSquare -> curl squared
698 *
699 */
702 const Array<OneD, Array<OneD, NekDouble>> &cnsVar,
704 const Array<OneD, Array<OneD, NekDouble>> &cnsVarFwd,
705 const Array<OneD, Array<OneD, NekDouble>> &cnsVarBwd)
706{
707 size_t nDim = fields[0]->GetCoordim(0);
708 size_t nVar = cnsVar.size();
709 size_t nPts = cnsVar[0].size();
710 size_t nPtsTrc = cnsVarFwd[0].size();
711
712 // These should be allocated once
713 Array<OneD, Array<OneD, NekDouble>> primVar(nVar - 1), primVarFwd(nVar - 1),
714 primVarBwd(nVar - 1);
715
716 for (unsigned short d = 0; d < nVar - 2; ++d)
717 {
718 primVar[d] = Array<OneD, NekDouble>(nPts, 0.0);
719 primVarFwd[d] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
720 primVarBwd[d] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
721 }
722 size_t ergLoc = nVar - 2;
723 primVar[ergLoc] = Array<OneD, NekDouble>(nPts, 0.0);
724 primVarFwd[ergLoc] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
725 primVarBwd[ergLoc] = Array<OneD, NekDouble>(nPtsTrc, 0.0);
726
727 // Get primitive variables [u,v,w,T=0]
728 // Possibly should be changed to [rho,u,v,w,T] to make IP and LDGNS more
729 // consistent with each other
730 for (unsigned short d = 0; d < nVar - 2; ++d)
731 {
732 // Volume
733 for (size_t p = 0; p < nPts; ++p)
734 {
735 primVar[d][p] = cnsVar[d + 1][p] / cnsVar[0][p];
736 }
737 // Trace
738 for (size_t p = 0; p < nPtsTrc; ++p)
739 {
740 primVarFwd[d][p] = cnsVarFwd[d + 1][p] / cnsVarFwd[0][p];
741 primVarBwd[d][p] = cnsVarBwd[d + 1][p] / cnsVarBwd[0][p];
742 }
743 }
744
745 // this should be allocated once
747 for (unsigned short j = 0; j < nDim; ++j)
748 {
749 primVarDer[j] = Array<OneD, Array<OneD, NekDouble>>(nVar - 1);
750 for (unsigned short i = 0; i < nVar - 1; ++i)
751 {
752 primVarDer[j][i] = Array<OneD, NekDouble>(nPts, 0.0);
753 }
754 }
755
756 // Get derivative tensor
757 m_diffusion->DiffuseCalcDerivative(fields, primVar, primVarDer, primVarFwd,
758 primVarBwd);
759
760 // Get div curl squared
761 GetDivCurlFromDvelT(primVarDer, div, curlSquare);
762}
763
764/**
765 * @brief Get divergence and curl from velocity derivative tensor
766 *
767 */
770 Array<OneD, NekDouble> &curlSquare)
771{
772 size_t nDim = pVarDer.size();
773 size_t nPts = div.size();
774
775 // div velocity
776 for (size_t p = 0; p < nPts; ++p)
777 {
778 NekDouble divTmp = 0;
779 for (unsigned short j = 0; j < nDim; ++j)
780 {
781 divTmp += pVarDer[j][j][p];
782 }
783 div[p] = divTmp;
784 }
785
786 // |curl velocity| ** 2
787 if (nDim > 2)
788 {
789 for (size_t p = 0; p < nPts; ++p)
790 {
791 // curl[0] 3/2 - 2/3
792 NekDouble curl032 = pVarDer[2][1][p]; // load 1x
793 NekDouble curl023 = pVarDer[1][2][p]; // load 1x
794 NekDouble curl0 = curl032 - curl023;
795 // square curl[0]
796 NekDouble curl0sqr = curl0 * curl0;
797
798 // curl[1] 3/1 - 1/3
799 NekDouble curl131 = pVarDer[2][0][p]; // load 1x
800 NekDouble curl113 = pVarDer[0][2][p]; // load 1x
801 NekDouble curl1 = curl131 - curl113;
802 // square curl[1]
803 NekDouble curl1sqr = curl1 * curl1;
804
805 // curl[2] 1/2 - 2/1
806 NekDouble curl212 = pVarDer[0][1][p]; // load 1x
807 NekDouble curl221 = pVarDer[1][0][p]; // load 1x
808 NekDouble curl2 = curl212 - curl221;
809 // square curl[2]
810 NekDouble curl2sqr = curl2 * curl2;
811
812 // reduce
813 curl0sqr += curl1sqr + curl2sqr;
814 // store
815 curlSquare[p] = curl0sqr; // store 1x
816 }
817 }
818 else if (nDim > 1)
819 {
820 for (size_t p = 0; p < nPts; ++p)
821 {
822 // curl[2] 1/2
823 NekDouble c212 = pVarDer[0][1][p]; // load 1x
824 // curl[2] 2/1
825 NekDouble c221 = pVarDer[1][0][p]; // load 1x
826 // curl[2] 1/2 - 2/1
827 NekDouble curl = c212 - c221;
828 // square curl[2]
829 curlSquare[p] = curl * curl; // store 1x
830 }
831 }
832 else
833 {
834 Vmath::Fill(nPts, 0.0, curlSquare, 1);
835 }
836}
837
839 std::vector<Array<OneD, NekDouble>> &fieldcoeffs,
840 std::vector<std::string> &variables)
841{
842 bool extraFields;
843 m_session->MatchSolverInfo("OutputExtraFields", "True", extraFields, true);
844 if (extraFields)
845 {
846 const int nPhys = m_fields[0]->GetNpoints();
847 const int nCoeffs = m_fields[0]->GetNcoeffs();
849
850 for (size_t i = 0; i < m_fields.size(); ++i)
851 {
852 cnsVar[i] = m_fields[i]->GetPhys();
853 }
854
857 for (int i = 0; i < m_spacedim; ++i)
858 {
860 velFwd[i] = Array<OneD, NekDouble>(nCoeffs);
861 }
862
863 Array<OneD, NekDouble> pressure(nPhys), temperature(nPhys);
864 Array<OneD, NekDouble> entropy(nPhys);
865 Array<OneD, NekDouble> soundspeed(nPhys), mach(nPhys);
866 Array<OneD, NekDouble> sensor(nPhys), SensorKappa(nPhys);
867
868 m_varConv->GetVelocityVector(cnsVar, velocity);
869 m_varConv->GetPressure(cnsVar, pressure);
870 m_varConv->GetTemperature(cnsVar, temperature);
871 m_varConv->GetEntropy(cnsVar, entropy);
872 m_varConv->GetSoundSpeed(cnsVar, soundspeed);
873 m_varConv->GetMach(cnsVar, soundspeed, mach);
874
875 int sensorOffset;
876 m_session->LoadParameter("SensorOffset", sensorOffset, 1);
877 m_varConv->GetSensor(m_fields[0], cnsVar, sensor, SensorKappa,
878 sensorOffset);
879
880 Array<OneD, NekDouble> pFwd(nCoeffs), TFwd(nCoeffs);
881 Array<OneD, NekDouble> sFwd(nCoeffs);
882 Array<OneD, NekDouble> aFwd(nCoeffs), mFwd(nCoeffs);
883 Array<OneD, NekDouble> sensFwd(nCoeffs);
884
885 string velNames[3] = {"u", "v", "w"};
886 for (int i = 0; i < m_spacedim; ++i)
887 {
888 m_fields[0]->FwdTransLocalElmt(velocity[i], velFwd[i]);
889 variables.push_back(velNames[i]);
890 fieldcoeffs.push_back(velFwd[i]);
891 }
892
893 m_fields[0]->FwdTransLocalElmt(pressure, pFwd);
894 m_fields[0]->FwdTransLocalElmt(temperature, TFwd);
895 m_fields[0]->FwdTransLocalElmt(entropy, sFwd);
896 m_fields[0]->FwdTransLocalElmt(soundspeed, aFwd);
897 m_fields[0]->FwdTransLocalElmt(mach, mFwd);
898 m_fields[0]->FwdTransLocalElmt(sensor, sensFwd);
899
900 variables.push_back("p");
901 variables.push_back("T");
902 variables.push_back("s");
903 variables.push_back("a");
904 variables.push_back("Mach");
905 variables.push_back("Sensor");
906 fieldcoeffs.push_back(pFwd);
907 fieldcoeffs.push_back(TFwd);
908 fieldcoeffs.push_back(sFwd);
909 fieldcoeffs.push_back(aFwd);
910 fieldcoeffs.push_back(mFwd);
911 fieldcoeffs.push_back(sensFwd);
912
914 {
915 // reuse pressure
916 Array<OneD, NekDouble> sensorFwd(nCoeffs);
917 m_artificialDiffusion->GetArtificialViscosity(cnsVar, pressure);
918 m_fields[0]->FwdTransLocalElmt(pressure, sensorFwd);
919
920 variables.push_back("ArtificialVisc");
921 fieldcoeffs.push_back(sensorFwd);
922 }
923
925 {
926
928 cnsVarBwd(m_fields.size());
929
930 for (size_t i = 0; i < m_fields.size(); ++i)
931 {
934 m_fields[i]->GetFwdBwdTracePhys(cnsVar[i], cnsVarFwd[i],
935 cnsVarBwd[i]);
936 }
937
938 Array<OneD, NekDouble> div(nPhys), curlSquare(nPhys);
939 GetDivCurlSquared(m_fields, cnsVar, div, curlSquare, cnsVarFwd,
940 cnsVarBwd);
941
942 Array<OneD, NekDouble> divFwd(nCoeffs, 0.0);
943 m_fields[0]->FwdTransLocalElmt(div, divFwd);
944 variables.push_back("div");
945 fieldcoeffs.push_back(divFwd);
946
947 Array<OneD, NekDouble> curlFwd(nCoeffs, 0.0);
948 m_fields[0]->FwdTransLocalElmt(curlSquare, curlFwd);
949 variables.push_back("curl^2");
950 fieldcoeffs.push_back(curlFwd);
951
952 m_varConv->SetAv(m_fields, cnsVar, div, curlSquare);
953
954 Array<OneD, NekDouble> muavFwd(nCoeffs);
955 m_fields[0]->FwdTransLocalElmt(m_varConv->GetAv(), muavFwd);
956 variables.push_back("ArtificialVisc");
957 fieldcoeffs.push_back(muavFwd);
958 }
959 }
960}
961
962bool NavierStokesCFE::v_SupportsShockCaptType(const std::string type) const
963{
964 if (type == "NonSmooth" || type == "Physical" || type == "Off")
965 {
966 return true;
967 }
968 else
969 {
970 return false;
971 }
972}
973} // 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.
Definition: NekFactory.hpp:197
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:143
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.
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
const std::vector< NekDouble > velocity
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