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.size()-1), "p"))
79  {
80  m_nConvectiveFields = m_fields.size()-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->SetForcing(m_forcing);
147  m_extrapolation->SubSteppingTimeIntegration(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.size(); ++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.size(); ++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
295  // set if they don't contain the appropriate boundary. To
296  // calculate the area, we integrate 1.0 over the boundary
297  // (which has been set up with the appropriate subcommunicator
298  // to avoid deadlock), and then communicate this to the other
299  // processors with an AllReduce.
300  if (m_flowrateBnd)
301  {
302  Array<OneD, NekDouble> inArea(m_flowrateBnd->GetNpoints(), 1.0);
303  m_flowrateArea = m_flowrateBnd->Integral(inArea);
304  }
306 
307  // In homogeneous case with forcing not aligned to the z-direction,
308  // redefine m_flowrateBnd so it is a 1D expansion
311  {
312  // For 3DH1D simulations with no force specified, find the mean
313  // (0th) plane.
314  Array<OneD, unsigned int> zIDs = m_fields[0]->GetZIDs();
315  m_planeID = -1;
316 
317  for (int i = 0; i < zIDs.size(); ++i)
318  {
319  if (zIDs[i] == 0)
320  {
321  m_planeID = i;
322  break;
323  }
324  }
325 
326  ASSERTL1(m_planeID <= 0, "Should be either at location 0 or -1 if not "
327  "found");
328 
329  if (m_planeID != -1)
330  {
332  ->GetBndCondExpansions()[m_flowrateBndID]
333  ->GetPlane(m_planeID);
334  }
335  }
336 
337  // Set up some storage for the Stokes solution (to be stored in
338  // m_flowrateStokes) and its initial condition (inTmp), which holds the
339  // unit forcing.
340  int nqTot = m_fields[0]->GetNpoints();
343 
344  for (int i = 0; i < m_spacedim; ++i)
345  {
346  inTmp[i] = Array<OneD, NekDouble>(
347  nqTot, flowrateForce[i] * aii_dt);
348  m_flowrateStokes[i] = Array<OneD, NekDouble>(nqTot, 0.0);
349 
351  {
352  Array<OneD, NekDouble> inTmp2(nqTot);
353  m_fields[i]->HomogeneousFwdTrans(inTmp[i], inTmp2);
354  m_fields[i]->SetWaveSpace(true);
355  inTmp[i] = inTmp2;
356  }
357 
358  Vmath::Zero(
359  m_fields[i]->GetNcoeffs(), m_fields[i]->UpdateCoeffs(), 1);
360  }
361 
362  // Create temporary extrapolation object to avoid issues with
363  // m_extrapolation for HOPBCs using higher order timestepping schemes.
364  // Zero pressure BCs in Neumann boundaries that may have been
365  // set in the advection step.
367  PBndConds = m_pressure->GetBndConditions();
369  PBndExp = m_pressure->GetBndCondExpansions();
370  for(int n = 0; n < PBndConds.size(); ++n)
371  {
372  if(PBndConds[n]->GetBoundaryConditionType() ==
374  {
375  Vmath::Zero(PBndExp[n]->GetNcoeffs(),
376  PBndExp[n]->UpdateCoeffs(),1);
377  }
378  }
379 
380  // Finally, calculate the solution and the flux of the Stokes
381  // solution. We set m_greenFlux to maximum numeric limit, which signals
382  // to SolveUnsteadyStokesSystem that we don't need to apply a flowrate
383  // force.
384  m_greenFlux = numeric_limits<NekDouble>::max();
385  m_flowrateAiidt = aii_dt;
386 
387  // Save the number of convective field in case it is not set
388  // to spacedim. Only need velocity components for stokes forcing
389  int SaveNConvectiveFields = m_nConvectiveFields;
391  SolveUnsteadyStokesSystem(inTmp, m_flowrateStokes, 0.0, aii_dt);
392  m_nConvectiveFields = SaveNConvectiveFields;
394 
395  // If the user specified IO_FlowSteps, open a handle to store output.
396  if (m_comm->GetRank() == 0 && m_flowrateSteps &&
397  !m_flowrateStream.is_open())
398  {
399  std::string filename = m_session->GetSessionName();
400  filename += ".prs";
401  m_flowrateStream.open(filename.c_str());
402  m_flowrateStream.setf(ios::scientific, ios::floatfield);
403  m_flowrateStream << "# step time dP" << endl
404  << "# -------------------------------------------"
405  << endl;
406  }
407 
408  // Replace pressure BCs with those evaluated from advection step
409  m_extrapolation->CopyPressureHBCsToPbndExp();
410  }
411 
412  /**
413  * @brief Measure the volumetric flow rate through the volumetric flow rate
414  * reference surface.
415  *
416  * This routine computes the volumetric flow rate
417  *
418  * \f[
419  * Q(\mathbf{u}) = \frac{1}{\mu(R)} \int_R \mathbf{u} \cdot d\mathbf{s}
420  * \f]
421  *
422  * through the boundary region \f$ R \f$.
423  */
425  const Array<OneD, Array<OneD, NekDouble> > &inarray)
426  {
427  NekDouble flowrate = 0.0;
428 
429  if (m_flowrateBnd && m_flowrateBndID >= 0)
430  {
431  // If we're an actual boundary, calculate the vector flux through
432  // the boundary.
434 
436  {
437  // General case
438  for (int i = 0; i < m_spacedim; ++i)
439  {
440  m_fields[i]->ExtractPhysToBnd(m_flowrateBndID, inarray[i],
441  boundary[i]);
442  }
443  flowrate = m_flowrateBnd->VectorFlux(boundary);
444  }
445  else if(m_planeID == 0)
446  {
447  //Homogeneous with forcing in plane. Calculate flux only on
448  // the meanmode - calculateFlux necessary for hybrid
449  // parallelisation.
450  for (int i = 0; i < m_spacedim; ++i)
451  {
452  m_fields[i]->GetPlane(m_planeID)->ExtractPhysToBnd(
453  m_flowrateBndID, inarray[i], boundary[i]);
454  }
455 
456  // the flowrate is calculated on the mean mode so it needs to be
457  // multiplied by LZ to be consistent with the general case.
458  flowrate = m_flowrateBnd->VectorFlux(boundary) *
459  m_session->GetParameter("LZ");
460  }
461  }
462  else if (m_flowrateBnd && !m_homd1DFlowinPlane)
463  {
464  // 3DH1D case with no Flowrate boundary defined: compute flux
465  // through the zero-th (mean) plane.
466  flowrate = m_flowrateBnd->Integral(inarray[2]);
467  }
468 
469  // Communication to obtain the total flowrate
471  {
472  m_comm->GetColumnComm()->AllReduce(flowrate, LibUtilities::ReduceSum);
473  }
474  else
475  {
476  m_comm->AllReduce(flowrate, LibUtilities::ReduceSum);
477  }
478  return flowrate / m_flowrateArea;
479  }
480 
482  {
483  if (m_flowrateSteps > 0)
484  {
485  if (m_comm->GetRank() == 0 && (step + 1) % m_flowrateSteps == 0)
486  {
487  m_flowrateStream << setw(8) << step << setw(16) << m_time
488  << setw(16) << m_alpha << endl;
489  }
490  }
491 
493  }
494 
495 
496  /**
497  * Destructor
498  */
500  {
501  }
502 
503  /**
504  *
505  */
507  {
510  "Splitting Scheme", "Velocity correction (strong press. form)");
511 
512  if( m_extrapolation->GetSubStepName().size() )
513  {
514  SolverUtils::AddSummaryItem( s, "Substepping",
515  m_extrapolation->GetSubStepName() );
516  }
517 
518  string dealias = m_homogen_dealiasing ? "Homogeneous1D" : "";
520  {
521  dealias += (dealias == "" ? "" : " + ") + string("spectral/hp");
522  }
523  if (dealias != "")
524  {
525  SolverUtils::AddSummaryItem(s, "Dealiasing", dealias);
526  }
527 
528 
529  string smoothing = m_useSpecVanVisc ? "spectral/hp" : "";
530  if (smoothing != "")
531  {
533  {
535  s, "Smoothing-SpecHP", "SVV (" + smoothing +
536  " Exp Kernel(cut-off = "
537  + boost::lexical_cast<string>(m_sVVCutoffRatio)
538  + ", diff coeff = "
539  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"))");
540  }
541  else
542  {
544  {
546  s, "Smoothing-SpecHP", "SVV (" + smoothing +
547  " Power Kernel (Power ratio ="
548  + boost::lexical_cast<string>(m_sVVCutoffRatio)
549  + ", diff coeff = "
550  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"*Uh/p))");
551  }
552  else
553  {
555  s, "Smoothing-SpecHP", "SVV (" + smoothing +
556  " DG Kernel (diff coeff = "
557  + boost::lexical_cast<string>(m_sVVDiffCoeff)+"*Uh/p))");
558 
559  }
560  }
561 
562  }
563 
565  {
567  s, "Smoothing-Homo1D", "SVV (Homogeneous1D - Exp Kernel(cut-off = "
568  + boost::lexical_cast<string>(m_sVVCutoffRatioHomo1D)
569  + ", diff coeff = "
570  + boost::lexical_cast<string>(m_sVVDiffCoeffHomo1D)+"))");
571  }
572 
573  }
574 
575  /**
576  *
577  */
579  {
581 
582  for (int i = 0; i < m_nConvectiveFields; ++i)
583  {
585  }
586 
587  m_flowrateAiidt = 0.0;
588 
590 
591  // Set up Field Meta Data for output files
592  m_fieldMetaDataMap["Kinvis"] =
593  boost::lexical_cast<std::string>(m_kinvis);
594  m_fieldMetaDataMap["TimeStep"] =
595  boost::lexical_cast<std::string>(m_timestep);
596 
597  // set boundary conditions here so that any normal component
598  // correction are imposed before they are imposed on initial
599  // field below
601 
602  // Ensure the initial conditions have correct BCs
603  for(int i = 0; i < m_fields.size(); ++i)
604  {
605  m_fields[i]->ImposeDirichletConditions(m_fields[i]->UpdateCoeffs());
606  m_fields[i]->LocalToGlobal();
607  m_fields[i]->GlobalToLocal();
608  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
609  m_fields[i]->UpdatePhys());
610  }
611  }
612 
613 
614  /**
615  *
616  */
618  {
619  int nfields = m_fields.size() - 1;
620  for (int k=0 ; k < nfields; ++k)
621  {
622  //Backward Transformation in physical space for time evolution
623  m_fields[k]->BwdTrans_IterPerExp(m_fields[k]->GetCoeffs(),
624  m_fields[k]->UpdatePhys());
625  }
626  }
627 
628  /**
629  *
630  */
632  {
633 
634  int nfields = m_fields.size() - 1;
635  for (int k=0 ; k < nfields; ++k)
636  {
637  //Forward Transformation in physical space for time evolution
638  m_fields[k]->FwdTrans_IterPerExp(m_fields[k]->GetPhys(),
639  m_fields[k]->UpdateCoeffs());
640  }
641  }
642 
643  /**
644  *
645  */
647  {
648  int vVar = m_session->GetVariables().size();
649  Array<OneD, bool> vChecks(vVar, false);
650  vChecks[vVar-1] = true;
651  return vChecks;
652  }
653 
654  /**
655  *
656  */
658  {
659  return m_session->GetVariables().size() - 1;
660  }
661 
662  /**
663  * Explicit part of the method - Advection, Forcing + HOPBCs
664  */
666  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
667  Array<OneD, Array<OneD, NekDouble> > &outarray,
668  const NekDouble time)
669  {
670 LibUtilities::Timer timer;
671 timer.Start();
672  EvaluateAdvectionTerms(inarray, outarray, time);
673 timer.Stop();
674 timer.AccumulateRegion("Advection Terms");
675 
676  // Smooth advection
678  {
679  for(int i = 0; i < m_nConvectiveFields; ++i)
680  {
681  m_pressure->SmoothField(outarray[i]);
682  }
683  }
684 
685  // Add forcing terms
686  for (auto &x : m_forcing)
687  {
688  x->Apply(m_fields, inarray, outarray, time);
689  }
690 
691  // Calculate High-Order pressure boundary conditions
692 timer.Start();
693  m_extrapolation->EvaluatePressureBCs(inarray,outarray,m_kinvis);
694 timer.Stop();
695 timer.AccumulateRegion("Pressure BCs");
696  }
697 
698  /**
699  * Implicit part of the method - Poisson + nConv*Helmholtz
700  */
702  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
703  Array<OneD, Array<OneD, NekDouble> > &outarray,
704  const NekDouble time,
705  const NekDouble aii_Dt)
706  {
707  // Set up flowrate if we're starting for the first time or the value of
708  // aii_Dt has changed.
709  if (m_flowrate > 0.0 && (aii_Dt != m_flowrateAiidt))
710  {
711  SetupFlowrate(aii_Dt);
712  }
713 
714  int physTot = m_fields[0]->GetTotPoints();
715 
716  // Substep the pressure boundary condition if using substepping
717  m_extrapolation->SubStepSetPressureBCs(inarray,aii_Dt,m_kinvis);
718 
719  // Set up forcing term for pressure Poisson equation
720 LibUtilities::Timer timer;
721 timer.Start();
722  SetUpPressureForcing(inarray, m_F, aii_Dt);
723 timer.Stop();
724 timer.AccumulateRegion("Pressure Forcing");
725 
726  // Solve Pressure System
727 timer.Start();
728  SolvePressure (m_F[0]);
729 timer.Stop();
730 timer.AccumulateRegion("Pressure Solve");
731 
732  // Set up forcing term for Helmholtz problems
733 timer.Start();
734  SetUpViscousForcing(inarray, m_F, aii_Dt);
735 timer.Stop();
736 timer.AccumulateRegion("Viscous Forcing");
737 
738  // Solve velocity system
739 timer.Start();
740  SolveViscous( m_F, outarray, aii_Dt);
741 timer.Stop();
742 timer.AccumulateRegion("Viscous Solve");
743 
744  // Apply flowrate correction
745  if (m_flowrate > 0.0 && m_greenFlux != numeric_limits<NekDouble>::max())
746  {
747  NekDouble currentFlux = MeasureFlowrate(outarray);
748  m_alpha = (m_flowrate - currentFlux) / m_greenFlux;
749 
750  for (int i = 0; i < m_spacedim; ++i)
751  {
752  Vmath::Svtvp(physTot, m_alpha, m_flowrateStokes[i], 1,
753  outarray[i], 1, outarray[i], 1);
754  //Enusre coeff space is updated for next time step
755  m_fields[i]->FwdTrans_IterPerExp(outarray[i],
756  m_fields[i]->UpdateCoeffs());
757  // Impsoe symmetry of flow on coeff space (good to enfore periodicity).
758  m_fields[i]->LocalToGlobal();
759  m_fields[i]->GlobalToLocal();
760  }
761  }
762  }
763 
764  /**
765  * Forcing term for Poisson solver solver
766  */
768  const Array<OneD, const Array<OneD, NekDouble> > &fields,
770  const NekDouble aii_Dt)
771  {
772  int i;
773  int physTot = m_fields[0]->GetTotPoints();
774  int nvel = m_velocity.size();
775 
776  m_fields[0]->PhysDeriv(eX,fields[0], Forcing[0]);
777 
778  for(i = 1; i < nvel; ++i)
779  {
780  // Use Forcing[1] as storage since it is not needed for the pressure
781  m_fields[i]->PhysDeriv(DirCartesianMap[i],fields[i],Forcing[1]);
782  Vmath::Vadd(physTot,Forcing[1],1,Forcing[0],1,Forcing[0],1);
783  }
784 
785  Vmath::Smul(physTot,1.0/aii_Dt,Forcing[0],1,Forcing[0],1);
786  }
787 
788  /**
789  * Forcing term for Helmholtz solver
790  */
792  const Array<OneD, const Array<OneD, NekDouble> > &inarray,
794  const NekDouble aii_Dt)
795  {
796  NekDouble aii_dtinv = 1.0/aii_Dt;
797  int phystot = m_fields[0]->GetTotPoints();
798 
799  // Grad p
800  m_pressure->BwdTrans(m_pressure->GetCoeffs(),m_pressure->UpdatePhys());
801 
802  int nvel = m_velocity.size();
803  if(nvel == 2)
804  {
805  m_pressure->PhysDeriv(m_pressure->GetPhys(),
806  Forcing[m_velocity[0]],
807  Forcing[m_velocity[1]]);
808  }
809  else
810  {
811  m_pressure->PhysDeriv(m_pressure->GetPhys(),
812  Forcing[m_velocity[0]],
813  Forcing[m_velocity[1]],
814  Forcing[m_velocity[2]]);
815  }
816 
817  // zero convective fields.
818  for(int i = nvel; i < m_nConvectiveFields; ++i)
819  {
820  Vmath::Zero(phystot,Forcing[i],1);
821  }
822 
823  // Subtract inarray/(aii_dt) and divide by kinvis. Kinvis will
824  // need to be updated for the convected fields.
825  for(int i = 0; i < m_nConvectiveFields; ++i)
826  {
827  Blas::Daxpy(phystot,-aii_dtinv,inarray[i],1,Forcing[i],1);
828  Blas::Dscal(phystot,1.0/m_diffCoeff[i],&(Forcing[i])[0],1);
829  }
830  }
831 
832 
833  /**
834  * Solve pressure system
835  */
838  {
840  // Setup coefficient for equation
841  factors[StdRegions::eFactorLambda] = 0.0;
842 
843  // Solver Pressure Poisson Equation
844  m_pressure->HelmSolve(Forcing, m_pressure->UpdateCoeffs(), factors);
845 
846  // Add presure to outflow bc if using convective like BCs
847  m_extrapolation->AddPressureToOutflowBCs(m_kinvis);
848  }
849 
850  /**
851  * Solve velocity system
852  */
854  const Array<OneD, const Array<OneD, NekDouble> > &Forcing,
855  Array<OneD, Array<OneD, NekDouble> > &outarray,
856  const NekDouble aii_Dt)
857  {
860  MultiRegions::VarFactorsMap varFactorsMap =
862 
863  AppendSVVFactors(factors,varFactorsMap);
864 
865  // Solve Helmholtz system and put in Physical space
866  for(int i = 0; i < m_nConvectiveFields; ++i)
867  {
868  // Setup coefficients for equation
869  factors[StdRegions::eFactorLambda] = 1.0/aii_Dt/m_diffCoeff[i];
870  m_fields[i]->HelmSolve(Forcing[i], m_fields[i]->UpdateCoeffs(),
871  factors, varCoeffMap,
872  varFactorsMap);
873  m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),outarray[i]);
874  }
875  }
876 
878  {
879 
880  m_session->MatchSolverInfo("SpectralVanishingViscosity",
881  "PowerKernel", m_useSpecVanVisc, false);
882 
883  if(m_useSpecVanVisc)
884  {
885  m_useHomo1DSpecVanVisc = true;
886  }
887  else
888  {
889  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP",
890  "PowerKernel", m_useSpecVanVisc, false);
891  }
892 
893  if(m_useSpecVanVisc)
894  {
895  m_IsSVVPowerKernel = true;
896  }
897  else
898  {
899  m_session->MatchSolverInfo("SpectralVanishingViscosity","DGKernel",
900  m_useSpecVanVisc, false);
901  if(m_useSpecVanVisc)
902  {
903  m_useHomo1DSpecVanVisc = true;
904  }
905  else
906  {
907  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP",
908  "DGKernel", m_useSpecVanVisc, false);
909  }
910 
911  if(m_useSpecVanVisc)
912  {
913  m_IsSVVPowerKernel = false;
914  }
915  }
916 
917  //set up varcoeff kernel if PowerKernel or DG is specified
918  if(m_useSpecVanVisc)
919  {
921  if(m_session->DefinesFunction("SVVVelocityMagnitude"))
922  {
923  if (m_comm->GetRank() == 0)
924  {
925  cout << "Seting up SVV velocity from "
926  "SVVVelocityMagnitude section in session file" << endl;
927  }
928  int nvel = m_velocity.size();
929  int phystot = m_fields[0]->GetTotPoints();
930  SVVVelFields = Array<OneD, Array<OneD, NekDouble> >(nvel);
931  vector<string> vars;
932  for(int i = 0; i < nvel; ++i)
933  {
934  SVVVelFields[i] = Array<OneD, NekDouble>(phystot);
935  vars.push_back(m_session->GetVariable(m_velocity[i]));
936  }
937 
938  // Load up files into m_fields;
939  GetFunction("SVVVelocityMagnitude")
940  ->Evaluate(vars,SVVVelFields);
941  }
942 
944  SVVVarDiffCoeff(1.0,m_svvVarDiffCoeff,SVVVelFields);
945  m_session->LoadParameter("SVVDiffCoeff", m_sVVDiffCoeff, 1.0);
946  }
947  else
948  {
950  m_session->LoadParameter("SVVDiffCoeff", m_sVVDiffCoeff, 0.1);
951  }
952 
953  // Load parameters for Spectral Vanishing Viscosity
954  if(m_useSpecVanVisc == false)
955  {
956  m_session->MatchSolverInfo("SpectralVanishingViscosity","True",
957  m_useSpecVanVisc, false);
958  if(m_useSpecVanVisc == false)
959  {
960  m_session->MatchSolverInfo("SpectralVanishingViscosity","ExpKernel",
961  m_useSpecVanVisc, false);
962  }
964 
965  if(m_useSpecVanVisc == false)
966  {
967  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP","True",
968  m_useSpecVanVisc, false);
969  if(m_useSpecVanVisc == false)
970  {
971  m_session->MatchSolverInfo("SpectralVanishingViscositySpectralHP","ExpKernel",
972  m_useSpecVanVisc, false);
973  }
974  }
975  }
976 
977 
978  // Case of only Homo1D kernel
979  if(m_session->DefinesSolverInfo("SpectralVanishingViscosityHomo1D"))
980  {
981  m_session->MatchSolverInfo("SpectralVanishingViscosityHomo1D",
982  "True", m_useHomo1DSpecVanVisc, false);
983  if(m_useHomo1DSpecVanVisc == false)
984  {
985  m_session->MatchSolverInfo("SpectralVanishingViscosityHomo1D",
986  "ExpKernel", m_useHomo1DSpecVanVisc, false);
987  }
988  }
989 
990  m_session->LoadParameter("SVVCutoffRatio",m_sVVCutoffRatio,0.75);
991  m_session->LoadParameter("SVVCutoffRatioHomo1D",m_sVVCutoffRatioHomo1D,m_sVVCutoffRatio);
992  m_session->LoadParameter("SVVDiffCoeffHomo1D", m_sVVDiffCoeffHomo1D, m_sVVDiffCoeff);
993 
995  {
997  "Expect to have three velocity fields with homogenous expansion");
998 
1000  {
1002  planes = m_fields[0]->GetZIDs();
1003 
1004  int num_planes = planes.size();
1005  Array<OneD, NekDouble> SVV(num_planes,0.0);
1006  NekDouble fac;
1007  int kmodes = m_fields[0]->GetHomogeneousBasis()->GetNumModes();
1008  int pstart;
1009 
1010  pstart = m_sVVCutoffRatioHomo1D*kmodes;
1011 
1012  for(int n = 0; n < num_planes; ++n)
1013  {
1014  if(planes[n] > pstart)
1015  {
1016  fac = (NekDouble)((planes[n] - kmodes)*(planes[n] - kmodes))/
1017  ((NekDouble)((planes[n] - pstart)*(planes[n] - pstart)));
1018  SVV[n] = m_sVVDiffCoeffHomo1D*exp(-fac)/m_kinvis;
1019  }
1020  }
1021 
1022  for(int i = 0; i < m_velocity.size(); ++i)
1023  {
1024  m_fields[m_velocity[i]]->SetHomo1DSpecVanVisc(SVV);
1025  }
1026  }
1027  }
1028 
1029  }
1030 
1032  const NekDouble velmag,
1033  Array<OneD, NekDouble> &diffcoeff,
1034  const Array<OneD, Array<OneD, NekDouble> > &vel)
1035  {
1036  int phystot = m_fields[0]->GetTotPoints();
1037  int nel = m_fields[0]->GetNumElmts();
1038  int nvel,cnt;
1039 
1041 
1042  Vmath::Fill(nel,velmag,diffcoeff,1);
1043 
1044  if(vel != NullNekDoubleArrayOfArray)
1045  {
1046  Array<OneD, NekDouble> Velmag(phystot);
1047  nvel = vel.size();
1048  // calculate magnitude of v
1049  Vmath::Vmul(phystot,vel[0],1,vel[0],1,Velmag,1);
1050  for(int n = 1; n < nvel; ++n)
1051  {
1052  Vmath::Vvtvp(phystot,vel[n],1,vel[n],1,Velmag,1,
1053  Velmag,1);
1054  }
1055  Vmath::Vsqrt(phystot,Velmag,1,Velmag,1);
1056 
1057 
1058  cnt = 0;
1060  // calculate mean value of vel mag.
1061  for(int i = 0; i < nel; ++i)
1062  {
1063  int nq = m_fields[0]->GetExp(i)->GetTotPoints();
1064  tmp = Velmag + cnt;
1065  diffcoeff[i] = m_fields[0]->GetExp(i)->Integral(tmp);
1066  Vmath::Fill(nq,1.0,tmp,1);
1067  NekDouble area = m_fields[0]->GetExp(i)->Integral(tmp);
1068  diffcoeff[i] = diffcoeff[i]/area;
1069  cnt += nq;
1070  }
1071  }
1072  else
1073  {
1074  nvel = m_expdim;
1075  }
1076 
1077 
1078  for (int e = 0; e < nel; e++)
1079  {
1080  LocalRegions::ExpansionSharedPtr exp = m_fields[0]->GetExp(e);
1081  NekDouble h = 0;
1082 
1083  // Find maximum length of edge.
1084  for(int i = 0; i < exp->GetGeom()->GetNumEdges(); ++i)
1085  {
1086  h = max(h, exp->GetGeom()->GetEdge(i)->GetVertex(0)->dist
1087  (*(exp->GetGeom()->GetEdge(i)->GetVertex(1))));
1088  }
1089 
1090  int p = 0;
1091  for(int i = 0; i < m_expdim; ++i)
1092  {
1093  p = max(p,exp->GetBasisNumModes(i)-1);
1094  }
1095 
1096  diffcoeff[e] *= h/p;
1097  }
1098  }
1099 
1101  StdRegions::ConstFactorMap &factors,
1102  MultiRegions::VarFactorsMap &varFactorsMap)
1103  {
1104 
1105  if(m_useSpecVanVisc)
1106  {
1110  {
1111  if(m_IsSVVPowerKernel)
1112  {
1115  }
1116  else
1117  {
1118  varFactorsMap[StdRegions::eFactorSVVDGKerDiffCoeff] =
1120  }
1121  }
1122  }
1123 
1124  }
1125 } //end of namespace
#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
This class is the base class for Navier Stokes problems.
virtual void v_InitObject()
Init object for UnsteadySystem class.
void SetBoundaryConditions(NekDouble time)
time dependent boundary conditions updating
MultiRegions::ExpListSharedPtr m_pressure
Pointer to field holding pressure field.
NekDouble m_kinvis
Kinematic viscosity.
bool m_SmoothAdvection
bool to identify if advection term smoothing is requested
ExtrapolateSharedPtr m_extrapolation
Array< OneD, int > m_velocity
int which identifies which components of m_fields contains the velocity (u,v,w);
EquationType m_equationType
equation type;
int m_nConvectiveFields
Number of fields to be convected;.
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)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:200
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
void DefineImplicitSolve(FuncPointerT func, ObjectPointerT obj)
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:67
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
virtual SOLVER_UTILS_EXPORT bool v_PostIntegrate(int step)
int m_spacedim
Spatial dimension (>= expansion dim).
int m_expdim
Expansion dimension.
LibUtilities::CommSharedPtr m_comm
Communicator.
NekDouble m_timestep
Time step size.
NekDouble m_time
Current time of simulation.
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
bool m_specHP_dealiasing
Flag to determine if dealisising is usde for the Spectral/hp element discretisation.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
enum HomogeneousType m_HomogeneousType
bool m_homogen_dealiasing
Flag to determine if dealiasing is used for homogeneous simulations.
SOLVER_UTILS_EXPORT int GetNcoeffs()
LibUtilities::FieldMetaDataMap m_fieldMetaDataMap
Map to identify relevant solver info to dump in output fields.
SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(std::string name, const MultiRegions::ExpListSharedPtr &field=MultiRegions::NullExpListSharedPtr, bool cache=false)
Get a SessionFunction by name.
SOLVER_UTILS_EXPORT int GetTotPoints()
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:73
Base class for unsteady solvers.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
virtual SOLVER_UTILS_EXPORT void v_DoInitialise()
Sets up initial conditions.
LibUtilities::TimeIntegrationSchemeSharedPtr m_intScheme
Wrapper to the time integration scheme.
bool m_explicitDiffusion
Indicates if explicit or implicit treatment of diffusion is used.
virtual SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s)
Print a summary of time stepping parameters.
NekDouble m_greenFlux
Flux of the Stokes function solution.
virtual std::string v_GetExtrapolateStr(void)
MultiRegions::ExpListSharedPtr m_flowrateBnd
Flowrate reference surface.
Array< OneD, NekDouble > m_svvVarDiffCoeff
Array of coefficient if power kernel is used in SVV.
NekDouble MeasureFlowrate(const Array< OneD, Array< OneD, NekDouble > > &inarray)
Measure the volumetric flow rate through the volumetric flow rate reference surface.
NekDouble m_sVVDiffCoeffHomo1D
Diffusion coefficient of SVV modes in homogeneous 1D Direction.
virtual void v_InitObject()
Init object for UnsteadySystem class.
NekDouble m_flowrate
Desired volumetric flowrate.
bool m_IsSVVPowerKernel
Identifier for Power Kernel otherwise DG kernel.
virtual void v_GenerateSummary(SolverUtils::SummaryList &s)
Print a summary of time stepping parameters.
virtual void v_SolveViscous(const Array< OneD, const Array< OneD, NekDouble > > &Forcing, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble aii_Dt)
virtual void v_DoInitialise(void)
Sets up initial conditions.
NekDouble m_sVVCutoffRatio
cutt off ratio from which to start decayhing modes
NekDouble m_sVVDiffCoeff
Diffusion coefficient of SVV modes.
void EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Array< OneD, Array< OneD, NekDouble > > m_flowrateStokes
Stokes solution used to impose flowrate.
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_alpha
Current flowrate correction.
virtual Array< OneD, bool > v_GetSystemSingularChecks()
virtual void v_TransPhysToCoeff(void)
Virtual function for transformation to coefficient space.
Array< OneD, Array< OneD, NekDouble > > m_F
virtual void v_SolvePressure(const Array< OneD, NekDouble > &Forcing)
virtual void v_TransCoeffToPhys(void)
Virtual function for transformation to physical space.
void SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
void SetupFlowrate(NekDouble aii_dt)
Set up the Stokes solution used to impose constant flowrate through a boundary.
void SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
virtual void v_SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
bool m_useSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
void SolveViscous(const Array< OneD, const Array< OneD, NekDouble > > &Forcing, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble aii_Dt)
Array< OneD, NekDouble > m_diffCoeff
Diffusion coefficients (will be kinvis for velocities)
int m_flowrateSteps
Interval at which to record flowrate data.
void SVVVarDiffCoeff(const NekDouble velmag, Array< OneD, NekDouble > &diffcoeff, const Array< OneD, Array< OneD, NekDouble > > &vel=NullNekDoubleArrayOfArray)
NekDouble m_flowrateArea
Area of the boundary through which we are measuring the flowrate.
std::ofstream m_flowrateStream
Output stream to record flowrate.
virtual void v_SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt)
virtual void v_EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
void AppendSVVFactors(StdRegions::ConstFactorMap &factors, MultiRegions::VarFactorsMap &varFactorsMap)
NekDouble m_flowrateAiidt
Value of aii_dt used to compute Stokes flowrate solution.
void SolvePressure(const Array< OneD, NekDouble > &Forcing)
int m_planeID
Plane ID for cases with homogeneous expansion.
bool m_useHomo1DSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
int m_flowrateBndID
Boundary ID of the flowrate reference surface.
virtual std::string v_GetSubSteppingExtrapolateStr(const std::string &instr)
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition: Blas.hpp:182
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:167
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Equation > EquationSharedPtr
Definition: Equation.h:131
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
MultiRegions::Direction const DirCartesianMap[]
Definition: ExpList.h:90
static VarFactorsMap NullVarFactorsMap
std::map< StdRegions::ConstFactorType, Array< OneD, NekDouble > > VarFactorsMap
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
EquationSystemFactory & GetEquationSystemFactory()
void AddSummaryItem(SummaryList &l, const std::string &name, const std::string &value)
Adds a summary item to the summary info list.
Definition: Misc.cpp:47
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:272
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:314
static VarCoeffMap NullVarCoeffMap
Definition: StdRegions.hpp:273
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
@ eUnsteadyStokes
@ eUnsteadyNavierStokes
static Array< OneD, Array< OneD, NekDouble > > NullNekDoubleArrayOfArray
ExtrapolateFactory & GetExtrapolateFactory()
Definition: Extrapolate.cpp:49
static Array< OneD, NekDouble > NullNekDouble1DArray
double NekDouble
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition: Vmath.cpp:475
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 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:565
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 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:322
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 Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:436
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45