Nektar++
DriverPFASST.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File DriverPFASST.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: Driver class for the PFASST solver
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <iomanip>
36
40#include <boost/format.hpp>
41
42namespace Nektar::SolverUtils
43{
44std::string DriverPFASST::className =
48
49/**
50 *
51 */
54 : DriverParallelInTime(pSession, pGraph)
55{
56}
57
58/**
59 *
60 */
61void DriverPFASST::v_InitObject(std::ostream &out)
62{
69}
70
71/**
72 *
73 */
74void DriverPFASST::v_Execute([[maybe_unused]] std::ostream &out)
75{
76 // Timing.
78 NekDouble totalTime = 0.0, predictorTime = 0.0, fineSolveTime = 0.0,
79 coarseSolveTime = 0.0, fasTime = 0.0;
80
81 // Initialie time step parameters.
82 size_t step = m_chunkRank;
86
87 // Start iteration windows.
88 m_comm->GetTimeComm()->Block();
89 for (size_t w = 0; w < m_numWindowsPIT; w++)
90 {
91 timer.Start();
92 PrintHeader((boost::format("WINDOWS #%1%") % (w + 1)).str(), '*');
93
94 // Compute initial guess for coarse solver.
98 for (size_t k = 0; k < m_chunkRank; k++)
99 {
104 }
106
107 // Interpolate coarse solution and residual to fine.
108 for (size_t timeLevel = m_nTimeLevel - 1; timeLevel > 0; timeLevel--)
109 {
110 InterpolateSolution(timeLevel);
111 InterpolateResidual(timeLevel);
112 }
113 timer.Stop();
114 predictorTime += timer.Elapsed().count();
115 totalTime += timer.Elapsed().count();
116
117 // Start CorrectInitialPFASST iteration.
118 size_t k = 0;
119 int convergenceCurr = 0;
120 std::vector<int> convergencePrev(m_nTimeLevel, m_chunkRank == 0);
121 while (k < m_iterMaxPIT && !convergenceCurr)
122 {
123 // The PFASST implementation follow "Bolten, M., Moser, D., & Speck,
124 // R. (2017). A multigrid perspective on the parallel full
125 // approximation scheme in space and time. Numerical Linear Algebra
126 // with Applications, 24(6)".
127
128 if (m_chunkRank == m_numChunks - 1 &&
129 m_comm->GetSpaceComm()->GetRank() == 0)
130 {
131 std::cout << "Iteration " << k + 1 << std::endl << std::flush;
132 }
133
134 // Performe sweep (parallel-in-time).
135 timer.Start();
136 RunSweep(m_time, 0, true);
137 timer.Stop();
138 fineSolveTime += timer.Elapsed().count();
139 totalTime += timer.Elapsed().count();
140
141 // Fine-to-coarse
142 timer.Start();
143 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel - 1;
144 timeLevel++)
145 {
146 // Performe sweep (parallel-in-time).
147 if (timeLevel != 0)
148 {
149 RunSweep(m_time, timeLevel, true);
150 }
151
152 // Compute FAS correction (parallel-in-time).
153 RestrictSolution(timeLevel);
154 RestrictResidual(timeLevel);
155 IntegratedResidualEval(timeLevel);
156 IntegratedResidualEval(timeLevel + 1);
157 ComputeFASCorrection(timeLevel + 1);
158
159 // Check convergence.
160 if (timeLevel == 0)
161 {
162 // Evaluate SDC residual norm.
163 EvaluateSDCResidualNorm(timeLevel);
164
165 // Display L2norm.
166 PrintErrorNorm(timeLevel, true);
167 }
168 }
169 timer.Stop();
170 fasTime += timer.Elapsed().count();
171 totalTime += timer.Elapsed().count();
172
173 // Perform coarse sweep (serial-in-time).
174 timer.Start();
176 ->UpdateFirstQuadratureSolutionVector(),
177 convergencePrev[m_nTimeLevel - 1]);
178 timer.Stop();
179 totalTime += timer.Elapsed().count();
180 timer.Start();
181 RunSweep(m_time, m_nTimeLevel - 1, true);
182 timer.Stop();
183 coarseSolveTime += timer.Elapsed().count();
184 totalTime += timer.Elapsed().count();
185 convergenceCurr = (vL2ErrorMax() < m_tolerPIT &&
186 convergencePrev[m_nTimeLevel - 1]);
187 timer.Start();
189 ->UpdateLastQuadratureSolutionVector(),
190 convergenceCurr);
191 timer.Stop();
192 totalTime += timer.Elapsed().count();
193
194 // Coarse-to-fine.
195 timer.Start();
196 for (size_t timeLevel = m_nTimeLevel - 1; timeLevel > 0;
197 timeLevel--)
198 {
199 // Correct solution and residual.
200 /*SendToNextProc(m_SDCSolver[timeLevel - 1]
201 ->UpdateLastQuadratureSolutionVector(),
202 convergenceCurr);*/
203 CorrectSolution(timeLevel - 1);
204 CorrectResidual(timeLevel - 1);
205 /*RecvFromPreviousProc(
206 m_SDCSolver[timeLevel - 1]
207 ->UpdateFirstQuadratureSolutionVector(),
208 convergencePrev[timeLevel - 1]);
209 CorrectInitialSolution(timeLevel - 1);*/
210 if (timeLevel - 1 != 0)
211 {
212 RunSweep(m_time, timeLevel - 1, true);
213 }
214 }
215 timer.Stop();
216 fasTime += timer.Elapsed().count();
217 totalTime += timer.Elapsed().count();
218 k++;
219 }
220
221 // Apply windowing.
222 timer.Start();
223 if (w < m_numWindowsPIT - 1)
224 {
226 }
227 timer.Stop();
228 totalTime += timer.Elapsed().count();
229
230 // Update field and write output.
231 WriteOutput(step, m_time);
232 if (m_chunkRank == m_numChunks - 1 &&
233 m_comm->GetSpaceComm()->GetRank() == 0)
234 {
235 std::cout << "Total Computation Time : " << totalTime << "s"
236 << std::endl
237 << std::flush;
238 std::cout << " - Predictor Time = " << predictorTime << "s"
239 << std::endl
240 << std::flush;
241 std::cout << " - Coarse Solve Time = " << coarseSolveTime << "s"
242 << std::endl
243 << std::flush;
244 std::cout << " - Fine Solve Time = " << fineSolveTime << "s"
245 << std::endl
246 << std::flush;
247 std::cout << " - FAS Correction Time = " << fasTime << "s"
248 << std::endl
249 << std::flush;
250 }
251 step += m_numChunks;
252 }
253
254 m_comm->GetTimeComm()->Block();
255 PrintHeader("SUMMARY", '*');
258 if (m_chunkRank == m_numChunks - 1 &&
259 m_comm->GetSpaceComm()->GetRank() == 0)
260 {
261 std::cout << "Total Computation Time : " << totalTime << "s"
262 << std::endl
263 << std::flush;
264 std::cout << " - Predictor Time = " << predictorTime << "s" << std::endl
265 << std::flush;
266 std::cout << " - Coarse Solve Time = " << coarseSolveTime << "s"
267 << std::endl
268 << std::flush;
269 std::cout << " - Fine Solve Time = " << fineSolveTime << "s"
270 << std::endl
271 << std::flush;
272 std::cout << " - FAS Correction Time = " << fasTime << "s" << std::endl
273 << std::flush;
274 }
275}
276
277/**
278 *
279 */
281{
282 // Assert time-stepping parameters.
283 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel; timeLevel++)
284 {
285 ASSERTL0(
286 m_nsteps[timeLevel] % m_numChunks == 0,
287 "Total number of steps should be divisible by number of chunks.");
288
289 ASSERTL0(m_timestep[0] == m_timestep[timeLevel],
290 "All SDC levels should have the same timestep");
291
292 ASSERTL0(m_nsteps[0] == m_nsteps[timeLevel],
293 "All SDC levels should have the same timestep");
294 }
295
296 // Assert I/O parameters.
297 if (m_EqSys[0]->GetCheckpointSteps())
298 {
299 ASSERTL0(m_nsteps[0] % m_EqSys[0]->GetCheckpointSteps() == 0,
300 "number of IO_CheckSteps should divide number of steps "
301 "per time chunk");
302 }
303
304 if (m_EqSys[0]->GetInfoSteps())
305 {
306 ASSERTL0(m_nsteps[0] % m_EqSys[0]->GetInfoSteps() == 0,
307 "number of IO_InfoSteps should divide number of steps "
308 "per time chunk");
309 }
310}
311
312/**
313 *
314 */
316{
320 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel; timeLevel++)
321 {
322 // Cast pointer for TimeIntegrationSchemeSDC.
323 m_SDCSolver[timeLevel] =
324 std::dynamic_pointer_cast<LibUtilities::TimeIntegrationSchemeSDC>(
325 m_EqSys[timeLevel]->GetTimeIntegrationScheme());
326
327 // Assert if a SDC time-integration is used.
328 ASSERTL0(m_SDCSolver[timeLevel] != nullptr,
329 "Should only be run with a SDC method");
330
331 // Order storage to list time-integrated fields first.
333 for (size_t i = 0; i < m_nVar; ++i)
334 {
335 fields[i] = m_EqSys[timeLevel]->UpdatePhysField(i);
336 }
337
338 // Initialize SDC scheme.
339 m_SDCSolver[timeLevel]->SetPFASST(timeLevel != 0);
340 m_SDCSolver[timeLevel]->InitializeScheme(
341 m_timestep[timeLevel], fields, 0.0,
342 m_EqSys[timeLevel]->GetTimeIntegrationSchemeOperators());
343 }
344
345 // Alocate memory.
347 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel; timeLevel++)
348 {
349 m_QuadPts[timeLevel] = m_SDCSolver[timeLevel]->GetQuadPtsNumber();
350 }
351
357 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel - 1; timeLevel++)
358 {
359 m_solutionRest[timeLevel] = SDCarray(m_QuadPts[timeLevel + 1]);
360 m_residualRest[timeLevel] = SDCarray(m_QuadPts[timeLevel + 1]);
361 m_integralRest[timeLevel] = SDCarray(m_QuadPts[timeLevel + 1]);
362 m_correction[timeLevel] = SDCarray(m_QuadPts[timeLevel + 1]);
363 m_storage[timeLevel] = SDCarray(m_QuadPts[timeLevel + 1]);
364 for (size_t n = 0; n < m_QuadPts[timeLevel + 1]; ++n)
365 {
366 m_solutionRest[timeLevel][n] =
368 m_residualRest[timeLevel][n] =
370 m_integralRest[timeLevel][n] =
372 m_correction[timeLevel][n] =
374 m_storage[timeLevel][n] =
376 for (size_t i = 0; i < m_nVar; ++i)
377 {
378 m_solutionRest[timeLevel][n][i] =
379 Array<OneD, NekDouble>(m_npts[timeLevel + 1], 0.0);
380 m_residualRest[timeLevel][n][i] =
381 Array<OneD, NekDouble>(m_npts[timeLevel + 1], 0.0);
382 m_integralRest[timeLevel][n][i] =
383 Array<OneD, NekDouble>(m_npts[timeLevel + 1], 0.0);
384 m_correction[timeLevel][n][i] =
385 Array<OneD, NekDouble>(m_npts[timeLevel + 1], 0.0);
386 m_storage[timeLevel][n][i] =
387 Array<OneD, NekDouble>(m_npts[timeLevel], 0.0);
388 }
389 }
390 }
391}
392
393/**
394 *
395 */
397{
398 // Initialize time interpolator.
401 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel - 1; timeLevel++)
402 {
404 m_SDCSolver[timeLevel]->GetPointsKey();
406 m_SDCSolver[timeLevel + 1]->GetPointsKey();
407 DNekMatSharedPtr ImatFtoC =
408 LibUtilities::PointsManager()[fpoints]->GetI(cpoints);
409 DNekMatSharedPtr ImatCtoF =
410 LibUtilities::PointsManager()[cpoints]->GetI(fpoints);
412 m_QuadPts[timeLevel] * m_QuadPts[timeLevel + 1], 0.0);
414 m_QuadPts[timeLevel] * m_QuadPts[timeLevel + 1], 0.0);
415
416 // Determine if Radau quadrature are used.
417 size_t i0 = m_SDCSolver[timeLevel]->HasFirstQuadrature() ? 0 : 1;
418 size_t j0 = m_SDCSolver[timeLevel + 1]->HasFirstQuadrature() ? 0 : 1;
419
420 // Adapt fine to coarse time interpolator.
421 for (size_t i = i0; i < m_QuadPts[timeLevel]; ++i)
422 {
423 for (size_t j = j0; j < m_QuadPts[timeLevel + 1]; ++j)
424 {
425 m_ImatFtoC[timeLevel][i * m_QuadPts[timeLevel + 1] + j] =
426 (ImatFtoC->GetPtr())[(i - i0) *
427 (m_QuadPts[timeLevel + 1] - j0) +
428 (j - j0)];
429 }
430 }
431 if (j0 == 1)
432 {
433 m_ImatFtoC[timeLevel][0] = 1.0;
434 }
435
436 // Adapt coarse to fine time interpolator.
437 for (size_t j = j0; j < m_QuadPts[timeLevel + 1]; ++j)
438 {
439 for (size_t i = i0; i < m_QuadPts[timeLevel]; ++i)
440 {
441 m_ImatCtoF[timeLevel][j * m_QuadPts[timeLevel] + i] =
442 (ImatCtoF
443 ->GetPtr())[(j - j0) * (m_QuadPts[timeLevel] - i0) +
444 (i - i0)];
445 }
446 }
447 if (i0 == 1)
448 {
449 m_ImatCtoF[timeLevel][0] = 1.0;
450 }
451 }
452}
453
454/**
455 *
456 */
458{
459 return !(n == 0 && m_chunkRank == 0);
460}
461
462/**
463 *
464 */
466 const size_t timeLevel, const size_t index)
467{
468 for (size_t n = 0; n < m_QuadPts[timeLevel]; ++n)
469 {
470 if (n != index)
471 {
472 for (size_t i = 0; i < m_nVar; ++i)
473 {
475 m_npts[timeLevel],
476 m_SDCSolver[timeLevel]->GetSolutionVector()[index][i], 1,
477 m_SDCSolver[timeLevel]->UpdateSolutionVector()[n][i], 1);
479 m_npts[timeLevel],
480 m_SDCSolver[timeLevel]->GetResidualVector()[index][i], 1,
481 m_SDCSolver[timeLevel]->UpdateResidualVector()[n][i], 1);
482 }
483 }
484 }
485}
486
487/**
488 *
489 */
490void DriverPFASST::UpdateFirstQuadrature(const size_t timeLevel)
491{
492 m_SDCSolver[timeLevel]->UpdateFirstQuadrature();
493}
494
495/**
496 *
497 */
498void DriverPFASST::RunSweep(const NekDouble time, const size_t timeLevel,
499 const bool update)
500{
501 size_t niter = m_SDCSolver[timeLevel]->GetOrder();
502
503 if (update == true)
504 {
505 ResidualEval(m_time, timeLevel, 0);
506 }
507
508 // Start SDC iteration loop.
509 m_SDCSolver[timeLevel]->SetTime(time);
510 for (size_t k = 0; k < niter; k++)
511 {
512 m_SDCSolver[timeLevel]->SDCIterationLoop(m_chunkTime);
513 }
514
515 // Update last quadrature point.
516 m_SDCSolver[timeLevel]->UpdateLastQuadrature();
517}
518
519/**
520 *
521 */
522void DriverPFASST::ResidualEval(const NekDouble time, const size_t timeLevel,
523 const size_t n)
524{
525 m_SDCSolver[timeLevel]->SetTime(time);
526 m_SDCSolver[timeLevel]->ResidualEval(m_chunkTime, n);
527}
528
529/**
530 *
531 */
532void DriverPFASST::ResidualEval(const NekDouble time, const size_t timeLevel)
533{
534 m_SDCSolver[timeLevel]->SetTime(time);
535 m_SDCSolver[timeLevel]->ResidualEval(m_chunkTime);
536}
537
538/**
539 *
540 */
541void DriverPFASST::IntegratedResidualEval(const size_t timeLevel)
542{
543 m_SDCSolver[timeLevel]->UpdateIntegratedResidualQFint(m_chunkTime);
544}
545
546/**
547 *
548 */
549void DriverPFASST::Interpolate(const size_t coarseLevel, const SDCarray &in,
550 const size_t fineLevel, SDCarray &out,
551 bool forced)
552{
553 // Interpolate solution in space.
554 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
555 {
556 Interpolate(m_EqSys[coarseLevel]->UpdateFields(),
557 m_EqSys[fineLevel]->UpdateFields(), in[n],
558 m_storage[fineLevel][n]);
559 }
560
561 // Interpolate solution in time.
562 for (size_t n = 0; n < m_QuadPts[fineLevel]; ++n)
563 {
564 if (forced || IsNotInitialCondition(n))
565 {
566 for (size_t i = 0; i < m_nVar; ++i)
567 {
568 Vmath::Smul(m_npts[fineLevel], m_ImatCtoF[fineLevel][n],
569 m_storage[fineLevel][0][i], 1, out[n][i], 1);
570 for (size_t k = 1; k < m_QuadPts[coarseLevel]; ++k)
571 {
572 size_t index = k * m_QuadPts[fineLevel] + n;
573 Vmath::Svtvp(m_npts[fineLevel],
574 m_ImatCtoF[fineLevel][index],
575 m_storage[fineLevel][k][i], 1, out[n][i], 1,
576 out[n][i], 1);
577 }
578 }
579 }
580 }
581}
582
583/**
584 *
585 */
586void DriverPFASST::InterpolateSolution(const size_t timeLevel)
587{
588 size_t coarseLevel = timeLevel;
589 size_t fineLevel = timeLevel - 1;
590
591 Interpolate(coarseLevel, m_SDCSolver[coarseLevel]->GetSolutionVector(),
592 fineLevel, m_SDCSolver[fineLevel]->UpdateSolutionVector(),
593 false);
594}
595
596/**
597 *
598 */
599void DriverPFASST::InterpolateResidual(const size_t timeLevel)
600{
601 size_t coarseLevel = timeLevel;
602 size_t fineLevel = timeLevel - 1;
603
604 Interpolate(coarseLevel, m_SDCSolver[coarseLevel]->GetResidualVector(),
605 fineLevel, m_SDCSolver[fineLevel]->UpdateResidualVector(),
606 true);
607}
608
609/**
610 *
611 */
612void DriverPFASST::Restrict(const size_t fineLevel, const SDCarray &in,
613 const size_t coarseLevel, SDCarray &out)
614{
615 // Restrict fine solution in time.
616 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
617 {
618 for (size_t i = 0; i < m_nVar; ++i)
619 {
620 Vmath::Smul(m_npts[fineLevel], m_ImatFtoC[fineLevel][n], in[0][i],
621 1, m_storage[fineLevel][n][i], 1);
622 for (size_t k = 1; k < m_QuadPts[fineLevel]; ++k)
623 {
624 size_t index = k * m_QuadPts[coarseLevel] + n;
625 Vmath::Svtvp(m_npts[fineLevel], m_ImatFtoC[fineLevel][index],
626 in[k][i], 1, m_storage[fineLevel][n][i], 1,
627 m_storage[fineLevel][n][i], 1);
628 }
629 }
630 }
631
632 // Restrict fine solution in space.
633 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
634 {
635 Interpolate(m_EqSys[fineLevel]->UpdateFields(),
636 m_EqSys[coarseLevel]->UpdateFields(),
637 m_storage[fineLevel][n], out[n]);
638 }
639}
640
641/**
642 *
643 */
644void DriverPFASST::RestrictSolution(const size_t timeLevel)
645{
646 size_t fineLevel = timeLevel;
647 size_t coarseLevel = timeLevel + 1;
648
649 Restrict(fineLevel, m_SDCSolver[fineLevel]->GetSolutionVector(),
650 coarseLevel, m_SDCSolver[coarseLevel]->UpdateSolutionVector());
651
652 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
653 {
654 CopySolutionVector(m_SDCSolver[coarseLevel]->GetSolutionVector()[n],
655 m_solutionRest[fineLevel][n]);
656 }
657}
658
659/**
660 *
661 */
662void DriverPFASST::RestrictResidual(const size_t timeLevel)
663{
664 size_t fineLevel = timeLevel;
665 size_t coarseLevel = timeLevel + 1;
666
667 ResidualEval(m_time, coarseLevel);
668
669 if (!m_updateResidual)
670 {
671 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
672 {
673 CopySolutionVector(m_SDCSolver[coarseLevel]->GetResidualVector()[n],
674 m_residualRest[fineLevel][n]);
675 }
676 }
677}
678
679/**
680 *
681 */
682void DriverPFASST::ComputeFASCorrection(const size_t timeLevel)
683{
684 size_t fineLevel = timeLevel - 1;
685 size_t coarseLevel = timeLevel;
686
687 if (fineLevel != 0)
688 {
689 // Restrict fine FAS correction term
690 Restrict(fineLevel, m_SDCSolver[fineLevel]->UpdateFAScorrectionVector(),
691 coarseLevel,
692 m_SDCSolver[coarseLevel]->UpdateFAScorrectionVector());
693
694 // Restrict fine integrated residual.
695 Restrict(fineLevel,
696 m_SDCSolver[fineLevel]->GetIntegratedResidualVector(),
697 coarseLevel, m_integralRest[fineLevel]);
698 }
699 else
700 {
701 // Restrict fine integrated residual.
702 Restrict(
703 fineLevel, m_SDCSolver[fineLevel]->GetIntegratedResidualVector(),
704 coarseLevel, m_SDCSolver[coarseLevel]->UpdateFAScorrectionVector());
705 }
706
707 // Compute coarse FAS correction terms.
708 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
709 {
710 for (size_t i = 0; i < m_nVar; ++i)
711 {
712 if (fineLevel != 0)
713 {
715 m_npts[coarseLevel],
716 m_SDCSolver[coarseLevel]->GetFAScorrectionVector()[n][i], 1,
717 m_integralRest[fineLevel][n][i], 1,
718 m_SDCSolver[coarseLevel]->UpdateFAScorrectionVector()[n][i],
719 1);
720 }
721
723 m_npts[coarseLevel],
724 m_SDCSolver[coarseLevel]->GetFAScorrectionVector()[n][i], 1,
725 m_SDCSolver[coarseLevel]->GetIntegratedResidualVector()[n][i],
726 1, m_SDCSolver[coarseLevel]->UpdateFAScorrectionVector()[n][i],
727 1);
728 }
729 }
730}
731
732/**
733 *
734 */
735void DriverPFASST::Correct(const size_t coarseLevel,
737 const size_t fineLevel,
739 bool forced)
740{
741 if (forced || IsNotInitialCondition(0))
742 {
743 // Compute difference between coarse solution and restricted
744 // solution.
745 Interpolate(m_EqSys[fineLevel]->UpdateFields(),
746 m_EqSys[coarseLevel]->UpdateFields(), out,
747 m_correction[fineLevel][0]);
748 for (size_t i = 0; i < m_nVar; ++i)
749 {
750 Vmath::Vsub(m_npts[coarseLevel], in[i], 1,
751 m_correction[fineLevel][0][i], 1,
752 m_correction[fineLevel][0][i], 1);
753 }
754
755 // Add correction to fine solution.
756 Interpolate(m_EqSys[coarseLevel]->UpdateFields(),
757 m_EqSys[fineLevel]->UpdateFields(),
758 m_correction[fineLevel][0], m_storage[fineLevel][0]);
759 for (size_t i = 0; i < m_nVar; ++i)
760 {
761 Vmath::Vadd(m_npts[fineLevel], m_storage[fineLevel][0][i], 1,
762 out[i], 1, out[i], 1);
763 }
764 }
765}
766
767/**
768 *
769 */
770void DriverPFASST::CorrectInitialSolution(const size_t timeLevel)
771{
772 size_t fineLevel = timeLevel;
773 size_t coarseLevel = timeLevel + 1;
774
775 Correct(coarseLevel, m_SDCSolver[coarseLevel]->GetSolutionVector()[0],
776 fineLevel, m_SDCSolver[fineLevel]->UpdateSolutionVector()[0],
777 false);
778}
779
780/**
781 *
782 */
783void DriverPFASST::CorrectInitialResidual(const size_t timeLevel)
784{
785 size_t fineLevel = timeLevel;
786 size_t coarseLevel = timeLevel + 1;
787
788 Correct(coarseLevel, m_SDCSolver[coarseLevel]->GetResidualVector()[0],
789 fineLevel, m_SDCSolver[fineLevel]->UpdateResidualVector()[0],
790 false);
791}
792
793/**
794 *
795 */
796void DriverPFASST::Correct(const size_t coarseLevel, const SDCarray &rest,
797 const SDCarray &in, const size_t fineLevel,
798 SDCarray &out, bool forced)
799{
800 // Compute difference between coarse solution and restricted
801 // solution.
802 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
803 {
804 if (forced || IsNotInitialCondition(n))
805 {
806 for (size_t i = 0; i < m_nVar; ++i)
807 {
808 Vmath::Vsub(m_npts[coarseLevel], in[n][i], 1, rest[n][i], 1,
809 m_correction[fineLevel][n][i], 1);
810 }
811 }
812 else
813 {
814 for (size_t i = 0; i < m_nVar; ++i)
815 {
816 Vmath::Zero(m_npts[coarseLevel], m_correction[fineLevel][n][i],
817 1);
818 }
819 }
820 }
821
822 // Interpolate coarse solution delta in space.
823 for (size_t n = 0; n < m_QuadPts[coarseLevel]; ++n)
824 {
825 Interpolate(m_EqSys[coarseLevel]->UpdateFields(),
826 m_EqSys[fineLevel]->UpdateFields(),
827 m_correction[fineLevel][n], m_storage[fineLevel][n]);
828 }
829
830 // Interpolate coarse solution delta in time and correct fine solution.
831 for (size_t n = 0; n < m_QuadPts[fineLevel]; ++n)
832 {
833 if (forced || IsNotInitialCondition(n))
834 {
835 for (size_t i = 0; i < m_nVar; ++i)
836 {
837 for (size_t k = 0; k < m_QuadPts[coarseLevel]; ++k)
838 {
839 size_t index = k * m_QuadPts[fineLevel] + n;
840 Vmath::Svtvp(m_npts[fineLevel],
841 m_ImatCtoF[fineLevel][index],
842 m_storage[fineLevel][k][i], 1, out[n][i], 1,
843 out[n][i], 1);
844 }
845 }
846 }
847 }
848}
849
850/**
851 *
852 */
853void DriverPFASST::CorrectSolution(const size_t timeLevel)
854{
855 size_t coarseLevel = timeLevel + 1;
856 size_t fineLevel = timeLevel;
857
858 Correct(coarseLevel, m_solutionRest[fineLevel],
859 m_SDCSolver[coarseLevel]->GetSolutionVector(), fineLevel,
860 m_SDCSolver[fineLevel]->UpdateSolutionVector(), false);
861}
862
863/**
864 *
865 */
866void DriverPFASST::CorrectResidual(const size_t timeLevel)
867{
868 size_t coarseLevel = timeLevel + 1;
869 size_t fineLevel = timeLevel;
870
871 // Evaluate fine residual.
873 {
874 for (size_t n = 1; n < m_QuadPts[fineLevel]; ++n)
875 {
876 ResidualEval(fineLevel, n);
877 }
878 }
879 // Correct fine residual.
880 else
881 {
882 Correct(coarseLevel, m_residualRest[fineLevel],
883 m_SDCSolver[coarseLevel]->GetResidualVector(), fineLevel,
884 m_SDCSolver[fineLevel]->UpdateResidualVector(), false);
885 }
886}
887
888/**
889 *
890 */
892{
893 // Use last chunk solution as initial condition for the next window.
894 if (m_chunkRank == m_numChunks - 1)
895 {
897 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel - 1; timeLevel++)
898 {
899 Interpolate(m_EqSys[timeLevel]->UpdateFields(),
900 m_EqSys[timeLevel + 1]->UpdateFields(),
901 m_SDCSolver[timeLevel]->GetSolutionVector()[0],
902 m_SDCSolver[timeLevel + 1]->UpdateSolutionVector()[0]);
903 }
904 }
905
906 // Broadcast I.C. for windowing.
907 for (size_t timeLevel = 0; timeLevel < m_nTimeLevel; timeLevel++)
908 {
909 for (size_t i = 0; i < m_nVar; ++i)
910 {
911 m_comm->GetTimeComm()->Bcast(
912 m_SDCSolver[timeLevel]->UpdateSolutionVector()[0][i],
913 m_numChunks - 1);
914 }
915 }
916}
917
918/**
919 *
920 */
921void DriverPFASST::EvaluateSDCResidualNorm(const size_t timeLevel)
922{
923 // Compute SDC residual norm
924 for (size_t i = 0; i < m_nVar; ++i)
925 {
927 m_npts[timeLevel],
928 m_SDCSolver[timeLevel]->GetSolutionVector()[0][i], 1,
929 m_SDCSolver[timeLevel]
930 ->GetIntegratedResidualVector()[m_QuadPts[timeLevel] - 1][i],
931 1, m_exactsoln[i], 1);
932 m_EqSys[timeLevel]->CopyToPhysField(
933 i, m_SDCSolver[timeLevel]
934 ->GetSolutionVector()[m_QuadPts[timeLevel] - 1][i]);
935 m_vL2Errors[i] = m_EqSys[timeLevel]->L2Error(i, m_exactsoln[i], 1);
936 m_vLinfErrors[i] = m_EqSys[timeLevel]->LinfError(i, m_exactsoln[i]);
937 }
938}
939
940/**
941 *
942 */
943void DriverPFASST::WriteOutput(const size_t step, const NekDouble time)
944{
945 size_t timeLevel = 0;
946 size_t IOChkStep =
947 m_EqSys[timeLevel]->GetSession()->DefinesParameter("IO_CheckSteps")
948 ? m_EqSys[timeLevel]->GetSession()->GetParameter("IO_CheckSteps")
949 : 0;
950 IOChkStep = IOChkStep ? IOChkStep : m_nsteps[timeLevel];
951 static std::string dirname = m_session->GetSessionName() + ".pit";
952
953 if ((step + 1) % IOChkStep == 0)
954 {
955 // Compute checkpoint index.
956 size_t nchk = (step + 1) / IOChkStep;
957
958 // Create directory if does not exist.
959 if (!fs::is_directory(dirname))
960 {
961 fs::create_directory(dirname);
962 }
963
964 // Update solution field.
966 timeLevel,
967 m_SDCSolver[timeLevel]->UpdateLastQuadratureSolutionVector());
968
969 // Set filename.
970 std::string filename = dirname + "/" + m_session->GetSessionName() +
971 "_" + std::to_string(nchk) + ".fld";
972
973 // Set time metadata.
974 m_EqSys[timeLevel]->SetTime(time);
975
976 // Write checkpoint.
977 m_EqSys[timeLevel]->WriteFld(filename);
978 }
979}
980
981} // namespace Nektar::SolverUtils
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Defines a specification for a set of points.
Definition: Points.h:50
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
Definition: Driver.h:83
LibUtilities::CommSharedPtr m_comm
Communication object.
Definition: Driver.h:80
void RestrictResidual(const size_t timeLevel)
void UpdateFirstQuadrature(const size_t timeLevel)
void RestrictSolution(const size_t timeLevel)
Array< OneD, Array< OneD, NekDouble > > m_ImatFtoC
Definition: DriverPFASST.h:152
Array< OneD, Array< OneD, NekDouble > > m_ImatCtoF
Definition: DriverPFASST.h:153
void Restrict(const size_t fineLevel, const SDCarray &in, const size_t coarseLevel, SDCarray &out)
void ResidualEval(const NekDouble time, const size_t timeLevel, const size_t n)
static std::string className
Name of the class.
Definition: DriverPFASST.h:65
void InterpolateResidual(const size_t timeLevel)
void CorrectSolution(const size_t timeLevel)
void EvaluateSDCResidualNorm(const size_t timeLevel)
void IntegratedResidualEval(const size_t timeLevel)
void RunSweep(const NekDouble time, const size_t timeLevel, const bool update=false)
static DriverSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
Definition: DriverPFASST.h:54
void Interpolate(const size_t coarseLevel, const SDCarray &in, const size_t fineLevel, SDCarray &out, bool forced)
void ComputeFASCorrection(const size_t timeLevel)
Array< OneD, SDCarray > m_solutionRest
Definition: DriverPFASST.h:154
void CorrectInitialResidual(const size_t timeLevel)
SOLVER_UTILS_EXPORT void v_Execute(std::ostream &out=std::cout) override
Virtual function for solve implementation.
void WriteOutput(const size_t step, const NekDouble time)
void CorrectInitialSolution(const size_t timeLevel)
Array< OneD, std::shared_ptr< LibUtilities::TimeIntegrationSchemeSDC > > m_SDCSolver
Definition: DriverPFASST.h:160
Array< OneD, SDCarray > m_correction
Definition: DriverPFASST.h:157
SOLVER_UTILS_EXPORT void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
Array< OneD, SDCarray > m_storage
Definition: DriverPFASST.h:158
Array< OneD, SDCarray > m_integralRest
Definition: DriverPFASST.h:156
void Correct(const size_t coarseLevel, const Array< OneD, Array< OneD, NekDouble > > &in, const size_t fineLevel, Array< OneD, Array< OneD, NekDouble > > &out, bool forced)
Array< OneD, SDCarray > m_residualRest
Definition: DriverPFASST.h:155
void InterpolateSolution(const size_t timeLevel)
void PropagateQuadratureSolutionAndResidual(const size_t timeLevel, const size_t index)
SOLVER_UTILS_EXPORT DriverPFASST(const LibUtilities::SessionReaderSharedPtr pSession, const SpatialDomains::MeshGraphSharedPtr pGraph)
Constructor.
static std::string driverLookupId
Definition: DriverPFASST.h:83
void CorrectResidual(const size_t timeLevel)
Array< OneD, size_t > m_QuadPts
Definition: DriverPFASST.h:151
bool IsNotInitialCondition(const size_t n)
Base class for the development of parallel-in-time solvers.
NekDouble m_totalTime
Total time integration interval.
Array< OneD, NekDouble > m_vL2Errors
Storage for parallel-in-time iteration.
void UpdateFieldCoeffs(const size_t timeLevel, const Array< OneD, const Array< OneD, NekDouble > > &in=NullNekDoubleArrayOfArray)
NekDouble m_chunkTime
Time integration interval per chunk.
void SendToNextProc(Array< OneD, Array< OneD, NekDouble > > &array, int &convergence)
size_t m_iterMaxPIT
Maximum number of parallel-in-time iteration.
void PrintErrorNorm(const size_t timeLevel, const bool normalized)
Array< OneD, size_t > m_nsteps
Number of time steps for each time level.
SOLVER_UTILS_EXPORT void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
void EvaluateExactSolution(const size_t timeLevel, const NekDouble &time)
void RecvFromPreviousProc(Array< OneD, Array< OneD, NekDouble > > &array, int &convergence)
Array< OneD, std::shared_ptr< UnsteadySystem > > m_EqSys
Equation system to solve.
void PrintHeader(const std::string &title, const char c)
NekDouble m_tolerPIT
ParallelInTime tolerance.
void PrintSolverInfo(std::ostream &out=std::cout)
Array< OneD, size_t > m_npts
Number of dof for each time level.
Array< OneD, Array< OneD, NekDouble > > m_exactsoln
void SolutionConvergenceSummary(const size_t timeLevel)
Array< OneD, NekDouble > m_timestep
Time step for each time level.
void CopySolutionVector(const Array< OneD, const Array< OneD, NekDouble > > &in, Array< OneD, Array< OneD, NekDouble > > &out)
PointsManagerT & PointsManager(void)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
DriverFactory & GetDriverFactory()
Definition: Driver.cpp:66
Array< OneD, Array< OneD, Array< OneD, NekDouble > > > SDCarray
Definition: DriverPFASST.h:45
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
std::vector< double > w(NPUPPER)
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition: Vmath.hpp:396
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 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