resultsFile/resultsFile/lib/basis.py

485 lines
12 KiB
Python
Executable File

#!/usr/bin/env python
# resultsFile is a library which allows to read output files of quantum
# chemistry codes and write input files.
# Copyright (C) 2007 Anthony SCEMAMA
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Anthony Scemama
# LCPQ - IRSAMC
# Universite Paul Sabatier
# 118, route de Narbonne
# 31062 Toulouse Cedex 4
# scemama@irsamc.ups-tlse.fr
#import pdb
from library import *
from math import *
import sys
def normalize_basis_name(s):
l = list(s)
is_sphe = False
l.sort()
for i in range(10):
if str(i) in l:
is_sphe = True
if is_sphe:
if l[0] == '0':
l.insert(0,'+')
l = [l[-1]]+l[:-1]
result = ""
for i in l:
result += i
result = result.lower()
return result
class primitive(object):
"""Class for a primitive basis function."""
def __init__(self):
_center = None
_expo = None
_sym = None
def __eq__(self,other):
thr = 1.e-6
result = True
result = result and abs(self.center[0] - other.center[0]) < thr
result = result and abs(self.center[1] - other.center[1]) < thr
result = result and abs(self.center[2] - other.center[2]) < thr
result = result and abs(self.expo - other.expo) < thr
result = result and self.sym == other.sym
return result
def __repr__(self):
out = "%6s %10.6f %10.6f %10.6f %16.6e"%tuple(
[self.sym]+list(self.center)+[self.expo])
return out
def __repr__debug__(self):
out = ""
out += str(self.sym)+'\t'
out += str(self.center)+'\t'
out += str(self.expo)
return out
def __cmp__(self,other):
assert ( isinstance(other,primitive) )
"""Primitive functions are sorted according to the exponents."""
if not isinstance(other,primitive):
raise TypeError
if self.expo < other.expo:
return -1
elif self.expo > other.expo:
return 1
elif self.expo == other.expo:
return 0
def get_norm(self):
result = sqrt(self.overlap(self))
return result
norm = property (get_norm,None,doc="Sqrt( Integral f^2(R) dR ).")
for i in "center expo sym".split():
exec """
def get_%(i)s(self): return self._%(i)s
def set_%(i)s(self,value): self._%(i)s = value
%(i)s = property(fget=get_%(i)s,fset=set_%(i)s) """%locals()
#-----------------------
powersave = { 's':(0,0,0) }
def powers(sym):
if sym in powersave:
return powersave[sym]
result = (sym.count('x'),sym.count('y'),sym.count('z'))
powersave[sym] = result
return result
fact_ = [1.]
def fact(n):
global fact_
nstart = len(fact_)
if n < nstart :
return fact_[n]
else:
for i in range(nstart,n+1):
fact_.append(fact_[i-1]*float(i))
return fact_[n]
def binom(n,m):
return fact(n)/(fact(m)*fact(n-m))
def rintgauss(n):
def ddfact2(n):
if n%2 == 0: print 'error in ddfact2'
res=1.
for i in range(1,n+1,2):
res*=float(i)
return res
res = sqrt(pi)
if n == 0: return res
elif n == 1: return 0.
elif n%2 == 1: return 0.
res /= 2.**(n/2)
res *= ddfact2(n-1)
return res
def Goverlap(fA,fB):
fA = spheToCart(fA)
fB = spheToCart(fB)
if isinstance(fA,contraction):
result = fA.overlap(fB)
elif isinstance(fB,contraction):
result = fB.overlap(fA)
else:
result = GoverlapCart(fA,fB)
return result
def GoverlapCart(fA,fB):
gamA=fA.expo
gamB=fB.expo
gamtot = gamA+gamB
SAB=1.0
A = fA.center
B = fB.center
nA = powers(fA.sym)
nB = powers(fB.sym)
for l in range(3):
Al = A[l]
Bl = B[l]
nAl = nA[l]
nBl = nB[l]
u=gamA/gamtot*Al+gamB/gamtot*Bl
arg=gamtot*u*u-gamA*Al*Al-gamB*Bl*Bl
alpha=exp(arg)/gamtot**((1.+float(nAl)+float(nBl))/2.)
temp = sqrt(gamtot)
wA=temp*(u-Al)
wB=temp*(u-Bl)
accu=0.
for n in range (nAl+1):
wAn = wA**n * binom(nAl,n)
for m in range (nBl+1):
integ=nAl+nBl-n-m
accu+=wAn*wB**m*binom(nBl,m)*rintgauss(integ)
SAB*=accu*alpha
return SAB
def GoverlapCartNorm2(fA,fB):
gamA=fA.expo
gamB=fB.expo
gamtot = gamA+gamB
SAB=1.0
nA = powers(fA.sym)
nB = powers(fB.sym)
for l in range(3):
nAl = nA[l]
nBl = nB[l]
SAB*=rintgauss(nAl+nBl)/(gamA+gamB)**((1.+float(nAl)+float(nBl))/2.)
return SAB
def GoverlapCartNorm(fA):
gamA=fA.expo
SAB=1.0
nA = powers(fA.sym)
for l in range(3):
nAl = nA[l]
SAB*=rintgauss(2*nAl)/(2.*gamA)**(0.5+float(nAl))
return SAB
angular_momentum = {}
for i,l in enumerate("spdfghijklmno"):
angular_momentum[l]=i
def get_lm(sym):
if 'x' in sym or 'y' in sym or 'z' in sym or sym == 's':
return None, None
else:
return angular_momentum[sym[0]], int(sym[1:])
def xyz_from_lm(l,m):
"""Returns the xyz powers and the coefficients of a spherical function
expressed in the cartesian basis"""
power = []
coef = []
absm = abs(m)
nb2 = absm
nb1 = (l-absm)/2
clmt = [ (-0.25)**t * binom(l,t) * binom(l-t,absm+t) for t in xrange(nb1+1) ]
mod_absm_2 = absm % 2
if m>=0:
nb2_start = mod_absm_2
elif m<0:
nb2_start = (absm+1) % 2
if m != 0:
norm = 2.**(-absm)/fact(l) * sqrt(2.*abs(fact(l+m)*fact(l-m)))
else:
norm = 1.
for n1 in range(nb2_start,nb2+1,2):
k = (absm-n1)/2
factor = (-1.)**k * binom(absm,n1) * norm
for t in xrange(nb1+1):
for n2 in xrange(t+1):
coe = clmt[t] * factor * binom(t,n2)
ipw = ( n1+2*n2 , absm-n1+2*(t-n2), l-2*t-absm )
done = False
for i,c in enumerate(coef):
if c != 0.:
if not done and ipw in power:
idx = power.index(ipw)
coef[idx] += coe
done = True
if not done:
power.append(ipw)
coef.append(coe)
return power,coef
def spheToCart(fA):
l,m = get_lm(fA.sym)
if l is None:
return fA
power, coef = xyz_from_lm(l,m)
contr = contraction()
for p,c in zip(power,coef):
gauss = gaussian()
gauss.center = fA.center
gauss.expo = fA.expo
gauss.sym = ''
for l,letter in enumerate('xyz'):
gauss.sym += p[l]*letter
contr.append(c,gauss)
return contr
class gaussian(primitive):
"""Gaussian primitive function."""
def __init__(self):
primitive.__init__(self)
def overlap(self,other):
result = Goverlap(self,other)
return result
def value(self,r):
"""Value at r."""
x, y, z = r
x -= self.center[0]
y -= self.center[1]
z -= self.center[2]
r2 = x**2 + y**2 + z**2
px, py, pz = powers(self.sym)
P = x**px * y**py * z**pz
return P*exp(-self.expo*r2)
def valuer2(self,r2):
"""Value at sqrt(r2)."""
return exp(-self.expo*r2)
#-----------------------
class contraction(object):
"""Contraction of primitive functions."""
def __init__(self):
self._center = None
self._prim = []
self._coef = []
self._sym = None
def __eq__(self,other):
thr = 1.e-6
result = True
result = result and abs(self._center[0] - other._center[0]) < thr
result = result and abs(self._center[1] - other._center[1]) < thr
result = result and abs(self._center[2] - other._center[2]) < thr
result = result and self._sym == other._sym
result = result and len(self._coef) == len(other._coef)
if result:
for i in range(len(self._coef)):
result = result and abs(self._coef[i] - other._coef[i]) < thr
if result:
for i in range(len(self._prim)):
result = result and self._prim[i] == other._prim[i]
return result
def __repr__(self):
out = "%6s %10.6f %10.6f %10.6f\n"%tuple(
[self.sym]+list(self.center))
for i,a in enumerate(self.prim):
out += " %16.6e %16.6e\n"%(a.expo,self.coef[i])
return out
def append(self,c,func):
if self.sym is None:
self.sym = func.sym
if self.center is None:
self.center = func.center
assert ( isinstance(func,primitive) )
assert ( self.center == func.center )
self._prim.append(func)
self._coef.append(c)
def get_norm(self):
sum=0.
for i, ci in enumerate(self.coef):
for j, cj in enumerate(self.coef):
sum += ci*cj*self.prim[i].overlap(self.prim[j])/(self.prim[i].norm*self.prim[j].norm)
result = sqrt(sum)
return result
def overlap(self,other0):
if isinstance(other0,contraction):
other=other0
else:
other=contraction()
other.sym = other0.sym
other.center = other0.center
other.append(1.,other0)
prim = self.prim
oprim = other.prim
sum = 0.
for i, ci in enumerate(self.coef):
for j, cj in enumerate(other.coef):
sum += ci*cj*prim[i].overlap(oprim[j])
return sum
def get_coef(self):
return self._coef
coef = property(fget=get_coef)
def get_center(self):
return self._center
center = property(fget=get_center)
def get_prim(self):
return self._prim
prim = property(fget=get_prim)
def normalize(self):
coef = self.coef
prim = self.prim
n = self.norm
for i, ci in enumerate(coef):
coef[i] /= n
def value(self,r):
"""Value at r."""
x, y, z = r
x -= self.center[0]
y -= self.center[1]
z -= self.center[2]
r2 = x**2 + y**2 + z**2
px, py, pz = powers(self.sym)
P = x**px * y**py * z**pz
result = 0.
for c,chi in zip(self.coef,self.prim):
result += c*chi.valuer2(r2)
return P*result
for i in "center prim sym coef".split():
exec """
def get_%(i)s(self): return self._%(i)s
def set_%(i)s(self,value): self._%(i)s = value
%(i)s = property(fget=get_%(i)s,fset=set_%(i)s) """%locals()
norm = property (get_norm,None,doc="Sqrt( Integral f^2(R) dR ).")
try:
import lib_cython
fact = lib_cython.fact
binom = lib_cython.binom
rintgauss = lib_cython.rintgauss
powers = lib_cython.powers
GoverlapCart = lib_cython.GoverlapCart
GoverlapCartNorm2 = lib_cython.GoverlapCartNorm2
except ImportError:
pass
#--------------
if __name__ == '__main__':
for l in range(6):
print '---'
for m in range(-l,l+1):
print "%3d %3d :"%(l,m), xyz_from_lm(l,m)
sys.exit(0)
if __name__ == '__main__':
a = gaussian()
a.sym = 'f+0'
a.expo = 3.
a.center = [0.,0.,0.]
b = gaussian()
b.sym = 'g+2'
b.expo = 4.
b.center = [0.,0.,0.]
x = spheToCart(a)
y = spheToCart(a)
print x
sys.exit(0)
print GoverlapCart(a,b)
print GoverlapCartNorm2(a,b)
print ''
for i in range(0,10):
print rintgauss(i)
sys.exit(0)
c = gaussian()
c.sym = 's'
c.expo = 1.159
c.center = [0.,0.,0.]
d = contraction()
d.append(0.025494863235, a)
d.append(0.190362765893, b)
d.append(0.852162022245, c)
d.normalize()
print d
sys.exit(0)
a = gaussian()
a.sym = 'x'
a.expo = 1.0
a.center = [0.,0.,0.]
b = gaussian()
b.sym = 'x'
b.expo = 2.0
b.center = [0.,0.,0.]
c = contraction()
c.append(1.,a)
c.append(2.,b)
print c.value( (1.,1.,0.) )
print b.overlap(a)
print a.overlap(b)
print a.norm
print c.norm, c.coef
c.normalize()
print c.norm, c.coef
c.normalize()
print c.norm, c.coef
print Goverlap(a,b)