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