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