Nektar++
VelocityCorrectionSchemeImplicit.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File VelocityCorrectionSchemeImplicit.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: Implicit Velocity Correction Scheme for the Incompressible
32// Navier Stokes equations based on Dong and Shen 2010
33///////////////////////////////////////////////////////////////////////////////
34
38
39#include <boost/algorithm/string.hpp>
40
41using namespace std;
42
43namespace Nektar
44{
45using namespace MultiRegions;
46
49 "VCSImplicit", VCSImplicit::create);
50
52 LibUtilities::SessionReader::RegisterEnumValue("SolverType", "VCSImplicit",
54
55/**
56 * Constructor. No special instructions here.
57 * v_DoInitialise sets the scheme up.
58 *
59 * \param
60 * \param
61 */
64 : UnsteadySystem(pSession, pGraph),
65 VelocityCorrectionScheme(pSession, pGraph)
66{
67}
68
69/**
70 * Destructor
71 */
73{
74}
75
76/**
77 *
78 */
80{
82 SolverUtils::AddSummaryItem(s, "Splitting Scheme",
83 "Implicit velocity correction");
84
85 if (m_extrapolation->GetSubStepName().size())
86 {
87 SolverUtils::AddSummaryItem(s, "Substepping",
88 m_extrapolation->GetSubStepName());
89 }
90
91 string dealias = m_homogen_dealiasing ? "Homogeneous1D" : "";
93 {
94 dealias += (dealias == "" ? "" : " + ") + string("spectral/hp");
95 }
96 if (dealias != "")
97 {
98 SolverUtils::AddSummaryItem(s, "Dealiasing", dealias);
99 }
100
101 string smoothing = m_useSpecVanVisc ? "spectral/hp" : "";
102 if (smoothing != "")
103 {
105 {
107 s, "Smoothing-SpecHP",
108 "SVV (" + smoothing + " Exp Kernel(cut-off = " +
109 boost::lexical_cast<string>(m_sVVCutoffRatio) +
110 ", diff coeff = " +
111 boost::lexical_cast<string>(m_sVVDiffCoeff) + "))");
112 }
113 else
114 {
116 {
118 s, "Smoothing-SpecHP",
119 "SVV (" + smoothing + " Power Kernel (Power ratio =" +
120 boost::lexical_cast<string>(m_sVVCutoffRatio) +
121 ", diff coeff = " +
122 boost::lexical_cast<string>(m_sVVDiffCoeff) +
123 "*Uh/p))");
124 }
125 else
126 {
128 s, "Smoothing-SpecHP",
129 "SVV (" + smoothing + " DG Kernel (diff coeff = " +
130 boost::lexical_cast<string>(m_sVVDiffCoeff) +
131 "*Uh/p))");
132 }
133 }
134 }
135
137 {
139 s, "Smoothing-Homo1D",
140 "SVV (Homogeneous1D - Exp Kernel(cut-off = " +
141 boost::lexical_cast<string>(m_sVVCutoffRatioHomo1D) +
142 ", diff coeff = " +
143 boost::lexical_cast<string>(m_sVVDiffCoeffHomo1D) + "))");
144 }
145
147 {
149 s, "GJP Stab. Impl. ",
150 m_session->GetSolverInfo("GJPStabilisation"));
151 SolverUtils::AddSummaryItem(s, "GJP Stab. JumpScale", m_GJPJumpScale);
152
153 if (boost::iequals(m_session->GetSolverInfo("GJPStabilisation"),
154 "Explicit"))
155 {
157 s, "GJP Normal Velocity",
158 m_session->GetSolverInfo("GJPNormalVelocity"));
159 }
160 }
161}
162
163/**
164 *
165 */
166void VCSImplicit::v_DoInitialise(bool dumpInitialConditions)
167{
168 VelocityCorrectionScheme::v_DoInitialise(dumpInitialConditions);
169
170 // Initialise Advection velocity
172 for (int i = 0; i < m_velocity.size(); i++)
173 {
175 }
176}
177
178/**
179 * Computes the forcing term for the pressure solve in
180 * VCSImplicit::v_SolvePressure(). It uses the weak pressure forcing similar to
181 * VCSWeakPressure (coefficient space).
182 *
183 * @param fields Holds the BDF formula of previous solutions \f$\sum_q
184 * \frac{\alpha_q}{\gamma} [u^{n-q}, v^{n-q}, \ldots]\f$.
185 * @param Forcing Array for the forcing term of the pressure solve. May
186 * contain temporary values on input. On output, Forcing = \f$ \int_\Omega
187 * \nabla \phi \cdot \left( \frac{1}{\Delta t} \sum_q \alpha_q \mathbf{u}^{n-q}
188 * + \mathbf{f}^{n+1} - N(\mathbf{u})^n \right) \f$.
189 *
190 */
192 const Array<OneD, const Array<OneD, NekDouble>> &fields,
194{
195 int ncoeffs = m_pressure->GetNcoeffs();
196
197 // Evaluate Advection -N(u)^n
198 int phystot = m_fields[0]->GetTotPoints();
199 int nvel = m_velocity.size();
200 Array<OneD, Array<OneD, NekDouble>> velocity(nvel), advection(nvel);
201 for (int i = 0; i < nvel; i++)
202 {
203 velocity[i] = Array<OneD, NekDouble>(phystot, 0.0);
204 advection[i] = Array<OneD, NekDouble>(phystot, 0.0);
205 }
206
207 // Get velocity fields u^n
208 for (int i = 0; i < nvel; i++)
209 {
210 velocity[i] = m_fields[i]->GetPhys();
211 }
212
213 // Get -N(u^n)
214 EvaluateAdvectionTerms(velocity, advection, m_time);
215
216 // Add 1/dt \sum_q \alpha_q u^{n-q} - N(u^n)
217 for (int i = 0; i < nvel; i++)
218 {
219 Vmath::Svtvp(phystot, 1.0 / aii_Dt, fields[i], 1, advection[i], 1,
220 advection[i], 1);
221 }
222
223 // Add forcing terms
224 for (auto &x : m_forcing)
225 {
226 x->Apply(m_fields, advection, advection, m_time);
227 }
228
229 // Do Innerproduct with derivative base
230 m_pressure->IProductWRTDerivBase(advection, Forcing[0]);
231
232 // Negate to reverse negation in HelmSolve
233 Vmath::Neg(ncoeffs, Forcing[0], 1);
234}
235
236/**
237 * Computes the forcing term and advection velocity for ADR solves.
238 *
239 * @param inarray Holds the BDF formula of previous solutions \f$\sum_q
240 \frac{\alpha_q}{\gamma} [u^{n-q}, v^{n-q}, \ldots]\f$.
241 * @param Forcing Shared forcing array m_F. Used in pressure and velocity
242 solve. On input, holds temporary values from pressure solve. On output: Forcing
243 = \f$ - \frac{1}{\nu} \left( \frac{1}{\Delta t} \sum_q \alpha_q
244 \mathbf{u}^{n-q} - \nabla p^{n+1} + \mathbf{f}^{n+1} \right) \f$.
245
246 * @param aii_Dt \f$\frac{\Delta t}{\gamma}\f$.
247 *
248 * Additionally, the advection velocity \f$ \tilde{\mathbf{u}}^{n+1} \f$ is
249 computed and handed to the velocity solve via the array m_AdvVel. It is
250 computed as \f$ \tilde{\mathbf{u}}^{n+1} = \sum_q \frac{\alpha_q}{\gamma}
251 \mathbf{u}^{n-q} - \frac{\Delta t}{\gamma} \left[ \nabla p^{n+1} -
252 N(\mathbf{u})^n - \nu \nabla \times \omega^n + \mathbf{f}^{n+1} \right] \f$.
253 *
254 */
256 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
258{
259 int phystot = m_fields[0]->GetTotPoints();
260 int nvel = m_velocity.size();
261
262 // Update pressure to n+1
263 m_pressure->BwdTrans(m_pressure->GetCoeffs(), m_pressure->UpdatePhys());
264
265 // Compute gradient \nabla p^{n+1}
266 if (nvel == 2)
267 {
268 m_pressure->PhysDeriv(m_pressure->GetPhys(), Forcing[m_velocity[0]],
269 Forcing[m_velocity[1]]);
270 }
271 else
272 {
273 m_pressure->PhysDeriv(m_pressure->GetPhys(), Forcing[m_velocity[0]],
275 }
276
277 // Zero convective fields
278 for (int i = nvel; i < m_nConvectiveFields; ++i)
279 {
280 Vmath::Zero(phystot, Forcing[i], 1);
281 }
282
283 // Get velocity fields and evaluate advection
284 Array<OneD, Array<OneD, NekDouble>> velocity(nvel), advection(nvel);
285 for (int i = 0; i < nvel; i++)
286 {
287 velocity[i] = Array<OneD, NekDouble>(phystot, 0.0);
288 advection[i] = Array<OneD, NekDouble>(phystot, 0.0);
289 }
290
291 // Velocity [u^n, v^n, ..]
292 for (int i = 0; i < nvel; i++)
293 {
294 velocity[i] = m_fields[i]->GetPhys();
295 }
296
297 // Advection [-N(u)^n, ..]
298 EvaluateAdvectionTerms(velocity, advection, m_time);
299
300 // Curl of vorticity \nabla \times \nabla \times [u^n, v^n, ..]
301 m_fields[0]->CurlCurl(velocity, velocity);
302
303 // Negate pressure gradient
304 for (int i = 0; i < nvel; ++i)
305 {
306 Vmath::Neg(phystot, Forcing[i], 1); // -1 * \nabla p
307 }
308
309 // Add forcing terms
310 for (auto &x : m_forcing)
311 {
312 x->Apply(m_fields, Forcing, Forcing, m_time); // += f^{n+1}
313 }
314
315 // Build Forcing term and Advection Velocity
316 for (int i = 0; i < nvel; ++i)
317 {
318 /// Advection Velocity
319 Vmath::Svtvp(phystot, aii_Dt, Forcing[i], 1, inarray[i], 1, m_AdvVel[i],
320 1); // \frac{\Delta t}{\gamma}(-\nabla p + f) + inarray
321 Vmath::Svtvp(phystot, aii_Dt, advection[i], 1, m_AdvVel[i], 1,
322 m_AdvVel[i],
323 1); // += \frac{\Delta t}{\gamma} -N(u)
324 Vmath::Svtvp(phystot, -aii_Dt * m_diffCoeff[i], velocity[i], 1,
325 m_AdvVel[i], 1, m_AdvVel[i],
326 1); // += -\frac{\Delta t}{\gamma} CurlCurl(u)
327 Vmath::Smul(phystot, 1.0 / m_diffCoeff[i], m_AdvVel[i], 1, m_AdvVel[i],
328 1); // *= 1/\nu
329
330 /// Forcing
331 Vmath::Svtvp(phystot, 1.0 / aii_Dt, inarray[i], 1, Forcing[i], 1,
332 Forcing[i],
333 1); // \frac{\gamma}{\Delta t} * inarray - \nabla p + f
334 Vmath::Smul(phystot, -1.0 / m_diffCoeff[i], Forcing[i], 1, Forcing[i],
335 1); // *= -1/kinvis
336 }
337}
338
339/**
340 * Solve pressure system via a Poisson problem with ContField::HelmSolve().
341 * Uses coefficient space forcing and hence sets the
342 * argument PhysSpaceForcing=false in ContFieldHelmSolve().
343 *
344 * @param Forcing See output description in
345 * VCSImplicit::v_SetUpPressureForcing().
346 *
347 */
349{
351 // Setup coefficient for equation, Lambda = 0 ensures Poisson instead of
352 // Helmholtz problem
354
355 // Solve Pressure Poisson Equation (with Weak Forcing)
356 m_pressure->HelmSolve(Forcing, m_pressure->UpdateCoeffs(), factors,
359 false);
360
361 // Add presure to outflow bc if using convective like BCs
362 // TODO Check HO outflow BCs with Implicit scheme
363 m_extrapolation->AddPressureToOutflowBCs(m_kinvis);
364}
365
366/**
367 * Solve velocity system via the
368 * ContField::LinearAdvectionDiffusionReactionSolve().
369 *
370 * @param Forcing Holds the forcing term for each velocity component. See output
371 * description in VCSImplicit::v_SetUpViscousForcing().
372 * @param inarray Unused in this routine. Still, holds \f$\sum_q
373 * \frac{\alpha_q}{\gamma} [u^{n-q}, v^{n-q}, \ldots] \f$.
374 * @param outarray Holds vector of previous solution \f$ [u^n, v^n, \ldots] \f$.
375 * Overwritten upon output with new solution [u^{n+1}, v^{n+1}, \ldots].
376 *
377 * Additionally, the advection velocity \f$ \tilde{\mathbf{u}}^{n+1} \f$ is
378 * handed to the velocity solve via the array m_AdvVel. It is computed in
379 * VCSImplicit::v_SetUpViscousForcing(). It is defined as \f$
380 * \tilde{\mathbf{u}}^{n+1} = \sum_q \frac{\alpha_q}{\gamma} \mathbf{u}^{n-q} -
381 * \frac{\Delta t}{\gamma} \left[ \nabla p^{n+1} - N(\mathbf{u})^n - \nu \nabla
382 * \times \omega^n + \mathbf{f}^{n+1} \right] \f$.
383 *
384 */
387 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
388 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble aii_Dt)
389{
391 StdRegions::VarCoeffMap varcoeffs;
393
394 AppendSVVFactors(factors, varfactors);
395 ComputeGJPNormalVelocity(inarray, varcoeffs);
396
397 // Set advection velocities
401 for (int i = 0; i < m_velocity.size(); i++)
402 {
403 varcoeffs[varcoefftypes[i]] = m_AdvVel[i];
404 }
405
406 // Solve Advection-Diffusion-Reaction system
407 for (int i = 0; i < m_nConvectiveFields; ++i)
408 {
409 // Add diffusion coefficient to GJP matrix operator (Implicit part)
411 {
413 }
414
415 // \lambda = - /frac{\gamma}{\Delta t \nu}
416 factors[StdRegions::eFactorLambda] = -1.0 / aii_Dt / m_diffCoeff[i];
417
418 auto gkey = m_fields[i]->LinearAdvectionDiffusionReactionSolve(
419 Forcing[i], m_fields[i]->UpdateCoeffs(), factors, varcoeffs,
420 varfactors);
421
422 // Nuke GlobalLinSys, avoids memory leak under condition:
423 // Remove after last velocity solve (w-velocity in 3D,
424 // assumes same matrix for each velocity)
425 // Also, catches Null return from 3DH1D solve by checking matrix type
426 // is an ADR matrix (variant)
427 if (i == m_nConvectiveFields - 1 &&
428 (gkey.GetMatrixType() ==
430 gkey.GetMatrixType() ==
432
433 {
434 m_fields[i]->UnsetGlobalLinSys(gkey, true);
435 }
436
437 // Transform solution to PhysSpace
438 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(), outarray[i]);
439 }
440}
441
442/**
443 * Explicit part of the method - HOPBCs based on VCSWeakPressure.
444 * For the implicit scheme, we do not extrapolate the advection and rotational
445 * diffusion terms, see also S. Dong and J. Shen (2010).
446 *
447 * @param inarray Holds the vector of previous solutions \f$ [u^n, v^n, \ldots]
448 * \f$.
449 * @param outarray In the implicit scheme, currently an empty array. TODO Don't
450 * waste memory here.
451 * @param time Holds the new time \f$ t^{n+1} = (n+1) \Delta t \f$.
452 *
453 */
455 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
456 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
457{
458 boost::ignore_unused(time); // Not required without advection terms
459
460 // Zero RHS derivatives, avoids undefined values
461 for (int i = 0; i < m_velocity.size(); ++i)
462 {
463 Vmath::Zero(outarray[i].size(), outarray[i], 1);
464 }
465
466 // Calculate High-Order pressure boundary conditions
468 timer.Start();
469 m_extrapolation->EvaluatePressureBCs(inarray, outarray, m_kinvis);
470 timer.Stop();
471 timer.AccumulateRegion("Pressure BCs");
472}
473
474} // namespace Nektar
MultiRegions::ExpListSharedPtr m_pressure
Pointer to field holding pressure field.
NekDouble m_kinvis
Kinematic viscosity.
ExtrapolateSharedPtr m_extrapolation
Array< OneD, int > m_velocity
int which identifies which components of m_fields contains the velocity (u,v,w);
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:198
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition: Timer.cpp:72
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 GetTotPoints()
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:73
Base class for unsteady solvers.
virtual SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s) override
Print a summary of time stepping parameters.
virtual void v_SolveViscous(const Array< OneD, const Array< OneD, NekDouble > > &Forcing, const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble aii_Dt) override
virtual void v_EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time) override
virtual void v_SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt) override
virtual void v_GenerateSummary(SolverUtils::SummaryList &s) override
Print a summary of time stepping parameters.
Array< OneD, Array< OneD, NekDouble > > m_AdvVel
virtual void v_DoInitialise(bool dumpInitialConditions) override
Sets up initial conditions.
VCSImplicit(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Constructor.
static std::string className
Name of class.
virtual void v_SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt) override
static SolverUtils::EquationSystemSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
virtual void v_SolvePressure(const Array< OneD, NekDouble > &Forcing) override
Array< OneD, NekDouble > m_svvVarDiffCoeff
Array of coefficient if power kernel is used in SVV.
NekDouble m_sVVDiffCoeffHomo1D
Diffusion coefficient of SVV modes in homogeneous 1D Direction.
bool m_IsSVVPowerKernel
Identifier for Power Kernel otherwise DG kernel.
NekDouble m_sVVCutoffRatio
cutt off ratio from which to start decayhing modes
NekDouble m_sVVDiffCoeff
Diffusion coefficient of SVV modes.
bool m_useGJPStabilisation
bool to identify if GJP semi-implicit is active.
bool m_useSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
Array< OneD, NekDouble > m_diffCoeff
Diffusion coefficients (will be kinvis for velocities)
void AppendSVVFactors(StdRegions::ConstFactorMap &factors, MultiRegions::VarFactorsMap &varFactorsMap)
virtual void v_DoInitialise(bool dumpInitialConditions=true) override
Sets up initial conditions.
bool m_useHomo1DSpecVanVisc
bool to identify if spectral vanishing viscosity is active.
void ComputeGJPNormalVelocity(const Array< OneD, const Array< OneD, NekDouble > > &inarray, StdRegions::VarCoeffMap &varcoeffs)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
static VarFactorsMap NullVarFactorsMap
std::map< StdRegions::ConstFactorType, Array< OneD, NekDouble > > VarFactorsMap
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:48
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:49
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:176
@ eLinearAdvectionDiffusionReactionGJP
Definition: StdRegions.hpp:111
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:408
static VarCoeffMap NullVarCoeffMap
Definition: StdRegions.hpp:353
std::map< StdRegions::VarCoeffType, VarCoeffEntry > VarCoeffMap
Definition: StdRegions.hpp:352
StdRegions::ConstFactorMap factors
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
static Array< OneD, NekDouble > NullNekDouble1DArray
double NekDouble
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:617
void Neg(int n, T *x, const int incx)
Negate x = -x.
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:245
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:487