00001 """generate voigt functions and their derivatives with respect to parameters"""
00002 _rcsid="$Id: voigt_profile.py,v 1.7 2007/01/25 12:44:05 mendenhall Exp $"
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 try:
00018 import numpy as Numeric
00019 from numpy import fft
00020 from numpy.fft import irfft as inverse_real_fft
00021 _numeric_float=Numeric.float64
00022
00023 except ImportError:
00024 import Numeric
00025 from FFT import inverse_real_fft
00026 _numeric_float=Numeric.Float64
00027
00028 import math
00029
00030
00031
00032
00033
00034 class Voigt_calculator:
00035
00036
00037
00038 def __init__(self):
00039
00040
00041 self.saved_params=(0,0, None, None, None, None)
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 def voigt_with_derivs(self, sigma, alpha, k_points=None, xfullwidth=10.0, kexptail=25):
00058 """return an x grid, voigt function with specified params, and d/dsigma and d/dalpha of this.
00059 Function is normalized to unit integral of points"""
00060 if k_points is None:
00061
00062
00063 q=-0.5*(alpha+math.sqrt(alpha*alpha+4.0*kexptail*(0.5*sigma**2)))
00064 k1=-kexptail/q
00065 kp=k1*xfullwidth/math.pi
00066 k_points=2**int(1+math.floor(math.log(kp)/math.log(2.0)))
00067
00068 if self.saved_params[:2] != (k_points, xfullwidth):
00069 kmax=math.pi*k_points/(xfullwidth)
00070 kvals=Numeric.array(range(k_points+1), _numeric_float)*(kmax/k_points)
00071 dx=xfullwidth/(2.0*k_points)
00072 xvals=Numeric.array(range(2*k_points), _numeric_float)*(xfullwidth/float(k_points))-xfullwidth
00073 k2=kvals*kvals
00074 x2=xvals*xvals
00075 cosarray=Numeric.cos((math.pi/xfullwidth)*xvals)
00076 self.saved_params=(k_points, xfullwidth, kvals, xvals, k2, cosarray, x2)
00077 else:
00078 k_points, xfullwidth, kvals, xvals, k2, cosarray, x2=self.saved_params
00079 kmax=math.pi*k_points/(xfullwidth)
00080 dx=xfullwidth/(2.0*k_points)
00081
00082 yvals=Numeric.exp(Numeric.clip((-0.5*sigma*sigma)*k2 - alpha*kvals, -100, 0))
00083 yvals[1::2]*=-1.0
00084 yft=inverse_real_fft(yvals)
00085 yft *= 0.5/dx
00086
00087
00088 delta=2*xfullwidth
00089 k1=2*math.pi*alpha/delta
00090 shk1=math.sinh(k1)/delta
00091 chk1=math.cosh(k1)
00092 uu1=1.0/(chk1-cosarray )
00093 uu2=Numeric.array(1.0/(x2+alpha**2))
00094 deltav=shk1*uu1-(alpha/math.pi)*uu2
00095
00096
00097
00098
00099 yft -= deltav*(1+(2*sigma**2/xfullwidth**4)*x2)
00100
00101
00102 yvals*=kvals
00103 dalpha=inverse_real_fft(yvals)
00104 dalpha*= -0.5/dx
00105
00106
00107 deltad=(-2.0*math.pi*shk1*shk1)*(uu1*uu1)
00108 deltad += ( 2.0*math.pi*chk1/(delta*delta))*uu1
00109 deltad += (alpha*alpha - x2)*(uu2*uu2)/math.pi
00110 dalpha -= deltad
00111
00112
00113 yvals*=kvals
00114 dsig=inverse_real_fft(yvals)
00115 dsig*= -0.5*sigma/dx
00116
00117
00118
00119 return (xvals, yft, dsig, dalpha)
00120
00121
00122
00123
00124 _voigt_instance=Voigt_calculator()
00125
00126
00127 def voigt_with_derivs(*args, **kwargs):
00128 return _voigt_instance.voigt_with_derivs(*args, **kwargs)
00129
00130
00131
00132
00133
00134 if __name__=='__main__':
00135 from graceplot import GracePlot
00136
00137 datasets=[]
00138
00139 stylecolors=[GracePlot.green, GracePlot.blue, GracePlot.red, GracePlot.orange, GracePlot.magenta, GracePlot.black]
00140 s1, s2, s3, s4, s5, s6 =[GracePlot.Symbol(symbol=GracePlot.circle, fillcolor=sc, size=0.5, linestyle=GracePlot.none) for sc in stylecolors]
00141 l1, l2, l3, l4, l5, l6=linestyles=[GracePlot.Line(type=GracePlot.solid, color=sc, linewidth=2.0) for sc in stylecolors]
00142 noline=GracePlot.Line(type=GracePlot.none)
00143
00144
00145 if 0:
00146 alpha0=.005
00147 sigma0=0.5
00148 xvals, vgta1, dsig, dalpha = voigt_with_derivs(sigma0, alpha0+0.0001)
00149 xvals, vgta2, dsig, dalpha = voigt_with_derivs(sigma0, alpha0-0.0001)
00150
00151 xvals, vgts1, dsig, dalpha = voigt_with_derivs(sigma0+0.0001, alpha0)
00152 xvals, vgts2, dsig, dalpha = voigt_with_derivs(sigma0-0.0001, alpha0)
00153
00154 xvals, vgt, dsig, dalpha = voigt_with_derivs(sigma0, alpha0)
00155
00156 scale=1.0
00157
00158 datasets.append(GracePlot.Data(x=xvals, y=vgt*scale, type='xy', line=l1))
00159 datasets.append(GracePlot.Data(x=xvals, y=dsig*sigma0, type='xy', line=l2))
00160 datasets.append(GracePlot.Data(x=xvals, y=dalpha*alpha0, type='xy', line=l3))
00161 datasets.append(GracePlot.Data(x=xvals, y=5000.0*alpha0*(vgta1-vgta2), type='xy', symbol=s3, line=noline))
00162 datasets.append(GracePlot.Data(x=xvals, y=5000.0*sigma0*(vgts1-vgts2), type='xy', symbol=s2, line=noline))
00163 else:
00164 from analysis import C2Functions
00165 class gauss(C2Functions.C2Function):
00166 scale=1.0/math.sqrt(2.0*math.pi)
00167 sigma=1.0
00168
00169 def set_width(self, wid):
00170 self.sigma=wid
00171
00172 def value_with_derivatives(self, x):
00173 x=x/self.sigma
00174 a=math.exp(-x*x/2)*self.scale/self.sigma
00175 return a, -x*a/self.sigma, (x*x-1)*a/self.sigma**2
00176
00177 class lorentz(C2Functions.C2Function):
00178 def set_center(self, center):
00179 self.center=center
00180 def set_width(self, wid):
00181 self.width=wid
00182
00183 def value_with_derivatives(self, x):
00184 x=(x-self.center)/self.width
00185 scale=1/(self.width*math.pi)
00186 a=1.0/(1.0+x*x)
00187 return a*scale, -2*x*a*a*scale/self.width, (6*x*x-2)*a*a*a*scale/self.width**2
00188
00189 ll=lorentz()
00190 gg=gauss()
00191 prod=ll*gg
00192
00193 alpha0=1.0
00194 import time
00195
00196 for pidx, (xfw, sigma0) in enumerate(((500., 1.), (500., 50.), (2000., 50.))):
00197 t0=time.time()
00198 for i in range(100):
00199 xvals1, vgta1, dsig, dalpha = voigt_with_derivs(sigma0, alpha0, kexptail=25, xfullwidth=xfw)
00200 t1=time.time()
00201
00202 convlist=[]
00203 ll.set_width(alpha0)
00204 gg.set_width(sigma0)
00205 for x in xvals1:
00206 ll.set_center(float(x))
00207 convlist.append(prod.integral(-10.0*sigma0, 10.0*sigma0, relative_error_tolerance=1e-13, absolute_error_tolerance=1e-16))
00208
00209 t2=time.time()
00210
00211 diff=vgta1-convlist
00212 print len(xvals1), (t1-t0)/100.0, t2-t1, math.sqrt(sum(diff*diff)/len(diff))
00213
00214 datasets.append(GracePlot.Data(x=xvals1, y=vgta1, type='xy', line=linestyles[2*pidx], legend=r"Function: \xs\f{} = %.0f, \xD\f{} = %.0f"%(sigma0, 2*xfw) ))
00215 datasets.append(GracePlot.Data(x=xvals1, y=diff/vgta1*1e3, type='xy', line=linestyles[2*pidx+1], legend=r"10\S3\N \x\#{b4}\f{} Relative Error: \xs\f{} = %.0f, \xD\f{} = %.0f"%(sigma0, 2*xfw)))
00216
00217 try:
00218 graceSession.clear()
00219 except:
00220 class myGrace(GracePlot.GracePlot):
00221
00222 def write(self, command):
00223 "make a graceSession look like a file"
00224 self._send(command)
00225 self._flush()
00226
00227 def send_commands(self, *commands):
00228 "send a list of commands, and then flush"
00229 for c in commands:
00230 self._send(c)
00231 self._flush()
00232
00233 graceSession=myGrace(width=11, height=7)
00234
00235 g=graceSession[0]
00236
00237 g.plot(datasets[::2]+datasets[1::2])
00238 g.legend()
00239 g.xaxis(label=GracePlot.Label('offset'), xmin=0, xmax=500)
00240 g.yaxis(label=GracePlot.Label('Amplitude'), scale='logarithmic', ymin=1e-6, ymax=1,
00241 tick=GracePlot.Tick(major=10, minorticks=9))
00242
00243 graceSession.send_commands('hardcopy device "PDF"', 'print to "voigt_errors.pdf"')
00244
00245
00246
00247
00248