Nektar++
TimeIntegrationSchemeGEM.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: TimeIntegrationSchemeGEM.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: Implementation of time integration scheme GEM class
32//
33///////////////////////////////////////////////////////////////////////////////
34
36
38{
39
41{
42 return m_name;
43}
44
46{
47 return m_variant;
48}
49
51{
52 return m_order;
53}
54
55std::vector<NekDouble> TimeIntegrationSchemeGEM::v_GetFreeParams() const
56{
57 return m_freeParams;
58}
59
61 const
62{
63 return m_schemeType;
64}
65
67{
68 return 1.0;
69}
70
72{
73 return 1;
74}
75
77{
78 return m_Y;
79}
80
82{
83 return m_Y;
84}
85
87 const DoubleArray &y)
88{
89 m_Y[Offset] = y;
90}
91
92/**
93 * @brief Worker method to initialize the integration scheme.
94 */
96 [[maybe_unused]] const NekDouble deltaT, ConstDoubleArray &y_0,
97 const NekDouble time, const TimeIntegrationSchemeOperators &op)
98
99{
100 if (m_initialized)
101 {
102 m_time = time;
103 for (size_t i = 0; i < m_nvars; ++i)
104 {
105 // Store the initial values as the first previous state.
106 Vmath::Vcopy(m_npoints, y_0[i], 1, m_Y[0][i], 1);
107 }
108 }
109 else
110 {
111 m_op = op;
112 m_time = time;
113 m_nvars = y_0.size();
114 m_npoints = y_0[0].size();
115
116 size_t nodes = m_order;
117 if (m_variant == "ExplicitMidpoint" || m_variant == "ImplicitMidpoint")
118 {
119 nodes /= 2;
120 }
121
122 // Storage of previous states and associated timesteps.
123 m_Y = TripleArray(m_order + 1);
124 m_T = TripleArray(nodes);
125 m_T0 = TripleArray(nodes);
126
127 for (size_t m = 0; m <= m_order; ++m)
128 {
129 m_Y[m] = DoubleArray(m_nvars);
130
131 for (size_t i = 0; i < m_nvars; ++i)
132 {
133 m_Y[m][i] = SingleArray(m_npoints, 0.0);
134
135 // Store the initial values as the first previous state.
136 if (m == 0)
137 {
138 Vmath::Vcopy(m_npoints, y_0[i], 1, m_Y[m][i], 1);
139 }
140 }
141 }
142
143 if (m_variant == "" || m_variant == "ExplicitEuler" ||
144 m_variant == "ExplicitMidpoint")
145 {
146 m_op.DoProjection(m_Y[0], m_Y[0], m_time);
147 }
148
149 for (size_t m = 0; m < nodes; ++m)
150 {
151 m_T[m] = DoubleArray(m_nvars);
153
154 for (size_t i = 0; i < m_nvars; ++i)
155 {
156 m_T[m][i] = SingleArray(m_npoints, 0.0);
157 m_T0[m][i] = SingleArray(m_npoints, 0.0);
158 }
159 }
160
161 // Storage for the stage derivative as the data will be re-used to
162 // update the solution.
165
166 for (size_t i = 0; i < m_nvars; ++i)
167 {
168 m_F[i] = SingleArray(m_npoints, 0.0);
169 m_F0[i] = SingleArray(m_npoints, 0.0);
170 }
171
172 m_initialized = true;
173 }
174}
175
176/**
177 * @brief Worker method that performs the time integration.
178 */
180 [[maybe_unused]] const size_t timestep, const NekDouble delta_t)
181{
182 // Compute initial residual
183 if (m_variant == "" || m_variant == "ExplicitEuler" ||
184 m_variant == "ExplicitMidpoint" || m_variant == "IMEXEuler")
185 {
187 }
188
189 // Euler approach
190 if (m_variant == "" || m_variant == "ExplicitEuler" ||
191 m_variant == "ImplicitEuler" || m_variant == "IMEXEuler")
192 {
193 // Compute first order approximation
194 for (size_t m = 1; m <= m_order; ++m)
195 {
196 for (size_t k = 1; k <= m; ++k)
197 {
198 // Implicit schemes
199 if (m_variant == "ImplicitEuler")
200 {
201 m_op.DoImplicitSolve(m_Y[k - 1], m_Y[k],
202 m_time + k * (delta_t / m),
203 delta_t / m);
204 }
205
206 // Explicit schemes
207 if (m_variant == "" || m_variant == "ExplicitEuler" ||
208 m_variant == "IMEXEuler")
209 {
210 // For the first stage, used pre-computed rhs
211 if (k == 1)
212 {
213 for (size_t i = 0; i < m_nvars; ++i)
214 {
215 Vmath::Svtvp(m_npoints, delta_t / m, m_F0[i], 1,
216 m_Y[k - 1][i], 1, m_Y[k][i], 1);
217 }
218 }
219 // For other stages, compute new rhs
220 else
221 {
222 m_op.DoOdeRhs(m_Y[k - 1], m_F,
223 m_time + (k - 1) * (delta_t / m));
224 for (size_t i = 0; i < m_nvars; ++i)
225 {
226 Vmath::Svtvp(m_npoints, delta_t / m, m_F[i], 1,
227 m_Y[k - 1][i], 1, m_Y[k][i], 1);
228 }
229 }
230 }
231 if (m_variant == "" || m_variant == "ExplicitEuler")
232 {
233 m_op.DoProjection(m_Y[k], m_Y[k],
234 m_time + k * (delta_t / m));
235 }
236
237 // IMEX schemes (NOTE: Order reduction problems)
238 if (m_variant == "IMEXEuler")
239 {
241 m_time + k * (delta_t / m),
242 delta_t / m);
243 }
244 }
245
246 // Save solution to m_T0
247 for (size_t i = 0; i < m_nvars; ++i)
248 {
249 Vmath::Vcopy(m_npoints, m_Y[m][i], 1, m_T0[m - 1][i], 1);
250 }
251 }
252
253 // No extrapolation required for first-order
254 if (m_order == 1)
255 {
256 for (size_t i = 0; i < m_nvars; ++i)
257 {
258 Vmath::Vcopy(m_npoints, m_Y[1][i], 1, m_Y[0][i], 1);
259 }
260 m_time += delta_t;
261 return m_Y[0];
262 }
263
264 // Extrapolate solution
265 for (size_t m = 1; m < m_order; ++m)
266 {
267 // Aitken - Neville formula
268 for (size_t k = m; k < m_order; ++k)
269 {
270 for (size_t i = 0; i < m_nvars; ++i)
271 {
272 Vmath::Vsub(m_npoints, m_T0[k][i], 1, m_T0[k - 1][i], 1,
273 m_T[k][i], 1);
275 (k - m + 1.0) / ((k + 1.0) - (k - m + 1.0)),
276 m_T[k][i], 1, m_T0[k][i], 1, m_T[k][i], 1);
277 }
278 }
279
280 // Copy new values to old values
281 for (size_t k = m; k < m_order; ++k)
282 {
283 for (size_t i = 0; i < m_nvars; ++i)
284 {
285 Vmath::Vcopy(m_npoints, m_T[k][i], 1, m_T0[k][i], 1);
286 }
287 }
288 }
289
290 // Copy final solution
291 for (size_t i = 0; i < m_nvars; ++i)
292 {
293 Vmath::Vcopy(m_npoints, m_T[m_order - 1][i], 1, m_Y[0][i], 1);
294 }
295 }
296 // Midpoint approach
297 else if (m_variant == "ExplicitMidpoint" || m_variant == "ImplicitMidpoint")
298 {
299 // Compute second order approximation
300 for (size_t m = 1; m <= m_order / 2; ++m)
301 {
302 // Implicit midpoint
303 if (m_variant == "ImplicitMidpoint")
304 {
305 for (size_t k = 1; k <= m; ++k)
306 {
307 m_op.DoImplicitSolve(m_Y[2 * k - 2], m_Y[2 * k - 1],
308 m_time +
309 (k - 1 + 0.25) * (delta_t / m),
310 0.25 * delta_t / m);
311 for (size_t i = 0; i < m_nvars; ++i)
312 {
313 Vmath::Svtsvtp(m_npoints, 2.0, m_Y[2 * k - 1][i], 1,
314 -1.0, m_Y[2 * k - 2][i], 1,
315 m_Y[2 * k][i], 1);
316 }
317 m_op.DoImplicitSolve(m_Y[2 * k], m_F,
318 m_time + (k - 0.25) * (delta_t / m),
319 0.25 * delta_t / m);
320 for (size_t i = 0; i < m_nvars; ++i)
321 {
322 Vmath::Vsub(m_npoints, m_F[i], 1, m_Y[2 * k][i], 1,
323 m_F[i], 1);
324 Vmath::Svtvp(m_npoints, 2.0, m_F[i], 1, m_Y[2 * k][i],
325 1, m_Y[2 * k][i], 1);
326 }
327 }
328 }
329
330 // Explicit midpoint
331 if (m_variant == "ExplicitMidpoint")
332 {
333 // Use precomputed rhs for initial Euler stage
334 for (size_t i = 0; i < m_nvars; ++i)
335 {
336 Vmath::Svtvp(m_npoints, delta_t / (2 * m), m_F0[i], 1,
337 m_Y[0][i], 1, m_Y[1][i], 1);
338 }
339 m_op.DoProjection(m_Y[1], m_Y[1], m_time + delta_t / (2 * m));
340
341 // Compute new rhs for midpoint stage
342 for (size_t k = 2; k <= 2 * m; ++k)
343 {
344 m_op.DoOdeRhs(m_Y[k - 1], m_F,
345 m_time + (k - 1) * (delta_t / (2 * m)));
346 for (size_t i = 0; i < m_nvars; ++i)
347 {
348 Vmath::Svtvp(m_npoints, delta_t / m, m_F[i], 1,
349 m_Y[k - 2][i], 1, m_Y[k][i], 1);
350 }
351 m_op.DoProjection(m_Y[k], m_Y[k],
352 m_time + k * (delta_t / (2 * m)));
353 }
354 }
355
356 // Save solution to m_T0
357 for (size_t i = 0; i < m_nvars; ++i)
358 {
359 Vmath::Vcopy(m_npoints, m_Y[2 * m][i], 1, m_T0[m - 1][i], 1);
360 }
361 }
362
363 // No extrapolation required for second-order
364 if (m_order == 2)
365 {
366 for (size_t i = 0; i < m_nvars; ++i)
367 {
368 Vmath::Vcopy(m_npoints, m_Y[2][i], 1, m_Y[0][i], 1);
369 }
370 m_time += delta_t;
371 return m_Y[0];
372 }
373
374 // Extrapolate solution
375 for (size_t m = 1; m < m_order / 2; ++m)
376 {
377 // Aitken - Neville formula
378 for (size_t k = m; k < m_order / 2; ++k)
379 {
380 for (size_t i = 0; i < m_nvars; ++i)
381 {
382 Vmath::Vsub(m_npoints, m_T0[k][i], 1, m_T0[k - 1][i], 1,
383 m_T[k][i], 1);
385 m_npoints,
386 std::pow(k - m + 1.0, 2) /
387 (std::pow(k + 1.0, 2) - std::pow(k - m + 1.0, 2)),
388 m_T[k][i], 1, m_T0[k][i], 1, m_T[k][i], 1);
389 }
390 }
391
392 // Copy new values to old values
393 for (size_t k = m; k < m_order / 2; ++k)
394 {
395 for (size_t i = 0; i < m_nvars; ++i)
396 {
397 Vmath::Vcopy(m_npoints, m_T[k][i], 1, m_T0[k][i], 1);
398 }
399 }
400 }
401
402 // Copy final solution
403 for (size_t i = 0; i < m_nvars; ++i)
404 {
405 Vmath::Vcopy(m_npoints, m_T[m_order / 2 - 1][i], 1, m_Y[0][i], 1);
406 }
407 }
408
409 // Return solution
410 m_time += delta_t;
411 return m_Y[0];
412}
413
414/**
415 * @brief Worker method to print details on the integration scheme
416 */
417void TimeIntegrationSchemeGEM::v_print(std::ostream &os) const
418{
419 os << "Time Integration Scheme: " << GetFullName() << std::endl;
420}
421
422void TimeIntegrationSchemeGEM::v_printFull(std::ostream &os) const
423{
424 os << "Time Integration Scheme: " << GetFullName() << std::endl;
425}
426
427// Friend Operators
428std::ostream &operator<<(std::ostream &os, const TimeIntegrationSchemeGEM &rhs)
429{
430 rhs.print(os);
431
432 return os;
433}
434
435std::ostream &operator<<(std::ostream &os,
437{
438 os << *rhs.get();
439
440 return os;
441}
442} // namespace Nektar::LibUtilities
Class for spectral deferred correction integration.
LUE TimeIntegrationSchemeType v_GetIntegrationSchemeType() const override
LUE void v_printFull(std::ostream &os) const override
LUE void v_SetSolutionVector(const size_t Offset, const DoubleArray &y) override
LUE const TripleArray & v_GetSolutionVector() const override
LUE void v_print(std::ostream &os) const override
Worker method to print details on the integration scheme.
DoubleArray m_F
Array containing the solution values.
size_t m_order
Array corresponding to the stage Derivatives.
TripleArray m_T
Array containing the stage values.
DoubleArray m_F0
Array corresponding to the stage Derivatives.
TripleArray m_T0
Array containing the solution values.
LUE ConstDoubleArray & v_TimeIntegrate(const size_t timestep, const NekDouble delta_t) override
Worker method that performs the time integration.
LUE std::vector< NekDouble > v_GetFreeParams() const override
LUE void v_InitializeScheme(const NekDouble deltaT, ConstDoubleArray &y_0, const NekDouble time, const TimeIntegrationSchemeOperators &op) override
Worker method to initialize the integration scheme.
Binds a set of functions for use by time integration schemes.
void DoImplicitSolve(InArrayType &inarray, OutArrayType &outarray, const NekDouble time, const NekDouble lambda) const
void DoProjection(InArrayType &inarray, OutArrayType &outarray, const NekDouble time) const
void DoOdeRhs(InArrayType &inarray, OutArrayType &outarray, const NekDouble time) const
AT< AT< NekDouble > > DoubleArray
AT< AT< AT< NekDouble > > > TripleArray
std::shared_ptr< TimeIntegrationSchemeGEM > TimeIntegrationSchemeGEMSharedPtr
std::ostream & operator<<(std::ostream &os, const BasisKey &rhs)
double NekDouble
void Svtsvtp(int n, const T alpha, const T *x, int incx, const T beta, const T *y, int incy, T *z, int incz)
Svtsvtp (scalar times vector plus scalar times vector):
Definition: Vmath.hpp:473
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 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