MADNESS  0.10.1
spectralprop.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31  $Id$
32 */
33 /*!
34  \file spectralprop.h
35  \brief Spectral propagator in time using semigroup approach
36  \defgroup spectralprop Spectral propagator in time using semigroup approach
37  \ingroup examples
38 
39  The source is <a href=http://code.google.com/p/m-a-d-n-e-s-s/source/browse/local/trunk/src/apps/examples/spectralprop.h>here</a>.
40 
41  \par Points of interest
42  - high-order integration of general time-dependent problems
43  - semigroup approach
44 
45  \par Background
46 
47  Given \f$ u(0) \f$, we seek to solve the PDE
48  \f[
49  \frac{du}{dt} = \hat{L} u + N(u)
50  \f]
51  for the function at some future time \f$ t \f$ (i.e., for \f$ u(t) \f$).
52  \f$ \hat{L} \f$ is a linear operator that we are
53  able to exponentiate, and \f$ N \f$ is everything else
54  including linear and non-linear parts.
55 
56  In the semigroup approach the formal solution to the PDE
57  is written
58  \f[
59  u(t) = \exp(t \hat{L} ) u(0) + \int_0^t \exp((t-\tau)\hat{L}) N(u(\tau)) d\tau
60  \f]
61  Numerical quadrature of the integral using Gauss-Legendre
62  quadrature points is used resulting in a set of equations
63  that are iteratively solved (presently using simple fixed
64  point iteration from a first-order explicit rule).
65 
66  The user provides
67  - functors to apply the exponential and non-linear parts, and
68  - if necessary a user-defined data type that supports
69  a copy constructor, assignment, inplace addition, multiplication
70  from the right by a double, and computation of the distance
71  between two solutions \f$ a \f$ and \f$ b \f$ with the api
72  \verb+double distance(a,b)+
73 
74  Have a look in testspectralprop.cc for example use.
75 
76  With \f$ n \f$ quadrature points, the error is \f$ O\left(t^{2n+1}\right) \f$
77  and the number of applications of the exponential operator per
78  time step is \f$ 1+(n_{it}+1)n +n_{it}n^2 \f$ where \f$ n_{it} \f$
79  is the number of iterations necessary to solve the equations
80  (typically about 5 but this is problem dependent).
81 
82 */
83 
84 
85 #include <madness/mra/legendre.h>
87 
88 #include <algorithm>
89 #include <cmath>
90 #include <complex>
91 
92 namespace madness {
93 
94  /// Default function for computing the distance between two doubles
95  inline double distance(double a, double b)
96  {
97  return std::sqrt((a-b)*(a-b));
98  }
99 
100  /// Default function for computing the distance between two complex numbers
101  template <typename T>
102  inline double distance(std::complex<T>& a, std::complex<T>& b)
103  {
104  return std::abs(a-b);
105  }
106 
107 
108  /// Spectral propagtor in time. Refer to documentation of file spectralprop.h for math detail.
110  const int NPT; ///< Number of quadrature points
111  std::vector<double> x; ///< Quadrature points on [0,1] with value 0 prepended
112  std::vector<double> w; ///< Quadrature weights on [0,1] with value 0 prepended
114 
115  /// Private: Makes interpolating polyn p[i](t), i=0..NPT
116  double p(int i, double t) {
117  double top=1.0, bot=1.0;
118  for (int j=0; j<i; j++) {
119  top *= (t-x[j]);
120  bot *= (x[i]-x[j]);
121  }
122  for (int j=i+1; j<=NPT; j++) {
123  top *= (t-x[j]);
124  bot *= (x[i]-x[j]);
125  }
126  return top/bot;
127  }
128 
129  /// Private: Computes interpolated solution
130  template <typename uT>
131  uT u(double dt, const std::vector<uT>& v) {
132  uT U = v[0]*p(0,dt);
133  for (int i=1; i<=NPT; i++) {
134  U += v[i]*p(i,dt);
135  }
136  return U;
137  }
138 
139  // Separated this out to enable recursive use of solver ... but this
140  // turned out to be largely not useful.
141  template <typename uT, typename expLT, typename NT>
142  std::vector<uT> solve(double t, double Delta, const uT& u0, const expLT& expL, const NT& N, const double eps, bool doprint, bool recurinit, int& napp) {
143  if (doprint) madness::print("solving with NPT", NPT);
144  std::vector<uT> v(NPT+1,u0);
145 
146  if (!recurinit || NPT==1) {
147  // Initialize using explicit first-order accurate rule
148  for (int i=1; i<=NPT; i++) {
149  double dt = x[i] - x[i-1];
150  v[i] = expL(dt*Delta,v[i-1]);
151  v[i] += expL(Delta*dt,N(t+Delta*x[i-1],v[i-1]))*(dt*Delta);
152  }
153  }
154  else {
155  // Recur down to lower-order quadrature rules for initial guess
156  std::vector<uT> vx = q->solve(t, Delta, u0, expL, N, eps*10000.0, doprint, recurinit, napp);
157  for (int i=1; i<=NPT; i++) {
158  v[i] = q->u(x[i],vx);
159  }
160  }
161 
162  // Precompute G(x[1]-x[0])*v[0]
163  uT Gv0 = expL((x[1] - x[0])*Delta,v[0]); napp++;
164 
165  // Crude fixed point iteration
166  uT vold = v[NPT]; // Track convergence thru change at last quadrature point
167  bool converged = false;
168  for (int iter=0; iter<20; iter++) {
169  for (int i=1; i<=NPT; i++) {
170  double dt = x[i] - x[i-1];
171  uT vinew = (i==0) ? Gv0*1.0 : expL(dt*Delta,v[i-1]); // *1.0 in case copy is shallow
172  if (i != 0) napp++;
173  for (int k=1; k<=NPT; k++) {
174  double ddt = x[i-1] + dt*x[k];
175  vinew += expL(dt*Delta*(1.0-x[k]), N(t + Delta*ddt, u(ddt, v)))*(dt*Delta*w[k]); napp++;
176  }
177  v[i] = vinew;
178  }
179  double err = ::madness::distance(v[NPT],vold);
180  vold = v[NPT];
181  if (doprint) print("spectral",iter,err);
182  converged = (err < eps);
183  if (converged) break;
184  }
185  if (!converged) throw "spectral propagator failed to converge";
186 
187  return v;
188  }
189 
190  public:
191  /// Construct propagator using \c NPT points
193  : NPT(NPT)
194  , x(NPT+1)
195  , w(NPT+1)
196  , q(0)
197  {
198  x[0] = w[0] = 0.0;
199  MADNESS_ASSERT(gauss_legendre(NPT, 0.0, 1.0, &x[1], &w[1]));
200 
201  // The iterative solution requires quadrature points in increasing
202  // order corresponding to shooting forward.
203  std::reverse(x.begin()+1, x.end());
204  std::reverse(w.begin()+1, w.end());
205 
206  if (NPT > 1) q = new SpectralPropagator(NPT-1);
207  }
208 
210  {
211  delete q;
212  }
213 
214  /// Step forward in time from \f$ t \f$ to \f$ t+\Delta \f$
215 
216  /// The template types should be automatically inferred from
217  /// the invocation. \c uT is the C++ type for the solution.
218  ///
219  /// @param[in] t The current time
220  /// @param[in] Delta The time step
221  /// @param[in] u0 The solution at the current time
222  /// @param[in] expL A function or functor to compute \f$ \exp{\tau \hat{L}} u \f$ for \f$ \tau \in (0,\Delta) \f$
223  /// @param[in] N A function to compute the non-linear part
224  /// @param[in] eps Threshold for convergence of iteration on norm of change in solution at last quadrature point.
225  /// @param[in] doprint If true will print some info on convergence
226  /// @param[in] recurinit If true initial guess is recursion from lower order quadrature instead of default explicit rule
227  /// @returns The solution at time \f$ t+\Delta \f$
228  ///
229  /// The user provided operators are invoked as
230  /// \code
231  /// uT expL(double tau, const uT& u)
232  /// \endcode
233  /// where \f$ \tau \in (0,\Delta) \f$
234  /// and
235  /// \code
236  /// uT N(double T, const uT& u)
237  /// \endcode
238  /// where \f$ T \in (t,t+\Delta) \f$ and \f$ u \f$ is a trial solution at time \f$ T \f$.
239  template <typename uT, typename expLT, typename NT>
240  uT step(double t, double Delta, const uT& u0, const expLT& expL, const NT& N, const double eps=1e-12, bool doprint=false, bool recurinit=true) {
241  int napp = 0;
242 
243  // Compute solution at quadrature points
244  std::vector<uT> v = solve(t, Delta, u0, expL, N, eps, doprint, recurinit, napp);
245 
246  // Integrate forward from last quadrature point to the end point
247  double dt = 1.0 - x[NPT];
248  uT vinew = expL(dt*Delta,v[NPT]);
249  for (int k=1; k<=NPT; k++) {
250  double ddt = x[NPT] + dt*x[k];
251  vinew += expL(dt*Delta*(1.0-x[k]), N(t + Delta*ddt, u(ddt, v)))*(dt*Delta*w[k]); napp++;
252  }
253 
254  if (doprint) print("number of operator applications", napp);
255  return vinew;
256  }
257  };
258 
260  const int NPT;
261  std::vector<double> x;
262  std::vector<double> w;
263 
264  // Makes interpolating polyn p[i](t), i=0..NPT-1
265  double p(int i, double t) {
266  double top=1.0, bot=1.0;
267  for (int j=0; j<i; j++) {
268  top *= (t-x[j]);
269  bot *= (x[i]-x[j]);
270  }
271  for (int j=i+1; j<NPT; j++) {
272  top *= (t-x[j]);
273  bot *= (x[i]-x[j]);
274  }
275  return top/bot;
276  }
277 
278  template <typename uT>
279  uT u(double dt, const std::vector<uT>& v) {
280  uT U = v[0]*p(0,dt);
281  for (int i=1; i<NPT; i++) {
282  U += v[i]*p(i,dt);
283  }
284  return U;
285  }
286 
287  public:
288  // Constructor
289  // ... input ... npt,
290  // ... makes ... x, w, p
291  //
292  // Apply
293  // ... input ... u(0)
294  // ... makes guess v(i), i=0..npt using explicit 1st order rule.
295 
297  : NPT(NPT)
298  , x(NPT)
299  , w(NPT)
300  {
301  MADNESS_ASSERT(NPT>=2 && NPT<=6);
302  // Gauss Lobatto on [-1,1]
303  x[0] = -1.0; x[NPT-1] = 1.0; w[0] = w[NPT-1] = 2.0/(NPT*(NPT-1));
304  if (NPT == 2) {
305  }
306  else if (NPT == 3) {
307  x[1] = 0.0; w[1] = 4.0/3.0;
308  }
309  else if (NPT == 4) {
310  x[1] = -1.0/std::sqrt(5.0); w[1] = 5.0/6.0;
311  x[2] = -x[1]; w[2] = w[1];
312  }
313  else if (NPT == 5) {
314  x[1] = -std::sqrt(3.0/7.0); w[1] = 49.0/90.0;
315  x[2] = 0.0; w[2] = 32.0/45.0;
316  x[3] = -x[1]; w[3] = w[1];
317  }
318  else if (NPT == 6) {
319  x[1] = -std::sqrt((7.0+2.0*std::sqrt(7.0))/21.0); w[1] = (14.0-std::sqrt(7.0))/30.0;
320  x[2] = -std::sqrt((7.0-2.0*std::sqrt(7.0))/21.0); w[2] = (14.0+std::sqrt(7.0))/30.0;
321  x[3] = -x[2]; w[3] = w[2];
322  x[4] = -x[1]; w[4] = w[1];
323  }
324  else {
325  throw "bad NPT";
326  }
327 
328  // Map from [-1,1] onto [0,1]
329  for (int i=0; i<NPT; i++) {
330  x[i] = 0.5*(1.0 + x[i]);
331  w[i] = 0.5*w[i];
332  }
333  }
334 
335  template <typename uT, typename expLT, typename NT>
336  uT step(double t, double Delta, const uT& u0, const expLT& expL, const NT& N, const double eps=1e-12, bool doprint=false) {
337  std::vector<uT> v(NPT,u0);
338 
339  // Initialize using explicit first-order accurate rule
340  for (int i=1; i<NPT; i++) {
341  double dt = x[i] - x[i-1];
342  v[i] = expL(dt*Delta,v[i-1]);
343  v[i] += expL(Delta*dt,N(t+Delta*x[i-1],v[i-1]))*(dt*Delta);
344  }
345 
346  // Crude fixed point iteration
347  uT vold = v[NPT-1];
348  for (int iter=0; iter<12; iter++) {
349  for (int i=1; i<NPT; i++) {
350  double dt = x[i] - x[i-1];
351  uT vinew = expL(dt*Delta,v[i-1]);
352  for (int k=0; k<NPT; k++) {
353  double ddt = x[i-1] + dt*x[k];
354  vinew += expL(dt*Delta*(1.0-x[k]), N(t + Delta*ddt, u(ddt, v)))*(dt*Delta*w[k]);
355  }
356  v[i] = vinew;
357  }
358  double err = ::madness::distance(vold, v[NPT-1]);
359  if (doprint) print("hello",iter,err);
360  vold = v[NPT-1];
361  if (err < eps) break;
362  }
363 
364  return vold;
365  }
366  };
367 
368 }
Definition: spectralprop.h:259
uT u(double dt, const std::vector< uT > &v)
Definition: spectralprop.h:279
std::vector< double > x
Definition: spectralprop.h:261
uT step(double t, double Delta, const uT &u0, const expLT &expL, const NT &N, const double eps=1e-12, bool doprint=false)
Definition: spectralprop.h:336
double p(int i, double t)
Definition: spectralprop.h:265
const int NPT
Definition: spectralprop.h:260
std::vector< double > w
Definition: spectralprop.h:262
SpectralPropagatorGaussLobatto(int NPT)
Definition: spectralprop.h:296
Spectral propagtor in time. Refer to documentation of file spectralprop.h for math detail.
Definition: spectralprop.h:109
std::vector< uT > solve(double t, double Delta, const uT &u0, const expLT &expL, const NT &N, const double eps, bool doprint, bool recurinit, int &napp)
Definition: spectralprop.h:142
std::vector< double > x
Quadrature points on [0,1] with value 0 prepended.
Definition: spectralprop.h:111
double p(int i, double t)
Private: Makes interpolating polyn p[i](t), i=0..NPT.
Definition: spectralprop.h:116
SpectralPropagator(int NPT)
Construct propagator using NPT points.
Definition: spectralprop.h:192
uT u(double dt, const std::vector< uT > &v)
Private: Computes interpolated solution.
Definition: spectralprop.h:131
uT step(double t, double Delta, const uT &u0, const expLT &expL, const NT &N, const double eps=1e-12, bool doprint=false, bool recurinit=true)
Step forward in time from to .
Definition: spectralprop.h:240
~SpectralPropagator()
Definition: spectralprop.h:209
const int NPT
Number of quadrature points.
Definition: spectralprop.h:110
SpectralPropagator * q
Definition: spectralprop.h:113
std::vector< double > w
Quadrature weights on [0,1] with value 0 prepended.
Definition: spectralprop.h:112
static const double v
Definition: hatom_sf_dirac.cc:20
Defines madness::MadnessException for exception handling.
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition: madness_exception.h:134
double distance(const madness::coord_3d &a, const madness::coord_3d &b)
Definition: molecularmask.h:10
File holds all helper structures necessary for the CC_Operator and CC2 class.
Definition: DFParameters.h:10
double distance(double a, double b)
Default function for computing the distance between two doubles.
Definition: spectralprop.h:95
bool gauss_legendre(int n, double xlo, double xhi, double *x, double *w)
Definition: legendre.cc:226
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition: print.h:225
static long abs(long a)
Definition: tensor.h:218
static const double b
Definition: nonlinschro.cc:119
static const double a
Definition: nonlinschro.cc:118
static const long k
Definition: rk.cc:44
void e()
Definition: test_sig.cc:75
#define N
Definition: testconv.cc:37
Fred expL(double dt, const Fred &f)
Definition: testspectralprop.cc:98