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