Nektar++
VelocityCorrectionScheme.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File VelocityCorrection.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: Velocity Correction Scheme for the Incompressible
32 // Navier Stokes equations
33 ///////////////////////////////////////////////////////////////////////////////
34 
39 #include <SolverUtils/Core/Misc.h>
40 
41 #include <boost/algorithm/string.hpp>
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47  using namespace MultiRegions;
48 
49  string VelocityCorrectionScheme::className =
51  "VelocityCorrectionScheme",
52  VelocityCorrectionScheme::create);
53 
54  /**
55  * Constructor. Creates ...
56  *
57  * \param
58  * \param
59  */
60  VelocityCorrectionScheme::VelocityCorrectionScheme(
63  : UnsteadySystem(pSession, pGraph),
64  IncNavierStokes(pSession, pGraph),
65  m_varCoeffLap(StdRegions::NullVarCoeffMap)
66  {
67 
68  }
69 
71  {
72  int n;
73 
75  m_explicitDiffusion = false;
76 
77  // Set m_pressure to point to last field of m_fields;
78  if (boost::iequals(m_session->GetVariable(m_fields.num_elements()-1), "p"))
79  {
80  m_nConvectiveFields = m_fields.num_elements()-1;
82  }
83  else
84  {
85  ASSERTL0(false,"Need to set up pressure field definition");
86  }
87 
88  // Determine diffusion coefficients for each field
90  for (n = 0; n < m_nConvectiveFields; ++n)
91  {
92  std::string varName = m_session->GetVariable(n);
93  if ( m_session->DefinesFunction("DiffusionCoefficient", varName))
94  {
96  = m_session->GetFunction("DiffusionCoefficient", varName);
97  m_diffCoeff[n] = ffunc->Evaluate();
98  }
99  }
100 
101  // Integrate only the convective fields
102  for (n = 0; n < m_nConvectiveFields; ++n)
103  {
104  m_intVariables.push_back(n);
105  }
106 
108  SetUpSVV();
109 
110  m_session->MatchSolverInfo("SmoothAdvection", "True",
111  m_SmoothAdvection, false);
112 
113  // set explicit time-intregration class operators
116 
117  // set implicit time-intregration class operators
120 
121  // Set up bits for flowrate.
122  m_session->LoadParameter("Flowrate", m_flowrate, 0.0);
123  m_session->LoadParameter("IO_FlowSteps", m_flowrateSteps, 0);
124  }
125 
127  {
128  // creation of the extrapolation object
131  {
132  std::string vExtrapolation = v_GetExtrapolateStr();
133  if (m_session->DefinesSolverInfo("Extrapolation"))
134  {
135  vExtrapolation = v_GetSubSteppingExtrapolateStr(
136  m_session->GetSolverInfo("Extrapolation"));
137  }
139  vExtrapolation,
140  m_session,
141  m_fields,
142  m_pressure,
143  m_velocity,
144  m_advObject);
145 
146  m_extrapolation->SubSteppingTimeIntegration(
147  m_intScheme->GetIntegrationMethod(), m_intScheme);
148  m_extrapolation->GenerateHOPBCMap(m_session);
149  }
150  }
151 
152  /**
153  * @brief Set up the Stokes solution used to impose constant flowrate
154  * through a boundary.
155  *
156  * This routine solves a Stokes equation using a unit forcing direction,
157  * specified by the user to be in the desired flow direction. This field can
158  * then be used to correct the end of each timestep to impose a constant
159  * volumetric flow rate through a user-defined boundary.
160  *
161  * There are three modes of operation:
162  *
163  * - Standard two-dimensional or three-dimensional simulations (e.g. pipes
164  * or channels)
165  * - 3DH1D simulations where the forcing is not in the homogeneous
166  * direction (e.g. channel flow, where the y-direction of the 2D mesh
167  * is perpendicular to the wall);
168  * - 3DH1D simulations where the forcing is in the homogeneous direction
169  * (e.g. pipe flow in the z-direction).
170  *
171  * In the first two cases, the user should define:
172  * - the `Flowrate` parameter, which dictates the volumetric flux through
173  * the reference area
174  * - tag a boundary region with the `Flowrate` user-defined type to define
175  * the reference area
176  * - define a `FlowrateForce` function with components `ForceX`, `ForceY`
177  * and `ForceZ` that defines a unit forcing in the appropriate direction.
178  *
179  * In the latter case, the user should define only the `Flowrate`; the
180  * reference area is taken to be the homogeneous plane and the force is
181  * assumed to be the unit z-vector \f$ \hat{e}_z \f$.
182  *
183  * This routine solves a single timestep of the Stokes problem
184  * (premultiplied by the backwards difference coefficient):
185  *
186  * \f[ \frac{\partial\mathbf{u}}{\partial t} = -\nabla p +
187  * \nu\nabla^2\mathbf{u} + \mathbf{f} \f]
188  *
189  * with a zero initial condition to obtain a field \f$ \mathbf{u}_s \f$. The
190  * flowrate is then corrected at each timestep \f$ n \f$ by adding the
191  * correction \f$ \alpha\mathbf{u}_s \f$ where
192  *
193  * \f[ \alpha = \frac{\overline{Q} - Q(\mathbf{u^n})}{Q(\mathbf{u}_s)} \f]
194  *
195  * where \f$ Q(\cdot)\f$ is the volumetric flux through the appropriate
196  * surface or line, which is implemented in
197  * VelocityCorrectionScheme::MeasureFlowrate. For more details, see chapter
198  * 3.2 of the thesis of D. Moxey (University of Warwick, 2011).
199  */
201  {
202  m_flowrateBndID = -1;
203  m_flowrateArea = 0.0;
204 
206  m_fields[0]->GetBndConditions();
207 
208  std::string forces[] = { "X", "Y", "Z" };
209  Array<OneD, NekDouble> flowrateForce(m_spacedim, 0.0);
210 
211  // Set up flowrate forces.
212  bool defined = true;
213  for (int i = 0; i < m_spacedim; ++i)
214  {
215  std::string varName = std::string("Force") + forces[i];
216  defined = m_session->DefinesFunction("FlowrateForce", varName);
217 
218  if (!defined && m_HomogeneousType == eHomogeneous1D)
219  {
220  break;
221  }
222 
223  ASSERTL0(defined,
224  "A 'FlowrateForce' function must defined with components "
225  "[ForceX, ...] to define direction of flowrate forcing");
226 
228  = m_session->GetFunction("FlowrateForce", varName);
229  flowrateForce[i] = ffunc->Evaluate();
230  }
231 
232  // Define flag for case with homogeneous expansion and forcing not in the
233  // z-direction
234  m_homd1DFlowinPlane = false;
235  if (defined && m_HomogeneousType == eHomogeneous1D)
236  {
237  m_homd1DFlowinPlane = true;
238  }
239 
240  // For 3DH1D simulations, if force isn't defined then assume in
241  // z-direction.
242  if (!defined)
243  {
244  flowrateForce[2] = 1.0;
245  }
246 
247  // Find the boundary condition that is tagged as the flowrate boundary.
248  for (int i = 0; i < bcs.num_elements(); ++i)
249  {
250  if (boost::iequals(bcs[i]->GetUserDefined(), "Flowrate"))
251  {
252  m_flowrateBndID = i;
253  break;
254  }
255  }
256 
257  int tmpBr = m_flowrateBndID;
258  m_comm->AllReduce(tmpBr, LibUtilities::ReduceMax);
259  ASSERTL0(tmpBr >= 0 || m_HomogeneousType == eHomogeneous1D,
260  "One boundary region must be marked using the 'Flowrate' "
261  "user-defined type to monitor the volumetric flowrate.");
262 
263  // Extract an appropriate expansion list to represents the boundary.
264  if (m_flowrateBndID >= 0)
265  {
266  // For a boundary, extract the boundary itself.
267  m_flowrateBnd = m_fields[0]->GetBndCondExpansions()[m_flowrateBndID];
268  }
270  {
271  // For 3DH1D simulations with no force specified, find the mean
272  // (0th) plane.
273  Array<OneD, unsigned int> zIDs = m_fields[0]->GetZIDs();
274  int tmpId = -1;
275 
276  for (int i = 0; i < zIDs.num_elements(); ++i)
277  {
278  if (zIDs[i] == 0)
279  {
280  tmpId = i;
281  break;
282  }
283  }
284 
285  ASSERTL1(tmpId <= 0, "Should be either at location 0 or -1 if not "
286  "found");
287 
288  if (tmpId != -1)
289  {
290  m_flowrateBnd = m_fields[0]->GetPlane(tmpId);
291  }
292  }
293 
294  // At this point, some processors may not have m_flowrateBnd set if they
295  // don't contain the appropriate boundary. To calculate the area, we
296  // integrate 1.0 over the boundary (which has been set up with the
297  // appropriate subcommunicator to avoid deadlock), and then communicate
298  // this to the other processors with an AllReduce.
299  if (m_flowrateBnd)
300  {
301  Array<OneD, NekDouble> inArea(m_flowrateBnd->GetNpoints(), 1.0);
302  m_flowrateArea = m_flowrateBnd->Integral(inArea);
303  }
305 
306  // In homogeneous case with forcing not aligned to the z-direction,
307  // redefine m_flowrateBnd so it is a 1D expansion
310  {
311  // For 3DH1D simulations with no force specified, find the mean
312  // (0th) plane.
313  Array<OneD, unsigned int> zIDs = m_fields[0]->GetZIDs();
314  m_planeID = -1;
315 
316  for (int i = 0; i < zIDs.num_elements(); ++i)
317  {
318  if (zIDs[i] == 0)
319  {
320  m_planeID = i;
321  break;
322  }
323  }
324 
325  ASSERTL1(m_planeID <= 0, "Should be either at location 0 or -1 if not "
326  "found");
327 
328  if (m_planeID != -1)
329  {
331  ->GetBndCondExpansions()[m_flowrateBndID]
332  ->GetPlane(m_planeID);
333  }
334  }
335 
336  // Set up some storage for the Stokes solution (to be stored in
337  // m_flowrateStokes) and its initial condition (inTmp), which holds the
338  // unit forcing.
339  int nqTot = m_fields[0]->GetNpoints();
340  Array<OneD, Array<OneD, NekDouble> > inTmp(m_spacedim);
342 
343  for (int i = 0; i < m_spacedim; ++i)
344  {
345  inTmp[i] = Array<OneD, NekDouble>(
346  nqTot, flowrateForce[i] * aii_dt);
347  m_flowrateStokes[i] = Array<OneD, NekDouble>(nqTot, 0.0);
348 
350  {
351  Array<OneD, NekDouble> inTmp2(nqTot);
352  m_fields[i]->HomogeneousFwdTrans(inTmp[i], inTmp2);
353  m_fields[i]->SetWaveSpace(true);
354  inTmp[i] = inTmp2;
355  }
356 
357  Vmath::Zero(
358  m_fields[i]->GetNcoeffs(), m_fields[i]->UpdateCoeffs(), 1);
359  }
360 
361  // Create temporary extrapolation object to avoid issues with
362  // m_extrapolation for HOPBCs using higher order timestepping schemes.
365  "Standard", m_session, m_fields, m_pressure, m_velocity,
366  m_advObject);
367 
368  // Finally, calculate the solution and the flux of the Stokes
369  // solution. We set m_greenFlux to maximum numeric limit, which signals
370  // to SolveUnsteadyStokesSystem that we don't need to apply a flowrate
371  // force.
372  m_greenFlux = numeric_limits<NekDouble>::max();
373  m_flowrateAiidt = aii_dt;
374  SolveUnsteadyStokesSystem(inTmp, m_flowrateStokes, 0.0, aii_dt);
376 
377  // If the user specified IO_FlowSteps, open a handle to store output.
378  if (m_comm->GetRank() == 0 && m_flowrateSteps &&
379  !m_flowrateStream.is_open())
380  {
381  std::string filename = m_session->GetSessionName();
382  filename += ".prs";
383  m_flowrateStream.open(filename.c_str());
384  m_flowrateStream.setf(ios::scientific, ios::floatfield);
385  m_flowrateStream << "# step time dP" << endl
386  << "# -------------------------------------------"
387  << endl;
388  }
389 
390  m_extrapolation = tmpExtrap;
391  }
392 
393  /**
394  * @brief Measure the volumetric flow rate through the volumetric flow rate
395  * reference surface.
396  *
397  * This routine computes the volumetric flow rate
398  *
399  * \f[
400  * Q(\mathbf{u}) = \frac{1}{\mu(R)} \int_R \mathbf{u} \cdot d\mathbf{s}
401  * \f]
402  *
403  * through the boundary region \f$ R \f$.
404  */
406  const Array<OneD, Array<OneD, NekDouble> > &inarray)
407  {
408  NekDouble flowrate = 0.0;
409 
410  if (m_flowrateBnd && m_flowrateBndID >= 0)
411  {
412  // If we're an actual boundary, calculate the vector flux through
413  // the boundary.
415 
417  {
418  // General case
419  for (int i = 0; i < m_spacedim; ++i)
420  {
421  m_fields[i]->ExtractPhysToBnd(m_flowrateBndID, inarray[i],
422  boundary[i]);
423  }
424  flowrate = m_flowrateBnd->VectorFlux(boundary);
425  }
426  else if(m_planeID == 0)
427  {
428  //Homogeneous with forcing in plane. Calculate flux only on
429  // the meanmode - calculateFlux necessary for hybrid
430  // parallelisation.
431  for (int i = 0; i < m_spacedim; ++i)
432  {
433  m_fields[i]->GetPlane(m_planeID)->ExtractPhysToBnd(
434  m_flowrateBndID, inarray[i], boundary[i]);
435  }
436 
437  // the flowrate is calculated on the mean mode so it needs to be
438  // multiplied by LZ to be consistent with the general case.
439  flowrate = m_flowrateBnd->VectorFlux(boundary) *
440  m_session->GetParameter("LZ");
441  }
442  }
443  else if (m_flowrateBnd && !m_homd1DFlowinPlane)
444  {
445  // 3DH1D case with no Flowrate boundary defined: compute flux
446  // through the zero-th (mean) plane.
447  flowrate = m_flowrateBnd->Integral(inarray[2]);
448  }
449 
450  // Communication to obtain the total flowrate
452  {
453  m_comm->GetColumnComm()->AllReduce(flowrate, LibUtilities::ReduceSum);
454  }
455  else
456  {
457  m_comm->AllReduce(flowrate, LibUtilities::ReduceSum);
458  }
459  return flowrate / m_flowrateArea;
460  }
461 
463  {
464  if (m_flowrateSteps > 0)
465  {
466  if (m_comm->GetRank() == 0 && (step + 1) % m_flowrateSteps == 0)
467  {
468  m_flowrateStream << setw(8) << step << setw(16) << m_time
469  << setw(16) << m_alpha << endl;
470  }
471  }
472 
474  }
475 
476 
477  /**
478  * Destructor
479  */
481  {
482  }
483 
484  /**
485  *
486  */
488  {
491  "Splitting Scheme", "Velocity correction (strong press. form)");
492 
493  if (m_extrapolation->GetSubStepIntegrationMethod() !=
495  {
496  SolverUtils::AddSummaryItem(s, "Substepping",
498  m_extrapolation->GetSubStepIntegrationMethod()]);
499  }
500 
501  string dealias = m_homogen_dealiasing ? "Homogeneous1D" : "";
503  {
504  dealias += (dealias == "" ? "" : " + ") + string("spectral/hp");
505  }
506  if (dealias != "")
507  {
508  SolverUtils::AddSummaryItem(s, "Dealiasing", dealias);
509  }
510 
511 
512  string smoothing = m_useSpecVanVisc ? "spectral/hp" : "";
513  if (smoothing != "")
514  {
516  {
518  s, "Smoothing-SpecHP", "SVV (" + smoothing +
519  " Exp Kernel(cut-off = "
520  + boost::lexical_cast<string>(m_sVVCutoffRatio)
521  + ", diff coeff = "
522  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"))");
523  }
524  else
525  {
527  {
529  s, "Smoothing-SpecHP", "SVV (" + smoothing +
530  " Power Kernel (Power ratio ="
531  + boost::lexical_cast<string>(m_sVVCutoffRatio)
532  + ", diff coeff = "
533  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"*Uh/p))");
534  }
535  else
536  {
538  s, "Smoothing-SpecHP", "SVV (" + smoothing +
539  " DG Kernel (diff coeff = "
540  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"*Uh/p))");
541 
542  }
543  }
544 
545  }
546 
548  {
550  s, "Smoothing-Homo1D", "SVV (Homogeneous1D - Exp Kernel(cut-off = "
551  + boost::lexical_cast<string>(m_sVVCutoffRatioHomo1D)
552  + ", diff coeff = "
553  + boost::lexical_cast<string>(m_sVVDiffCoeffHomo1D)+"))");
554  }
555 
556  }
557 
558  /**
559  *
560  */
562  {
564 
565  for (int i = 0; i < m_nConvectiveFields; ++i)
566  {
567  m_F[i] = Array< OneD, NekDouble> (m_fields[0]->GetTotPoints(), 0.0);
568  }
569 
570  m_flowrateAiidt = 0.0;
571 
573 
574  // Set up Field Meta Data for output files
575  m_fieldMetaDataMap["Kinvis"] =
576  boost::lexical_cast<std::string>(m_kinvis);
577  m_fieldMetaDataMap["TimeStep"] =
578  boost::lexical_cast<std::string>(m_timestep);
579 
580  // set boundary conditions here so that any normal component
581  // correction are imposed before they are imposed on initial
582  // field below
584 
585  for(int i = 0; i < m_nConvectiveFields; ++i)
586  {
587  m_fields[i]->LocalToGlobal();
588  m_fields[i]->ImposeDirichletConditions(m_fields[i]->UpdateCoeffs());
589  m_fields[i]->GlobalToLocal();
590  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
591  m_fields[i]->UpdatePhys());
592  }
593  }
594 
595 
596  /**
597  *
598  */
600  {
601  int nfields = m_fields.num_elements() - 1;
602  for (int k=0 ; k < nfields; ++k)
603  {
604  //Backward Transformation in physical space for time evolution
605  m_fields[k]->BwdTrans_IterPerExp(m_fields[k]->GetCoeffs(),
606  m_fields[k]->UpdatePhys());
607  }
608  }
609 
610  /**
611  *
612  */
614  {
615 
616  int nfields = m_fields.num_elements() - 1;
617  for (int k=0 ; k < nfields; ++k)
618  {
619  //Forward Transformation in physical space for time evolution
620  m_fields[k]->FwdTrans_IterPerExp(m_fields[k]->GetPhys(),
621  m_fields[k]->UpdateCoeffs());
622  }
623  }
624 
625  /**
626  *
627  */
629  {
630  int vVar = m_session->GetVariables().size();
631  Array<OneD, bool> vChecks(vVar, false);
632  vChecks[vVar-1] = true;
633  return vChecks;
634  }
635 
636  /**
637  *
638  */
640  {
641  return m_session->GetVariables().size() - 1;
642  }
643 
644  /**
645  * Explicit part of the method - Advection, Forcing + HOPBCs
646  */
648  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
649  Array<OneD, Array<OneD, NekDouble> > &outarray,
650  const NekDouble time)
651  {
652  EvaluateAdvectionTerms(inarray, outarray);
653 
654  // Smooth advection
656  {
657  for(int i = 0; i < m_nConvectiveFields; ++i)
658  {
659  m_pressure->SmoothField(outarray[i]);
660  }
661  }
662 
663  // Add forcing terms
664  for (auto &x : m_forcing)
665  {
666  x->Apply(m_fields, inarray, outarray, time);
667  }
668 
669  // Calculate High-Order pressure boundary conditions
670  m_extrapolation->EvaluatePressureBCs(inarray,outarray,m_kinvis);
671  }
672 
673  /**
674  * Implicit part of the method - Poisson + nConv*Helmholtz
675  */
677  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
678  Array<OneD, Array<OneD, NekDouble> > &outarray,
679  const NekDouble time,
680  const NekDouble aii_Dt)
681  {
682  // Set up flowrate if we're starting for the first time or the value of
683  // aii_Dt has changed.
684  if (m_flowrate > 0.0 && (aii_Dt != m_flowrateAiidt))
685  {
686  SetupFlowrate(aii_Dt);
687  }
688 
689  int physTot = m_fields[0]->GetTotPoints();
690 
691  // Substep the pressure boundary condition if using substepping
692  m_extrapolation->SubStepSetPressureBCs(inarray,aii_Dt,m_kinvis);
693 
694  // Set up forcing term for pressure Poisson equation
695  SetUpPressureForcing(inarray, m_F, aii_Dt);
696 
697  // Solve Pressure System
698  SolvePressure (m_F[0]);
699 
700  // Set up forcing term for Helmholtz problems
701  SetUpViscousForcing(inarray, m_F, aii_Dt);
702 
703  // Solve velocity system
704  SolveViscous( m_F, outarray, aii_Dt);
705 
706  // Apply flowrate correction
707  if (m_flowrate > 0.0 && m_greenFlux != numeric_limits<NekDouble>::max())
708  {
709  NekDouble currentFlux = MeasureFlowrate(outarray);
710  m_alpha = (m_flowrate - currentFlux) / m_greenFlux;
711 
712  for (int i = 0; i < m_spacedim; ++i)
713  {
714  Vmath::Svtvp(physTot, m_alpha, m_flowrateStokes[i], 1,
715  outarray[i], 1, outarray[i], 1);
716  }
717  }
718  }
719 
720  /**
721  * Forcing term for Poisson solver solver
722  */
724  const Array<OneD, const Array<OneD, NekDouble> > &fields,
726  const NekDouble aii_Dt)
727  {
728  int i;
729  int physTot = m_fields[0]->GetTotPoints();
730  int nvel = m_velocity.num_elements();
731 
732  m_fields[0]->PhysDeriv(eX,fields[0], Forcing[0]);
733 
734  for(i = 1; i < nvel; ++i)
735  {
736  // Use Forcing[1] as storage since it is not needed for the pressure
737  m_fields[i]->PhysDeriv(DirCartesianMap[i],fields[i],Forcing[1]);
738  Vmath::Vadd(physTot,Forcing[1],1,Forcing[0],1,Forcing[0],1);
739  }
740 
741  Vmath::Smul(physTot,1.0/aii_Dt,Forcing[0],1,Forcing[0],1);
742  }
743 
744  /**
745  * Forcing term for Helmholtz solver
746  */
748  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
750  const NekDouble aii_Dt)
751  {
752  NekDouble aii_dtinv = 1.0/aii_Dt;
753  int phystot = m_fields[0]->GetTotPoints();
754 
755  // Grad p
756  m_pressure->BwdTrans(m_pressure->GetCoeffs(),m_pressure->UpdatePhys());
757 
758  int nvel = m_velocity.num_elements();
759  if(nvel == 2)
760  {
761  m_pressure->PhysDeriv(m_pressure->GetPhys(),
762  Forcing[m_velocity[0]],
763  Forcing[m_velocity[1]]);
764  }
765  else
766  {
767  m_pressure->PhysDeriv(m_pressure->GetPhys(),
768  Forcing[m_velocity[0]],
769  Forcing[m_velocity[1]],
770  Forcing[m_velocity[2]]);
771  }
772 
773  // zero convective fields.
774  for(int i = nvel; i < m_nConvectiveFields; ++i)
775  {
776  Vmath::Zero(phystot,Forcing[i],1);
777  }
778 
779  // Subtract inarray/(aii_dt) and divide by kinvis. Kinvis will
780  // need to be updated for the convected fields.
781  for(int i = 0; i < m_nConvectiveFields; ++i)
782  {
783  Blas::Daxpy(phystot,-aii_dtinv,inarray[i],1,Forcing[i],1);
784  Blas::Dscal(phystot,1.0/m_diffCoeff[i],&(Forcing[i])[0],1);
785  }
786  }
787 
788 
789  /**
790  * Solve pressure system
791  */
794  {
796  // Setup coefficient for equation
797  factors[StdRegions::eFactorLambda] = 0.0;
798 
799  // Solver Pressure Poisson Equation
800  m_pressure->HelmSolve(Forcing, m_pressure->UpdateCoeffs(),
801  NullFlagList, factors);
802 
803  // Add presure to outflow bc if using convective like BCs
804  m_extrapolation->AddPressureToOutflowBCs(m_kinvis);
805  }
806 
807  /**
808  * Solve velocity system
809  */
811  const Array<OneD, const Array<OneD, NekDouble> > &Forcing,
812  Array<OneD, Array<OneD, NekDouble> > &outarray,
813  const NekDouble aii_Dt)
814  {
817  MultiRegions::VarFactorsMap varFactorsMap =
819 
820  AppendSVVFactors(factors,varFactorsMap);
821 
822  // Solve Helmholtz system and put in Physical space
823  for(int i = 0; i < m_nConvectiveFields; ++i)
824  {
825  // Setup coefficients for equation
826  factors[StdRegions::eFactorLambda] = 1.0/aii_Dt/m_diffCoeff[i];
827  m_fields[i]->HelmSolve(Forcing[i], m_fields[i]->UpdateCoeffs(),
828  NullFlagList, factors, varCoeffMap,
829  varFactorsMap);
830  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),outarray[i]);
831  }
832  }
833 
835  {
836 
837  m_session->MatchSolverInfo("SpectralVanishingViscosity",
838  "PowerKernel", m_useSpecVanVisc, false);
839 
840  if(m_useSpecVanVisc)
841  {
842  m_useHomo1DSpecVanVisc = true;
843  }
844  else
845  {
846  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP",
847  "PowerKernel", m_useSpecVanVisc, false);
848  }
849 
850  if(m_useSpecVanVisc)
851  {
852  m_IsSVVPowerKernel = true;
853  }
854  else
855  {
856  m_session->MatchSolverInfo("SpectralVanishingViscosity","DGKernel",
857  m_useSpecVanVisc, false);
858  if(m_useSpecVanVisc)
859  {
860  m_useHomo1DSpecVanVisc = true;
861  }
862  else
863  {
864  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP",
865  "DGKernel", m_useSpecVanVisc, false);
866  }
867 
868  if(m_useSpecVanVisc)
869  {
870  m_IsSVVPowerKernel = false;
871  }
872  }
873 
874  //set up varcoeff kernel if PowerKernel or DG is specified
875  if(m_useSpecVanVisc)
876  {
878  if(m_session->DefinesFunction("SVVVelocityMagnitude"))
879  {
880  if (m_comm->GetRank() == 0)
881  {
882  cout << "Seting up SVV velocity from "
883  "SVVVelocityMagnitude section in session file" << endl;
884  }
885  int nvel = m_velocity.num_elements();
886  int phystot = m_fields[0]->GetTotPoints();
887  SVVVelFields = Array<OneD, Array<OneD, NekDouble> >(nvel);
888  vector<string> vars;
889  for(int i = 0; i < nvel; ++i)
890  {
891  SVVVelFields[i] = Array<OneD, NekDouble>(phystot);
892  vars.push_back(m_session->GetVariable(m_velocity[i]));
893  }
894 
895  // Load up files into m_fields;
896  GetFunction("SVVVelocityMagnitude")
897  ->Evaluate(vars,SVVVelFields);
898  }
899 
901  SVVVarDiffCoeff(1.0,m_svvVarDiffCoeff,SVVVelFields);
902  m_session->LoadParameter("SVVDiffCoeff", m_sVVDiffCoeff, 1.0);
903  }
904  else
905  {
907  m_session->LoadParameter("SVVDiffCoeff", m_sVVDiffCoeff, 0.1);
908  }
909 
910  // Load parameters for Spectral Vanishing Viscosity
911  if(m_useSpecVanVisc == false)
912  {
913  m_session->MatchSolverInfo("SpectralVanishingViscosity","True",
914  m_useSpecVanVisc, false);
915  if(m_useSpecVanVisc == false)
916  {
917  m_session->MatchSolverInfo("SpectralVanishingViscosity","ExpKernel",
918  m_useSpecVanVisc, false);
919  }
921 
922  if(m_useSpecVanVisc == false)
923  {
924  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP","True",
925  m_useSpecVanVisc, false);
926  if(m_useSpecVanVisc == false)
927  {
928  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP","ExpKernel",
929  m_useSpecVanVisc, false);
930  }
931  }
932  }
933 
934 
935  // Case of only Homo1D kernel
936  if(m_session->DefinesSolverInfo("SpectralVanishingViscosityHomo1D"))
937  {
938  m_session->MatchSolverInfo("SpectralVanishingViscosityHomo1D",
939  "True", m_useHomo1DSpecVanVisc, false);
940  if(m_useHomo1DSpecVanVisc == false)
941  {
942  m_session->MatchSolverInfo("SpectralVanishingViscosityHomo1D",
943  "ExpKernel", m_useHomo1DSpecVanVisc, false);
944  }
945  }
946 
947  m_session->LoadParameter("SVVCutoffRatio",m_sVVCutoffRatio,0.75);
948  m_session->LoadParameter("SVVCutoffRatioHomo1D",m_sVVCutoffRatioHomo1D,m_sVVCutoffRatio);
949  m_session->LoadParameter("SVVDiffCoeffHomo1D", m_sVVDiffCoeffHomo1D, m_sVVDiffCoeff);
950 
952  {
954  "Expect to have three velocity fields with homogenous expansion");
955 
957  {
959  planes = m_fields[0]->GetZIDs();
960 
961  int num_planes = planes.num_elements();
962  Array<OneD, NekDouble> SVV(num_planes,0.0);
963  NekDouble fac;
964  int kmodes = m_fields[0]->GetHomogeneousBasis()->GetNumModes();
965  int pstart;
966 
967  pstart = m_sVVCutoffRatioHomo1D*kmodes;
968 
969  for(int n = 0; n < num_planes; ++n)
970  {
971  if(planes[n] > pstart)
972  {
973  fac = (NekDouble)((planes[n] - kmodes)*(planes[n] - kmodes))/
974  ((NekDouble)((planes[n] - pstart)*(planes[n] - pstart)));
975  SVV[n] = m_sVVDiffCoeffHomo1D*exp(-fac)/m_kinvis;
976  }
977  }
978 
979  for(int i = 0; i < m_velocity.num_elements(); ++i)
980  {
981  m_fields[m_velocity[i]]->SetHomo1DSpecVanVisc(SVV);
982  }
983  }
984  }
985 
986  }
987 
989  const NekDouble velmag,
990  Array<OneD, NekDouble> &diffcoeff,
991  const Array<OneD, Array<OneD, NekDouble> > &vel)
992  {
993  int phystot = m_fields[0]->GetTotPoints();
994  int nel = m_fields[0]->GetNumElmts();
995  int nvel,cnt;
996 
998 
999  Vmath::Fill(nel,velmag,diffcoeff,1);
1000 
1001  if(vel != NullNekDoubleArrayofArray)
1002  {
1003  Array<OneD, NekDouble> Velmag(phystot);
1004  nvel = vel.num_elements();
1005  // calculate magnitude of v
1006  Vmath::Vmul(phystot,vel[0],1,vel[0],1,Velmag,1);
1007  for(int n = 1; n < nvel; ++n)
1008  {
1009  Vmath::Vvtvp(phystot,vel[n],1,vel[n],1,Velmag,1,
1010  Velmag,1);
1011  }
1012  Vmath::Vsqrt(phystot,Velmag,1,Velmag,1);
1013 
1014 
1015  cnt = 0;
1017  // calculate mean value of vel mag.
1018  for(int i = 0; i < nel; ++i)
1019  {
1020  int nq = m_fields[0]->GetExp(i)->GetTotPoints();
1021  tmp = Velmag + cnt;
1022  diffcoeff[i] = m_fields[0]->GetExp(i)->Integral(tmp);
1023  Vmath::Fill(nq,1.0,tmp,1);
1024  NekDouble area = m_fields[0]->GetExp(i)->Integral(tmp);
1025  diffcoeff[i] = diffcoeff[i]/area;
1026  cnt += nq;
1027  }
1028  }
1029  else
1030  {
1031  nvel = m_expdim;
1032  }
1033 
1034  if(m_expdim == 3)
1035  {
1037  for (int e = 0; e < nel; e++)
1038  {
1039  exp3D = m_fields[0]->GetExp(e)->as<LocalRegions::Expansion3D>();
1040  NekDouble h = 0;
1041  for(int i = 0; i < exp3D->GetNedges(); ++i)
1042  {
1043 
1044  h = max(h, exp3D->GetGeom3D()->GetEdge(i)->GetVertex(0)->dist(
1045  *(exp3D->GetGeom3D()->GetEdge(i)->GetVertex(1))));
1046  }
1047 
1048  int p = 0;
1049  for(int i = 0; i < 3; ++i)
1050  {
1051  p = max(p,exp3D->GetBasisNumModes(i)-1);
1052  }
1053 
1054  diffcoeff[e] *= h/p;
1055  }
1056  }
1057  else
1058  {
1060  for (int e = 0; e < nel; e++)
1061  {
1062  exp2D = m_fields[0]->GetExp(e)->as<LocalRegions::Expansion2D>();
1063  NekDouble h = 0;
1064  for(int i = 0; i < exp2D->GetNedges(); ++i)
1065  {
1066 
1067  h = max(h, exp2D->GetGeom2D()->GetEdge(i)->GetVertex(0)->dist(
1068  *(exp2D->GetGeom2D()->GetEdge(i)->GetVertex(1))));
1069  }
1070 
1071  int p = 0;
1072  for(int i = 0; i < 2; ++i)
1073  {
1074  p = max(p,exp2D->GetBasisNumModes(i)-1);
1075  }
1076 
1077  diffcoeff[e] *= h/p;
1078  }
1079  }
1080  }
1081 
1083  StdRegions::ConstFactorMap &factors,
1084  MultiRegions::VarFactorsMap &varFactorsMap)
1085  {
1086 
1087  if(m_useSpecVanVisc)
1088  {
1092  {
1093  if(m_IsSVVPowerKernel)
1094  {
1097  }
1098  else
1099  {
1100  varFactorsMap[StdRegions::eFactorSVVDGKerDiffCoeff] =
1102  }
1103  }
1104  }
1105 
1106  }
1107 } //end of namespace
void SetupFlowrate(NekDouble aii_dt)
Set up the Stokes solution used to impose constant flowrate through a boundary.
NekDouble MeasureFlowrate(const Array< OneD, Array< OneD, NekDouble > > &inarray)
Measure the volumetric flow rate through the volumetric flow rate reference surface.
EquationType m_equationType
equation type;
virtual Array< OneD, bool > v_GetSystemSingularChecks()
virtual void v_DoInitialise(void)
Sets up initial conditions.
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:163
static VarFactorsMap NullVarFactorsMap
void SetBoundaryConditions(NekDouble time)
time dependent boundary conditions updating
Array< OneD, Array< OneD, NekDouble > > m_flowrateStokes
Stokes solution used to impose flowrate.
void EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
static Array< OneD, NekDouble > NullNekDouble1DArray
void SolveUnsteadyStokesSystem(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time, const NekDouble a_iixDt)
NekDouble m_time
Current time of simulation.
bool m_explicitDiffusion
Indicates if explicit or implicit treatment of diffusion is used.
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.cpp:411
NekDouble m_kinvis
Kinematic viscosity.
void DefineImplicitSolve(FuncPointerT func, ObjectPointerT obj)
void SolvePressure(const Array< OneD, NekDouble > &Forcing)
ExtrapolateFactory & GetExtrapolateFactory()
Definition: Extrapolate.cpp:49
NekDouble m_flowrate
Desired volumetric flowrate.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
NekDouble m_timestep
Time step size.
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
virtual void v_GenerateSummary(SolverUtils::SummaryList &s)
Print a summary of time stepping parameters.
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
std::shared_ptr< Extrapolate > ExtrapolateSharedPtr
Definition: Extrapolate.h:59
Array< OneD, int > m_velocity
int which identifies which components of m_fields contains the velocity (u,v,w);
bool m_useHomo1DSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
int m_expdim
Expansion dimension.
NekDouble m_sVVDiffCoeff
Diffusion coefficient of SVV modes.
bool m_IsSVVPowerKernel
Identifier for Power Kernel otherwise DG kernel.
ExtrapolateSharedPtr m_extrapolation
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector plus vector): z = alpha*x + y
Definition: Vmath.cpp:488
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:445
STL namespace.
virtual std::string v_GetSubSteppingExtrapolateStr(const std::string &instr)
virtual std::string v_GetExtrapolateStr(void)
void EvaluateAdvectionTerms(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray)
bool m_specHP_dealiasing
Flag to determine if dealisising is usde for the Spectral/hp element discretisation.
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:294
const char *const TimeIntegrationMethodMap[]
int m_nConvectiveFields
Number of fields to be convected;.
LibUtilities::CommSharedPtr m_comm
Communicator.
void SolveViscous(const Array< OneD, const Array< OneD, NekDouble > > &Forcing, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble aii_Dt)
void SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
MultiRegions::ExpListSharedPtr m_flowrateBnd
Flowrate reference surface.
NekDouble m_flowrateAiidt
Value of aii_dt used to compute Stokes flowrate solution.
virtual SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s)
Print a summary of time stepping parameters.
std::ofstream m_flowrateStream
Output stream to record flowrate.
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition: Expansion2D.h:49
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*y.
Definition: Vmath.cpp:216
virtual SOLVER_UTILS_EXPORT bool v_PostIntegrate(int step)
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
NekDouble m_flowrateArea
Area of the boundary through which we are measuring the flowrate.
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:264
std::vector< SolverUtils::ForcingSharedPtr > m_forcing
Forcing terms.
Base class for unsteady solvers.
virtual void v_SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
void SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
bool m_SmoothAdvection
bool to identify if advection term smoothing is requested
void AddSummaryItem(SummaryList &l, const std::string &name, const std::string &value)
Adds a summary item to the summary info list.
Definition: Misc.cpp:49
int m_spacedim
Spatial dimension (>= expansion dim).
virtual void v_TransCoeffToPhys(void)
Virtual function for transformation to physical space.
LibUtilities::FieldMetaDataMap m_fieldMetaDataMap
Map to identify relevant solver info to dump in output fields.
double NekDouble
virtual void v_SolvePressure(const Array< OneD, NekDouble > &Forcing)
Array< OneD, NekDouble > m_svvVarDiffCoeff
Array of coefficient if power kernel is used in SVV.
bool m_homogen_dealiasing
Flag to determine if dealiasing is used for homogeneous simulations.
EquationSystemFactory & GetEquationSystemFactory()
Array< OneD, Array< OneD, NekDouble > > m_F
void SVVVarDiffCoeff(const NekDouble velmag, Array< OneD, NekDouble > &diffcoeff, const Array< OneD, Array< OneD, NekDouble > > &vel=NullNekDoubleArrayofArray)
std::shared_ptr< Equation > EquationSharedPtr
Definition: Equation.h:131
SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(std::string name, const MultiRegions::ExpListSharedPtr &field=MultiRegions::NullExpListSharedPtr, bool cache=false)
Get a SessionFunction by name.
MultiRegions::Direction const DirCartesianMap[]
Definition: ExpList.h:88
virtual void v_SolveViscous(const Array< OneD, const Array< OneD, NekDouble > > &Forcing, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble aii_Dt)
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition: Blas.hpp:125
NekDouble m_sVVCutoffRatio
cutt off ratio from which to start decayhing modes
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
bool m_useSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
Array< OneD, NekDouble > m_diffCoeff
Diffusion coefficients (will be kinvis for velocities)
SOLVER_UTILS_EXPORT int GetNcoeffs()
int m_flowrateSteps
Interval at which to record flowrate data.
NekDouble m_sVVDiffCoeffHomo1D
Diffusion coefficient of SVV modes in homogeneous 1D Direction.
virtual void v_TransPhysToCoeff(void)
Virtual function for transformation to coefficient space.
LibUtilities::TimeIntegrationWrapperSharedPtr m_intScheme
Wrapper to the time integration scheme.
This class is the base class for Navier Stokes problems.
NekDouble m_alpha
Current flowrate correction.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
virtual void v_InitObject()
Init object for UnsteadySystem class.
MultiRegions::ExpListSharedPtr m_pressure
Pointer to field holding pressure field.
static Array< OneD, Array< OneD, NekDouble > > NullNekDoubleArrayofArray
NekDouble m_greenFlux
Flux of the Stokes function solution.
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:72
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:376
virtual void v_SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
void AppendSVVFactors(StdRegions::ConstFactorMap &factors, MultiRegions::VarFactorsMap &varFactorsMap)
static void Daxpy(const int &n, const double &alpha, const double *x, const int &incx, const double *y, const int &incy)
BLAS level 1: y = alpha x plus y.
Definition: Blas.hpp:110
virtual void v_InitObject()
Init object for UnsteadySystem class.
virtual void v_EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
int m_flowrateBndID
Boundary ID of the flowrate reference surface.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
virtual SOLVER_UTILS_EXPORT void v_DoInitialise()
Sets up initial conditions.
int m_planeID
Plane ID for cases with homogeneous expansion.
enum HomogeneousType m_HomogeneousType
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:302
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:186
static FlagList NullFlagList
An empty flag list.
static VarCoeffMap NullVarCoeffMap
Definition: StdRegions.hpp:265
std::map< StdRegions::ConstFactorType, Array< OneD, NekDouble > > VarFactorsMap