Nektar++
Loading...
Searching...
No Matches
DIRKTimeIntegrationSchemes.h
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: DIRKTimeIntegrationSchemes.h
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2018 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// License for the specific language governing rights and limitations under
14// Permission is hereby granted, free of charge, to any person obtaining a
15// copy of this software and associated documentation files (the "Software"),
16// to deal in the Software without restriction, including without limitation
17// the rights to use, copy, modify, merge, publish, distribute, sublicense,
18// and/or sell copies of the Software, and to permit persons to whom the
19// Software is furnished to do so, subject to the following conditions:
20//
21// The above copyright notice and this permission notice shall be included
22// in all copies or substantial portions of the Software.
23//
24// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30// DEALINGS IN THE SOFTWARE.
31//
32// Description: Combined header file for all basic DIRK based time integration
33// schemes.
34//
35///////////////////////////////////////////////////////////////////////////////
36
37// Note : If adding a new integrator be sure to register the
38// integrator with the Time Integration Scheme Facatory in
39// SchemeInitializor.cpp.
40
41#ifndef NEKTAR_LIB_UTILITIES_TIME_INTEGRATION_DIRK_TIME_INTEGRATION_SCHEME
42#define NEKTAR_LIB_UTILITIES_TIME_INTEGRATION_DIRK_TIME_INTEGRATION_SCHEME
43
44#define LUE LIB_UTILITIES_EXPORT
45
47
49{
50
51///////////////////////////////////////////////////////////////////////////////
52// DIRK Order N
54{
55public:
56 DIRKTimeIntegrationScheme(std::string variant, size_t order,
57 std::vector<NekDouble> freeParams)
58 : TimeIntegrationSchemeGLM(variant, order, freeParams)
59 {
60 // Currently up to 4th order is implemented.
61 ASSERTL0(1 <= order && order <= 4,
62 "Diagonally Implicit Runge Kutta integration scheme bad order "
63 "(1-4): " +
64 std::to_string(order));
65
69
70 ASSERTL1((variant == "" || variant == "ES5" || variant == "ES6"),
71 "DIRK Time integration scheme bad variant: " + variant +
72 ". "
73 "Must blank, 'ES5', or 'ES6'");
74
75 if ("" == variant)
76 {
78 order);
79 }
80 else
81 {
83 m_integration_phases[0], variant, order, freeParams);
84 }
85 }
86
87 ~DIRKTimeIntegrationScheme() override = default;
88
90 std::string variant, size_t order, std::vector<NekDouble> freeParams)
91 {
94 variant, order, freeParams);
95 return p;
96 }
97
98 static std::string className;
99
101 size_t order)
102 {
103 phase->m_schemeType = eDiagonallyImplicit;
104 phase->m_order = order;
105 phase->m_name =
106 std::string("DIRKOrder" + std::to_string(phase->m_order));
107
108 phase->m_numsteps = 1;
109 phase->m_numstages = phase->m_order;
110
111 phase->m_A = Array<OneD, Array<TwoD, NekDouble>>(1);
112 phase->m_B = Array<OneD, Array<TwoD, NekDouble>>(1);
113
114 phase->m_A[0] =
115 Array<TwoD, NekDouble>(phase->m_numstages, phase->m_numstages, 0.0);
116 phase->m_B[0] =
117 Array<TwoD, NekDouble>(phase->m_numsteps, phase->m_numstages, 0.0);
118 phase->m_U =
119 Array<TwoD, NekDouble>(phase->m_numstages, phase->m_numsteps, 1.0);
120 phase->m_V =
121 Array<TwoD, NekDouble>(phase->m_numsteps, phase->m_numsteps, 1.0);
122
123 switch (phase->m_order)
124 {
125 case 1:
126 {
127 // One-stage, 1st order, L-stable Diagonally Implicit
128 // Runge Kutta (backward Euler) method:
129
130 phase->m_A[0][0][0] = 1.0;
131
132 phase->m_B[0][0][0] = 1.0;
133 }
134 break;
135 case 2:
136 {
137 // Two-stage, 2nd order Diagonally Implicit Runge
138 // Kutta method. It is A-stable if and only if x ≥ 1/4
139 // and is L-stable if and only if x equals one of the
140 // roots of the polynomial x^2 - 2x + 1/2, i.e. if
141 // x = 1 ± sqrt(2)/2.
142 const NekDouble lambda = (2.0 - sqrt(2.0)) / 2.0;
143
144 phase->m_A[0][0][0] = lambda;
145 phase->m_A[0][1][0] = 1.0 - lambda;
146 phase->m_A[0][1][1] = lambda;
147
148 phase->m_B[0][0][0] = 1.0 - lambda;
149 phase->m_B[0][0][1] = lambda;
150 }
151 break;
152
153 case 3:
154 {
155 // Three-stage, 3rd order, L-stable Diagonally Implicit
156 // Runge Kutta method:
157 constexpr NekDouble lambda = 0.4358665215;
158
159 phase->m_A[0][0][0] = lambda;
160 phase->m_A[0][1][0] = 0.5 * (1.0 - lambda);
161 phase->m_A[0][2][0] =
162 0.25 * (-6.0 * lambda * lambda + 16.0 * lambda - 1.0);
163
164 phase->m_A[0][1][1] = lambda;
165
166 phase->m_A[0][2][1] =
167 0.25 * (6.0 * lambda * lambda - 20.0 * lambda + 5.0);
168 phase->m_A[0][2][2] = lambda;
169
170 phase->m_B[0][0][0] =
171 0.25 * (-6.0 * lambda * lambda + 16.0 * lambda - 1.0);
172 phase->m_B[0][0][1] =
173 0.25 * (6.0 * lambda * lambda - 20.0 * lambda + 5.0);
174 phase->m_B[0][0][2] = lambda;
175 }
176 break;
177 }
178
179 phase->m_numMultiStepValues = 1;
180 phase->m_numMultiStepImplicitDerivs = 0;
181 phase->m_numMultiStepExplicitDerivs = 0;
182 phase->m_timeLevelOffset = Array<OneD, size_t>(phase->m_numsteps);
183 phase->m_timeLevelOffset[0] = 0;
184
185 phase->CheckAndVerify();
186 }
187
189 TimeIntegrationAlgorithmGLMSharedPtr &phase, std::string variant,
190 size_t order, std::vector<NekDouble> freeParams)
191 {
192 phase->m_schemeType = eDiagonallyImplicit;
193 phase->m_order = order;
194 phase->m_name =
195 std::string("DIRKOrder" + std::to_string(phase->m_order) + variant);
196
197 phase->m_numsteps = 1;
198 char const &stage = variant.back();
199 phase->m_numstages = std::atoi(&stage);
200
201 phase->m_A = Array<OneD, Array<TwoD, NekDouble>>(1);
202 phase->m_B = Array<OneD, Array<TwoD, NekDouble>>(1);
203
204 phase->m_A[0] =
205 Array<TwoD, NekDouble>(phase->m_numstages, phase->m_numstages, 0.0);
206 phase->m_B[0] =
207 Array<TwoD, NekDouble>(phase->m_numsteps, phase->m_numstages, 0.0);
208 phase->m_U =
209 Array<TwoD, NekDouble>(phase->m_numstages, phase->m_numsteps, 1.0);
210 phase->m_V =
211 Array<TwoD, NekDouble>(phase->m_numsteps, phase->m_numsteps, 1.0);
212
213 const NekDouble ConstSqrt2 = sqrt(2.0);
214 switch (phase->m_order)
215 {
216 case 3:
217 {
218 // See: Kennedy, Christopher A., and Mark H. Carpenter.
219 // Diagonally implicit Runge-Kutta methods for ordinary
220 // differential equations. A review. No. NF1676L-19716. 2016.
221 ASSERTL0(5 == phase->m_numstages,
222 std::string("DIRKOrder3_ES" +
223 std::to_string(phase->m_numstages) +
224 " not defined"));
225
226 NekDouble lambda =
227 (freeParams.size()) ? freeParams[0] : 9.0 / 40.0;
228
229 phase->m_A[0][0][0] = 0.0;
230 phase->m_A[0][1][0] = lambda;
231 phase->m_A[0][2][0] = 9.0 * (1.0 + ConstSqrt2) / 80.0;
232 phase->m_A[0][3][0] =
233 (22.0 + 15.0 * ConstSqrt2) / (80.0 * (1.0 + ConstSqrt2));
234 phase->m_A[0][4][0] = (2398.0 + 1205.0 * ConstSqrt2) /
235 (2835.0 * (4.0 + 3.0 * ConstSqrt2));
236
237 phase->m_A[0][1][1] = phase->m_A[0][1][0];
238 phase->m_A[0][2][1] = phase->m_A[0][2][0];
239 phase->m_A[0][3][1] = phase->m_A[0][3][0];
240 phase->m_A[0][4][1] = phase->m_A[0][4][0];
241
242 phase->m_A[0][2][2] = lambda;
243 phase->m_A[0][3][2] = -7.0 / (40.0 * (1.0 + ConstSqrt2));
244 phase->m_A[0][4][2] = -2374.0 * (1.0 + 2.0 * ConstSqrt2) /
245 (2835.0 * (5.0 + 3.0 * ConstSqrt2));
246
247 phase->m_A[0][3][3] = lambda;
248 phase->m_A[0][4][3] = 5827.0 / 7560.0;
249
250 phase->m_A[0][4][4] = lambda;
251
252 phase->m_B[0][0][0] = phase->m_A[0][4][0];
253 phase->m_B[0][0][1] = phase->m_A[0][4][1];
254 phase->m_B[0][0][2] = phase->m_A[0][4][2];
255 phase->m_B[0][0][3] = phase->m_A[0][4][3];
256 phase->m_B[0][0][4] = phase->m_A[0][4][4];
257 }
258 break;
259
260 case 4:
261 {
262 // See: Kennedy, Christopher A., and Mark H. Carpenter.
263 // Diagonally implicit Runge-Kutta methods for ordinary
264 // differential equations. A review. No. NF1676L-19716. 2016.
265 ASSERTL0(6 == phase->m_numstages,
266 std::string("DIRKOrder4_ES" +
267 std::to_string(phase->m_numstages) +
268 " not defined"));
269
270 NekDouble lambda =
271 (freeParams.size()) ? freeParams[0] : 1.0 / 4.0;
272
273 phase->m_A[0][0][0] = 0.0;
274 phase->m_A[0][1][0] = lambda;
275 phase->m_A[0][2][0] = (1.0 - ConstSqrt2) / 8.0;
276 phase->m_A[0][3][0] = (5.0 - 7.0 * ConstSqrt2) / 64.0;
277 phase->m_A[0][4][0] =
278 (-13796.0 - 54539.0 * ConstSqrt2) / 125000.0;
279 phase->m_A[0][5][0] = (1181.0 - 987.0 * ConstSqrt2) / 13782.0;
280
281 phase->m_A[0][1][1] = phase->m_A[0][1][0];
282 phase->m_A[0][2][1] = phase->m_A[0][2][0];
283 phase->m_A[0][3][1] = phase->m_A[0][3][0];
284 phase->m_A[0][4][1] = phase->m_A[0][4][0];
285 phase->m_A[0][5][1] = phase->m_A[0][5][0];
286
287 phase->m_A[0][2][2] = lambda;
288 phase->m_A[0][3][2] = 7.0 * (1.0 + ConstSqrt2) / 32.0;
289 phase->m_A[0][4][2] =
290 (506605.0 + 132109.0 * ConstSqrt2) / 437500.0;
291 phase->m_A[0][5][2] =
292 47.0 * (-267.0 + 1783.0 * ConstSqrt2) / 273343.0;
293
294 phase->m_A[0][3][3] = lambda;
295 phase->m_A[0][4][3] =
296 166.0 * (-97.0 + 376.0 * ConstSqrt2) / 109375.0;
297 phase->m_A[0][5][3] =
298 -16.0 * (-22922.0 + 3525.0 * ConstSqrt2) / 571953.0;
299
300 phase->m_A[0][4][4] = lambda;
301 phase->m_A[0][5][4] =
302 -15625.0 * (97.0 + 376.0 * ConstSqrt2) / 90749876.0;
303
304 phase->m_A[0][5][5] = lambda;
305
306 phase->m_B[0][0][0] = phase->m_A[0][5][0];
307 phase->m_B[0][0][1] = phase->m_A[0][5][1];
308 phase->m_B[0][0][2] = phase->m_A[0][5][2];
309 phase->m_B[0][0][3] = phase->m_A[0][5][3];
310 phase->m_B[0][0][4] = phase->m_A[0][5][4];
311 phase->m_B[0][0][5] = phase->m_A[0][5][5];
312 }
313 break;
314 default:
315 {
316 ASSERTL0(false, std::string("ESDIRK of order" +
317 std::to_string(phase->m_order) +
318 " not defined"));
319 break;
320 }
321 }
322
323 phase->m_numMultiStepValues = 1;
324 phase->m_numMultiStepImplicitDerivs = 0;
325 phase->m_numMultiStepExplicitDerivs = 0;
326 phase->m_timeLevelOffset = Array<OneD, size_t>(phase->m_numsteps);
327 phase->m_timeLevelOffset[0] = 0;
328
329 phase->CheckAndVerify();
330 }
331
332protected:
333 LUE std::string v_GetName() const override
334 {
335 return std::string("DIRK");
336 }
337
339 {
340 return 1.0;
341 }
342
343}; // end class DIRKTimeIntegrationScheme
344
345} // namespace Nektar::LibUtilities
346
347#endif
#define ASSERTL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
static LUE void SetupSchemeDataESDIRK(TimeIntegrationAlgorithmGLMSharedPtr &phase, std::string variant, size_t order, std::vector< NekDouble > freeParams)
static LUE void SetupSchemeData(TimeIntegrationAlgorithmGLMSharedPtr &phase, size_t order)
DIRKTimeIntegrationScheme(std::string variant, size_t order, std::vector< NekDouble > freeParams)
static TimeIntegrationSchemeSharedPtr create(std::string variant, size_t order, std::vector< NekDouble > freeParams)
Base class for GLM time integration schemes.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< TimeIntegrationAlgorithmGLM > TimeIntegrationAlgorithmGLMSharedPtr
@ eDiagonallyImplicit
Diagonally implicit scheme (e.g. the DIRK schemes)
std::vector< TimeIntegrationAlgorithmGLMSharedPtr > TimeIntegrationAlgorithmGLMVector
std::shared_ptr< TimeIntegrationScheme > TimeIntegrationSchemeSharedPtr
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290