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