Nektar++
Loading...
Searching...
No Matches
IncNavierStokes.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: IncNavierStokes.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: Incompressible Navier Stokes class definition built on
32// ADRBase class
33//
34///////////////////////////////////////////////////////////////////////////////
35
36#include <boost/algorithm/string.hpp>
37#include <iomanip>
38
45
49#include <algorithm>
50#include <fstream>
51#include <iostream>
52#include <sstream>
53
56#include <tinyxml.h>
57
58namespace Nektar
59{
60
61std::string IncNavierStokes::eqTypeLookupIds[6] = {
67 "EqType", "SteadyNavierStokes", eSteadyNavierStokes),
69 "EqType", "SteadyLinearisedNS", eSteadyLinearisedNS),
71 "EqType", "UnsteadyNavierStokes", eUnsteadyNavierStokes),
72 LibUtilities::SessionReader::RegisterEnumValue("EqType", "UnsteadyStokes",
74
75/**
76 * Constructor. Creates ...
77 *
78 * \param
79 * \param
80 */
84 : UnsteadySystem(pSession, pGraph), AdvectionSystem(pSession, pGraph),
85 m_SmoothAdvection(false)
86{
87}
88
89void IncNavierStokes::v_InitObject(bool DeclareField)
90{
92
93 int i, j;
94 int numfields = m_fields.size();
95 std::string velids[] = {"u", "v", "w"};
96
97 // Set up Velocity field to point to the first m_expdim of m_fields;
99
100 for (i = 0; i < m_spacedim; ++i)
101 {
102 for (j = 0; j < numfields; ++j)
103 {
104 std::string var = m_boundaryConditions->GetVariable(j);
105 if (boost::iequals(velids[i], var))
106 {
107 m_velocity[i] = j;
108 break;
109 }
110
111 ASSERTL0(j != numfields, "Failed to find field: " + var);
112 }
113 }
114
115 // Set up equation type enum using kEquationTypeStr
116 for (i = 0; i < (int)eEquationTypeSize; ++i)
117 {
118 bool match;
119 m_session->MatchSolverInfo("EQTYPE", kEquationTypeStr[i], match, false);
120 if (match)
121 {
123 break;
124 }
125 }
126 ASSERTL0(i != eEquationTypeSize, "EQTYPE not found in SOLVERINFO section");
127
128 m_session->LoadParameter("Kinvis", m_kinvis);
129
130 // Default advection type per solver
131 std::string vConvectiveType;
132 switch (m_equationType)
133 {
134 case eUnsteadyStokes:
136 vConvectiveType = "NoAdvection";
137 break;
140 vConvectiveType = "Convective";
141 break;
143 vConvectiveType = "Linearised";
144 break;
145 default:
146 break;
147 }
148
149 // Check if advection type overridden
150 if (m_session->DefinesTag("AdvectiveType") &&
153 {
154 vConvectiveType = m_session->GetTag("AdvectiveType");
155 }
156
157 // Initialise advection
159 vConvectiveType, vConvectiveType);
160 m_advObject->InitObject(m_session, m_fields);
161
162 // Set up arrays for moving reference frame
163 // Note: this must be done before the forcing
164 if (DefinedForcing("MovingReferenceFrame"))
165 {
166 std::string vSolver = m_session->GetSolverInfo("SolverType");
167 const bool isVCS = boost::iequals(vSolver, "VelocityCorrectionScheme");
168 if (isVCS)
169 {
170 ASSERTL0(false, "The Forcing MovingRefenceFrame is no "
171 "longer supported for use in the "
172 "VelocityCorrectionScheme. Please replace the "
173 "SolverType with VCSFSI or PressDecompVCSFSI.");
174 }
175 // 0-5(inertial disp), 6-11(body vel), 12-17(body acce) current
176 // 18-21(body pivot)
178 "X", "Y", "Z", "Theta_x", "Theta_y", "Theta_z",
179 "U", "V", "W", "Omega_x", "Omega_y", "Omega_z",
180 "A_x", "A_y", "A_z", "DOmega_x", "DOmega_y", "DOmega_z",
181 "X0", "Y0", "Z0"};
183 m_aeroForces = Array<OneD, NekDouble>(12, 0.0); // p; vis
184 m_movableDoFs.resize(6, false);
185 }
186 else
187 {
189 }
190 // Forcing terms
191 m_forcing = SolverUtils::Forcing::Load(m_session, shared_from_this(),
193
194 // check to see if any Robin boundary conditions and if so set
195 // up m_field to boundary condition maps;
199
200 for (size_t i = 0; i < m_fields.size(); ++i)
201 {
202 bool Set = false;
203
206 int radpts = 0;
207
208 BndConds = m_fields[i]->GetBndConditions();
209 BndExp = m_fields[i]->GetBndCondExpansions();
210 for (size_t n = 0; n < BndConds.size(); ++n)
211 {
212 if (boost::iequals(BndConds[n]->GetUserDefined(), "Radiation"))
213 {
214 ASSERTL0(
215 BndConds[n]->GetBoundaryConditionType() ==
217 "Radiation boundary condition must be of type Robin <R>");
218
219 if (Set == false)
220 {
221 m_fields[i]->GetBoundaryToElmtMap(m_fieldsBCToElmtID[i],
223 Set = true;
224 }
225 radpts += BndExp[n]->GetTotPoints();
226 }
227 if (boost::iequals(BndConds[n]->GetUserDefined(),
228 "ZeroNormalComponent"))
229 {
230 ASSERTL0(BndConds[n]->GetBoundaryConditionType() ==
232 "Zero Normal Component boundary condition option must "
233 "be of type Dirichlet <D>");
234
235 if (Set == false)
236 {
237 m_fields[i]->GetBoundaryToElmtMap(m_fieldsBCToElmtID[i],
239 Set = true;
240 }
241 }
242 }
243
245
246 radpts = 0; // reset to use as a counter
247
248 for (size_t n = 0; n < BndConds.size(); ++n)
249 {
250 if (boost::iequals(BndConds[n]->GetUserDefined(), "Radiation"))
251 {
252
253 int npoints = BndExp[n]->GetNpoints();
254 Array<OneD, NekDouble> x0(npoints, 0.0);
255 Array<OneD, NekDouble> x1(npoints, 0.0);
256 Array<OneD, NekDouble> x2(npoints, 0.0);
257 Array<OneD, NekDouble> tmpArray;
258
259 BndExp[n]->GetCoords(x0, x1, x2);
260
262 std::static_pointer_cast<
264 ->m_robinPrimitiveCoeff;
265
266 coeff->Evaluate(x0, x1, x2, m_time,
267 tmpArray = m_fieldsRadiationFactor[i] + radpts);
268 // Vmath::Neg(npoints,tmpArray = m_fieldsRadiationFactor[i]+
269 // radpts,1);
270 radpts += npoints;
271 }
272 }
273 }
274
275 // Set up maping for womersley BC - and load variables
276 for (size_t i = 0; i < m_fields.size(); ++i)
277 {
278 for (size_t n = 0; n < m_fields[i]->GetBndConditions().size(); ++n)
279 {
280 if (boost::istarts_with(
281 m_fields[i]->GetBndConditions()[n]->GetUserDefined(),
282 "Womersley"))
283 {
284 // assumes that boundary condition is applied in normal
285 // direction and is decomposed for each direction. There could
286 // be a unique file for each direction
287 m_womersleyParams[i][n] =
289 m_spacedim);
290 // Read in fourier coeffs and precompute coefficients
292 i, n, m_fields[i]->GetBndConditions()[n]->GetUserDefined());
293
294 m_fields[i]->GetBoundaryToElmtMap(m_fieldsBCToElmtID[i],
296 }
297 }
298 }
299
300 // Set up Field Meta Data for output files
301 m_fieldMetaDataMap["Kinvis"] = boost::lexical_cast<std::string>(m_kinvis);
302 m_fieldMetaDataMap["TimeStep"] =
303 boost::lexical_cast<std::string>(m_timestep);
304}
305
306/**
307 * Evaluation -N(V) for all fields except pressure using m_velocity
308 */
310 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
311 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
312{
313 size_t VelDim = m_velocity.size();
314 Array<OneD, Array<OneD, NekDouble>> velocity(VelDim);
315
316 size_t npoints = m_fields[0]->GetNpoints();
317 for (size_t i = 0; i < VelDim; ++i)
318 {
319 velocity[i] = Array<OneD, NekDouble>(npoints);
320 Vmath::Vcopy(npoints, inarray[m_velocity[i]], 1, velocity[i], 1);
321 }
322 for (auto &x : m_forcing)
323 {
324 x->PreApply(m_fields, velocity, velocity, time);
325 }
326
327 m_advObject->Advect(m_nConvectiveFields, m_fields, velocity, inarray,
328 outarray, time);
329}
330
331/**
332 * Time dependent boundary conditions updating
333 */
335{
336 size_t i, n;
337 std::string varName;
338 size_t nvariables = m_fields.size();
339
340 for (i = 0; i < nvariables; ++i)
341 {
342 for (n = 0; n < m_fields[i]->GetBndConditions().size(); ++n)
343 {
344 if (m_fields[i]->GetBndConditions()[n]->IsTimeDependent())
345 {
346 varName = m_session->GetVariable(i);
347 m_fields[i]->EvaluateBoundaryConditions(time, varName);
348 }
349 else if (boost::istarts_with(
350 m_fields[i]->GetBndConditions()[n]->GetUserDefined(),
351 "Womersley"))
352 {
354 }
355 }
356
357 // Set Radiation conditions if required
359 }
360
361 // Enforcing the boundary conditions (Inlet and wall) for the
362 // Moving reference frame
364}
365
366/**
367 * Probably should be pushed back into ContField?
368 */
370{
371 size_t i, n;
372
375
376 BndConds = m_fields[fieldid]->GetBndConditions();
377 BndExp = m_fields[fieldid]->GetBndCondExpansions();
378
381
382 size_t cnt;
383 size_t elmtid, nq, offset, boundary;
384 Array<OneD, NekDouble> Bvals, U;
385 size_t cnt1 = 0;
386
387 for (cnt = n = 0; n < BndConds.size(); ++n)
388 {
389 std::string type = BndConds[n]->GetUserDefined();
390
391 if ((BndConds[n]->GetBoundaryConditionType() ==
393 (boost::iequals(type, "Radiation")))
394 {
395 size_t nExp = BndExp[n]->GetExpSize();
396 for (i = 0; i < nExp; ++i, cnt++)
397 {
398 elmtid = m_fieldsBCToElmtID[m_velocity[fieldid]][cnt];
399 elmt = m_fields[fieldid]->GetExp(elmtid);
400 offset = m_fields[fieldid]->GetPhys_Offset(elmtid);
401
402 U = m_fields[fieldid]->UpdatePhys() + offset;
403 Bc = BndExp[n]->GetExp(i);
404
405 boundary = m_fieldsBCToTraceID[fieldid][cnt];
406
407 // Get edge values and put into ubc
408 nq = Bc->GetTotPoints();
410 elmt->GetTracePhysVals(boundary, Bc, U, ubc);
411
412 Vmath::Vmul(nq,
414 [fieldid][cnt1 + BndExp[n]->GetPhys_Offset(i)],
415 1, &ubc[0], 1, &ubc[0], 1);
416
417 Bvals =
418 BndExp[n]->UpdateCoeffs() + BndExp[n]->GetCoeff_Offset(i);
419
420 Bc->IProductWRTBase(ubc, Bvals);
421 }
422 cnt1 += BndExp[n]->GetTotPoints();
423 }
424 else
425 {
426 cnt += BndExp[n]->GetExpSize();
427 }
428 }
429}
430
432{
433 // use static trip since cannot use UserDefinedTag for zero
434 // velocity and have time dependent conditions
435 static bool Setup = false;
436
437 if (Setup == true)
438 {
439 return;
440 }
441 Setup = true;
442
443 size_t i, n;
444
446 BndConds(m_spacedim);
448
449 for (int i = 0; i < m_spacedim; ++i)
450 {
451 BndConds[i] = m_fields[m_velocity[i]]->GetBndConditions();
452 BndExp[i] = m_fields[m_velocity[i]]->GetBndCondExpansions();
453 }
454
456
457 size_t cnt;
458 size_t elmtid, nq, boundary;
459
461 Array<OneD, NekDouble> Bphys, Bcoeffs;
462
463 size_t fldid = m_velocity[0];
464
465 for (cnt = n = 0; n < BndConds[0].size(); ++n)
466 {
467 if ((BndConds[0][n]->GetBoundaryConditionType() ==
469 (boost::iequals(BndConds[0][n]->GetUserDefined(),
470 "ZeroNormalComponent")))
471 {
472 size_t nExp = BndExp[0][n]->GetExpSize();
473 for (i = 0; i < nExp; ++i, cnt++)
474 {
475 elmtid = m_fieldsBCToElmtID[fldid][cnt];
476 elmt = m_fields[0]->GetExp(elmtid);
477 boundary = m_fieldsBCToTraceID[fldid][cnt];
478
479 normals = elmt->GetTraceNormal(boundary);
480
481 nq = BndExp[0][n]->GetExp(i)->GetTotPoints();
482 Array<OneD, NekDouble> normvel(nq, 0.0);
483
484 for (int k = 0; k < m_spacedim; ++k)
485 {
486 Bphys = BndExp[k][n]->UpdatePhys() +
487 BndExp[k][n]->GetPhys_Offset(i);
488 Bc = BndExp[k][n]->GetExp(i);
489 Vmath::Vvtvp(nq, normals[k], 1, Bphys, 1, normvel, 1,
490 normvel, 1);
491 }
492
493 // negate normvel for next step
494 Vmath::Neg(nq, normvel, 1);
495
496 for (int k = 0; k < m_spacedim; ++k)
497 {
498 Bphys = BndExp[k][n]->UpdatePhys() +
499 BndExp[k][n]->GetPhys_Offset(i);
500 Bcoeffs = BndExp[k][n]->UpdateCoeffs() +
501 BndExp[k][n]->GetCoeff_Offset(i);
502 Bc = BndExp[k][n]->GetExp(i);
503 Vmath::Vvtvp(nq, normvel, 1, normals[k], 1, Bphys, 1, Bphys,
504 1);
505 Bc->FwdTransBndConstrained(Bphys, Bcoeffs);
506 }
507 }
508 }
509 else
510 {
511 cnt += BndExp[0][n]->GetExpSize();
512 }
513 }
514}
515
516/**
517 * Womersley boundary condition defintion
518 */
519void IncNavierStokes::SetWomersleyBoundary(const int fldid, const int bndid)
520{
521 ASSERTL1(m_womersleyParams.count(bndid) == 1,
522 "Womersley parameters for this boundary have not been set up");
523
524 WomersleyParamsSharedPtr WomParam = m_womersleyParams[fldid][bndid];
525 NekComplexDouble zvel;
526 size_t i, j, k;
527
528 size_t M_coeffs = WomParam->m_wom_vel.size();
529
530 NekDouble T = WomParam->m_period;
531 NekDouble axis_normal = WomParam->m_axisnormal[fldid];
532
533 // Womersley Number
534 NekComplexDouble omega_c(2.0 * M_PI / T, 0.0);
535 NekComplexDouble k_c(0.0, 0.0);
536 NekComplexDouble m_time_c(m_time, 0.0);
537 NekComplexDouble zi(0.0, 1.0);
538 NekComplexDouble i_pow_3q2(-1.0 / sqrt(2.0), 1.0 / sqrt(2.0));
539
541 BndCondExp = m_fields[fldid]->GetBndCondExpansions()[bndid];
542
544 size_t cnt = 0;
545 size_t nfq;
547 size_t exp_npts = BndCondExp->GetExpSize();
548 Array<OneD, NekDouble> wbc(exp_npts, 0.0);
549
551
552 // preallocate the exponent
553 for (k = 1; k < M_coeffs; k++)
554 {
555 k_c = NekComplexDouble((NekDouble)k, 0.0);
556 zt[k] = std::exp(zi * omega_c * k_c * m_time_c);
557 }
558
559 // Loop over each element in an expansion
560 for (i = 0; i < exp_npts; ++i, cnt++)
561 {
562 // Get Boundary and trace expansion
563 bc = BndCondExp->GetExp(i);
564 nfq = bc->GetTotPoints();
565 Array<OneD, NekDouble> wbc(nfq, 0.0);
566
567 // Compute womersley solution
568 for (j = 0; j < nfq; j++)
569 {
570 wbc[j] = WomParam->m_poiseuille[i][j];
571 for (k = 1; k < M_coeffs; k++)
572 {
573 zvel = WomParam->m_zvel[i][j][k] * zt[k];
574 wbc[j] = wbc[j] + zvel.real();
575 }
576 }
577
578 // Multiply w by normal to get u,v,w component of velocity
579 Vmath::Smul(nfq, axis_normal, wbc, 1, wbc, 1);
580 // get the offset
581 Bvals = BndCondExp->UpdateCoeffs() + BndCondExp->GetCoeff_Offset(i);
582
583 // Push back to Coeff space
584 bc->FwdTrans(wbc, Bvals);
585 }
586}
587
588void IncNavierStokes::SetUpWomersley(const int fldid, const int bndid,
589 std::string womStr)
590{
591 std::string::size_type indxBeg = womStr.find_first_of(':') + 1;
592 std::string filename = womStr.substr(indxBeg, std::string::npos);
593
594 TiXmlDocument doc(filename);
595
596 bool loadOkay = doc.LoadFile();
597 ASSERTL0(loadOkay,
598 (std::string("Failed to load file: ") + filename).c_str());
599
600 TiXmlHandle docHandle(&doc);
601
602 int err; /// Error value returned by TinyXML.
603
604 TiXmlElement *nektar = doc.FirstChildElement("NEKTAR");
605 ASSERTL0(nektar, "Unable to find NEKTAR tag in file.");
606
607 TiXmlElement *wombc = nektar->FirstChildElement("WOMERSLEYBC");
608 ASSERTL0(wombc, "Unable to find WOMERSLEYBC tag in file.");
609
610 // read womersley parameters
611 TiXmlElement *womparam = wombc->FirstChildElement("WOMPARAMS");
612 ASSERTL0(womparam, "Unable to find WOMPARAMS tag in file.");
613
614 // Input coefficients
615 TiXmlElement *params = womparam->FirstChildElement("W");
616 std::map<std::string, std::string> Wparams;
617
618 // read parameter list
619 while (params)
620 {
621
622 std::string propstr;
623 propstr = params->Attribute("PROPERTY");
624
625 ASSERTL0(!propstr.empty(),
626 "Failed to read PROPERTY value Womersley BC Parameter");
627
628 std::string valstr;
629 valstr = params->Attribute("VALUE");
630
631 ASSERTL0(!valstr.empty(),
632 "Failed to read VALUE value Womersley BC Parameter");
633
634 std::transform(propstr.begin(), propstr.end(), propstr.begin(),
635 ::toupper);
636 Wparams[propstr] = valstr;
637
638 params = params->NextSiblingElement("W");
639 }
640 bool parseGood;
641
642 // Read parameters
643
644 ASSERTL0(
645 Wparams.count("RADIUS") == 1,
646 "Failed to find Radius parameter in Womersley boundary conditions");
647 std::vector<NekDouble> rad;
648 ParseUtils::GenerateVector(Wparams["RADIUS"], rad);
649 m_womersleyParams[fldid][bndid]->m_radius = rad[0];
650
651 ASSERTL0(
652 Wparams.count("PERIOD") == 1,
653 "Failed to find period parameter in Womersley boundary conditions");
654 std::vector<NekDouble> period;
655 parseGood = ParseUtils::GenerateVector(Wparams["PERIOD"], period);
656 m_womersleyParams[fldid][bndid]->m_period = period[0];
657
658 ASSERTL0(
659 Wparams.count("AXISNORMAL") == 1,
660 "Failed to find axisnormal parameter in Womersley boundary conditions");
661 std::vector<NekDouble> anorm;
662 parseGood = ParseUtils::GenerateVector(Wparams["AXISNORMAL"], anorm);
663 m_womersleyParams[fldid][bndid]->m_axisnormal[0] = anorm[0];
664 m_womersleyParams[fldid][bndid]->m_axisnormal[1] = anorm[1];
665 m_womersleyParams[fldid][bndid]->m_axisnormal[2] = anorm[2];
666
667 ASSERTL0(
668 Wparams.count("AXISPOINT") == 1,
669 "Failed to find axispoint parameter in Womersley boundary conditions");
670 std::vector<NekDouble> apt;
671 parseGood = ParseUtils::GenerateVector(Wparams["AXISPOINT"], apt);
672 m_womersleyParams[fldid][bndid]->m_axispoint[0] = apt[0];
673 m_womersleyParams[fldid][bndid]->m_axispoint[1] = apt[1];
674 m_womersleyParams[fldid][bndid]->m_axispoint[2] = apt[2];
675
676 // Read Temporal Fourier Coefficients.
677
678 // Find the FourierCoeff tag
679 TiXmlElement *coeff = wombc->FirstChildElement("FOURIERCOEFFS");
680
681 // Input coefficients
682 TiXmlElement *fval = coeff->FirstChildElement("F");
683
684 int indx;
685
686 while (fval)
687 {
688 TiXmlAttribute *fvalAttr = fval->FirstAttribute();
689 std::string attrName(fvalAttr->Name());
690
691 ASSERTL0(attrName == "ID",
692 (std::string("Unknown attribute name: ") + attrName).c_str());
693
694 err = fvalAttr->QueryIntValue(&indx);
695 ASSERTL0(err == TIXML_SUCCESS, "Unable to read attribute ID.");
696
697 std::string coeffStr = fval->FirstChild()->ToText()->ValueStr();
698 std::vector<NekDouble> coeffvals;
699
700 parseGood = ParseUtils::GenerateVector(coeffStr, coeffvals);
701 ASSERTL0(
702 parseGood,
703 (std::string("Problem reading value of fourier coefficient, ID=") +
704 std::to_string(indx))
705 .c_str());
706 ASSERTL1(
707 coeffvals.size() == 2,
708 (std::string(
709 "Have not read two entries of Fourier coefficicent from ID=" +
710 std::to_string(indx))
711 .c_str()));
712
713 m_womersleyParams[fldid][bndid]->m_wom_vel.push_back(
714 NekComplexDouble(coeffvals[0], coeffvals[1]));
715
716 fval = fval->NextSiblingElement("F");
717 }
718
719 // starting point of precalculation
720 size_t i, j, k;
721 // M fourier coefficients
722 size_t M_coeffs = m_womersleyParams[fldid][bndid]->m_wom_vel.size();
723 NekDouble R = m_womersleyParams[fldid][bndid]->m_radius;
724 NekDouble T = m_womersleyParams[fldid][bndid]->m_period;
725 Array<OneD, NekDouble> x0 = m_womersleyParams[fldid][bndid]->m_axispoint;
726
728 // Womersley Number
729 NekComplexDouble omega_c(2.0 * M_PI / T, 0.0);
730 NekComplexDouble alpha_c(R * sqrt(omega_c.real() / m_kinvis), 0.0);
731 NekComplexDouble z1(1.0, 0.0);
732 NekComplexDouble i_pow_3q2(-1.0 / sqrt(2.0), 1.0 / sqrt(2.0));
733
735 BndCondExp = m_fields[fldid]->GetBndCondExpansions()[bndid];
736
738 size_t cnt = 0;
739 size_t nfq;
741
742 size_t exp_npts = BndCondExp->GetExpSize();
743 Array<OneD, NekDouble> wbc(exp_npts, 0.0);
744
745 // allocate time indepedent variables
746 m_womersleyParams[fldid][bndid]->m_poiseuille =
748 m_womersleyParams[fldid][bndid]->m_zvel =
750 // could use M_coeffs - 1 but need to avoid complicating things
751 Array<OneD, NekComplexDouble> zJ0(M_coeffs);
752 Array<OneD, NekComplexDouble> lamda_n(M_coeffs);
753 Array<OneD, NekComplexDouble> k_c(M_coeffs);
754 NekComplexDouble zJ0r;
755
756 for (k = 1; k < M_coeffs; k++)
757 {
758 k_c[k] = NekComplexDouble((NekDouble)k, 0.0);
759 lamda_n[k] = i_pow_3q2 * alpha_c * sqrt(k_c[k]);
760 zJ0[k] = Polylib::ImagBesselComp(0, lamda_n[k]);
761 }
762
763 // Loop over each element in an expansion
764 for (i = 0; i < exp_npts; ++i, cnt++)
765 {
766 // Get Boundary and trace expansion
767 bc = BndCondExp->GetExp(i);
768 nfq = bc->GetTotPoints();
769
770 Array<OneD, NekDouble> x(nfq, 0.0);
771 Array<OneD, NekDouble> y(nfq, 0.0);
772 Array<OneD, NekDouble> z(nfq, 0.0);
773 bc->GetCoords(x, y, z);
774
775 m_womersleyParams[fldid][bndid]->m_poiseuille[i] =
777 m_womersleyParams[fldid][bndid]->m_zvel[i] =
779
780 // Compute coefficients
781 for (j = 0; j < nfq; j++)
782 {
783 rqR = NekComplexDouble(sqrt((x[j] - x0[0]) * (x[j] - x0[0]) +
784 (y[j] - x0[1]) * (y[j] - x0[1]) +
785 (z[j] - x0[2]) * (z[j] - x0[2])) /
786 R,
787 0.0);
788
789 // Compute Poiseulle Flow
790 m_womersleyParams[fldid][bndid]->m_poiseuille[i][j] =
791 m_womersleyParams[fldid][bndid]->m_wom_vel[0].real() *
792 (1. - rqR.real() * rqR.real());
793
794 m_womersleyParams[fldid][bndid]->m_zvel[i][j] =
796
797 // compute the velocity information
798 for (k = 1; k < M_coeffs; k++)
799 {
800 zJ0r = Polylib::ImagBesselComp(0, rqR * lamda_n[k]);
801 m_womersleyParams[fldid][bndid]->m_zvel[i][j][k] =
802 m_womersleyParams[fldid][bndid]->m_wom_vel[k] *
803 (z1 - (zJ0r / zJ0[k]));
804 }
805 }
806 }
807}
808
809/**
810 * Add an additional forcing term programmatically.
811 */
813{
814 m_forcing.push_back(pForce);
815}
816
817/**
818 *
819 */
821 [[maybe_unused]] const NekDouble SpeedSoundFactor)
822{
823 size_t nvel = m_velocity.size();
824 size_t nelmt = m_fields[0]->GetExpSize();
825
826 Array<OneD, NekDouble> stdVelocity(nelmt, 0.0);
828
829 if (m_HomogeneousType == eHomogeneous1D) // just do check on 2D info
830 {
832
833 for (size_t i = 0; i < 2; ++i)
834 {
835 velfields[i] = m_fields[m_velocity[i]]->UpdatePhys();
836 }
837 }
838 else
839 {
840 velfields = Array<OneD, Array<OneD, NekDouble>>(nvel);
841
842 for (size_t i = 0; i < nvel; ++i)
843 {
844 velfields[i] = m_fields[m_velocity[i]]->UpdatePhys();
845 }
846 }
847
848 stdVelocity = m_extrapolation->GetMaxStdVelocity(velfields);
849
850 return stdVelocity;
851}
852
853/**
854 *
855 */
857 const Array<OneD, const Array<OneD, NekDouble>> &physfield,
858 Array<OneD, NekDouble> &pressure)
859{
860 if (physfield.size())
861 {
862 pressure = physfield[physfield.size() - 1];
863 }
864}
865
866/**
867 *
868 */
870 const Array<OneD, const Array<OneD, NekDouble>> &physfield,
871 Array<OneD, NekDouble> &density)
872{
873 int nPts = physfield[0].size();
874 Vmath::Fill(nPts, 1.0, density, 1);
875}
876
877/**
878 *
879 */
881 const Array<OneD, const Array<OneD, NekDouble>> &physfield,
883{
884 for (int i = 0; i < m_spacedim; ++i)
885 {
886 velocity[i] = physfield[i];
887 }
888}
889
890/**
891 * Function to set the moving frame velocities calucated in the forcing
892 * this gives access to the moving reference forcing to set the velocities
893 * to be later used in enforcing the boundary condition in IncNavierStokes
894 * class
895 */
897 const Array<OneD, NekDouble> &vFrameVels)
898{
899 if (m_movingFrameData.size())
900 {
901 ASSERTL0(vFrameVels.size() <= 12,
902 "Arrays have different dimensions, cannot set moving frame "
903 "velocities");
905 Vmath::Vcopy(vFrameVels.size(), vFrameVels, 1, temp, 1);
906 }
907}
908
910 Array<OneD, NekDouble> &vFrameVels)
911{
912 if (m_movingFrameData.size())
913 {
914 ASSERTL0(vFrameVels.size() <= 12,
915 "Arrays have different dimensions, cannot get moving frame "
916 "velocities");
917 Vmath::Vcopy(vFrameVels.size(), m_movingFrameData + 6, 1, vFrameVels,
918 1);
919 return true;
920 }
921 else
922 {
923 return false;
924 }
925}
926
927/**
928 * Function to set the angles between the moving frame of reference and
929 * stationary inertial reference frame
930 **/
932 const Array<OneD, NekDouble> &vFrameDisp)
933{
934 if (m_movingFrameData.size())
935 {
936 ASSERTL0(
937 vFrameDisp.size() == 6,
938 "Arrays have different size, cannot set moving frame displacement");
940 Vmath::Vcopy(vFrameDisp.size(), vFrameDisp, 1, temp, 1);
941 }
942}
943
944/**
945 * Function to get the angles between the moving frame of reference and
946 * stationary inertial reference frame
947 **/
949{
950 if (m_movingFrameData.size())
951 {
952 ASSERTL0(
953 vFrameDisp.size() == 6,
954 "Arrays have different size, cannot get moving frame displacement");
955 Vmath::Vcopy(vFrameDisp.size(), m_movingFrameData, 1, vFrameDisp, 1);
956 return true;
957 }
958 else
959 {
960 return false;
961 }
962}
963
965 const Array<OneD, NekDouble> &vFramePivot)
966{
967 ASSERTL0(vFramePivot.size() == 3,
968 "Arrays have different size, cannot set moving frame pivot");
970 Vmath::Vcopy(vFramePivot.size(), vFramePivot, 1, temp, 1);
971}
972
974{
975 ASSERTL0(vFramePivot.size() == 3,
976 "Arrays have different size, cannot set moving frame pivot");
978 Vmath::Vcopy(vFramePivot.size(), temp, 1, vFramePivot, 1);
979}
980
981void IncNavierStokes::v_SetMovableDoFs(const std::set<int> &dirDoFs)
982{
983 for (int i = 0; i < m_movableDoFs.size(); ++i)
984 {
985 m_movableDoFs[i] = dirDoFs.find(i) != dirDoFs.end();
986 }
987}
988
989void IncNavierStokes::v_GetMovableDoFs(std::set<int> &dirDoFs)
990{
991 dirDoFs.clear();
992 for (int i = 0; i < m_movableDoFs.size(); ++i)
993 {
994 if (m_movableDoFs[i])
995 {
996 dirDoFs.insert(i);
997 }
998 }
999}
1000
1002{
1003 if (m_aeroForces.size() >= 12)
1004 {
1005 Vmath::Vcopy(12, forces, 1, m_aeroForces, 1);
1006 }
1007}
1008
1010{
1011 if (m_aeroForces.size() >= 12)
1012 {
1013 Vmath::Vcopy(12, m_aeroForces, 1, forces, 1);
1014 }
1015}
1016
1017/**
1018 * Function to check the type of forcing
1019 **/
1020bool IncNavierStokes::DefinedForcing(const std::string &sForce)
1021{
1022 std::vector<std::string> vForceList;
1023 bool hasForce{false};
1024
1025 if (!m_session->DefinesElement("Nektar/Forcing"))
1026 {
1027 return hasForce;
1028 }
1029
1030 TiXmlElement *vForcing = m_session->GetElement("Nektar/Forcing");
1031 if (vForcing)
1032 {
1033 TiXmlElement *vForce = vForcing->FirstChildElement("FORCE");
1034 while (vForce)
1035 {
1036 std::string vType = vForce->Attribute("TYPE");
1037
1038 vForceList.push_back(vType);
1039 vForce = vForce->NextSiblingElement("FORCE");
1040 }
1041 }
1042
1043 for (auto &f : vForceList)
1044 {
1045 if (boost::iequals(f, sForce))
1046 {
1047 hasForce = true;
1048 }
1049 }
1050
1051 return hasForce;
1052}
1053
1054/**
1055 * Perform the extrapolation.
1056 */
1058{
1059 m_extrapolation->SubStepSaveFields(step);
1060 m_extrapolation->SubStepAdvance(step, m_time);
1062 return false;
1063}
1064
1065} // namespace Nektar
#define ASSERTL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Array< OneD, Array< OneD, int > > m_fieldsBCToTraceID
Mapping from BCs to Elmt Edge IDs.
void v_GetMovingFramePivot(Array< OneD, NekDouble > &vFramePivot) override
Array< OneD, NekDouble > v_GetMaxStdVelocity(const NekDouble SpeedSoundFactor) override
std::map< int, std::map< int, WomersleyParamsSharedPtr > > m_womersleyParams
Womersley parameters if required.
bool v_GetMovingFrameDisp(Array< OneD, NekDouble > &vFrameDisp) override
void v_SetAeroForce(Array< OneD, NekDouble > forces) override
virtual int v_GetForceDimension()=0
void SetWomersleyBoundary(const int fldid, const int bndid)
Set Womersley Profile if specified.
void v_GetMovableDoFs(std::set< int > &dirDoFs) override
void v_GetAeroForce(Array< OneD, NekDouble > forces) override
void SetZeroNormalVelocity()
Set Normal Velocity Component to Zero.
MultiRegions::ExpListSharedPtr v_GetPressure() override
Array< OneD, NekDouble > m_aeroForces
void SetBoundaryConditions(NekDouble time)
time dependent boundary conditions updating
NekDouble m_kinvis
Kinematic viscosity.
void v_GetDensity(const Array< OneD, const Array< OneD, NekDouble > > &physfield, Array< OneD, NekDouble > &density) override
void SetRadiationBoundaryForcing(int fieldid)
Set Radiation forcing term.
Array< OneD, Array< OneD, NekDouble > > m_fieldsRadiationFactor
RHS Factor for Radiation Condition.
bool DefinedForcing(const std::string &sForce)
void v_SetMovingFrameVelocities(const Array< OneD, NekDouble > &vFrameVels) override
bool v_GetMovingFrameVelocities(Array< OneD, NekDouble > &vFrameVels) override
bool v_PreIntegrate(int step) override
void SetUpWomersley(const int fldid, const int bndid, std::string womstr)
Set Up Womersley details.
void v_InitObject(bool DeclareField=true) override
Initialisation object for EquationSystem.
ExtrapolateSharedPtr m_extrapolation
Array< OneD, int > m_velocity
int which identifies which components of m_fields contains the velocity (u,v,w);
static std::string eqTypeLookupIds[]
void v_SetMovingFramePivot(const Array< OneD, NekDouble > &vFramePivot) override
void v_SetMovableDoFs(const std::set< int > &dirDoFs) override
Array< OneD, Array< OneD, int > > m_fieldsBCToElmtID
Mapping from BCs to Elmt IDs.
void v_GetVelocity(const Array< OneD, const Array< OneD, NekDouble > > &physfield, Array< OneD, Array< OneD, NekDouble > > &velocity) override
EquationType m_equationType
equation type;
int m_nConvectiveFields
Number of fields to be convected;.
void AddForcing(const SolverUtils::ForcingSharedPtr &pForce)
std::vector< SolverUtils::ForcingSharedPtr > m_forcing
Forcing terms.
void v_SetMovingFrameDisp(const Array< OneD, NekDouble > &vFrameDisp) override
void EvaluateAdvectionTerms(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
IncNavierStokes(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Constructor.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
A base class for PDEs which include an advection component.
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareField=true) override
Initialisation object for EquationSystem.
int m_spacedim
Spatial dimension (>= expansion dim).
NekDouble m_timestep
Time step size.
NekDouble m_time
Current time of simulation.
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
std::vector< std::string > m_strFrameData
variable name in m_movingFrameData
SOLVER_UTILS_EXPORT int GetPhys_Offset(int n)
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
LibUtilities::FieldMetaDataMap m_fieldMetaDataMap
Map to identify relevant solver info to dump in output fields.
SpatialDomains::BoundaryConditionsSharedPtr m_boundaryConditions
Pointer to boundary conditions object.
Array< OneD, NekDouble > m_movingFrameData
Moving reference frame status in the body frame X, Y, Z, Theta_x, Theta_y, Theta_z,...
static SOLVER_UTILS_EXPORT std::vector< ForcingSharedPtr > Load(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields=0)
Definition Forcing.cpp:76
Base class for unsteady solvers.
static NekDouble rad(NekDouble x, NekDouble y)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Equation > EquationSharedPtr
Definition Equation.h:131
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition Expansion.h:66
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
AdvectionFactory & GetAdvectionFactory()
Gets the factory for initialising advection objects.
Definition Advection.cpp:43
SOLVER_UTILS_EXPORT typedef std::shared_ptr< Forcing > ForcingSharedPtr
A shared pointer to an EquationSystem object.
Definition Forcing.h:53
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition MeshGraph.h:224
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
std::complex< double > NekComplexDouble
@ eSteadyNavierStokes
@ eUnsteadyNavierStokes
@ eSteadyLinearisedNS
@ eUnsteadyLinearisedNS
@ eEquationTypeSize
std::shared_ptr< WomersleyParams > WomersleyParamsSharedPtr
const std::string kEquationTypeStr[]
std::complex< Nektar::NekDouble > ImagBesselComp(int n, std::complex< Nektar::NekDouble > y)
Calcualte the bessel function of the first kind with complex double input y. Taken from Numerical Rec...
Definition Polylib.cpp:1559
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 Neg(int n, T *x, const int incx)
Negate x = -x.
Definition Vmath.hpp:292
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 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 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
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290