Nektar++
Loading...
Searching...
No Matches
UnsteadySystem.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: UnsteadySystem.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: Generic timestepping for Unsteady solvers
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <iomanip>
36#include <iostream>
37using namespace std;
38
39#include <boost/format.hpp>
40
45
46namespace Nektar::SolverUtils
47{
50 "set-start-time", "", "Set the starting time of the simulation.");
51
54 "set-start-chknumber", "",
55 "Set the starting number of the checkpoint file.");
56
57/**
58 * @class UnsteadySystem
59 *
60 * Provides the underlying timestepping framework for unsteady solvers
61 * including the general timestepping routines. This class is not
62 * intended to be directly instantiated, but rather is a base class
63 * on which to define unsteady solvers.
64 *
65 * For details on implementing unsteady solvers see
66 * \ref sectionADRSolverModuleImplementation here
67 */
68
69/**
70 * Processes SolverInfo parameters from the session file and sets up
71 * timestepping-specific code.
72 * @param pSession Session object to read parameters from.
73 */
77 : EquationSystem(pSession, pGraph), SolverUtils::ALEHelper()
78
79{
80}
81
82/**
83 * Initialization object for UnsteadySystem class.
84 */
85void UnsteadySystem::v_InitObject(bool DeclareField)
86{
87 EquationSystem::v_InitObject(DeclareField);
89 m_initialStep = 0;
90
91 // Load SolverInfo parameters.
92 m_session->MatchSolverInfo("DIFFUSIONADVANCEMENT", "Explicit",
94 m_session->MatchSolverInfo("ADVECTIONADVANCEMENT", "Explicit",
96 m_session->MatchSolverInfo("REACTIONADVANCEMENT", "Explicit",
97 m_explicitReaction, true);
98 m_session->LoadParameter("CheckAbortSteps", m_abortSteps, 1);
99
100 // Steady state tolerance.
101 m_session->LoadParameter("SteadyStateTol", m_steadyStateTol, 0.0);
102
103 // Frequency for checking steady state.
104 m_session->LoadParameter("SteadyStateSteps", m_steadyStateSteps, 1);
105
106 // For steady problems, we do not initialise the time integration.
107 if (m_session->DefinesSolverInfo("TimeIntegrationMethod") ||
108 m_session->DefinesTimeIntScheme())
109 {
111 if (m_session->DefinesTimeIntScheme())
112 {
113 timeInt = m_session->GetTimeIntScheme();
114 }
115 else
116 {
117 std::cout << "TimeIntegrationMethod is deprecated, please use "
118 "TIMEINTEGRATIONSCHEME";
119 timeInt.method = m_session->GetSolverInfo("TimeIntegrationMethod");
120 }
121
124 timeInt.method, timeInt.variant, timeInt.order,
125 timeInt.freeParams);
126
127 // Load generic input parameters.
128 m_session->LoadParameter("IO_InfoSteps", m_infosteps, 0);
129 m_session->LoadParameter("IO_FiltersInfoSteps", m_filtersInfosteps,
130 10 * m_infosteps);
131 m_session->LoadParameter("CFL", m_cflSafetyFactor, 0.0);
132 m_session->LoadParameter("CFLEnd", m_CFLEnd, 0.0);
133 m_session->LoadParameter("CFLGrowth", m_CFLGrowth, 1.0);
134
135 // Ensure that there is no conflict of parameters.
136 if (m_cflSafetyFactor > 0.0)
137 {
138 // Check final condition.
139 ASSERTL0(m_fintime == 0.0 || m_steps == 0,
140 "Final condition not unique: "
141 "fintime > 0.0 and Nsteps > 0");
142 // Check timestep condition.
143 ASSERTL0(m_timestep == 0.0,
144 "Timestep not unique: timestep > 0.0 & CFL > 0.0");
145 }
146 else
147 {
148 ASSERTL0(m_timestep != 0.0, "Need to set either TimeStep or CFL");
149 }
150
151 // Ensure that there is no conflict of parameters.
152 if (m_CFLGrowth > 1.0)
153 {
154 // Check final condition.
156 "m_CFLEnd >= m_cflSafetyFactor required");
157 }
158
159 // Set up time to be dumped in field information.
160 m_fieldMetaDataMap["Time"] = boost::lexical_cast<std::string>(m_time);
161 }
162
163 // By default attempt to forward transform initial condition.
164 m_homoInitialFwd = true;
165
166 // Set up filters.
167 for (auto &x : m_session->GetFilters())
168 {
169 m_filters.push_back(make_pair(
170 x.name, GetFilterFactory().CreateInstance(
171 x.name, m_session, shared_from_this(), x.params)));
172 }
173}
174
175/**
176 * @brief Returns the maximum time estimator for CFL control.
177 */
179{
180 return m_intScheme->GetTimeStability();
181}
182
183/**
184 * @brief Returns the time integration scheme.
185 */
191
192/**
193 * @brief Returns the time integration scheme operators.
194 */
200
201/**
202 * @brief Initialises the time integration scheme (as specified in the
203 * session file), and perform the time integration.
204 */
206{
207 ASSERTL0(m_intScheme != nullptr, "No time integration scheme.");
208
209 int i = 1;
210 int nvariables = 0;
211 int nfields = m_fields.size();
212 if (m_intVariables.empty())
213 {
214 for (i = 0; i < nfields; ++i)
215 {
216 m_intVariables.push_back(i);
217 }
218 nvariables = nfields;
219 }
220 else
221 {
222 nvariables = m_intVariables.size();
223 }
224
225 // Integrate in wave-space if using homogeneous1D.
227 {
228 for (i = 0; i < nfields; ++i)
229 {
230 m_fields[i]->HomogeneousFwdTrans(m_fields[i]->GetTotPoints(),
231 m_fields[i]->GetPhys(),
232 m_fields[i]->UpdatePhys());
233 m_fields[i]->SetWaveSpace(true);
234 m_fields[i]->SetPhysState(false);
235 }
236 }
237
238 // Set up wrapper to fields data storage.
239 Array<OneD, Array<OneD, NekDouble>> fields(nvariables);
240
241 // Order storage to list time-integrated fields first.
242 // @TODO: Refactor to take coeffs (FwdTrans) if boolean flag (in constructor
243 // function) says to.
244 for (i = 0; i < nvariables; ++i)
245 {
246 fields[i] = m_fields[m_intVariables[i]]->UpdatePhys();
247 m_fields[m_intVariables[i]]->SetPhysState(false);
248 }
249
250 // @TODO: Virtual function that allows to transform the field space, embed
251 // the MultiplyMassMatrix in here.
252 // @TODO: Specify what the fields variables are physical or coefficient,
253 // boolean in UnsteadySystem class...
254
255 if (m_meshDistorted)
256 {
257 v_ALEPreMultiplyMass(fields);
258 }
259
260 // Initialise time integration scheme.
261 m_intScheme->InitializeScheme(m_timestep, fields, m_time, m_ode);
262
263 // Initialise filters.
264 for (auto &x : m_filters)
265 {
266 x.second->Initialise(m_fields, m_time);
267 }
268
270 bool doCheckTime = false;
271 int step = m_initialStep;
272 int stepCounter = 0;
273 NekDouble intTime = 0.0;
274 NekDouble cpuTime = 0.0;
275 NekDouble cpuPrevious = 0.0;
276 NekDouble elapsed = 0.0;
277 NekDouble totFilterTime = 0.0;
278
279 m_lastCheckTime = 0.0;
280
281 Array<OneD, int> abortFlags(2, 0);
282 string abortFile = "abort";
283 if (m_session->DefinesSolverInfo("CheckAbortFile"))
284 {
285 abortFile = m_session->GetSolverInfo("CheckAbortFile");
286 }
287
288 NekDouble tmp_cflSafetyFactor = m_cflSafetyFactor;
289 while ((step < m_steps || m_time < m_fintime - NekConstants::kNekZeroTol) &&
290 abortFlags[1] == 0)
291 {
293 {
294 tmp_cflSafetyFactor =
295 min(m_CFLEnd, m_CFLGrowth * tmp_cflSafetyFactor);
296 }
297
298 // Frozen preconditioner checks.
299 if (!m_comm->IsParallelInTime())
300 {
302 {
303 m_cflSafetyFactor = tmp_cflSafetyFactor;
304
306 {
307 m_timestep = GetTimeStep(fields);
308 }
309
310 // Ensure that the final timestep finishes at the final
311 // time, or at a prescribed IO_CheckTime.
312 if (m_time + m_timestep > m_fintime && m_fintime > 0.0)
313 {
315 }
316 else if (m_checktime &&
318 {
321 doCheckTime = true;
322 }
323 }
324 }
325
326 if (m_TimeIncrementFactor > 1.0)
327 {
328 NekDouble timeincrementFactor = m_TimeIncrementFactor;
329 m_timestep *= timeincrementFactor;
330
331 if (m_time + m_timestep > m_fintime && m_fintime > 0.0)
332 {
334 }
335 }
336
337 // Perform any solver-specific pre-integration steps.
338 timer.Start();
339 if (v_PreIntegrate(
340 step)) // Could be possible to put a preintegrate step in the
341 // ALEHelper class, put in the Unsteady Advection class
342 {
343 break;
344 }
345
346 ASSERTL0(m_timestep > 0, "m_timestep < 0");
347
348 fields = m_intScheme->TimeIntegrate(stepCounter, m_timestep);
349 timer.Stop();
350
352 elapsed = timer.TimePerTest(1);
353 intTime += elapsed;
354 cpuTime += elapsed;
355
356 // Update time in field info if required
357 if (m_fieldMetaDataMap.find("Time") != m_fieldMetaDataMap.end())
358 {
359 m_fieldMetaDataMap["Time"] =
360 boost::lexical_cast<std::string>(m_time);
361 }
362
363 // Write out status information.
364 v_PrintStatusInformation(step, cpuTime);
365 if (m_infosteps &&
366 m_session->GetComm()->GetSpaceComm()->GetRank() == 0 &&
367 !((step + 1) % m_infosteps))
368 {
369 cpuPrevious = cpuTime;
370 cpuTime = 0.0;
371 }
372
373 // Change to advect coeffs
374 if (m_meshDistorted)
375 {
378 }
379 else
380 {
381 // Transform data into coefficient space
382 for (i = 0; i < nvariables; ++i)
383 {
384 // copy fields into ExpList::m_phys and assign the new
385 // array to fields
386 m_fields[m_intVariables[i]]->SetPhys(fields[i]);
387 fields[i] = m_fields[m_intVariables[i]]->UpdatePhys();
388 if (v_RequireFwdTrans())
389 {
390 if (m_comm->IsParallelInTime())
391 {
392 m_fields[m_intVariables[i]]->FwdTrans(
393 m_fields[m_intVariables[i]]->GetPhys(),
394 m_fields[m_intVariables[i]]->UpdateCoeffs());
395 }
396 else
397 {
398 m_fields[m_intVariables[i]]->FwdTransLocalElmt(
399 m_fields[m_intVariables[i]]->GetPhys(),
400 m_fields[m_intVariables[i]]->UpdateCoeffs());
401 }
402 }
403 m_fields[m_intVariables[i]]->SetPhysState(false);
404 }
405 }
406
407 // Perform any solver-specific post-integration steps.
408 if (v_PostIntegrate(step))
409 {
410 break;
411 }
412
413 // Check for steady-state.
415 (!((step + 1) % m_steadyStateSteps)))
416 {
417 if (CheckSteadyState(step, intTime))
418 {
419 if (m_comm->GetRank() == 0)
420 {
421 cout << "Reached Steady State to tolerance "
422 << m_steadyStateTol << endl;
423 }
424 break;
425 }
426 }
427
428 // Test for abort conditions (nan, or abort file).
429 if (m_abortSteps && !((step + 1) % m_abortSteps))
430 {
431 abortFlags[0] = 0;
432 for (i = 0; i < nvariables; ++i)
433 {
434 if (Vmath::Nnan(m_fields[m_intVariables[i]]->GetPhys().size(),
435 m_fields[m_intVariables[i]]->GetPhys(), 1) > 0)
436 {
437 abortFlags[0] = 1;
438 }
439 }
440
441 // Rank zero looks for abort file and deletes it
442 // if it exists. Communicates the abort.
443 if (m_session->GetComm()->GetSpaceComm()->GetRank() == 0)
444 {
445 if (fs::exists(abortFile))
446 {
447 fs::remove(abortFile);
448 abortFlags[1] = 1;
449 }
450 }
451
452 m_session->GetComm()->GetSpaceComm()->AllReduce(
453 abortFlags, LibUtilities::ReduceMax);
454
455 ASSERTL0(!abortFlags[0], "NaN found during time integration.");
456 }
457
458 // Update filters.
459 for (auto &x : m_filters)
460 {
461 timer.Start();
462 x.second->Update(m_fields, m_time);
463 timer.Stop();
464 elapsed = timer.TimePerTest(1);
465 totFilterTime += elapsed;
466
467 // Write out individual filter status information.
468 if (m_filtersInfosteps && m_session->GetComm()->GetRank() == 0 &&
469 !((step + 1) % m_filtersInfosteps) && !m_filters.empty() &&
470 m_session->DefinesCmdLineArgument("verbose"))
471 {
472 stringstream s0;
473 s0 << x.first << ":";
474 stringstream s1;
475 s1 << elapsed << "s";
476 stringstream s2;
477 s2 << elapsed / cpuPrevious * 100 << "%";
478 cout << "CPU time for filter " << setw(25) << left << s0.str()
479 << setw(12) << left << s1.str() << endl
480 << "\t Percentage of time integration: " << setw(10)
481 << left << s2.str() << endl;
482 }
483 }
484
485 // Write out overall filter status information.
486 if (m_filtersInfosteps && m_session->GetComm()->GetRank() == 0 &&
487 !((step + 1) % m_filtersInfosteps) && !m_filters.empty())
488 {
489 stringstream ss;
490 ss << totFilterTime << "s";
491 cout << "Total filters CPU Time:\t\t\t " << setw(10) << left
492 << ss.str() << endl;
493 }
494 totFilterTime = 0.0;
495
496 // Write out checkpoint files.
497 if ((m_checksteps && !((step + 1) % m_checksteps)) || doCheckTime)
498 {
500 {
501 // Transform to physical space for output.
502 vector<bool> transformed(nfields, false);
503 for (i = 0; i < nfields; i++)
504 {
505 if (m_fields[i]->GetWaveSpace())
506 {
507 m_fields[i]->SetWaveSpace(false);
508 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
509 m_fields[i]->UpdatePhys());
510 transformed[i] = true;
511 }
512 }
514 m_nchk++;
515
516 // Transform back to wave-space after output.
517 for (i = 0; i < nfields; i++)
518 {
519 if (transformed[i])
520 {
521 m_fields[i]->SetWaveSpace(true);
522 m_fields[i]->HomogeneousFwdTrans(
523 m_fields[i]->GetTotPoints(), m_fields[i]->GetPhys(),
524 m_fields[i]->UpdatePhys());
525 m_fields[i]->SetPhysState(false);
526 }
527 }
528 }
529 else
530 {
532 m_nchk++;
533 }
534 doCheckTime = false;
535 }
536
537 // Step advance.
538 ++step;
539 ++stepCounter;
540 }
541
542 // Print out summary statistics.
544
545 // If homogeneous, transform back into physical space if necessary.
546 if (!m_meshDistorted)
547 {
549 {
550 for (i = 0; i < nfields; i++)
551 {
552 if (m_fields[i]->GetWaveSpace())
553 {
554 m_fields[i]->SetWaveSpace(false);
555 m_fields[i]->BwdTrans(m_fields[i]->GetCoeffs(),
556 m_fields[i]->UpdatePhys());
557 }
558 }
559 }
560 else
561 {
562 for (i = 0; i < nvariables; ++i)
563 {
564 m_fields[m_intVariables[i]]->SetPhysState(true);
565 }
566 }
567 }
568 // Finalise filters.
569 for (auto &x : m_filters)
570 {
571 x.second->Finalise(m_fields, m_time);
572 }
573
574 // Print for 1D problems.
575 if (m_spacedim == 1)
576 {
578 }
579}
580
582 const NekDouble cpuTime)
583{
584 if (m_infosteps && m_session->GetComm()->GetSpaceComm()->GetRank() == 0 &&
585 !((step + 1) % m_infosteps))
586 {
587 if (m_comm->IsParallelInTime())
588 {
589 cout << "RANK " << m_session->GetComm()->GetTimeComm()->GetRank()
590 << " Steps: " << setw(8) << left << step + 1 << " "
591 << "Time: " << setw(12) << left << m_time;
592 }
593 else
594 {
595 cout << "Steps: " << setw(8) << left << step + 1 << " "
596 << "Time: " << setw(12) << left << m_time;
597 }
598
600 {
601 cout << " Time-step: " << setw(12) << left << m_timestep;
602 }
603
604 stringstream ss;
605 ss << cpuTime << "s";
606 cout << " CPU Time: " << setw(8) << left << ss.str() << endl;
607 }
608}
609
611{
612 if (m_session->GetComm()->GetRank() == 0)
613 {
614 if (m_cflSafetyFactor > 0.0)
615 {
616 cout << "CFL safety factor : " << m_cflSafetyFactor << endl
617 << "CFL time-step : " << m_timestep << endl;
618 }
619
620 if (m_session->GetSolverInfo("Driver") != "SteadyState" &&
621 m_session->GetSolverInfo("Driver") != "Parareal" &&
622 m_session->GetSolverInfo("Driver") != "PFASST")
623 {
624 cout << "Time-integration : " << intTime << "s" << endl;
625 }
626 }
627}
628
629/**
630 * @brief Sets the initial conditions.
631 */
632void UnsteadySystem::v_DoInitialise(bool dumpInitialConditions)
633{
636 SetInitialConditions(m_time, dumpInitialConditions);
637
639
641}
642
643/**
644 * @brief Prints a summary with some information regards the
645 * time-stepping.
646 */
648{
650 AddSummaryItem(s, "Advect. advancement",
651 m_explicitAdvection ? "explicit" : "implicit");
652
653 AddSummaryItem(s, "Diffuse. advancement",
654 m_explicitDiffusion ? "explicit" : "implicit");
655
656 if (m_session->GetSolverInfo("EQTYPE") ==
657 "SteadyAdvectionDiffusionReaction")
658 {
659 AddSummaryItem(s, "React. advancement",
660 m_explicitReaction ? "explicit" : "implicit");
661 }
662
663 AddSummaryItem(s, "Time Step", m_timestep);
664 AddSummaryItem(s, "No. of Steps", m_steps);
665 AddSummaryItem(s, "Checkpoints (steps)", m_checksteps);
666 if (m_intScheme)
667 {
668 AddSummaryItem(s, "Integration Type", m_intScheme->GetName());
669 }
670}
671
672/**
673 * Stores the solution in a file for 1D problems only. This method has
674 * been implemented to facilitate the post-processing for 1D problems.
675 */
677{
678 // Coordinates of the quadrature points in the real physical space.
682 m_fields[0]->GetCoords(x, y, z);
683
684 // Print out the solution in a txt file.
685 ofstream outfile;
686 outfile.open("solution1D.txt");
687 for (int i = 0; i < GetNpoints(); i++)
688 {
689 outfile << scientific << setw(17) << setprecision(16) << x[i] << " "
690 << m_fields[m_intVariables[0]]->GetPhys()[i] << endl;
691 }
692 outfile << endl << endl;
693 outfile.close();
694}
695
696/**
697 *
698 */
700{
701 if (m_session->DefinesFunction("InitialConditions"))
702 {
703 for (int i = 0; i < m_fields.size(); ++i)
704 {
706
707 vType = m_session->GetFunctionType("InitialConditions",
708 m_session->GetVariable(i));
709
711 {
712 std::string filename = m_session->GetFunctionFilename(
713 "InitialConditions", m_session->GetVariable(i));
714
715 fs::path pfilename(filename);
716
717 // Redefine path for parallel file which is in directory.
718 if (fs::is_directory(pfilename))
719 {
720 fs::path metafile("Info.xml");
721 fs::path fullpath = pfilename / metafile;
722 filename = LibUtilities::PortablePath(fullpath);
723 }
726 fld->ImportFieldMetaData(filename, m_fieldMetaDataMap);
727
728 // Check to see if time defined.
730 {
731 auto iter = m_fieldMetaDataMap.find("Time");
732 if (iter != m_fieldMetaDataMap.end())
733 {
734 time = std::stod(iter->second);
735 }
736
737 iter = m_fieldMetaDataMap.find("ChkFileNum");
738 if (iter != m_fieldMetaDataMap.end())
739 {
740 nchk = std::stod(iter->second);
741 }
742 }
743
744 break;
745 }
746 }
747 }
748 if (m_session->DefinesCmdLineArgument("set-start-time"))
749 {
750 time = std::stod(
751 m_session->GetCmdLineArgument<std::string>("set-start-time")
752 .c_str());
753 }
754 if (m_session->DefinesCmdLineArgument("set-start-chknumber"))
755 {
756 nchk = std::stoi(
757 m_session->GetCmdLineArgument<std::string>("set-start-chknumber"));
758 }
759 ASSERTL0(time >= 0 && nchk >= 0,
760 "Starting time and checkpoint number should be >= 0");
761}
762
763/**
764 * @brief Return the timestep to be used for the next step in the
765 * time-marching loop.
766 *
767 * @see UnsteadySystem::GetTimeStep
768 */
770 [[maybe_unused]] const Array<OneD, const Array<OneD, NekDouble>> &inarray)
771{
772 NEKERROR(ErrorUtil::efatal, "Not defined for this class");
773 return 0.0;
774}
775
776/**
777 *
778 */
779bool UnsteadySystem::v_PreIntegrate([[maybe_unused]] int step)
780{
781 return false;
782}
783
784/**
785 *
786 */
787bool UnsteadySystem::v_PostIntegrate([[maybe_unused]] int step)
788{
789 return false;
790}
791
792/**
793 *
794 */
796{
797 return true;
798}
799
800/**
801 *
802 */
804{
805 return true;
806}
807
808/**
809 *
810 */
813 StdRegions::VarCoeffMap &varCoeffMap)
814{
815 int phystot = m_fields[0]->GetTotPoints();
816 int nvel = vel.size();
817
818 Array<OneD, NekDouble> varcoeff(phystot), tmp;
819
820 // Calculate magnitude of v.
821 Vmath::Vmul(phystot, vel[0], 1, vel[0], 1, varcoeff, 1);
822 for (int n = 1; n < nvel; ++n)
823 {
824 Vmath::Vvtvp(phystot, vel[n], 1, vel[n], 1, varcoeff, 1, varcoeff, 1);
825 }
826 Vmath::Vsqrt(phystot, varcoeff, 1, varcoeff, 1);
827
828 for (int i = 0; i < m_fields[0]->GetNumElmts(); ++i)
829 {
830 int offset = m_fields[0]->GetPhys_Offset(i);
831 int nq = m_fields[0]->GetExp(i)->GetTotPoints();
832 Array<OneD, NekDouble> unit(nq, 1.0);
833
834 int nmodes = 0;
835
836 for (int n = 0; n < m_fields[0]->GetExp(i)->GetNumBases(); ++n)
837 {
838 nmodes = max(nmodes, m_fields[0]->GetExp(i)->GetBasisNumModes(n));
839 }
840
841 NekDouble h = m_fields[0]->GetExp(i)->Integral(unit);
842 h = pow(h, (NekDouble)(1.0 / nvel)) / ((NekDouble)nmodes);
843
844 Vmath::Smul(nq, h, varcoeff + offset, 1, tmp = varcoeff + offset, 1);
845 }
846
847 // Set up map with eVarCoffLaplacian key.
848 varCoeffMap[StdRegions::eVarCoeffLaplacian] = varcoeff;
849}
850
851/**
852 *
853 */
855{
856 if (m_steadyStateTol > 0.0)
857 {
858 const int nPoints = m_fields[0]->GetTotPoints();
861
862 for (int i = 0; i < m_fields.size(); ++i)
863 {
865 Vmath::Vcopy(nPoints, m_fields[i]->GetPhys(), 1,
866 m_previousSolution[i], 1);
867 }
868
869 if (m_comm->GetRank() == 0)
870 {
871 std::string fName =
872 m_session->GetSessionName() + std::string(".resd");
873 m_errFile.open(fName.c_str());
874 m_errFile << setw(26) << left << "# Time";
875
876 m_errFile << setw(26) << left << "CPU_Time";
877
878 m_errFile << setw(26) << left << "Step";
879
880 for (int i = 0; i < m_fields.size(); ++i)
881 {
882 m_errFile << setw(26) << m_session->GetVariables()[i];
883 }
884
885 m_errFile << endl;
886 }
887 }
888}
889
890/**
891 * @brief Calculate whether the system has reached a steady state by
892 * observing residuals to a user-defined tolerance.
893 */
894bool UnsteadySystem::CheckSteadyState(int step, const NekDouble &totCPUTime)
895{
896 const int nPoints = GetTotPoints();
897 const int nFields = m_fields.size();
898
899 // Holds L2 errors.
900 Array<OneD, NekDouble> L2(nFields);
901
902 SteadyStateResidual(step, L2);
903
904 if (m_infosteps && m_comm->GetRank() == 0 &&
905 (((step + 1) % m_infosteps == 0) || ((step == m_initialStep))))
906 {
907 // Output time.
908 m_errFile << boost::format("%25.19e") % m_time;
909
910 m_errFile << " " << boost::format("%25.19e") % totCPUTime;
911
912 int stepp = step + 1;
913
914 m_errFile << " " << boost::format("%25.19e") % stepp;
915
916 // Output residuals.
917 for (int i = 0; i < nFields; ++i)
918 {
919 m_errFile << " " << boost::format("%25.19e") % L2[i];
920 }
921
922 m_errFile << endl;
923 }
924
925 // Calculate maximum L2 error.
926 NekDouble maxL2 = Vmath::Vmax(nFields, L2, 1);
927
928 if (m_infosteps && m_session->DefinesCmdLineArgument("verbose") &&
929 m_comm->GetRank() == 0 && ((step + 1) % m_infosteps == 0))
930 {
931 cout << "-- Maximum L^2 residual: " << maxL2 << endl;
932 }
933
934 if (maxL2 <= m_steadyStateTol)
935 {
936 return true;
937 }
938
939 for (int i = 0; i < m_fields.size(); ++i)
940 {
941 Vmath::Vcopy(nPoints, m_fields[i]->GetPhys(), 1, m_previousSolution[i],
942 1);
943 }
944
945 return false;
946}
947
948/**
949 *
950 */
951void UnsteadySystem::v_SteadyStateResidual([[maybe_unused]] int step,
953{
954 const int nPoints = GetTotPoints();
955 const int nFields = m_fields.size();
956
957 // Holds L2 errors.
958 Array<OneD, NekDouble> RHSL2(nFields);
959 Array<OneD, NekDouble> residual(nFields);
960 Array<OneD, NekDouble> reference(nFields);
961
962 for (int i = 0; i < nFields; ++i)
963 {
964 Array<OneD, NekDouble> tmp(nPoints);
965
966 Vmath::Vsub(nPoints, m_fields[i]->GetPhys(), 1, m_previousSolution[i],
967 1, tmp, 1);
968 Vmath::Vmul(nPoints, tmp, 1, tmp, 1, tmp, 1);
969 residual[i] = Vmath::Vsum(nPoints, tmp, 1);
970
972 tmp, 1);
973 reference[i] = Vmath::Vsum(nPoints, tmp, 1);
974 }
975
976 m_comm->GetSpaceComm()->AllReduce(residual, LibUtilities::ReduceSum);
977 m_comm->GetSpaceComm()->AllReduce(reference, LibUtilities::ReduceSum);
978
979 // L2 error.
980 for (int i = 0; i < nFields; ++i)
981 {
982 reference[i] = (reference[i] == 0) ? 1 : reference[i];
983 L2[i] = sqrt(residual[i] / reference[i]);
984 }
985}
986
987/**
988 *
989 */
991 const Array<OneD, const Array<OneD, NekDouble>> &inarray,
993 [[maybe_unused]] const NekDouble time)
994{
995
996 if (&inarray != &outarray)
997 {
998 for (int i = 0; i < inarray.size(); ++i)
999 {
1000 Vmath::Vcopy(GetNpoints(), inarray[i], 1, outarray[i], 1);
1001 }
1002 }
1003}
1004
1005} // namespace Nektar::SolverUtils
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
static std::shared_ptr< FieldIO > CreateForFile(const LibUtilities::SessionReaderSharedPtr session, const std::string &filename)
Construct a FieldIO object for a given input filename.
Definition FieldIO.cpp:223
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
static std::string RegisterCmdLineArgument(const std::string &pName, const std::string &pShortName, const std::string &pDescription)
Registers a command-line argument with the session reader.
Binds a set of functions for use by time integration schemes.
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition Timer.cpp:65
virtual SOLVER_UTILS_EXPORT void v_ALEPreMultiplyMass(Array< OneD, Array< OneD, NekDouble > > &fields)
virtual SOLVER_UTILS_EXPORT void v_ALEInitObject(int spaceDim, Array< OneD, MultiRegions::ExpListSharedPtr > &fields)
Definition ALEHelper.cpp:42
SOLVER_UTILS_EXPORT void ALEDoElmtInvMass(Array< OneD, Array< OneD, NekDouble > > &traceNormals, Array< OneD, Array< OneD, NekDouble > > &fields, NekDouble time)
Update m_fields with u^n by multiplying by inverse mass matrix. That's then used in e....
virtual SOLVER_UTILS_EXPORT void v_UpdateGridVelocity(const NekDouble &time)
Definition ALEHelper.cpp:97
A base class for describing how to solve specific equations.
int m_spacedim
Spatial dimension (>= expansion dim).
LibUtilities::CommSharedPtr m_comm
Communicator.
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.
SOLVER_UTILS_EXPORT int GetNpoints()
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.
virtual SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareFeld=true)
Initialisation object for EquationSystem.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
SOLVER_UTILS_EXPORT void SetInitialConditions(NekDouble initialtime=0.0, bool dumpInitialConditions=true, const int domain=0)
Initialise the data in the dependent fields.
Array< OneD, Array< OneD, NekDouble > > m_traceNormals
Array holding trace normals for DG simulations in the forwards direction.
int m_initialStep
Number of the step where the simulation should begin.
SOLVER_UTILS_EXPORT int GetTotPoints()
int m_nchk
Number of checkpoints written so far.
int m_steps
Number of steps to take.
LibUtilities::FieldMetaDataMap m_fieldMetaDataMap
Map to identify relevant solver info to dump in output fields.
SOLVER_UTILS_EXPORT void SetBoundaryConditions(NekDouble time)
Evaluates the boundary conditions at the given time.
virtual SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &l)
Virtual function for generating summary information.
int m_checksteps
Number of steps between checkpoints.
LibUtilities::TimeIntegrationSchemeOperators m_ode
The time integration scheme operators to use.
NekDouble m_CFLGrowth
CFL growth rate.
bool m_explicitReaction
Indicates if explicit or implicit treatment of reaction is used.
Array< OneD, Array< OneD, NekDouble > > m_previousSolution
Storage for previous solution for steady-state check.
SOLVER_UTILS_EXPORT void v_DoInitialise(bool dumpInitialConditions=true) override
Sets up initial conditions.
virtual SOLVER_UTILS_EXPORT bool v_UpdateTimeStepCheck()
std::vector< std::pair< std::string, FilterSharedPtr > > m_filters
NekDouble m_cflSafetyFactor
CFL safety factor (comprise between 0 to 1).
LibUtilities::TimeIntegrationSchemeSharedPtr m_intScheme
Wrapper to the time integration scheme.
SOLVER_UTILS_EXPORT void DoDummyProjection(const Array< OneD, const Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble time)
Perform dummy projection.
NekDouble m_steadyStateTol
Tolerance to which steady state should be evaluated at.
int m_abortSteps
Number of steps between checks for abort conditions.
bool m_explicitAdvection
Indicates if explicit or implicit treatment of advection is used.
SOLVER_UTILS_EXPORT NekDouble MaxTimeStepEstimator()
Get the maximum timestep estimator for cfl control.
bool m_explicitDiffusion
Indicates if explicit or implicit treatment of diffusion is used.
virtual SOLVER_UTILS_EXPORT bool v_PostIntegrate(int step)
NekDouble m_CFLEnd
Maximun cfl in cfl growth.
virtual SOLVER_UTILS_EXPORT void v_PrintSummaryStatistics(const NekDouble intTime)
Print Summary Statistics.
virtual SOLVER_UTILS_EXPORT void v_PrintStatusInformation(const int step, const NekDouble cpuTime)
Print Status Information.
bool CheckSteadyState(int step, const NekDouble &totCPUTime=0.0)
Calculate whether the system has reached a steady state by observing residuals to a user-defined tole...
virtual SOLVER_UTILS_EXPORT NekDouble v_GetTimeStep(const Array< OneD, const Array< OneD, NekDouble > > &inarray)
Return the timestep to be used for the next step in the time-marching loop.
SOLVER_UTILS_EXPORT void v_GenerateSummary(SummaryList &s) override
Print a summary of time stepping parameters.
virtual SOLVER_UTILS_EXPORT void v_SteadyStateResidual(int step, Array< OneD, NekDouble > &L2)
SOLVER_UTILS_EXPORT void AppendOutput1D(void)
Print the solution at each solution point in a txt file.
virtual SOLVER_UTILS_EXPORT bool v_PreIntegrate(int step)
SOLVER_UTILS_EXPORT void CheckForRestartTime(NekDouble &time, int &nchk)
SOLVER_UTILS_EXPORT UnsteadySystem(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Initialises UnsteadySystem class members.
virtual SOLVER_UTILS_EXPORT bool v_RequireFwdTrans()
SOLVER_UTILS_EXPORT void SteadyStateResidual(int step, Array< OneD, NekDouble > &L2)
SOLVER_UTILS_EXPORT void v_InitObject(bool DeclareField=true) override
Init object for UnsteadySystem class.
SOLVER_UTILS_EXPORT LibUtilities::TimeIntegrationSchemeOperators & GetTimeIntegrationSchemeOperators()
Returns the time integration scheme operators.
int m_steadyStateSteps
Check for steady state at step interval.
SOLVER_UTILS_EXPORT LibUtilities::TimeIntegrationSchemeSharedPtr & GetTimeIntegrationScheme()
Returns the time integration scheme.
int m_filtersInfosteps
Number of time steps between outputting filters information.
SOLVER_UTILS_EXPORT void SVVVarDiffCoeff(const Array< OneD, Array< OneD, NekDouble > > vel, StdRegions::VarCoeffMap &varCoeffMap)
Evaluate the SVV diffusion coefficient according to Moura's paper where it should proportional to h t...
bool m_homoInitialFwd
Flag to determine if simulation should start in homogeneous forward transformed state.
SOLVER_UTILS_EXPORT NekDouble GetTimeStep()
SOLVER_UTILS_EXPORT void v_DoSolve() override
Solves an unsteady problem.
TimeIntegrationSchemeFactory & GetTimeIntegrationSchemeFactory()
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition FieldIO.h:322
static std::string PortablePath(const fs::path &path)
create portable path on different platforms for std::filesystem path.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
static FieldMetaDataMap NullFieldMetaDataMap
Definition FieldIO.h:51
std::shared_ptr< TimeIntegrationScheme > TimeIntegrationSchemeSharedPtr
static const NekDouble kNekZeroTol
std::vector< std::pair< std::string, std::string > > SummaryList
Definition Misc.h:46
FilterFactory & GetFilterFactory()
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
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition MeshGraph.h:224
std::map< StdRegions::VarCoeffType, VarCoeffEntry > VarCoeffMap
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition Vmath.hpp:340
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 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
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition Vmath.hpp:608
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
int Nnan(int n, const T *x, const int incx)
Return number of NaN elements of x.
Definition Vmath.hpp:743
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition Vmath.hpp:644
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
STL namespace.
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290
std::vector< NekDouble > freeParams