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