mirror of
https://code.it4i.cz/sccs/easyconfigs-it4i.git
synced 2025-04-15 19:28:06 +01:00
6201 lines
191 KiB
Fortran
6201 lines
191 KiB
Fortran
************************************************************************
|
|
integer*8 function fact(n)
|
|
************************************************************************
|
|
* This function gives back n factorial *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
integer*8 isum
|
|
C
|
|
isum=1
|
|
do i=2,n
|
|
isum=isum*i
|
|
enddo
|
|
fact=isum
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
real*8 function factd(n)
|
|
************************************************************************
|
|
* This function return n factorial in double precision
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
real*8 isum
|
|
C
|
|
isum=1.d0
|
|
do i=2,n
|
|
isum=isum*dble(i)
|
|
enddo
|
|
factd=isum
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
integer*8 function dfact(n)
|
|
************************************************************************
|
|
* This function gives back n double factorial *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
integer*8 isum
|
|
C
|
|
isum=1
|
|
if(mod(n,2).eq.0) then
|
|
do i=1,n/2
|
|
isum=isum*2*i
|
|
enddo
|
|
else
|
|
do i=1,(n+1)/2
|
|
isum=isum*(2*i-1)
|
|
enddo
|
|
endif
|
|
dfact=isum
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
real*8 function ddfact(n)
|
|
************************************************************************
|
|
* This function gives back n double factorial in double precision *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
real*8 isum
|
|
C
|
|
isum=1.d0
|
|
if(mod(n,2).eq.0) then
|
|
do i=1,n/2
|
|
isum=isum*2.d0*dble(i)
|
|
enddo
|
|
else
|
|
do i=1,(n+1)/2
|
|
isum=isum*(2.d0*dble(i)-1.d0)
|
|
enddo
|
|
endif
|
|
ddfact=isum
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
integer*8 function dfact2(n)
|
|
************************************************************************
|
|
* This function gives back (2n-1)!! *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
integer*8 isum
|
|
C
|
|
isum=1
|
|
do i=3,2*n-1,2
|
|
isum=isum*i
|
|
enddo
|
|
dfact2=isum
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
integer*8 function binom(m,n)
|
|
************************************************************************
|
|
* This function gives back the binomial coefficient *
|
|
************************************************************************
|
|
implicit none
|
|
integer m,n,i
|
|
integer*8 isum,fact
|
|
C
|
|
isum=1
|
|
do i=m-n+1,m
|
|
isum=isum*i
|
|
enddo
|
|
binom=isum/fact(n)
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
real*8 function lfact(n)
|
|
************************************************************************
|
|
* This function gives back the logarithm of n factorial *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
real*8 sum
|
|
C
|
|
sum=0.d0
|
|
do i=2,n
|
|
sum=sum+dlog(dble(i))
|
|
enddo
|
|
lfact=sum
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
real*8 function lbinom(m,n)
|
|
************************************************************************
|
|
* This function gives back the logarithm of the binomial coefficient *
|
|
************************************************************************
|
|
implicit none
|
|
integer m,n,i
|
|
real*8 sum,lfact
|
|
C
|
|
sum=0
|
|
do i=m-n+1,m
|
|
sum=sum+dlog(dble(i))
|
|
enddo
|
|
lbinom=sum-lfact(n)
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine ifillzero(v,n)
|
|
************************************************************************
|
|
* This subroutine fills an integer array vectorized with zeros *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,v(*)
|
|
C
|
|
c C$OMP PARALLEL DO
|
|
c C$OMP& DEFAULT(SHARED)
|
|
do i=1,n
|
|
v(i)=0
|
|
enddo
|
|
c C$OMP END PARALLEL DO
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine dfillzero(v,n)
|
|
************************************************************************
|
|
* This subroutine fills an real*8 array vectorized with zeros *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
real*8 v(*)
|
|
C
|
|
c C$OMP PARALLEL DO
|
|
c C$OMP& DEFAULT(SHARED)
|
|
do i=1,n
|
|
v(i)=0.d0
|
|
enddo
|
|
c C$OMP END PARALLEL DO
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine dfillzer1(v,n)
|
|
************************************************************************
|
|
* This subroutine fills an real*8 array vectorized with zeros *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i
|
|
real*8 v(*)
|
|
C
|
|
do i=1,n
|
|
v(i)=0.d0
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine ishift(v,n)
|
|
************************************************************************
|
|
* v=v+1 *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,v(*)
|
|
C
|
|
c C$OMP PARALLEL DO
|
|
c C$OMP& DEFAULT(SHARED)
|
|
do i=1,n
|
|
v(i)=v(i)+1
|
|
enddo
|
|
c C$OMP END PARALLEL DO
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine skip1(ilev,file)
|
|
************************************************************************
|
|
* This subroutine reads the non-used lines from the formula-file. *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,isave,nn,ilev,file
|
|
C
|
|
ilev=ilev+1
|
|
read(file,*) n
|
|
do nn=1,n
|
|
if(ilev.eq.4) then
|
|
read(file,*) i,i,i,i,i,i,i,i,i,i,i,i,isave,i,i,i,i,i,i,i,i
|
|
else
|
|
read(file,*) i,i,i,i,i,i,i,i,i,i,i,isave,i,i,i,i,i,i,i,i
|
|
if(isave.gt.0) call skip2(ilev,file)
|
|
endif
|
|
enddo
|
|
ilev=ilev-1
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine skip2(ilev,file)
|
|
************************************************************************
|
|
* This subroutine reads the non-used lines from the formula-file. *
|
|
************************************************************************
|
|
implicit none
|
|
integer ilev,file
|
|
C
|
|
call skip1(ilev,file)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine comb(n,nact,icomb,ilev,in,inact,ip,ncomb,ic)
|
|
************************************************************************
|
|
* Generate combinations *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,nact,icomb(0:n,*),ilev,in,inact,ncomb,ic(*),ip
|
|
C
|
|
call ifillzero(ic,n)
|
|
ilev=0
|
|
ncomb=0
|
|
call comb1(n,nact,icomb,ilev,in,inact,ip,ncomb,ic)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine comb1(n,nact,icomb,ilev,in,inact,ip,ncomb,ic)
|
|
************************************************************************
|
|
* Generate combinations *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,nact,icomb(0:n,*),ilev,in,inact,ncomb,ic(*),i,j,ip
|
|
integer is(n),ina
|
|
logical log
|
|
C
|
|
if(ilev.eq.in) then
|
|
ina=0
|
|
do i=1,nact ! Only for virtual strings (actives first)!!!
|
|
if(ic(i).eq.1) ina=ina+1
|
|
enddo
|
|
if(ina.ne.inact) return
|
|
C
|
|
ncomb=ncomb+1
|
|
do i=1,n
|
|
icomb(i,ncomb)=ic(i)
|
|
is(i)=ic(i)
|
|
enddo
|
|
icomb(0,ncomb)=1
|
|
log=.true.
|
|
do while(log)
|
|
log=.false.
|
|
do i=1,n-1
|
|
if(is(i).lt.is(i+1)) then
|
|
icomb(0,ncomb)=-icomb(0,ncomb)
|
|
log=.true.
|
|
j=is(i)
|
|
is(i)=is(i+1)
|
|
is(i+1)=j
|
|
endif
|
|
enddo
|
|
enddo
|
|
return
|
|
endif
|
|
C
|
|
ilev=ilev+1
|
|
do i=ip+1,n
|
|
ic(i)=1
|
|
call comb2(n,nact,icomb,ilev,in,inact,i,ncomb,ic)
|
|
ic(i)=0
|
|
enddo
|
|
ilev=ilev-1
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine comb2(n,nact,icomb,ilev,in,inact,ip,ncomb,ic)
|
|
************************************************************************
|
|
* Generate combinations *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,nact,icomb(0:n,*),ilev,in,inact,ncomb,ic(*),ip
|
|
C
|
|
call comb1(n,nact,icomb,ilev,in,inact,ip,ncomb,ic)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
#if defined (OMP)
|
|
************************************************************************
|
|
subroutine ompred(w,n)
|
|
************************************************************************
|
|
* "Manual" reduction for OpenMP
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer n,i
|
|
real*8 w(n,xyzsiz1)
|
|
C
|
|
do i=2,xyzsiz1
|
|
call daxpy(n,1.d0,w(1,i),1,w(1,1),1)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
#endif
|
|
************************************************************************
|
|
subroutine trimloc(beg,end)
|
|
************************************************************************
|
|
* Local trim function
|
|
************************************************************************
|
|
implicit none
|
|
integer lb,le,i
|
|
character*1 beg(*),end(*)
|
|
C
|
|
lb=0
|
|
le=0
|
|
do i=1,128
|
|
if(beg(i).ne.' ') lb=i
|
|
if(end(i).ne.' ') le=i
|
|
enddo
|
|
do i=lb+1,min(128,lb+le)
|
|
beg(i)=end(i-lb)
|
|
enddo
|
|
do i=lb+le+1,128
|
|
beg(i)=' '
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
integer function intadd(n)
|
|
************************************************************************
|
|
* This function returns the address of dcore(n) wrt icore *
|
|
************************************************************************
|
|
implicit none
|
|
integer n,iintfp
|
|
#if defined (INT64)
|
|
parameter(iintfp=1)
|
|
#else
|
|
parameter(iintfp=2)
|
|
#endif
|
|
C
|
|
intadd=iintfp*(n-1)+1
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
integer function dbladd(n)
|
|
************************************************************************
|
|
* This function returns the address of icore(n) wrt dcore *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer n,i
|
|
C
|
|
i=mod(n-1,iintfp)
|
|
if(i.ne.0) i=iintfp-i
|
|
dbladd=(n-1+i)/iintfp+1
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine putint(ifile,irec,vec,ilength)
|
|
************************************************************************
|
|
* Write an integer array to a direct access file *
|
|
* ifile - unit number *
|
|
* irec - record number in direct access file *
|
|
* vec - array to be read *
|
|
* ilength - length of the array *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ifile,irec,ilength,nrec,i,j,jrec,vec(*)
|
|
C
|
|
if(ilength.eq.0) return
|
|
j=mod(ilength,iibufln)
|
|
nrec=(ilength-j)/iibufln-1
|
|
do jrec=0,nrec
|
|
write(ifile,rec=irec+jrec) (vec(jrec*iibufln+i),i=1,iibufln)
|
|
enddo
|
|
if(j.ne.0) write(ifile,rec=irec+nrec+1)
|
|
$(vec((nrec+1)*iibufln+i),i=1,j)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getint(ifile,irec,vec,ilength)
|
|
************************************************************************
|
|
* Read an integer array from a direct access file *
|
|
* ifile - unit number *
|
|
* irec - record number in direct access file *
|
|
* vec - array to be read *
|
|
* ilength - length of the array *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ifile,irec,ilength,nrec,i,j,jrec,vec(*)
|
|
C
|
|
if(ilength.eq.0) return
|
|
j=mod(ilength,iibufln)
|
|
nrec=(ilength-j)/iibufln-1
|
|
do jrec=0,nrec
|
|
read(ifile,rec=irec+jrec) (vec(jrec*iibufln+i),i=1,iibufln)
|
|
enddo
|
|
if(j.ne.0) read(ifile,rec=irec+nrec+1)
|
|
$(vec((nrec+1)*iibufln+i),i=1,j)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine putlst(ifile,irec,vec,ilength)
|
|
************************************************************************
|
|
* Write a double precision array to a direct access file *
|
|
* ifile - unit number *
|
|
* irec - record number in direct access file *
|
|
* vec - array to be read *
|
|
* ilength - length of the array *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ifile,irec,ilength,nrec,i,j,jrec
|
|
real*8 vec(*)
|
|
C
|
|
if(ilength.eq.0) return
|
|
j=mod(ilength,ibufln)
|
|
nrec=(ilength-j)/ibufln-1
|
|
do jrec=0,nrec
|
|
write(ifile,rec=irec+jrec) (vec(jrec*ibufln+i),i=1,ibufln)
|
|
enddo
|
|
if(j.ne.0) write(ifile,rec=irec+nrec+1)
|
|
$(vec((nrec+1)*ibufln+i),i=1,j)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getlst(ifile,irec,vec,ilength)
|
|
************************************************************************
|
|
* Read a double precision array from a direct access file *
|
|
* ifile - unit number *
|
|
* irec - record number in direct access file *
|
|
* vec - array to be read *
|
|
* ilength - length of the array *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ifile,irec,ilength,nrec,i,j,jrec
|
|
real*8 vec(*)
|
|
C
|
|
if(ilength.eq.0) return
|
|
j=mod(ilength,ibufln)
|
|
nrec=(ilength-j)/ibufln-1
|
|
do jrec=0,nrec
|
|
read(ifile,rec=irec+jrec) (vec(jrec*ibufln+i),i=1,ibufln)
|
|
enddo
|
|
if(j.ne.0) read(ifile,rec=irec+nrec+1)
|
|
$(vec((nrec+1)*ibufln+i),i=1,j)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getput(ifile,irec,vec,ilength)
|
|
************************************************************************
|
|
* Adds vec and a vector from ifile together and writes back into ifile
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ifile,irec,ilength,nrec,i,j
|
|
real*8 vec(*)
|
|
C
|
|
if(ilength.eq.0) return
|
|
nrec=0
|
|
j=irec
|
|
do while (nrec.lt.ilength)
|
|
read(ifile,rec=j) ibuf
|
|
c C$OMP PARALLEL DO
|
|
c C$OMP& DEFAULT(SHARED)
|
|
do i=1,min(ibufln,ilength-nrec)
|
|
ibuf(i)=ibuf(i)+vec(nrec+i)
|
|
enddo
|
|
c C$OMP END PARALLEL DO
|
|
write(ifile,rec=j) ibuf
|
|
nrec=nrec+ibufln
|
|
j=j+1
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getkeym(key,nlk,val,nlv)
|
|
************************************************************************
|
|
* Get the value of a keyword from inputfile
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character*1 key(nlk),val(nlv),line(512)
|
|
character*4 line4
|
|
character*8 line8
|
|
character*512 line1
|
|
integer nlk,nlv,i,n
|
|
logical ll
|
|
equivalence(line,line1,line4,line8)
|
|
C
|
|
val(1:nlv)=' '
|
|
line(1:512)=' '
|
|
rewind(minpfile)
|
|
do
|
|
read(minpfile,'(512a1)',end=1000) line
|
|
call lowercase(line,line,512)
|
|
line1=adjustl(line1)
|
|
if(line4.eq.'geom') then
|
|
line(5)='='
|
|
else if(line8.eq.'pointcha') then
|
|
return
|
|
endif
|
|
n=1
|
|
do while(line(n).ne.'='.and.line(n).ne.' '.and.n.lt.512)
|
|
n=n+1
|
|
enddo
|
|
if(n-1.eq.nlk) then
|
|
ll=.true.
|
|
do i=1,nlk
|
|
ll=ll.and.line(i).eq.key(i)
|
|
enddo
|
|
if(ll) then
|
|
i=1
|
|
do while(line(i).ne.'='.and.i.lt.512)
|
|
line(i)=' '
|
|
i=i+1
|
|
enddo
|
|
line(i)=' '
|
|
line1=adjustl(line1)
|
|
i=1
|
|
do while(line(i).ne.' ')
|
|
val(i)=line(i)
|
|
i=i+1
|
|
enddo
|
|
return
|
|
endif
|
|
endif
|
|
enddo
|
|
1000 continue
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getkey(key,nlk,val,nlv)
|
|
************************************************************************
|
|
* Get the value of a keyword from keyword file
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character*1 key(nlk),val(nlv),line(512)
|
|
character*512 line1
|
|
integer nlk,nlv,i,n
|
|
logical ll
|
|
equivalence(line,line1)
|
|
C
|
|
open(keywdfile,file='KEYWD',status='old')
|
|
rewind(keywdfile)
|
|
val(1:nlv)=' '
|
|
line(1:512)=' '
|
|
do
|
|
read(keywdfile,'(512a1)',end=1000) line
|
|
call lowercase(line,line,512)
|
|
line1=adjustl(line1)
|
|
n=1
|
|
do while(line(n).ne.'='.and.line(n).ne.' '.and.n.le.nlk)
|
|
n=n+1
|
|
enddo
|
|
if(n-1.eq.nlk) then
|
|
ll=.true.
|
|
do i=1,nlk
|
|
ll=ll.and.line(i).eq.key(i)
|
|
enddo
|
|
if(ll) then
|
|
i=1
|
|
do while(line(i).ne.'='.and.i.lt.512)
|
|
line(i)=' '
|
|
i=i+1
|
|
enddo
|
|
line(i)=' '
|
|
line1=adjustl(line1)
|
|
i=1
|
|
do while(line(i).ne.' '.and.i.le.nlv)
|
|
val(i)=line(i)
|
|
i=i+1
|
|
enddo
|
|
goto 1000
|
|
endif
|
|
endif
|
|
enddo
|
|
1000 continue
|
|
close(keywdfile)
|
|
C
|
|
return
|
|
end
|
|
************************************************************************
|
|
double precision function dgetkey(key,nlk,nlv) result(dkey)
|
|
************************************************************************
|
|
* Reads a keyword and converts to double precision
|
|
************************************************************************
|
|
implicit none
|
|
integer nlk,nlv
|
|
character*1 key(nlk)
|
|
character*128 c
|
|
|
|
c=' '
|
|
call getkey(key,nlk,c,nlv)
|
|
read(c,*) dkey
|
|
end function
|
|
C
|
|
************************************************************************
|
|
subroutine unknown(key,nlen)
|
|
************************************************************************
|
|
* Exit if the value of a keyword is not correct
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer nlen,i
|
|
character*1 key(nlen)
|
|
C
|
|
write(iout,*)
|
|
write(iout,*)
|
|
$'Unknown option for keyword "',(key(i),i=1,nlen),'"!'
|
|
call mrccend(1)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine changekey(key,nlk,val,nlv)
|
|
************************************************************************
|
|
* Change a keyword in keyword file
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character*1 key(nlk),val(nlv),line(512)
|
|
character*512 line1
|
|
integer nlk,nlv,i,n
|
|
logical ll
|
|
equivalence(line,line1)
|
|
C
|
|
open(keywdfile,file='KEYWD',status='old')
|
|
open(scrfile7,status='unknown')
|
|
rewind(keywdfile)
|
|
rewind(scrfile7)
|
|
do i=1,nlk
|
|
line(i)=key(i)
|
|
enddo
|
|
do
|
|
read(keywdfile,'(512a1)',end=1000) line
|
|
line1=adjustl(line1)
|
|
n=1
|
|
do while(line(n).ne.'='.and.line(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
if(n-1.eq.nlk) then
|
|
ll=.true.
|
|
do i=1,nlk
|
|
ll=ll.and.line(i).eq.key(i)
|
|
enddo
|
|
if(ll) then
|
|
do i=1,nlv
|
|
line(n+i)=val(i)
|
|
enddo
|
|
do i=n+nlv+1,512
|
|
line(i)=' '
|
|
enddo
|
|
endif
|
|
endif
|
|
write(scrfile7,'(512a1)') line
|
|
enddo
|
|
1000 continue
|
|
rewind(keywdfile)
|
|
rewind(scrfile7)
|
|
do
|
|
read(scrfile7,'(512a1)',end=1001) line
|
|
line1=adjustl(line1)
|
|
write(keywdfile,*) trim(line1)
|
|
enddo
|
|
1001 continue
|
|
close(keywdfile)
|
|
close(scrfile7,status='delete')
|
|
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine lowercase(ch,chl,nlen)
|
|
************************************************************************
|
|
* Convert upper case to lower case
|
|
************************************************************************
|
|
implicit none
|
|
integer nlen,i,ii
|
|
character*1 ch(*),chl(*)
|
|
C
|
|
do i=1,nlen
|
|
chl(i)=ch(i)
|
|
ii=ichar(chl(i))
|
|
if(ii.ge.65.and.ii.le.90) chl(i)=char(ii+32)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine uppercase(ch,chl,nlen)
|
|
************************************************************************
|
|
* Convert upper case to lower case
|
|
************************************************************************
|
|
implicit none
|
|
integer nlen,i,ii
|
|
character*1 ch(*),chl(*)
|
|
C
|
|
do i=1,nlen
|
|
chl(i)=ch(i)
|
|
ii=ichar(chl(i))
|
|
if(ii.ge.97.and.ii.le.122) chl(i)=char(ii-32)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
#if defined (MPI)
|
|
************************************************************************
|
|
subroutine mrccini_mpi
|
|
************************************************************************
|
|
* Initiates MPI
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character*16 devnul
|
|
common/output/ devnul
|
|
integer bcast_size, provided
|
|
integer :: mpi_err
|
|
integer mpi_rank, mpi_size, nlen, parent
|
|
logical mpi_in
|
|
character*8 rank_ch
|
|
character*512 wdir_parent
|
|
character*(MPI_MAX_PROCESSOR_NAME) pname
|
|
character*21 prov_ch
|
|
logical dodiis
|
|
common /pd/ dodiis
|
|
|
|
tim=0.d0
|
|
wct=0.d0
|
|
call mtime(tim,wct)
|
|
timold=tim
|
|
wctold=wct
|
|
timvold=tim
|
|
wctvold=wct
|
|
|
|
! iout = 6
|
|
mem_allocated = .false.
|
|
! del_wdir = .false.
|
|
! master_thread = .true.
|
|
! master_rank = 0
|
|
! inbcast = .true.
|
|
bcast_comm = MPI_COMM_NULL
|
|
|
|
call signalinitchild ! initialise response to SIG's
|
|
|
|
call MPI_Initialized(mpi_in, mpi_err)
|
|
if(.not. mpi_in) then
|
|
call MPI_Init_thread(MPI_THREAD_SERIALIZED, !MULTIPLE,
|
|
$ provided, mpi_err)
|
|
if(provided .ne. MPI_THREAD_SERIALIZED) then !MULTIPLE) then
|
|
if(provided .eq. MPI_THREAD_SINGLE) then
|
|
prov_ch = 'MPI_THREAD_SINGLE '
|
|
elseif(provided .eq. MPI_THREAD_FUNNELED) then
|
|
prov_ch = 'MPI_THREAD_FUNNELED '
|
|
elseif(provided .eq. MPI_THREAD_SERIALIZED) then
|
|
prov_ch = 'MPI_THREAD_SERIALIZED'
|
|
elseif(provided .eq. MPI_THREAD_MULTIPLE) then
|
|
prov_ch = 'MPI_THREAD_MULTIPLE '
|
|
else
|
|
prov_ch = 'unknown '
|
|
end if
|
|
write(6, '("WARNING: MPI initialized at ",
|
|
$ a, " thread support level.")') trim(prov_ch)
|
|
end if
|
|
end if
|
|
|
|
call MPI_Comm_rank(MPI_COMM_WORLD, mpi_rank, mpi_err)
|
|
call MPI_Comm_size(MPI_COMM_WORLD, mpi_size, mpi_err)
|
|
call MPI_Get_processor_name(pname, nlen, mpi_err)
|
|
|
|
call MPI_Comm_get_parent(parent, mpi_err)
|
|
call getcwd(wdir)
|
|
if(parent .eq. MPI_COMM_NULL) then
|
|
if(mpi_rank .eq. 0) then
|
|
output_folder = 'mpi_output'
|
|
wdir_parent = wdir
|
|
call system('mkdir -p ' // trim(output_folder) // char(0))
|
|
end if
|
|
parent = MPI_COMM_WORLD
|
|
end if
|
|
|
|
c if(parent .ne. MPI_COMM_NULL) then
|
|
call MPI_Bcast(wdir_parent, 512, MPI_CHARACTER, 0, parent,
|
|
$ mpi_err)
|
|
|
|
if(trim(wdir) .ne. trim(wdir_parent)) then
|
|
call system('mkdir -p ' // trim(wdir_parent) //
|
|
$ ' > /dev/null')
|
|
call chdir(trim(wdir_parent))
|
|
|
|
call getcwd(wdir)
|
|
if(wdir_parent .ne. wdir) then
|
|
write(*,
|
|
$ '(" Error: Couldn''t create working directory on ",a)'),
|
|
$ trim(pname)
|
|
call mrccend(1)
|
|
end if
|
|
c end if
|
|
|
|
c if(.not. master_thread) del_wdir = .true.
|
|
end if
|
|
|
|
call MPI_Bcast(output_folder, 32, MPI_CHARACTER, 0, parent,
|
|
$ mpi_err)
|
|
|
|
if(mpi_size .gt. 1) then
|
|
call choose_master_process
|
|
call create_bcast_group(MPI_COMM_WORLD,master_rank,bcast_comm,
|
|
$ inbcast,0)
|
|
|
|
del_wdir = inbcast .and. .not.master_thread
|
|
else
|
|
master_rank = 0
|
|
inbcast = .true.
|
|
master_thread = .true.
|
|
del_wdir = .false.
|
|
end if
|
|
|
|
dodiis = .false. !inbcast
|
|
c if(inbcast .and. mpi_size .gt. 1) then
|
|
c call MPI_Comm_size(bcast_comm, bcast_size, mpi_err)
|
|
c if(bcast_size .ne. mpi_size) dodiis = .false.
|
|
c end if
|
|
|
|
! redirect output
|
|
write(rank_ch, '(i8)') mpi_rank
|
|
if(.not. master_thread) then
|
|
outfilename = 'mrcc.out.'//trim(adjustl(rank_ch))
|
|
|
|
iout = outfile
|
|
open(iout, file = outfilename, access = 'append')
|
|
|
|
devnul = '>>' // trim(outfilename)
|
|
else
|
|
outfilename = ' '
|
|
devnul = ' '
|
|
iout = 6
|
|
tag = -1
|
|
end if
|
|
tag = 0
|
|
|
|
if(mpi_size .ne. 1) then
|
|
if(master_thread)
|
|
$ write(iout, '(" MPI parallel version",/)')
|
|
call MPI_Barrier(MPI_COMM_WORLD, mpi_err)
|
|
call sleep_f(1)
|
|
write(rank_ch, '(i8)') mpi_rank
|
|
if(master_thread) then
|
|
write(*,"(' rank ', a4, ' running on ', a20,
|
|
$ ' master')")
|
|
$ trim(adjustl(rank_ch)), pname
|
|
else
|
|
write(*,"(' rank ', a4, ' running on ', a20)")
|
|
$ trim(adjustl(rank_ch)), pname
|
|
end if
|
|
call MPI_Barrier(MPI_COMM_WORLD, mpi_err)
|
|
call sleep_f(1)
|
|
if(master_thread) write(iout, *)
|
|
end if
|
|
|
|
if(master_thread) then
|
|
open(unit=exitfile,file='EXIT',status='unknown')
|
|
write(exitfile,"(i5,2x,2(1pe15.8))") 1,0.d0,0.d0
|
|
close(exitfile)
|
|
end if
|
|
|
|
call addPidToList
|
|
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine choose_master_process
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer mpi_rank, mpi_size, mpi_err, nlen, parent, i
|
|
character*(MPI_MAX_PROCESSOR_NAME) pname
|
|
logical mpi_in, file_exists
|
|
logical, allocatable :: master_node(:)
|
|
character(len=MPI_MAX_PROCESSOR_NAME) :: id_ref
|
|
character*8 date
|
|
character*10 time
|
|
character*5 zone
|
|
integer dt(8)
|
|
|
|
call MPI_Comm_rank(MPI_COMM_WORLD, mpi_rank, mpi_err)
|
|
call MPI_Comm_size(MPI_COMM_WORLD, mpi_size, mpi_err)
|
|
call MPI_Get_processor_name(pname, nlen, mpi_err)
|
|
|
|
call MPI_Comm_get_parent(parent, mpi_err)
|
|
|
|
allocate(master_node(0:mpi_size-1))
|
|
|
|
master_node = .false.
|
|
if(parent .ne. MPI_COMM_NULL) then
|
|
! receive id from dmrcc
|
|
call MPI_Bcast(id_ref, MPI_MAX_PROCESSOR_NAME, MPI_CHARACTER,
|
|
$ 0, parent, mpi_err)
|
|
|
|
|
|
! choose master process
|
|
if(trim(adjustl(pname)) .eq. trim(adjustl(id_ref)))
|
|
$ master_node(mpi_rank) = .true.
|
|
|
|
else
|
|
if(mpi_size .gt. 1 .and. mpi_rank .eq. 0) then
|
|
write(*, '(/," WARNING: no parent process")')
|
|
write(*, '( " assigning rank 0 as master",/)')
|
|
end if
|
|
|
|
if(mpi_rank .eq. 0) then
|
|
master_node(0) = .true.
|
|
call date_and_time(date, time, zone, dt)
|
|
id_ref = pname
|
|
end if
|
|
call MPI_Bcast(id_ref, MPI_MAX_PROCESSOR_NAME, MPI_CHARACTER,
|
|
$ 0, MPI_COMM_WORLD, mpi_err)
|
|
end if
|
|
|
|
call MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
|
|
$ master_node, 1, MPI_LOGICAL, MPI_COMM_WORLD, mpi_err)
|
|
|
|
do i = 0, mpi_size-1
|
|
if(master_node(i)) exit
|
|
end do
|
|
master_rank = i
|
|
if(i .eq. mpi_size) then
|
|
write(*,*) "ERROR: input files not found"
|
|
call mrccend(1)
|
|
else if(i .eq. mpi_rank) then
|
|
master_thread = .true.
|
|
else
|
|
master_thread = .false.
|
|
end if
|
|
|
|
deallocate(master_node)
|
|
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine create_bcast_group(communicator, master_rank,
|
|
$ bcast_comm, inbcast, group_id)
|
|
************************************************************************
|
|
implicit none
|
|
#include "mpif.h"
|
|
integer mpi_group_world, bcast_group, group_id
|
|
integer group_size, communicator, master_rank, bcast_comm
|
|
integer mpi_rank, mpi_size, mpi_err, nlen, parent, i
|
|
integer, allocatable :: group_members(:)
|
|
logical mpi_in, file_exists, ingroup, inbcast
|
|
character*8 rank_ch,group_id_c
|
|
character*64 id, id_ref, group_idfile
|
|
character*(MPI_MAX_PROCESSOR_NAME) pname
|
|
data id /''/
|
|
|
|
character*8 date
|
|
character*10 time
|
|
character*5 zone
|
|
integer dt(8)
|
|
integer, parameter :: idfile = 961
|
|
|
|
|
|
! choose one process for each disk
|
|
call MPI_Comm_rank(communicator, mpi_rank, mpi_err)
|
|
call MPI_Comm_size(communicator, mpi_size, mpi_err)
|
|
call MPI_Get_processor_name(pname, nlen, mpi_err)
|
|
|
|
allocate(group_members(mpi_size))
|
|
|
|
write(group_id_c,'(i6)') group_id
|
|
group_idfile=trim('idfile') // '.' // trim(group_id_c)
|
|
c write(*,*) 'rank,idf',mpi_rank, trim(group_idfile)
|
|
|
|
if(mpi_rank .eq. master_rank) then
|
|
call date_and_time(date, time, zone, dt)
|
|
id_ref = date // time // zone // pname
|
|
|
|
open(idfile, file = trim(group_idfile))
|
|
write(idfile, *) trim(id_ref)
|
|
close(idfile)
|
|
|
|
inbcast = .true.
|
|
end if
|
|
|
|
call MPI_Bcast(id_ref, 64, MPI_CHARACTER, master_rank,
|
|
$ communicator, mpi_err)
|
|
|
|
group_size = 1
|
|
group_members(group_size) = master_rank
|
|
|
|
|
|
call MPI_Barrier(communicator, mpi_err)
|
|
do i = 0, mpi_size-1
|
|
if(i .eq. master_rank) cycle
|
|
|
|
if(i .eq. mpi_rank) then
|
|
id = ''
|
|
inquire(file = trim(group_idfile) , exist = file_exists)
|
|
if(file_exists) then
|
|
open(idfile, file = trim(group_idfile) )
|
|
read(idfile, *) id
|
|
close(idfile)
|
|
end if
|
|
|
|
if(id .ne. id_ref) then
|
|
open(idfile, file = trim(group_idfile) )
|
|
write(idfile, *) trim(id_ref)
|
|
close(idfile)
|
|
|
|
ingroup = .true.
|
|
else
|
|
ingroup = .false.
|
|
end if
|
|
inbcast = ingroup
|
|
end if
|
|
|
|
call MPI_Bcast(ingroup, 1, MPI_LOGICAL, i,
|
|
$ communicator, mpi_err)
|
|
|
|
if(ingroup) then
|
|
group_size = group_size + 1
|
|
group_members(group_size) = i
|
|
end if
|
|
end do
|
|
|
|
call MPI_Comm_group(communicator, mpi_group_world, mpi_err)
|
|
call MPI_Group_incl(mpi_group_world, group_size, group_members,
|
|
$ bcast_group, mpi_err)
|
|
call MPI_Comm_create(communicator, bcast_group, bcast_comm,
|
|
$ mpi_err)
|
|
|
|
deallocate(group_members)
|
|
|
|
c call delete_file('dmrcc.id', inbcast)
|
|
call delete_file(trim(group_idfile), inbcast)
|
|
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine bcast_file(filename, comm)
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer :: comm
|
|
character(len = *) :: filename
|
|
|
|
integer :: mpi_rank, mpi_err, comm_size
|
|
integer :: msg_size
|
|
integer :: iostatus
|
|
integer, parameter :: buff_size = 1048576 ! 1 MB
|
|
character(len = :), allocatable :: buffer
|
|
logical :: flag, flag2
|
|
logical :: empty, fexists
|
|
|
|
logical fexist
|
|
c integer fsize
|
|
|
|
if(.not.inbcast) return
|
|
|
|
call MPI_Initialized(flag, mpi_err)
|
|
call MPI_Finalized(flag2, mpi_err)
|
|
if(.not. flag .or. flag2) return
|
|
|
|
if(comm .eq. MPI_COMM_NULL) return
|
|
|
|
c fpos = 1
|
|
|
|
call MPI_Comm_size(comm, comm_size, mpi_err)
|
|
if(comm_size .eq. 1) return
|
|
|
|
call MPI_Comm_rank(comm, mpi_rank, mpi_err)
|
|
|
|
inquire(file = filename, exist = fexist)
|
|
|
|
allocate(character(len = buff_size) :: buffer)
|
|
|
|
if(mpi_rank .eq. 0) then
|
|
c msg_size = min(buff_size, fsize)
|
|
msg_size = buff_size
|
|
|
|
inquire(file = filename, exist = fexists)
|
|
call MPI_Bcast(fexists, 1, MPI_LOGICAL,
|
|
$ 0, comm, mpi_err)
|
|
|
|
open(unit = cpfile, file = filename, access = 'stream')
|
|
|
|
do
|
|
! read and bcast filename
|
|
buffer = repeat(' ', buff_size)
|
|
read(cpfile, iostat = iostatus) buffer
|
|
c read(cpfile, pos = fpos, iostat = iostatus) buffer
|
|
c fpos = fpos + buff_size
|
|
|
|
! end of file
|
|
if(iostatus .ne. 0) msg_size = len_trim(buffer)
|
|
if(msg_size .eq. 0) exit ! empty or end of file
|
|
|
|
call MPI_Bcast(msg_size, 1, MPI_INTEGER_MRCC,
|
|
$ 0, comm, mpi_err)
|
|
call MPI_Bcast(buffer, msg_size, MPI_CHARACTER,
|
|
$ 0, comm, mpi_err)
|
|
|
|
if(iostatus .ne. 0) exit
|
|
end do
|
|
|
|
call MPI_Bcast(0, 1, MPI_INTEGER_MRCC,
|
|
$ 0, comm, mpi_err)
|
|
|
|
c empty = .not.fexists
|
|
|
|
else
|
|
call delete_file(filename, .true.)
|
|
close(cpfile)
|
|
open(unit = cpfile, file = filename, access = 'stream')
|
|
|
|
call MPI_Bcast(fexists, 1, MPI_LOGICAL,
|
|
$ 0, comm, mpi_err)
|
|
|
|
c empty = .true.
|
|
do
|
|
! receive bcast
|
|
call MPI_Bcast(msg_size, 1, MPI_INTEGER_MRCC,
|
|
$ 0, comm, mpi_err)
|
|
|
|
! end of file
|
|
if(msg_size .eq. 0) exit
|
|
c empty = .false.
|
|
|
|
call MPI_Bcast(buffer, msg_size, MPI_CHARACTER,
|
|
$ 0, comm, mpi_err)
|
|
|
|
! write to file
|
|
write(cpfile) buffer(1:msg_size)
|
|
c write(cpfile, pos = fpos) buffer(1:msg_size)
|
|
c fpos = fpos + msg_size
|
|
end do
|
|
end if
|
|
empty = .not.fexists
|
|
|
|
close(cpfile)
|
|
call delete_file(filename, empty)
|
|
|
|
deallocate(buffer)
|
|
|
|
call MPI_Barrier(comm, mpi_err)
|
|
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine gather_file(filename, comm)
|
|
************************************************************************
|
|
c Gathers output files from other ranks. Only works with comm=bcast_comm
|
|
#include "MRCCCOMMON"
|
|
integer comm
|
|
character(len = *) filename
|
|
|
|
integer :: mpi_err, comm_size, msg_tag, mpi_rank
|
|
integer :: msg_size
|
|
integer :: iostatus, i
|
|
integer :: stat(MPI_STATUS_SIZE)
|
|
integer, parameter :: buff_size = 1048576 ! 1 MB
|
|
character(len = 4) i_ch
|
|
character(len = :), allocatable :: buffer
|
|
logical :: flag, flag2
|
|
|
|
call MPI_Initialized(flag, mpi_err)
|
|
call MPI_Finalized(flag2, mpi_err)
|
|
if(.not. flag .or. flag2) return
|
|
|
|
if(comm .eq. MPI_COMM_NULL) return
|
|
|
|
call MPI_Comm_size(comm, comm_size, mpi_err)
|
|
if(comm_size .eq. 1) return
|
|
|
|
call MPI_Comm_rank(comm, mpi_rank, mpi_err)
|
|
|
|
allocate(character(len = buff_size) :: buffer)
|
|
|
|
c if(.not. master_thread) then
|
|
if(mpi_rank .ne. master_rank) then
|
|
open(unit = cpfile, file = filename, access = 'stream')
|
|
|
|
msg_tag = 0
|
|
|
|
do
|
|
! read file and send it to master
|
|
buffer = repeat(' ', buff_size)
|
|
read(cpfile, iostat = iostatus) buffer
|
|
|
|
if(iostatus .ne. 0) then
|
|
! end of file
|
|
msg_size = len_trim(buffer)
|
|
msg_tag = 1
|
|
end if
|
|
|
|
call MPI_Send(msg_size, 1, MPI_INTEGER_MRCC,
|
|
$ master_rank, msg_tag, comm, mpi_err)
|
|
|
|
call MPI_Send(buffer, msg_size, MPI_CHARACTER,
|
|
$ master_rank, msg_tag, comm, mpi_err)
|
|
|
|
if(msg_tag .ne. 0) exit
|
|
end do
|
|
|
|
close(cpfile)
|
|
|
|
else
|
|
do i = 0, comm_size-1
|
|
if(i .eq. master_rank) cycle
|
|
|
|
write(i_ch, '(i4)') i
|
|
open(unit = cpfile, file = trim(adjustl(output_folder)) //
|
|
$ '/' // trim(adjustl(filename)) // '.' //
|
|
$ trim(adjustl(i_ch)),
|
|
$ access = 'stream', position = 'append')
|
|
|
|
do
|
|
! receive bcast
|
|
call MPI_Recv(msg_size, 1, MPI_INTEGER_MRCC,
|
|
$ i, MPI_ANY_TAG, comm, stat, mpi_err)
|
|
|
|
call MPI_Recv(buffer, msg_size, MPI_CHARACTER,
|
|
$ i, MPI_ANY_TAG, comm, stat, mpi_err)
|
|
|
|
! write to file
|
|
write(cpfile) buffer(1:msg_size)
|
|
|
|
! end of file
|
|
if(stat(MPI_TAG) .ne. 0) exit
|
|
end do
|
|
|
|
close(cpfile)
|
|
end do
|
|
end if
|
|
|
|
deallocate(buffer)
|
|
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine mpifinalize(ierr)
|
|
************************************************************************
|
|
* Finalizes MPI
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ierr
|
|
integer mpi_err, request, parent
|
|
integer system_error, nlen
|
|
integer system
|
|
logical mpi_in, mpi_fin
|
|
character(len = MPI_MAX_PROCESSOR_NAME) pname
|
|
|
|
|
|
call MPI_Initialized(mpi_in, mpi_err)
|
|
call MPI_Finalized(mpi_fin, mpi_err)
|
|
if(mpi_in .and. .not.mpi_fin) then
|
|
c if(tag.ge.0) then
|
|
|
|
call MPI_Get_processor_name(pname, nlen, mpi_err)
|
|
|
|
if(del_wdir) then
|
|
call delete_file('pids', inbcast)
|
|
call chdir('..')
|
|
system_error = system('rmdir ' // trim(wdir))! // ' 2>/dev/null') !!! wdir should have been set in mpiinit
|
|
if(system_error .ne. 0) then
|
|
write(*,
|
|
$ '(" Error: Couldn''t delete working directory on ", a)')
|
|
$ trim(pname)
|
|
end if
|
|
end if
|
|
|
|
flush(iout)
|
|
if(.not. master_thread) close(iout)
|
|
|
|
if(ierr .eq. -1) call exit(abs(ierr)) ! parent signalled child, no need to notify parent
|
|
|
|
call MPI_Comm_get_parent(parent, mpi_err)
|
|
|
|
! signal parents
|
|
if(parent .ne. MPI_COMM_NULL) then
|
|
call MPI_Ibarrier(parent, request, mpi_err)
|
|
call MPI_Wait(request, MPI_STATUS_IGNORE, mpi_err)
|
|
call sleep_f(1)
|
|
|
|
call MPI_Comm_disconnect(parent, mpi_err)
|
|
c call MPI_Comm_free(parent, mpi_err)
|
|
end if
|
|
|
|
call MPI_Finalize(mpi_err)
|
|
end if
|
|
|
|
end subroutine
|
|
|
|
#endif
|
|
|
|
************************************************************************
|
|
subroutine delete_file(filename, delete)
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character(len = *) :: filename
|
|
logical :: delete
|
|
|
|
#if defined(MPI)
|
|
if(.not.delete) return
|
|
#endif
|
|
c$OMP CRITICAL
|
|
open(delfile, file = trim(filename))
|
|
close(delfile, status = 'delete')
|
|
c$OMP END CRITICAL
|
|
end subroutine
|
|
|
|
************************************************************************
|
|
subroutine file_copy_fortran(origfilename,copiedfilename)
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character(len = *) :: origfilename,copiedfilename
|
|
c character*4 origfilename,copiedfilename
|
|
integer, parameter :: buff_size = 1048576 ! 1 MB
|
|
integer :: iostatus,write_size
|
|
character(len = :), allocatable :: buffer
|
|
logical lll
|
|
|
|
call delete_file(trim(copiedfilename), .true.)
|
|
open(unit = delfile, file = trim(origfilename),
|
|
$access = 'stream',IOSTAT=iostatus)
|
|
open(unit=cpfile,file=trim(copiedfilename),access='stream')
|
|
write_size=buff_size
|
|
allocate(character(len = buff_size) :: buffer)
|
|
|
|
do
|
|
buffer = repeat(' ', buff_size)
|
|
read(delfile, iostat = iostatus) buffer
|
|
if(iostatus.ne.0) write_size = len_trim(buffer)
|
|
if(write_size.eq.0) exit ! empty file
|
|
|
|
write(cpfile) buffer(1:write_size)
|
|
if(iostatus.ne.0) exit ! end of file
|
|
end do
|
|
|
|
close(delfile)
|
|
close(cpfile)
|
|
|
|
deallocate(buffer)
|
|
|
|
end subroutine
|
|
************************************************************************
|
|
subroutine mrccini
|
|
************************************************************************
|
|
* Initiates mrcc
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
C
|
|
tim=0.d0
|
|
wct=0.d0
|
|
call mtime(tim,wct)
|
|
timold=tim
|
|
wctold=wct
|
|
timvold=tim
|
|
wctvold=wct
|
|
|
|
call addPidToList
|
|
|
|
iout = 6
|
|
mem_allocated = .false.
|
|
del_wdir = .false.
|
|
master_thread = .true.
|
|
master_rank = 0
|
|
inbcast = .true.
|
|
bcast_comm = -1
|
|
|
|
open(unit=exitfile,file='EXIT',status='unknown')
|
|
write(exitfile,"(i5,2x,2(1pe15.8))") 1,0.d0,0.d0
|
|
close(exitfile)
|
|
|
|
call signalinitchild ! initialise response to SIG's
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mrccini_from_subroutine
|
|
************************************************************************
|
|
* Initialize if mrccini is not executed when calling a program as a subroutine
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
C
|
|
call mtime(tim,wct)
|
|
timold=tim
|
|
wctold=wct
|
|
C
|
|
return
|
|
end
|
|
c
|
|
************************************************************************
|
|
subroutine mrccend(ierr)
|
|
************************************************************************
|
|
* Terminates mrcc
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ierr
|
|
C
|
|
tim=1.d0
|
|
wct=1.d0
|
|
call mtime(tim,wct)
|
|
|
|
call removePidFromList
|
|
|
|
#if defined(MPI)
|
|
if(master_thread) then
|
|
#endif
|
|
open(unit=exitfile,file='EXIT',status='unknown')
|
|
write(exitfile,"(i5,2x,2(1pe15.8))") ierr,tim-timvold,wct-wctvold
|
|
close(exitfile)
|
|
#if defined(MPI)
|
|
end if
|
|
|
|
call mpifinalize(ierr)
|
|
#endif
|
|
|
|
if(ierr .eq. -2) return ! return to signal handler to call previous handler
|
|
|
|
call exit(ierr)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine addPidToList
|
|
************************************************************************
|
|
* Adds PID of the calling process to the list of running processes
|
|
* stored in file pids
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer :: getpid_f
|
|
|
|
open(unit = pidfile, file = 'pids', access = 'append')
|
|
write(pidfile, *) getpid_f()
|
|
close(unit = pidfile)
|
|
|
|
end subroutine
|
|
C
|
|
************************************************************************
|
|
subroutine removePidFromList
|
|
************************************************************************
|
|
* Removes PID of the calling process from the list of running processes
|
|
* stored in file pids
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
|
|
integer :: ownPid, getpid_f
|
|
character(len = 8) :: pidChar
|
|
|
|
ownPid = getpid_f()
|
|
write(pidChar, '(i8)') ownPid
|
|
|
|
call system('sed -i "/' // trim(adjustl(pidChar)) //
|
|
$ '/d" pids 2> /dev/null')
|
|
|
|
end subroutine
|
|
C
|
|
************************************************************************
|
|
subroutine timer
|
|
************************************************************************
|
|
* Returns CPU time minutes *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
C
|
|
tim=1.d0
|
|
wct=1.d0
|
|
call mtime(tim,wct)
|
|
write(iout,"(' CPU time [min]:',f10.3,
|
|
$' Wall time [min]:',f10.3)") tim/60.d0,wct/60.d0
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mtime(tt,ww)
|
|
************************************************************************
|
|
* Machine-dependent TIME routine *
|
|
* Returns CPU and wall time in seconds via double precision tt and wct *
|
|
************************************************************************
|
|
implicit none
|
|
integer wzero,w,ps
|
|
real*8 tt,tzero,t,ww
|
|
save tzero
|
|
save wzero
|
|
c real*4 t
|
|
C# AIX
|
|
C real*8 timef
|
|
C# LINUX
|
|
c call CPU_TIME(t)
|
|
c tt=t
|
|
call CPU_TIME(t)
|
|
if(tt.eq.0.d0) tzero=t
|
|
tt=t-tzero
|
|
call SYSTEM_CLOCK(w,ps)
|
|
if(ww.eq.0.d0) wzero=w
|
|
ww=dble(w-wzero)/dble(ps)
|
|
C# AIX
|
|
C tt=timef()/1000.d0
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine ishell(string)
|
|
************************************************************************
|
|
* Call external programs *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
character*(*) string
|
|
integer*4 istat
|
|
#if !defined (gfortran) && !defined (G95)
|
|
integer*4 system
|
|
external system
|
|
#endif
|
|
#if defined (Solaris10) || defined (gfortran)
|
|
character cpath*4096, cmd*5000
|
|
if( string(1:5).eq.'echo '
|
|
$ .or. string(1:4).eq.'sed '
|
|
$ .or. string(1:4).eq.'cat ') then
|
|
cmd=string
|
|
goto 100
|
|
endif
|
|
call getenv('PATH', cpath)
|
|
C Test if cpath was long enough to contain PATH
|
|
if(len_trim(cpath).gt.len(cpath)-5) then
|
|
write(iout,*)
|
|
write(iout,*) 'ishell: cpath variable too short.'
|
|
write(iout,*) 'Program will stop.'
|
|
call flush(iout)
|
|
call exit(1)
|
|
endif
|
|
C Build the tricky command
|
|
cmd="bash -c "//"'"//"export PATH="//cpath(1:len_trim(cpath))
|
|
$ //"; "//string(1:len_trim(string))//"'"
|
|
C Test if cmd was long enough to expand PATH and string
|
|
if(len_trim(cmd).gt.len(cmd)-5) then
|
|
write(iout,*)
|
|
write(iout,*) 'ishell: cmd variable too short.'
|
|
write(iout,*) 'Program will stop.'
|
|
call flush(iout)
|
|
call exit(1)
|
|
endif
|
|
100 continue
|
|
istat=system(cmd)
|
|
if(istat.lt.0) then
|
|
#else
|
|
character*512 cmd
|
|
cmd=string // char(0)
|
|
istat=system(cmd)
|
|
if(istat.ne.0) then
|
|
#endif
|
|
write(iout,*)
|
|
write(iout,*) 'Fatal error in ',string,'.'
|
|
write(iout,*) 'Program will stop.'
|
|
call flush(iout)
|
|
call dmrccend(1)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine dmrccend(ierr)
|
|
************************************************************************
|
|
* Terminates mrcc
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer ierr
|
|
character*16 devnul
|
|
common/output/ devnul
|
|
#if defined(MPI)
|
|
integer mpi_err, mpi_rank
|
|
logical mpi_in
|
|
#endif
|
|
C
|
|
write(iout,*)
|
|
call system(
|
|
$'echo " ************************ "`date +"%F %T"`"' //
|
|
$' *************************"'//trim(devnul))
|
|
c#if defined(MPI)
|
|
c call MPI_Initialized(mpi_in, mpi_err)
|
|
c
|
|
c if(mpi_in) then
|
|
c call MPI_Comm_rank(MPI_COMM_WORLD, mpi_rank, mpi_err)
|
|
c
|
|
c if(mpi_rank .ne. 0) read(iout, *)
|
|
c end if
|
|
c#endif
|
|
if(ierr.eq.0) then
|
|
write(iout,"(22x,a27)") 'Normal termination of mrcc.'
|
|
else
|
|
write(iout,"(19x,a33)") 'Error at the termination of mrcc.'
|
|
endif
|
|
write(iout,"(1x,70('*'))")
|
|
|
|
#if defined(MPI)
|
|
call mpifinalize(ierr)
|
|
#endif
|
|
|
|
call delete_file('pids', inbcast)
|
|
|
|
call exit(ierr)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getvar(vname,var)
|
|
************************************************************************
|
|
* Read variables from file VARS
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer i,n
|
|
integer*1 var(*)
|
|
character*10 vname,cscr
|
|
C
|
|
open(varsfile,file='VARS',form='UNFORMATTED')
|
|
rewind(varsfile)
|
|
do
|
|
read(varsfile,end=1002) cscr
|
|
if(cscr.eq.vname) exit
|
|
enddo
|
|
backspace(varsfile)
|
|
read(varsfile) cscr,n,(var(i),i=1,n)
|
|
close(varsfile)
|
|
C
|
|
return
|
|
1002 continue
|
|
write(iout,*) 'Corrupted file VARS!'
|
|
write(iout,*) 'Variable '//trim(adjustl(vname))//' is missing!'
|
|
write(iout,*) 'Please run integ first!'
|
|
call mrccend(1)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getvar_c(vname,var)
|
|
************************************************************************
|
|
* Read variables from file VARS
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer i,n
|
|
character*1 var(*)
|
|
character*10 vname,cscr
|
|
C
|
|
open(varsfile,file='VARS',form='UNFORMATTED')
|
|
rewind(varsfile)
|
|
do
|
|
read(varsfile,end=1002) cscr
|
|
if(cscr.eq.vname) exit
|
|
enddo
|
|
backspace(varsfile)
|
|
read(varsfile) cscr,n,(var(i),i=1,n)
|
|
close(varsfile)
|
|
C
|
|
return
|
|
1002 continue
|
|
write(iout,*) 'Corrupted file VARS!'
|
|
write(iout,*) 'Please run integ first!'
|
|
call mrccend(1)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine rspmx(h,n,ifile)
|
|
************************************************************************
|
|
* Read and unpack symmetry-packed matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer n,ifile,i,j,ii
|
|
real*8 h(n*n)
|
|
C
|
|
read(ifile) (h(i),i=1,(n+1)*n/2)
|
|
ii=(n+1)*n/2
|
|
do j=n,1,-1
|
|
do i=n,j,-1
|
|
h((j-1)*n+i)=h(ii)
|
|
ii=ii-1
|
|
enddo
|
|
enddo
|
|
c call fillup(h,n)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine rspmx2(h,n,ifile)
|
|
************************************************************************
|
|
* Read symmetry-packed matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer n,ifile,i,j,ii
|
|
real*8 h(n*n)
|
|
C
|
|
read(ifile) (h(i),i=1,(n+1)*n/2)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine roeint_kineti(r8heap,i4heap,h,ifile,nbasis)
|
|
C***********************************************************************
|
|
C Read one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis
|
|
real*8 r8heap(*),h(nbasis,nbasis)
|
|
integer*4 i4heap(*)
|
|
C
|
|
call dfillzero(h,nbasis**2)
|
|
read(ifile) nn
|
|
rewind(ifile)
|
|
c write(6,*) nn
|
|
read(ifile) ii,(r8heap(jj),jj=1,2*nn)
|
|
do ii=1,nn
|
|
i=i4heap((ii-1)*4+3)
|
|
j=i4heap((ii-1)*4+4)
|
|
h(i,j)=r8heap(ii*2-1)
|
|
h(j,i)=r8heap(ii*2-1)
|
|
c write(6,"(i7,2x,2i4,f12.5)") ii,i,j,h(i,j)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine roeint(r8heap,i4heap,h,ifile,nbasis)
|
|
C***********************************************************************
|
|
C Read one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis
|
|
real*8 r8heap(*),h(nbasis,nbasis)
|
|
integer*4 i4heap(*)
|
|
C
|
|
call dfillzero(h,nbasis**2)
|
|
read(ifile) nn
|
|
backspace(ifile)
|
|
c write(6,*) nn
|
|
read(ifile) ii,(r8heap(jj),jj=1,2*nn)
|
|
do ii=1,nn
|
|
i=i4heap((ii-1)*4+3)
|
|
j=i4heap((ii-1)*4+4)
|
|
h(i,j)=r8heap(ii*2-1)
|
|
h(j,i)=r8heap(ii*2-1)
|
|
c write(6,"(i7,2x,2i4,f12.5)") ii,i,j,h(i,j)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine woeint(r8heap,i4heap,h,ifile,itol,nbasis)
|
|
C***********************************************************************
|
|
C Write one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis
|
|
real*8 r8heap(*),h(nbasis,nbasis),itol
|
|
integer*4 i4heap(*)
|
|
C
|
|
nn=0
|
|
do i=1,nbasis
|
|
do j=1,i
|
|
if(dabs(h(i,j)).gt.itol) then
|
|
nn=nn+1
|
|
r8heap(nn*2-1)=h(i,j)
|
|
i4heap((nn-1)*4+3)=i
|
|
i4heap((nn-1)*4+4)=j
|
|
endif
|
|
enddo
|
|
enddo
|
|
write(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine woeintu(r8heap,i4heap,h,ifile,itol,nbasis)
|
|
C***********************************************************************
|
|
C Write one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis
|
|
real*8 r8heap(*),h(nbasis,nbasis),itol
|
|
integer*4 i4heap(*)
|
|
C
|
|
nn=0
|
|
do i=1,nbasis
|
|
do j=1,i
|
|
if(dabs(h(j,i)).gt.itol) then
|
|
nn=nn+1
|
|
r8heap(nn*2-1)=h(j,i)
|
|
i4heap((nn-1)*4+3)=j
|
|
i4heap((nn-1)*4+4)=i
|
|
endif
|
|
enddo
|
|
enddo
|
|
write(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
|
|
C***********************************************************************
|
|
subroutine wtdmx(r8heap,i4heap,h,ifile,itol,nb1,nb2)
|
|
C***********************************************************************
|
|
C Write two-dimensional matrix
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nb1,nb2
|
|
real*8 r8heap(*),h(nb1,nb2),itol
|
|
integer*4 i4heap(*)
|
|
C
|
|
c write(6,"(4f10.5)") h
|
|
nn=0
|
|
do i=1,nb1
|
|
do j=1,nb2
|
|
if(dabs(h(i,j)).gt.itol) then
|
|
nn=nn+1
|
|
r8heap(nn*2-1)=h(i,j)
|
|
i4heap((nn-1)*4+3)=i
|
|
i4heap((nn-1)*4+4)=j
|
|
endif
|
|
enddo
|
|
enddo
|
|
write(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine wrtmo(r8heap,i4heap,c,ifile,itol,nbf,nbasis)
|
|
C***********************************************************************
|
|
C Write MO coefficients
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbf,nbasis
|
|
real*8 r8heap(*),c(nbf,nbasis),itol
|
|
integer*4 i4heap(*)
|
|
C
|
|
nn=0
|
|
do j=1,nbasis
|
|
do i=1,nbf
|
|
if(dabs(c(i,j)).gt.itol) then
|
|
nn=nn+1
|
|
r8heap(nn*2-1)=c(i,j)
|
|
i4heap((nn-1)*4+3)=i
|
|
i4heap((nn-1)*4+4)=j
|
|
endif
|
|
enddo
|
|
enddo
|
|
write(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine rtdmx(r8heap,i4heap,h,ifile,nb1,nb2)
|
|
C***********************************************************************
|
|
C Read one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nb1,nb2
|
|
real*8 r8heap(*),h(nb1,nb2)
|
|
integer*4 i4heap(*)
|
|
C
|
|
call dfillzero(h,nb1*nb2)
|
|
read(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
do ii=1,nn
|
|
i=i4heap((ii-1)*4+3)
|
|
j=i4heap((ii-1)*4+4)
|
|
if(j.le.nb2) h(i,j)=r8heap(ii*2-1)
|
|
C write(6,"(2i4,f12.5)") i,j,h(i,j)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
|
|
C***********************************************************************
|
|
subroutine roequa(r8heap,i4heap,h,ifile,nbasis)
|
|
C***********************************************************************
|
|
C Read non-symmetric one-electron quantities
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis
|
|
real*8 r8heap(*),h(nbasis,nbasis)
|
|
integer*4 i4heap(*)
|
|
C
|
|
call dfillzero(h,nbasis**2)
|
|
read(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
do ii=1,nn
|
|
i=i4heap((ii-1)*4+3)
|
|
j=i4heap((ii-1)*4+4)
|
|
h(i,j)=r8heap(ii*2-1)
|
|
c write(6,"(2i4,f12.5)") i,j,h(i,j)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine syminv(mat,invmat,n,nn,scr)
|
|
C***********************************************************************
|
|
C Calculate the inverse of a symmetric real matrix
|
|
C The lower triangle of the matrix is used!
|
|
C***********************************************************************
|
|
implicit none
|
|
integer n,nn,i,j
|
|
real*8 mat(nn,nn),invmat(nn,nn),scr(n*(n+1)/2+2*n)
|
|
C
|
|
if (n.gt.1) then
|
|
do j=1,n
|
|
do i=1,j
|
|
scr(i+(j-1)*j/2)=mat(j,i)
|
|
enddo
|
|
enddo
|
|
call dsptrf('U',n,scr,scr(n*(n+1)/2+1),scr(n*(n+1)/2+n+1),i)
|
|
call dsptri('U',n,scr,scr(n*(n+1)/2+1),scr(n*(n+1)/2+n+1),i)
|
|
if(i.ne.0) then
|
|
write(6,*) 'Fatal error at matrix inversion!'
|
|
if(i.lt.0) then
|
|
write(6,*) 'Illegal arguments!'
|
|
else
|
|
write(6,*) 'The matrix is singular!'
|
|
endif
|
|
call mrccend(1)
|
|
endif
|
|
c write(6,"(10000f9.5)") scr
|
|
do j=1,n
|
|
do i=1,j
|
|
invmat(i,j)=scr(i+(j-1)*j/2)
|
|
invmat(j,i)=invmat(i,j)
|
|
enddo
|
|
enddo
|
|
elseif (n.eq.1) then !NP
|
|
if(dabs(mat(1,1)).lt.1.d-15) then
|
|
write(6,*) 'The matrix for inversion has 1 element:',mat(1,1)
|
|
call mrccend(1)
|
|
endif
|
|
invmat(1,1)=1.d0/mat(1,1)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
C***********************************************************************
|
|
subroutine syminvpd(mat,n,nn)
|
|
C***********************************************************************
|
|
C Calculate the inverse of a symmetric real positive definite matrix
|
|
C The lower triangle of the matrix is used!
|
|
C***********************************************************************
|
|
implicit none
|
|
integer n,nn,i
|
|
integer*4 ii
|
|
equivalence(i,ii)
|
|
real*8 mat(nn,nn)
|
|
C
|
|
call dpotrf('L',n,mat,nn,ii)
|
|
if(ii.ne.0) goto 9876
|
|
call dpotri('L',n,mat,nn,ii)
|
|
if(ii.ne.0) goto 9876
|
|
C
|
|
return
|
|
9876 write(6,*) 'Fatal error at matrix inversion!'
|
|
write(6,*) 'The matrix is not positive definite!'
|
|
call mrccend(1)
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine invsqrt(mat,n,scr,iout,erri,tol,iflag)
|
|
************************************************************************
|
|
* Calculate the inverse/square root of a symmetric, positive def. matrix
|
|
* The lower triangle of the matrix is stored
|
|
* iflag=1 - inverse square root
|
|
* iflag=2 - square root
|
|
* iflag=3 - Cholesky deco of the inverse
|
|
* iflag=4 - inverse
|
|
************************************************************************
|
|
implicit none
|
|
integer n,iout,i,j,erri,iflag,ii,info8
|
|
integer*4 err,info4
|
|
real*8 mat(n,n),scr(*),ss,tol,mr
|
|
equivalence(info8,info4)
|
|
integer imem,imem1,maxcor,memfree,memreq
|
|
common/actmem/ imem,maxcor
|
|
common/memcom/ imem1
|
|
|
|
C
|
|
memfree = maxcor - (imem - imem1)
|
|
c write(6,*)
|
|
c do i=1,n
|
|
c write(6,"(10000f9.5)") (mat(i,j),j=1,n)
|
|
c enddo
|
|
if(iflag.ge.3) then
|
|
C Inverse of the matrix
|
|
call dpotrf('L',n,mat,n,info4)
|
|
if(info4.ne.0) then
|
|
write(iout,*) 'Fatal error at Cholesky decomposition!'
|
|
call mrccend(1)
|
|
endif
|
|
call dpotri('L',n,mat,n,info4)
|
|
if(info4.ne.0) then
|
|
write(iout,*) 'Fatal error at matrix inversion!'
|
|
call mrccend(1)
|
|
endif
|
|
if(iflag.eq.4) then
|
|
erri=0
|
|
return
|
|
endif
|
|
C Cholesky deco of the inverse of the matrix
|
|
call dpotrf('L',n,mat,n,info4)
|
|
if(info4.ne.0) then
|
|
write(iout,*) 'Fatal error at Cholesky decomposition!'
|
|
call mrccend(1)
|
|
endif
|
|
do j=2,n
|
|
mat(1:j-1,j)=0.d0
|
|
enddo
|
|
erri=0
|
|
c call dtrtri('L','N',n,mat,n,i)
|
|
c if(i.ne.0) then
|
|
c write(iout,*) 'Fatal error at matrix inversion!'
|
|
c call mrccend(1)
|
|
c endif
|
|
c do i=1,n
|
|
c do j=1,min(i,n-i)
|
|
c ss=mat(i,j)
|
|
c mat(i,j)=mat(n-j+1,n-i+1)
|
|
c mat(n-j+1,n-i+1)=ss
|
|
c enddo
|
|
c enddo
|
|
c write(6,*)
|
|
c do i=1,n
|
|
c write(6,"(10000f9.5)") (mat(i,j),j=1,n)
|
|
c enddo
|
|
c return
|
|
C
|
|
c ii=0
|
|
c do i=1,n
|
|
c do j=1,i
|
|
c ii=ii+1
|
|
c scr(ii)=mat(i,j)
|
|
c enddo
|
|
c enddo
|
|
c call dsptrf('U',n,scr,scr(n*(n+1)/2+1),scr(n*(n+1)/2+n+1),i)
|
|
c call dsptri('U',n,scr,scr(n*(n+1)/2+1),scr(n*(n+1)/2+n+1),i)
|
|
c if(i.ne.0) then
|
|
c write(iout,*) 'Fatal error at matrix inversion!'
|
|
c call mrccend(1)
|
|
c endif
|
|
c call dpptrf('U',n,scr,i)
|
|
c if(i.ne.0) then
|
|
c write(iout,*) 'Fatal error at Cholesky decomposition!'
|
|
c call mrccend(1)
|
|
c endif
|
|
c ii=0
|
|
c do i=1,n
|
|
c do j=1,i
|
|
c ii=ii+1
|
|
c mat(i,j)=scr(ii)
|
|
c enddo
|
|
c do j=i+1,n
|
|
c mat(i,j)=0.d0
|
|
c enddo
|
|
c enddo
|
|
c erri=0
|
|
c write(6,*)
|
|
c do i=1,n
|
|
c write(6,"(10000f9.5)") (mat(i,j),j=1,n)
|
|
c enddo
|
|
C dpotf2.f dpptrf.f dpotrf.f
|
|
else
|
|
C Inverse/square root
|
|
call dsyev('V','L',n,mat,n,scr,mr,-1,err)
|
|
c memreq = idnint(mr)
|
|
memreq = int(mr)
|
|
if(memfree .le. memreq) then
|
|
write(iout, '(a)') ' Error: Insufficient memory'
|
|
write(iout, '(i8,a)') (memreq-memfree)*8/1024**2,
|
|
$ ' MB more memory needed'
|
|
call mrccend(1)
|
|
end if
|
|
c write(6,*) (mat(i,i),i=1,n)
|
|
c write(6,"(9f10.6)") mat
|
|
C Diagonalize
|
|
call dsyev('V','L',n,mat,n,scr,scr(n+1),3*n**2,err)
|
|
c write(6,*) 'eig'
|
|
c write(6,"(10000f20.12)") (scr(j),j=1,n)
|
|
erri=err
|
|
if(err.ne.0) then
|
|
write(iout,*) 'Inverse square root: Fatal error at the ' //
|
|
$'diagonalization of the matrix!'
|
|
call mrccend(1)
|
|
endif
|
|
C Inverse square root
|
|
call dcopy(n**2,mat,1,scr(n+1),1)
|
|
do i=1,n
|
|
ss=scr(i)
|
|
if(ss.lt.tol) then
|
|
c if(ss.lt.1d-10) then
|
|
write(iout,*)
|
|
$'Inverse square root: The matrix is not positive definite!'
|
|
c write(iout,"(' Critical eigenvalue: ',1pe8.2)") ss
|
|
erri=1
|
|
c call mrccend(1)
|
|
return
|
|
else
|
|
c if(iflag.eq.4) then
|
|
c ss=1.d0/ss !inverse
|
|
c else
|
|
ss=dsqrt(ss) !square root
|
|
if(iflag.eq.1) ss=1.d0/ss !inverse square root
|
|
c endif
|
|
call dscal(n,ss,mat(1,i),1)
|
|
endif
|
|
enddo
|
|
call dgemm('n','t',n,n,n,1.d0,mat,n,scr(n+1),n,0.d0,
|
|
$scr(n+n**2+1),n)
|
|
call dcopy(n**2,scr(n+n**2+1),1,mat,1)
|
|
c write(6,"(2f10.5)") mat
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine sppack(n,m,c,spc,spi,tol)
|
|
************************************************************************
|
|
* Pack sparse matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer n,m,i,j,nn
|
|
integer*8 spi(0:3*n*m)
|
|
real*8 c(n,m),spc(0:3*n*m),tol
|
|
C
|
|
nn=0
|
|
do i=1,n
|
|
c write(6,"(10000f14.8)") (c(i,j),j=1,m)
|
|
do j=1,m
|
|
if(dabs(c(i,j)).gt.tol) then
|
|
spc(3*nn+1)=c(i,j)
|
|
spi(3*nn+2)=i
|
|
spi(3*nn+3)=j
|
|
nn=nn+1
|
|
endif
|
|
enddo
|
|
enddo
|
|
spi(0)=3*nn-3
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine spgemmn(m,n,k,spa,spi,b,c)
|
|
************************************************************************
|
|
* Multiplication of sparse matrix A with matrix B
|
|
************************************************************************
|
|
implicit none
|
|
integer m,n,i,j,k,l,nn
|
|
integer*8 spi(0:3*m*k)
|
|
real*8 spa(0:3*m*k),b(k,n),c(m,n),sum
|
|
C
|
|
c call dfillzero(c,m*n)
|
|
c=0.d0
|
|
do nn=0,spi(0),3
|
|
sum=spa(nn+1)
|
|
i= spi(nn+2)
|
|
l= spi(nn+3)
|
|
do j=1,n
|
|
c(i,j)=c(i,j)+sum*b(l,j)
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine spgemmt(m,n,k,spa,spi,b,c)
|
|
************************************************************************
|
|
* Multiplication of sparse matrix A with matrix B^T
|
|
************************************************************************
|
|
implicit none
|
|
integer m,n,i,j,k,l,nn
|
|
integer*8 spi(0:3*m*k)
|
|
real*8 spa(0:3*m*k),b(n,k),c(m,n),sum
|
|
C
|
|
c call dfillzero(c,m*n)
|
|
c=0.d0
|
|
do nn=0,spi(0),3
|
|
sum=spa(nn+1)
|
|
i= spi(nn+2)
|
|
l= spi(nn+3)
|
|
c c(i,1:n)=c(i,1:n)+sum*b(1:n,l)
|
|
do j=1,n
|
|
c(i,j)=c(i,j)+sum*b(j,l)
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine spgemmr(m,n,k,spa,spi,b,c)
|
|
************************************************************************
|
|
* Multiplication of matrix B with the transpose of sparse matrix A
|
|
************************************************************************
|
|
implicit none
|
|
integer m,n,i,j,k,l,nn
|
|
integer*8 spi(0:3*n*k)
|
|
real*8 spa(0:3*n*k),b(m,k),c(m,n),sum
|
|
C
|
|
c call dfillzero(c,m*n)
|
|
c=0.d0
|
|
do nn=0,spi(0),3
|
|
sum=spa(nn+1)
|
|
j= spi(nn+2)
|
|
l= spi(nn+3)
|
|
do i=1,m
|
|
c(i,j)=c(i,j)+b(i,l)*sum
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mxtrans(b,n,m,file,irec,inewadd)
|
|
************************************************************************
|
|
* General matrix transposition, the matrix is read from file *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer n,m,i,j,ii,file,irec,inewadd,ifrec
|
|
real*8 b(m,n)
|
|
C
|
|
if(m*n.le.0) return
|
|
ifrec=irec+(inewadd-mod(inewadd,ibufln))/ibufln
|
|
read(file,rec=ifrec) ibuf
|
|
ii=mod(inewadd,ibufln)
|
|
do j=1,m
|
|
do i=1,n
|
|
ii=ii+1
|
|
b(j,i)=ibuf(ii)
|
|
if(ii.eq.ibufln) then
|
|
ii=0
|
|
ifrec=ifrec+1
|
|
if(i*j.lt.n*m) read(file,rec=ifrec) ibuf
|
|
endif
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine gtrans(a,b,n,m)
|
|
************************************************************************
|
|
* General matrix transposition
|
|
************************************************************************
|
|
implicit none
|
|
integer n,m,i,j
|
|
real*8 a(n,m),b(m,n)
|
|
C
|
|
do i=1,n
|
|
do j=1,m
|
|
b(j,i)=a(i,j)
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine fillup(a,n)
|
|
************************************************************************
|
|
* Fill up the upper triangle of a symmetric matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 a(n,n)
|
|
C
|
|
do i=1,n
|
|
do j=1,i-1
|
|
a(j,i)=a(i,j)
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine filllo(a,n)
|
|
************************************************************************
|
|
* Fill up the lower triangle of a symmetric matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 a(n,n)
|
|
C
|
|
do i=1,n
|
|
do j=1,i-1
|
|
a(i,j)=a(j,i)
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine filezero(file,ilo,iup)
|
|
************************************************************************
|
|
* Initialize files *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer file,ilo,iup,i
|
|
C
|
|
call dfillzero(ibuf,ibufln)
|
|
do i=ilo,iup
|
|
write(file,rec=i) ibuf
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
|
|
C***********************************************************************
|
|
subroutine readmo(r8heap,i4heap,mo,ifile,nbf,nbasis)
|
|
C***********************************************************************
|
|
C Read MO coefficients (without core orbitals)
|
|
C***********************************************************************
|
|
implicit none
|
|
integer ii,jj,nn,i,j,ifile,nbasis,nbf,ncore
|
|
real*8 r8heap(*),mo(nbf,nbasis)
|
|
integer*4 i4heap(*)
|
|
C
|
|
call dfillzero(mo,nbf*nbasis)
|
|
ncore=nbf-nbasis
|
|
read(ifile) nn,(r8heap(jj),jj=1,2*nn)
|
|
do ii=1,nn
|
|
i=i4heap((ii-1)*4+3)
|
|
j=i4heap((ii-1)*4+4)
|
|
if(j.gt.ncore) mo(i,j-ncore)=r8heap(ii*2-1)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine gbcheck(lgb,atsymbas,gbasfile)
|
|
************************************************************************
|
|
* Checks if file GENBAS exists and contains a basis set/grid
|
|
************************************************************************
|
|
implicit none
|
|
integer gbasfile
|
|
character*24 atsymbas,glabel
|
|
logical lgb
|
|
C
|
|
inquire(file='GENBAS',exist=lgb)
|
|
if(lgb) then
|
|
open(gbasfile,file='GENBAS')
|
|
glabel=' '
|
|
do while(trim(atsymbas).ne.trim(glabel))
|
|
read(gbasfile,*,end=1000) glabel
|
|
call lowercase(glabel,glabel,24)
|
|
enddo
|
|
c close(gbasfile)
|
|
endif
|
|
C
|
|
return
|
|
1000 continue
|
|
close(gbasfile)
|
|
lgb=.false.
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine motransp(nmatrix,nbasis,mo1,mo2,lll)
|
|
************************************************************************
|
|
* Transpose MO coefficient matrix
|
|
************************************************************************
|
|
implicit none
|
|
integer nmatrix,nbasis,i,mu
|
|
real*8 mo1(nmatrix,nbasis),mo2(nbasis,nmatrix)
|
|
logical lll
|
|
C
|
|
if(lll) then
|
|
do i=1,nmatrix
|
|
do mu=1,nbasis
|
|
mo2(mu,i)=mo1(i,mu)
|
|
enddo
|
|
enddo
|
|
else
|
|
do i=1,nmatrix
|
|
do mu=1,nbasis
|
|
mo1(i,mu)=mo2(mu,i)
|
|
enddo
|
|
enddo
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
SUBROUTINE QSORTD (ORD,N,A)
|
|
************************************************************************
|
|
* SORTS THE ARRAY A(I),I=1,2,...,N BY PUTTING THE
|
|
* ASCENDING ORDER VECTOR IN ORD. THAT IS ASCENDING ORDERED A
|
|
* IS A(ORD(I)),I=1,2,...,N; DESCENDING ORDER A IS A(ORD(N-I+1)),
|
|
* I=1,2,...,N . THIS SORT RUNS IN TIME PROPORTIONAL TO N LOG N .
|
|
************************************************************************
|
|
IMPLICIT INTEGER (A-Z)
|
|
C
|
|
DIMENSION ORD(N),POPLST(2,20)
|
|
REAL*8 X,XX,Z,ZZ,Y
|
|
C
|
|
C TO SORT DIFFERENT INPUT TYPES, CHANGE THE FOLLOWING
|
|
C SPECIFICATION STATEMENTS; FOR EXAMPLE, FOR FORTRAN CHARACTER
|
|
C USE THE FOLLOWING: CHARACTER *(*) A(N)
|
|
C
|
|
REAL*8 A(N)
|
|
C
|
|
NDEEP=0
|
|
U1=N
|
|
L1=1
|
|
DO 1 I=1,N
|
|
1 ORD(I)=I
|
|
2 IF (U1.LE.L1) RETURN
|
|
C
|
|
3 L=L1
|
|
U=U1
|
|
C
|
|
C PART
|
|
C
|
|
4 P=L
|
|
Q=U
|
|
C FOR CHARACTER SORTS, THE FOLLOWING 3 STATEMENTS WOULD BECOME
|
|
C X = ORD(P)
|
|
C Z = ORD(Q)
|
|
C IF (A(X) .LE. A(Z)) GO TO 2
|
|
C
|
|
C WHERE "CLE" IS A LOGICAL FUNCTION WHICH RETURNS "TRUE" IF THE
|
|
C FIRST ARGUMENT IS LESS THAN OR EQUAL TO THE SECOND, BASED ON "LEN"
|
|
C CHARACTERS.
|
|
C
|
|
X=A(ORD(P))
|
|
Z=A(ORD(Q))
|
|
IF (X.LE.Z) GO TO 5
|
|
Y=X
|
|
X=Z
|
|
Z=Y
|
|
YP=ORD(P)
|
|
ORD(P)=ORD(Q)
|
|
ORD(Q)=YP
|
|
5 IF (U-L.LE.1) GO TO 15
|
|
XX=X
|
|
IX=P
|
|
ZZ=Z
|
|
IZ=Q
|
|
C
|
|
C LEFT
|
|
C
|
|
6 P=P+1
|
|
IF (P.GE.Q) GO TO 7
|
|
X=A(ORD(P))
|
|
IF (X.GE.XX) GO TO 8
|
|
GO TO 6
|
|
7 P=Q-1
|
|
GO TO 13
|
|
C
|
|
C RIGHT
|
|
C
|
|
8 Q=Q-1
|
|
IF (Q.LE.P) GO TO 9
|
|
Z=A(ORD(Q))
|
|
IF (Z.LE.ZZ) GO TO 10
|
|
GO TO 8
|
|
9 Q=P
|
|
P=P-1
|
|
Z=X
|
|
X=A(ORD(P))
|
|
C
|
|
C DIST
|
|
C
|
|
10 IF (X.LE.Z) GO TO 11
|
|
Y=X
|
|
X=Z
|
|
Z=Y
|
|
IP=ORD(P)
|
|
ORD(P)=ORD(Q)
|
|
ORD(Q)=IP
|
|
11 IF (X.LE.XX) GO TO 12
|
|
XX=X
|
|
IX=P
|
|
12 IF (Z.GE.ZZ) GO TO 6
|
|
ZZ=Z
|
|
IZ=Q
|
|
GO TO 6
|
|
C
|
|
C OUT
|
|
C
|
|
13 CONTINUE
|
|
IF (.NOT.(P.NE.IX.AND.X.NE.XX)) GO TO 14
|
|
IP=ORD(P)
|
|
ORD(P)=ORD(IX)
|
|
ORD(IX)=IP
|
|
14 CONTINUE
|
|
IF (.NOT.(Q.NE.IZ.AND.Z.NE.ZZ)) GO TO 15
|
|
IQ=ORD(Q)
|
|
ORD(Q)=ORD(IZ)
|
|
ORD(IZ)=IQ
|
|
15 CONTINUE
|
|
IF (U-Q.LE.P-L) GO TO 16
|
|
L1=L
|
|
U1=P-1
|
|
L=Q+1
|
|
GO TO 17
|
|
16 U1=U
|
|
L1=Q+1
|
|
U=P-1
|
|
17 CONTINUE
|
|
IF (U1.LE.L1) GO TO 18
|
|
C
|
|
C START RECURSIVE CALL
|
|
C
|
|
NDEEP=NDEEP+1
|
|
POPLST(1,NDEEP)=U
|
|
POPLST(2,NDEEP)=L
|
|
GO TO 3
|
|
18 IF (U.GT.L) GO TO 4
|
|
C
|
|
C POP BACK UP IN THE RECURSION LIST
|
|
C
|
|
IF (NDEEP.EQ.0) GO TO 2
|
|
U=POPLST(1,NDEEP)
|
|
L=POPLST(2,NDEEP)
|
|
NDEEP=NDEEP-1
|
|
GO TO 18
|
|
C
|
|
C END SORT
|
|
C END QSORT
|
|
C
|
|
END
|
|
C
|
|
!NP
|
|
c {{{ subroutines timeadd time0
|
|
subroutine timeadd(t,t0)
|
|
implicit none
|
|
real*8 t(6),tmp,t0(2)
|
|
integer w,ps
|
|
|
|
c integer omp_get_thread_num,
|
|
c $ omp_get_ancestor_thread_num,omp_get_level
|
|
c write(*,*) "timeadd", omp_get_thread_num(),
|
|
c $ omp_get_ancestor_thread_num(omp_get_level()-1)
|
|
c$OMP CRITICAL
|
|
call CPU_TIME(tmp)
|
|
call SYSTEM_CLOCK(w,ps)
|
|
t(1)=tmp-t0(1)
|
|
t(2)=dble(w)/dble(ps)-t0(2)
|
|
c sum of times
|
|
t(3)=t(3)+t(1)
|
|
t(4)=t(4)+t(2)
|
|
c max times
|
|
t(5)=max(t(1),t(5))
|
|
t(6)=max(t(2),t(6))
|
|
c$OMP END CRITICAL
|
|
return
|
|
end
|
|
|
|
subroutine time0(t)
|
|
implicit none
|
|
real*8 t(2)
|
|
integer w,ps
|
|
|
|
call CPU_TIME(t(1))
|
|
call SYSTEM_CLOCK(w,ps)
|
|
t(2)=dble(w)/dble(ps)
|
|
return
|
|
end
|
|
c }}}
|
|
!NP
|
|
************************************************************************
|
|
subroutine dsymv_sp(n,a,x,y)
|
|
************************************************************************
|
|
* y=Ax matrix-vector product, symmetry-packed matrix, lower triangle
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j,ii,nn
|
|
real*8 a((n+1)*n/2),x(n),y(n),tmp1,tmp2,tmp
|
|
c real*8 a(n,n),x(n),y(n)
|
|
C
|
|
y=0.d0
|
|
nn=2*n+2
|
|
do j=1,n
|
|
tmp1=x(j)
|
|
tmp2=0.d0
|
|
ii=(nn-j)*(j-1)/2-j+1
|
|
y(j)=y(j)+tmp1*a(ii+j)
|
|
C$OMP PARALLEL DO Schedule(Static)
|
|
C$OMP& DEFAULT(SHARED)
|
|
C$OMP& PRIVATE(i,tmp)
|
|
C$OMP& REDUCTION(+:tmp2)
|
|
do i=j+1,n
|
|
tmp=a(ii+i)
|
|
y(i)=y(i)+tmp1*tmp
|
|
tmp2=tmp2+tmp*x(i)
|
|
enddo
|
|
C$OMP END PARALLEL DO
|
|
y(j)=y(j)+tmp2
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getenergy(ener,cscr15)
|
|
************************************************************************
|
|
* Get energy from iface file
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer i,j
|
|
real*8 ener
|
|
character(len=8) cscr8
|
|
character(len=15) cscr15
|
|
C
|
|
open(unit=ifcfile,file='iface',status='old')
|
|
i=0
|
|
do
|
|
read(ifcfile,*,end=7597)
|
|
i=i+1
|
|
enddo
|
|
7597 rewind(ifcfile)
|
|
do j=1,i-1
|
|
read(ifcfile,*)
|
|
enddo
|
|
read(ifcfile,7596) cscr8,cscr15,i,i,i,ener
|
|
close(ifcfile)
|
|
7596 format(a8,1x,a15,1x,3(i2,1x),1pe23.15)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
logical function lanycc(calc)
|
|
************************************************************************
|
|
* Check if calc refers to any of the CC or CI methods computed with mrcc
|
|
* as well as ADC(2) and CIS(D_Inf)
|
|
* Warning: MP2, spin scaled MP2 and all RPA variants are left out intentionally!
|
|
************************************************************************
|
|
implicit none
|
|
character*16 calc,xcalc
|
|
character*1 xcalc1(16)
|
|
equivalence(xcalc,xcalc1)
|
|
integer i,ii
|
|
C
|
|
xcalc=calc
|
|
do i=2,15
|
|
ii=ichar(xcalc1(i))
|
|
if(ii.ge.49.and.ii.le.57.and.(xcalc1(i-1).eq.'['.or.
|
|
$xcalc1(i-1).eq.'('.or.xcalc1(i+1).eq.']'.or.xcalc1(i+1).eq.')'.or.
|
|
$xcalc1(i-1).eq.'c'.or.xcalc1(i-1).eq.'n')) xcalc1(i)='n'
|
|
enddo
|
|
do i=2,13
|
|
if(xcalc1(i ).eq.'-'.and.
|
|
$ xcalc1(i+1).eq.'f'.and.
|
|
$ xcalc1(i+2).eq.'1'.and.
|
|
$ xcalc1(i+3).eq.'2') then
|
|
xcalc1(i:i+3)=' '
|
|
if(xcalc1(1).eq.'c'.and.xcalc1(2).eq.'i') then
|
|
write(6,*) 'Explicit correlation is not available for CI!'
|
|
call mrccend(1)
|
|
endif
|
|
exit
|
|
endif
|
|
enddo
|
|
c
|
|
lanycc=
|
|
$ xcalc.eq.'mp3 '.or.
|
|
$ xcalc.eq.'ccs '.or.
|
|
$ xcalc.eq.'ccsd '.or.
|
|
$ xcalc.eq.'ccsdt '.or.
|
|
$ xcalc.eq.'ccsdtq '.or.
|
|
$ xcalc.eq.'ccsdtqp '.or.
|
|
$ xcalc.eq.'cc(n) '.or.
|
|
$ xcalc.eq.'cc(nn) '.or.
|
|
$ xcalc.eq.'ccsd[t] '.or.
|
|
$ xcalc.eq.'ccsdt[q] '.or.
|
|
$ xcalc.eq.'ccsdtq[p] '.or.
|
|
$ xcalc.eq.'cc(n)[n] '.or.
|
|
$ xcalc.eq.'cc(n)[nn] '.or.
|
|
$ xcalc.eq.'cc(nn)[nn] '.or.
|
|
$ xcalc.eq.'ccsd(t) '.or.
|
|
$ xcalc.eq.'ccsdt(q) '.or.
|
|
$ xcalc.eq.'ccsdtq(p) '.or.
|
|
$ xcalc.eq.'cc(n)(n) '.or.
|
|
$ xcalc.eq.'cc(n)(nn) '.or.
|
|
$ xcalc.eq.'cc(nn)(nn) '.or.
|
|
$ xcalc.eq.'ccsd(t)_l '.or.
|
|
$ xcalc.eq.'ccsdt(q)_l '.or.
|
|
$ xcalc.eq.'ccsdtq(p)_l '.or.
|
|
$ xcalc.eq.'cc(n)(n)_l '.or.
|
|
$ xcalc.eq.'cc(n)(nn)_l '.or.
|
|
$ xcalc.eq.'cc(nn)(nn)_l '.or.
|
|
$ xcalc.eq.'ccsdt-1a '.or.
|
|
$ xcalc.eq.'ccsdtq-1a '.or.
|
|
$ xcalc.eq.'ccsdtqp-1a '.or.
|
|
$ xcalc.eq.'cc(n)-1a '.or.
|
|
$ xcalc.eq.'cc(nn)-1a '.or.
|
|
$ xcalc.eq.'ccsdt-1b '.or.
|
|
$ xcalc.eq.'ccsdtq-1b '.or.
|
|
$ xcalc.eq.'ccsdtqp-1b '.or.
|
|
$ xcalc.eq.'cc(n)-1b '.or.
|
|
$ xcalc.eq.'cc(nn)-1b '.or.
|
|
$ xcalc.eq.'ccn '.or.
|
|
$ xcalc.eq.'ccnn '.or.
|
|
$ xcalc.eq.'ccsdt-3 '.or.
|
|
$ xcalc.eq.'ccsdtq-3 '.or.
|
|
$ xcalc.eq.'ccsdtqp-3 '.or.
|
|
$ xcalc.eq.'cc(n)-3 '.or.
|
|
$ xcalc.eq.'cc(nn)-3 '.or.
|
|
$ xcalc.eq.'ccsdt[q]/a '.or.
|
|
$ xcalc.eq.'ccsdtq[p]/a '.or.
|
|
$ xcalc.eq.'cc(n)[n]/a '.or.
|
|
$ xcalc.eq.'cc(n)[nn]/a '.or.
|
|
$ xcalc.eq.'cc(nn)[nn]/a '.or.
|
|
$ xcalc.eq.'ccsdt[q]/b '.or.
|
|
$ xcalc.eq.'ccsdtq[p]/b '.or.
|
|
$ xcalc.eq.'cc(n)[n]/b '.or.
|
|
$ xcalc.eq.'cc(n)[nn]/b '.or.
|
|
$ xcalc.eq.'cc(nn)[nn]/b '.or.
|
|
$ xcalc.eq.'ccsdt(q)/a '.or.
|
|
$ xcalc.eq.'ccsdtq(p)/a '.or.
|
|
$ xcalc.eq.'cc(n)(n)/a '.or.
|
|
$ xcalc.eq.'cc(n)(nn)/a '.or.
|
|
$ xcalc.eq.'cc(nn)(nn)/a '.or.
|
|
$ xcalc.eq.'ccsdt(q)/b '.or.
|
|
$ xcalc.eq.'ccsdtq(p)/b '.or.
|
|
$ xcalc.eq.'cc(n)(n)/b '.or.
|
|
$ xcalc.eq.'cc(n)(nn)/b '.or.
|
|
$ xcalc.eq.'cc(nn)(nn)/b '.or.
|
|
$ xcalc.eq.'cis '.or.
|
|
$ xcalc.eq.'cisd '.or.
|
|
$ xcalc.eq.'cisdt '.or.
|
|
$ xcalc.eq.'cisdtq '.or.
|
|
$ xcalc.eq.'cisdtqp '.or.
|
|
$ xcalc.eq.'fci '.or.
|
|
$ xcalc.eq.'ci(n) '.or.
|
|
$ xcalc.eq.'adc(n) '.or. ! or calc.eq.'adc(2) ' but wrong with xcalc.eq.'adc(2) '
|
|
$ xcalc.eq.'cis(di) '.or.
|
|
$ xcalc.eq.'ci(nn) '
|
|
return
|
|
end
|
|
C
|
|
c {{{ subroutine setenvcalc
|
|
subroutine setenvcalc(envcalc,envcalcfull,minpfile,iout,lrc)
|
|
************************************************************************
|
|
* set calc keyword for the environment
|
|
************************************************************************
|
|
implicit none
|
|
integer clen
|
|
parameter(clen=16)
|
|
character*1 c16_1(clen)
|
|
character*16 envcalc,c16,envcalcfull
|
|
character*32 c32
|
|
character*8 cscr8
|
|
integer minpfile,i,iout
|
|
equivalence(c16,c16_1)
|
|
logical localmp2,lrc,lstartwlno,lstartwl
|
|
c
|
|
open(minpfile,file='MINP')
|
|
call getkeym('corembed',8,cscr8,8)
|
|
read(minpfile,*)
|
|
read(minpfile,*) c16
|
|
close(minpfile)
|
|
call lowercase(c16,c16,clen)
|
|
c32(1:16)=c16
|
|
c32(17:32)=" "
|
|
lrc=.true.
|
|
if (lstartwlno(c32)) then ! for the LNO- synonym
|
|
call removeprefix(c16_1,clen,4)
|
|
elseif (lstartwl(c32)) then ! for the L synonym
|
|
call removeprefix(c16_1,clen,1)
|
|
elseif (trim(c16).eq.'hf') then
|
|
c16='scf '
|
|
lrc=.false.
|
|
elseif (trim(c16).eq.'hf+lrc') then
|
|
c16='scf '
|
|
else
|
|
write(iout,*)'Input error: only local correlation methods and
|
|
$HF or HF+lrc are available as environment models of corembed'
|
|
call mrccend(1)
|
|
endif
|
|
envcalcfull=c16
|
|
localmp2=(envcalcfull.eq.'mp2 '.or.
|
|
$ envcalcfull.eq.'scs-mp2 '.or.
|
|
$ envcalcfull.eq.'sos-mp2 ')
|
|
envcalc=envcalcfull
|
|
if (localmp2) envcalc='mp2 '
|
|
c
|
|
return
|
|
end
|
|
c }}}
|
|
C
|
|
c {{{ function setccprog
|
|
character*4 function setccprog(envcalc)
|
|
************************************************************************
|
|
* set ccprog keyword for the environment
|
|
************************************************************************
|
|
implicit none
|
|
character*16 envcalc
|
|
logical domrcc,lanycc
|
|
c
|
|
domrcc=.true.
|
|
if (envcalc.eq.'ccsd '.or.
|
|
$ envcalc.eq.'ccsd(t) ') then
|
|
setccprog='ccsd'
|
|
domrcc=.false.
|
|
endif
|
|
if (lanycc(envcalc).and.domrcc) then
|
|
setccprog='mrcc'
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
c }}}
|
|
C
|
|
************************************************************************
|
|
real*8 function expval(o,d,n)
|
|
************************************************************************
|
|
* Calculate the expectation value of a one-electron operator
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 o(n,n),d(n,n),ss
|
|
C
|
|
ss=0.d0
|
|
C$OMP PARALLEL DO Schedule(Dynamic)
|
|
C$OMP& DEFAULT(SHARED)
|
|
C$OMP& PRIVATE(j)
|
|
C$OMP& REDUCTION(+:ss)
|
|
do j=1,n
|
|
ss=ss+o(j,j)*d(j,j)+2.d0*dot_product(o(j+1:n,j),d(j+1:n,j))
|
|
enddo
|
|
C$OMP END PARALLEL DO
|
|
expval=ss
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine getgrfile(grfile,atsymbol,basname,charge,ich,natoms,
|
|
$scfiguess)
|
|
************************************************************************
|
|
* Construct the name of grfile
|
|
************************************************************************
|
|
implicit none
|
|
integer charge,ich,natoms,i
|
|
character*1 bname1(20)
|
|
character*2 ch2,atsymbol
|
|
character*7 scfiguess
|
|
character*16 cscr16
|
|
character*20 basname,bname
|
|
character*40 grfile,c40
|
|
equivalence(bname,bname1)
|
|
C
|
|
if(mod(charge,natoms).eq.0) then
|
|
ich=charge/natoms
|
|
else
|
|
ich=0
|
|
endif
|
|
write(c40,'(i5)') ich
|
|
bname=basname
|
|
do i=1,20
|
|
if(bname1(i).eq.'('.or.bname1(i).eq.')') bname1(i)='-'
|
|
if(bname1(i).eq.'*') bname1(i)='x'
|
|
enddo
|
|
if(scfiguess.eq.'gfnrest') then
|
|
grfile='SCFCOREDENSITIES.' // trim(adjustl(atsymbol)) //
|
|
$'.'// trim(adjustl(bname)) // '.' // trim(adjustl(c40))
|
|
else !if(scfiguess.eq.'sad') then
|
|
grfile='SCFDENSITIES.' // trim(adjustl(atsymbol)) //
|
|
$'.'// trim(adjustl(bname)) // '.' // trim(adjustl(c40))
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
#if defined (LIBXC)
|
|
************************************************************************
|
|
subroutine libxcconv(dft)
|
|
************************************************************************
|
|
* Convert mrcc functional name to Libxc identifier
|
|
************************************************************************
|
|
implicit none
|
|
character(len=32) dft
|
|
C
|
|
select case(trim(dft))
|
|
C LDA
|
|
case('pz')
|
|
dft='LDA_C_PZ'
|
|
case('vwn1')
|
|
dft='LDA_C_VWN_1'
|
|
case('vwn2')
|
|
dft='LDA_C_VWN_2'
|
|
case('vwn3')
|
|
dft='LDA_C_VWN_RPA'
|
|
case('vwn4')
|
|
dft='LDA_C_VWN_4'
|
|
C GGA
|
|
case('g96')
|
|
dft='GGA_X_G96'
|
|
case('mpw91x')
|
|
dft='GGA_X_MPW91'
|
|
case('pbeh')
|
|
dft='GGA_X_WPBEH'
|
|
c case('vv10')
|
|
c dft='GGA_XC_VV10'
|
|
case('mpwlyp1w')
|
|
dft='GGA_XC_MPWLYP1W'
|
|
case('xlyp')
|
|
dft='GGA_XC_XLYP'
|
|
C Hybrid GGA
|
|
case('x3lyp')
|
|
dft='HYB_GGA_XC_X3LYP'
|
|
case('b1lyp')
|
|
dft='HYB_GGA_XC_B1LYP'
|
|
case('o3lyp')
|
|
dft='HYB_GGA_XC_O3LYP'
|
|
C Meta-GGA
|
|
case('b95')
|
|
dft='MGGA_C_BC95'
|
|
case('revtpssx')
|
|
dft='MGGA_X_REVTPSS'
|
|
case('revtpssc')
|
|
dft='MGGA_C_REVTPSS'
|
|
case('tpssx')
|
|
dft='MGGA_X_TPSS'
|
|
case('tpssc')
|
|
dft='MGGA_C_TPSS'
|
|
case('scanx')
|
|
dft='MGGA_X_SCAN'
|
|
case('scanc')
|
|
dft='MGGA_C_SCAN'
|
|
case('revscanc')
|
|
dft='MGGA_C_REVSCAN'
|
|
C Hybrid meta-GGA
|
|
case('tpssh')
|
|
dft='HYB_MGGA_XC_TPSSH'
|
|
case('revtpssh')
|
|
dft='HYB_MGGA_XC_REVTPSSH'
|
|
case('mpw1b95')
|
|
dft='HYB_MGGA_XC_MPW1B95'
|
|
case('pw6b95')
|
|
dft='HYB_MGGA_XC_PW6B95'
|
|
end select
|
|
call lowercase(dft,dft,32)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
#endif
|
|
************************************************************************
|
|
subroutine dmatmul(transa,transb,m,n,k,alpha,a,lda,b,ldb,beta,c,
|
|
$ldc,choice,nthread)
|
|
************************************************************************
|
|
* real*8 matrix multiplication with intrinsic matmul or dgemm
|
|
* see Lapack dgemm for the explanation of variables
|
|
* beta.ne.0.d0 is not implemented for matmul
|
|
************************************************************************
|
|
implicit none
|
|
character*6 choice,finalc
|
|
character*1 transa,transb
|
|
integer m,n,k,lda,ldb,ldc,stacksize,nthread
|
|
parameter (stacksize=6*10**5)
|
|
real*8 alpha,beta,a(lda,*),b(ldb,*),c(ldc,*)
|
|
c real*8 alpha,beta,a(m,k),b(k,n),c(m,n)
|
|
c
|
|
finalc='matmul'
|
|
if (choice.eq.'auto '.or.choice.eq.'matmul') then
|
|
c stack owerflow occurs with ifort + matmul for large matrices
|
|
if ((m*k+n*k+m*n)*nthread.gt.stacksize.or.beta.ne.0.d0)
|
|
$ finalc='dgemm '
|
|
endif
|
|
c
|
|
if (choice.eq.'dgemm '.or.finalc.eq.'dgemm ') then
|
|
call dgemm(transa,transb,m,n,k,alpha,a,lda,b,ldb,beta,c,ldc)
|
|
else
|
|
if (transa.eq.'n'.and.transb.eq.'n') then
|
|
c(1:m,1:n)=alpha*matmul(a(1:m,1:k),b(1:k,1:n))
|
|
elseif (transa.eq.'t'.and.transb.eq.'n') then
|
|
c(1:m,1:n)=alpha*matmul(transpose(a(1:k,1:m)),b(1:k,1:n))
|
|
elseif (transa.eq.'n'.and.transb.eq.'t') then
|
|
c(1:m,1:n)=alpha*matmul(a(1:m,1:k),transpose(b(1:n,1:k)))
|
|
elseif (transa.eq.'t'.and.transb.eq.'t') then
|
|
c(1:m,1:n)=alpha*
|
|
$ matmul(transpose(a(1:k,1:m)),transpose(b(1:n,1:k)))
|
|
endif
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine symmat(a,n)
|
|
************************************************************************
|
|
* Symmetrize nxn matrix a
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 a(n,n),tmp
|
|
C
|
|
do i=1,n
|
|
do j=1,i-1
|
|
tmp=0.5d0*(a(i,j)+a(j,i))
|
|
a(i,j)=tmp
|
|
a(j,i)=tmp
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine symmat2(a,n)
|
|
************************************************************************
|
|
* Symmetrize nxn matrix a without the 0.5 factor
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 a(n,n),tmp
|
|
C
|
|
do i=1,n
|
|
do j=1,i
|
|
tmp=a(i,j)+a(j,i)
|
|
a(i,j)=tmp
|
|
a(j,i)=tmp
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine gtrmat(trmat,nispher,nicontr,nicart,niprim,nprimmax,
|
|
$ncontrmax,gcoef,ctostr)
|
|
************************************************************************
|
|
* Genarate Cartesian-primitive -> spherical-contracted transformation
|
|
************************************************************************
|
|
implicit none
|
|
integer nispher,nicontr,nicart,niprim,nprimmax,ncontrmax
|
|
integer ispher,icontr,icart,iprim,ii
|
|
real*8 gcoef(nprimmax,ncontrmax)
|
|
real*8 ctostr(nispher,nicart)
|
|
real*8 trmat(nispher*nicontr*nicart*niprim)
|
|
C
|
|
ii=0
|
|
do iprim=1,niprim
|
|
do icart=1,nicart
|
|
do icontr=1,nicontr
|
|
do ispher=1,nispher
|
|
ii=ii+1
|
|
trmat(ii)=ctostr(ispher,icart)*gcoef(iprim,icontr)
|
|
enddo
|
|
enddo
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
character*1 function angsym(l)
|
|
************************************************************************
|
|
* Genarate symbol for azimuthal quantum number
|
|
************************************************************************
|
|
implicit none
|
|
integer l
|
|
C
|
|
if(l.eq.0) then
|
|
angsym='s'
|
|
else if(l.eq.1) then
|
|
angsym='p'
|
|
else if(l.eq.2) then
|
|
angsym='d'
|
|
else if(l.eq.3) then
|
|
angsym='f'
|
|
else if(l.eq.4) then
|
|
angsym='g'
|
|
else if(l.eq.5) then
|
|
angsym='h'
|
|
else if(l.eq.6) then
|
|
angsym='i'
|
|
else
|
|
angsym=char(l+100)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
c
|
|
************************************************************************
|
|
subroutine moldenloc(mocoeffull,eo,ev,eob,evb,perm,nbasis,
|
|
$ moldenfile,nbf,no,nv,nob,nvb,eigenvalue,scrfile1,oslcc)
|
|
************************************************************************
|
|
* Print (strictly) local MO's (e.g. in an extended domain) or NO's in cis.f
|
|
************************************************************************
|
|
C
|
|
implicit none
|
|
C
|
|
integer nbasis,i,j,ii,jj,nn,perm(nbf),mocoeffile,moldenfile,nbf
|
|
integer no,nv,nob,nvb,scrfile1
|
|
real*8 eigenvalue(nbasis),eo(no),ev(nv),eob(nob),evb(nvb)
|
|
real*8 mocoeffull(nbf,nbasis)
|
|
character*4 mark
|
|
character*15 cscr
|
|
logical oslcc
|
|
C
|
|
do i=1,no
|
|
eigenvalue(i)=eo(i)
|
|
enddo
|
|
do i=1,nv
|
|
eigenvalue(no+i)=ev(i)
|
|
enddo
|
|
if (oslcc) then
|
|
do i=1,nob
|
|
eigenvalue(no+nv+i) = eob(i)
|
|
enddo
|
|
do i=1,nvb
|
|
eigenvalue(no+nv+nob+i) = evb(i)
|
|
enddo
|
|
endif
|
|
C Write MO coefficients to moldenfile
|
|
rewind(moldenfile)
|
|
read(moldenfile,"(a15,1000000i6)") cscr,(perm(i),i=1,nbf)
|
|
|
|
open(scrfile1,file='MOLDEN.perm')
|
|
read(scrfile1,*,err=101) perm(1:nbf)
|
|
101 continue
|
|
close(scrfile1)
|
|
mark='aaaa'
|
|
do while (mark.ne.'[MO]')
|
|
read(moldenfile,"(4a)")mark
|
|
enddo
|
|
do i=1,no+nv
|
|
write(moldenfile,"(' Ene=',f14.4)") min(eigenvalue(i),1.d7)
|
|
write(moldenfile,"(12a)") ' Spin= Alpha'
|
|
if(i.le.no.and..not.oslcc) then
|
|
write(moldenfile,"(' Occup=',f14.4)") 2.d0
|
|
elseif ((i.le.no.and.oslcc)) then
|
|
write(moldenfile,"(' Occup=',f14.4)") 1.d0
|
|
elseif (i.gt.no) then
|
|
write(moldenfile,"(' Occup=',f14.4)") 0.d0
|
|
endif
|
|
do j=1,nbf
|
|
write(moldenfile,"(i4,f18.10)") j,mocoeffull(perm(j),i)
|
|
enddo
|
|
enddo
|
|
if (oslcc) then
|
|
do i=1,nob+nvb
|
|
write(moldenfile,"(' Ene=',f14.4)")
|
|
$ min(eigenvalue(no+nv+i),1.d7)
|
|
write(moldenfile,"(11a)") ' Spin= Beta'
|
|
if(i.le.nob) then
|
|
write(moldenfile,"(' Occup=',f14.4)") 1.d0
|
|
else
|
|
write(moldenfile,"(' Occup=',f14.4)") 0.d0
|
|
endif
|
|
do j=1,nbf
|
|
write(moldenfile,"(i4,f18.10)") j,mocoeffull(perm(j),no+nv+i)
|
|
enddo
|
|
enddo
|
|
endif !oslcc
|
|
C
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine moldeninp(natoms,nangmax,ncontrmax,nprimmax,atsymbol,
|
|
$nang,ncontr,nprim,gexp,gcoef,coord,atnum,cartg,molperm)
|
|
************************************************************************
|
|
* Write MOLDEN input file: coordinates and AO basis info
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer natoms,nangmax,ncontrmax,nprimmax,atnum(*),iatoms,j,icontr
|
|
character*2 atsymbol(natoms)
|
|
integer nang(natoms),ncontr(0:nangmax,natoms),iang,iprim
|
|
integer nprim(0:nangmax,natoms),molperm(*),i,k,l,m,icart,ii,ibasis
|
|
real*8 gexp(nprimmax,0:nangmax,natoms),coord(3,natoms)
|
|
real*8 gcoef(nprimmax,ncontrmax,0:nangmax,natoms)
|
|
character*1 angsym
|
|
character*10 cscr
|
|
logical cartg
|
|
C Write COORD.xyz file
|
|
open(moldenfile,file='COORD.xyz')
|
|
m=0
|
|
do iatoms=1,natoms
|
|
if(atnum(iatoms).gt.0) m=m+1
|
|
enddo
|
|
write(cscr,"(i10)") m
|
|
write(moldenfile,"(a10)") adjustl(cscr)
|
|
write(moldenfile,*)
|
|
do iatoms=1,natoms
|
|
if(atnum(iatoms).gt.0) write(moldenfile,"(a2,3f20.10)")
|
|
$adjustl(atsymbol(iatoms)),(angtobohr*coord(j,iatoms),j=1,3)
|
|
enddo
|
|
write(moldenfile,*)
|
|
close(moldenfile)
|
|
C MOLDEN convention
|
|
C 5D: D 0, D+1, D-1, D+2, D-2
|
|
C 6D: xx, yy, zz, xy, xz, yz
|
|
|
|
C 7F: F 0, F+1, F-1, F+2, F-2, F+3, F-3
|
|
C 10F: xxx, yyy, zzz, xyy, xxy, xxz, xzz, yzz, yyz, xyz
|
|
|
|
C 9G: G 0, G+1, G-1, G+2, G-2, G+3, G-3, G+4, G-4
|
|
C 15G: xxxx yyyy zzzz xxxy xxxz yyyx yyyz zzzx zzzy,
|
|
C xxyy xxzz yyzz xxyz yyxz zzxy
|
|
C Generate permutation vector to follow the above convention
|
|
ibasis=0
|
|
ii=0
|
|
do iatoms=1,natoms
|
|
do iang=0,nang(iatoms)
|
|
do icontr=1,ncontr(iang,iatoms)
|
|
icart=0
|
|
if(cartg) then
|
|
do i=0,iang
|
|
do k=0,iang-i
|
|
m=iang-i-k
|
|
icart=icart+1
|
|
ibasis=ibasis+1
|
|
molperm(ibasis)=ibasis
|
|
enddo
|
|
enddo
|
|
k=ibasis-icart
|
|
if(iang.eq.1) then !p functions z,y,x -> x,y,z
|
|
molperm(k+1)=k+3
|
|
molperm(k+2)=k+2
|
|
molperm(k+3)=k+1
|
|
else if(iang.eq.2) then
|
|
molperm(k+1)=k+6
|
|
molperm(k+2)=k+3
|
|
molperm(k+3)=k+1
|
|
molperm(k+4)=k+5
|
|
molperm(k+5)=k+4
|
|
molperm(k+6)=k+2
|
|
else if(iang.eq.3) then
|
|
molperm(k+1)=k+10
|
|
molperm(k+2)=k+4
|
|
molperm(k+3)=k+1
|
|
molperm(k+4)=k+7
|
|
molperm(k+5)=k+9
|
|
molperm(k+6)=k+8
|
|
molperm(k+7)=k+5
|
|
molperm(k+8)=k+2
|
|
molperm(k+9)=k+3
|
|
molperm(k+10)=k+6
|
|
else if(iang.eq.4) then
|
|
molperm(k+1)=k+15
|
|
molperm(k+2)=k+5
|
|
molperm(k+3)=k+1
|
|
molperm(k+4)=k+14
|
|
molperm(k+5)=k+13
|
|
molperm(k+6)=k+9
|
|
molperm(k+7)=k+4
|
|
molperm(k+8)=k+6
|
|
molperm(k+9)=k+2
|
|
molperm(k+10)=k+12
|
|
molperm(k+11)=k+10
|
|
molperm(k+12)=k+3
|
|
molperm(k+13)=k+11
|
|
molperm(k+14)=k+8
|
|
molperm(k+15)=k+7
|
|
endif
|
|
else
|
|
do l=-iang,iang
|
|
ibasis=ibasis+1
|
|
molperm(ibasis)=ibasis
|
|
enddo
|
|
if(iang.eq.1) then
|
|
k=molperm(ibasis)
|
|
molperm(ibasis)=molperm(ibasis-2)
|
|
molperm(ibasis-2)=k
|
|
else if(iang.ge.2) then
|
|
k=ibasis-2*iang
|
|
molperm(k)=ibasis-iang
|
|
do l=1,iang
|
|
k=k+1
|
|
molperm(k)=ibasis-iang+l
|
|
k=k+1
|
|
molperm(k)=ibasis-iang-l
|
|
enddo
|
|
endif
|
|
endif
|
|
enddo
|
|
enddo !iang
|
|
enddo !iatoms
|
|
C Write MOLDEN file
|
|
open(moldenfile,file='MOLDEN.perm')
|
|
write(moldenfile,'(100000i7)') (molperm(j),j=1,nbasis)
|
|
close(moldenfile)
|
|
open(moldenfile,file='MOLDEN')
|
|
write(moldenfile,"('[Molden Format]')")
|
|
write(moldenfile,"('[ATOMS] AU')")
|
|
do iatoms=1,natoms
|
|
write(moldenfile,"(a3,2i5,3f20.10)")
|
|
$atsymbol(iatoms),iatoms,atnum(iatoms),(coord(j,iatoms),j=1,3)
|
|
enddo
|
|
write(moldenfile,"('[GTO]')")
|
|
do iatoms=1,natoms
|
|
write(moldenfile,"(2i4,i2)") iatoms,0
|
|
do iang=0,nang(iatoms)
|
|
do icontr=1,ncontr(iang,iatoms)
|
|
write(moldenfile,"(a2,i5,f5.2)") angsym(iang)
|
|
$,nprim(iang,iatoms),1.d0
|
|
do iprim=1,nprim(iang,iatoms)
|
|
write(moldenfile,"(2d18.10)")
|
|
$gexp(iprim,iang,iatoms),gcoef(iprim,icontr,iang,iatoms)
|
|
enddo
|
|
enddo
|
|
enddo
|
|
write(moldenfile,*)
|
|
enddo
|
|
if(.not.cartg) then
|
|
write(moldenfile,"('[5D]')")
|
|
write(moldenfile,"('[7F]')")
|
|
write(moldenfile,"('[9G]')")
|
|
endif
|
|
write(moldenfile,"('[MO]')")
|
|
close(moldenfile)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine embedat(natoms,minpfile,ind,iout,kywd,nkywd)
|
|
************************************************************************
|
|
* Read atoms of embedded subsystem
|
|
************************************************************************
|
|
implicit none
|
|
integer natoms,m,n,minpfile,iout,i,ii,jj,ind(natoms),nkywd,nn
|
|
character*1 line2(16),line3(max(512,6*natoms))
|
|
character*8 embed,kywd
|
|
character*16 line1
|
|
equivalence(line1,line2)
|
|
C Read atoms of embedded subsystem
|
|
call getkeym(kywd,nkywd,embed,8)
|
|
nn=1
|
|
if(trim(kywd).eq.'cvs') then
|
|
backspace(minpfile)
|
|
nn=nkywd+2
|
|
endif
|
|
n=0
|
|
line3=' '
|
|
do
|
|
n=n+1
|
|
read(minpfile,'(a)',advance='no',eor=1234,end=1234) line3(n)
|
|
enddo
|
|
1234 continue
|
|
n=nn
|
|
ind=0
|
|
do while(line3(n).ne.' ')
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.'-'
|
|
$.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) ii
|
|
jj=ii
|
|
if(line3(n).eq.'-') then
|
|
n=n+1
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) jj
|
|
endif
|
|
if(jj.gt.natoms) then
|
|
write(iout,*) 'Invalid serial number for '//trim(kywd)//'!'
|
|
call mrccend(1)
|
|
endif
|
|
ind(ii:jj)=1
|
|
n=n+1
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine readlinelist(nquant,minpfile,ind,iout,quant)
|
|
************************************************************************
|
|
* Read quantities list from a line
|
|
************************************************************************
|
|
implicit none
|
|
! intent(in)
|
|
integer, intent(in) :: nquant
|
|
integer, intent(in) :: minpfile
|
|
integer, intent(in) :: iout
|
|
integer, intent(out) :: ind(nquant)
|
|
! local
|
|
character(len=max(512,6*nquant)) :: line
|
|
character(len=1) :: line2(16)
|
|
character(len=8) :: quant
|
|
character(len=16) :: line1
|
|
integer :: istat
|
|
integer :: i,ii,jj,m,n,kk
|
|
integer :: iquant
|
|
equivalence(line1,line2)
|
|
iquant=0
|
|
n=0
|
|
line=''
|
|
read(minpfile,'(a)',iostat=istat) line
|
|
n=1
|
|
ind=0
|
|
do while(line(n:n).ne.' ')
|
|
m=n
|
|
do while(line(n:n).ne.','.and.line(n:n).ne.'-'
|
|
$.and.line(n:n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line(i:i)
|
|
enddo
|
|
read(line1,*) ii
|
|
if(quant.eq.'mmserial') then
|
|
iquant=iquant+1
|
|
ind(iquant)=ii
|
|
endif
|
|
jj=ii
|
|
if(line(n:n).eq.'-') then
|
|
n=n+1
|
|
m=n
|
|
do while(line(n:n).ne.','.and.line(n:n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line(i:i)
|
|
enddo
|
|
read(line1,*) jj
|
|
endif
|
|
if(jj.gt.nquant.and.quant.ne.'mmserial') then
|
|
if(quant.eq.'atoms ') then
|
|
write(iout,*) 'Invalid serial number for atoms!'
|
|
else if(quant.eq.'mos ') then
|
|
write(iout,*) 'Invalid serial number for MOs!'
|
|
endif
|
|
call mrccend(1)
|
|
endif
|
|
if(quant.ne.'mmserial') then
|
|
ind(ii:jj)=1
|
|
else
|
|
do kk=ii+1,jj
|
|
iquant=iquant+1
|
|
ind(iquant)=kk
|
|
enddo
|
|
endif
|
|
n=n+1
|
|
enddo
|
|
if(istat.ne.0) then
|
|
write(iout,'(a)') 'Cannot read a list of '//trim(adjustl(quant))
|
|
$//' from MINP file.'
|
|
write(iout,'(a)')
|
|
$' The error is detected @ readlinelist (combin.f)'
|
|
call mrccend(1)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
logical function quadratic(a,b,c,r1,r2)
|
|
************************************************************************
|
|
* Calculate the roots of a general quadratic equation
|
|
************************************************************************
|
|
implicit none
|
|
real*8 a,b,c,r1,r2,disc
|
|
C
|
|
disc=b*b-4.d0*a*c
|
|
if(disc.lt.0.d0) then
|
|
quadratic=.false.
|
|
else
|
|
quadratic=.true.
|
|
disc=dsqrt(disc)
|
|
r1=(-b+disc)/(2.d0*a)
|
|
r2=(-b-disc)/(2.d0*a)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine prtenergc(meth,ene,erefc,locnoc)
|
|
************************************************************************
|
|
* Print energies *
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
real*8 ene,erefc
|
|
integer locnoc
|
|
character*15 beg
|
|
character*(*) meth
|
|
C
|
|
call timer
|
|
#if defined(MPI)
|
|
if(.not.master_thread .and. locnoc.eq.0) return ! need to print it if lccoporder=lccfirst & MPI
|
|
#endif
|
|
c if(log1) then
|
|
c beg=' Total ' // meth
|
|
c end=' energy [au]:'
|
|
c call trimloc(beg,end)
|
|
c write(iout,"(a31,f22.12)") beg,ene
|
|
c endif
|
|
beg=' '
|
|
beg=meth
|
|
if(locnoc.gt.0) then
|
|
write(ifcfile,7596)
|
|
$'ENERGY ','REF ',1,1,1,erefc,0.d0,0.d0
|
|
write(ifcfile,7596)
|
|
$'ENERGY ',beg,1,1,1,ene,tim-timold,wct-wctold
|
|
else if(trim(beg).eq.'CCSD(T)') then
|
|
write(ifcfile,7596)
|
|
$'ENERGY ',beg,1,1,1,ene+erefc,tim-timold,wct-wctold
|
|
else
|
|
write(ifcfile,7596)
|
|
$'ENERGY ',beg,1,1,1,ene,tim-timold,wct-wctold
|
|
endif
|
|
timold=tim
|
|
wctold=wct
|
|
7596 format(a8,1x,a15,1x,3(i2,1x),1pe23.15,2(1pe15.8))
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine genprojmx(dens,cmo,nb,nmo,ss,tol,scmo,smo,redunant,scr,
|
|
$mode)
|
|
************************************************************************
|
|
* construct the mx projecting onto a possibly overlapping cmo basis
|
|
* if redundant, linear dependency of the cmo basis is removed via discarding
|
|
* S_cmo eigenvectors with lower than tol scmo eigenvalues
|
|
* mode=1 make full projector mx
|
|
* mode=2 make only the invrese of the cmo overlap mx
|
|
* mode=3 make the inverse of the input overlap mx (provided in smo)
|
|
************************************************************************
|
|
implicit none
|
|
integer nb,nmo,mode
|
|
real*8 dens(nb,nb),cmo(nb,nmo),ss(nb,nb),tol
|
|
real*8 scmo(nb,nmo),smo(nmo,nmo),scr(*)
|
|
logical redunant
|
|
c internal
|
|
integer iisyev,nred,j,i
|
|
integer*4 isyev
|
|
equivalence(isyev,iisyev) !For Intel
|
|
C
|
|
if (mode.eq.1.or.mode.eq.2) then
|
|
c overlap mx of the cmo basis goes to Smo
|
|
call dsymm('l','l',nb,nmo,1.d0,ss,nb,cmo,nb,0.d0,scmo,nb)
|
|
call dgemm('t','n',nmo,nmo,nb,1.d0,cmo,nb,scmo,nb,0.d0,
|
|
$smo,nmo)
|
|
endif
|
|
c invert Smo
|
|
if (redunant) then
|
|
call dsyev('V','U',nmo,smo,nmo,scr,scr(1+nmo),20*nmo,isyev)
|
|
if(isyev.ne.0) then
|
|
write(*,*) 'Error at inversion in genprojmx'
|
|
call mrccend(1)
|
|
endif
|
|
nred=0
|
|
c write(*,*) 'S_paop eigvals'
|
|
c write(*,'(10000es14.6)') scr(1:nmo)
|
|
do while(scr(nred+1).lt.tol)
|
|
nred=nred+1
|
|
c write(*,*) 'drop redundant cmo',nred,scr(nred)
|
|
if (scr(nred+1).lt.-tol) then
|
|
write(*,*) 'warning <0 S_mo eigval',nred,scr(nred)
|
|
endif
|
|
enddo
|
|
c if (nred.gt.0)
|
|
c $ write(*,*) 'drop',nred,'redundant cmo in genprojmx',scr(nred)
|
|
do j=nred+1,nmo
|
|
call dscal(nmo,1.d0/dsqrt(scr(j)),smo(1,j),1)
|
|
enddo
|
|
call dsyrk('u','n',nmo,nmo-nred,1.d0,smo(1,nred+1),nmo,0.d0,
|
|
$scr,nmo)
|
|
call dcopy(nmo**2,scr,1,smo,1)
|
|
call filllo(smo,nmo)
|
|
else
|
|
call syminvpd(smo,nmo,nmo)
|
|
call fillup(smo,nmo)
|
|
endif
|
|
if (mode.eq.1) then
|
|
c return the mx of the projector: cmo*Smo^-1*cmo^T
|
|
call dsymm('r','u',nb,nmo,1.d0,smo,nmo,cmo,nb,0.d0,scmo,nb)
|
|
call dgemm('n','t',nb,nb,nmo,1.d0,scmo,nb,cmo,nb,0.d0,dens,nb)
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
c
|
|
************************************************************************
|
|
subroutine normalize(nb,nmo,cmo,scmo,ss,havescmo,norm,
|
|
& normalize_scmo)
|
|
************************************************************************
|
|
* Normalize the input orbitals in cmo, scmo=overlap*cmo, ss: overlap mx of the basis functions
|
|
************************************************************************
|
|
implicit none
|
|
integer nb,nmo,i
|
|
real*8 cmo(nb,nmo),ss(nb,nb)
|
|
real*8 scmo(nb,nmo),tmp,ddot,norm
|
|
logical havescmo,normalize_scmo
|
|
c
|
|
if (.not.havescmo) then
|
|
call dsymm('l','l',nb,nmo,1.d0,ss,nb,cmo,nb,0.d0,scmo,nb)
|
|
endif
|
|
c
|
|
do i=1,nmo
|
|
tmp=ddot(nb,cmo(1,i),1,scmo(1,i),1)
|
|
tmp=dsqrt(norm/tmp)
|
|
call dscal(nb,tmp,cmo(1,i),1)
|
|
if (normalize_scmo) call dscal(nb,tmp,scmo(1,i),1)
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
c
|
|
subroutine canonicalize(nb,nmo,fmat,cmo,pscan,scr,ev)
|
|
************************************************************************
|
|
* Create pseudo canonical orbitals of the subspace spanned by the input orbitals in cmo
|
|
* fmat: Fock mx
|
|
************************************************************************
|
|
implicit none
|
|
integer nb,nmo,i,iisyev,j
|
|
real*8 cmo(nb,nmo),fmat(nb,nb),ev(nmo),pscan(nmo,nmo),scr(*)
|
|
integer*4 isyev
|
|
equivalence(isyev,iisyev) !For Intel
|
|
c
|
|
c Fock mx of the cmo basis
|
|
call dsymm('l','l',nb,nmo,1.d0,fmat,nb,cmo,nb,0.d0,scr,nb)
|
|
call dgemm('t','n',nmo,nmo,nb,1.d0,cmo,nb,scr,nb,0.d0,pscan,nmo)
|
|
c
|
|
call dsyev('V','U',nmo,pscan,nmo,ev,scr,20*nmo,isyev)
|
|
if(isyev.ne.0) then
|
|
write(*,*) 'Error in subroutine canonicalize'
|
|
call mrccend(1)
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
c
|
|
subroutine lwdncanOG(nb,nmo,ss,cmo,scmo,scr,tol,havescmo,lindep,ev
|
|
$,smo,ndrop,overwrite,havesmo,ogcmo)
|
|
************************************************************************
|
|
* Orthogonalize and remove linearly dependent cmos, if needed
|
|
* scmo=overlap*cmo, ss: overlap mx of the basis functions
|
|
* if havesmo then the overlap is not computed
|
|
* if havescmo then AO overlap x input mo coeff is not computed
|
|
************************************************************************
|
|
implicit none
|
|
integer nb,nmo,i,iisyev,j,ndrop
|
|
real*8 cmo(nb,nmo),ss(nb,nb),scmo(nb,*),scr(*),ev(nmo),smo(nmo,*)
|
|
real*8 tol,ogcmo(nb,nmo)
|
|
integer*4 isyev
|
|
equivalence(isyev,iisyev) !For Intel
|
|
logical havescmo,lindep,overwrite,havesmo
|
|
c
|
|
if (.not.havesmo) then
|
|
if (.not.havescmo) then
|
|
call dsymm('l','l',nb,nmo,1.d0,ss,nb,cmo,nb,0.d0,scmo,nb)
|
|
endif
|
|
call dgemm('t','n',nmo,nmo,nb,1.d0,cmo,nb,scmo,nb,0.d0,smo,nmo)
|
|
endif
|
|
c write(*,"('norms in lwdncanOG:',10000es14.6)")(smo(j,j),j=1,nmo)
|
|
scr(1)=1.d0
|
|
do j=1,nmo
|
|
if (smo(j,j).lt.scr(1)) scr(1)=smo(j,j)
|
|
if (smo(j,j).lt.1d-4) write(*,*) 'small norm',j,smo(j,j)
|
|
enddo
|
|
c write(*,"('min norm in lwdncanOG:',10es14.6)")scr(1)
|
|
C Remove linearly dependent orbitals and orthogonalize
|
|
call dsyev('V','U',nmo,smo,nmo,ev,scr,20*nmo,isyev)
|
|
if(isyev.ne.0) then
|
|
write(*,*) 'Error in subroutine lwdncanOG'
|
|
call mrccend(1)
|
|
endif
|
|
ndrop=0
|
|
if (lindep) then
|
|
do while(ev(ndrop+1).lt.tol)
|
|
ndrop=ndrop+1
|
|
c write(*,*) 'drop redundant orb', ndrop,ev(ndrop)
|
|
enddo
|
|
endif
|
|
c write(*,"('next S ev in lwdncanOG:',1000es14.6)")
|
|
c $ev(ndrop+1:min(ndrop+10,nmo))
|
|
do j=ndrop+1,nmo
|
|
call dscal(nmo,1.d0/dsqrt(ev(j)),smo(1,j),1)
|
|
enddo
|
|
call dgemm('n','n',nb,nmo-ndrop,nmo,1.d0,cmo,nb,smo(1,ndrop+1),nmo
|
|
$,0.d0,ogcmo,nb)
|
|
if (overwrite) call dcopy(nb*(nmo-ndrop),ogcmo,1,cmo,1)
|
|
c
|
|
return
|
|
end
|
|
c
|
|
c {{{ subroutine dfillzeroup
|
|
subroutine dfillzeroup(a,n)
|
|
************************************************************************
|
|
* Fill up the upper triangle of a matrix with zeros
|
|
************************************************************************
|
|
implicit none
|
|
integer n,i,j
|
|
real*8 a(n,n)
|
|
C
|
|
do i=1,n
|
|
do j=i+1,n
|
|
a(i,j)=0.d0
|
|
enddo
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
c }}}
|
|
c
|
|
c {{{ SUBROUTINE GENTRANS
|
|
SUBROUTINE GENTRANS(A,RD,M,N,MN,B,MOVE,IWRK,IOK)
|
|
C IN-PLACE TRANSFORM OF A(N ARRAY OF) RECTANGULAR OR SQUARE MATRIX(S)
|
|
C INPUT:
|
|
C A IS A MATRIX WITH RD ROW DIMENSION AND MN=M*N COLUMN DIMENSION
|
|
C B IS A BUFFER FOR THE ELEMENT INTERCHANGE WITH RD DIMENSION
|
|
C THE M BY N MATRIX OF A(RD,.) IS TO BE TRANSPOSED FOR EACH RD VALUE
|
|
C MOVE IS A ONE-DIMENSIONAL ARRAY OF LENGTH IWRK
|
|
C VALUE IWRK=(M+N)/2 IS RECOMMENDED.
|
|
C IOK INDICATES THE SUCCESS OR FAILURE OF THE ROUTINE.
|
|
C NORMAL RETURN IOK=0
|
|
C ERRORS IOK=-1, MN NOT EQUAL TO M*N.
|
|
C IOK=-2, IWRK NEGATIVE OR ZERO.
|
|
C IOK.GT.0, (SHOULD NEVER OCCUR). IN THIS CASE
|
|
C WE SET IOK EQUAL TO THE FINAL VALUE OF I WHEN THE SEARCH
|
|
C IS COMPLETED BUT SOME LOOPS HAVE NOT BEEN MOVED.
|
|
C
|
|
C BASED ON THE ALGORITH IN COMM. ACM, VOL. 13, NO. 05, P. 324. AND NETLIB.ORG/TOMS/380
|
|
IMPLICIT NONE
|
|
INTEGER IWRK,MOVE(IWRK),RD,MN,M,N,NCOUNT,M2,I,IB,IA,K,KMI,MAX,I1
|
|
INTEGER I2,IOK,N1,J,J1
|
|
real*8 A(RD,MN),B(RD)
|
|
C CHECK ARGUMENTS AND INITIALISE
|
|
IF(M.LT.2.OR.N.LT.2) GO TO 60
|
|
IF(MN.NE.M*N) GO TO 92
|
|
IF(IWRK.LT.1) GO TO 93
|
|
IF(M.EQ.N) GO TO 70
|
|
NCOUNT=2
|
|
M2=M-2
|
|
DO 10 I=1,IWRK
|
|
10 MOVE(I)=0
|
|
IF(M2.LT.1) GO TO 12
|
|
C COUNT NUMBER,NCOUNT, OF SINGLE POINTS.
|
|
DO 11 IA=1,M2
|
|
IB=IA*(N-1)/(M-1)
|
|
IF(IA*(N-1).NE.IB*(M-1)) GO TO 11
|
|
NCOUNT=NCOUNT+1
|
|
I=IA*N+IB
|
|
IF(I.GT.IWRK) GO TO 11
|
|
MOVE(I)=1
|
|
11 CONTINUE
|
|
C SET INITIAL VALUES FOR SEARCH.
|
|
12 K=MN-1
|
|
KMI=K-1
|
|
MAX=MN
|
|
I=1
|
|
C AT LEAST ONE LOOP MUST BE RE-ARRANGED.
|
|
GO TO 30
|
|
C SEARCH FOR LOOPS TO BE REARRANGED.
|
|
20 MAX=K-I
|
|
I=I+1
|
|
KMI=K-I
|
|
IF(I.GT.MAX) GO TO 90
|
|
IF(I.GT.IWRK) GO TO 21
|
|
IF(MOVE(I).LT.1) GO TO 30
|
|
GO TO 20
|
|
21 IF(I.EQ.M*I-K*(I/N)) GO TO 20
|
|
I1=I
|
|
22 I2=M*I1-K*(I1/N)
|
|
IF(I2.LE.I .OR. I2.GE.MAX) GO TO 23
|
|
I1=I2
|
|
GO TO 22
|
|
23 IF(I2.NE.I) GO TO 20
|
|
C REARRANGE ELEMENTS OF A LOOP.
|
|
30 I1=I
|
|
31 B(1:RD)=A(1:RD,I1+1)
|
|
32 I2=M*I1-K*(I1/N)
|
|
IF(I1.LE.IWRK) MOVE(I1)=2
|
|
33 NCOUNT=NCOUNT+1
|
|
IF(I2.EQ.I .OR. I2.GE.KMI) GO TO 35
|
|
34 A(1:RD,I1+1)=A(1:RD,I2+1)
|
|
I1=I2
|
|
GO TO 32
|
|
35 IF(MAX.EQ.KMI .OR. I2.EQ.I) GO TO 41
|
|
MAX=KMI
|
|
GO TO 34
|
|
C TEST FOR SYMMETRIC PAIR OF LOOPS.
|
|
41 A(1:RD,I1+1)=B(1:RD)
|
|
IF(NCOUNT.GE.MN) GO TO 60
|
|
IF(I2.EQ.MAX .OR. MAX.EQ.KMI) GO TO 20
|
|
MAX=KMI
|
|
I1=MAX
|
|
GO TO 31
|
|
C NORMAL RETURN.
|
|
60 IOK=0
|
|
RETURN
|
|
C IF MATRIX IS SQUARE, EXCHANGE ELEMENTS A(I,J) AND A(J,I).
|
|
70 N1=N-1
|
|
DO 71 I=1,N1
|
|
J1=I+1
|
|
DO 71 J=J1,N
|
|
I1=I+(J-1)*N
|
|
I2=J+(I-1)*M
|
|
B(1:RD)=A(1:RD,I1)
|
|
A(1:RD,I1)=A(1:RD,I2)
|
|
A(1:RD,I2)=B(1:RD)
|
|
71 CONTINUE
|
|
GO TO 60
|
|
C ERROR RETURNS.
|
|
90 IOK=I
|
|
91 RETURN
|
|
92 IOK=-1
|
|
GO TO 91
|
|
93 IOK=-2
|
|
GO TO 91
|
|
END
|
|
c }}}
|
|
c
|
|
c {{{ subroutine relocatemx
|
|
subroutine relocatemx(m1,m2,drow,dcol,backward)
|
|
************************************************************************
|
|
* copy the mx in m1 to m2 in memory elementwise
|
|
* hence m1 and m2 may be overlapping in memory
|
|
************************************************************************
|
|
#if defined (Intel)
|
|
c !DIR$ NOOPTIMIZE
|
|
!DIR$ OPTIMIZE:1
|
|
#endif
|
|
implicit none
|
|
integer i,j,drow,dcol
|
|
real*8 m1(drow,dcol),m2(drow,dcol)
|
|
logical backward
|
|
C
|
|
if (backward) then
|
|
c loc(m1) > loc(m2)
|
|
!$OMP SINGLE
|
|
do i=1,dcol
|
|
do j=1,drow
|
|
m2(j,i)=m1(j,i)
|
|
enddo
|
|
enddo
|
|
!$OMP END SINGLE
|
|
else
|
|
c loc(m1) < loc(m2)
|
|
!$OMP SINGLE
|
|
do i=dcol,1,-1
|
|
do j=drow,1,-1
|
|
m2(j,i)=m1(j,i)
|
|
enddo
|
|
enddo
|
|
!$OMP END SINGLE
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
c }}}
|
|
c
|
|
c {{{ function localcc15p
|
|
logical function localcc15p(localcc)
|
|
************************************************************************
|
|
* T: if localcc >=2015 , F: otherwise
|
|
************************************************************************
|
|
implicit none
|
|
character*4 localcc
|
|
c
|
|
localcc15p=localcc.eq.'2015'.or.localcc.eq.'2016'.or.
|
|
$ localcc.eq.'2018'.or.localcc.eq.'2021'.or.localcc.eq.'2022'
|
|
C
|
|
return
|
|
end
|
|
c }}}
|
|
c
|
|
c {{{ function localccXp
|
|
logical function localccXp(localcc,year)
|
|
************************************************************************
|
|
* T: if localcc >=year , F: otherwise
|
|
************************************************************************
|
|
implicit none
|
|
character*4 localcc
|
|
integer year,localcc2int
|
|
c
|
|
if (localcc.eq.'off ') then
|
|
localccXp=.false.
|
|
elseif (localcc.eq.'on '.or.localcc.eq.' ') then
|
|
write(*,*)'Error: unsupported localcc value in localccXp',localcc
|
|
call mrccend(1)
|
|
else
|
|
read(localcc,*) localcc2int
|
|
localccXp=localcc2int.ge.year
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
c }}}
|
|
c
|
|
c {{{ lstartwl and lstartwlno
|
|
************************************************************************
|
|
logical function lstartwl(calc)
|
|
************************************************************************
|
|
* Check if calc starts with l, true if a local correlation computation is requested
|
|
************************************************************************
|
|
implicit none
|
|
character(len=32) calc,xcalc
|
|
character*1 calc1(32)
|
|
equivalence(xcalc,calc1)
|
|
c
|
|
xcalc=calc
|
|
lstartwl=calc1(1).eq.'l'.and.(calc1(2).ne.'d'.or.calc1(3).ne.'a')
|
|
$ .and.(calc1(2).ne.'c'.or.calc1(3).ne.'-')
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
logical function lstartwlno(calc)
|
|
************************************************************************
|
|
* Check if calc starts with LNO-, true if a local correlation computation is requested
|
|
************************************************************************
|
|
implicit none
|
|
character(len=32) calc,xcalc
|
|
character*1 calc1(32)
|
|
equivalence(xcalc,calc1)
|
|
c
|
|
xcalc=calc
|
|
lstartwlno=calc1(1).eq.'l'.and.calc1(2).eq.'n'.and.calc1(3).eq.'o'
|
|
$.and.calc1(4).eq.'-'
|
|
return
|
|
end
|
|
C }}}
|
|
c
|
|
************************************************************************
|
|
subroutine removeprefix(calc1,clen,nchartoremove)
|
|
************************************************************************
|
|
* remove the first nchartoremove character of calc, e.g. for DF-, RI-, LNO-, L prefixes
|
|
************************************************************************
|
|
implicit none
|
|
integer clen,nchartoremove,i
|
|
character*1 calc1(clen)
|
|
c
|
|
do i=1,clen-nchartoremove
|
|
calc1(i)=calc1(i+nchartoremove)
|
|
enddo
|
|
do i=clen-nchartoremove+1,clen
|
|
calc1(i)=' '
|
|
enddo
|
|
c
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine basislocation(cdmrcc,cdmrcc1)
|
|
************************************************************************
|
|
* determine the folder containing the basis set information
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer*4 istat
|
|
character*512 cdmrcc
|
|
character*1 cdmrcc1(512)
|
|
character*128 command
|
|
integer i
|
|
#if !defined (gfortran) && !defined (G95)
|
|
integer*4 system
|
|
external system
|
|
#endif
|
|
c
|
|
cdmrcc1=' '
|
|
command=trim("which dmrcc > mrccjunk1") // char(0)
|
|
istat=system(command)
|
|
if(istat.eq.0) then
|
|
open(unit=scrfile1,file='mrccjunk1')
|
|
read(scrfile1,'(a512)') cdmrcc
|
|
cdmrcc=adjustl(cdmrcc)
|
|
close(scrfile1,status='delete')
|
|
i=507
|
|
do while(cdmrcc1(i ).ne.'d'.or.
|
|
$ cdmrcc1(i+1).ne.'m'.or.
|
|
$ cdmrcc1(i+2).ne.'r'.or.
|
|
$ cdmrcc1(i+3).ne.'c'.or.
|
|
$ cdmrcc1(i+4).ne.'c')
|
|
i=i-1
|
|
enddo
|
|
cdmrcc1(i )='B'
|
|
cdmrcc1(i+1)='A'
|
|
cdmrcc1(i+2)='S'
|
|
cdmrcc1(i+3)='I'
|
|
cdmrcc1(i+4)='S'
|
|
cdmrcc1(i+5)='/'
|
|
cdmrcc1(i+6:512)=' '
|
|
else
|
|
write(*,*) 'Error in determining PATH of BASIS folder',istat
|
|
write(*,*) ' Warning: assuming ./BASIS'
|
|
cdmrcc1(1)='.'
|
|
cdmrcc1(2)='/'
|
|
i=3
|
|
cdmrcc1(i )='B'
|
|
cdmrcc1(i+1)='A'
|
|
cdmrcc1(i+2)='S'
|
|
cdmrcc1(i+3)='I'
|
|
cdmrcc1(i+4)='S'
|
|
cdmrcc1(i+5)='/'
|
|
cdmrcc1(i+6:512)=' '
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
c
|
|
************************************************************************
|
|
function iname(ch)
|
|
implicit none
|
|
integer iname
|
|
character*4 ch
|
|
if(ch.eq."abcd")iname=0
|
|
if(ch.eq."ijkl")iname=1
|
|
if(ch.eq."abci")iname=2
|
|
if(ch.eq."aijk")iname=3
|
|
if(ch.eq."abij")iname=4
|
|
if(ch.eq."aibj")iname=5
|
|
if(ch.eq."iajk")iname=6
|
|
if(ch.eq."abic")iname=7
|
|
if(ch.eq."aibc")iname=8
|
|
if(ch.eq."iabc")iname=9
|
|
if(ch.eq."ijak")iname=10
|
|
if(ch.eq."ijka")iname=11
|
|
if(ch.eq."iajb")iname=12
|
|
if(ch.eq."aijb")iname=13
|
|
if(ch.eq."ijab")iname=14
|
|
if(ch.eq."iabj")iname=15
|
|
end
|
|
c
|
|
************************************************************************
|
|
subroutine write56(nbmax,iface,ccalc,domain_is_cs,lis_nal,lis_nbe)
|
|
************************************************************************
|
|
* Write fort.56 for ovirt and mrcc
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
c taken from MRCCCOMMON: ncore,op,calc,nocc,rest,dens,conver,isym,diag,
|
|
c iclsh,ihf,ndoub,nsing,ntrip,nacto,nactv,maxex,ptfreq,sacc,dboc,
|
|
c maxmem,maxcor,idnint
|
|
c minpfile,eifile,iout
|
|
integer i,j,k,m,n,ii,jj,iitol,nbmax,occvec(nbmax),iacto,iactv,nco
|
|
integer iocc,lis_nal,lis_nbe,nact,ndoc
|
|
real*8 eps,rr
|
|
character*1 xcalc1(16),chs,line2(16),line3(512)
|
|
character*2 ch2
|
|
character*4 cmult,cctol,symm,localcc,nstate,nnsing,nntrip,ovirt
|
|
character*4 ch4
|
|
character*5 scftype
|
|
character*6 cdiag,core
|
|
character*8 active,refdet,iface,embed
|
|
character*13 rohftype
|
|
character*16 ccalc,xcalc,mem,orblocc,orbloco,orblocv,orbloce,line1
|
|
character*512 line
|
|
logical domain_is_cs
|
|
equivalence(line,line3)
|
|
equivalence(line1,line2)
|
|
equivalence(xcalc,xcalc1)
|
|
C
|
|
call getkey('embed',5,embed,8)
|
|
open(minpfile,file='MINP')
|
|
call getkey('core',4,core,6)
|
|
nco=ncore
|
|
if(core.eq.'corr ') nco=0
|
|
if(core.eq.'corr '.and.embed.eq.'huzinaga') nco=nfroz
|
|
C ex.lev. & calc
|
|
c call getkey('calc',4,ccalc,16)
|
|
op=0
|
|
calc=1
|
|
if(ccalc.eq.'fci ') then
|
|
op=nocc-2*nco
|
|
calc=0
|
|
endif
|
|
xcalc=ccalc
|
|
if(xcalc1(1).eq.'c'.and.xcalc1(2).eq.'i') calc=0
|
|
xcalc1(1)=' '
|
|
xcalc1(2)=' '
|
|
do i=3,15
|
|
if(xcalc1(i).eq.'/') calc=9
|
|
if(xcalc1(i).eq.'_') calc=4
|
|
if(xcalc1(i).eq.'-') then
|
|
if(xcalc1(i+1).eq.'3') calc=8
|
|
if(xcalc1(i+1).eq.'1') then
|
|
if(xcalc1(i+2).eq.'b') then
|
|
calc=6
|
|
else
|
|
calc=5
|
|
endif
|
|
endif
|
|
do j=i,16
|
|
xcalc1(j)=' '
|
|
enddo
|
|
endif
|
|
enddo
|
|
if(xcalc.eq.' s ') op=1
|
|
if(xcalc.eq.' sd ') op=2
|
|
if(xcalc.eq.' sdt ') op=3
|
|
if(xcalc.eq.' sdtq ') op=4
|
|
if(xcalc.eq.' sdtqp ') op=5
|
|
jj=0
|
|
do i=3,16
|
|
ii=ichar(xcalc1(i))
|
|
if((ii.lt.49.or.ii.gt.57).and.xcalc1(i).ne.' ') jj=jj+1
|
|
enddo
|
|
if(jj.eq.0) then
|
|
calc=7
|
|
read(xcalc,*) op
|
|
endif
|
|
if(op.eq.0) then
|
|
if(calc.le.1) then
|
|
do i=3,15
|
|
if(xcalc1(i).eq.')'.and.xcalc1(i+1).eq.'(') calc=3
|
|
if(xcalc1(i).eq.')'.and.xcalc1(i+1).eq.'[') calc=2
|
|
enddo
|
|
endif
|
|
i=16
|
|
do while(xcalc1(i).ne.')'.and.xcalc1(i).ne.']')
|
|
i=i-1
|
|
enddo
|
|
j=i-2
|
|
chs='('
|
|
if(xcalc1(i).eq.']') chs='['
|
|
do while(xcalc1(j).ne.chs)
|
|
j=j-1
|
|
enddo
|
|
do ii=1,j
|
|
xcalc1(ii)=' '
|
|
enddo
|
|
do ii=i,16
|
|
xcalc1(ii)=' '
|
|
enddo
|
|
if(xcalc1(j+1).eq.'d') then
|
|
op=2
|
|
else if(xcalc1(j+1).eq.'t') then
|
|
op=3
|
|
if(calc.le.1) calc=3
|
|
else if(xcalc1(j+1).eq.'q') then
|
|
op=4
|
|
if(calc.le.1) calc=3
|
|
else if(xcalc1(j+1).eq.'p') then
|
|
op=5
|
|
if(calc.le.1) calc=3
|
|
else
|
|
read(xcalc,*) op
|
|
endif
|
|
if(calc.eq.3.and.chs.eq.'[') calc=2
|
|
endif
|
|
if(op.gt.nal+nbe-2*nco) then
|
|
op=nal+nbe-2*nco
|
|
if(calc.gt.1) calc=1
|
|
endif
|
|
C rest & fort.57
|
|
call getkey('rest',4,ch4,4)
|
|
read(ch4,*) rest
|
|
if(rest.ge.3) then
|
|
call getkeym('rest',4,ch4,4)
|
|
read(minpfile,'(512a1)') line3
|
|
open(eifile,file='fort.57',status='unknown')
|
|
rewind(eifile)
|
|
write(eifile,*) trim(line)
|
|
close(eifile)
|
|
else
|
|
open(eifile,file='fort.57',status='unknown')
|
|
close(eifile,status='delete')
|
|
endif
|
|
call getkey('ciguess',7,ch4,4)
|
|
if(ch4.eq.'on ') then
|
|
call getkeym('ciguess',7,ch4,4)
|
|
c call ishell("sed '1,/ciguess/d' MINP |grep -iv [a-z] > fort.57")
|
|
open(eifile,file='fort.57',status='unknown')
|
|
do
|
|
read(minpfile,'(512a1)',end=8599) line3
|
|
if(ichar(line3(1)).lt.48.or.ichar(line3(1)).gt.57) exit
|
|
write(eifile,*) trim(line)
|
|
enddo
|
|
8599 continue
|
|
close(eifile)
|
|
endif
|
|
C dens
|
|
call getkey('dens',4,ch4,4)
|
|
read(ch4,*) dens
|
|
if(mod(dens,2).eq.1) dens=dens+1
|
|
if(iface.eq.'columbus'.or.iface.eq.'none ') dens=-dens
|
|
C conver
|
|
conver=0
|
|
C symm
|
|
call getkey('symm',4,symm,4)
|
|
call getkey('localcc',7,localcc,4)
|
|
call getkey('orblocc',7,orblocc,16)
|
|
call getkey('orbloco',7,orbloco,16)
|
|
call getkey('orblocv',7,orblocv,16)
|
|
call getkey('orbloce',7,orbloce,16)
|
|
if(trim(orblocc).ne.'off'.or.
|
|
$ trim(orbloco).ne.'off'.or.
|
|
$ trim(orblocv).ne.'off'.or.
|
|
$ trim(orbloce).ne.'off') then
|
|
isym=0
|
|
else if(symm.eq.' '.or.localcc.ne.'off ') then
|
|
isym=1
|
|
else
|
|
read(symm,*) isym
|
|
endif
|
|
C diag
|
|
call getkey('diag',4,cdiag,6)
|
|
if(cdiag.eq.'olsen ') then
|
|
diag=1
|
|
else if(cdiag.eq.'follow') then
|
|
diag=2
|
|
else
|
|
diag=0
|
|
endif
|
|
C CS
|
|
call getkey('mult',4,cmult,4)
|
|
if(cmult.eq.'1 ') then
|
|
iclsh=1
|
|
else
|
|
iclsh=0
|
|
endif
|
|
if(iface.eq.'dirac ') iclsh=0
|
|
C spatial
|
|
call getkey('scftype',7,scftype,5)
|
|
call getkey('rohftype',8,rohftype,13)
|
|
if((scftype.eq.'uhf '.or.(scftype.eq.'rohf '.and.
|
|
$rohftype.eq.'semicanonical')).and..not.domain_is_cs) then
|
|
k=0
|
|
else
|
|
k=1
|
|
endif
|
|
if(iface.eq.'dirac ') k=1
|
|
C HF
|
|
if(scftype.eq.'rhf '.or.scftype.eq.'uhf ') then
|
|
ihf=1
|
|
else
|
|
ihf=0
|
|
endif
|
|
if(trim(orblocc).ne.'off'.or.
|
|
$ trim(orbloco).ne.'off'.or.
|
|
$ trim(orblocv).ne.'off'.or.
|
|
c $ trim(orbloce).ne.'off'.or.
|
|
$ embed.eq.'scl '.or.embed.eq.'fdm ') ihf=0
|
|
if(localcc.ne.'off '.and.embed.ne.'scl '.and.
|
|
$ embed.ne.'fdm ') ihf=1
|
|
C nsing, ntrip, & ndoub
|
|
call getkey('nstate',6,nstate,4)
|
|
read(nstate,*) ndoub
|
|
call getkey('nsing' ,5,nnsing,4)
|
|
read(nnsing,*) nsing
|
|
call getkey('ntrip' ,5,nntrip,4)
|
|
read(nntrip,*) ntrip
|
|
if(iclsh.eq.1) then !.and.k.eq.1) then
|
|
if(nsing.eq.0) nsing=ndoub
|
|
if(calc.ge.1) nsing=max(1,nsing)
|
|
ndoub=0
|
|
else
|
|
ndoub=max(ndoub,nsing+ntrip)
|
|
nsing=0
|
|
ntrip=0
|
|
endif
|
|
C nacto
|
|
call getkey('nacto',5,ch4,4)
|
|
read(ch4,*) nacto
|
|
C nactv
|
|
call getkey('nactv',5,ch4,4)
|
|
read(ch4,*) nactv
|
|
C tol
|
|
call getkey('cctol',5,cctol,4)
|
|
read(cctol,*) iitol
|
|
C maxex
|
|
call getkey('maxex',5,ch4,4)
|
|
read(ch4,*) maxex
|
|
!!! !HB
|
|
if((maxex.eq.0.and.embed.eq.'huzinaga').or.nvfroz.ne.0) then
|
|
maxex=op
|
|
endif
|
|
!!! !HB
|
|
C sacc
|
|
sacc=0
|
|
C ptfreq
|
|
call getkey('ptfreq',6,line1,16)
|
|
read(line1,*) ptfreq
|
|
C dboc
|
|
dboc=0
|
|
call getkey('dboc',4,ch4,4)
|
|
if(ch4.eq.'on ') dboc=1
|
|
C mem
|
|
call getkey('mem',3,line1,16)
|
|
if(line1.ne.' ') then
|
|
i=1
|
|
do while(line2(i).ne.' '.and.i.lt.16)
|
|
i=i+1
|
|
enddo
|
|
call lowercase(line2(i-2),ch2,2)
|
|
if(ch2.ne.'mb'.and.ch2.ne.'gb') then
|
|
write(iout,*) 'Unknown memory unit!'
|
|
call exit(1)
|
|
endif
|
|
line2(i-2)=' '
|
|
line2(i-1)=' '
|
|
read(line1,*) maxmem
|
|
else
|
|
ch2='mb'
|
|
maxmem=256.d0
|
|
endif
|
|
if(ch2.eq.'gb') maxmem=1024.d0*maxmem
|
|
maxcor=idnint(maxmem)
|
|
C locno & eps
|
|
locno=0
|
|
eps=0.d0
|
|
call getkey('eps',3,line1,16)
|
|
call getkey('ovirt',5,ovirt,4)
|
|
if(ovirt.eq.'mp2 ') locno=1
|
|
if(ovirt.eq.'ovos') locno=2
|
|
if(ovirt.ne.'off ') then
|
|
if(line1 .ne. ' ') then
|
|
read(line1,*) eps
|
|
else
|
|
call getkey('lnoepsv',7,line1,16)
|
|
read(line1,*) eps
|
|
end if
|
|
end if
|
|
call getkey('localcc',7,localcc,4)
|
|
if(localcc.ne.'off ') then
|
|
locno=3
|
|
call getkey('lnoepsv',7,line1,16)
|
|
read(line1,*) eps
|
|
call getkey('lnoepso',7,line1,16)
|
|
read(line1,*) rr
|
|
eps=min(eps,rr)
|
|
endif
|
|
C Occupation vector
|
|
call getkey('refdet',6,refdet,8)
|
|
if(refdet.ne.'none ') then
|
|
call getkeym('refdet',6,refdet,8)
|
|
if(refdet.eq.'serialno') then
|
|
call ifillzero(occvec,nbasis-nco)
|
|
do iocc=2,-1,-1
|
|
if(iocc.ne.0) then
|
|
read(minpfile,'(512a1)') line3
|
|
line=adjustl(line)
|
|
n=1
|
|
do while(line3(n).ne.' ')
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.'-'
|
|
$.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) ii
|
|
jj=ii
|
|
if(line3(n).eq.'-') then
|
|
n=n+1
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) jj
|
|
endif
|
|
if(jj.gt.nbasis-nco) then
|
|
write(iout,*)
|
|
$'Invalid serial number for keyword refdet!'
|
|
call dmrccend(1)
|
|
endif
|
|
do i=ii,jj
|
|
occvec(i)=iocc
|
|
enddo
|
|
n=n+1
|
|
enddo
|
|
endif
|
|
enddo
|
|
else
|
|
read(minpfile,*) (occvec(i),i=1,nbasis-nco)
|
|
endif
|
|
do i=1,nbasis-nco
|
|
if(occvec(i).ne.2.or.occvec(i).ne.0) then
|
|
iclsh=0
|
|
ihf=0
|
|
ndoub=ndoub+nsing+ntrip
|
|
nsing=0
|
|
ntrip=0
|
|
exit
|
|
endif
|
|
enddo
|
|
endif
|
|
C Options (first line)
|
|
open(inpfile,status='unknown',file='fort.56')
|
|
rewind(inpfile)
|
|
write(inpfile,"(i4,17i7,f9.5,i7,i9,i5,1pe10.3)")
|
|
c write(inpfile,"(i4,17i7,f9.5,3i7,1pe10.3)")
|
|
c write(inpfile,"(i4,17i6,f9.5,3i5,1pe10.3)")
|
|
$op,nsing,ntrip,rest,calc,dens,conver,isym,diag,iclsh,k,ihf,ndoub,
|
|
$nacto,nactv,iitol,maxex,sacc,ptfreq,dboc,maxcor,locno,eps
|
|
C Keword names (second line)
|
|
write(inpfile,"(a138)") 'ex.lev,nsing,ntrip, rest,CC/CI,dens,' //
|
|
$'conver,symm, diag, CS ,spatial, HF ,ndoub,nacto,nactv, ' //
|
|
$'tol ,maxex, sacc, freq, dboc, mem, locno, eps'
|
|
C Occupation vector (third line)
|
|
if (localcc.ne.'off '.and.trim(scftype).ne.'rhf') then
|
|
write(inpfile,"(1000000i2)") (2,i=1,lis_nbe),
|
|
$ (1,i=1,lis_nal-lis_nbe),(0,i=1,nbasis-lis_nal)
|
|
endif !localcc.ne.'off'
|
|
if(localcc.eq.'off ') then
|
|
if(refdet.ne.'none ') then
|
|
write(inpfile,"(100000i3)") (occvec(i),i=1,nbasis-nco)
|
|
else
|
|
if(iface.eq.'none ') then
|
|
write(inpfile,"(1000000i2)") (2,i=1,nbe-nco),(1,i=1,nal-nbe),
|
|
$(0,i=1,nbasis-nal)
|
|
else
|
|
write(inpfile,"(1000000i3)") (2,i=1,nbe),(1,i=1,nal-nbe),
|
|
$(0,i=1,nbasis-nal)
|
|
endif
|
|
endif
|
|
C Active/inactive oribitals (fourth line)
|
|
rewind(inpfile)
|
|
read(inpfile,*)
|
|
read(inpfile,*)
|
|
read(inpfile,*)
|
|
if((embed.eq.'huzinaga'.and.nfroz.ne.0).or.nvfroz.ne.0) then
|
|
call ifillzero(occvec,nbasis-nco)
|
|
occvec(1:nal-nco)=1 ! occupied mos
|
|
occvec(nal-nco+nvfroz+1:nbasis-nco)=1 ! virtual mos
|
|
write(inpfile,"(100000i2)") (occvec(i),i=1,nbasis-nco)
|
|
else
|
|
call getkey('active',6,active,8)
|
|
if(active.ne.'none ') then
|
|
call getkeym('active',6,active,8)
|
|
if(active.eq.'serialno') then
|
|
call ifillzero(occvec,nbasis-nco)
|
|
read(minpfile,'(512a1)') line3
|
|
line=adjustl(line)
|
|
n=1
|
|
do while(line3(n).ne.' ')
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.'-'
|
|
$.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) ii
|
|
jj=ii
|
|
if(line3(n).eq.'-') then
|
|
n=n+1
|
|
m=n
|
|
do while(line3(n).ne.','.and.line3(n).ne.' ')
|
|
n=n+1
|
|
enddo
|
|
line1=' '
|
|
do i=m,n-1
|
|
line2(i-m+1)=line3(i)
|
|
enddo
|
|
read(line1,*) jj
|
|
endif
|
|
if(jj.gt.nbasis-nco) then
|
|
write(iout,*)'Invalid serial number for active orbitals!'
|
|
call dmrccend(1)
|
|
endif
|
|
do i=ii,jj
|
|
occvec(i)=1
|
|
enddo
|
|
n=n+1
|
|
enddo
|
|
else
|
|
read(minpfile,*) (occvec(i),i=1,nbasis-nco)
|
|
endif
|
|
write(inpfile,"(100000i2)") (occvec(i),i=1,nbasis-nco)
|
|
else if(trim(scftype).eq.'mcscf') then
|
|
call nactorb('docc',ndoc)
|
|
call nactorb('mact',nact)
|
|
write(inpfile,"(100000i2)") (0,i=1,ndoc-nco),(1,i=1,nact),
|
|
$(0,i=nact+1,nbasis-nco)
|
|
endif
|
|
endif
|
|
C Maximum number of inactive orbitals (fifth line)
|
|
if((embed.eq.'huzinaga'.and.nfroz.ne.0).or.nvfroz.ne.0) then
|
|
call ifillzero(occvec,nbasis-nco)
|
|
write(inpfile,"(100000i3)") (occvec(i),i=1,op)
|
|
else
|
|
call getkey('maxact',6,ch4,4)
|
|
if(ch4.eq.'on ') then
|
|
if(active.eq.'none ') then
|
|
backspace(inpfile)
|
|
read(inpfile,*) (occvec(i),i=1,nbasis-nco)
|
|
iacto=nacto
|
|
iactv=nactv
|
|
do i=1,nbasis-nco
|
|
occvec(i)=iabs(occvec(i))
|
|
enddo
|
|
ii=nbasis-nco
|
|
do while(occvec(ii).eq.0)
|
|
ii=ii-1
|
|
enddo
|
|
jj=ii
|
|
do while(occvec(ii).eq.1)
|
|
ii=ii-1
|
|
iacto=iacto-1
|
|
iactv=iactv-1
|
|
enddo
|
|
do i=jj+1,jj+iactv/2
|
|
occvec(i)=1
|
|
enddo
|
|
do i=ii,ii-iacto/2+1,-1
|
|
occvec(i)=1
|
|
enddo
|
|
do i=1,nbasis-nco
|
|
occvec(i)=mod(occvec(i),2)
|
|
enddo
|
|
write(inpfile,"(100000i2)") (occvec(i),i=1,nbasis-nco)
|
|
endif
|
|
call getkeym('maxact',6,ch4,4)
|
|
read(minpfile,*) (occvec(i),i=1,op)
|
|
write(inpfile,"(100000i3)") (occvec(i),i=1,op)
|
|
endif
|
|
endif
|
|
endif ! localcc.eq.off
|
|
C
|
|
close(minpfile)
|
|
close(inpfile)
|
|
C
|
|
return
|
|
end
|
|
c
|
|
************************************************************************
|
|
subroutine sym2aobasistrf(symmat,aomat,n,nir,nfunc,offset,
|
|
$sqroffset,scr,scr2,scrfile1)
|
|
************************************************************************
|
|
* transform symmat from symmerty basis to the original AO basis of dimension n
|
|
* output: aomat
|
|
************************************************************************
|
|
implicit none
|
|
integer n,nir,nfunc(nir),sqroffset(nir),offset(nir),scrfile1,i
|
|
real*8 scr(*),scr2(*),symmat(*),aomat(*)
|
|
c
|
|
if(nir.gt.1) then
|
|
open(scrfile1,file='SYMTRA',form='unformatted')
|
|
call rtdmx(scr2,scr2,scr,scrfile1,n,n)
|
|
close(scrfile1)
|
|
do i=1,nir
|
|
if(nfunc(i).gt.0) then
|
|
call dsymm('r','u',n,nfunc(i),1.d0,symmat(sqroffset(i)),
|
|
$nfunc(i),scr((offset(i)-1)*n+1),n,0.d0,scr2((offset(i)-1)*n+1),n)
|
|
endif
|
|
enddo
|
|
call dgemm('n','t',n,n,n,1.d0,scr2,n,scr,n,0.d0,aomat,n)
|
|
endif
|
|
c
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine qsi(iwork,n,a)
|
|
************************************************************************
|
|
* Integer quick sort
|
|
************************************************************************
|
|
implicit none
|
|
integer iwork(*),n,a(n),i
|
|
call qsortint(iwork,n,a)
|
|
do i=1,n
|
|
iwork(n+i)=a(i)
|
|
enddo
|
|
do i=1,n
|
|
a(i)=iwork(n+iwork(i))
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
SUBROUTINE QSORTINT(ORD,N,A)
|
|
************************************************************************
|
|
* SORTS THE ARRAY A(I),I=1,2,...,N BY PUTTING THE
|
|
* ASCENDING ORDER VECTOR IN ORD. THAT IS ASCENDING ORDERED A
|
|
* IS A(ORD(I)),I=1,2,...,N; DESCENDING ORDER A IS A(ORD(N-I+1)),
|
|
* I=1,2,...,N . THIS SORT RUNS IN TIME PROPORTIONAL TO N LOG N .
|
|
************************************************************************
|
|
IMPLICIT INTEGER (A-Z)
|
|
C
|
|
DIMENSION ORD(N),POPLST(2,20)
|
|
integer X,XX,Z,ZZ,Y
|
|
C
|
|
C TO SORT DIFFERENT INPUT TYPES, CHANGE THE FOLLOWING
|
|
C SPECIFICATION STATEMENTS; FOR EXAMPLE, FOR FORTRAN CHARACTER
|
|
C USE THE FOLLOWING: CHARACTER *(*) A(N)
|
|
C
|
|
integer A(N)
|
|
C
|
|
NDEEP=0
|
|
U1=N
|
|
L1=1
|
|
DO 1 I=1,N
|
|
1 ORD(I)=I
|
|
2 IF (U1.LE.L1) RETURN
|
|
C
|
|
3 L=L1
|
|
U=U1
|
|
C
|
|
C PART
|
|
C
|
|
4 P=L
|
|
Q=U
|
|
C FOR CHARACTER SORTS, THE FOLLOWING 3 STATEMENTS WOULD BECOME
|
|
C X = ORD(P)
|
|
C Z = ORD(Q)
|
|
C IF (A(X) .LE. A(Z)) GO TO 2
|
|
C
|
|
C WHERE "CLE" IS A LOGICAL FUNCTION WHICH RETURNS "TRUE" IF THE
|
|
C FIRST ARGUMENT IS LESS THAN OR EQUAL TO THE SECOND, BASED ON "LEN"
|
|
C CHARACTERS.
|
|
C
|
|
X=A(ORD(P))
|
|
Z=A(ORD(Q))
|
|
IF (X.LE.Z) GO TO 5
|
|
Y=X
|
|
X=Z
|
|
Z=Y
|
|
YP=ORD(P)
|
|
ORD(P)=ORD(Q)
|
|
ORD(Q)=YP
|
|
5 IF (U-L.LE.1) GO TO 15
|
|
XX=X
|
|
IX=P
|
|
ZZ=Z
|
|
IZ=Q
|
|
C
|
|
C LEFT
|
|
C
|
|
6 P=P+1
|
|
IF (P.GE.Q) GO TO 7
|
|
X=A(ORD(P))
|
|
IF (X.GE.XX) GO TO 8
|
|
GO TO 6
|
|
7 P=Q-1
|
|
GO TO 13
|
|
C
|
|
C RIGHT
|
|
C
|
|
8 Q=Q-1
|
|
IF (Q.LE.P) GO TO 9
|
|
Z=A(ORD(Q))
|
|
IF (Z.LE.ZZ) GO TO 10
|
|
GO TO 8
|
|
9 Q=P
|
|
P=P-1
|
|
Z=X
|
|
X=A(ORD(P))
|
|
C
|
|
C DIST
|
|
C
|
|
10 IF (X.LE.Z) GO TO 11
|
|
Y=X
|
|
X=Z
|
|
Z=Y
|
|
IP=ORD(P)
|
|
ORD(P)=ORD(Q)
|
|
ORD(Q)=IP
|
|
11 IF (X.LE.XX) GO TO 12
|
|
XX=X
|
|
IX=P
|
|
12 IF (Z.GE.ZZ) GO TO 6
|
|
ZZ=Z
|
|
IZ=Q
|
|
GO TO 6
|
|
C
|
|
C OUT
|
|
C
|
|
13 CONTINUE
|
|
IF (.NOT.(P.NE.IX.AND.X.NE.XX)) GO TO 14
|
|
IP=ORD(P)
|
|
ORD(P)=ORD(IX)
|
|
ORD(IX)=IP
|
|
14 CONTINUE
|
|
IF (.NOT.(Q.NE.IZ.AND.Z.NE.ZZ)) GO TO 15
|
|
IQ=ORD(Q)
|
|
ORD(Q)=ORD(IZ)
|
|
ORD(IZ)=IQ
|
|
15 CONTINUE
|
|
IF (U-Q.LE.P-L) GO TO 16
|
|
L1=L
|
|
U1=P-1
|
|
L=Q+1
|
|
GO TO 17
|
|
16 U1=U
|
|
L1=Q+1
|
|
U=P-1
|
|
17 CONTINUE
|
|
IF (U1.LE.L1) GO TO 18
|
|
C
|
|
C START RECURSIVE CALL
|
|
C
|
|
NDEEP=NDEEP+1
|
|
POPLST(1,NDEEP)=U
|
|
POPLST(2,NDEEP)=L
|
|
GO TO 3
|
|
18 IF (U.GT.L) GO TO 4
|
|
C
|
|
C POP BACK UP IN THE RECURSION LIST
|
|
C
|
|
IF (NDEEP.EQ.0) GO TO 2
|
|
U=POPLST(1,NDEEP)
|
|
L=POPLST(2,NDEEP)
|
|
NDEEP=NDEEP-1
|
|
GO TO 18
|
|
C
|
|
C END SORT
|
|
C END QSORT
|
|
C
|
|
END
|
|
C
|
|
************************************************************************
|
|
subroutine removed3(calc1)
|
|
************************************************************************
|
|
* Removes the -D3 postfix if it is specified in the calc or dft keywords
|
|
************************************************************************
|
|
implicit none
|
|
character*1 calc1(*)
|
|
integer i
|
|
c
|
|
do i=1,30
|
|
if(calc1(i ).eq.'-'.and.
|
|
$ calc1(i+1).eq.'d'.and.
|
|
$ calc1(i+2).eq.'3') then
|
|
calc1(i:i+2)=' '
|
|
exit
|
|
endif
|
|
enddo
|
|
c
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine get_subsyscoord(natoms,atsymbol,coord,atnum,ind)
|
|
************************************************************************
|
|
* Write XYZ of the embedded subsystem
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer, intent(in) :: natoms
|
|
integer, intent(in) :: atnum(*)
|
|
character(len=2), intent(in) :: atsymbol(natoms)
|
|
double precision, intent(in) :: coord(3,natoms)
|
|
integer, intent(inout) :: ind(natoms)
|
|
integer :: iatom,j,m
|
|
character(len=10) :: cscr
|
|
ind = 0
|
|
call embedat(natoms,minpfile,ind,iout,'embed ',5)
|
|
C Write COORD_SUBSYSA.xyz file
|
|
open(moldenfile,file='COORD_SUBSYSA.xyz')
|
|
m = 0
|
|
do iatom = 1 , natoms
|
|
if(atnum(iatom).gt.0.and.ind(iatom).eq.1) m=m+1
|
|
enddo
|
|
write(cscr,"(i10)") m
|
|
write(moldenfile,"(a10)") adjustl(cscr)
|
|
write(moldenfile,*)
|
|
do iatom = 1 , natoms
|
|
if(atnum(iatom).gt.0.and.ind(iatom).eq.1)
|
|
$write(moldenfile,"(a2,3f20.10)")
|
|
$adjustl(atsymbol(iatom)),(angtobohr*coord(j,iatom),j=1,3)
|
|
enddo
|
|
write(moldenfile,*)
|
|
close(moldenfile)
|
|
C
|
|
end subroutine get_subsyscoord
|
|
C
|
|
************************************************************************
|
|
character(len=16) function get_moselectalg( minpfile )
|
|
$ result( mo_select_alg )
|
|
************************************************************************
|
|
* Returns the MO selection scheme in the case of embedding calculations
|
|
************************************************************************
|
|
implicit none
|
|
integer, intent(in) :: minpfile
|
|
character(len=8) :: embed
|
|
character(len=32) :: dft
|
|
character(len=512) :: read_buffer
|
|
integer :: i,j
|
|
integer :: istat, channelopen
|
|
logical :: foundopen
|
|
istat = 0
|
|
read_buffer = ''
|
|
mo_select_alg = ' '
|
|
inquire(file='MINP',opened=foundopen,number=channelopen)
|
|
if( .not. foundopen .or. channelopen .ne. minpfile)
|
|
$ open(minpfile,file='MINP',position='REWIND',action='READ',
|
|
$ status='OLD',form='FORMATTED',iostat=istat)
|
|
call getkeym('embed',5,embed,8)
|
|
! atom list
|
|
read(minpfile,'(a)',iostat=istat) read_buffer
|
|
! low-level method
|
|
if(istat.eq.0) read(minpfile,'(a)',iostat=istat) read_buffer
|
|
dft = trim(adjustl( read_buffer ) )
|
|
if(trim(dft).eq.'user'.or.trim(dft).eq.'userd') then
|
|
read(minpfile,'(a)',iostat=istat) read_buffer
|
|
read( read_buffer , * ) j
|
|
do i=1,j
|
|
read(minpfile,'(a)',iostat=istat) read_buffer
|
|
enddo
|
|
if(trim(dft).eq.'userd') then
|
|
read(minpfile,'(a)',iostat=istat) read_buffer
|
|
read( read_buffer , * ) j
|
|
do i=1,j
|
|
read(minpfile,'(a)',iostat=istat) read_buffer
|
|
enddo
|
|
endif
|
|
if(istat.ne.0) then
|
|
write(6,'(a)') ' Error during the read of the
|
|
$user-defined DFT functional parameters'
|
|
call mrccend(1)
|
|
endif
|
|
endif
|
|
! Read the active MO specifier line
|
|
if(istat.eq.0) read(minpfile,'(a)',iostat=istat)
|
|
$ read_buffer
|
|
if( .not. foundopen .or. channelopen .ne. minpfile)
|
|
$close(minpfile)
|
|
! first character a number
|
|
i = index( read_buffer , ' ')
|
|
read_buffer( 1 : i ) = ' '
|
|
read_buffer = adjustl( read_buffer )
|
|
! second character: the method
|
|
i = index( read_buffer ,' ')
|
|
mo_select_alg = 'default'
|
|
if( i .ne. 1 ) mo_select_alg = read_buffer( 1 : i )
|
|
end function get_moselectalg
|
|
C
|
|
************************************************************************
|
|
subroutine get_orbloce_special(orblocc,orbloco,orblocv)
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer :: istat, channelopen
|
|
character(len=16) :: cscr16
|
|
character(len=16) :: orblocc
|
|
character(len=16) :: orbloco
|
|
character(len=16) :: orblocv
|
|
logical :: foundopen
|
|
istat = 0
|
|
inquire(file='MINP',opened=foundopen,number=channelopen)
|
|
if(.not. foundopen .or. channelopen .ne. minpfile) then
|
|
open(unit=minpfile,file='MINP',status='OLD',iostat=istat,
|
|
$ action='READ',form='FORMATTED')
|
|
endif
|
|
rewind(minpfile)
|
|
call getkeym('orbloce',7,cscr16,16)
|
|
if(istat.eq.0) read(minpfile,'(a)',iostat=istat) orblocc
|
|
if(istat.eq.0) read(minpfile,'(a)',iostat=istat) orbloco
|
|
if(istat.eq.0) read(minpfile,'(a)',iostat=istat) orblocv
|
|
if(.not. foundopen .or. channelopen .ne. minpfile) then
|
|
close(minpfile)
|
|
endif
|
|
if( istat .ne. 0 ) then
|
|
write(iout,'(a)')
|
|
$'Cannot read orblocc/orbloco/orblocv for orbloce=special'
|
|
call mrccend(1)
|
|
endif
|
|
end subroutine get_orbloce_special
|
|
C
|
|
************************************************************************
|
|
subroutine separate_string(string,stringlen,separator,s1,s1len,
|
|
$s2,s2len)
|
|
************************************************************************
|
|
* Separates 'string' into string 's1' and 's2' connected by the separator
|
|
************************************************************************
|
|
implicit none
|
|
integer :: stringlen,i,j,s1len,s2len
|
|
character(len=1) :: line(stringlen),line2(stringlen)
|
|
character(len=1) :: s1(s1len),s2(s2len)
|
|
character(len=1) :: separator
|
|
character(len=1) :: string(stringlen)
|
|
logical llg
|
|
call lowercase(string,string,stringlen)
|
|
line(:)=string(:)
|
|
line2=' '
|
|
s1=' '
|
|
s2=' '
|
|
i=1
|
|
llg=.false.
|
|
do while(line(i).ne.' '.and.i.lt.stringlen)
|
|
if(line(i).eq.separator) then
|
|
line2(1:i-1)=line(1:i-1)
|
|
s1(1:s1len)=line2(1:s1len)
|
|
line2=' '
|
|
j=1
|
|
do while(line(i+j).ne.' '.and.j.ne.s2len.and.(i+j).ne.stringlen)
|
|
s2(j)=line(i+j)
|
|
j=j+1
|
|
enddo
|
|
llg=.true.
|
|
endif
|
|
i=i+1
|
|
enddo
|
|
if(.not.llg) then
|
|
s1(1:s1len)=string(1:s1len)
|
|
s2=' '
|
|
endif
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine write_mop(qmmm,dens,isp,minpfile,natoms,natwdummy,
|
|
$ncent,coord,atsymbol,atchg,method,charge,mult,iout,
|
|
$usetemp,verbosity,uval,pcm,pcmkeystring,npcmdefkeys,
|
|
$oniomtype,ccoord,ncharge,firstcall,moldenval)
|
|
************************************************************************
|
|
* write MOPAC input file
|
|
************************************************************************
|
|
implicit none
|
|
integer ncent,natoms,isp,i,j,iout,minpfile,iatoms,k,ncharge
|
|
integer charge,mult,natwdummy,ierr,npcmdefkeys
|
|
character*1 line1(512)
|
|
character*2 atsymbol(natwdummy),cscr2
|
|
character*3 moldenval
|
|
character*4 verbosity,dens,uval,oniomtype
|
|
character*8 qmmm,cscr8
|
|
character*16 cscr16,inpfile
|
|
character*32 method,pcm
|
|
character*512 line,pcmkeystring
|
|
real*8 coord(3,ncent),atchg(ncent),ccoord(3,ncent),rscr
|
|
logical usetemp,llg,firstcall
|
|
equivalence(line,line1)
|
|
line=' '
|
|
write(iout,'(a)') ' Writing mop file ...'
|
|
write(cscr2,'(i2)') isp
|
|
! Search for template file
|
|
inpfile='MINP.'//trim(adjustl(cscr2))
|
|
cscr16='MINP.'//trim(adjustl(cscr2))//'.tpl'
|
|
if(usetemp) then
|
|
inquire(file=cscr16,exist=llg)
|
|
if(llg) then
|
|
write(iout,
|
|
$"( ' Template file is found. Using file: ',a12)") cscr16
|
|
open(minpfile, file=cscr16, iostat=ierr)
|
|
rewind(minpfile)
|
|
read(minpfile,'(a)') line
|
|
close(minpfile)
|
|
else
|
|
write(iout,"( ' Template file is not found.')")
|
|
endif
|
|
endif
|
|
line=trim(adjustl(line))
|
|
! set MS
|
|
rscr=(mult-1d0)/2.0d0
|
|
write(cscr16,'(f6.1)') rscr
|
|
line=trim(adjustl(line))//' MS='//trim(adjustl(cscr16))
|
|
if(mult.ne.1) line=trim(adjustl(line))//' UHF '
|
|
! set Charge
|
|
write(cscr16,'(i5)') charge
|
|
line=trim(adjustl(line))//' CHARGE='//trim(adjustl(cscr16))
|
|
! set Bohr/Angstrom
|
|
if(uval.eq.'bohr') line=trim(adjustl(line))//' A0 '
|
|
! set verbosity
|
|
read(verbosity,'(i4)') i
|
|
if(i.gt.2) line=trim(adjustl(line))//' '//'PL'
|
|
! set bond order
|
|
if(isp.eq.1) line=trim(adjustl(line))//' BONDS'
|
|
! Set gradient and density-reading related keywords
|
|
read(dens,'(i4)') i
|
|
! Set gradient and density matrix writing keywords
|
|
if(i.gt.1) line=trim(adjustl(line))//' GRADIENTS DENOUT'
|
|
! Set density matrix reading keyword (use it as guess)
|
|
if(.not.firstcall) line=trim(adjustl(line))//' OLDENS '
|
|
! Print MOs in the unformatted, Molden-readable format
|
|
! (the formatted command, GRAPHF, is not working... )
|
|
if(moldenval.ne.'off') line=trim(adjustl(line))//' GRAPH '
|
|
!!! Most important keywords for the interface !!!
|
|
! Request a single SCF
|
|
line=trim(adjustl(line))//' 1SCF '
|
|
! Request an auxilirary file with increased printing precision
|
|
line=trim(adjustl(line))//' AUX(PRECISION=12,XP,XS,XW) '
|
|
! Disable the reorientation of the system
|
|
line=trim(adjustl(line))//' NOREOR '
|
|
! Increase the SCF criteria (do we need this other than developement?)
|
|
line=trim(adjustl(line))//' SCFCRT=1.D-8 '
|
|
! Add the calculation type
|
|
line=trim(adjustl(method))//' '//trim(adjustl(line))
|
|
! Add solvent-specification
|
|
if(npcmdefkeys.gt.0) then
|
|
line=trim(adjustl(line))//' '//trim(adjustl(pcmkeystring))
|
|
endif
|
|
open(minpfile, file=inpfile, iostat=ierr, status='replace')
|
|
write(minpfile,'(a)') trim(adjustl(line))
|
|
write(minpfile,*)
|
|
if(usetemp) then
|
|
write(minpfile,'(a)')
|
|
$'! User defined keywords from: template file+MINP'
|
|
else
|
|
write(minpfile,'(a)')'! User defined keywords from: MINP'
|
|
endif
|
|
do iatoms=1,natoms
|
|
write(minpfile,'(a2,3f25.16)')
|
|
$atsymbol(iatoms),coord(1:3,iatoms)
|
|
enddo
|
|
close(minpfile)
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine execute_mopac(cisp,iprog,iout,istat,cput,walt)
|
|
************************************************************************
|
|
* execute MOPAC
|
|
************************************************************************
|
|
implicit none
|
|
#if !defined (gfortran) && !defined (G95)
|
|
integer*4 system
|
|
external system
|
|
#endif
|
|
integer iout,istat
|
|
character*2 cisp
|
|
character*16 iprog
|
|
character*64 cscr64
|
|
real*8 cput,walt
|
|
write(iout,'(2a)')
|
|
$' MOP file is written into: MINP.'//trim(adjustl(cisp))
|
|
cscr64=trim(adjustl(iprog))//' MINP.'//trim(adjustl(cisp))
|
|
write(iout,'(2a)')
|
|
$' Executing command line: '//trim(adjustl(cscr64))
|
|
cput=0.0d0
|
|
walt=0.0d0
|
|
call mtime(cput,walt)
|
|
istat=system(trim(adjustl(cscr64)))
|
|
cput=1.0d0
|
|
walt=1.0d0
|
|
call mtime(cput,walt)
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine read_mopac_aux(cfilenum,scrfile1,nval,rscrmat,rtype,
|
|
$skey,skeylen)
|
|
************************************************************************
|
|
* read MOPAC's aux file
|
|
************************************************************************
|
|
implicit none
|
|
integer :: ios,scrfile1,skeylen,i,n,nval,nrow
|
|
real*8 :: rscrmat(nval),rscrr
|
|
character(len=2) :: cfilenum
|
|
character(len=6) :: rtype
|
|
character(len=1) :: bline(64),linev,cscr1
|
|
character(len=64) :: read_buffer,cscr64
|
|
character(len=64) :: skey
|
|
equivalence(read_buffer,bline)
|
|
equivalence(cscr64,linev)
|
|
open(scrfile1,file='MINP.'//trim(adjustl(cfilenum))//'.aux',
|
|
$ form='formatted')
|
|
rewind(scrfile1)
|
|
cscr64=skey
|
|
linev(skeylen:64)=' '
|
|
do
|
|
read(scrfile1,'(a)',iostat=ios) read_buffer
|
|
! End of file; data not found
|
|
bline(skeylen:64)=' '
|
|
if(ios.lt.0) exit
|
|
if (read_buffer.eq.cscr64) then
|
|
if(rtype.eq.'block ') then
|
|
read(scrfile1,*) cscr1
|
|
if(cscr1.ne.'#') backspace(scrfile1)
|
|
! Count rows
|
|
rscrr=nval/10d0
|
|
nrow=nint(rscrr)
|
|
if(nval.gt.0.and.nrow.eq.0) nrow=1
|
|
! Read from aux file
|
|
do i=1,nrow
|
|
if(i.ne.nrow) then
|
|
read(scrfile1,*) rscrmat((i-1)*10+1:10*i)
|
|
else
|
|
read(scrfile1,*) rscrmat((i-1)*10+1:nval)
|
|
endif
|
|
enddo
|
|
else if(rtype.eq.'horizo') then
|
|
backspace(scrfile1)
|
|
read(scrfile1,'(a)') read_buffer
|
|
i=1
|
|
do while(bline(i).ne.'='.and.i.le.64)
|
|
bline(i)=' '
|
|
i=i+1
|
|
enddo
|
|
bline(i)=' '
|
|
read(read_buffer,*) rscrmat(1:nval)
|
|
endif
|
|
endif
|
|
enddo
|
|
close(scrfile1)
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine check_sqm_prog(sqmprog,exe,iout,userset)
|
|
************************************************************************
|
|
* Check the availability of sqm programs
|
|
************************************************************************
|
|
implicit none
|
|
character*16 sqmprog,exe,extprog(2),extprogexe(2)
|
|
character*32 string
|
|
integer iout,istat,nprog,iprog,foundprog(2)
|
|
logical lfound,userset
|
|
#if !defined (gfortran) && !defined (G95)
|
|
integer*4 system
|
|
external system
|
|
#endif
|
|
lfound=.false.
|
|
nprog=2
|
|
foundprog=0
|
|
extprog(1)='xtb '
|
|
extprog(2)='mopac2016 '
|
|
extprogexe(1)='xtb '
|
|
extprogexe(2)='MOPAC2016.exe '
|
|
write(iout,*)
|
|
write(iout,'(a)')
|
|
$' Checking if a semi-empirical program is '//
|
|
$'available...'
|
|
do iprog=1,nprog
|
|
if(sqmprog.ne.' '.and.
|
|
$ sqmprog.ne.extprog(iprog)) then
|
|
cycle
|
|
endif
|
|
write(iout,"(' Searching for sqm program: ',a)")
|
|
$ trim(adjustl(extprog(iprog)))
|
|
string='which '//trim(adjustl(extprogexe(iprog)))
|
|
istat=system(trim(adjustl(string)))
|
|
foundprog(iprog)=1
|
|
if(istat.eq.0) then
|
|
lfound=.true.
|
|
write(iout,"(' 'a,' is found!')")
|
|
$ trim(adjustl(extprogexe(iprog)))
|
|
else
|
|
lfound=.false.
|
|
endif
|
|
enddo
|
|
if(.not.lfound) then
|
|
write(iout,"(' No executables are found.')")
|
|
call mrccend(1)
|
|
else
|
|
do iprog=1,nprog
|
|
if((sqmprog.eq.' '.and.foundprog(iprog).eq.1)
|
|
$.or.
|
|
$ (sqmprog.eq.extprog(iprog) .and.foundprog(iprog).eq.1))
|
|
$then
|
|
exe=extprogexe(iprog)
|
|
exit
|
|
else if(sqmprog.eq.extprog(iprog) .and.foundprog(iprog).eq.0)
|
|
$ then
|
|
write(iout,"(' The executable for the requested program ('a,
|
|
$') is not found.')") trim(adjustl(sqmprog))
|
|
call mrccend(1)
|
|
endif
|
|
enddo
|
|
write(iout,*)
|
|
write(iout,"(' ',a,' will be used as external sqm program.')")
|
|
$ trim(adjustl(exe))
|
|
if(.not.userset) then
|
|
write(iout,'(a)') ' (by default) '
|
|
else
|
|
write(iout,'(a)') ' (by user request) '
|
|
endif
|
|
write(iout,*)
|
|
endif
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine write_xtb_files(qmmm,dens,isp,minpfile,natoms,
|
|
$natwdummy,ncent,coord,atsymbol,atchg,method,charge,mult,
|
|
$iout,usetemp,verbosity,uval,pcm,pcmkeystring,npcmdefkeys,
|
|
$oniomtype,ccoord,ncharge,firstcall,moldenval,xtbstring,
|
|
$printcharges,initguess,etemp)
|
|
************************************************************************
|
|
* write input files for the xtb program
|
|
************************************************************************
|
|
implicit none
|
|
integer ncent,natoms,isp,i,j,iout,minpfile,iatoms,k,ncharge
|
|
integer charge,mult,natwdummy,ierr,npcmdefkeys
|
|
character*1 line1(512)
|
|
character*2 atsymbol(natwdummy),cscr2
|
|
character*3 moldenval
|
|
character*4 verbosity,dens,uval,oniomtype
|
|
character*8 qmmm,cscr8,etemp
|
|
character*16 cscr16,inpfile,pcfile,coordfile,coordfile2
|
|
character*16 tempfile,outfile
|
|
character*32 method,pcm,cscr32
|
|
character*512 line,pcmkeystring
|
|
character*128 xtbstring
|
|
real*8 coord(3,ncent),atchg(ncent),ccoord(3,ncent),rscr
|
|
logical usetemp,llg,firstcall,printcharges,initguess
|
|
equivalence(line,line1)
|
|
line=' '
|
|
llg=.false.
|
|
write(iout,'(a)') ' Writing files for xtb program ...'
|
|
write(cscr2,'(i2)') isp
|
|
! Search for template file
|
|
inpfile='MINP.'//trim(adjustl(cscr2))//'.xtbinp'
|
|
coordfile='MINP.'//trim(adjustl(cscr2))//'.xyz'
|
|
coordfile2='MINP.'//trim(adjustl(cscr2))//'.coord'
|
|
pcfile='MINP.'//trim(adjustl(cscr2))//'.pc'
|
|
tempfile='MINP.'//trim(adjustl(cscr2))//'.tpl'
|
|
! Read the first line of the template file to extend the command line
|
|
if(usetemp) then
|
|
inquire(file=tempfile,exist=llg)
|
|
if(llg) then
|
|
write(iout,
|
|
$"( ' Template file is found. Using file: ',a12)") tempfile
|
|
open(minpfile, file=tempfile, iostat=ierr)
|
|
rewind(minpfile)
|
|
read(minpfile,'(a)') line
|
|
close(minpfile)
|
|
else
|
|
write(iout,"( ' Template file is not found.')")
|
|
endif
|
|
endif
|
|
xtbstring='--input '//trim(adjustl(inpfile))//' --grad '//
|
|
$'--namespace MINP.'//trim(adjustl(cscr2))//' '//
|
|
$trim(adjustl(line))
|
|
if(initguess) then
|
|
xtbstring=trim(adjustl(xtbstring))//' --acc 0.0001'
|
|
endif
|
|
xtbstring=trim(adjustl(xtbstring))//' --etemp '//
|
|
$trim(adjustl(etemp))
|
|
open(minpfile,file=inpfile,form='formatted')
|
|
! set spin
|
|
c rscr=(mult-1d0)/2.0d0
|
|
c write(cscr16,'(f6.1)') rscr
|
|
i=(mult-1) ! xtb requires the number of unpaired electrons
|
|
write(cscr16,'(i4)') i
|
|
write(minpfile,'(2a)') '$spin '//trim(adjustl(cscr16))
|
|
! set Charge
|
|
write(cscr16,'(i5)') charge
|
|
write(minpfile,'(2a)') '$chrg '//trim(adjustl(cscr16))
|
|
! set geometry units - geometry input dependent??
|
|
if(uval.eq.'bohr') then
|
|
write(minpfile,'(a)') '$coord bohr'
|
|
else
|
|
write(minpfile,'(a)') '$coord angs'
|
|
endif
|
|
write(minpfile,'(a)') '$write'
|
|
! set bond order
|
|
if(isp.eq.1) write(minpfile,'(a)') ' wiberg=1'
|
|
! Do not print (mulliken?) charges
|
|
if(printcharges) then
|
|
write(minpfile,'(a)') ' charges=1'
|
|
else
|
|
write(minpfile,'(a)') ' charges=0'
|
|
endif
|
|
! set molden output
|
|
if(moldenval.ne.'off') write(minpfile,'(a)') ' mos=1'
|
|
write(minpfile,'(a)') '$'
|
|
! Set gradient and density-reading related keywords
|
|
read(dens,'(i4)') i
|
|
! Set gradient and density matrix writing keywords
|
|
if(i.gt.1) xtbstring=trim(adjustl(xtbstring))//' --grad'
|
|
! Add the calculation type
|
|
if(method.eq.'gfn0-xtb'.or.
|
|
$ method.eq.'gfn1-xtb'.or.
|
|
$ method.eq.'gfn2-xtb') then
|
|
write(minpfile,'(a)') '$gfn'
|
|
if(method.eq.'gfn0-xtb') write(minpfile,'(a)') 'method=0'
|
|
if(method.eq.'gfn1-xtb') write(minpfile,'(a)') 'method=1'
|
|
if(method.eq.'gfn2-xtb') write(minpfile,'(a)') 'method=2'
|
|
write(minpfile,'(a)') '$'
|
|
else if(method.eq.'gfn-ff') then
|
|
xtbstring=trim(adjustl(xtbstring))//' --gfnff'
|
|
endif
|
|
if(ncharge.gt.0) then
|
|
write(minpfile,'(a)') '$embedding'
|
|
write(minpfile,'(3a)')
|
|
$ 'input=MINP.'//trim(adjustl(cscr2))//'.pc'
|
|
write(minpfile,'(a)') '$'
|
|
endif
|
|
close(minpfile)
|
|
! Catanate the template file and the input file
|
|
if(usetemp.and.llg) then
|
|
call ishell('cat '//trim(adjustl(tempfile))//' >>'//
|
|
$trim(adjustl(inpfile)))
|
|
endif
|
|
open(minpfile, file=coordfile, iostat=ierr, status='replace')
|
|
write(cscr16,'(i16)') natoms
|
|
write(minpfile,'(a)') trim(adjustl(cscr16))
|
|
write(minpfile,*)
|
|
do iatoms=1,natoms
|
|
write(minpfile,'(a2,3f25.16)')
|
|
$atsymbol(iatoms),coord(1:3,iatoms)
|
|
enddo
|
|
write(minpfile,*)
|
|
close(minpfile)
|
|
!
|
|
open(minpfile, file=coordfile2, iostat=ierr, status='replace')
|
|
if(uval.eq.'angs') write(minpfile,'(a)') '$coord angs'
|
|
if(uval.eq.'bohr') write(minpfile,'(a)') '$coord bohr'
|
|
do iatoms=1,natoms
|
|
write(minpfile,'(3f25.16,2x,a2)')
|
|
$coord(1:3,iatoms),atsymbol(iatoms)
|
|
enddo
|
|
write(minpfile,'(a)') '$end'
|
|
close(minpfile)
|
|
! Write point charge file in the case of embedding
|
|
if(ncharge.gt.0) then
|
|
open(minpfile, file=pcfile, iostat=ierr, status='replace')
|
|
write(minpfile,'(100000000i12)') ncharge
|
|
do iatoms=1,ncharge
|
|
write(minpfile,'(4f25.16,2x,a)')
|
|
$atchg(iatoms),ccoord(1:3,iatoms),' 999'
|
|
enddo
|
|
close(minpfile)
|
|
endif
|
|
! Add pcm info
|
|
if(trim(adjustl(pcm)).ne.'off') then
|
|
if(npcmdefkeys.ne.0) then
|
|
do i=1,npcmdefkeys
|
|
if(i.eq.1) then
|
|
read(pcmkeystring,*) line
|
|
else
|
|
read(pcmkeystring,*) (line1(k),k=1,i-1),line
|
|
endif
|
|
call separate_string(line,512,'=',cscr32,32,cscr16,16)
|
|
if (trim(adjustl(cscr16)).eq.'alpb') then
|
|
xtbstring=trim(adjustl(xtbstring))//' --alpb '//pcm
|
|
else if(trim(adjustl(cscr16)).eq.'gbsa') then
|
|
xtbstring=trim(adjustl(xtbstring))//' --gbsa '//pcm
|
|
endif
|
|
enddo
|
|
else
|
|
xtbstring=trim(adjustl(xtbstring))//' --alpb '//pcm
|
|
endif
|
|
endif
|
|
! Add the coordinate file to the executing string
|
|
xtbstring='xtb '
|
|
$//trim(adjustl(coordfile2))//' '//trim(adjustl(xtbstring))
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine execute_xtb(cisp,iout,xtbstring,ioutprint,istat,
|
|
$cput,walt)
|
|
************************************************************************
|
|
* execute MOPAC
|
|
************************************************************************
|
|
implicit none
|
|
integer iout,istat
|
|
#if !defined (gfortran) && !defined (G95)
|
|
integer*4 system
|
|
external system
|
|
#endif
|
|
character*2 cisp
|
|
character*16 outfile
|
|
character*128 xtbstring
|
|
real*8 cput,walt
|
|
logical ioutprint
|
|
outfile='MINP.'//trim(adjustl(cisp))//'.xtbout'
|
|
write(iout,'(2a)')
|
|
$' xTB xcontrol file is written into: MINP.'//trim(adjustl(cisp))
|
|
$//'.xtbinp'
|
|
write(iout,'(3a)')
|
|
$' xTB coord file is written into : '//
|
|
$'MINP.'//trim(adjustl(cisp))//'.xyz'
|
|
if(.not.ioutprint) then
|
|
xtbstring=trim(adjustl(xtbstring))//' > '
|
|
$//trim(adjustl(outfile))
|
|
write(iout,'(3a)')
|
|
$' xTB output file is written into : '//
|
|
$'MINP.'//trim(adjustl(cisp))//'.xtbout'
|
|
endif
|
|
write(iout,'(a)') ' Executing command line: '
|
|
write(iout,'(x,a)') trim(adjustl(xtbstring))
|
|
cput=0.0d0
|
|
walt=0.0d0
|
|
call mtime(cput,walt)
|
|
istat=system(trim(adjustl(xtbstring)))
|
|
cput=1.0d0
|
|
walt=1.0d0
|
|
call mtime(cput,walt)
|
|
return
|
|
end
|
|
C
|
|
logical function mopac_was_used() result( used )
|
|
#include "MRCCCOMMON"
|
|
character(len=1024) :: read_buffer
|
|
character(len=8) :: prop
|
|
character(len=16) :: method
|
|
integer :: istat
|
|
used = .false.
|
|
open(unit=ifcfile,file='iface',status='OLD',
|
|
$ action='READ',position='REWIND',iostat=istat)
|
|
read(ifcfile,'(a)',iostat=istat) read_buffer
|
|
do while( istat .eq. 0 .and. .not. used )
|
|
read(ifcfile,'(a)',iostat=istat) read_buffer
|
|
read(read_buffer,*) prop,method
|
|
used = trim(adjustl(method)) .eq. 'MOPAC-SCF'
|
|
enddo
|
|
close(ifcfile)
|
|
end function mopac_was_used
|
|
************************************************************************
|
|
subroutine getatnum(atsymbol,atnum)
|
|
************************************************************************
|
|
* Get atomic number and atomic symbol
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer atnum
|
|
character*2 atsymbol,atsym(0:natmax),ch1,ch2
|
|
data atsym /'Bf',
|
|
$ 'H ','He','Li','Be','B ','C ','N ','O ','F ','Ne',
|
|
$ 'Na','Mg','Al','Si','P ','S ','Cl','Ar','K ','Ca',
|
|
$ 'Sc','Ti','V ','Cr','Mn','Fe','Co','Ni','Cu','Zn',
|
|
$ 'Ga','Ge','As','Se','Br','Kr','Rb','Sr','Y ','Zr',
|
|
$ 'Nb','Mo','Tc','Ru','Rh','Pd','Ag','Cd','In','Sn',
|
|
$ 'Sb','Te','I ','Xe','Cs','Ba','La','Ce','Pr','Nd',
|
|
$ 'Pm','Sm','Eu','Gd','Tb','Dy','Ho','Er','Tm','Yb',
|
|
$ 'Lu','Hf','Ta','W ','Re','Os','Ir','Pt','Au','Hg',
|
|
$ 'Tl','Pb','Bi','Po','At','Rn','Fr','Ra','Ac','Th',
|
|
$ 'Pa','U ','Np','Pu','Am','Cm','Bk','Cf','Es','Fm',
|
|
$ 'Md','No','Lr','Rf','Db','Sg','Bh','Hs','Mt','Ds',
|
|
$ 'Rg','Cn','Nh','Fl','Mc','Lv','Ts','Og'/
|
|
C
|
|
if(atnum.eq.0) then
|
|
call lowercase(atsymbol,ch1,2)
|
|
atnum=-1
|
|
ch2=' '
|
|
do while(ch1.ne.ch2)
|
|
atnum=atnum+1
|
|
if(atnum.gt.natmax) then
|
|
call uppercase(atsymbol,atsymbol,1)
|
|
write(iout,*) 'Unknown atomic symbol '//trim(atsymbol)//'!'
|
|
call mrccend(1)
|
|
endif
|
|
call lowercase(atsym(atnum),ch2,2)
|
|
enddo
|
|
endif
|
|
atsymbol=atsym(atnum)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
***********************************************************************
|
|
logical function dof12(calc)
|
|
***********************************************************************
|
|
* Shall we do F12 calculation?
|
|
***********************************************************************
|
|
implicit none
|
|
character*1 calc(16)
|
|
integer i
|
|
C
|
|
dof12=.false.
|
|
do i=1,13
|
|
dof12=dof12.or.((calc(i ).eq.'-'.or.calc(i ).eq.'(').and.
|
|
$ calc(i+1).eq.'f'.and.
|
|
$ calc(i+2).eq.'1'.and.
|
|
$ calc(i+3).eq.'2')
|
|
enddo
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine orth(nb,mb,s,c,w)
|
|
************************************************************************
|
|
* Symmetric orthogonalization
|
|
************************************************************************
|
|
implicit none
|
|
integer nb,mb,i,j
|
|
real*8 s(nb,nb),c(nb,mb),w(*)
|
|
C
|
|
call dsymm('l','u',nb,mb,1.d0,s,nb,c,nb,0.d0,w(nb*nb+1),nb)
|
|
call dgemm('t','n',mb,mb,nb,1.d0,c,nb,w(nb*nb+1),nb,0.d0,w,mb)
|
|
call invsqrt(w,mb,w(mb*mb+1),6,i,0.d0,1)
|
|
if(i.ne.0) call mrccend(1)
|
|
call dsymm('r','u',nb,mb,1.d0,w,mb,c,nb,0.d0,w(mb*mb+1),nb)
|
|
call dcopy(nb*mb,w(mb*mb+1),1,c,1)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine smearoccup(nmos,eigenvalue,nelectr,occup,etemp)
|
|
************************************************************************
|
|
* Calculate the occupation of the orbitals if the Fermi-smearing is utilized
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer nmos,nelectr,p,nsingle
|
|
real*8 fermilevel,betafact,etemp,sumocc,sumscal,sumfod
|
|
real*8 occup(nmos),eigenvalue(nmos)
|
|
sumfod=0.0d0
|
|
nsingle=0
|
|
sumocc=0.0d0
|
|
occup(1:nmos)=0.0d0
|
|
! Calculate fractional occupations
|
|
fermilevel=( eigenvalue(nelectr)+eigenvalue(nelectr+1) )/2.d0
|
|
betafact=1.0d0/((boltz/jtoeh*1d-5)*etemp)
|
|
do p=1,nmos
|
|
occup(p)=1.0d0/
|
|
$(1.0d0+exp( (eigenvalue(p)-fermilevel)*betafact ) )
|
|
sumocc=sumocc+occup(p)
|
|
if(abs(1.0d0-occup(p)).lt.1d-9) then
|
|
nsingle=nsingle+1
|
|
else
|
|
sumfod=sumfod+occup(p)
|
|
endif
|
|
enddo
|
|
! Rescale the occupation number of the partially occupied orbitals
|
|
sumscal=nsingle
|
|
if(sumfod.gt.1d-9) then
|
|
do p=nsingle+1,nmos
|
|
occup(p)=dble(nelectr-nsingle)/sumfod*occup(p)
|
|
sumscal=sumscal+occup(p)
|
|
enddo
|
|
endif
|
|
c write(iout,'(a,E15.10)') ' Particle number residue: ',
|
|
c $abs( sumscal-dble(nelectr) )
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine gsch(o, x, y, ldo, n, m)
|
|
************************************************************************
|
|
* gram-schmidt ortogonalization
|
|
* input:
|
|
* o(ldo, m) a set of orthonormal vectors
|
|
* y: temporary vector of length ldo
|
|
* x: new vector
|
|
* output:
|
|
* x: ortogonalized vector
|
|
************************************************************************
|
|
implicit none
|
|
|
|
integer ldo, n, m, i
|
|
double precision o(ldo, *), x(*), norm, y(*), tmp, oldnorm, eta
|
|
parameter(eta = 0.707106781d0)
|
|
double precision dnrm2, ddot
|
|
|
|
if(m .ge. n) then
|
|
call dlaset('f', 1, n, 0.0d0, 0.0d0, x, 1)
|
|
return
|
|
endif
|
|
oldnorm = dnrm2(n, x, 1)
|
|
call dgemv('t', n, m, 1.0d0, o, ldo, x, 1, 0.0d0, y, 1)
|
|
call dgemv('n', n, m, -1.0d0, o, ldo, y, 1, 1.0d0, x, 1)
|
|
norm = dnrm2(n, x, 1)
|
|
do while(oldnorm*eta .gt. norm .or.
|
|
& (oldnorm*eta .gt. norm .and. norm .gt. 1.0d-16))
|
|
call dgemv('t', n, m, 1.0d0, o, ldo, x, 1, 0.0d0, y, 1)
|
|
call dgemv('n', n, m, -1.0d0, o, ldo, y, 1, 1.0d0, x, 1)
|
|
oldnorm = norm
|
|
norm = dnrm2(n, x, 1)
|
|
enddo
|
|
|
|
norm = dnrm2(n, x, 1)
|
|
if(norm .gt. 1.0d-16) then
|
|
call dscal(n, 1.0d0/norm, x, 1)
|
|
else
|
|
call dlaset('f', 1, n, 0.0d0, 0.0d0, x, 1)
|
|
endif
|
|
|
|
end subroutine
|
|
************************************************************************
|
|
subroutine write_dat_file_for_amber
|
|
$(finalener,selfener,idens,natoms,ncent,grads,efield,
|
|
$dipx,dipy,dipz)
|
|
************************************************************************
|
|
* Write a formatted data file for the Amber interface
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
integer :: datoms,natoms,ncent,idens
|
|
real*8 :: grads(3,*)
|
|
real*8 :: efield(3,*)
|
|
real*8 :: selfener
|
|
real*8 :: finalener
|
|
real*8 :: dipx,dipy,dipz
|
|
C
|
|
open(scrfile1,file='mrcc_job.dat',form='formatted')
|
|
if(idens.gt.1) then
|
|
write(scrfile1,'(a)')
|
|
write(scrfile1,'(a)') 'Forces on QM atoms [Hartree/Bohr]'
|
|
do datoms=1,natoms
|
|
write(scrfile1,"(3e23.15)")
|
|
$ grads(1,datoms),grads(2,datoms),grads(3,datoms)
|
|
enddo
|
|
C Electric field
|
|
write(scrfile1,'(a)')
|
|
write(scrfile1,'(a)') 'Electric field at MM atoms'
|
|
do datoms=natoms+1,ncent
|
|
write(scrfile1,"(3e23.15)")
|
|
$ efield(1,datoms),efield(2,datoms),efield(3,datoms)
|
|
enddo
|
|
C Dipole moment
|
|
write(scrfile1,'(a)')
|
|
write(scrfile1,'(a)')
|
|
$'Magnitude of dipole moment vector [Debye]'
|
|
write(scrfile1,'(e23.15)')
|
|
$echesu*angtobohr*dsqrt(dipx**2+dipy**2+dipz**2)
|
|
write(scrfile1,'(a)')
|
|
$'Direction of dipole moment vector [Debye]'
|
|
write(scrfile1,'(3e23.15)')
|
|
$echesu*angtobohr*dipx,echesu*angtobohr*dipy,echesu*angtobohr*dipz
|
|
write(scrfile1,'(a)')
|
|
endif
|
|
write(scrfile1,'(a)')'Final energy of the QM region [AU]'
|
|
write(scrfile1,'(e23.15)') finalener
|
|
write(scrfile1,'(a)')'Self energy of the point charges [AU]'
|
|
write(scrfile1,'(e23.15)') selfener
|
|
close(scrfile1)
|
|
end subroutine write_dat_file_for_amber
|
|
C
|
|
************************************************************************
|
|
subroutine readh(r8heap,ifile,symtra,nbasis,offset,lsa)
|
|
************************************************************************
|
|
* Read core Hamiltonian
|
|
************************************************************************
|
|
implicit none
|
|
integer ifile,nbasis,offset
|
|
real*8 r8heap(*),symtra
|
|
logical lsa
|
|
C
|
|
open(ifile,file='OEINT',form='unformatted')
|
|
read(ifile)
|
|
call readone(r8heap,ifile,symtra,nbasis,r8heap(nbasis**2+1),
|
|
$offset,lsa)
|
|
close(ifile)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine readone(mat,ifile,symtra,nbasis,r8heap,offset,lsa)
|
|
************************************************************************
|
|
* Read and compress one-electron integrals
|
|
************************************************************************
|
|
implicit none
|
|
integer ifile,nbasis,offset,ii
|
|
real*8 mat(nbasis,nbasis),symtra(nbasis,nbasis),r8heap(*)
|
|
logical lsa
|
|
C
|
|
if(lsa) then
|
|
ii=nbasis*nbasis+1
|
|
call roeint(r8heap(ii),r8heap(ii),r8heap,ifile,nbasis)
|
|
call mxts(r8heap,symtra,r8heap(ii),nbasis,mat,offset,lsa)
|
|
else
|
|
call roeint(r8heap,r8heap,mat,ifile,nbasis)
|
|
endif
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mxts(mat1,symtra,r8heap,nbasis,mat2,offset,lsa)
|
|
************************************************************************
|
|
* Transform one-electron quantities to symmetry basis
|
|
************************************************************************
|
|
implicit none
|
|
integer nbasis,offset
|
|
real*8 mat1(nbasis,nbasis),mat2(nbasis,nbasis)
|
|
real*8 symtra(nbasis,nbasis),r8heap(*)
|
|
logical lsa
|
|
C
|
|
if(.not.lsa) return
|
|
call mx_basis_tr(mat1,symtra,r8heap,'TS',nbasis)
|
|
call mx_symm_compr(mat1,mat2,offset)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mxto(mat1,symtra,r8heap,nbasis,mat2,offset,lsa)
|
|
************************************************************************
|
|
* Transform one-electron quantities to symmetry basis
|
|
************************************************************************
|
|
implicit none
|
|
integer nbasis,offset
|
|
real*8 mat1(nbasis,nbasis),mat2(nbasis,nbasis)
|
|
real*8 symtra(nbasis,nbasis),r8heap(*)
|
|
logical lsa
|
|
C
|
|
if(.not.lsa) return
|
|
call mx_symm_extr(mat1,mat2,offset)
|
|
call mx_basis_tr(mat1,symtra,r8heap,'TO',nbasis)
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
subroutine mx_basis_tr(mx,symtra,r8heap,mode,lsize)
|
|
************************************************************************
|
|
* subroutine to symmetrise matrices with transformation
|
|
* matrix from symtra file (running in destructive mode)
|
|
************************************************************************
|
|
implicit none
|
|
c arguments
|
|
real*8 mx(lsize**2) !non compressed input/output matrix
|
|
real*8 symtra(lsize**2) !symmetry transformation matrix
|
|
real*8 r8heap(*) !workspace
|
|
character*2 mode
|
|
integer lsize !linear size of matrices
|
|
c variables
|
|
character*1 lmx,rmx
|
|
c program
|
|
select case (mode)
|
|
case ('ts','TS','Ts','tS')
|
|
lmx='t'
|
|
rmx='n'
|
|
case ('to','TO','To','tO')
|
|
lmx='n'
|
|
rmx='t'
|
|
case default
|
|
write(*,*) ' @mx_basis_tr: ERROR'
|
|
write(*,*) ' unknown transformation mode'
|
|
write(*,*) ' last argument of subroutine'
|
|
return
|
|
end select
|
|
c multiply from right
|
|
call dgemm(
|
|
& 'n',
|
|
& rmx,
|
|
& lsize,
|
|
& lsize,
|
|
& lsize,
|
|
& 1.d0,
|
|
& mx,
|
|
& lsize,
|
|
& symtra,
|
|
& lsize,
|
|
& 0.d0,
|
|
& r8heap,
|
|
& lsize)
|
|
c multiply from left
|
|
call dgemm(
|
|
& lmx,
|
|
& 'n',
|
|
& lsize,
|
|
& lsize,
|
|
& lsize,
|
|
& 1.d0,
|
|
& symtra,
|
|
& lsize,
|
|
& r8heap,
|
|
& lsize,
|
|
& 0.d0,
|
|
& mx,
|
|
& lsize)
|
|
c
|
|
return
|
|
end
|
|
|
|
************************************************************************
|
|
subroutine mx_symm_extr(full_mx,compr_mx,offset)
|
|
************************************************************************
|
|
* subroutine to extract a matrix from blockdiagonal storage format
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
#include "SCFCOMMON"
|
|
c arguments
|
|
real*8 full_mx(nbasis,nbasis)
|
|
real*8 compr_mx(sqrsize)
|
|
integer offset(*)
|
|
c scalar variables
|
|
integer pivot
|
|
integer ii,jj,kk
|
|
c program
|
|
call dfillzero(full_mx,nbasis**2)
|
|
pivot=1
|
|
do kk=1,nir
|
|
if(nfunc(kk).eq.0) cycle
|
|
do jj=1,nfunc(kk)
|
|
do ii=1,nfunc(kk)
|
|
full_mx(offset(kk)-1+ii,offset(kk)-1+jj)=compr_mx(pivot)
|
|
pivot=pivot+1
|
|
enddo
|
|
enddo
|
|
enddo
|
|
c
|
|
return
|
|
end
|
|
|
|
************************************************************************
|
|
subroutine mx_symm_compr(full_mx,compr_mx,offset)
|
|
************************************************************************
|
|
* subroutine to comprass a matrix into blockdiagonal storage format
|
|
************************************************************************
|
|
#include "MRCCCOMMON"
|
|
#include "SCFCOMMON"
|
|
c arguments
|
|
real*8 full_mx(nbasis,nbasis)
|
|
real*8 compr_mx(sqrsize)
|
|
integer offset(*)
|
|
c scalar variables
|
|
integer pivot
|
|
integer ii,jj,kk
|
|
c program
|
|
pivot=1
|
|
do kk=1,nir
|
|
if(nfunc(kk).eq.0) cycle
|
|
do jj=1,nfunc(kk)
|
|
do ii=1,nfunc(kk)
|
|
compr_mx(pivot)=full_mx(offset(kk)-1+ii,offset(kk)-1+jj)
|
|
pivot=pivot+1
|
|
enddo
|
|
enddo
|
|
enddo
|
|
c
|
|
return
|
|
end
|
|
************************************************************************
|
|
subroutine nactorb(corb,n)
|
|
************************************************************************
|
|
* Calculates the number of active/doubly occupied MCSCF orbitals
|
|
************************************************************************
|
|
implicit none
|
|
integer n,m,i,ii
|
|
character(len=1) line2(16),line3(512)
|
|
character(len=16) line1
|
|
character(len=512) line
|
|
character(len=4) corb
|
|
equivalence(line,line3)
|
|
equivalence(line1,line2)
|
|
C
|
|
line3=' '
|
|
call getkey(corb,4,line3,512)
|
|
n=0
|
|
ii=0
|
|
line2=' '
|
|
do i=1,len(line)
|
|
select case(line3(i))
|
|
case ('0','1','2','3','4','5','6','7','8','9')
|
|
ii=ii+1
|
|
line2(ii)=line3(i)
|
|
case (',')
|
|
read(line1,*) m
|
|
n=n+m
|
|
ii=0
|
|
line2=' '
|
|
case default
|
|
exit
|
|
end select
|
|
enddo
|
|
read(line1,*) m
|
|
n=n+m
|
|
C
|
|
return
|
|
end
|
|
C
|
|
************************************************************************
|
|
module error_handler
|
|
************************************************************************
|
|
* Error handling for various run-time problems.
|
|
* It is intended to give more informative feedbacks to the user
|
|
* while keeping programming duties minimal.
|
|
* 2023-05-12 Bence Hégely
|
|
************************************************************************
|
|
save
|
|
integer :: out_channel
|
|
interface out_of_range_error
|
|
module procedure out_of_range_error_limited_int
|
|
module procedure out_of_range_error_unlimited_int
|
|
module procedure out_of_range_error_limited_real
|
|
module procedure out_of_range_error_unlimited_real
|
|
module procedure out_of_range_error_limited_mixed_lowreal
|
|
module procedure out_of_range_error_limited_mixed_lowint
|
|
end interface
|
|
interface illegal_value_error
|
|
module procedure illegal_value_error_int
|
|
module procedure illegal_value_error_char
|
|
end interface
|
|
!
|
|
contains
|
|
!
|
|
subroutine init_error_handler( iout )
|
|
out_channel = iout
|
|
end subroutine
|
|
!
|
|
subroutine failed_memop(varname,memoptype)
|
|
implicit none
|
|
integer :: memoptype
|
|
character(len=*) :: varname
|
|
if(memoptype.eq.1) then
|
|
write(out_channel,"(a,a,a)")
|
|
$" Memory allocation is failed for variable: '",
|
|
$trim(adjustl(varname)),"'"
|
|
else if(memoptype.eq.2) then
|
|
write(out_channel,"(a,a,a)")
|
|
$" Memory deallocation is failed for variable: '",
|
|
$trim(adjustl(varname)),"'"
|
|
endif
|
|
call mrccend(1)
|
|
end subroutine failed_memop
|
|
!
|
|
subroutine io_error(inpstring,source)
|
|
implicit none
|
|
character(len=*) :: inpstring
|
|
character(len=*) :: source
|
|
write(out_channel,'(a)') ' An error occured during IO operation!'
|
|
write(out_channel,'(5a)') ' (',inpstring,' @ ',source,')'
|
|
call mrccend(1)
|
|
end subroutine io_error
|
|
!
|
|
subroutine out_of_range_error_limited_int
|
|
$(message,upper,ubound_in,lower,lbound_in)
|
|
implicit none
|
|
character(len=*),intent(in) :: message
|
|
integer, intent(in) :: upper
|
|
integer, intent(in) :: lower
|
|
logical, intent(in) :: ubound_in
|
|
logical, intent(in) :: lbound_in
|
|
character(len=32) :: cupper
|
|
character(len=32) :: clower
|
|
character(len=1 ) :: c1u
|
|
character(len=1 ) :: c1l
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( lbound_in) c1l = '['
|
|
if(.not.lbound_in) c1l = '('
|
|
if( ubound_in) c1u = ']'
|
|
if(.not.ubound_in) c1u = ')'
|
|
write(cupper,*) upper
|
|
write(clower,*) lower
|
|
write(out_channel,*)
|
|
$ c1l,trim(adjustl(clower)),',',trim(adjustl(cupper)),c1u
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_limited_int
|
|
!
|
|
subroutine out_of_range_error_unlimited_int
|
|
$(message,bound_type,bound,bound_in)
|
|
implicit none
|
|
character(len=*),intent(in) :: message
|
|
character(len=1 ),intent(in) :: bound_type
|
|
integer, intent(in) :: bound
|
|
logical, intent(in) :: bound_in
|
|
character(len=32) :: cbound
|
|
character(len=1 ) :: c1b
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( bound_type .eq. 'u' ) then
|
|
if( bound_in) c1b = ']'
|
|
if(.not.bound_in) c1b = ')'
|
|
write(cbound,*) bound
|
|
write(out_channel,*) '(-INFINITY,',trim(adjustl(cbound)),c1b
|
|
else if( bound_type .eq. 'l' ) then
|
|
if( bound_in) c1b = '['
|
|
if(.not.bound_in) c1b = '('
|
|
write(cbound,*) bound
|
|
write(out_channel,*) c1b,trim(adjustl(cbound)),',+INFINITY)'
|
|
else
|
|
write(6,*) ' Cannot show bounds.'
|
|
endif
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_unlimited_int
|
|
!
|
|
subroutine out_of_range_error_limited_real
|
|
$(message,upper,ubound_in,lower,lbound_in)
|
|
implicit none
|
|
character(len=*), intent(in) :: message
|
|
double precision, intent(in) :: upper
|
|
double precision, intent(in) :: lower
|
|
logical, intent(in) :: ubound_in
|
|
logical, intent(in) :: lbound_in
|
|
character(len=32) :: cupper
|
|
character(len=32) :: clower
|
|
character(len=1 ) :: c1u
|
|
character(len=1 ) :: c1l
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( lbound_in) c1l = '['
|
|
if(.not.lbound_in) c1l = '('
|
|
if( ubound_in) c1u = ']'
|
|
if(.not.ubound_in) c1u = ')'
|
|
write(cupper,*) upper
|
|
write(clower,*) lower
|
|
write(out_channel,*)
|
|
$ c1l,trim(adjustl(clower)),',',trim(adjustl(cupper)),c1u
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_limited_real
|
|
!
|
|
subroutine out_of_range_error_unlimited_real
|
|
$(message,bound_type,bound,bound_in)
|
|
implicit none
|
|
character(len=*), intent(in) :: message
|
|
character(len=1 ), intent(in) :: bound_type
|
|
double precision , intent(in) :: bound
|
|
logical, intent(in) :: bound_in
|
|
character(len=32) :: cbound
|
|
character(len=1 ) :: c1b
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( bound_type .eq. 'u' ) then
|
|
if( bound_in) c1b = ']'
|
|
if(.not.bound_in) c1b = ')'
|
|
write(cbound,*) bound
|
|
write(out_channel,*) '(-INFINITY,',trim(adjustl(cbound)),c1b
|
|
else if( bound_type .eq. 'l' ) then
|
|
if( bound_in) c1b = '['
|
|
if(.not.bound_in) c1b = '('
|
|
write(cbound,*) bound
|
|
write(out_channel,*) c1b,trim(adjustl(cbound)),',+INFINITY)'
|
|
else
|
|
write(out_channel,*) ' Cannot show bounds.'
|
|
endif
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_unlimited_real
|
|
!
|
|
subroutine out_of_range_error_limited_mixed_lowreal
|
|
$(message,upper,ubound_in,lower,lbound_in)
|
|
implicit none
|
|
character(len=*), intent(in) :: message
|
|
integer , intent(in) :: upper
|
|
double precision, intent(in) :: lower
|
|
logical, intent(in) :: ubound_in
|
|
logical, intent(in) :: lbound_in
|
|
character(len=32) :: cupper
|
|
character(len=32) :: clower
|
|
character(len=1 ) :: c1u
|
|
character(len=1 ) :: c1l
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( lbound_in) c1l = '['
|
|
if(.not.lbound_in) c1l = '('
|
|
if( ubound_in) c1u = ']'
|
|
if(.not.ubound_in) c1u = ')'
|
|
write(cupper,*) upper
|
|
write(clower,*) lower
|
|
write(out_channel,*)
|
|
$ c1l,trim(adjustl(clower)),',',trim(adjustl(cupper)),c1u
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_limited_mixed_lowreal
|
|
!
|
|
subroutine out_of_range_error_limited_mixed_lowint
|
|
$(message,upper,ubound_in,lower,lbound_in)
|
|
implicit none
|
|
character(len=*), intent(in) :: message
|
|
double precision, intent(in) :: upper
|
|
integer , intent(in) :: lower
|
|
logical, intent(in) :: ubound_in
|
|
logical, intent(in) :: lbound_in
|
|
character(len=32) :: cupper
|
|
character(len=32) :: clower
|
|
character(len=1 ) :: c1u
|
|
character(len=1 ) :: c1l
|
|
write(out_channel,'(a)') ' Out of bounds error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Legal range: '
|
|
if( lbound_in) c1l = '['
|
|
if(.not.lbound_in) c1l = '('
|
|
if( ubound_in) c1u = ']'
|
|
if(.not.ubound_in) c1u = ')'
|
|
write(cupper,*) upper
|
|
write(clower,*) lower
|
|
write(out_channel,*)
|
|
$ c1l,trim(adjustl(clower)),',',trim(adjustl(cupper)),c1u
|
|
call mrccend(1)
|
|
end subroutine out_of_range_error_limited_mixed_lowint
|
|
!
|
|
subroutine illegal_value_error_int
|
|
$( message , actual , expected )
|
|
character(len=*), intent(in) :: message
|
|
integer, intent(in) :: actual
|
|
integer, intent(in) :: expected
|
|
write(out_channel,'(a)') ' Illegal value error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Expected:'
|
|
write(out_channel,*) expected
|
|
write(out_channel,'(a)',advance='no') ' Actual:'
|
|
write(out_channel,*) actual
|
|
call mrccend(1)
|
|
end subroutine illegal_value_error_int
|
|
!
|
|
subroutine illegal_value_error_char
|
|
$( message , actual , expected )
|
|
character(len=*), intent(in) :: message
|
|
character(len=*), intent(in) :: actual
|
|
character(len=*), intent(in) :: expected
|
|
write(out_channel,'(a)') ' Illegal value error.'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)',advance='no') ' Expected:'
|
|
write(out_channel,*) expected
|
|
write(out_channel,'(a)',advance='no') ' Actual:'
|
|
write(out_channel,*) actual
|
|
call mrccend(1)
|
|
end subroutine illegal_value_error_char
|
|
!
|
|
subroutine no_implementation_error( message )
|
|
character(len=*), intent(in) :: message
|
|
write(out_channel,'(a)') ' Expected feature is not implemented:'
|
|
write(out_channel,'(a)') message
|
|
write(out_channel,'(a)')
|
|
$' This state of the program will produce an undefined behavior.'
|
|
write(out_channel,'(2a)') ' The program will stop.'
|
|
call mrccend(1)
|
|
end subroutine no_implementation_error
|
|
!
|
|
end module error_handler
|
|
C
|
|
subroutine oslccversioncheck(localcc,scftype,mult,calc,iout)
|
|
implicit none
|
|
integer localccn,iout
|
|
character*4 localcc,mult
|
|
character*5 scftype
|
|
character*32 calc
|
|
logical lanycc
|
|
|
|
if (localcc.eq.'off ') then
|
|
localccn=0
|
|
else
|
|
read(localcc,*) localccn
|
|
endif
|
|
|
|
if(localccn.le.2021.and.localcc.ne.'off '.and.
|
|
$ ((scftype.ne.'rhf '.and.scftype.ne.' ').or.
|
|
$ (mult.ne.' '.and.mult.ne.'1 '))) then
|
|
if(localccn.lt.2022.and.lanycc(calc)) then
|
|
write(iout,"(a60)")
|
|
$ 'Error: Open-shell LNO-CC is only available via localcc>2021!'
|
|
call mrccend(1)
|
|
elseif(localccn.lt.2021.and..not.lanycc(calc)) then
|
|
write(iout,"(a60)")
|
|
$ 'Error: Open-shell LMP2 is only available via localcc>=2021!'
|
|
call mrccend(1)
|
|
endif
|
|
endif
|
|
|
|
end subroutine oslccversioncheck
|