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 <iomanip>
37 #include <boost/algorithm/string.hpp>
38 
45 
49 #include <algorithm>
50 #include <iostream>
51 #include <fstream>
52 #include <sstream>
53 
54 #include <tinyxml.h>
57 
58 using namespace std;
59 
60 namespace Nektar
61 {
62 
63  /**
64  * Constructor. Creates ...
65  *
66  * \param
67  * \param
68  */
69  IncNavierStokes::IncNavierStokes(
72  UnsteadySystem(pSession, pGraph),
73  AdvectionSystem(pSession, pGraph),
74  m_SmoothAdvection(false)
75  {
76  }
77 
79  {
81 
82  int i,j;
83  int numfields = m_fields.size();
84  std::string velids[] = {"u","v","w"};
85 
86  // Set up Velocity field to point to the first m_expdim of m_fields;
88 
89  for(i = 0; i < m_spacedim; ++i)
90  {
91  for(j = 0; j < numfields; ++j)
92  {
93  std::string var = m_boundaryConditions->GetVariable(j);
94  if(boost::iequals(velids[i], var))
95  {
96  m_velocity[i] = j;
97  break;
98  }
99 
100  ASSERTL0(j != numfields, "Failed to find field: " + var);
101  }
102  }
103 
104  // Set up equation type enum using kEquationTypeStr
105  for(i = 0; i < (int) eEquationTypeSize; ++i)
106  {
107  bool match;
108  m_session->MatchSolverInfo("EQTYPE",
109  kEquationTypeStr[i],match,false);
110  if(match)
111  {
113  break;
114  }
115  }
117  "EQTYPE not found in SOLVERINFO section");
118 
119  // This probably should to into specific implementations
120  // Equation specific Setups
121  switch(m_equationType)
122  {
123  case eSteadyStokes:
124  case eSteadyOseen:
125  case eSteadyNavierStokes:
126  case eSteadyLinearisedNS:
128  case eUnsteadyStokes:
129  break;
130  case eNoEquationType:
131  default:
132  ASSERTL0(false,"Unknown or undefined equation type");
133  }
134 
135  m_session->LoadParameter("Kinvis", m_kinvis);
136 
137  // Default advection type per solver
138  std::string vConvectiveType;
139  switch(m_equationType)
140  {
141  case eUnsteadyStokes:
142  case eSteadyLinearisedNS:
143  vConvectiveType = "NoAdvection";
144  break;
146  case eSteadyNavierStokes:
147  vConvectiveType = "Convective";
148  break;
150  vConvectiveType = "Linearised";
151  break;
152  default:
153  break;
154  }
155 
156  // Check if advection type overridden
157  if (m_session->DefinesTag("AdvectiveType") &&
160  {
161  vConvectiveType = m_session->GetTag("AdvectiveType");
162  }
163 
164  // Initialise advection
166  vConvectiveType, vConvectiveType);
167  m_advObject->InitObject( m_session, m_fields);
168 
169  // Forcing terms
170  m_forcing = SolverUtils::Forcing::Load(m_session, shared_from_this(),
172 
173  // check to see if any Robin boundary conditions and if so set
174  // up m_field to boundary condition maps;
179 
180  for (i = 0; i < m_fields.size(); ++i)
181  {
182  bool Set = false;
183 
186  int radpts = 0;
187 
188  BndConds = m_fields[i]->GetBndConditions();
189  BndExp = m_fields[i]->GetBndCondExpansions();
190  for(int n = 0; n < BndConds.size(); ++n)
191  {
192  if(boost::iequals(BndConds[n]->GetUserDefined(),"Radiation"))
193  {
194  ASSERTL0(BndConds[n]->GetBoundaryConditionType() ==
196  "Radiation boundary condition must be of type Robin <R>");
197 
198  if(Set == false)
199  {
200  m_fields[i]->GetBoundaryToElmtMap(
202  Set = true;
203  }
204  radpts += BndExp[n]->GetTotPoints();
205  }
206  if(boost::iequals(BndConds[n]->GetUserDefined(),
207  "ZeroNormalComponent"))
208  {
209  ASSERTL0(BndConds[n]->GetBoundaryConditionType() ==
211  "Zero Normal Component boundary condition option must be of type Dirichlet <D>");
212 
213  if(Set == false)
214  {
215  m_fields[i]->GetBoundaryToElmtMap(
217  Set = true;
218  }
219  }
220  }
221 
223 
224  radpts = 0; // reset to use as a counter
225 
226  for(int n = 0; n < BndConds.size(); ++n)
227  {
228  if(boost::iequals(BndConds[n]->GetUserDefined(),"Radiation"))
229  {
230 
231  int npoints = BndExp[n]->GetNpoints();
232  Array<OneD, NekDouble> x0(npoints,0.0);
233  Array<OneD, NekDouble> x1(npoints,0.0);
234  Array<OneD, NekDouble> x2(npoints,0.0);
235  Array<OneD, NekDouble> tmpArray;
236 
237  BndExp[n]->GetCoords(x0,x1,x2);
238 
239  LibUtilities::Equation coeff =
240  std::static_pointer_cast<
242  >(BndConds[n])->m_robinPrimitiveCoeff;
243 
244  coeff.Evaluate(x0,x1,x2,m_time,
245  tmpArray = m_fieldsRadiationFactor[i]+ radpts);
246  //Vmath::Neg(npoints,tmpArray = m_fieldsRadiationFactor[i]+ radpts,1);
247  radpts += npoints;
248  }
249  }
250  }
251 
252  // Set up maping for womersley BC - and load variables
253  for (int i = 0; i < m_fields.size(); ++i)
254  {
255  for(int n = 0; n < m_fields[i]->GetBndConditions().size(); ++n)
256  {
257  if(boost::istarts_with(m_fields[i]->GetBndConditions()[n]->GetUserDefined(),"Womersley"))
258  {
259  // assumes that boundary condition is applied in normal direction
260  // and is decomposed for each direction. There could be a
261  // unique file for each direction
263  // Read in fourier coeffs and precompute coefficients
264  SetUpWomersley(i, n,
265  m_fields[i]->GetBndConditions()[n]->GetUserDefined());
266 
267  m_fields[i]->GetBoundaryToElmtMap(m_fieldsBCToElmtID[i],m_fieldsBCToTraceID[i]);
268 
269  }
270  }
271  }
272 
273  // Set up Field Meta Data for output files
274  m_fieldMetaDataMap["Kinvis"] = boost::lexical_cast<std::string>(m_kinvis);
275  m_fieldMetaDataMap["TimeStep"] = boost::lexical_cast<std::string>(m_timestep);
276  }
277 
278  /**
279  * Destructor
280  */
282  {
283  }
284 
285  /**
286  * Evaluation -N(V) for all fields except pressure using m_velocity
287  */
289  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
290  Array<OneD, Array<OneD, NekDouble> > &outarray,
291  const NekDouble time)
292  {
293  int i;
294  int VelDim = m_velocity.size();
295  Array<OneD, Array<OneD, NekDouble> > velocity(VelDim);
296 
297  int npoints = m_fields[0]->GetNpoints();
298  for (i = 0; i < VelDim; ++i)
299  {
300  velocity[i] = Array<OneD, NekDouble>(npoints);
301  Vmath::Vcopy(npoints, inarray[m_velocity[i]], 1, velocity[i], 1);
302  }
303  for (auto &x : m_forcing)
304  {
305  x->PreApply(m_fields, velocity, velocity, time);
306  }
307 
309  velocity, inarray, outarray, time);
310  }
311 
312  /**
313  * Time dependent boundary conditions updating
314  */
316  {
317  int i, n;
318  std::string varName;
319  int nvariables = m_fields.size();
320 
321  for (i = 0; i < nvariables; ++i)
322  {
323  for(n = 0; n < m_fields[i]->GetBndConditions().size(); ++n)
324  {
325  if(m_fields[i]->GetBndConditions()[n]->IsTimeDependent())
326  {
327  varName = m_session->GetVariable(i);
328  m_fields[i]->EvaluateBoundaryConditions(time, varName);
329  }
330  else if(boost::istarts_with(
331  m_fields[i]->GetBndConditions()[n]->GetUserDefined(),
332  "Womersley"))
333  {
335  }
336  }
337 
338  // Set Radiation conditions if required
340  }
341 
343  }
344 
345  /**
346  * Probably should be pushed back into ContField?
347  */
349  {
350  int i,n;
351 
354 
355  BndConds = m_fields[fieldid]->GetBndConditions();
356  BndExp = m_fields[fieldid]->GetBndCondExpansions();
357 
360 
361  int cnt;
362  int elmtid,nq,offset, boundary;
363  Array<OneD, NekDouble> Bvals, U;
364  int cnt1 = 0;
365 
366  for(cnt = n = 0; n < BndConds.size(); ++n)
367  {
368  std::string type = BndConds[n]->GetUserDefined();
369 
370  if((BndConds[n]->GetBoundaryConditionType() ==
372  (boost::iequals(type,"Radiation")))
373  {
374  for(i = 0; i < BndExp[n]->GetExpSize(); ++i,cnt++)
375  {
376  elmtid = m_fieldsBCToElmtID[m_velocity[fieldid]][cnt];
377  elmt = m_fields[fieldid]->GetExp(elmtid);
378  offset = m_fields[fieldid]->GetPhys_Offset(elmtid);
379 
380  U = m_fields[fieldid]->UpdatePhys() + offset;
381  Bc = BndExp[n]->GetExp(i);
382 
383  boundary = m_fieldsBCToTraceID[fieldid][cnt];
384 
385  // Get edge values and put into ubc
386  nq = Bc->GetTotPoints();
387  Array<OneD, NekDouble> ubc(nq);
388  elmt->GetTracePhysVals(boundary,Bc,U,ubc);
389 
390  Vmath::Vmul(nq,&m_fieldsRadiationFactor[fieldid][cnt1 +
391  BndExp[n]->GetPhys_Offset(i)],1,
392  &ubc[0],1,&ubc[0],1);
393 
394  Bvals = BndExp[n]->UpdateCoeffs()+BndExp[n]->
395  GetCoeff_Offset(i);
396 
397  Bc->IProductWRTBase(ubc,Bvals);
398  }
399  cnt1 += BndExp[n]->GetTotPoints();
400  }
401  else
402  {
403  cnt += BndExp[n]->GetExpSize();
404  }
405  }
406  }
407 
408 
410  {
411  // use static trip since cannot use UserDefinedTag for zero
412  // velocity and have time dependent conditions
413  static bool Setup = false;
414 
415  if(Setup == true)
416  {
417  return;
418  }
419  Setup = true;
420 
421  int i,n;
422 
424  BndConds(m_spacedim);
426  BndExp(m_spacedim);
427 
428 
429  for(i = 0; i < m_spacedim; ++i)
430  {
431  BndConds[i] = m_fields[m_velocity[i]]->GetBndConditions();
432  BndExp[i] = m_fields[m_velocity[i]]->GetBndCondExpansions();
433  }
434 
436 
437  int cnt;
438  int elmtid,nq, boundary;
439 
441  Array<OneD, NekDouble> Bphys,Bcoeffs;
442 
443  int fldid = m_velocity[0];
444 
445  for(cnt = n = 0; n < BndConds[0].size(); ++n)
446  {
447  if((BndConds[0][n]->GetBoundaryConditionType() ==
449  (boost::iequals(BndConds[0][n]->GetUserDefined(),
450  "ZeroNormalComponent")))
451  {
452  for(i = 0; i < BndExp[0][n]->GetExpSize(); ++i,cnt++)
453  {
454  elmtid = m_fieldsBCToElmtID[fldid][cnt];
455  elmt = m_fields[0]->GetExp(elmtid);
456  boundary = m_fieldsBCToTraceID[fldid][cnt];
457 
458  normals = elmt->GetTraceNormal(boundary);
459 
460  nq = BndExp[0][n]->GetExp(i)->GetTotPoints();
461  Array<OneD, NekDouble> normvel(nq,0.0);
462 
463  for(int k = 0; k < m_spacedim; ++k)
464  {
465  Bphys = BndExp[k][n]->UpdatePhys()+
466  BndExp[k][n]->GetPhys_Offset(i);
467  Bc = BndExp[k][n]->GetExp(i);
468  Vmath::Vvtvp(nq,normals[k],1,Bphys,1,normvel,1,
469  normvel,1);
470  }
471 
472  // negate normvel for next step
473  Vmath::Neg(nq,normvel,1);
474 
475  for(int k = 0; k < m_spacedim; ++k)
476  {
477  Bphys = BndExp[k][n]->UpdatePhys()+
478  BndExp[k][n]->GetPhys_Offset(i);
479  Bcoeffs = BndExp[k][n]->UpdateCoeffs()+
480  BndExp[k][n]->GetCoeff_Offset(i);
481  Bc = BndExp[k][n]->GetExp(i);
482  Vmath::Vvtvp(nq,normvel,1,normals[k],1,Bphys,1,
483  Bphys,1);
484  Bc->FwdTrans_BndConstrained(Bphys,Bcoeffs);
485  }
486  }
487  }
488  else
489  {
490  cnt += BndExp[0][n]->GetExpSize();
491  }
492  }
493  }
494 
495 
496  /**
497  * Womersley boundary condition defintion
498  */
499  void IncNavierStokes::SetWomersleyBoundary(const int fldid, const int bndid)
500  {
501  ASSERTL1(m_womersleyParams.count(bndid) == 1,
502  "Womersley parameters for this boundary have not been set up");
503 
504  WomersleyParamsSharedPtr WomParam = m_womersleyParams[fldid][bndid];
505  NekComplexDouble zvel;
506  int i,j,k;
507 
508  int M_coeffs = WomParam->m_wom_vel.size();
509 
510  NekDouble T = WomParam->m_period;
511  NekDouble axis_normal = WomParam->m_axisnormal[fldid];
512 
513  // Womersley Number
514  NekComplexDouble omega_c (2.0*M_PI/T, 0.0);
515  NekComplexDouble k_c (0.0, 0.0);
516  NekComplexDouble m_time_c (m_time, 0.0);
517  NekComplexDouble zi (0.0,1.0);
518  NekComplexDouble i_pow_3q2 (-1.0/sqrt(2.0),1.0/sqrt(2.0));
519 
521  BndCondExp = m_fields[fldid]->GetBndCondExpansions()[bndid];
522 
524  int cnt=0;
525  int nfq;
527  int exp_npts = BndCondExp->GetExpSize();
528  Array<OneD, NekDouble> wbc(exp_npts,0.0);
529 
530  Array<OneD, NekComplexDouble> zt(M_coeffs);
531 
532  // preallocate the exponent
533  for (k=1; k < M_coeffs; k++)
534  {
535  k_c = NekComplexDouble((NekDouble) k, 0.0);
536  zt[k] = std::exp(zi * omega_c * k_c * m_time_c);
537  }
538 
539  // Loop over each element in an expansion
540  for(i = 0; i < exp_npts; ++i,cnt++)
541  {
542  // Get Boundary and trace expansion
543  bc = BndCondExp->GetExp(i);
544  nfq = bc->GetTotPoints();
545  Array<OneD, NekDouble> wbc(nfq,0.0);
546 
547  // Compute womersley solution
548  for (j=0; j < nfq; j++)
549  {
550  wbc[j] = WomParam->m_poiseuille[i][j];
551  for (k=1; k < M_coeffs; k++)
552  {
553  zvel = WomParam->m_zvel[i][j][k] * zt[k];
554  wbc[j] = wbc[j] + zvel.real();
555  }
556  }
557 
558  // Multiply w by normal to get u,v,w component of velocity
559  Vmath::Smul(nfq,axis_normal,wbc,1,wbc,1);
560  // get the offset
561  Bvals = BndCondExp->UpdateCoeffs()+
562  BndCondExp->GetCoeff_Offset(i);
563 
564  // Push back to Coeff space
565  bc->FwdTrans(wbc,Bvals);
566  }
567  }
568 
569 
570  void IncNavierStokes::SetUpWomersley(const int fldid, const int bndid, std::string womStr)
571  {
572  std::string::size_type indxBeg = womStr.find_first_of(':') + 1;
573  string filename = womStr.substr(indxBeg,string::npos);
574 
575  TiXmlDocument doc(filename);
576 
577  bool loadOkay = doc.LoadFile();
578  ASSERTL0(loadOkay,(std::string("Failed to load file: ") +
579  filename).c_str());
580 
581  TiXmlHandle docHandle(&doc);
582 
583  int err; /// Error value returned by TinyXML.
584 
585  TiXmlElement *nektar = doc.FirstChildElement("NEKTAR");
586  ASSERTL0(nektar, "Unable to find NEKTAR tag in file.");
587 
588  TiXmlElement *wombc = nektar->FirstChildElement("WOMERSLEYBC");
589  ASSERTL0(wombc, "Unable to find WOMERSLEYBC tag in file.");
590 
591  // read womersley parameters
592  TiXmlElement *womparam = wombc->FirstChildElement("WOMPARAMS");
593  ASSERTL0(womparam, "Unable to find WOMPARAMS tag in file.");
594 
595  // Input coefficients
596  TiXmlElement *params = womparam->FirstChildElement("W");
597  map<std::string,std::string> Wparams;
598 
599  // read parameter list
600  while (params)
601  {
602 
603  std::string propstr;
604  propstr = params->Attribute("PROPERTY");
605 
606  ASSERTL0(!propstr.empty(),
607  "Failed to read PROPERTY value Womersley BC Parameter");
608 
609 
610  std::string valstr;
611  valstr = params->Attribute("VALUE");
612 
613  ASSERTL0(!valstr.empty(),
614  "Failed to read VALUE value Womersley BC Parameter");
615 
616  std::transform(propstr.begin(),propstr.end(),propstr.begin(),
617  ::toupper);
618  Wparams[propstr] = valstr;
619 
620  params = params->NextSiblingElement("W");
621  }
622  bool parseGood;
623 
624  // Read parameters
625 
626  ASSERTL0(Wparams.count("RADIUS") == 1,
627  "Failed to find Radius parameter in Womersley boundary conditions");
628  std::vector<NekDouble> rad;
629  ParseUtils::GenerateVector(Wparams["RADIUS"],rad);
630  m_womersleyParams[fldid][bndid]->m_radius = rad[0];
631 
632  ASSERTL0(Wparams.count("PERIOD") == 1,
633  "Failed to find period parameter in Womersley boundary conditions");
634  std::vector<NekDouble> period;
635  parseGood = ParseUtils::GenerateVector(Wparams["PERIOD"],period);
636  m_womersleyParams[fldid][bndid]->m_period = period[0];
637 
638 
639  ASSERTL0(Wparams.count("AXISNORMAL") == 1,
640  "Failed to find axisnormal parameter in Womersley boundary conditions");
641  std::vector<NekDouble> anorm;
642  parseGood = ParseUtils::GenerateVector(Wparams["AXISNORMAL"],anorm);
643  m_womersleyParams[fldid][bndid]->m_axisnormal[0] = anorm[0];
644  m_womersleyParams[fldid][bndid]->m_axisnormal[1] = anorm[1];
645  m_womersleyParams[fldid][bndid]->m_axisnormal[2] = anorm[2];
646 
647 
648  ASSERTL0(Wparams.count("AXISPOINT") == 1,
649  "Failed to find axispoint parameter in Womersley boundary conditions");
650  std::vector<NekDouble> apt;
651  parseGood = ParseUtils::GenerateVector(Wparams["AXISPOINT"],apt);
652  m_womersleyParams[fldid][bndid]->m_axispoint[0] = apt[0];
653  m_womersleyParams[fldid][bndid]->m_axispoint[1] = apt[1];
654  m_womersleyParams[fldid][bndid]->m_axispoint[2] = apt[2];
655 
656  // Read Temporal Fourier Coefficients.
657 
658  // Find the FourierCoeff tag
659  TiXmlElement *coeff = wombc->FirstChildElement("FOURIERCOEFFS");
660 
661  // Input coefficients
662  TiXmlElement *fval = coeff->FirstChildElement("F");
663 
664  int indx;
665  int nextFourierCoeff = -1;
666 
667  while (fval)
668  {
669  nextFourierCoeff++;
670 
671  TiXmlAttribute *fvalAttr = fval->FirstAttribute();
672  std::string attrName(fvalAttr->Name());
673 
674  ASSERTL0(attrName == "ID",
675  (std::string("Unknown attribute name: ") + attrName).c_str());
676 
677  err = fvalAttr->QueryIntValue(&indx);
678  ASSERTL0(err == TIXML_SUCCESS, "Unable to read attribute ID.");
679 
680  std::string coeffStr = fval->FirstChild()->ToText()->ValueStr();
681  vector<NekDouble> coeffvals;
682 
683  parseGood = ParseUtils::GenerateVector(coeffStr, coeffvals);
684  ASSERTL0(parseGood,
685  (std::string("Problem reading value of fourier coefficient, ID=") +
686  boost::lexical_cast<string>(indx)).c_str());
687  ASSERTL1(coeffvals.size() == 2,
688  (std::string("Have not read two entries of Fourier coefficicent from ID="+
689  boost::lexical_cast<string>(indx)).c_str()));
690 
691  m_womersleyParams[fldid][bndid]->m_wom_vel.push_back(NekComplexDouble (coeffvals[0], coeffvals[1]));
692 
693  fval = fval->NextSiblingElement("F");
694  }
695 
696  // starting point of precalculation
697  int i,j,k;
698  // M fourier coefficients
699  int M_coeffs = m_womersleyParams[fldid][bndid]->m_wom_vel.size();
700  NekDouble R = m_womersleyParams[fldid][bndid]->m_radius;
701  NekDouble T = m_womersleyParams[fldid][bndid]->m_period;
702  Array<OneD, NekDouble > x0 = m_womersleyParams[fldid][bndid]->m_axispoint;
703 
704  NekComplexDouble rqR;
705  // Womersley Number
706  NekComplexDouble omega_c (2.0*M_PI/T, 0.0);
707  NekComplexDouble alpha_c (R*sqrt(omega_c.real()/m_kinvis), 0.0);
708  NekComplexDouble z1 (1.0,0.0);
709  NekComplexDouble i_pow_3q2 (-1.0/sqrt(2.0),1.0/sqrt(2.0));
710 
712  BndCondExp = m_fields[fldid]->GetBndCondExpansions()[bndid];
713 
715  int cnt = 0;
716  int nfq;
718 
719  int exp_npts = BndCondExp->GetExpSize();
720  Array<OneD, NekDouble> wbc(exp_npts,0.0);
721 
722  // allocate time indepedent variables
723  m_womersleyParams[fldid][bndid]->m_poiseuille = Array<OneD, Array<OneD, NekDouble> > (exp_npts);
724  m_womersleyParams[fldid][bndid]->m_zvel = Array<OneD, Array<OneD, Array<OneD, NekComplexDouble> > > (exp_npts);
725  // could use M_coeffs - 1 but need to avoid complicating things
726  Array<OneD, NekComplexDouble> zJ0(M_coeffs);
727  Array<OneD, NekComplexDouble> lamda_n(M_coeffs);
728  Array<OneD, NekComplexDouble> k_c(M_coeffs);
729  NekComplexDouble zJ0r;
730 
731  for (k=1; k < M_coeffs; k++)
732  {
733  k_c[k] = NekComplexDouble((NekDouble) k, 0.0);
734  lamda_n[k] = i_pow_3q2 * alpha_c * sqrt(k_c[k]);
735  zJ0[k] = Polylib::ImagBesselComp(0,lamda_n[k]);
736  }
737 
738  // Loop over each element in an expansion
739  for(i = 0; i < exp_npts; ++i,cnt++)
740  {
741  // Get Boundary and trace expansion
742  bc = BndCondExp->GetExp(i);
743  nfq = bc->GetTotPoints();
744 
745  Array<OneD, NekDouble> x(nfq,0.0);
746  Array<OneD, NekDouble> y(nfq,0.0);
747  Array<OneD, NekDouble> z(nfq,0.0);
748  bc->GetCoords(x,y,z);
749 
750  m_womersleyParams[fldid][bndid]->m_poiseuille[i] =
752  m_womersleyParams[fldid][bndid]->m_zvel[i] =
754 
755  // Compute coefficients
756  for (j=0; j < nfq; j++)
757  {
758  rqR = NekComplexDouble (sqrt((x[j]-x0[0])*(x[j]-x0[0]) +
759  (y[j]-x0[1])*(y[j]-x0[1]) +
760  (z[j]-x0[2])*(z[j]-x0[2]))/R, 0.0);
761 
762  // Compute Poiseulle Flow
763  m_womersleyParams[fldid][bndid]->m_poiseuille[i][j] =
764  m_womersleyParams[fldid][bndid]->m_wom_vel[0].real() *
765  (1. - rqR.real()*rqR.real());
766 
767 
768  m_womersleyParams[fldid][bndid]->m_zvel[i][j] =
770 
771  // compute the velocity information
772  for (k=1; k < M_coeffs; k++)
773  {
774  zJ0r = Polylib::ImagBesselComp(0,rqR * lamda_n[k]);
775  m_womersleyParams[fldid][bndid]->m_zvel[i][j][k] =
776  m_womersleyParams[fldid][bndid]->m_wom_vel[k] *
777  (z1 - (zJ0r / zJ0[k]));
778  }
779  }
780  }
781  }
782 
783  /**
784  * Add an additional forcing term programmatically.
785  */
787  const SolverUtils::ForcingSharedPtr& pForce)
788  {
789  m_forcing.push_back(pForce);
790  }
791 
792  /**
793  *
794  */
796  const NekDouble SpeedSoundFactor)
797  {
798  boost::ignore_unused(SpeedSoundFactor);
799  int nvel = m_velocity.size();
800  int nelmt = m_fields[0]->GetExpSize();
801 
802  Array<OneD, NekDouble> stdVelocity(nelmt, 0.0);
804 
805  if(m_HomogeneousType == eHomogeneous1D) // just do check on 2D info
806  {
807  velfields = Array<OneD, Array<OneD, NekDouble> >(2);
808 
809  for(int i = 0; i < 2; ++i)
810  {
811  velfields[i] = m_fields[m_velocity[i]]->UpdatePhys();
812  }
813  }
814  else
815  {
816  velfields = Array<OneD, Array<OneD, NekDouble> >(nvel);
817 
818  for(int i = 0; i < nvel; ++i)
819  {
820  velfields[i] = m_fields[m_velocity[i]]->UpdatePhys();
821  }
822  }
823 
824  stdVelocity = m_extrapolation->GetMaxStdVelocity(velfields);
825 
826  return stdVelocity;
827  }
828 
829  /**
830  *
831  */
833  const Array<OneD, const Array<OneD, NekDouble> > &physfield,
835  {
836  pressure = physfield[m_nConvectiveFields];
837  }
838 
839  /**
840  *
841  */
843  const Array<OneD, const Array<OneD, NekDouble> > &physfield,
844  Array<OneD, NekDouble> &density)
845  {
846  int nPts = physfield[0].size();
847  Vmath::Fill(nPts, 1.0, density, 1);
848  }
849 
850  /**
851  *
852  */
854  const Array<OneD, const Array<OneD, NekDouble> > &physfield,
855  Array<OneD, Array<OneD, NekDouble> > &velocity)
856  {
857  for(int i = 0; i < m_spacedim; ++i)
858  {
859  velocity[i] = physfield[i];
860  }
861  }
862 
863  /**
864  * Perform the extrapolation.
865  */
867  {
868  m_extrapolation->SubStepSaveFields(step);
869  m_extrapolation->SubStepAdvance(step,m_time);
871  return false;
872  }
873 
874 } //end of namespace
875 
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:250
virtual Array< OneD, NekDouble > v_GetMaxStdVelocity(const NekDouble SpeedSoundFactor)
Array< OneD, int > & GetVelocity(void)
Array< OneD, Array< OneD, int > > m_fieldsBCToTraceID
Mapping from BCs to Elmt Edge IDs.
virtual void v_InitObject()
Init object for UnsteadySystem class.
virtual int v_GetForceDimension()=0
void SetWomersleyBoundary(const int fldid, const int bndid)
Set Womersley Profile if specified.
void SetZeroNormalVelocity()
Set Normal Velocity Component to Zero.
void SetBoundaryConditions(NekDouble time)
time dependent boundary conditions updating
virtual bool v_PreIntegrate(int step)
NekDouble m_kinvis
Kinematic viscosity.
virtual void GetDensity(const Array< OneD, const Array< OneD, NekDouble > > &physfield, Array< OneD, NekDouble > &density)
Extract array with density from physfield.
void SetRadiationBoundaryForcing(int fieldid)
Set Radiation forcing term.
Array< OneD, Array< OneD, NekDouble > > m_fieldsRadiationFactor
RHS Factor for Radiation Condition.
void SetUpWomersley(const int fldid, const int bndid, std::string womstr)
Set Up Womersley details.
ExtrapolateSharedPtr m_extrapolation
Array< OneD, int > m_velocity
int which identifies which components of m_fields contains the velocity (u,v,w);
std::map< int, std::map< int, WomersleyParamsSharedPtr > > m_womersleyParams
Womersley parameters if required.
Array< OneD, Array< OneD, int > > m_fieldsBCToElmtID
Mapping from BCs to Elmt IDs.
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)
NekDouble Evaluate() const
Definition: Equation.cpp:95
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
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:135
A base class for PDEs which include an advection component.
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
virtual SOLVER_UTILS_EXPORT void v_InitObject()
Init object for UnsteadySystem class.
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.
SOLVER_UTILS_EXPORT int GetCoeff_Offset(int n)
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
enum HomogeneousType m_HomogeneousType
SOLVER_UTILS_EXPORT MultiRegions::ExpListSharedPtr GetPressure()
Get pressure field if available.
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.
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:128
Base class for unsteady solvers.
static NekDouble rad(NekDouble x, NekDouble y)
Definition: Interpreter.cpp:86
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
AdvectionFactory & GetAdvectionFactory()
Gets the factory for initialising advection objects.
Definition: Advection.cpp:47
SOLVER_UTILS_EXPORT typedef std::shared_ptr< Forcing > ForcingSharedPtr
A shared pointer to an EquationSystem object.
Definition: Forcing.h:52
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
std::complex< double > NekComplexDouble
@ eSteadyNavierStokes
@ eUnsteadyStokes
@ eUnsteadyNavierStokes
@ eSteadyLinearisedNS
@ eUnsteadyLinearisedNS
@ eEquationTypeSize
@ eNoEquationType
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:1651
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:192
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:461
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:513
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:225
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1199
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267