1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
|
!***********************************************************************
! This file is part of OpenMolcas. *
! *
! OpenMolcas is free software; you can redistribute it and/or modify *
! it under the terms of the GNU Lesser General Public License, v. 2.1. *
! OpenMolcas is distributed in the hope that it will be useful, but it *
! is provided "as is" and without any express or implied warranties. *
! For more details see the full text of the license in the file *
! LICENSE or in <http://www.gnu.org/licenses/>. *
!***********************************************************************
SUBROUTINE CASPT2_AXB(PSI,F,NMO,ONEINT,TWOINT)
! Computes the CASPT2 second-order energy of the wavefunction PSI, provided
! that the full Fock matrix and necessary 1- and 2-el integrals are given.
USE ISO_FORTRAN_ENV, ONLY: REAL64
USE SECOND_QUANTIZATION
USE WAVEFUNCTION
USE DENSITY
USE FOCKMATRIX
USE ORBINT
IMPLICIT NONE
TYPE(WFN), INTENT(IN) :: PSI
TYPE(FMAT), INTENT(IN) :: F
INTEGER, INTENT(IN) :: NMO
REAL(REAL64), INTENT(IN) :: ONEINT(NMO,NMO), TWOINT(NMO,NMO,NMO,NMO)
INTEGER :: NI, NA, NS
INTEGER :: NACTEL, NTOTEL, MULT
REAL(REAL64), ALLOCATABLE :: FTOT(:,:)
TYPE(WFN) :: PSI1, SGM, TAU
REAL(REAL64), ALLOCATABLE :: D1(:,:), D2(:,:,:,:)
REAL(REAL64) :: FACT
REAL(REAL64), ALLOCATABLE :: VPQRS(:,:,:,:), V0(:), X(:)
REAL(REAL64), ALLOCATABLE :: H0(:,:), S0(:,:), U0(:,:), T0(:,:)
REAL(REAL64), ALLOCATABLE :: TMP(:,:), TMPV(:)
REAL(REAL64) :: E0, E2
INTEGER :: ISD, JSD, NSD, MSD
REAL(REAL64), ALLOCATABLE :: PSI1BRA(:,:,:), PSI1KET(:,:,:), FOCKKET(:,:,:)
REAL(REAL64), ALLOCATABLE :: WORK(:), EVAL(:)
INTEGER :: NWORK, INFO
INTEGER, ALLOCATABLE :: IPIV(:)
INTEGER :: I, J, P, Q, R, S, IA, IB
INTEGER :: DETA, DETB, TMPA, TMPB
REAL(REAL64), EXTERNAL :: DNRM2_, DDOT_
! get appropriate orbital space dimensions from the supplied Fock matrix
NI=SIZE(F%II,1)
NA=SIZE(F%AA,1)
NS=SIZE(F%SS,1)
#ifdef _DEBUG_
WRITE(*,'(1X,A,I6)') '#inactive orbitals = ', NI
WRITE(*,'(1X,A,I6)') '#active orbitals = ', NA
WRITE(*,'(1X,A,I6)') '#secondary orbitals = ', NS
WRITE(*,'(1X,A,I6)') '#molecular orbitals = ', NMO
#endif
! some sanity checks
IF (PSI%NORB.NE.NA) STOP 'CASPT2_AXB: PSI%NORB does not match #active orbitals'
IF (NMO.NE.NI+NA+NS) STOP 'CASPT2_AXB: supplied total #orbitals does not compute'
NACTEL=PSI%NEL
NTOTEL=2*NI+NACTEL
MULT=PSI%MULT
! put Fock matrix in general matrix format
ALLOCATE(FTOT(NMO,NMO))
CALL FMAT_COPY(F,FTOT,NMO)
! first, set up PSI1 as a (sparse) full-CI wavefunction for which we will use
! projectors to handle the restriction of single-double replacement states
CALL WFN_INIT(PSI1,NTOTEL,NMO,MULT)
PSI1%COEF=0.0D0
CALL WFN_COPY0(NI,PSI,PSI1)
#ifdef _DEBUG_
WRITE(*,'(1X,A)') 'The 0th-order wavefunction in FCI space:'
CALL WFN_PRINT(PSI1,1.0D-15)
#endif
! compute the CASSCF energy for the 0-th order wavefunction
ALLOCATE(D1(NMO,NMO))
ALLOCATE(D2(NMO,NMO,NMO,NMO))
CALL D1_ANN(PSI1,D1)
CALL D2_ANN(PSI1,D2)
CALL WFN_ENERGY(0,NMO,0,D1,D2,ONEINT,TWOINT)
CALL WFN_INIT(SGM,NTOTEL,NMO,MULT)
CALL WFN_INIT(TAU,NTOTEL,NMO,MULT)
! set up the equation system Ax=b as (H0 -E0*S0) X = -V0 with:
! H0_ij = <i|Ĥ_0|j>
! E0 = <0|Ĥ_0|0>
! S0_ij = <i|j>
! V0_i = <i|Ĥ|0>
! |i>, |j> = P_SD Ê_pqrs |0>
! First, compute the 0-th order energy and construct the right hand side
! vector -V0, which is computed for each |i> that is non-zero. This still
! leaves an overcomplete basis for the VSD space, but that is solved later by
! diagonalization of S0 and removal of any linear dependency before solving
! Ax=b.
! step 1: |TAU> = Ĥ|0>; |SGM> = Ĥ_0|0>
TAU%COEF=0.0D0
SGM%COEF=0.0D0
DETB=LEX_INIT(PSI%NELB,PSI%NORB)
DO IB=1,PSI%NDETB
TMPB=ISHFT(DETB,NI)+(2**NI-1)
DETA=LEX_INIT(PSI%NELA,PSI%NORB)
DO IA=1,PSI%NDETA
TMPA=ISHFT(DETA,NI)+(2**NI-1)
FACT=PSI%COEF(IA,IB)
DO P=1,NMO
DO Q=1,NMO
! h_pq, g_pqrs for TAU
CALL DET_EX1(FACT*ONEINT(P,Q),P,Q,TMPA,TMPB,TAU)
DO R=1,NMO
DO S=1,NMO
CALL DET_EX2(FACT*0.5D0*TWOINT(P,Q,R,S),P,Q,R,S,TMPA,TMPB,TAU)
END DO
END DO
! f_pq for SGM
CALL DET_EX1(FACT*FTOT(P,Q),P,Q,TMPA,TMPB,SGM)
END DO
END DO
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
#ifdef _DEBUG_
WRITE(*,'(1X,A)') 'wavefunction Ĥ|0>'
CALL WFN_PRINT(TAU,1.0D-6)
WRITE(*,'(1X,A)') 'wavefunction Ĥ_0|0>'
CALL WFN_PRINT(SGM,1.0D-6)
#endif
! step 2: compute 0-th order energy E0 = <0|SGM>
E0 = 0.0D0
DETB=LEX_INIT(PSI%NELB,PSI%NORB)
DO IB=1,PSI%NDETB
TMPB=ISHFT(DETB,NI)+(2**NI-1)
DETA=LEX_INIT(PSI%NELA,PSI%NORB)
DO IA=1,PSI%NDETA
TMPA=ISHFT(DETA,NI)+(2**NI-1)
E0 = E0 + PSI%COEF(IA,IB) * SGM%COEF(RANK_(TMPA),RANK_(TMPB))
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
WRITE(*,'(1X,A32,F21.14)') "0-th order energy E0 = ", E0
! step 3: construct V0 = <i|TAU>, store the computed functions |i> in PSI1KET
! and PSI1BRA
ALLOCATE(VPQRS(NMO,NMO,NMO,NMO))
NSD=0
VPQRS=0.0D0
DO S=1,NMO
DO R=1,NMO
DO Q=1,NMO
DO P=1,NMO
! determine |i> = E_pqrs |Psi0>
SGM%COEF=0.0D0
DETB=LEX_INIT(PSI%NELB,PSI%NORB)
DO IB=1,PSI%NDETB
TMPB=ISHFT(DETB,NI)+(2**NI-1)
DETA=LEX_INIT(PSI%NELA,PSI%NORB)
DO IA=1,PSI%NDETA
TMPA=ISHFT(DETA,NI)+(2**NI-1)
CALL DET_EX2(PSI%COEF(IA,IB),P,Q,R,S,TMPA,TMPB,SGM)
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
PSI1%COEF=0.0D0
CALL WFN_PSD(NI,NA,NS,SGM,PSI1)
IF (DNRM2_(PSI1%NDET,PSI1%COEF,1).NE.0.0D0) THEN
VPQRS(P,Q,R,S)=DDOT_(PSI1%NDET,PSI1%COEF,1,TAU%COEF,1)
NSD=NSD+1
END IF
END DO
END DO
END DO
END DO
ALLOCATE(V0(NSD))
ISD=0
DO S=1,NMO
DO R=1,NMO
DO Q=1,NMO
DO P=1,NMO
IF (ABS(VPQRS(P,Q,R,S)).GT.0.0D0) THEN
ISD=ISD+1
V0(ISD)=VPQRS(P,Q,R,S)
END IF
END DO
END DO
END DO
END DO
! Now compute H0 and S0 matrices
ALLOCATE(H0(NSD,NSD))
ALLOCATE(S0(NSD,NSD))
H0 = 0.0D0
S0 = 0.0D0
ALLOCATE(PSI1BRA(NSD,PSI1%NDETA,PSI1%NDETB))
ALLOCATE(PSI1KET(PSI1%NDETA,PSI1%NDETB,NSD))
ALLOCATE(FOCKKET(PSI1%NDETA,PSI1%NDETB,NSD))
ISD=0
DO S=1,NMO
DO R=1,NMO
DO Q=1,NMO
DO P=1,NMO
SGM%COEF=0.0D0
! determine |i> = E_pqrs |Psi0>
DETB=LEX_INIT(PSI%NELB,PSI%NORB)
DO IB=1,PSI%NDETB
TMPB=ISHFT(DETB,NI)+(2**NI-1)
DETA=LEX_INIT(PSI%NELA,PSI%NORB)
DO IA=1,PSI%NDETA
TMPA=ISHFT(DETA,NI)+(2**NI-1)
CALL DET_EX2(PSI%COEF(IA,IB),P,Q,R,S,TMPA,TMPB,SGM)
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
PSI1%COEF=0.0D0
CALL WFN_PSD(NI,NA,NS,SGM,PSI1)
IF (DNRM2_(PSI1%NDET,PSI1%COEF,1).NE.0.0D0) THEN
ISD=ISD+1
! put |i> = E_pqrs |0> into PSI1BRA and PSI1KET
PSI1BRA(ISD,:,:) = PSI1%COEF
PSI1KET(:,:,ISD) = PSI1%COEF
! compute Ĥ_0|i> = Sum_ij f_ij Ê_ij |i>
SGM%COEF=0.0D0
DETB=LEX_INIT(PSI1%NELB,PSI1%NORB)
DO IB=1,PSI1%NDETB
DETA=LEX_INIT(PSI1%NELA,PSI1%NORB)
DO IA=1,PSI1%NDETA
DO J=1,NMO
DO I=1,NMO
! accumulate F_ij Ê_ij |i>
CALL DET_EX1(PSI1%COEF(IA,IB)*FTOT(I,J),I,J,DETA,DETB,SGM)
END DO
END DO
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
! put Ĥ_0|i> into FOCKKET
FOCKKET(:,:,ISD) = SGM%COEF
END IF
END DO
END DO
END DO
END DO
CALL DGEMM_('N','N',NSD,NSD,PSI1%NDET,1.0D0, &
& PSI1BRA,NSD,PSI1KET,PSI1%NDET, &
& 0.0D0,S0,NSD)
CALL DGEMM_('N','N',NSD,NSD,PSI1%NDET,1.0D0, &
& PSI1BRA,NSD,FOCKKET,PSI1%NDET, &
& 0.0D0,H0,NSD)
DEALLOCATE(PSI1BRA)
DEALLOCATE(PSI1KET)
DEALLOCATE(FOCKKET)
! remove linear dependencies by diagonalizing the overlap matrix, construct a
! transformation matrix to orthogonal basis, and transform S0, H0 and V0
! accordingly
ALLOCATE(U0(NSD,NSD))
U0(:,:)=S0
NWORK=NSD**2
ALLOCATE(WORK(NWORK))
ALLOCATE(EVAL(NSD))
call dsyev_('V','U',NSD,U0,NSD,EVAL,WORK,NWORK,INFO)
IF (INFO.NE.0) STOP 'CASPT2_UDL: diagonalization of S0 failed'
! go through columns of U0, keep non-zero eigenvalues
MSD=0
DO ISD=1,NSD
IF (EVAL(ISD).GT.1.0D-6) THEN
MSD=MSD+1
END IF
END DO
WRITE(*,'(1X,A,I6)') '#non-zero overlap eigenvalues = ', MSD
ALLOCATE(T0(NSD,MSD))
ISD=0
DO JSD=1,NSD
IF (EVAL(JSD).GT.1.0D-6) THEN
ISD=ISD+1
T0(:,ISD) = U0(:,JSD)/SQRT(EVAL(JSD))
END IF
END DO
! transform equation system
ALLOCATE(TMP(NSD,MSD))
TMP(:,:) = MATMUL(H0,T0)
H0(1:MSD,1:MSD) = MATMUL(TRANSPOSE(T0),TMP)
TMP(:,:) = MATMUL(S0,T0)
S0(1:MSD,1:MSD) = MATMUL(TRANSPOSE(T0),TMP)
DEALLOCATE(TMP)
! Solve (H0 - E0 S0) X = -V0
H0(:,:) = H0 - E0 * S0
ALLOCATE(IPIV(NSD))
! solution vector is initially filled with the RHS = -V0
ALLOCATE(X(NSD))
X(1:MSD) = -1.0D0 * MATMUL(TRANSPOSE(T0),V0)
call dgesv_(MSD,1,H0,NSD,IPIV,X,NSD,INFO)
IF (INFO.NE.0) THEN
WRITE(*,*) 'INFO = ', INFO
STOP 'Failed to solve linear equation system'
END IF
ALLOCATE(TMPV(NSD))
TMPV(:) = MATMUL(T0,X(1:MSD))
X(:) = TMPV
DEALLOCATE(TMPV)
! compute the energy
! method 1: E2 = <V0|X>
E2 = DDOT_(NSD,V0,1,X,1)
WRITE(*,'(1X,A32,F21.14)') 'E2 as <V0|X> = ', E2
! method 2: E2 = <0|Ĥ|Psi1>
! first, form the first-order wavefunction |Psi1>
ISD=0
SGM%COEF=0.0D0
DO S=1,NMO
DO R=1,NMO
DO Q=1,NMO
DO P=1,NMO
IF (VPQRS(P,Q,R,S).NE.0.0D0) THEN
ISD=ISD+1
DETB=LEX_INIT(PSI%NELB,PSI%NORB)
DO IB=1,PSI%NDETB
TMPB=ISHFT(DETB,NI)+(2**NI-1)
DETA=LEX_INIT(PSI%NELA,PSI%NORB)
DO IA=1,PSI%NDETA
TMPA=ISHFT(DETA,NI)+(2**NI-1)
CALL DET_EX2(PSI%COEF(IA,IB)*X(ISD),P,Q,R,S,TMPA,TMPB,SGM)
DETA=LEX_NEXT(DETA)
END DO
DETB=LEX_NEXT(DETB)
END DO
END IF
END DO
END DO
END DO
END DO
PSI1%COEF=0.0D0
CALL WFN_PSD(NI,NA,NS,SGM,PSI1)
!WRITE(*,*) 'Final first-order wavefunction from Ax=b method:'
!CALL WFN_PRINT(PSI1,1.0D-8)
! TAU still contains Ĥ|0>, so contract with |Psi1>
E2 = DDOT_(PSI1%NDET,PSI1%COEF,1,TAU%COEF,1)
WRITE(*,'(1X,A32,F21.14)') 'E2 as <Psi1|H|0> = ', E2
END SUBROUTINE
|