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