Nektar++
MMFAdvection.cpp
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2//
3// File: MMFAdvection.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: MMF solve routines
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <iomanip>
36#include <iostream>
37
38#include <boost/algorithm/string.hpp>
39
43
44namespace Nektar
45{
46std::string MMFAdvection::className =
48 "MMFAdvection", MMFAdvection::create, "MMFAdvection equation.");
49
52 : UnsteadySystem(pSession, pGraph), MMFSystem(pSession, pGraph),
53 AdvectionSystem(pSession, pGraph)
54{
55}
56
57/**
58 * @brief Initialisation object for the unsteady linear advection equation.
59 */
60void MMFAdvection::v_InitObject(bool DeclareFields)
61{
62 // Call to the initialisation object
63 UnsteadySystem::v_InitObject(DeclareFields);
64
65 int nq = m_fields[0]->GetNpoints();
66 int shapedim = m_fields[0]->GetShapeDimension();
67 Array<OneD, Array<OneD, NekDouble>> Anisotropy(shapedim);
68 for (int j = 0; j < shapedim; ++j)
69 {
70 Anisotropy[j] = Array<OneD, NekDouble>(nq, 1.0);
71 }
72
73 MMFSystem::MMFInitObject(Anisotropy);
74
75 // Define TestType
76 ASSERTL0(m_session->DefinesSolverInfo("TESTTYPE"),
77 "No TESTTYPE defined in session.");
78 std::string TestTypeStr = m_session->GetSolverInfo("TESTTYPE");
79 for (int i = 0; i < (int)SIZE_TestType; ++i)
80 {
81 if (boost::iequals(TestTypeMap[i], TestTypeStr))
82 {
84 break;
85 }
86 }
87
88 m_session->LoadParameter("Angular Frequency", m_waveFreq, m_pi);
89 m_session->LoadParameter("Rotational Angle", m_RotAngle, 0.0);
90 m_session->LoadParameter("Velocity Projection", m_VelProjection, 0);
91
92 // Read the advection velocities from session file
93 m_session->LoadParameter("advx", m_advx, 1.0);
94 m_session->LoadParameter("advy", m_advy, 1.0);
95 m_session->LoadParameter("advz", m_advz, 1.0);
96
97 std::vector<std::string> vel;
98 vel.push_back("Vx");
99 vel.push_back("Vy");
100 vel.push_back("Vz");
101
102 // Resize the advection velocities vector to dimension of the problem
103 vel.resize(m_spacedim);
104
105 // Store in the global variable m_velocity the advection velocities
107 for (int k = 0; k < m_spacedim; ++k)
108 {
110 }
111
112 switch (m_surfaceType)
113 {
118 {
119 // true = project velocity onto the tangent plane
121 }
122 break;
123
126 {
127 GetFunction("AdvectionVelocity")->Evaluate(vel, m_velocity);
128 }
129 break;
130
131 default:
132 break;
133 }
134
135 std::cout << "|Velocity vector| = ( " << RootMeanSquare(m_velocity[0])
136 << " , " << RootMeanSquare(m_velocity[1]) << " , "
137 << RootMeanSquare(m_velocity[2]) << " ) " << std::endl;
138
139 // Define the normal velocity fields
140 if (m_fields[0]->GetTrace())
141 {
143 }
144
145 std::string advName;
146 std::string riemName;
147 m_session->LoadSolverInfo("AdvectionType", advName, "WeakDG");
150 m_advObject->SetFluxVector(&MMFAdvection::GetFluxVector, this);
151 m_session->LoadSolverInfo("UpwindType", riemName, "Upwind");
153 riemName, m_session);
154 m_riemannSolver->SetScalar("Vn", &MMFAdvection::GetNormalVelocity, this);
155
156 m_advObject->SetRiemannSolver(m_riemannSolver);
157 m_advObject->InitObject(m_session, m_fields);
158
159 // Compute m_traceVn = n \cdot v
161
162 // Compute m_vellc = nabal a^j \cdot m_vel
164 std::cout << "m_vellc is generated with mag = " << AvgInt(m_vellc)
165 << std::endl;
166
167 // Compute vel \cdot MF
169
170 // Modify e^i as v^i e^i
171 for (int j = 0; j < m_shapedim; j++)
172 {
173 for (int k = 0; k < m_spacedim; k++)
174 {
175 Vmath::Vmul(nq, &m_veldotMF[j][0], 1, &m_movingframes[j][k * nq], 1,
176 &m_movingframes[j][k * nq], 1);
177 }
178 }
179
180 // Reflect it into m_ncdotMFFwd and Bwd
182
183 // If explicit it computes RHS and PROJECTION for the time integration
185 {
188 }
189 // Otherwise it gives an error (no implicit integration)
190 else
191 {
192 ASSERTL0(false, "Implicit unsteady Advection not set up.");
193 }
194}
195
197{
198 ASSERTL0(m_intScheme != nullptr, "No time integration scheme.");
199
200 int i, nchk = 1;
201 int nvariables = 0;
202 int nfields = m_fields.size();
203 int nq = m_fields[0]->GetNpoints();
204
205 if (m_intVariables.empty())
206 {
207 for (i = 0; i < nfields; ++i)
208 {
209 m_intVariables.push_back(i);
210 }
211 nvariables = nfields;
212 }
213 else
214 {
215 nvariables = m_intVariables.size();
216 }
217
218 // Set up wrapper to fields data storage.
219 Array<OneD, Array<OneD, NekDouble>> fields(nvariables);
220 Array<OneD, Array<OneD, NekDouble>> tmp(nvariables);
221
222 // Order storage to list time-integrated fields first.
223 for (i = 0; i < nvariables; ++i)
224 {
225 fields[i] = m_fields[m_intVariables[i]]->GetPhys();
226 m_fields[m_intVariables[i]]->SetPhysState(false);
227 }
228
229 // Initialise time integration scheme
230 m_intScheme->InitializeScheme(m_timestep, fields, m_time, m_ode);
231
232 // Check uniqueness of checkpoint output
233 ASSERTL0((m_checktime == 0.0 && m_checksteps == 0) ||
234 (m_checktime > 0.0 && m_checksteps == 0) ||
235 (m_checktime == 0.0 && m_checksteps > 0),
236 "Only one of IO_CheckTime and IO_CheckSteps "
237 "should be set!");
238
240 bool doCheckTime = false;
241 int step = 0;
242 NekDouble intTime = 0.0;
243 NekDouble cpuTime = 0.0;
244 NekDouble elapsed = 0.0;
245
246 int Ntot, indx;
247 // Perform integration in time.
248 Ntot = m_checksteps ? m_steps / m_checksteps + 1 : 0;
249
250 Array<OneD, NekDouble> dMass(Ntot ? Ntot : 1);
251
252 Array<OneD, NekDouble> zeta(nq);
253 Array<OneD, Array<OneD, NekDouble>> fieldsprimitive(nvariables);
254 for (int i = 0; i < nvariables; ++i)
255 {
256 fieldsprimitive[i] = Array<OneD, NekDouble>(nq);
257 }
258
260 {
261 timer.Start();
262 fields = m_intScheme->TimeIntegrate(step, m_timestep);
263 timer.Stop();
264
266 elapsed = timer.TimePerTest(1);
267 intTime += elapsed;
268 cpuTime += elapsed;
269
270 // Write out status information
271 if (m_infosteps && !((step + 1) % m_infosteps) &&
272 m_session->GetComm()->GetRank() == 0)
273 {
274 std::cout << "Steps: " << std::setw(8) << std::left << step + 1
275 << " "
276 << "Time: " << std::setw(12) << std::left << m_time;
277
278 std::stringstream ss;
279 ss << cpuTime << "s";
280 std::cout << " CPU Time: " << std::setw(8) << std::left << ss.str()
281 << std::endl;
282
283 // Masss = h^*
284 indx = m_checksteps ? (step + 1) / m_checksteps : 0;
285 dMass[indx] =
286 (m_fields[0]->Integral(fields[0]) - m_Mass0) / m_Mass0;
287
288 std::cout << "dMass = " << std::setw(8) << std::left << dMass[indx]
289 << std::endl;
290
291 cpuTime = 0.0;
292 }
293
294 // Transform data into coefficient space
295 for (i = 0; i < nvariables; ++i)
296 {
297 m_fields[m_intVariables[i]]->SetPhys(fields[i]);
298 m_fields[m_intVariables[i]]->FwdTransLocalElmt(
299 fields[i], m_fields[m_intVariables[i]]->UpdateCoeffs());
300 m_fields[m_intVariables[i]]->SetPhysState(false);
301 }
302
303 // Write out checkpoint files
304 if ((m_checksteps && step && !((step + 1) % m_checksteps)) ||
305 doCheckTime)
306 {
307 Checkpoint_Output(nchk++);
308 doCheckTime = false;
309 }
310
311 // Step advance
312 ++step;
313 }
314
315 std::cout << "dMass = ";
316 for (i = 0; i < Ntot; ++i)
317 {
318 std::cout << dMass[i] << " , ";
319 }
320 std::cout << std::endl << std::endl;
321
322 // Print out summary statistics
323 if (m_session->GetComm()->GetRank() == 0)
324 {
325 if (m_cflSafetyFactor > 0.0)
326 {
327 std::cout << "CFL safety factor : " << m_cflSafetyFactor
328 << std::endl
329 << "CFL time-step : " << m_timestep << std::endl;
330 }
331
332 if (m_session->GetSolverInfo("Driver") != "SteadyState")
333 {
334 std::cout << "Time-integration : " << intTime << "s" << std::endl;
335 }
336 }
337
338 for (i = 0; i < nvariables; ++i)
339 {
340 m_fields[m_intVariables[i]]->SetPhys(fields[i]);
341 m_fields[m_intVariables[i]]->SetPhysState(true);
342 }
343
344 for (i = 0; i < nvariables; ++i)
345 {
346 m_fields[i]->FwdTrans(m_fields[i]->GetPhys(),
347 m_fields[i]->UpdateCoeffs());
348 }
349}
350
351/**
352 * @brief Get the normal velocity for the linear advection equation.
353 */
355{
356 // Number of trace (interface) points
357 int i;
358 int nTracePts = GetTraceNpoints();
359
360 // Auxiliary variable to compute the normal velocity
361 Array<OneD, NekDouble> tmp(nTracePts);
362
363 // Reset the normal velocity
364 Vmath::Zero(nTracePts, m_traceVn, 1);
365
366 for (i = 0; i < m_velocity.size(); ++i)
367 {
368 m_fields[0]->ExtractTracePhys(m_velocity[i], tmp);
369
370 Vmath::Vvtvp(nTracePts, m_traceNormals[i], 1, tmp, 1, m_traceVn, 1,
371 m_traceVn, 1);
372 }
373
374 return m_traceVn;
375}
376
377/**
378 * @brief Compute the right-hand side for the linear advection equation.
379 *
380 * @param inarray Given fields.
381 * @param outarray Calculated solution.
382 * @param time Time.
383 */
385 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
387 [[maybe_unused]] const NekDouble time)
388{
389 int i;
390 int nvariables = inarray.size();
391 int npoints = GetNpoints();
392
393 switch (m_projectionType)
394 {
396 {
397 int ncoeffs = inarray[0].size();
398
399 if (m_spacedim == 3)
400 {
401 Array<OneD, Array<OneD, NekDouble>> WeakAdv(nvariables);
402
403 WeakAdv[0] = Array<OneD, NekDouble>(ncoeffs * nvariables);
404 for (i = 1; i < nvariables; ++i)
405 {
406 WeakAdv[i] = WeakAdv[i - 1] + ncoeffs;
407 }
408
409 // Compute \nabla \cdot \vel u according to MMF scheme
410 WeakDGDirectionalAdvection(inarray, WeakAdv);
411
412 for (i = 0; i < nvariables; ++i)
413 {
414 m_fields[i]->MultiplyByElmtInvMass(WeakAdv[i], WeakAdv[i]);
415 m_fields[i]->BwdTrans(WeakAdv[i], outarray[i]);
416 Vmath::Neg(npoints, outarray[i], 1);
417 }
418 }
419 else
420 {
421 m_advObject->Advect(2, m_fields, m_velocity, inarray, outarray,
422 0.0);
423
424 for (i = 0; i < nvariables; ++i)
425 {
426 Vmath::Neg(npoints, outarray[i], 1);
427 }
428 }
429 }
430 break;
431
432 default:
433 {
434 ASSERTL0(false, "Unknown projection scheme");
435 }
436 break;
437 }
438}
439
440/**
441 * @brief Compute the projection for the linear advection equation.
442 *
443 * @param inarray Given fields.
444 * @param outarray Calculated solution.
445 * @param time Time.
446 */
448 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
449 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble time)
450{
451 // Counter variable
452 int i;
453
454 // Number of fields (variables of the problem)
455 int nVariables = inarray.size();
456
457 // Set the boundary conditions
459
460 // Switch on the projection type (Discontinuous or Continuous)
461 switch (m_projectionType)
462 {
463 // Discontinuous projection
465 {
466 // Number of quadrature points
467 int nQuadraturePts = GetNpoints();
468
469 // Just copy over array
470 if (inarray != outarray)
471 {
472 for (i = 0; i < nVariables; ++i)
473 {
474 Vmath::Vcopy(nQuadraturePts, inarray[i], 1, outarray[i], 1);
475 }
476 }
477 break;
478 }
479
480 // Continuous projection
483 {
484 Array<OneD, NekDouble> coeffs(m_fields[0]->GetNcoeffs(), 0.0);
485 for (i = 0; i < nVariables; ++i)
486 {
487 m_fields[i]->FwdTrans(inarray[i], coeffs);
488 m_fields[i]->BwdTrans(coeffs, outarray[i]);
489 }
490 break;
491 }
492
493 default:
494 ASSERTL0(false, "Unknown projection scheme");
495 break;
496 }
497}
498
499/**
500 * @brief Return the flux vector for the linear advection equation.
501 *
502 * @param i Component of the flux vector to calculate.
503 * @param physfield Fields.
504 * @param flux Resulting flux.
505 */
507 const Array<OneD, Array<OneD, NekDouble>> &physfield,
509{
510 ASSERTL1(flux[0].size() == m_velocity.size(),
511 "Dimension of flux array and velocity array do not match");
512
513 int i, j;
514 int nq = physfield[0].size();
515
516 for (i = 0; i < flux.size(); ++i)
517 {
518 for (j = 0; j < flux[0].size(); ++j)
519 {
520 Vmath::Vmul(nq, physfield[i], 1, m_velocity[j], 1, flux[i][j], 1);
521 }
522 }
523}
524
526 const Array<OneD, Array<OneD, NekDouble>> &InField,
528{
529 int i, j;
530 int ncoeffs = GetNcoeffs();
531 int nTracePointsTot = GetTraceNpoints();
532 int nvariables = m_fields.size();
533
534 Array<OneD, Array<OneD, NekDouble>> physfield(nvariables);
535
536 // Get the variables in physical space
537 // already in physical space
538 for (i = 0; i < nvariables; ++i)
539 {
540 physfield[i] = InField[i];
541 }
542
544 for (i = 0; i < nvariables; ++i)
545 {
546 for (j = 0; j < m_shapedim; ++j)
547 {
548 WeakDeriv[j] = Array<OneD, NekDouble>(ncoeffs, 0.0);
549
550 // Directional derivation with respect to the j'th moving frame
551 // tmp[j] = \nabla \physfield[i] \cdot \mathbf{e}^j
552 // Implemented at TriExp::v_IProductWRTDirectionalDerivBase_SumFa
553 m_fields[0]->IProductWRTDirectionalDerivBase(
554 m_movingframes[j], physfield[i], WeakDeriv[j]);
555 }
556
557 // Get the numerical flux and add to the modal coeffs
558 // if the NumericalFluxs function already includes the
559 // normal in the output
560
561 Array<OneD, NekDouble> Fwd(nTracePointsTot);
562 Array<OneD, NekDouble> Bwd(nTracePointsTot);
563
564 Array<OneD, NekDouble> flux(nTracePointsTot, 0.0);
565 Array<OneD, NekDouble> fluxFwd(nTracePointsTot);
566 Array<OneD, NekDouble> fluxBwd(nTracePointsTot);
567
568 // Evaluate numerical flux in physical space which may in
569 // general couple all component of vectors
570 m_fields[i]->GetFwdBwdTracePhys(physfield[i], Fwd, Bwd);
571
572 // evaulate upwinded m_fields[i]
573 m_fields[i]->GetTrace()->Upwind(m_traceVn, Fwd, Bwd, flux);
574
575 OutField[i] = Array<OneD, NekDouble>(ncoeffs, 0.0);
576 for (j = 0; j < m_shapedim; ++j)
577 {
578 // calculate numflux = (n \cdot MF)*flux
579 Vmath::Vmul(nTracePointsTot, &flux[0], 1, &m_ncdotMFFwd[j][0], 1,
580 &fluxFwd[0], 1);
581 Vmath::Vmul(nTracePointsTot, &flux[0], 1, &m_ncdotMFBwd[j][0], 1,
582 &fluxBwd[0], 1);
583 Vmath::Neg(ncoeffs, WeakDeriv[j], 1);
584
585 // FwdBwdtegral because generallize (N \cdot MF)_{FWD} \neq -(N
586 // \cdot MF)_{BWD}
587 m_fields[i]->AddFwdBwdTraceIntegral(fluxFwd, fluxBwd, WeakDeriv[j]);
588 m_fields[i]->SetPhysState(false);
589
590 Vmath::Vadd(ncoeffs, &WeakDeriv[j][0], 1, &OutField[i][0], 1,
591 &OutField[i][0], 1);
592 }
593 }
594}
595
598{
599 int nq = m_fields[0]->GetNpoints();
600
601 NekDouble vel_phi, vel_theta, sin_varphi, cos_varphi, sin_theta, cos_theta;
602 NekDouble x0j, x1j, x2j;
603
607
608 m_fields[0]->GetCoords(x0, x1, x2);
609
610 // theta = a*sin(z/r), phi = a*tan(y/x);
611 for (int j = 0; j < nq; j++)
612 {
613 x0j = x0[j];
614 x1j = x1[j];
615 x2j = x2[j];
616
617 CartesianToSpherical(x0j, x1j, x2j, sin_varphi, cos_varphi, sin_theta,
618 cos_theta);
619
620 vel_phi = m_waveFreq * (cos_theta * cos(m_RotAngle) +
621 sin_theta * cos_varphi * sin(m_RotAngle));
622 vel_theta = -1.0 * m_waveFreq * sin_theta * sin(m_RotAngle);
623
624 velocity[0][j] =
625 -1.0 * vel_phi * sin_varphi - vel_theta * sin_theta * cos_varphi;
626 velocity[1][j] =
627 vel_phi * cos_varphi - vel_theta * sin_theta * sin_varphi;
628 velocity[2][j] = vel_theta * cos_theta;
629 }
630
631 // Project the veloicty on the tangent plane
632
633 if (m_VelProjection)
634 {
635 // Check MovingFrames \cdot SurfaceNormals = 0
637
641
642 for (int k = 0; k < m_spacedim; ++k)
643 {
644 newvelocity[k] = Array<OneD, NekDouble>(nq);
645 MF1[k] = Array<OneD, NekDouble>(nq);
646 MF2[k] = Array<OneD, NekDouble>(nq);
647 SN[k] = Array<OneD, NekDouble>(nq);
648
649 Vmath::Vcopy(nq, &m_movingframes[0][k * nq], 1, &MF1[k][0], 1);
650 Vmath::Vcopy(nq, &m_movingframes[1][k * nq], 1, &MF2[k][0], 1);
651 }
652
653 VectorCrossProd(MF1, MF2, SN);
654 GramSchumitz(SN, m_velocity, newvelocity, true);
655
656 Array<OneD, NekDouble> tmp(nq, 0.0);
658
659 for (int k = 0; k < m_spacedim; ++k)
660 {
661 Vmath::Vsub(nq, &m_velocity[0][0], 1, &newvelocity[0][0], 1,
662 &tmp[0], 1);
663 Vmath::Vmul(nq, &tmp[0], 1, &tmp[0], 1, &tmp[0], 1);
664 Vmath::Vadd(nq, tmp, 1, Projection, 1, Projection, 1);
665 }
666
667 std::cout
668 << "Velocity vector is projected onto the tangent plane: Diff = "
669 << RootMeanSquare(Projection) << std::endl;
670
671 for (int k = 0; k < m_spacedim; ++k)
672 {
673 Vmath::Vcopy(nq, &newvelocity[k][0], 1, &m_velocity[k][0], 1);
674 }
675 }
676}
677
679 const NekDouble Rhs)
680{
681
682 NekDouble Tol = 0.0001, Maxiter = 1000, N = 100;
683 NekDouble newy, F = 0.0, dF = 1.0, y0, tmp;
684
685 Array<OneD, NekDouble> xp(N + 1);
686 Array<OneD, NekDouble> yp(N + 1);
687
688 NekDouble intval = 0.0;
689 switch (m_surfaceType)
690 {
693 {
694 intval = sqrt(Rhs - zlevel * zlevel);
695 }
696 break;
697
699 {
700 intval = sqrt(0.5 * (Rhs - zlevel * zlevel * zlevel * zlevel -
701 zlevel * zlevel));
702 }
703 break;
704
706 {
707 tmp = 0.5 *
708 (Rhs - zlevel * zlevel * zlevel * zlevel - zlevel * zlevel);
709 intval = sqrt(0.5 * (1.0 + sqrt(1.0 + 4.0 * tmp)));
710 }
711 break;
712
713 default:
714 break;
715 }
716
717 switch (m_surfaceType)
718 {
719 // Find the half of all the xp and yp on zlevel ....
723 {
724 for (int j = 0; j < N + 1; ++j)
725 {
726 xp[j] = j * 2.0 * intval / N - intval;
727
728 y0 = 1.0;
729 for (int i = 0; i < Maxiter; ++i)
730 {
731 switch (m_surfaceType)
732 {
733 // Find the half of all the xp and yp on zlevel ....
736 {
737 F = xp[j] * xp[j] + y0 * y0 + zlevel * zlevel - Rhs;
738 dF = 2.0 * y0;
739 }
740 break;
741
743 {
744 F = 2.0 * xp[j] * xp[j] + y0 * y0 * y0 * y0 +
745 y0 * y0 + zlevel * zlevel * zlevel * zlevel +
746 zlevel * zlevel - Rhs;
747 dF = 4.0 * y0 * y0 * y0 + 2.0 * y0;
748 }
749 break;
750
751 default:
752 break;
753 }
754
755 newy = y0 - F / dF;
756
757 if (fabs(F / dF) < Tol)
758 {
759 yp[j] = newy;
760 break;
761 }
762
763 else
764 {
765 y0 = newy;
766 }
767
768 ASSERTL0(i < Maxiter,
769 "Advection Velocity convergence fails");
770
771 } // i-loop
772 }
773 }
774 break;
775
777 {
778 for (int j = 0; j < N + 1; ++j)
779 {
780 xp[j] = j * 2.0 * intval / N - intval;
781 tmp = 0.5 * Rhs -
782 0.5 * (zlevel * zlevel * zlevel * zlevel +
783 zlevel * zlevel) -
784 (xp[j] * xp[j] * xp[j] * xp[j] - xp[j] * xp[j]);
785 if (tmp < 0)
786 {
787 tmp = -1.0 * tmp;
788 }
789 yp[j] = sqrt(tmp);
790 } // j-loop
791 }
792 break;
793
794 default:
795 break;
796
797 } // switch-loop
798
799 NekDouble pi = 3.14159265358979323846;
800 NekDouble arclength = 0.0;
801 for (int j = 0; j < N; ++j)
802 {
803 arclength =
804 arclength + sqrt((yp[j + 1] - yp[j]) * (yp[j + 1] - yp[j]) +
805 (xp[j + 1] - xp[j]) * (xp[j + 1] - xp[j])) /
806 pi;
807 }
808
809 return arclength;
810}
811
813 bool dumpInitialConditions,
814 [[maybe_unused]] const int domain)
815{
816 int nq = m_fields[0]->GetNpoints();
817
819
820 switch (m_TestType)
821 {
822 case eAdvectionBell:
823 {
825 m_fields[0]->SetPhys(u);
826
827 m_Mass0 = m_fields[0]->Integral(u);
828
829 // forward transform to fill the modal coeffs
830 for (int i = 0; i < m_fields.size(); ++i)
831 {
832 m_fields[i]->SetPhysState(true);
833 m_fields[i]->FwdTrans(m_fields[i]->GetPhys(),
834 m_fields[i]->UpdateCoeffs());
835 }
836 }
837 break;
838
839 case eTestPlane:
840 {
841 Test2Dproblem(initialtime, u);
842 m_fields[0]->SetPhys(u);
843
844 m_Mass0 = m_fields[0]->Integral(u);
845
846 // forward transform to fill the modal coeffs
847 for (int i = 0; i < m_fields.size(); ++i)
848 {
849 m_fields[i]->SetPhysState(true);
850 m_fields[i]->FwdTrans(m_fields[i]->GetPhys(),
851 m_fields[i]->UpdateCoeffs());
852 }
853 }
854 break;
855
857 {
859 m_fields[0]->SetPhys(u);
860
861 m_Mass0 = m_fields[0]->Integral(u);
862 std::cout << "m_Mass0 = " << m_Mass0 << std::endl;
863
864 // forward transform to fill the modal coeffs
865 for (int i = 0; i < m_fields.size(); ++i)
866 {
867 m_fields[i]->SetPhysState(true);
868 m_fields[i]->FwdTrans(m_fields[i]->GetPhys(),
869 m_fields[i]->UpdateCoeffs());
870 }
871 }
872 break;
873
874 case eTestCube:
875 {
876 Test3Dproblem(initialtime, u);
877 m_fields[0]->SetPhys(u);
878
879 // forward transform to fill the modal coeffs
880 for (int i = 0; i < m_fields.size(); ++i)
881 {
882 m_fields[i]->SetPhysState(true);
883 m_fields[i]->FwdTrans(m_fields[i]->GetPhys(),
884 m_fields[i]->UpdateCoeffs());
885 }
886 }
887 break;
888
889 default:
890 break;
891 }
892
893 if (dumpInitialConditions)
894 {
895 // dump initial conditions to file
896 std::string outname = m_sessionName + "_initial.chk";
897 WriteFld(outname);
898 }
899}
900
902{
903 int nq = m_fields[0]->GetNpoints();
904
905 NekDouble dist, m_radius_limit;
906
910
911 m_fields[0]->GetCoords(x, y, z);
912
913 // Sets of parameters
914 m_radius_limit = 0.5;
915
916 NekDouble x0j, x1j;
917 outfield = Array<OneD, NekDouble>(nq, 0.0);
918 for (int j = 0; j < nq; ++j)
919 {
920 x0j = x[j];
921 x1j = y[j];
922
923 dist = sqrt(x0j * x0j + x1j * x1j);
924
925 if (dist < m_radius_limit)
926 {
927 outfield[j] = 0.5 * (1.0 + cos(m_pi * dist / m_radius_limit));
928 }
929 else
930 {
931 outfield[j] = 0.0;
932 }
933 }
934}
935
937{
938 int nq = m_fields[0]->GetNpoints();
939
940 NekDouble dist, radius, cosdiff, sin_theta, cos_theta, sin_varphi,
941 cos_varphi;
942 NekDouble m_theta_c, m_varphi_c, m_radius_limit, m_c0;
943
947
948 m_fields[0]->GetCoords(x, y, z);
949
950 // Sets of parameters
951 m_theta_c = 0.0;
952 m_varphi_c = 3.0 * m_pi / 2.0;
953 m_radius_limit = 7.0 * m_pi / 64.0;
954 m_c0 = 0.0;
955
956 NekDouble x0j, x1j, x2j;
957 outfield = Array<OneD, NekDouble>(nq, 0.0);
958 for (int j = 0; j < nq; ++j)
959 {
960 x0j = x[j];
961 x1j = y[j];
962 x2j = z[j];
963
964 radius = sqrt(x0j * x0j + x1j * x1j + x2j * x2j);
965
966 sin_varphi = x1j / sqrt(x0j * x0j + x1j * x1j);
967 cos_varphi = x0j / sqrt(x0j * x0j + x1j * x1j);
968
969 sin_theta = x2j / radius;
970 cos_theta = sqrt(x0j * x0j + x1j * x1j) / radius;
971
972 cosdiff = cos_varphi * cos(m_varphi_c) + sin_varphi * sin(m_varphi_c);
973 dist = radius * acos(sin(m_theta_c) * sin_theta +
974 cos(m_theta_c) * cos_theta * cosdiff);
975
976 if (dist < m_radius_limit)
977 {
978 outfield[j] =
979 0.5 * (1.0 + cos(m_pi * dist / m_radius_limit)) + m_c0;
980 }
981 else
982 {
983 outfield[j] = m_c0;
984 }
985 }
986}
987
989 Array<OneD, NekDouble> &outfield)
990{
991 int nq = m_fields[0]->GetNpoints();
992
996
997 m_fields[0]->GetCoords(x0, x1, x2);
998
1000
1001 for (int i = 0; i < nq; ++i)
1002 {
1003 u[i] = cos(m_pi * (x0[i] - m_advx * time)) *
1004 cos(m_pi * (x1[i] - m_advy * time));
1005 }
1006
1007 outfield = u;
1008}
1009
1011 Array<OneD, NekDouble> &outfield)
1012{
1013 int nq = m_fields[0]->GetNpoints();
1014
1018
1019 m_fields[0]->GetCoords(x0, x1, x2);
1020
1022
1023 for (int i = 0; i < nq; ++i)
1024 {
1025 u[i] = cos(m_pi * (x0[i] - m_advx * time)) *
1026 cos(m_pi * (x1[i] - m_advy * time)) *
1027 cos(m_pi * (x2[i] - m_advz * time));
1028 }
1029
1030 outfield = u;
1031}
1032
1034{
1035 int nq = m_fields[0]->GetNpoints();
1036
1037 Array<OneD, NekDouble> velcoeff(nq, 0.0);
1038
1039 Array<OneD, NekDouble> Dtmp0(nq);
1040 Array<OneD, NekDouble> Dtmp1(nq);
1041 Array<OneD, NekDouble> Dtmp2(nq);
1042 Array<OneD, NekDouble> Drv(nq);
1043
1044 vellc = Array<OneD, NekDouble>(nq, 0.0);
1045
1046 // m_vellc = \nabla m_vel \cdot tan_i
1047 Array<OneD, NekDouble> tmp(nq);
1048 Array<OneD, NekDouble> vessel(nq);
1049
1050 for (int j = 0; j < m_shapedim; ++j)
1051 {
1052 Vmath::Zero(nq, velcoeff, 1);
1053 for (int k = 0; k < m_spacedim; ++k)
1054 {
1055 // a_j = tan_j cdot m_vel
1056 Vmath::Vvtvp(nq, &m_movingframes[j][k * nq], 1, &m_velocity[k][0],
1057 1, &velcoeff[0], 1, &velcoeff[0], 1);
1058 }
1059
1060 // d a_j / d x^k
1061 m_fields[0]->PhysDeriv(velcoeff, Dtmp0, Dtmp1, Dtmp2);
1062
1063 for (int k = 0; k < m_spacedim; ++k)
1064 {
1065 // tan_j^k ( d a_j / d x^k )
1066 switch (k)
1067 {
1068 case (0):
1069 {
1070 Vmath::Vvtvp(nq, &Dtmp0[0], 1, &m_movingframes[j][k * nq],
1071 1, &vellc[0], 1, &vellc[0], 1);
1072 }
1073 break;
1074
1075 case (1):
1076 {
1077 Vmath::Vvtvp(nq, &Dtmp1[0], 1, &m_movingframes[j][k * nq],
1078 1, &vellc[0], 1, &vellc[0], 1);
1079 }
1080 break;
1081
1082 case (2):
1083 {
1084 Vmath::Vvtvp(nq, &Dtmp2[0], 1, &m_movingframes[j][k * nq],
1085 1, &vellc[0], 1, &vellc[0], 1);
1086 }
1087 break;
1088 }
1089 }
1090 }
1091}
1092
1094 Array<OneD, Array<OneD, NekDouble>> &veldotMF)
1095{
1096 int nq = m_fields[0]->GetNpoints();
1097
1099
1100 Array<OneD, NekDouble> magMF(nq);
1101 for (int j = 0; j < m_shapedim; ++j)
1102 {
1103 veldotMF[j] = Array<OneD, NekDouble>(nq, 0.0);
1104
1105 for (int k = 0; k < m_spacedim; ++k)
1106 {
1107 Vmath::Vvtvp(nq, &m_movingframes[j][k * nq], 1, &m_velocity[k][0],
1108 1, &veldotMF[j][0], 1, &veldotMF[j][0], 1);
1109 }
1110 }
1111}
1112
1113void MMFAdvection::v_EvaluateExactSolution([[maybe_unused]] unsigned int field,
1114 Array<OneD, NekDouble> &outfield,
1115 const NekDouble time)
1116{
1117 switch (m_TestType)
1118 {
1119 case eAdvectionBell:
1120 {
1121 AdvectionBellSphere(outfield);
1122 }
1123 break;
1124
1125 case eTestPlane:
1126 {
1127 Test2Dproblem(time, outfield);
1128 }
1129 break;
1130
1132 {
1133 AdvectionBellPlane(outfield);
1134 }
1135 break;
1136
1137 case eTestCube:
1138 {
1139 Test3Dproblem(time, outfield);
1140 }
1141 break;
1142
1143 default:
1144 break;
1145 }
1146}
1147
1149{
1152 SolverUtils::AddSummaryItem(s, "Rotation Angle", m_RotAngle);
1153}
1154} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:242
@ eTestPlaneMassConsv
Definition: MMFAdvection.h:46
@ eAdvectionBell
Definition: MMFAdvection.h:48
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
void DefineProjection(FuncPointerT func, ObjectPointerT obj)
void DefineOdeRhs(FuncPointerT func, ObjectPointerT obj)
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:65
void Test2Dproblem(const NekDouble time, Array< OneD, NekDouble > &outfield)
void GetFluxVector(const Array< OneD, Array< OneD, NekDouble > > &physfield, Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &flux)
Evaluate the flux at each solution point.
Array< OneD, Array< OneD, NekDouble > > m_veldotMF
Definition: MMFAdvection.h:98
void DoOdeProjection(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Compute the projection.
void Test3Dproblem(const NekDouble time, Array< OneD, NekDouble > &outfield)
void AdvectionBellSphere(Array< OneD, NekDouble > &outfield)
NekDouble ComputeCirculatingArclength(const NekDouble zlevel, const NekDouble Rhs)
MMFAdvection(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Session reader.
void WeakDGDirectionalAdvection(const Array< OneD, Array< OneD, NekDouble > > &InField, Array< OneD, Array< OneD, NekDouble > > &OutField)
void DoOdeRhs(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Compute the RHS.
void ComputeNablaCdotVelocity(Array< OneD, NekDouble > &vellc)
void ComputeveldotMF(Array< OneD, Array< OneD, NekDouble > > &veldotMF)
void v_SetInitialConditions(const NekDouble initialtime, bool dumpInitialConditions, const int domain) override
void EvaluateAdvectionVelocity(Array< OneD, Array< OneD, NekDouble > > &velocity)
static SolverUtils::EquationSystemSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
Definition: MMFAdvection.h:68
void v_GenerateSummary(SolverUtils::SummaryList &s) override
Print Summary.
void v_InitObject(bool DeclareFields=true) override
Initialise the object.
SolverUtils::RiemannSolverSharedPtr m_riemannSolver
Definition: MMFAdvection.h:86
void v_EvaluateExactSolution(unsigned int field, Array< OneD, NekDouble > &outfield, const NekDouble time) override
Array< OneD, Array< OneD, NekDouble > > m_velocity
Advection velocity.
Definition: MMFAdvection.h:95
Array< OneD, NekDouble > & GetNormalVelocity()
Get the normal velocity.
void v_DoSolve() override
Solves an unsteady problem.
static std::string className
Name of class.
Definition: MMFAdvection.h:78
Array< OneD, NekDouble > m_vellc
Definition: MMFAdvection.h:99
void AdvectionBellPlane(Array< OneD, NekDouble > &outfield)
Array< OneD, NekDouble > m_traceVn
Definition: MMFAdvection.h:96
A base class for PDEs which include an advection component.
SolverUtils::AdvectionSharedPtr m_advObject
Advection term.
int m_spacedim
Spatial dimension (>= expansion dim).
SOLVER_UTILS_EXPORT int GetTraceNpoints()
NekDouble m_timestep
Time step size.
int m_infosteps
Number of time steps between outputting status information.
NekDouble m_time
Current time of simulation.
Array< OneD, MultiRegions::ExpListSharedPtr > m_fields
Array holding all dependent variables.
NekDouble m_fintime
Finish time of the simulation.
SOLVER_UTILS_EXPORT void Checkpoint_Output(const int n)
Write checkpoint file of m_fields.
NekDouble m_checktime
Time between checkpoints.
SOLVER_UTILS_EXPORT void WriteFld(const std::string &outname)
Write field data to the given filename.
std::string m_sessionName
Name of the session.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
Array< OneD, Array< OneD, NekDouble > > m_traceNormals
Array holding trace normals for DG simulations in the forwards direction.
SOLVER_UTILS_EXPORT int GetNpoints()
SOLVER_UTILS_EXPORT int GetNcoeffs()
enum MultiRegions::ProjectionType m_projectionType
Type of projection; e.g continuous or discontinuous.
int m_steps
Number of steps to take.
SOLVER_UTILS_EXPORT void SetBoundaryConditions(NekDouble time)
Evaluates the boundary conditions at the given time.
int m_checksteps
Number of steps between checkpoints.
SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(std::string name, const MultiRegions::ExpListSharedPtr &field=MultiRegions::NullExpListSharedPtr, bool cache=false)
Get a SessionFunction by name.
A base class for PDEs which include an advection component.
Definition: MMFSystem.h:144
SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s) override
Virtual function for generating summary information.
Definition: MMFSystem.cpp:2463
SOLVER_UTILS_EXPORT void VectorCrossProd(const Array< OneD, const Array< OneD, NekDouble > > &v1, const Array< OneD, const Array< OneD, NekDouble > > &v2, Array< OneD, Array< OneD, NekDouble > > &v3)
Definition: MMFSystem.cpp:696
SOLVER_UTILS_EXPORT NekDouble AvgInt(const Array< OneD, const NekDouble > &inarray)
Definition: MMFSystem.cpp:2292
Array< OneD, Array< OneD, NekDouble > > m_movingframes
Definition: MMFSystem.h:183
SOLVER_UTILS_EXPORT void GramSchumitz(const Array< OneD, const Array< OneD, NekDouble > > &v1, const Array< OneD, const Array< OneD, NekDouble > > &v2, Array< OneD, Array< OneD, NekDouble > > &outarray, bool KeepTheMagnitude=true)
Definition: MMFSystem.cpp:2399
Array< OneD, Array< OneD, NekDouble > > m_ncdotMFBwd
Definition: MMFSystem.h:187
SOLVER_UTILS_EXPORT void ComputencdotMF()
Definition: MMFSystem.cpp:317
SOLVER_UTILS_EXPORT void CartesianToSpherical(const NekDouble x0j, const NekDouble x1j, const NekDouble x2j, NekDouble &sin_varphi, NekDouble &cos_varphi, NekDouble &sin_theta, NekDouble &cos_theta)
Definition: MMFSystem.cpp:792
SOLVER_UTILS_EXPORT NekDouble RootMeanSquare(const Array< OneD, const NekDouble > &inarray)
Definition: MMFSystem.cpp:2338
Array< OneD, Array< OneD, NekDouble > > m_ncdotMFFwd
Definition: MMFSystem.h:186
SOLVER_UTILS_EXPORT void MMFInitObject(const Array< OneD, const Array< OneD, NekDouble > > &Anisotropy, const int TangentXelem=-1)
Definition: MMFSystem.cpp:51
Base class for unsteady solvers.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
NekDouble m_cflSafetyFactor
CFL safety factor (comprise between 0 to 1).
LibUtilities::TimeIntegrationSchemeSharedPtr m_intScheme
Wrapper to the time integration scheme.
bool m_explicitAdvection
Indicates if explicit or implicit treatment of advection is used.
SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareField=true) override
Init object for UnsteadySystem class.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
const std::vector< NekDouble > velocity
static const NekDouble kNekZeroTol
AdvectionFactory & GetAdvectionFactory()
Gets the factory for initialising advection objects.
Definition: Advection.cpp:43
std::vector< std::pair< std::string, std::string > > SummaryList
Definition: Misc.h:46
EquationSystemFactory & GetEquationSystemFactory()
void AddSummaryItem(SummaryList &l, const std::string &name, const std::string &value)
Adds a summary item to the summary info list.
Definition: Misc.cpp:47
RiemannSolverFactory & GetRiemannSolverFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::vector< double > z(NPUPPER)
@ eTestPlane
Definition: MMFDiffusion.h:48
@ eTestCube
Definition: MMFDiffusion.h:49
@ SIZE_TestType
Length of enum list.
Definition: MMFDiffusion.h:55
const char *const TestTypeMap[]
Definition: MMFDiffusion.h:58
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 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
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294