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