Nektar++
VCSMapping.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: VCSMapping.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 w/ coordinate transformation
32// for the Incompressible Navier Stokes equations
33///////////////////////////////////////////////////////////////////////////////
34
38
39#include <boost/algorithm/string.hpp>
40
41using namespace std;
42
43namespace Nektar
44{
47 "VCSMapping", VCSMapping::create);
48
50 LibUtilities::SessionReader::RegisterEnumValue("SolverType", "VCSMapping",
52
53/**
54 * Constructor. Creates ...
55 *
56 * \param
57 * \param
58 */
61 : UnsteadySystem(pSession, pGraph),
62 VelocityCorrectionScheme(pSession, pGraph)
63{
64}
65
66void VCSMapping::v_InitObject(bool DeclareField)
67{
69
71 ASSERTL0(m_mapping, "Could not create mapping in VCSMapping.");
72
73 std::string vExtrapolation = "Mapping";
75 vExtrapolation, m_session, m_fields, m_pressure, m_velocity,
77 m_extrapolation->SubSteppingTimeIntegration(m_intScheme);
78 m_extrapolation->GenerateBndElmtExpansion();
79 m_extrapolation->GenerateHOPBCMap(m_session);
80
81 // Storage to extrapolate pressure forcing
82 size_t physTot = m_fields[0]->GetTotPoints();
83 size_t intSteps = 1;
84
85 if (m_intScheme->GetName() == "IMEX" ||
86 m_intScheme->GetName() == "IMEXGear")
87 {
88 m_intSteps = m_intScheme->GetOrder();
89 }
90 else
91 {
93 "Integration method not suitable: "
94 "Options include IMEXGear or IMEXOrder{1,2,3,4}");
95 }
96
98 for (size_t i = 0; i < m_presForcingCorrection.size(); i++)
99 {
101 }
102 m_verbose = (m_session->DefinesCmdLineArgument("verbose")) ? true : false;
103
104 // Load solve parameters related to the mapping
105 // Flags determining if pressure/viscous terms should be treated implicitly
106 m_session->MatchSolverInfo("MappingImplicitPressure", "True",
107 m_implicitPressure, false);
108 m_session->MatchSolverInfo("MappingImplicitViscous", "True",
109 m_implicitViscous, false);
110 m_session->MatchSolverInfo("MappingNeglectViscous", "True",
111 m_neglectViscous, false);
112
114 {
115 m_implicitViscous = false;
116 }
117
118 // Tolerances and relaxation parameters for implicit terms
119 m_session->LoadParameter("MappingPressureTolerance", m_pressureTolerance,
120 1e-12);
121 m_session->LoadParameter("MappingViscousTolerance", m_viscousTolerance,
122 1e-12);
123 m_session->LoadParameter("MappingPressureRelaxation", m_pressureRelaxation,
124 1.0);
125 m_session->LoadParameter("MappingViscousRelaxation", m_viscousRelaxation,
126 1.0);
127}
128
129/**
130 * Destructor
131 */
133{
134}
135
136void VCSMapping::v_DoInitialise(bool dumpInitialConditions)
137{
138 UnsteadySystem::v_DoInitialise(dumpInitialConditions);
139
140 // Set up Field Meta Data for output files
141 m_fieldMetaDataMap["Kinvis"] = boost::lexical_cast<std::string>(m_kinvis);
142 m_fieldMetaDataMap["TimeStep"] =
143 boost::lexical_cast<std::string>(m_timestep);
144
145 // Correct Dirichlet boundary conditions to account for mapping
146 m_mapping->UpdateBCs(0.0);
147 //
149 for (int i = 0; i < m_nConvectiveFields; ++i)
150 {
151 m_fields[i]->ImposeDirichletConditions(m_fields[i]->UpdateCoeffs());
152 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
153 m_fields[i]->UpdatePhys());
155 }
156
157 // Initialise m_gradP
158 size_t physTot = m_fields[0]->GetTotPoints();
160 for (int i = 0; i < m_nConvectiveFields; ++i)
161 {
162 m_gradP[i] = Array<OneD, NekDouble>(physTot, 0.0);
164 m_pressure->GetPhys(), m_gradP[i]);
165 if (m_pressure->GetWaveSpace())
166 {
167 m_pressure->HomogeneousBwdTrans(physTot, m_gradP[i], m_gradP[i]);
168 }
169 }
170}
171
172/**
173 * Explicit part of the method - Advection, Forcing + HOPBCs
174 */
176 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
177 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
178{
179 EvaluateAdvectionTerms(inarray, outarray, time);
180
181 // Smooth advection
183 {
184 for (int i = 0; i < m_nConvectiveFields; ++i)
185 {
186 m_pressure->SmoothField(outarray[i]);
187 }
188 }
189
190 // Add forcing terms
191 for (auto &x : m_forcing)
192 {
193 x->Apply(m_fields, inarray, outarray, time);
194 }
195
196 // Add mapping terms
197 ApplyIncNSMappingForcing(inarray, outarray);
198
199 // Calculate High-Order pressure boundary conditions
200 m_extrapolation->EvaluatePressureBCs(inarray, outarray, m_kinvis);
201
202 // Update mapping and deal with Dirichlet boundary conditions
203 if (m_mapping->IsTimeDependent())
204 {
205 if (m_mapping->IsFromFunction())
206 {
207 // If the transformation is explicitly defined, update it here
208 // Otherwise, it will be done somewhere else (ForcingMovingBody)
209 m_mapping->UpdateMapping(time + m_timestep);
210 }
211 m_mapping->UpdateBCs(time + m_timestep);
212 }
213}
214
215/**
216 * Forcing term for Poisson solver solver
217 */
219 const Array<OneD, const Array<OneD, NekDouble>> &fields,
221{
222 if (m_mapping->HasConstantJacobian())
223 {
225 aii_Dt);
226 }
227 else
228 {
229 size_t physTot = m_fields[0]->GetTotPoints();
230 size_t nvel = m_nConvectiveFields;
231 Array<OneD, NekDouble> wk(physTot, 0.0);
232
233 Array<OneD, NekDouble> Jac(physTot, 0.0);
234 m_mapping->GetJacobian(Jac);
235
236 // Calculate div(J*u/Dt)
237 Vmath::Zero(physTot, Forcing[0], 1);
238 for (size_t i = 0; i < nvel; ++i)
239 {
240 if (m_fields[i]->GetWaveSpace())
241 {
242 m_fields[i]->HomogeneousBwdTrans(physTot, fields[i], wk);
243 }
244 else
245 {
246 Vmath::Vcopy(physTot, fields[i], 1, wk, 1);
247 }
248 Vmath::Vmul(physTot, wk, 1, Jac, 1, wk, 1);
249 if (m_fields[i]->GetWaveSpace())
250 {
251 m_fields[i]->HomogeneousFwdTrans(physTot, wk, wk);
252 }
253 m_fields[i]->PhysDeriv(MultiRegions::DirCartesianMap[i], wk, wk);
254 Vmath::Vadd(physTot, wk, 1, Forcing[0], 1, Forcing[0], 1);
255 }
256 Vmath::Smul(physTot, 1.0 / aii_Dt, Forcing[0], 1, Forcing[0], 1);
257
258 //
259 // If the mapping viscous terms are being treated explicitly
260 // we need to apply a correction to the forcing
262 {
263 bool wavespace = m_fields[0]->GetWaveSpace();
264 m_fields[0]->SetWaveSpace(false);
265
266 //
267 // Part 1: div(J*grad(U/J . grad(J)))
270 for (size_t i = 0; i < tmp.size(); i++)
271 {
272 tmp[i] = Array<OneD, NekDouble>(physTot, 0.0);
273 velocity[i] = Array<OneD, NekDouble>(physTot, 0.0);
274 if (wavespace)
275 {
276 m_fields[0]->HomogeneousBwdTrans(
277 physTot, m_fields[i]->GetPhys(), velocity[i]);
278 }
279 else
280 {
281 Vmath::Vcopy(physTot, m_fields[i]->GetPhys(), 1,
282 velocity[i], 1);
283 }
284 }
285 // Calculate wk = U.grad(J)
286 m_mapping->DotGradJacobian(velocity, wk);
287 // Calculate wk = (U.grad(J))/J
288 Vmath::Vdiv(physTot, wk, 1, Jac, 1, wk, 1);
289 // J*grad[(U.grad(J))/J]
290 for (size_t i = 0; i < nvel; ++i)
291 {
292 m_fields[0]->PhysDeriv(MultiRegions::DirCartesianMap[i], wk,
293 tmp[i]);
294 Vmath::Vmul(physTot, Jac, 1, tmp[i], 1, tmp[i], 1);
295 }
296 // div(J*grad[(U.grad(J))/J])
297 Vmath::Zero(physTot, wk, 1);
298 for (size_t i = 0; i < nvel; ++i)
299 {
300 m_fields[0]->PhysDeriv(MultiRegions::DirCartesianMap[i], tmp[i],
301 tmp[i]);
302 Vmath::Vadd(physTot, wk, 1, tmp[i], 1, wk, 1);
303 }
304
305 // Part 2: grad(J) . curl(curl(U))
306 m_mapping->CurlCurlField(velocity, tmp, m_implicitViscous);
307 // dont need velocity any more, so reuse it
308 m_mapping->DotGradJacobian(tmp, velocity[0]);
309
310 // Add two parts
311 Vmath::Vadd(physTot, velocity[0], 1, wk, 1, wk, 1);
312
313 // Multiply by kinvis and prepare to extrapolate
314 size_t nlevels = m_presForcingCorrection.size();
315 Vmath::Smul(physTot, m_kinvis, wk, 1,
316 m_presForcingCorrection[nlevels - 1], 1);
317
318 // Extrapolate correction
319 m_extrapolation->ExtrapolateArray(m_presForcingCorrection);
320
321 // Put in wavespace
322 if (wavespace)
323 {
324 m_fields[0]->HomogeneousFwdTrans(
325 physTot, m_presForcingCorrection[nlevels - 1], wk);
326 }
327 else
328 {
329 Vmath::Vcopy(physTot, m_presForcingCorrection[nlevels - 1], 1,
330 wk, 1);
331 }
332 // Apply correction: Forcing = Forcing - correction
333 Vmath::Vsub(physTot, Forcing[0], 1, wk, 1, Forcing[0], 1);
334
335 m_fields[0]->SetWaveSpace(wavespace);
336 }
337 }
338}
339
340/**
341 * Forcing term for Helmholtz solver
342 */
344 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
346{
347 NekDouble aii_dtinv = 1.0 / aii_Dt;
348 size_t physTot = m_fields[0]->GetTotPoints();
349
350 // Grad p
351 m_pressure->BwdTrans(m_pressure->GetCoeffs(), m_pressure->UpdatePhys());
352
353 size_t nvel = m_velocity.size();
354 if (nvel == 2)
355 {
356 m_pressure->PhysDeriv(m_pressure->GetPhys(), Forcing[0], Forcing[1]);
357 }
358 else
359 {
360 m_pressure->PhysDeriv(m_pressure->GetPhys(), Forcing[0], Forcing[1],
361 Forcing[2]);
362 }
363
364 // Copy grad p in physical space to m_gradP to reuse later
365 if (m_pressure->GetWaveSpace())
366 {
367 for (size_t i = 0; i < nvel; i++)
368 {
369 m_pressure->HomogeneousBwdTrans(physTot, Forcing[i], m_gradP[i]);
370 }
371 }
372 else
373 {
374 for (size_t i = 0; i < nvel; i++)
375 {
376 Vmath::Vcopy(physTot, Forcing[i], 1, m_gradP[i], 1);
377 }
378 }
379
380 if ((!m_mapping->HasConstantJacobian()) || m_implicitPressure)
381 {
382 // If pressure terms are treated explicitly, we need to divide by J
383 // if they are implicit, we need to calculate G(p)
385 {
386 m_mapping->RaiseIndex(m_gradP, Forcing);
387 }
388 else
389 {
390 Array<OneD, NekDouble> Jac(physTot, 0.0);
391 m_mapping->GetJacobian(Jac);
392 for (size_t i = 0; i < nvel; i++)
393 {
394 Vmath::Vdiv(physTot, m_gradP[i], 1, Jac, 1, Forcing[i], 1);
395 }
396 }
397 // Transform back to wavespace
398 if (m_pressure->GetWaveSpace())
399 {
400 for (size_t i = 0; i < nvel; i++)
401 {
402 m_pressure->HomogeneousFwdTrans(physTot, Forcing[i],
403 Forcing[i]);
404 }
405 }
406 }
407
408 // Subtract inarray/(aii_dt) and divide by kinvis. Kinvis will
409 // need to be updated for the convected fields.
410 for (size_t i = 0; i < nvel; ++i)
411 {
412 Blas::Daxpy(physTot, -aii_dtinv, inarray[i], 1, Forcing[i], 1);
413 Blas::Dscal(physTot, 1.0 / m_kinvis, &(Forcing[i])[0], 1);
414 }
415}
416
417/**
418 * Solve pressure system
419 */
421{
423 {
425 }
426 else
427 {
428 size_t physTot = m_fields[0]->GetTotPoints();
429 size_t nvel = m_nConvectiveFields;
430 bool converged = false; // flag to mark if system converged
431 size_t s = 0; // iteration counter
432 NekDouble error; // L2 error at current iteration
433 NekDouble forcing_L2 = 0.0; // L2 norm of F
434
435 size_t maxIter;
436 m_session->LoadParameter("MappingMaxIter", maxIter, 5000);
437
438 // rhs of the equation at current iteration
439 Array<OneD, NekDouble> F_corrected(physTot, 0.0);
440 // Pressure field at previous iteration
441 Array<OneD, NekDouble> previous_iter(physTot, 0.0);
442 // Temporary variables
446 for (size_t i = 0; i < nvel; ++i)
447 {
448 wk1[i] = Array<OneD, NekDouble>(physTot, 0.0);
449 wk2[i] = Array<OneD, NekDouble>(physTot, 0.0);
450 gradP[i] = Array<OneD, NekDouble>(physTot, 0.0);
451 }
452
453 // Jacobian
454 Array<OneD, NekDouble> Jac(physTot, 0.0);
455 m_mapping->GetJacobian(Jac);
456
457 // Factors for Laplacian system
460
461 m_pressure->BwdTrans(m_pressure->GetCoeffs(), m_pressure->UpdatePhys());
462 forcing_L2 = m_pressure->L2(Forcing, wk1[0]);
463 while (!converged)
464 {
465 // Update iteration counter and set previous iteration field
466 // (use previous timestep solution for first iteration)
467 s++;
468 ASSERTL0(s < maxIter,
469 "VCSMapping exceeded maximum number of iterations.");
470
471 Vmath::Vcopy(physTot, m_pressure->GetPhys(), 1, previous_iter, 1);
472
473 // Correct pressure bc to account for iteration
474 m_extrapolation->CorrectPressureBCs(previous_iter);
475
476 //
477 // Calculate forcing term for this iteration
478 //
479 for (size_t i = 0; i < nvel; ++i)
480 {
482 previous_iter, gradP[i]);
483 if (m_pressure->GetWaveSpace())
484 {
485 m_pressure->HomogeneousBwdTrans(physTot, gradP[i], wk1[i]);
486 }
487 else
488 {
489 Vmath::Vcopy(physTot, gradP[i], 1, wk1[i], 1);
490 }
491 }
492 m_mapping->RaiseIndex(wk1, wk2); // G(p)
493
494 m_mapping->Divergence(wk2, F_corrected); // div(G(p))
495 if (!m_mapping->HasConstantJacobian())
496 {
497 Vmath::Vmul(physTot, F_corrected, 1, Jac, 1, F_corrected, 1);
498 }
499 // alpha*J*div(G(p))
500 Vmath::Smul(physTot, m_pressureRelaxation, F_corrected, 1,
501 F_corrected, 1);
502 if (m_pressure->GetWaveSpace())
503 {
504 m_pressure->HomogeneousFwdTrans(physTot, F_corrected,
505 F_corrected);
506 }
507 // alpha*J*div(G(p)) - p_ii
508 for (int i = 0; i < m_nConvectiveFields; ++i)
509 {
511 gradP[i], wk1[0]);
512 Vmath::Vsub(physTot, F_corrected, 1, wk1[0], 1, F_corrected, 1);
513 }
514 // p_i,i - J*div(G(p))
515 Vmath::Neg(physTot, F_corrected, 1);
516 // alpha*F - alpha*J*div(G(p)) + p_i,i
517 Vmath::Smul(physTot, m_pressureRelaxation, Forcing, 1, wk1[0], 1);
518 Vmath::Vadd(physTot, wk1[0], 1, F_corrected, 1, F_corrected, 1);
519
520 //
521 // Solve system
522 //
523 m_pressure->HelmSolve(F_corrected, m_pressure->UpdateCoeffs(),
524 factors);
525 m_pressure->BwdTrans(m_pressure->GetCoeffs(),
526 m_pressure->UpdatePhys());
527
528 //
529 // Test convergence
530 //
531 error = m_pressure->L2(m_pressure->GetPhys(), previous_iter);
532 if (forcing_L2 != 0)
533 {
534 if ((error / forcing_L2 < m_pressureTolerance))
535 {
536 converged = true;
537 }
538 }
539 else
540 {
541 if (error < m_pressureTolerance)
542 {
543 converged = true;
544 }
545 }
546 }
547 if (m_verbose && m_session->GetComm()->GetRank() == 0)
548 {
549 std::cout << " Pressure system (mapping) converged in " << s
550 << " iterations with error = " << error << std::endl;
551 }
552 }
553}
554
555/**
556 * Solve velocity system
557 */
560 [[maybe_unused]] const Array<OneD, const Array<OneD, NekDouble>> &inarray,
561 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble aii_Dt)
562{
564 {
566 aii_Dt);
567 }
568 else
569 {
570 size_t physTot = m_fields[0]->GetTotPoints();
571 size_t nvel = m_nConvectiveFields;
572 bool converged = false; // flag to mark if system converged
573 size_t s = 0; // iteration counter
574 NekDouble error, max_error; // L2 error at current iteration
575
576 size_t maxIter;
577 m_session->LoadParameter("MappingMaxIter", maxIter, 5000);
578
579 // L2 norm of F
581
582 // rhs of the equation at current iteration
583 Array<OneD, Array<OneD, NekDouble>> F_corrected(nvel);
584 // Solution at previous iteration
585 Array<OneD, Array<OneD, NekDouble>> previous_iter(nvel);
586 // Working space
588 for (size_t i = 0; i < nvel; ++i)
589 {
590 F_corrected[i] = Array<OneD, NekDouble>(physTot, 0.0);
591 previous_iter[i] = Array<OneD, NekDouble>(physTot, 0.0);
592 wk[i] = Array<OneD, NekDouble>(physTot, 0.0);
593 }
594
595 // Factors for Helmholtz system
598 1.0 * m_viscousRelaxation / aii_Dt / m_kinvis;
600 {
604 }
605
606 // Calculate L2-norm of F and set initial solution for iteration
607 for (size_t i = 0; i < nvel; ++i)
608 {
609 forcing_L2[i] = m_fields[0]->L2(Forcing[i], wk[0]);
610 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(), previous_iter[i]);
611 }
612
613 while (!converged)
614 {
615 converged = true;
616 // Iteration counter
617 s++;
618 ASSERTL0(s < maxIter,
619 "VCSMapping exceeded maximum number of iterations.");
620
621 max_error = 0.0;
622
623 //
624 // Calculate forcing term for next iteration
625 //
626
627 // Calculate L(U)- in this parts all components might be coupled
628 if (m_fields[0]->GetWaveSpace())
629 {
630 for (size_t i = 0; i < nvel; ++i)
631 {
632 m_fields[0]->HomogeneousBwdTrans(physTot, previous_iter[i],
633 wk[i]);
634 }
635 }
636 else
637 {
638 for (size_t i = 0; i < nvel; ++i)
639 {
640 Vmath::Vcopy(physTot, previous_iter[i], 1, wk[i], 1);
641 }
642 }
643
644 // (L(U^i) - 1/alpha*U^i_jj)
645 m_mapping->VelocityLaplacian(wk, F_corrected,
646 1.0 / m_viscousRelaxation);
647
648 if (m_fields[0]->GetWaveSpace())
649 {
650 for (size_t i = 0; i < nvel; ++i)
651 {
652 m_fields[0]->HomogeneousFwdTrans(physTot, F_corrected[i],
653 F_corrected[i]);
654 }
655 }
656 else
657 {
658 for (size_t i = 0; i < nvel; ++i)
659 {
660 Vmath::Vcopy(physTot, F_corrected[i], 1, F_corrected[i], 1);
661 }
662 }
663
664 // Loop velocity components
665 for (size_t i = 0; i < nvel; ++i)
666 {
667 // (-alpha*L(U^i) + U^i_jj)
668 Vmath::Smul(physTot, -1.0 * m_viscousRelaxation, F_corrected[i],
669 1, F_corrected[i], 1);
670 // F_corrected = alpha*F + (-alpha*L(U^i) + U^i_jj)
671 Vmath::Smul(physTot, m_viscousRelaxation, Forcing[i], 1, wk[0],
672 1);
673 Vmath::Vadd(physTot, wk[0], 1, F_corrected[i], 1,
674 F_corrected[i], 1);
675
676 //
677 // Solve System
678 //
679 m_fields[i]->HelmSolve(F_corrected[i],
680 m_fields[i]->UpdateCoeffs(), factors);
681 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(), outarray[i]);
682
683 //
684 // Test convergence
685 //
686 error = m_fields[i]->L2(outarray[i], previous_iter[i]);
687
688 if (forcing_L2[i] != 0)
689 {
690 if ((error / forcing_L2[i] >= m_viscousTolerance))
691 {
692 converged = false;
693 }
694 }
695 else
696 {
697 if (error >= m_viscousTolerance)
698 {
699 converged = false;
700 }
701 }
702 if (error > max_error)
703 {
704 max_error = error;
705 }
706
707 // Copy field to previous_iter
708 Vmath::Vcopy(physTot, outarray[i], 1, previous_iter[i], 1);
709 }
710 }
711 if (m_verbose && m_session->GetComm()->GetRank() == 0)
712 {
713 std::cout << " Velocity system (mapping) converged in " << s
714 << " iterations with error = " << max_error << std::endl;
715 }
716 }
717}
718
719/**
720 * Explicit terms of the mapping
721 */
723 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
725{
726 size_t physTot = m_fields[0]->GetTotPoints();
731 for (int i = 0; i < m_nConvectiveFields; ++i)
732 {
733 velPhys[i] = Array<OneD, NekDouble>(physTot, 0.0);
734 Forcing[i] = Array<OneD, NekDouble>(physTot, 0.0);
735 tmp[i] = Array<OneD, NekDouble>(physTot, 0.0);
736 }
737
738 // Get fields and store velocity in wavespace and physical space
739 if (m_fields[0]->GetWaveSpace())
740 {
741 for (int i = 0; i < m_nConvectiveFields; ++i)
742 {
743 vel[i] = inarray[i];
744 m_fields[0]->HomogeneousBwdTrans(physTot, vel[i], velPhys[i]);
745 }
746 }
747 else
748 {
749 for (int i = 0; i < m_nConvectiveFields; ++i)
750 {
751 vel[i] = inarray[i];
752 Vmath::Vcopy(physTot, inarray[i], 1, velPhys[i], 1);
753 }
754 }
755
756 // Advection contribution
758
759 // Time-derivative contribution
760 if (m_mapping->IsTimeDependent())
761 {
762 MappingAccelerationCorrection(vel, velPhys, tmp);
763 for (int i = 0; i < m_nConvectiveFields; ++i)
764 {
765 Vmath::Vadd(physTot, tmp[i], 1, Forcing[i], 1, Forcing[i], 1);
766 }
767 }
768
769 // Pressure contribution
771 {
773 for (int i = 0; i < m_nConvectiveFields; ++i)
774 {
775 Vmath::Vadd(physTot, tmp[i], 1, Forcing[i], 1, Forcing[i], 1);
776 }
777 }
778 // Viscous contribution
780 {
781 MappingViscousCorrection(velPhys, tmp);
782 for (int i = 0; i < m_nConvectiveFields; ++i)
783 {
784 Vmath::Smul(physTot, m_kinvis, tmp[i], 1, tmp[i], 1);
785 Vmath::Vadd(physTot, tmp[i], 1, Forcing[i], 1, Forcing[i], 1);
786 }
787 }
788
789 // If necessary, transform to wavespace
790 if (m_fields[0]->GetWaveSpace())
791 {
792 for (int i = 0; i < m_nConvectiveFields; ++i)
793 {
794 m_fields[0]->HomogeneousFwdTrans(physTot, Forcing[i], Forcing[i]);
795 }
796 }
797
798 // Add to outarray
799 for (int i = 0; i < m_nConvectiveFields; ++i)
800 {
801 Vmath::Vadd(physTot, outarray[i], 1, Forcing[i], 1, outarray[i], 1);
802 }
803}
804
806 const Array<OneD, const Array<OneD, NekDouble>> &velPhys,
808{
809 size_t physTot = m_fields[0]->GetTotPoints();
810 size_t nvel = m_nConvectiveFields;
811
812 Array<OneD, Array<OneD, NekDouble>> wk(nvel * nvel);
813
814 // Apply Christoffel symbols to obtain {i,kj}vel(k)
815 m_mapping->ApplyChristoffelContravar(velPhys, wk);
816
817 // Calculate correction -U^j*{i,kj}vel(k)
818 for (size_t i = 0; i < nvel; i++)
819 {
820 Vmath::Zero(physTot, outarray[i], 1);
821 for (size_t j = 0; j < nvel; j++)
822 {
823 Vmath::Vvtvp(physTot, wk[i * nvel + j], 1, velPhys[j], 1,
824 outarray[i], 1, outarray[i], 1);
825 }
826 Vmath::Neg(physTot, outarray[i], 1);
827 }
828}
829
831 const Array<OneD, const Array<OneD, NekDouble>> &vel,
832 const Array<OneD, const Array<OneD, NekDouble>> &velPhys,
834{
835 size_t physTot = m_fields[0]->GetTotPoints();
836 size_t nvel = m_nConvectiveFields;
837
838 Array<OneD, Array<OneD, NekDouble>> wk(nvel * nvel);
841 for (size_t i = 0; i < nvel; i++)
842 {
843 tmp[i] = Array<OneD, NekDouble>(physTot, 0.0);
844 coordVel[i] = Array<OneD, NekDouble>(physTot, 0.0);
845 }
846 // Get coordinates velocity in transformed system
847 m_mapping->GetCoordVelocity(tmp);
848 m_mapping->ContravarFromCartesian(tmp, coordVel);
849
850 // Calculate first term: U^j u^i,j = U^j (du^i/dx^j + {i,kj}u^k)
851 m_mapping->ApplyChristoffelContravar(velPhys, wk);
852 for (size_t i = 0; i < nvel; i++)
853 {
854 Vmath::Zero(physTot, outarray[i], 1);
855
856 m_fields[0]->PhysDeriv(velPhys[i], tmp[0], tmp[1]);
857 for (size_t j = 0; j < nvel; j++)
858 {
859 if (j == 2)
860 {
861 m_fields[0]->PhysDeriv(MultiRegions::DirCartesianMap[j], vel[i],
862 tmp[2]);
863 if (m_fields[0]->GetWaveSpace())
864 {
865 m_fields[0]->HomogeneousBwdTrans(physTot, tmp[2], tmp[2]);
866 }
867 }
868
869 Vmath::Vadd(physTot, wk[i * nvel + j], 1, tmp[j], 1,
870 wk[i * nvel + j], 1);
871
872 Vmath::Vvtvp(physTot, coordVel[j], 1, wk[i * nvel + j], 1,
873 outarray[i], 1, outarray[i], 1);
874 }
875 }
876
877 // Set wavespace to false and store current value
878 bool wavespace = m_fields[0]->GetWaveSpace();
879 m_fields[0]->SetWaveSpace(false);
880
881 // Add -u^j U^i,j
882 m_mapping->ApplyChristoffelContravar(coordVel, wk);
883 for (size_t i = 0; i < nvel; i++)
884 {
885 if (nvel == 2)
886 {
887 m_fields[0]->PhysDeriv(coordVel[i], tmp[0], tmp[1]);
888 }
889 else
890 {
891 m_fields[0]->PhysDeriv(coordVel[i], tmp[0], tmp[1], tmp[2]);
892 }
893
894 for (size_t j = 0; j < nvel; j++)
895 {
896 Vmath::Vadd(physTot, wk[i * nvel + j], 1, tmp[j], 1,
897 wk[i * nvel + j], 1);
898 Vmath::Neg(physTot, wk[i * nvel + j], 1);
899
900 Vmath::Vvtvp(physTot, velPhys[j], 1, wk[i * nvel + j], 1,
901 outarray[i], 1, outarray[i], 1);
902 }
903 }
904
905 // Restore value of wavespace
906 m_fields[0]->SetWaveSpace(wavespace);
907}
908
911{
912 size_t physTot = m_fields[0]->GetTotPoints();
913 size_t nvel = m_nConvectiveFields;
914
915 // Calculate g^(ij)p_(,j)
916 m_mapping->RaiseIndex(m_gradP, outarray);
917
918 // Calculate correction = (nabla p)/J - g^(ij)p_,j
919 // (Jac is not required if it is constant)
920 if (!m_mapping->HasConstantJacobian())
921 {
922 Array<OneD, NekDouble> Jac(physTot, 0.0);
923 m_mapping->GetJacobian(Jac);
924 for (size_t i = 0; i < nvel; ++i)
925 {
926 Vmath::Vdiv(physTot, m_gradP[i], 1, Jac, 1, m_gradP[i], 1);
927 }
928 }
929 for (size_t i = 0; i < nvel; ++i)
930 {
931 Vmath::Vsub(physTot, m_gradP[i], 1, outarray[i], 1, outarray[i], 1);
932 }
933}
934
936 const Array<OneD, const Array<OneD, NekDouble>> &velPhys,
938{
939 // L(U) - 1.0*d^2(u^i)/dx^jdx^j
940 m_mapping->VelocityLaplacian(velPhys, outarray, 1.0);
941}
942
943} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:202
static GLOBAL_MAPPING_EXPORT MappingSharedPtr Load(const LibUtilities::SessionReaderSharedPtr &pSession, const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields)
Return a pointer to the mapping, creating it on first call.
Definition: Mapping.cpp:266
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);
int m_intSteps
Number of time integration steps AND Order of extrapolation for pressure boundary conditions.
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:197
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:143
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
NekDouble m_timestep
Time step size.
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
LibUtilities::FieldMetaDataMap m_fieldMetaDataMap
Map to identify relevant solver info to dump in output fields.
SOLVER_UTILS_EXPORT int GetTotPoints()
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:71
Base class for unsteady solvers.
SOLVER_UTILS_EXPORT void v_DoInitialise(bool dumpInitialConditions=true) override
Sets up initial conditions.
LibUtilities::TimeIntegrationSchemeSharedPtr m_intScheme
Wrapper to the time integration scheme.
void v_SolvePressure(const Array< OneD, NekDouble > &Forcing) override
Definition: VCSMapping.cpp:420
void v_SetUpPressureForcing(const Array< OneD, const Array< OneD, NekDouble > > &fields, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt) override
Definition: VCSMapping.cpp:218
void MappingViscousCorrection(const Array< OneD, const Array< OneD, NekDouble > > &velPhys, Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: VCSMapping.cpp:935
void v_DoInitialise(bool dumpInitialConditions=true) override
Sets up initial conditions.
Definition: VCSMapping.cpp:136
void v_SetUpViscousForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &Forcing, const NekDouble aii_Dt) override
Definition: VCSMapping.cpp:343
NekDouble m_pressureTolerance
Definition: VCSMapping.h:88
NekDouble m_viscousRelaxation
Definition: VCSMapping.h:91
static std::string className
Name of class.
Definition: VCSMapping.h:58
NekDouble m_pressureRelaxation
Definition: VCSMapping.h:90
static SolverUtils::EquationSystemSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
Definition: VCSMapping.h:47
NekDouble m_viscousTolerance
Definition: VCSMapping.h:89
void v_EvaluateAdvection_SetPressureBCs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time) override
Definition: VCSMapping.cpp:175
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
Definition: VCSMapping.cpp:558
~VCSMapping() override
Definition: VCSMapping.cpp:132
static std::string solverTypeLookupId
Definition: VCSMapping.h:77
GlobalMapping::MappingSharedPtr m_mapping
Definition: VCSMapping.h:75
void MappingPressureCorrection(Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: VCSMapping.cpp:909
void ApplyIncNSMappingForcing(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: VCSMapping.cpp:722
Array< OneD, Array< OneD, NekDouble > > m_presForcingCorrection
Definition: VCSMapping.h:123
VCSMapping(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Constructor.
Definition: VCSMapping.cpp:59
void v_InitObject(bool DeclareField=true) override
Initialisation object for EquationSystem.
Definition: VCSMapping.cpp:66
void MappingAccelerationCorrection(const Array< OneD, const Array< OneD, NekDouble > > &vel, const Array< OneD, const Array< OneD, NekDouble > > &velPhys, Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: VCSMapping.cpp:830
Array< OneD, Array< OneD, NekDouble > > m_gradP
Definition: VCSMapping.h:94
void MappingAdvectionCorrection(const Array< OneD, const Array< OneD, NekDouble > > &velPhys, Array< OneD, Array< OneD, NekDouble > > &outarray)
Definition: VCSMapping.cpp:805
NekDouble m_sVVCutoffRatio
cutt off ratio from which to start decayhing modes
NekDouble m_sVVDiffCoeff
Diffusion coefficient of SVV modes.
virtual void v_SolvePressure(const Array< OneD, NekDouble > &Forcing)
Array< OneD, Array< OneD, NekDouble > > m_F
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.
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)
void v_InitObject(bool DeclareField=true) override
Initialisation object for EquationSystem.
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition: Blas.hpp:149
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:135
std::shared_ptr< SessionReader > SessionReaderSharedPtr
const std::vector< NekDouble > velocity
MultiRegions::Direction const DirCartesianMap[]
Definition: ExpList.h:86
EquationSystemFactory & GetEquationSystemFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:402
StdRegions::ConstFactorMap factors
ExtrapolateFactory & GetExtrapolateFactory()
Definition: Extrapolate.cpp:48
double NekDouble
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.hpp:72
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.hpp:292
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition: Vmath.hpp:366
void 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.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.hpp:100
void Vdiv(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x/y.
Definition: Vmath.hpp:126
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.hpp:273
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:825
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.hpp:220