hermite_numerov.py

Go to the documentation of this file.
00001 """Compute Hermite-Gauss basis functions very quickly and efficiently using 
00002 Numerov's method to solve the underlying differential equations"""
00003 _rcsid="$Id: hermite_numerov.py,v 1.7 2003/10/03 14:38:45 mendenhall Exp $"
00004 
00005 import math
00006 import Numeric
00007 import spline
00008 import time
00009 
00010 hermite_x_bound=15.0
00011 hermite_n_points=5000
00012 
00013 def generate_table(order, final_x=None, npoints=None):
00014     "generate a spline table of H[n](x) exp(-x^2/2) ... a Hermite-Gauss basis function, using the Numerov method"
00015     if final_x is None:
00016         final_x=hermite_x_bound
00017 
00018     if npoints is None:
00019         npoints=hermite_n_points
00020 
00021     Y=Numeric.zeros(npoints+1, Numeric.Float)
00022     dx=float(final_x)/npoints
00023     dx2=dx*dx
00024     e2=2*order+1
00025     x=-final_x+Numeric.array(range(npoints+1),Numeric.Float)*dx
00026     V=(x*x-e2)
00027     
00028     ypsifact=1.0/(1.0-(dx*dx/12.0)*V)
00029     coef=2.0+dx2*V*ypsifact
00030 
00031     Y[0]=1.0/ypsifact[0]
00032     Y[1]=math.exp(math.sqrt(V[0])*dx))/ypsifact[1]
00033             
00034     for i in range(1,npoints):
00035         yy=Y[i+1]=Y[i]*coef[i]-Y[i-1]
00036         if abs(yy) > 1e20: #don't let exponential blow up
00037             Y*=1e-20
00038 
00039     psi = Y*ypsifact
00040 
00041     x=-final_x+Numeric.array(range(2*npoints+1),Numeric.Float)*dx
00042     
00043     if order%2 == 0: #even function
00044         y=Numeric.concatenate((psi, psi[::-1][1:]))
00045     else:
00046         psi[-1]=0 #enforce oddness exactly
00047         y=Numeric.concatenate((psi, -psi[::-1][1:]))
00048 
00049     y=y*math.sqrt(1.0/(Numeric.dot(y,y)*dx))
00050     y2=spline.spline(x, y)
00051     return (final_x, x,y,y2)
00052 
00053 hermite_cache={}
00054 
00055 def hermite_gauss(order,x, cache_key=None):
00056     "compute h[order](x)*exp(-x^2/2).  x may be an array, and cache_key should be a unique identifier for x if cacheing is desired."
00057     if type(x) is not type(1.0):
00058         xmax=max(abs(x))
00059     else:
00060         xmax=abs(x)
00061         
00062     if (not hermite_cache.has_key(order)) or hermite_cache[order][0] < xmax:
00063         q=generate_table(order, max(1.5*xmax, hermite_x_bound))
00064         hermite_cache[order]=q
00065     
00066     if cache_key and hermite_cache.has_key((order, cache_key)):
00067         hermite_cache[(order, cache_key)][0]=time.time() #update time stamp
00068         return hermite_cache[(order, cache_key)][1]
00069     else:
00070         xmax, xa, ya, y2a=hermite_cache[order]
00071         y= spline.splint(xa, ya, y2a, x)
00072         if cache_key:
00073             hermite_cache[(order,cache_key)]=[time.time(), y]
00074         return y
00075 
00076 def purge_cache():
00077     "purge_cache() clears all pre-gridded datasets from the cache, leaving the raw interpolating functions"
00078     k=hermite_cache.keys()
00079     for i in k:
00080         if type(i) is not type(1):
00081             del hermite_cache[i]
00082 
00083 integral_cache={}
00084 
00085 def hermite_gauss_integral(m, n, x0, x1, stepsize=0.01):
00086     "compute integral(h[m](x}*h[n](x)*exp(-x^2),{x,x0,x1})"
00087     if m>n:
00088         m,n = n,m #always make m<=n
00089     xmax=max(abs(x0), abs(x1))
00090     if not integral_cache.has_key((m,n)) or integral_cache[(m,n)][0] < xmax:
00091         #just use Simpson's rule for this
00092         #first, load up cache
00093         hermite_gauss(m,xmax)
00094         hermite_gauss(n,xmax)
00095         xm, xa1, ya1, y2a1 = hermite_cache[m]
00096         xm, xa2, ya2, y2a2 = hermite_cache[n]
00097 
00098         stepcount=int(2.0*xmax/stepsize)
00099         if stepcount%2==0:
00100             stepcount=stepcount+1 #always odd for Simpson
00101         stepsize=2*xmax/(stepcount-1) #exact step size
00102         xlist=Numeric.array(range(stepcount),Numeric.Float)*stepsize - xmax
00103         y=spline.splint(xa1, ya1, y2a1, xlist)*spline.splint(xa2, ya2, y2a2, xlist)
00104         hmn2=spline.spline(xlist, y)
00105         yint=Numeric.cumsum(y[0:-2:2]+y[2::2]+4.0*y[1::2])*(stepsize/3.0)
00106         yint=Numeric.concatenate( ( (0,), yint )) #first element of integral is 0
00107         yi2=spline.spline(xlist[::2], yint)
00108         integral_cache[(m,n)]=(xmax, xlist[::2], yint, yi2, stepsize, xlist, y, hmn2)
00109 
00110     xmax, xa, ya, y2a, stepjunk, xjunk, yjunk, hmn2junk=integral_cache[(m,n)]
00111     iv1, iv2=spline.splint(xa, ya, y2a, (x0, x1) )
00112     return iv2-iv1
00113 
00114 def hermite_gauss_matrix_element(m, n, x0, x1, f, stepsize=0.01):
00115     "compute integral(h[m](x}*h[n](x)*exp(-x^2)*f(x),{x,x0,x1}) : f should be able to be evaluated with a vector x"
00116     if m>n:
00117         m,n = n,m #always make m<=n
00118     xmax=max(abs(x0), abs(x1))
00119     if not integral_cache.has_key((m,n)) or integral_cache[(m,n)][0] < xmax:
00120         hermite_gauss_integral(m,n,x0,x1) #preload cache with raw data
00121 
00122     jxmax, jxa, jya, jy2a, jstepsize, xa, hmn, hmn2=integral_cache[(m,n)]
00123     
00124     stepcount=int((x1-x0)/stepsize)
00125     if stepcount%2==0:
00126         stepcount=stepcount+1 #always odd for Simpson
00127     stepsize=(x1-x0)/(stepcount-1) #exact step size
00128     xlist=Numeric.array(range(stepcount),Numeric.Float)*stepsize + x0
00129     y=spline.splint(xa, hmn, hmn2, xlist)*f(xlist)
00130     yint=Numeric.sum(y[0:-2:2]+y[2::2]+4.0*y[1::2])*(stepsize/3.0)
00131     return yint
00132 
00133 if __name__=="__main__":
00134     print "\n***Start"
00135     for m in range(10):
00136         for n in range(10):
00137             print m,n,("%10.4f " % hermite_gauss_integral(m,n,-10., 10.)), 
00138             print "%10.4f" % hermite_gauss_matrix_element(m,n,-.5, 0.5, lambda x: 1.0),
00139             print "%10.4f" % hermite_gauss_integral(m,n,-.5, 0.5)
00140         
00141 
00142         
00143         
00144         
00145        
00146 

Generated on Wed Nov 21 10:18:31 2007 for analysis by  doxygen 1.5.4