1 //
2 // fjt.cc
3 //
4 // Copyright (C) 2001 Edward Valeev
5 //
6 // Author: Edward Valeev <edward.valeev@chemistry.gatech.edu>
7 // Maintainer: EV
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 #ifdef __GNUG__
29 #pragma implementation
30 #endif
31 
32 /* These routines are based on the gamfun program of
33  * Trygve Ulf Helgaker (fall 1984)
34  * and calculates the incomplete gamma function as
35  * described by McMurchie & Davidson, J. Comp. Phys. 26 (1978) 218.
36  * The original routine computed the function for maximum j = 20.
37  */
38 
39 #include <stdlib.h>
40 #include <util/misc/math.h>
41 
42 #include <iostream>
43 #include <chemistry/qc/cints/fjt.h>
44 
45 using namespace std;
46 
47 /*------------------------------------------------------
48   Initialize Taylor_Fm_Eval object (computes incomplete
49   gamma function via Taylor interpolation)
50  ------------------------------------------------------*/
Taylor_Fjt_Eval(unsigned int mmax,double accuracy)51 Taylor_Fjt_Eval::Taylor_Fjt_Eval(unsigned int mmax, double accuracy)
52 {
53   int i, m;
54   int T_idx;
55   double T, T_new;
56   double egamma, func, dfuncdT;
57   double term, sum, denom, rel_error;
58 
59   cutoff = epsilon;
60   /*---------------------------------------
61     We are doing Taylor interpolation with
62     n=TAYLOR_ORDER terms here:
63     error <= delT^n/(n+1)!
64    ---------------------------------------*/
65   order_interp = TAYLOR_ORDER;
66   delT = 2.0*pow(cutoff*fac[order_interp+1],
67 			1.0/order_interp);
68   max_m = mmax + order_interp - 1;
69 
70   /*------------------------------------------------
71      Check if Taylor_Fm_Eval has been initialized with
72      the same mmax before:
73      2) yes  - re-initialize again
74      3) no - initialize
75    ------------------------------------------------*/
76   if (grid != NULL || T_crit != NULL) {
77     free_Taylor_Fm_Eval();
78   }
79 
80   T_crit = new double[max_m + 1];   /*--- m=0 is included! ---*/
81   max_T = 0;
82   /*--- Figure out T_crit for each m and put into the T_crit ---*/
83   for(m=max_m;m>=0;m--) {
84     /*------------------------------------------
85       Newton-Raphson method to solve
86       T^{m-0.5}*exp(-T) = epsilon*Gamma(m+0.5)
87       The solution is the max T for which to do
88       the interpolation
89      ------------------------------------------*/
90     T = -log(epsilon);
91     egamma = epsilon*sqrt(M_PI)*df[2*m]/pow(2,m);
92     T_new = T;
93     do {
94       T = T_new;
95       func = pow(T,m-0.5) * exp(-T) - egamma;
96       dfuncdT = ((m-0.5) * pow(T,m-1.5) - pow(T,m-0.5)) * exp(-T);
97       if (dfuncdT >= 0.0) {
98 	T_new *= 2.5;
99 	continue;
100       }
101       T_new = T - func/dfuncdT;
102       if ( T_new <= 0.0 ) {
103 	T_new = T / 2.0;
104       }
105     } while (fabs(func/egamma) >= SOFT_ZERO);
106     T_crit[m] = T_new;
107     T_idx = floor(T_new/delT);
108     if (T_idx > max_T)
109       max_T = T_idx;
110   }
111 
112   /*-------------------------------------------------------
113     Tabulate the gamma function from t=delT to T_crit[m]:
114     1) include T=0 though the table is empty for T=0 since
115        Fm(0) is simple to compute
116     2) modified MacLaurin series converges fastest for
117        the largest m -> use it to compute Fmmax(T)
118        see JPC 94, 5564 (1990).
119     3) then either use the series to compute the rest
120        of the row or maybe use downward recursion
121    -------------------------------------------------------*/
122   grid = block_matrix(max_T+1,max_m+1);
123   /*--- do the mmax first ---*/
124   for(m=0;m<=max_m;m++)
125   for(T_idx = max_T;
126       T_idx >= 0;
127       T_idx--) {
128     T = T_idx*delT;
129     denom = (m+0.5);
130     term = 0.5*exp(-T)/denom;
131     sum = term;
132     do {
133       denom += 1.0;
134       term *= T/denom;
135       sum += term;
136       rel_error = term/sum;
137     } while (rel_error >= cutoff);
138 
139     grid[T_idx][m] = sum;
140   }
141 
142 }
143 
~Taylor_Fm_Eval()144 Taylor_Fjt_Eval::~Taylor_Fm_Eval()
145 {
146   delete[] T_crit;
147   T_crit = NULL;
148   free_block(grid);
149   grid = NULL;
150 }
151 
152 /* Using the tabulated incomplete gamma function in gtable, compute
153  * the incomplete gamma function for a particular wval for all 0<=j<=J.
154  * The result is placed in the global intermediate int_fjttable.
155  */
156 double *
compute_Fjt(double T,unsigned int l)157 Taylor_Fjt_Eval::compute_Fjt(double T, unsigned int l)
158 {
159 
160     int m;
161   unsigned int T_ind;
162   double T_crit, two_T, exp_mT, h, F_m, F_mp1;
163   double *F_row;
164 
165 #define STATIC_OO2NP1
166 #define STATIC_OON
167 #include "static.h"
168 
169   T_crit = Taylor_Fm_Eval.T_crit[l];
170   two_T = 2.0*T;
171 
172   /*------------------------
173     First compute Fl(T) ...
174    ------------------------*/
175   if (T > T_crit) {
176     /*--- Asymptotic formula ---*/
177     F[l] = df[2*l]*sqrt(M_PI/2)/pow(two_T,l+0.5);
178   }
179   else {
180     /*--- Taylor interpolation ---*/
181     T_ind = floor(0.5+T/Taylor_Fm_Eval.delT);
182     h = T_ind*Taylor_Fm_Eval.delT - T;
183     F_row = Taylor_Fm_Eval.grid[T_ind] + l;
184     F[l] =          F_row[0] +
185 	         h*(F_row[1] +
186 	  oon[2]*h*(F_row[2] +
187 	  oon[3]*h*(F_row[3] +
188 	  oon[4]*h*(F_row[4] +
189 	  oon[5]*h*(F_row[5])))));
190   }
191 
192   /*------------------------------------
193     And then do downward recursion in m
194    ------------------------------------*/
195   if (l > 0) {
196     F_mp1 = F[l];
197     exp_mT = exp(-T);
198     for(m=l-1;m>=0;m--) {
199       F_m = (exp_mT + two_T*F_mp1)*oo2np1[m];
200       F[m] = F_m;
201       F_mp1 = F_m;
202     }
203   }
204 
205   return Fjt_buffer;
206 }
207 
208 /////////////////////////////////////////////////////////////////////////////
209 
210 // Local Variables:
211 // mode: c++
212 // c-file-style: "CLJ-CONDENSED"
213 // End:
214