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