1!--------------------------------------------------------------------------------------------------! 2! DFTB+: general package for performing fast atomistic simulations ! 3! Copyright (C) 2006 - 2019 DFTB+ developers group ! 4! ! 5! See the LICENSE file for terms of usage and distribution. ! 6!--------------------------------------------------------------------------------------------------! 7 8#:include 'common.fypp' 9 10!> Linear response excitations and gradients with respect to atomic coordinates 11module dftbp_linrespgrad 12 use dftbp_assert 13 use dftbp_arpack 14 use dftbp_linrespcommon 15 use dftbp_commontypes 16 use dftbp_slakocont 17 use dftbp_shortgamma 18 use dftbp_accuracy 19 use dftbp_constants, only : Hartree__eV, au__Debye 20 use dftbp_nonscc, only : NonSccDiff 21 use dftbp_scc, only : TScc 22 use dftbp_blasroutines 23 use dftbp_eigensolver 24 use dftbp_message 25 use dftbp_taggedoutput, only : TTaggedWriter, tagLabels 26 use dftbp_sorting 27 use dftbp_qm 28 use dftbp_transcharges 29 implicit none 30 private 31 32 public :: LinRespGrad_old 33 34 35 !> Tolerance for ARPACK solver. 36 real(dp), parameter :: ARTOL = epsilon(1.0_rsp) 37 38 39 !> Maximal allowed iteration in the ARPACK solver. 40 integer, parameter :: MAX_AR_ITER = 300 41 42 character(lc) :: tmpStr 43 44 45 !> Names of output files 46 character(*), parameter :: arpackOut = "ARPACK.DAT" 47 character(*), parameter :: testArpackOut = "TEST_ARPACK.DAT" 48 character(*), parameter :: transitionsOut = "TRA.DAT" 49 character(*), parameter :: XplusYOut = "XplusY.DAT" 50 character(*), parameter :: excitedQOut = "XCH.DAT" 51 character(*), parameter :: excitedDipoleOut = "XREST.DAT" 52 character(*), parameter :: excitedCoefsOut = "COEF.DAT" 53 character(*), parameter :: excitationsOut = "EXC.DAT" 54 character(*), parameter :: transDipOut = "TDP.DAT" 55 character(*), parameter :: singlePartOut = "SPX.DAT" 56 57 58 !> Communication with ARPACK for progress information 59 integer :: logfil, ndigit, mgetv0 60 integer :: msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd 61 integer :: mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd 62 integer :: mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd 63 64 65 !> Common block of ARPACK variables 66 common /debug/ logfil, ndigit, mgetv0,& 67 & msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,& 68 & mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,& 69 & mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd 70 71contains 72 73 74 !> This subroutine analytically calculates excitations and gradients of excited state energies 75 !> based on Time Dependent DFRT 76 subroutine LinRespGrad_old(tSpin, natom, iAtomStart, grndEigVecs, grndEigVal, sccCalc, dq,& 77 & coord0, nexc, nstat0, symc, SSqr, filling, species0, HubbardU, spinW, rnel, iNeighbour,& 78 & img2CentCell, orb, tWriteTagged, fdTagged, taggedWriter, fdMulliken, fdCoeffs, tGrndState,& 79 & fdXplusY, fdTrans, fdSPTrans, fdTradip, tArnoldi, fdArnoldi, fdArnoldiDiagnosis, fdExc, & 80 & tEnergyWindow, energyWindow, tOscillatorWindow, oscillatorWindow, tCacheCharges, omega,& 81 & allOmega, onsMEs, shift, skHamCont, skOverCont, excgrad, derivator, rhoSqr, occNatural,& 82 & naturalOrbs) 83 84 !> spin polarized calculation 85 logical, intent(in) :: tSpin 86 87 !> number of atoms 88 integer, intent(in) :: natom 89 90 !> index vector for S and H matrices 91 integer, intent(in) :: iAtomStart(:) 92 93 !> ground state MO-coefficients 94 real(dp), intent(in) :: grndEigVecs(:,:,:) 95 96 !> ground state MO-energies 97 real(dp), intent(in) :: grndEigVal(:,:) 98 99 !> Self-consistent charge module settings 100 type(TScc), intent(in) :: sccCalc 101 102 !> converged ground state Mulliken gross charges - atomic charges 103 real(dp), intent(in) :: dq(:) 104 105 !> atomic positions 106 real(dp), intent(in) :: coord0(:,:) 107 108 !> number of excited states to solve for 109 integer, intent(in) :: nexc 110 111 !> state of interest (< 0 find brightest, 0 calculate all nexc states, > 0 that specific state) 112 integer, intent(in) :: nstat0 113 114 !> symmetry required singlet ('S'), triplet ("T") or both ("B") 115 character, intent(in) :: symc 116 117 !> square overlap matrix between basis functions, both triangles required 118 real(dp), intent(in) :: SSqr(:,:) 119 120 !> occupations for the states 121 real(dp), intent(in) :: filling(:,:) 122 123 !> chemical species of each atom 124 integer, intent(in) :: species0(:) 125 126 !> ground state Hubbard U values for each species 127 real(dp), intent(in) :: HubbardU(:) 128 129 !> ground state spin derivatives for each species 130 real(dp), intent(in) :: spinW(:) 131 132 !> real number of electrons in system 133 real(dp), intent(in) :: rnel 134 135 !> Atomic neighbour lists 136 integer, intent(in) :: iNeighbour(0:,:) 137 138 !> Mapping of atom number to central cell atom number 139 integer, intent(in) :: img2CentCell(:) 140 141 !> data type for atomic orbital information 142 type(TOrbitals), intent(in) :: orb 143 144 !> print tag information 145 logical, intent(in) :: tWriteTagged 146 147 !> file descriptor for the tagged data output 148 integer, intent(in) :: fdTagged 149 150 !> tagged writer 151 type(TTaggedWriter), intent(inout) :: taggedWriter 152 153 !> file unit for excited Mulliken populations? 154 integer, intent(in) :: fdMulliken 155 156 !> file unit if the coefficients for the excited states should be written to disc 157 integer, intent(in) :: fdCoeffs 158 159 !> Add the ground state to the excited state transition density matrix when determining the 160 !> natural orbitals 161 logical, intent(in) :: tGrndState 162 163 !> file for X+Y data 164 integer, intent(in) :: fdXplusY 165 166 !> File unit for single particle (KS) transitions if required 167 integer, intent(in) :: fdTrans 168 169 !> File unit for single particle transition dipole strengths 170 integer, intent(in) :: fdSPTrans 171 172 !> File unit for transition dipole data 173 integer, intent(in) :: fdTradip 174 175 !> write state of Arnoldi solver to disc 176 logical, intent(in) :: tArnoldi 177 178 !> file unit for Arnoldi write out 179 integer, intent(in) :: fdArnoldi 180 181 !> file unit for Arnoldi solver tests, if this is < 1 no tests are performed 182 integer, intent(in) :: fdArnoldiDiagnosis 183 184 !> file handle for excitation energies 185 integer, intent(in) :: fdExc 186 187 !> is an energy window specified 188 logical, intent(in) :: tEnergyWindow 189 190 !> energy window for transitions above energy of nexc-th single particle transtion 191 real(dp), intent(in) :: energyWindow 192 193 !> is an oscillator window specified 194 logical, intent(in) :: tOscillatorWindow 195 196 !> the window for transitions not included in nexc and energy window (if used) 197 real(dp), intent(in) :: oscillatorWindow 198 199 !> should transition charges be cached or evaluated on the fly? 200 logical, intent(in) :: tCacheCharges 201 202 !> excitation energy of state nstat0 203 real(dp), intent(out) :: omega 204 205 !> excitation energy of all states that have been solved 206 real(dp), allocatable, intent(inout) :: allOmega(:) 207 208 !> onsite corrections if in use 209 real(dp), allocatable :: onsMEs(:,:,:,:) 210 211 !> shift vector for potentials in the ground state 212 real(dp), intent(in), optional :: shift(:) 213 214 !> non-SCC hamitonian data 215 type(OSlakoCont), intent(in), optional :: skHamCont 216 217 !> overlap data 218 type(OSlakoCont), intent(in), optional :: skOverCont 219 220 !> excitation energy gradient with respect to atomic positions 221 real(dp), intent(out), optional :: excgrad(:,:) 222 223 !> Differentiator for H0 and S matrices. 224 class(NonSccDiff), intent(in), optional :: derivator 225 226 !> ground state square density matrix 227 real(dp), intent(in), optional :: rhoSqr(:,:,:) 228 229 !> Occupation numbers for natural orbitals from the excited state density matrix 230 real(dp), intent(out), optional :: occNatural(:) 231 232 !> the single particle eigenvectors themselves for the excited state density matrix. 233 real(dp), intent(out), optional :: naturalOrbs(:,:,:) 234 235 real(dp) :: Ssq(nexc) 236 real(dp), allocatable :: gammaMat(:,:), snglPartTransDip(:,:) 237 real(dp), allocatable :: stimc(:,:,:), wij(:) 238 real(dp), allocatable :: dqex(:), sposz(:), osz(:), xpy(:), xmy(:), pc(:,:) 239 real(dp), allocatable :: t(:,:), rhs(:), woo(:), wvv(:), wov(:) 240 real(dp), allocatable :: evec(:,:), eval(:), transitionDipoles(:,:) 241 integer, allocatable :: win(:), getij(:,:) 242 243 !> array from pairs of single particles states to compound index - should replace with a more 244 !> compact data structure in the cases where there are oscilator windows 245 integer, allocatable :: iatrans(:,:) 246 247 character, allocatable :: symmetries(:) 248 249 integer :: nocc, nocc_r, nvir_r, nxoo_r, nxvv_r 250 integer :: nxov, nxov_ud(2), nxov_r, nxov_d, nxov_rd 251 integer :: norb 252 integer :: i, j, iSpin, isym, iLev, nStartLev, nEndLev 253 integer :: nSpin 254 character :: sym 255 256 real(dp) :: energyThreshold 257 258 integer :: nStat 259 260 !> control variables 261 logical :: tZVector, tCoeffs, tTradip 262 263 !> printing data 264 logical :: tMulliken 265 266 !> should gradients be calculated 267 logical :: tForces 268 269 !> transition charges, either cached or evaluated on demand 270 type(TTransCharges) :: transChrg 271 272 273 ! ARPACK library variables 274 ndigit = -3 275 ! Output unit: 276 logfil = fdArnoldi 277 msgets = 0 278 msaitr = 0 279 msapps = 0 280 mseigt = 0 281 mseupd = 0 282 if(tArnoldi) then 283 msaupd = 1 284 msaup2 = 1 285 else 286 msaupd = 0 287 msaup2 = 0 288 endif 289 ! End of ARPACK communication variables 290 291 @:ASSERT(fdExc > 0) 292 293 ! work out which data files are required, based on whether they have valid file IDs (>0) 294 tMulliken = (fdMulliken > 0) 295 tCoeffs = (fdCoeffs > 0) 296 tTradip = (fdTradip > 0) 297 298 if (tMulliken) then 299 open(fdMulliken, file=excitedQOut,position="rewind", status="replace") 300 close(fdMulliken) 301 open(fdMulliken, file=excitedDipoleOut, position="rewind", status="replace") 302 close(fdMulliken) 303 end if 304 305 @:ASSERT(fdArnoldi > 0) 306 if (tArnoldi) then 307 open(fdArnoldi, file=arpackOut, position="rewind", status="replace") 308 end if 309 310 nSpin = size(grndEigVal, dim=2) 311 @:ASSERT(nSpin > 0 .and. nSpin <=2) 312 313 norb = orb%nOrb 314 315 @:ASSERT(present(excgrad) .eqv. present(shift)) 316 @:ASSERT(present(excgrad) .eqv. present(skHamCont)) 317 @:ASSERT(present(excgrad) .eqv. present(skOverCont)) 318 @:ASSERT(present(excgrad) .eqv. present(rhoSqr)) 319 @:ASSERT(present(excgrad) .eqv. present(derivator)) 320 321 @:ASSERT(present(occNatural) .eqv. present(naturalOrbs)) 322 323 ! count initial number of transitions from occupied to empty states 324 nxov_ud = 0 325 do iSpin = 1, nSpin 326 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i,j) SCHEDULE(RUNTIME) REDUCTION(+:nxov_ud) 327 do i = 1, norb - 1 328 do j = i, norb 329 if (filling(i,iSpin) > filling(j,iSpin) + elecTolMax) then 330 nxov_ud(iSpin) = nxov_ud(iSpin) + 1 331 end if 332 end do 333 end do 334 !$OMP END PARALLEL DO 335 end do 336 nxov = sum(nxov_ud) 337 338 if (nexc + 1 >= nxov) then 339 write(tmpStr,"(' Insufficent single particle excitations, ',I0,& 340 & ', for required number of excited states ',I0)")nxov, nexc 341 call error(tmpStr) 342 end if 343 344 tForces = .false. 345 ! are gradients required? 346 if (present(excgrad)) then 347 if (size(excgrad) > 0) then 348 tForces = .true. 349 end if 350 end if 351 352 353 !> is a z vector required? 354 tZVector = tForces .or. tMulliken .or. tCoeffs .or. present(naturalOrbs) 355 356 ! Sanity checks 357 nstat = nstat0 358 if (nstat < 0 .and. symc /= "S") then 359 call error("Linresp: Brightest mode only available for singlets.") 360 end if 361 if (nstat /= 0 .and. symc == "B") then 362 call error("Linresp: Both symmetries not allowed if a specific state is excited") 363 end if 364 if (tZVector .and. nexc > nxov - 1) then 365 call error("Linresp: With gradients/properties, nexc can be greater than the number of& 366 & occupied-virtual excitations") 367 end if 368 369 ! Select symmetries to process 370 if (.not. tSpin) then 371 select case (symc) 372 case ("B") 373 ALLOCATE(symmetries(2)) 374 symmetries(:) = [ "T", "S" ] 375 case ("S") 376 ALLOCATE(symmetries(1)) 377 symmetries(:) = [ "S" ] 378 case ("T") 379 ALLOCATE(symmetries(1)) 380 symmetries(:) = [ "T" ] 381 end select 382 else 383 ! ADG: temporary solution for spin polarized case. 384 ALLOCATE(symmetries(1)) 385 symmetries(:) = [ " " ] 386 end if 387 388 ! Allocation for general arrays 389 ALLOCATE(gammaMat(natom, natom)) 390 ALLOCATE(snglPartTransDip(nxov, 3)) 391 ALLOCATE(stimc(norb, norb, nSpin)) 392 ALLOCATE(wij(nxov)) 393 ALLOCATE(win(nxov)) 394 ALLOCATE(eval(nexc)) 395 ALLOCATE(getij(nxov, 2)) 396 ALLOCATE(transitionDipoles(nxov, 3)) 397 ALLOCATE(sposz(nxov)) 398 399 ! Overlap times wave function coefficients - most routines in DFTB+ use lower triangle (would 400 ! remove the need to symmetrize the overlap and ground state density matrix in the main code if 401 ! this could be used everywhere in these routines) 402 do iSpin = 1, nSpin 403 call symm(stimc(:,:,iSpin), "L", SSqr, grndEigVecs(:,:,iSpin)) 404 end do 405 406 ! ground state Hubbard U softened coulombic interactions 407 call sccCalc%getAtomicGammaMatrix(gammaMat, iNeighbour, img2CentCell) 408 409 ! Oscillator strengths for exited states, when needed. 410 ALLOCATE(osz(nexc)) 411 412 ! Find all single particle transitions and KS energy differences for cases that go from filled 413 ! to empty states 414 call getSPExcitations(grndEigVal, filling, wij, getij) 415 416 ! put them in ascending energy order 417 if (tOscillatorWindow) then 418 ! use a stable sort so that degenerate transitions from the same single particle state are 419 ! grouped together in the results, allowing these to be selected together (since how intensity 420 ! is shared out over degenerate transitions is arbitrary between eigensolvers/platforms). 421 call merge_sort(win, wij, 1.0_dp*epsilon(1.0)) 422 else 423 ! do not require stability, use the usual routine to sort, saving an O(N) workspace 424 call index_heap_sort(win, wij) 425 end if 426 wij = wij(win) 427 428 ! dipole strength of transitions between K-S states 429 call calcTransitionDipoles(coord0, win, nxov_ud(1), getij, iAtomStart, stimc, grndEigVecs,& 430 & snglPartTransDip) 431 432 ! single particle excitation oscillator strengths 433 sposz(:) = twothird * wij(:) * sum(snglPartTransDip**2, dim=2) 434 435 if (tOscillatorWindow .and. tZVector ) then 436 call error("Incompabilitity between excited state property evaluation and an oscillator& 437 & strength window at the moment.") 438 end if 439 440 if (tOscillatorWindow .or. tEnergyWindow) then 441 442 if (.not. tEnergyWindow) then 443 444 ! find transitions that are strongly dipole allowed (> oscillatorWindow) 445 call dipselect(wij, sposz, win, snglPartTransDip,nxov_rd, oscillatorWindow, grndEigVal,& 446 & getij) 447 448 else 449 450 ! energy window above the lowest nexc single particle transitions 451 energyThreshold = wij(nexc) + energyWindow 452 nxov_r = count(wij <= energyThreshold) 453 454 nxov_d = 0 455 if (tOscillatorWindow) then 456 457 ! find transitions that are strongly dipole allowed (> oscillatorWindow) 458 if (nxov_r < nxov) then 459 ! find transitions that are strongly dipole allowed (> oscillatorWindow) 460 call dipselect(wij(nxov_r+1:), sposz(nxov_r+1:), win(nxov_r+1:),& 461 & snglPartTransDip(nxov_r+1:,:),nxov_d, oscillatorWindow,& 462 & grndEigVal, getij) 463 end if 464 465 end if 466 467 nxov_rd = nxov_r + nxov_d 468 469 end if 470 else 471 472 nxov_rd = nxov 473 474 end if 475 476 ! just in case energy/dipole windows add no extra states, and is due to an arpack solver 477 ! requirement combined with the need to get at least nexc states 478 nxov_rd = max(nxov_rd,min(nexc+1,nxov)) 479 480 call TTransCharges_init(transChrg, iAtomStart, stimc, grndEigVecs, nxov_rd, nxov_ud(1), getij,& 481 & win, tCacheCharges) 482 483 484 if (fdXplusY > 0) then 485 open(fdXplusY, file=XplusYOut, position="rewind", status="replace") 486 end if 487 488 if(fdTrans>0) then 489 open(fdTrans, file=transitionsOut, position="rewind", status="replace") 490 write(fdTrans,*) 491 endif 492 493 ! single particle transition dipole file 494 if (fdTradip > 0) then 495 open(fdTradip, file=transDipOut, position="rewind", status="replace") 496 write(fdTradip,*) 497 write(fdTradip,'(5x,a,5x,a,2x,a)') "#", 'w [eV]', 'Transition dipole (x,y,z) [Debye]' 498 write(fdTradip,*) 499 write(fdTradip,'(1x,57("="))') 500 write(fdTradip,*) 501 endif 502 503 ! excitation energies 504 open(fdExc, file=excitationsOut, position="rewind", status="replace") 505 write(fdExc,*) 506 if (tSpin) then 507 write(fdExc,'(5x,a,7x,a,9x,a,9x,a,6x,a,4x,a)') 'w [eV]', 'Osc.Str.', 'Transition','Weight',& 508 & 'KS [eV]','D<S*S>' 509 else 510 write(fdExc,'(5x,a,7x,a,9x,a,9x,a,6x,a,4x,a)') 'w [eV]','Osc.Str.', 'Transition','Weight',& 511 & 'KS [eV]','Sym.' 512 end if 513 514 write(fdExc,*) 515 write(fdExc,'(1x,80("="))') 516 write(fdExc,*) 517 518 ! single particle excitations (output file and tagged file if needed). Was used for nxov_rd = 519 ! size(wij), but now for just states that are actually included in the excitation calculation. 520 call writeSPExcitations(wij, win, nxov_ud(1), getij, fdSPTrans, sposz, nxov_rd, tSpin) 521 ALLOCATE(evec(nxov_rd, nexc)) 522 523 do isym = 1, size(symmetries) 524 525 sym = symmetries(isym) 526 call buildAndDiagExcMatrix(tSpin, wij(:nxov_rd), sym, win, nxov_ud(1), nxov_rd, iAtomStart,& 527 & stimc, grndEigVecs, filling, getij, gammaMat, species0, spinW, transChrg,& 528 & fdArnoldiDiagnosis, eval, evec, onsMEs, orb) 529 530 ! Excitation oscillator strengths for resulting states 531 call getOscillatorStrengths(sym, snglPartTransDip(1:nxov_rd,:), wij(:nxov_rd), eval, evec,& 532 & filling, win, nxov_ud(1), getij, nstat, osz, tTradip, transitionDipoles) 533 534 if (tSpin) then 535 call getExcSpin(Ssq, nxov_ud(1), getij, win, eval, evec, wij(:nxov_rd), filling, stimc,& 536 & grndEigVecs) 537 call writeExcitations(sym, osz, nexc, nxov_ud(1), getij, win, eval, evec, wij(:nxov_rd),& 538 & fdXplusY, fdTrans, fdTradip, transitionDipoles, tWriteTagged, fdTagged, taggedWriter,& 539 & fdExc, Ssq) 540 else 541 call writeExcitations(sym, osz, nexc, nxov_ud(1), getij, win, eval, evec, wij(:nxov_rd),& 542 & fdXplusY, fdTrans, fdTradip, transitionDipoles, tWriteTagged, fdTagged, taggedWriter,& 543 & fdExc) 544 end if 545 546 if (allocated(allOmega)) then 547 if (size(allOmega) /= size(symmetries) * nExc) then 548 deallocate(allOmega) 549 end if 550 end if 551 if (.not. allocated(allOmega)) then 552 allocate(allOmega(size(symmetries) * nExc)) 553 end if 554 allOmega(1+(iSym-1)*nExc:iSym*nExc) = sqrt(eval) 555 556 end do 557 558 if (tArnoldi) then 559 close(fdArnoldi) 560 end if 561 562 if (fdTrans > 0) close(fdTrans) 563 if (fdXplusY > 0) close(fdXplusY) 564 if (fdExc > 0) close(fdExc) 565 if (fdTradip > 0) close(fdTradip) 566 567 ! Remove some un-used memory 568 deallocate(snglPartTransDip) 569 deallocate(transitionDipoles) 570 deallocate(sposz) 571 572 if (.not. tZVector) then 573 if (nstat == 0) then 574 omega = 0.0_dp 575 else 576 omega = sqrt(eval(nstat)) 577 end if 578 else 579 ! calculate Furche vectors and transition density matrix for various properties 580 581 if (nstat == 0) then 582 nStartLev = 1 583 nEndLev = nexc 584 585 if (tForces) then 586 call error("Forces currently not available unless a single excited state is specified") 587 end if 588 589 else 590 nStartLev = nstat 591 nEndLev = nstat 592 end if 593 594 if (tSpin) then 595 call error("Z vector evaluation does not currently support spin polarization.") 596 end if 597 598 if (any( abs(filling) > elecTolMax .and. abs(filling-2.0_dp) > elecTolMax ) ) then 599 call error("Fractional fillings not currently possible for excited state property& 600 & calculations") 601 end if 602 603 ! redefine if needed (generalize it for spin-polarized and fractional occupancy) 604 nocc = nint(rnel) / 2 605 nocc_r = nOcc 606 nvir_r = nOrb - nOcc 607 608 ! elements in a triangle plus the diagonal of the occ-occ and virt-virt blocks 609 nxoo_r = (nocc_r * (nocc_r + 1)) / 2 610 nxvv_r = (nvir_r * (nvir_r + 1)) / 2 611 612 ! Arrays needed for Z vector 613 ALLOCATE(xpy(nxov_rd)) 614 ALLOCATE(xmy(nxov_rd)) 615 ALLOCATE(t(norb, norb)) 616 ALLOCATE(rhs(nxov_rd)) 617 ALLOCATE(woo(nxoo_r)) 618 ALLOCATE(wvv(nxvv_r)) 619 ALLOCATE(wov(nxov_rd)) 620 ALLOCATE(iatrans(1:nocc, nocc+1:norb)) 621 622 ! Arrays for gradients and Mulliken analysis 623 if (tZVector) then 624 ALLOCATE(dqex(natom)) 625 ALLOCATE(pc(norb, norb)) 626 end if 627 628 ! set up transition indexing 629 call rindxov_array(win, nocc, nxov, getij, iatrans) 630 631 do iLev = nStartLev, nEndLev 632 omega = sqrt(eval(iLev)) 633 ! Furche terms: X+Y, X-Y 634 xpy(:nxov_rd) = evec(:nxov_rd,iLev) * sqrt(wij(:nxov_rd) / omega) 635 xmy(:nxov_rd) = evec(:nxov_rd,iLev) * sqrt(omega / wij(:nxov_rd)) 636 637 ! solve for Z and W to get excited state density matrix 638 call getZVectorEqRHS(xpy, xmy, win, iAtomStart, nocc, nocc_r,& 639 & nxov_ud(1), getij, iatrans, natom, species0,grndEigVal(:,1),& 640 & stimc, grndEigVecs, gammaMat, spinW, omega, sym, rhs, t,& 641 & wov, woo, wvv, transChrg) 642 call solveZVectorPrecond(rhs, win, nxov_ud(1), getij, natom, iAtomStart,& 643 & stimc, gammaMat, wij(:nxov_rd), grndEigVecs, transChrg) 644 call calcWVectorZ(rhs, win, nocc, nocc_r, nxov_ud(1), getij, iAtomStart,& 645 & stimc, grndEigVecs, gammaMat, grndEigVal(:,1), wov, woo, wvv, transChrg) 646 call calcPMatrix(t, rhs, win, getij, pc) 647 648 call writeCoeffs(pc, grndEigVecs, filling, nocc, fdCoeffs,& 649 & tCoeffs, tGrndState, occNatural, naturalOrbs) 650 651 ! Make MO to AO transformation of the excited density matrix 652 call makeSimiliarityTrans(pc, grndEigVecs(:,:,1)) 653 654 call getExcMulliken(iAtomStart, pc, SSqr, dqex) 655 if (tMulliken) then 656 call writeExcMulliken(sym, iLev, dq, dqex, coord0, fdMulliken) 657 end if 658 659 if (tForces) then 660 call addGradients(sym, nxov_rd, natom, species0, iAtomStart, norb, nocc, nocc_r,& 661 & nxov_ud(1), getij, win, grndEigVecs, pc, stimc, dq, dqex, gammaMat, HubbardU,& 662 & spinW, shift, woo, wov, wvv, transChrg, xpy, coord0, orb, skHamCont,& 663 & skOverCont, derivator, rhoSqr(:,:,1), excgrad) 664 end if 665 666 end do 667 668 if (nstat == 0) then 669 omega = 0.0_dp 670 end if 671 672 end if 673 674 end subroutine LinRespGrad_old 675 676 677 !> Builds and diagonalizes the excitation matrix via iterative technique. 678 subroutine buildAndDiagExcMatrix(tSpin, wij, sym, win, nmatup, nxov, iAtomStart, stimc,& 679 & grndEigVecs, filling, getij, gammaMat, species0, spinW, transChrg, fdArnoldiDiagnosis,& 680 & eval, evec, onsMEs, orb) 681 682 !> spin polarisation? 683 logical, intent(in) :: tSpin 684 685 !> single particle excitation energies 686 real(dp), intent(in) :: wij(:) 687 688 !> symmetry to calculate transitions 689 character, intent(in) :: sym 690 691 !> index array for single particle excitions 692 integer, intent(in) :: win(:) 693 694 !> number of same spin excitations 695 integer, intent(in) :: nmatup 696 697 !> number of occupied-virtual transitions 698 integer, intent(in) :: nxov 699 700 !> indexing array for square matrices 701 integer, intent(in) :: iAtomStart(:) 702 703 !> overlap times ground state eigenvectors 704 real(dp), intent(in) :: stimc(:,:,:) 705 706 !> ground state eigenvectors 707 real(dp), intent(in) :: grndEigVecs(:,:,:) 708 709 !> occupation numbers 710 real(dp), intent(in) :: filling(:,:) 711 712 !> electrostatic matrix 713 real(dp), intent(in) :: gammaMat(:,:) 714 715 !> index array for for single particle excitations 716 integer, intent(in) :: getij(:,:) 717 718 !> central cell chemical species 719 integer, intent(in) :: species0(:) 720 721 !> file handle for ARPACK eigenstate tests 722 integer, intent(in) :: fdArnoldiDiagnosis 723 724 !> atomic resolved spin constants 725 real(dp), intent(in) :: spinW(:) 726 727 !> machinery for transition charges between single particle levels 728 type(TTransCharges), intent(in) :: transChrg 729 730 !> resulting eigenvalues for transitions 731 real(dp), intent(out) :: eval(:) 732 733 !> eigenvectors for transitions 734 real(dp), intent(out) :: evec(:,:) 735 736 !> onsite corrections if in use 737 real(dp), allocatable :: onsMEs(:,:,:,:) 738 739 !> data type for atomic orbital information 740 type(TOrbitals), intent(in) :: orb 741 742 real(dp), allocatable :: workl(:), workd(:), resid(:), vv(:,:), qij(:) 743 real(dp) :: sigma 744 integer :: iparam(11), ipntr(11) 745 integer :: ido, ncv, lworkl, info 746 logical, allocatable :: selection(:) 747 logical :: rvec 748 integer :: nexc, natom 749 750 integer :: iState 751 real(dp), allocatable :: Hv(:), orthnorm(:,:) 752 753 nexc = size(eval) 754 natom = size(gammaMat, dim=1) 755 @:ASSERT(all(shape(evec) == [ nxov, nexc ])) 756 757 ! Three times more Lanczos vectors than desired eigenstates 758 ncv = min(3 * nexc, nxov) 759 760 lworkl = ncv * (ncv + 8) 761 762 ALLOCATE(workl(lworkl)) 763 ALLOCATE(workd(3 * nxov)) 764 ALLOCATE(resid(nxov)) 765 ALLOCATE(selection(ncv)) 766 ALLOCATE(vv(nxov, ncv)) 767 ALLOCATE(qij(natom)) 768 769 resid = 0.0_dp 770 workd = 0.0_dp 771 772 ! random initial vector used for dsaupd ARPACK call 773 info = 0 774 ! IDO must be zero on the first call 775 ido = 0 776 ! restarting the iteration with a starting vector that is a linear combination of Ritz vectors 777 ! associated with the "wanted" Ritz values. 778 iparam(1) = 1 779 ! maximum iterations of solver 780 iparam(3) = MAX_AR_ITER 781 ! solve A*x = lambda*x, with A symmetric 782 iparam(7) = 1 783 784 ! loop until exit 785 do 786 787 ! call the reverse communication interface from arpack 788 call saupd (ido, "I", nxov, "SM", nexc, ARTOL, resid, ncv, vv, nxov, iparam, ipntr, workd,& 789 & workl, lworkl, info) 790 791 if (ido == 99) then 792 ! has terminated normally, exit loop 793 exit 794 end if 795 796 ! still running, test for an error return 797 if (abs(ido) /= 1) then 798 write(tmpStr,"(' Unexpected return from arpack routine saupd, IDO ',I0, ' INFO ',I0)")& 799 & ido,info 800 call error(tmpStr) 801 end if 802 803 ! Action of excitation supermatrix on supervector 804 call omegatvec(tSpin, workd(ipntr(1):ipntr(1)+nxov-1), workd(ipntr(2):ipntr(2)+nxov-1),& 805 & wij, sym, win, nmatup, iAtomStart, stimc, grndEigVecs, filling, getij, gammaMat,& 806 & species0, spinW, onsMEs, orb, transChrg) 807 808 end do 809 810 ! check returned info flag for errors 811 if (info < 0) then 812 write(tmpStr,"(' Error with ARPACK routine saupd, info = ',I0)")info 813 call error(tmpStr) 814 else if (info == 1) then 815 call error("Maximum number of iterations reached. Increase the number of excited states to& 816 & solve for (NrOfExcitations).") 817 else 818 819 ! now want Ritz vectors 820 rvec = .true. 821 822 ! everything after the first 6 variables are passed directly to DSEUPD following the last call 823 ! to DSAUPD. These arguments MUST NOT BE MODIFIED between the the last call to DSAUPD and the 824 ! call to DSEUPD. 825 call seupd (rvec, "All", selection, eval, evec, nxov, sigma, "I", nxov, "SM", nexc, ARTOL,& 826 & resid, ncv, vv, nxov, iparam, ipntr, workd, workl, lworkl, info) 827 828 ! check for error on return 829 if (info /= 0) then 830 write(tmpStr,"(' Error with ARPACK routine seupd, info = ',I0)")info 831 call error(tmpStr) 832 end if 833 834 end if 835 836 if (fdArnoldiDiagnosis > 0) then 837 ! tests for quality of returned eigenpairs 838 open(fdArnoldiDiagnosis, file=testArpackOut, position="rewind", status="replace") 839 ALLOCATE(Hv(nxov)) 840 ALLOCATE(orthnorm(nxov,nxov)) 841 orthnorm = matmul(transpose(evec(:,:nExc)),evec(:,:nExc)) 842 843 write(fdArnoldiDiagnosis,"(A)")'State Ei deviation Evec deviation Norm deviation Max& 844 & non-orthog' 845 do iState = 1, nExc 846 call omegatvec(tSpin, evec(:,iState), Hv, wij, sym, win, nmatup, iAtomStart, stimc,& 847 & grndEigVecs, filling, getij, gammaMat, species0, spinW, onsMEs, orb, transChrg) 848 write(fdArnoldiDiagnosis,"(I4,4E16.8)")iState, dot_product(Hv,evec(:,iState))-eval(iState),& 849 & sqrt(sum( (Hv-evec(:,iState)*eval(iState) )**2 )), orthnorm(iState,iState) - 1.0_dp,& 850 & max(maxval(orthnorm(:iState-1,iState)), maxval(orthnorm(iState+1:,iState))) 851 end do 852 close(fdArnoldiDiagnosis) 853 end if 854 855 end subroutine buildAndDiagExcMatrix 856 857 858 !> Calculate oscillator strength for a given excitation between KS states 859 subroutine getOscillatorStrengths(sym, snglPartTransDip, wij, eval, evec, filling, win, nmatup,& 860 & getij, istat, osz, tTradip, transitionDipoles) 861 862 !> symmetry of transition 863 character, intent(in) :: sym 864 865 !> dipole moments for single particle transtions 866 real(dp), intent(in) :: snglPartTransDip(:,:) 867 868 !> energies for single particle transitions 869 real(dp), intent(in) :: wij(:) 870 871 !> Low lying eigenvalues of Casida eqn 872 real(dp), intent(in) :: eval(:) 873 874 !> eigenvectors of Casida eqn 875 real(dp), intent(in) :: evec(:,:) 876 877 !> Single particle occupations in the ground state 878 real(dp), intent(in) :: filling(:,:) 879 880 !> index for transitions 881 integer, intent(in) :: win(:) 882 883 !> number of up spin transitions before the down spin start 884 integer, intent(in) :: nmatup 885 886 !> index from single particle excitation to specific pair of single particle states involved 887 integer, intent(in) :: getij(:,:) 888 889 !> write transition dipole 890 logical :: tTradip 891 892 !> flag wich if <-1 on entry is returned as the brightest state 893 integer, intent(inout) :: istat 894 895 !> Oscilator strengths of transitions 896 real(dp), intent(out) :: osz(:) 897 898 !> resulting transition dipoles 899 real(dp), intent(out) :: transitionDipoles(:,:) 900 901 integer :: ii, nmat, oszLoc(1) 902 real(dp) :: wnij(size(evec, dim=1)) 903 logical :: tSpin 904 905 nmat = size(evec, dim=1) 906 907 if (size(filling, dim=2) == 2) then 908 tSpin = .true. 909 else 910 tSpin = .false. 911 end if 912 913 transitionDipoles = 0.0_dp 914 osz = 0.0_dp 915 916 ! Triplet oscillator strength and transition dipole is zero for 917 ! closed shell ground state 918 if ((.not. tSpin) .and. (sym == "T")) then 919 return 920 end if 921 922 call wtdn(wij, filling, win, nmatup, nmat, getij, wnij) 923 924 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(ii) SCHEDULE(RUNTIME) 925 do ii = 1, size(evec, dim=2) 926 osz(ii) = oscillatorStrength(snglPartTransDip, wnij, evec(:,ii)) 927 end do 928 !$OMP END PARALLEL DO 929 930 if (istat < 0) then 931 ! find largest transition dipole transition 932 oszLoc = maxloc(osz) 933 istat = oszLoc(1) 934 end if 935 936 if (tTradip) then 937 call transitionDipole(snglPartTransDip, wnij, eval, evec, transitionDipoles) 938 end if 939 940 end subroutine getOscillatorStrengths 941 942 943 !> Calculate <S^2> as a measure of spin contamination (smaller magnitudes are better, 0.5 is 944 !> considered an upper threshold for reliability according to Garcia thesis) 945 subroutine getExcSpin(Ssq, nmatup, getij, win, eval, evec, wij, filling, stimc, grndEigVecs) 946 947 !> spin contamination 948 real(dp), intent(out) :: Ssq(:) 949 950 !> number of spin up excitations 951 integer, intent(in) :: nmatup 952 953 !> index for composite excitations to specific occupied and empty states 954 integer, intent(in) :: getij(:,:) 955 956 !> single particle excitation index 957 integer, intent(in) :: win(:) 958 959 !> Casida exitation energies 960 real(dp), intent(in) :: eval(:) 961 962 !> Casida excited eigenvectors 963 real(dp), intent(in) :: evec(:,:) 964 965 !> single particle excitation energies 966 real(dp), intent(in) :: wij(:) 967 968 !> occupations in ground state 969 real(dp), intent(in) :: filling(:,:) 970 971 !> Overlap times ground state eigenvectors 972 real(dp), intent(in) :: stimc(:,:,:) 973 974 !> Ground state eigenvectors 975 real(dp), intent(in) :: grndEigVecs(:,:,:) 976 977 integer:: i, k, l, m, ia, jb, ii, aa, jj, bb 978 integer:: nmat, nexc, nup, ndwn 979 real(dp) :: rsqw, TDvnorm 980 real(dp), allocatable :: TDvec(:), TDvec_sq(:) 981 integer, allocatable :: TDvin(:) 982 logical :: ud_ia, ud_jb 983 real(dp) :: s_iaja, s_iaib, s_iajb, tmp 984 real(dp) :: wnij(size(wij)) 985 986 nmat = size(evec, dim=1) 987 nexc = size(Ssq) 988 nup = ceiling(sum(filling(:,1))) 989 ndwn = ceiling(sum(filling(:,2))) 990 ALLOCATE(TDvec(nmat)) 991 ALLOCATE(TDvec_sq(nmat)) 992 ALLOCATE(TDvin(nmat)) 993 994 call wtdn(wij, filling, win, nmatup, nmat, getij, wnij) 995 996 do i = 1, nexc 997 rsqw = 1.0_dp / sqrt(sqrt(eval(i))) 998 TDvec(:) = sqrt(wnij(:)) * rsqw * evec(:,i) 999 TDvnorm = 1.0_dp / sqrt(sum(TDvec**2)) 1000 TDvec(:) = TDvec(:) * TDvnorm 1001 TDvec_sq = TDvec**2 1002 1003 ! put these transition dipoles in order of descending magnitude 1004 call index_heap_sort(TDvin, TDvec_sq) 1005 TDvin = TDvin(nmat:1:-1) 1006 TDvec_sq = TDvec_sq(TDvin) 1007 1008 ! S_{ia,ja} 1009 s_iaja = 0.0_dp 1010 do k = 1, nmat 1011 ia = TDvin(k) 1012 call indxov(win, ia, getij, ii, aa) 1013 ud_ia = (win(ia) <= nmatup) 1014 do l = 1, nmat 1015 jb = TDvin(l) 1016 call indxov(win, jb, getij, jj, bb) 1017 ud_jb = (win(jb) <= nmatup) 1018 1019 if ( (bb /= aa) .or. (ud_jb .neqv. ud_ia) ) then 1020 cycle 1021 end if 1022 1023 tmp = 0.0_dp 1024 if (ud_ia) then 1025 do m = 1,ndwn 1026 tmp = tmp + MOoverlap(ii,m,stimc,grndEigVecs) * MOoverlap(jj,m,stimc,grndEigVecs) 1027 end do 1028 else 1029 do m = 1,nup 1030 tmp = tmp + MOoverlap(m,ii,stimc,grndEigVecs) * MOoverlap(m,jj,stimc,grndEigVecs) 1031 end do 1032 end if 1033 1034 s_iaja = s_iaja + TDvec(ia)*TDvec(jb)*tmp 1035 1036 end do 1037 end do 1038 1039 ! S_{ia,ib} 1040 s_iaib = 0.0_dp 1041 do k = 1, nmat 1042 ia = TDvin(k) 1043 call indxov(win, ia, getij, ii, aa) 1044 ud_ia = (win(ia) <= nmatup) 1045 do l = 1, nmat 1046 jb = TDvin(l) 1047 call indxov(win, jb, getij, jj, bb) 1048 ud_jb = (win(jb) <= nmatup) 1049 1050 if ( (ii /= jj) .or. (ud_jb .neqv. ud_ia) ) then 1051 cycle 1052 end if 1053 1054 tmp = 0.0_dp 1055 if (ud_ia) then 1056 do m = 1,ndwn 1057 tmp = tmp + MOoverlap(aa,m,stimc,grndEigVecs) * MOoverlap(bb,m,stimc,grndEigVecs) 1058 end do 1059 else 1060 do m = 1,nup 1061 tmp = tmp + MOoverlap(m,aa,stimc,grndEigVecs) * MOoverlap(m,bb,stimc,grndEigVecs) 1062 end do 1063 end if 1064 1065 s_iaib = s_iaib + TDvec(ia)*TDvec(jb)*tmp 1066 end do 1067 end do 1068 1069 ! S_{ia,jb} 1070 s_iajb = 0.0_dp 1071 do k = 1, nmat 1072 ia = TDvin(k) 1073 call indxov(win, ia, getij, ii, aa) 1074 ud_ia = (win(ia) <= nmatup) 1075 if (.not. ud_ia ) then 1076 cycle 1077 end if 1078 do l = 1, nmat 1079 jb = TDvin(l) 1080 call indxov(win, jb, getij, jj, bb) 1081 ud_jb = (win(jb) <= nmatup) 1082 1083 if ( ud_jb ) cycle 1084 1085 s_iajb = s_iajb + TDvec(ia)*TDvec(jb) * MOoverlap(aa,bb,stimc,grndEigVecs)& 1086 & * MOoverlap(ii,jj,stimc,grndEigVecs) 1087 1088 end do 1089 end do 1090 1091 Ssq(i) = s_iaja - s_iaib - 2.0_dp*s_iajb 1092 1093 end do 1094 1095 end subroutine getExcSpin 1096 1097 1098 !> Build right hand side of the equation for the Z-vector and those parts of the W-vectors which 1099 !> do not depend on Z. 1100 subroutine getZVectorEqRHS(xpy, xmy, win, iAtomStart, homo, nocc, nmatup, getij, iatrans, natom,& 1101 & species0, grndEigVal, stimc, c, gammaMat, spinW, omega, sym, rhs, t, wov, woo, wvv,& 1102 & transChrg) 1103 1104 !> X+Y Furche term 1105 real(dp), intent(in) :: xpy(:) 1106 1107 !> X-Y Furche term 1108 real(dp), intent(in) :: xmy(:) 1109 1110 !> index array for single particle transitions 1111 integer, intent(in) :: win(:) 1112 1113 !> index vector for S and H matrices 1114 integer, intent(in) :: iAtomStart(:) 1115 1116 !> highest occupied level 1117 integer, intent(in) :: homo 1118 1119 !> number of filled states 1120 integer, intent(in) :: nocc 1121 1122 !> number of same spin excitations 1123 integer, intent(in) :: nmatup 1124 1125 !> index array between transitions in square and 1D representations 1126 integer, intent(in) :: getij(:,:) 1127 1128 !> index array from orbital pairs to compound index 1129 integer, intent(in) :: iatrans(:,homo+1:) 1130 1131 !> number of central cell atoms 1132 integer, intent(in) :: natom 1133 1134 !> central cell chemical species 1135 integer, intent(in) :: species0(:) 1136 1137 !> ground state wavefunctions 1138 real(dp), intent(in) :: grndEigVal(:) 1139 1140 !> overlap times ground state wavefunctions 1141 real(dp), intent(in) :: stimc(:,:,:) 1142 1143 !> ground state wavefunctions 1144 real(dp), intent(in) :: c(:,:,:) 1145 1146 !> softened coulomb matrix 1147 real(dp), intent(in) :: gammaMat(:,:) 1148 1149 !> ground state spin derivatives for each species 1150 real(dp), intent(in) :: spinW(:) 1151 1152 !> Excitation energies 1153 real(dp), intent(in) :: omega 1154 1155 !> Symmetry of the transitions 1156 character, intent(in) :: sym 1157 1158 !> Right hand side for the Furche solution 1159 real(dp), intent(out) :: rhs(:) 1160 1161 !> T matrix 1162 real(dp), intent(out) :: t(:,:) 1163 1164 !> W vector occupied-virtual part 1165 real(dp), intent(out) :: wov(:) 1166 1167 !> W vector occupied part 1168 real(dp), intent(out) :: woo(:) 1169 1170 !> W vector virtual part 1171 real(dp), intent(out) :: wvv(:) 1172 1173 !> machinery for transition charges between single particle levels 1174 type(TTransCharges), intent(in) :: transChrg 1175 1176 real(dp), allocatable :: xpyq(:), qij(:), gamxpyq(:), qgamxpyq(:), gamqt(:) 1177 integer :: nxov, nxoo, nxvv 1178 integer :: i, j, a, b, ia, ib, ij, ab, ja 1179 real(dp) :: tmp1, tmp2 1180 logical, parameter :: updwn = .true. 1181 1182 nxov = size(rhs) 1183 nxoo = size(woo) 1184 nxvv = size(wvv) 1185 1186 ALLOCATE(xpyq(natom)) 1187 ALLOCATE(qij(natom)) 1188 ALLOCATE(gamxpyq(natom)) 1189 ALLOCATE(gamqt(natom)) 1190 ALLOCATE(qgamxpyq(max(nxoo, nxvv))) 1191 1192 t(:,:) = 0.0_dp 1193 rhs(:) = 0.0_dp 1194 wov(:) = 0.0_dp 1195 woo(:) = 0.0_dp 1196 wvv(:) = 0.0_dp 1197 1198 ! Build t_ab = 0.5 * sum_i (X+Y)_ia (X+Y)_ib + (X-Y)_ia (X-Y)_ib 1199 ! and w_ab = Q_ab with Q_ab as in (B16) but with corrected sign. 1200 ! factor 1 / (1 + delta_ab) follows later 1201 do ia = 1, nxov 1202 call indxov(win, ia, getij, i, a) 1203 1204 ! BA: is T_aa = 0? 1205 do b = homo + 1, a 1206 ib = iatrans(i, b) 1207 call rindxvv(homo, a, b, ab) 1208 tmp1 = xpy(ia) * xpy(ib) + xmy(ia) * xmy(ib) 1209 tmp2 = omega * (xpy(ia) * xmy(ib)+ xmy(ia) * xpy(ib)) 1210 t(a,b) = t(a,b) + 0.5_dp * tmp1 1211 ! to prevent double counting 1212 if (a /= b) then 1213 t(b,a) = t(b,a) + 0.5_dp * tmp1 1214 end if 1215 ! Note: diagonal elements will be multiplied by 0.5 later. 1216 wvv(ab) = wvv(ab) + grndEigVal(i) * tmp1 + tmp2 1217 end do 1218 1219 ! Build t_ij = 0.5 * sum_a (X+Y)_ia (X+Y)_ja + (X-Y)_ia (X-Y)_ja and 1 / (1 + delta_ij) Q_ij 1220 ! with Q_ij as in eq. (B9) (1st part of w_ij) 1221 do j = i, homo 1222 ja = iatrans(j,a) 1223 call rindxvv(homo-nocc, j, i, ij) 1224 tmp1 = xpy(ia) * xpy(ja) + xmy(ia) * xmy(ja) 1225 tmp2 = omega * (xpy(ia) * xmy(ja) + xmy(ia) * xpy(ja)) 1226 ! Note, there is a typo in Heringer et al. J. Comp Chem 28, 2589. 1227 ! The sign must be negative see Furche, J. Chem. Phys, 117 7433 (2002). 1228 t(i,j) = t(i,j) - 0.5_dp * tmp1 1229 ! to prevent double counting 1230 if (i /= j) then 1231 t(j,i) = t(j,i) - 0.5_dp * tmp1 1232 end if 1233 woo(ij) = woo(ij) - grndEigVal(a) * tmp1 + tmp2 1234 end do 1235 1236 end do 1237 1238 ! xpyq = Q * xpy 1239 xpyq(:) = 0.0_dp 1240 call transChrg%qMatVec(iAtomStart, stimc, c, getij, win, xpy, xpyq) 1241 1242 1243 ! qgamxpyq(ab) = sum_jc K_ab,jc (X+Y)_jc 1244 if (sym == "S") then 1245 call hemv(gamxpyq, gammaMat, xpyq) 1246 do ab = 1, nxvv 1247 call indxvv(homo, ab, a, b) 1248 qij(:) = transq(a, b, iAtomStart, updwn, stimc, c) 1249 qgamxpyq(ab) = 2.0_dp * sum(qij * gamxpyq) 1250 end do 1251 else ! triplet case 1252 do ab = 1, nxvv 1253 call indxvv(homo, ab, a, b) 1254 qij(:) = transq(a, b, iAtomStart, updwn, stimc, c) 1255 qgamxpyq(ab) = 2.0_dp * sum(qij * xpyq * spinW(species0)) 1256 end do 1257 end if 1258 1259 ! rhs(ia) -= Qia = sum_b (X+Y)_ib * qgamxpyq(ab)) 1260 do ia = 1, nxov 1261 call indxov(win, ia, getij, i, a) 1262 do b = homo + 1, a 1263 call rindxvv(homo, a, b, ab) 1264 ib = iatrans(i,b) 1265 rhs(ia) = rhs(ia) - 2.0_dp * xpy(ib) * qgamxpyq(ab) 1266 ! Since qgamxpyq has only upper triangle 1267 if (a /= b) then 1268 rhs(ib) = rhs(ib) - 2.0_dp * xpy(ia) * qgamxpyq(ab) 1269 end if 1270 end do 1271 end do 1272 1273 ! -rhs = -rhs - sum_j (X + Y)_ja H + _ij[X + Y] 1274 if (sym == "S") then 1275 do ij = 1, nxoo 1276 qgamxpyq(ij) = 0.0_dp 1277 call indxoo(ij, i, j) 1278 qij(:) = transq(i, j, iAtomStart, updwn, stimc, c) 1279 ! qgamxpyq(ij) = sum_kb K_ij,kb (X+Y)_kb 1280 qgamxpyq(ij) = 2.0_dp * sum(qij * gamxpyq) 1281 end do 1282 else 1283 do ij = 1, nxoo 1284 qgamxpyq(ij) = 0.0_dp 1285 call indxoo(ij, i, j) 1286 qij(:) = transq(i, j, iAtomStart, updwn, stimc, c) 1287 qgamxpyq(ij) = 2.0_dp * sum(qij * xpyq * spinW(species0)) 1288 end do 1289 end if 1290 1291 ! rhs(ia) += Qai = sum_j (X+Y)_ja qgamxpyq(ij) 1292 ! add Qai to Wia as well. 1293 do ia = 1, nxov 1294 call indxov(win, ia, getij, i, a) 1295 do j = i, homo 1296 ja = iatrans(j, a) 1297 ij = i-homo+nocc + ((j-homo+nocc - 1) * (j-homo+nocc)) / 2 1298 tmp1 = 2.0_dp * xpy(ja) * qgamxpyq(ij) 1299 rhs(ia) = rhs(ia) + tmp1 1300 wov(ia) = wov(ia) + tmp1 1301 if (i /= j) then 1302 tmp2 = 2.0_dp * xpy(ia) * qgamxpyq(ij) 1303 rhs(ja) = rhs(ja) + tmp2 1304 wov(ja) = wov(ja) + tmp2 1305 end if 1306 end do 1307 end do 1308 1309 ! gamxpyq(iAt2) = sum_ij q_ij(iAt2) T_ij 1310 gamxpyq(:) = 0.0_dp 1311 do ij = 1, nxoo 1312 call indxoo(ij, i, j) 1313 qij = transq(i, j, iAtomStart, updwn, stimc, c) 1314 if (i == j) then 1315 gamxpyq(:) = gamxpyq(:) + t(i,j) * qij(:) 1316 else 1317 ! factor 2 because of symmetry of the matrix 1318 gamxpyq(:) = gamxpyq(:) + 2.0_dp * t(i,j) * qij(:) 1319 end if 1320 end do 1321 1322 ! gamxpyq(iAt2) += sum_ab q_ab(iAt2) T_ab 1323 do ab = 1, nxvv 1324 call indxvv(homo, ab, a, b) 1325 qij(:) = transq(a, b, iAtomStart, updwn, stimc, c) 1326 if (a == b) then 1327 gamxpyq(:) = gamxpyq(:) + t(a,b) * qij(:) 1328 else 1329 ! factor 2 because of symmetry of the matrix 1330 gamxpyq(:) = gamxpyq(:) + 2.0_dp * t(a,b) * qij(:) 1331 end if 1332 end do 1333 1334 ! gamqt(iAt1) = sum_iAt2 gamma_iAt1,iAt2 gamxpyq(iAt2) 1335 call hemv(gamqt, gammaMat, gamxpyq) 1336 1337 ! rhs -= sum_q^ia(iAt1) gamxpyq(iAt1) 1338 call transChrg%qVecMat(iAtomStart, stimc, c, getij, win, -4.0_dp*gamqt, rhs) 1339 1340 ! Furche vectors 1341 do ij = 1, nxoo 1342 call indxoo(ij, i, j) 1343 qij(:) = transq(i, j, iAtomStart, updwn, stimc, c) 1344 woo(ij) = woo(ij) + 4.0_dp * sum(qij * gamqt) 1345 end do 1346 1347 end subroutine getZVectorEqRHS 1348 1349 1350 !> Solving the (A+B) Z = -R equation via diagonally preconditioned conjugate gradient 1351 subroutine solveZVectorPrecond(rhs, win, nmatup, getij, natom, iAtomStart, stimc, gammaMat, wij,& 1352 & c, transChrg) 1353 1354 !> on entry -R, on exit Z 1355 real(dp), intent(inout) :: rhs(:) 1356 1357 !> index for single particle excitations 1358 integer, intent(in) :: win(:) 1359 1360 !> number of transitions between only up states 1361 integer, intent(in) :: nmatup 1362 1363 !> index array from composite index to specific filled-empty transition 1364 integer, intent(in) :: getij(:,:) 1365 1366 !> number of atoms 1367 integer, intent(in) :: natom 1368 1369 !> index vector for S and H0 matrices 1370 integer, intent(in) :: iAtomStart(:) 1371 1372 !> overlap times ground state mo-coefficients 1373 real(dp), intent(in) :: stimc(:,:,:) 1374 1375 !> Softened coulomb matrix 1376 real(dp), intent(in) :: gammaMat(:,:) 1377 1378 !> single particle excitation energies 1379 real(dp), intent(in) :: wij(:) 1380 1381 !> ground state mo-coefficients 1382 real(dp), intent(in) :: c(:,:,:) 1383 1384 !> machinery for transition charges between single particle levels 1385 type(TTransCharges), intent(in) :: transChrg 1386 1387 integer :: nxov 1388 integer :: ia, i, a, k 1389 real(dp) :: rhs2(size(rhs)), rkm1(size(rhs)), zkm1(size(rhs)), pkm1(size(rhs)), apk(size(rhs)) 1390 real(dp) :: qTmp(nAtom), rs, alphakm1, tmp1, tmp2, bkm1 1391 real(dp), allocatable :: qij(:), P(:) 1392 1393 nxov = size(rhs) 1394 allocate(qij(nAtom)) 1395 1396 ! diagonal preconditioner 1397 ! P^-1 = 1 / (A+B)_ia,ia (diagonal of the supermatrix sum A+B) 1398 allocate(P(nxov)) 1399 do ia = 1, nxov 1400 qij = transChrg%qTransIJ(ia, iAtomStart, stimc, c, getij, win) 1401 call hemv(qTmp, gammaMat, qij) 1402 rs = 4.0_dp * dot_product(qij, qTmp) + wij(ia) 1403 P(ia) = 1.0_dp / rs 1404 end do 1405 1406 ! Free some space, before entering the apbw routine 1407 deallocate(qij) 1408 1409 ! unit vector as initial guess solution 1410 rhs2(:) = 1.0_dp / sqrt(real(nxov,dp)) 1411 1412 ! action of matrix on vector 1413 call apbw(rkm1, rhs2, wij, nxov, natom, win, nmatup, getij, iAtomStart, stimc, c, gammaMat,& 1414 & transChrg) 1415 1416 rkm1(:) = rhs - rkm1 1417 zkm1(:) = P * rkm1 1418 pkm1(:) = zkm1 1419 1420 ! Iteration: should be convergent in at most nxov steps for a quadradic surface, so set higher 1421 do k = 1, nxov**2 1422 1423 ! action of matrix on vector 1424 call apbw(apk, pkm1, wij, nxov, natom, win, nmatup, getij, iAtomStart, stimc, c, gammaMat,& 1425 & transChrg) 1426 1427 tmp1 = dot_product(rkm1, zkm1) 1428 tmp2 = dot_product(pkm1, apk) 1429 alphakm1 = tmp1 / tmp2 1430 1431 rhs2 = rhs2 + alphakm1 * pkm1 1432 1433 rkm1 = rkm1 -alphakm1 * apk 1434 1435 tmp2 = dot_product(rkm1, rkm1) 1436 1437 ! residual 1438 if (tmp2 <= epsilon(1.0_dp)**2) then 1439 exit 1440 end if 1441 1442 if (k == nxov**2) then 1443 call error("solveZVectorEq : Z vector not converged!") 1444 end if 1445 1446 zkm1(:) = P * rkm1 1447 1448 tmp2 = dot_product(zkm1, rkm1) 1449 1450 ! Fletcher–Reeves update 1451 bkm1 = tmp2 / tmp1 1452 1453 pkm1 = zkm1 + bkm1 * pkm1 1454 1455 end do 1456 1457 rhs(:) = rhs2(:) 1458 1459 end subroutine solveZVectorPrecond 1460 1461 1462 !> Calculate Z-dependent parts of the W-vectors and divide diagonal elements of W_ij and W_ab by 1463 !> 2. 1464 subroutine calcWvectorZ(zz, win, homo, nocc, nmatup, getij, iAtomStart, stimc, c, gammaMat,& 1465 & grndEigVal, wov, woo, wvv, transChrg) 1466 1467 !> Z vector 1468 real(dp), intent(in) :: zz(:) 1469 1470 !> index array for single particle transitions 1471 integer, intent(in) :: win(:) 1472 1473 !> highest occupied level 1474 integer, intent(in) :: homo 1475 1476 !> number of filled levels 1477 integer, intent(in) :: nocc 1478 1479 !> number of same spin excitations 1480 integer, intent(in) :: nmatup 1481 1482 !> index array between transitions in square and 1D representations 1483 integer, intent(in) :: getij(:,:) 1484 1485 !> index array for S and H0 ground state square matrices 1486 integer, intent(in) :: iAtomStart(:) 1487 1488 !> overlap times ground state wavefunctions 1489 real(dp), intent(in) :: stimc(:,:,:) 1490 1491 !> ground state wavefunctions 1492 real(dp), intent(in) :: c(:,:,:) 1493 1494 !> softened coulomb matrix 1495 real(dp), intent(in) :: gammaMat(:,:) 1496 1497 !> ground state MO-energies 1498 real(dp), intent(in) :: grndEigVal(:) 1499 1500 !> W vector occupied-virtual part 1501 real(dp), intent(inout) :: wov(:) 1502 1503 !> W vector occupied part 1504 real(dp), intent(inout) :: woo(:) 1505 1506 !> W vector virtual part 1507 real(dp), intent(inout) :: wvv(:) 1508 1509 !> machinery for transition charges between single particle levels 1510 type(TTransCharges), intent(in) :: transChrg 1511 1512 integer :: nxov, nxoo, nxvv, natom 1513 integer :: ij, ia, ab, i, j, a, b, iAt1 1514 real(dp), allocatable :: qij(:), gamxpyq(:), zq(:) 1515 logical, parameter :: updwn = .true. 1516 1517 nxov = size(zz) 1518 natom = size(gammaMat, dim=1) 1519 nxoo = size(woo) 1520 nxvv = size(wvv) 1521 ALLOCATE(qij(natom)) 1522 ALLOCATE(gamxpyq(natom)) 1523 ALLOCATE(zq(natom)) 1524 1525 ! Adding missing epsilon_i * Z_ia term to W_ia 1526 do ia = 1, nxov 1527 call indxov(win, ia, getij, i, a) 1528 wov(ia) = wov(ia) + zz(ia) * grndEigVal(i) 1529 end do 1530 1531 ! Missing sum_kb 4 K_ijkb Z_kb term in W_ij: zq(iAt1) = sum_kb q^kb(iAt1) Z_kb 1532 zq(:) = 0.0_dp 1533 call transChrg%qMatVec(iAtomStart, stimc, c, getij, win, zz, zq) 1534 1535 call hemv(gamxpyq, gammaMat, zq) 1536 1537 1538 ! sum_iAt1 qij(iAt1) gamxpyq(iAt1) 1539 do ij = 1, nxoo 1540 call indxoo(ij, i, j) 1541 qij(:) = transq(i, j, iAtomStart, updwn, stimc, c) 1542 ! W contains 1/2 for i == j. 1543 woo(ij) = woo(ij) + 4.0_dp * sum(qij * gamxpyq) 1544 end do 1545 1546 ! Divide diagonal elements of W_ij by 2. 1547 do ij = 1, nxoo 1548 call indxoo(ij, i, j) 1549 if (i == j) then 1550 woo(ij) = 0.5_dp * woo(ij) 1551 end if 1552 end do 1553 1554 ! Divide diagonal elements of W_ab by 2. 1555 do ab = 1, nxvv 1556 call indxvv(homo, ab, a, b) 1557 if (a == b) then 1558 wvv(ab) = 0.5_dp * wvv(ab) 1559 end if 1560 end do 1561 1562 end subroutine calcWvectorZ 1563 1564 1565 !> Mulliken population for a square density matrix and overlap 1566 !> Note: assumes both triangles of both square matrices are filled 1567 subroutine getExcMulliken(iAtomStart, pc, s, dqex) 1568 1569 !> indexing array for atoms 1570 integer, intent(in) :: iAtomStart(:) 1571 1572 !> density matrix 1573 real(dp), intent(in) :: pc(:,:) 1574 1575 !> overlap matrix 1576 real(dp), intent(in) :: s(:,:) 1577 1578 !> output atomic charges 1579 real(dp), intent(out) :: dqex(:) 1580 1581 real(dp) :: tmp(size(pc,dim=1)) 1582 integer :: iAt1 1583 1584 @:ASSERT(all(shape(pc)==shape(s))) 1585 1586 tmp = sum(pc * s,dim=2) 1587 dqex(:) = 0.0_dp 1588 do iAt1 = 1, size(dqex) 1589 dqex(iAt1) = sum(tmp(iAtomStart(iAt1):iAtomStart(iAt1 + 1) -1)) 1590 end do 1591 1592 end subroutine getExcMulliken 1593 1594 1595 !> Excited state Mulliken charges and dipole moments written to disc 1596 subroutine writeExcMulliken(sym, nstat, dq, dqex, coord0, fdMulliken) 1597 1598 !> symmetry label 1599 character, intent(in) :: sym 1600 1601 !> state index 1602 integer, intent(in) :: nstat 1603 1604 !> ground state gross charge 1605 real(dp), intent(in) :: dq(:) 1606 1607 !> change in atomic charges from ground to excited state 1608 real(dp), intent(in) :: dqex(:) 1609 1610 !> central cell coordinates 1611 real(dp), intent(in) :: coord0(:,:) 1612 1613 !> file unit for Mulliken data 1614 integer, intent(in) :: fdMulliken 1615 1616 integer :: natom, m 1617 real(dp) :: dipol(3), dipabs 1618 1619 natom = size(dq) 1620 1621 @:ASSERT(size(dq) == size(dqex)) 1622 @:ASSERT(all(shape(coord0) == [3,nAtom])) 1623 1624 ! Output of excited state Mulliken charges 1625 open(fdMulliken, file=excitedQOut,position="append") 1626 write(fdMulliken, "(a,a,i2)") "# MULLIKEN CHARGES of excited state ",& 1627 & sym, nstat 1628 write(fdMulliken, "(a,2x,A,i4)") "#", 'Natoms =',natom 1629 write(fdMulliken, "('#',1X,A4,T15,A)")'Atom','netCharge' 1630 write(fdMulliken,'("#",41("="))') 1631 do m = 1, natom 1632 write(fdMulliken,"(i5,1x,f16.8)") m, -dq(m) - dqex(m) 1633 end do 1634 close(fdMulliken) 1635 1636 ! Calculation of excited state dipole moment 1637 dipol(:) = -1.0_dp * matmul(coord0, dq + dqex) 1638 dipabs = sqrt(sum(dipol**2)) 1639 1640 open(fdMulliken, file=excitedDipoleOut, position="append") 1641 write(fdMulliken, "(a,a,i2)") "Mulliken analysis of excited state ",& 1642 & sym, nstat 1643 write(fdMulliken, '(42("="))') 1644 write(fdMulliken, "(a)") " " 1645 write(fdMulliken, "(a)") "Mulliken exc. state dipole moment [Debye]" 1646 write(fdMulliken, '(42("="))') 1647 write(fdMulliken, "(3f14.8)") (dipol(m) * au__Debye, m = 1, 3) 1648 write(fdMulliken, "(a)") " " 1649 write(fdMulliken, "(a)") "Norm of exc. state dipole moment [Debye]" 1650 write(fdMulliken, '(42("="))') 1651 write(fdMulliken, "(e20.12)") dipabs * au__Debye 1652 write(fdMulliken, *) 1653 close(fdMulliken) 1654 1655 end subroutine writeExcMulliken 1656 1657 1658 !> Calculate transition moments for transitions between Kohn-Sham states, including spin-flipping 1659 !> transitions 1660 subroutine calcTransitionDipoles(coord0, win, nmatup, getij, iAtomStart, stimc, grndEigVecs,& 1661 & snglPartTransDip) 1662 1663 !> Atomic positions 1664 real(dp), intent(in) :: coord0(:,:) 1665 1666 !> single particle transition index 1667 integer, intent(in) :: win(:) 1668 1669 !> number of same-spin transitions 1670 integer, intent(in) :: nmatup 1671 1672 !> index array for ground state square matrices 1673 integer, intent(in) :: iAtomStart(:) 1674 1675 !> index array for excitation pairs 1676 integer, intent(in) :: getij(:,:) 1677 1678 !> overlap times ground state wavefunctions 1679 real(dp), intent(in) :: stimc(:,:,:) 1680 1681 !> ground state wavefunctions 1682 real(dp), intent(in) :: grndEigVecs(:,:,:) 1683 1684 !> resulting transition dipoles 1685 real(dp), intent(out) :: snglPartTransDip(:,:) 1686 1687 integer :: nxov, natom 1688 integer :: indm, ii, jj 1689 real(dp), allocatable :: qij(:) 1690 logical :: updwn 1691 1692 nxov = size(win) 1693 natom = size(coord0, dim=2) 1694 1695 ALLOCATE(qij(natom)) 1696 1697 ! Calculate transition dipole elements 1698 do indm = 1, nxov 1699 call indxov(win, indm, getij, ii, jj) 1700 updwn = (win(indm) <= nmatup) 1701 qij(:) = transq(ii, jj, iAtomStart, updwn, stimc, grndEigVecs) 1702 snglPartTransDip(indm, :) = matmul(coord0, qij) 1703 end do 1704 1705 end subroutine calcTransitionDipoles 1706 1707 1708 !> Calculation of force from derivatives of excitation energy 1709 !> 1. we need the ground and excited Mulliken charges 1710 !> 2. we need P,(T,Z),W, X + Y from linear response 1711 !> 3. calculate dsmndr, dhmndr (dS/dR, dh/dR), dgabda (dGamma_{IAt1,IAt2}/dR_{IAt1}), 1712 !> dgext (dGamma-EXT_{IAt1,k}/dR_{IAt1}) 1713 subroutine addGradients(sym, nxov, natom, species0, iAtomStart, norb, homo, nocc, nmatup, getij,& 1714 & win, grndEigVecs, pc, stimc, dq, dqex, gammaMat, HubbardU, spinW, shift, woo, wov, wvv,& 1715 & transChrg, xpy, coord0, orb, skHamCont, skOverCont, derivator, rhoSqr, excgrad) 1716 1717 !> symmetry of the transition 1718 character, intent(in) :: sym 1719 1720 !> number of single particle transitions to include 1721 integer, intent(in) :: nxov 1722 1723 !> number of central cell atoms 1724 integer, intent(in) :: natom 1725 1726 !> central cell chemical species 1727 integer, intent(in) :: species0(:) 1728 1729 !> index array for S and H0 ground state square matrices 1730 integer, intent(in) :: iAtomStart(:) 1731 1732 !> number of orbitals for ground state system 1733 integer, intent(in) :: norb 1734 1735 !> number of highest occupied state in ground state 1736 integer, intent(in) :: homo 1737 1738 !> number of occupied states in calculation (not neccessarily same as HOMO in the case of 1739 !> windowing) 1740 integer, intent(in) :: nocc 1741 1742 !> single particle transition index 1743 integer, intent(in) :: win(:) 1744 1745 !> number of up->up transitions 1746 integer, intent(in) :: nmatup 1747 1748 !> index array from composite transition index to specific single particle states 1749 integer, intent(in) :: getij(:,:) 1750 1751 !> ground state eigenvectors 1752 real(dp), intent(in) :: grndEigVecs(:,:,:) 1753 1754 !> transition density matrix 1755 real(dp), intent(in) :: pc(:,:) 1756 1757 !> overlap times ground state eigenvectors 1758 real(dp), intent(in) :: stimc(:,:,:) 1759 1760 !> ground state gross charges 1761 real(dp), intent(in) :: dq(:) 1762 1763 !> charge differences from ground to excited state 1764 real(dp), intent(in) :: dqex(:) 1765 1766 !> softened coulomb matrix 1767 real(dp), intent(in) :: gammaMat(:,:) 1768 1769 !> ground state Hubbard U values 1770 real(dp), intent(in) :: HubbardU(:) 1771 1772 !> ground state spin derivatives for each species 1773 real(dp), intent(in) :: spinW(:) 1774 1775 !> ground state potentials (shift vector) 1776 real(dp), intent(in) :: shift(:) 1777 1778 !> W vector occupied part 1779 real(dp), intent(in) :: woo(:) 1780 1781 !> W vector occupied-virtual part 1782 real(dp), intent(in) :: wov(:) 1783 1784 !> W vector virtual part 1785 real(dp), intent(in) :: wvv(:) 1786 1787 !> machinery for transition charges between single particle levels 1788 type(TTransCharges), intent(in) :: transChrg 1789 1790 !> X+Y Furche term 1791 real(dp), intent(in) :: xpy(:) 1792 1793 !> central cell atomic coordinates 1794 real(dp), intent(in) :: coord0(:,:) 1795 1796 !> data type for atomic orbital information 1797 type(TOrbitals), intent(in) :: orb 1798 1799 !> H0 data 1800 type(OSlakoCont), intent(in) :: skHamCont 1801 1802 !> overlap data 1803 type(OSlakoCont), intent(in) :: skOverCont 1804 1805 !> Differentiatior for the non-scc matrices 1806 class(NonSccDiff), intent(in) :: derivator 1807 1808 !> ground state density matrix for spin-free case 1809 real(dp), intent(in) :: rhoSqr(:,:) 1810 1811 !> resulting excited state gradient 1812 real(dp), intent(out) :: excgrad(:,:) 1813 1814 real(dp), allocatable :: shift_excited(:), xpyq(:) 1815 real(dp), allocatable :: shxpyq(:), xpycc(:,:), wcc(:,:) 1816 real(dp), allocatable :: qij(:), temp(:) 1817 real(dp), allocatable :: dH0(:,:,:), dS(:,:,:) 1818 integer :: ia, i, j, a, b, ab, ij, m, n, mu, nu, xyz, iAt1, iAt2 1819 integer :: indalpha, indalpha1, indbeta, indbeta1 1820 integer :: iSp1, iSp2 1821 real(dp) :: tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, rab 1822 real(dp) :: diffvec(3), dgab(3), tmp3a, tmp3b 1823 1824 integer :: nxoo, nxvv 1825 1826 ALLOCATE(shift_excited(natom)) 1827 ALLOCATE(xpyq(natom)) 1828 ALLOCATE(shxpyq(natom)) 1829 ALLOCATE(xpycc(norb, norb)) 1830 ALLOCATE(wcc(norb, norb)) 1831 ALLOCATE(qij(natom)) 1832 ALLOCATE(temp(norb)) 1833 1834 ALLOCATE(dH0(orb%mOrb, orb%mOrb, 3)) 1835 ALLOCATE(dS(orb%mOrb, orb%mOrb, 3)) 1836 1837 nxoo = size(woo) 1838 nxvv = size(wvv) 1839 1840 excgrad = 0.0_dp 1841 1842 ! excited state potentials at atomic sites 1843 call hemv(shift_excited, gammaMat, dqex) 1844 1845 ! xypq(alpha) = sum_ia (X+Y)_ia q^ia(alpha) 1846 ! complexity norb * norb * norb 1847 xpyq(:) = 0.0_dp 1848 call transChrg%qMatVec(iAtomStart, stimc, grndEigVecs, getij, win, xpy,xpyq) 1849 1850 ! complexity norb * norb 1851 shxpyq(:) = 0.0_dp 1852 if (sym == "S") then 1853 call hemv(shxpyq, gammaMat, xpyq) 1854 else 1855 shxpyq(:) = xpyq(:) * spinW(species0) 1856 end if 1857 1858 ! calculate xpycc 1859 ! (xpycc)_{mu nu} = sum_{ia} (X + Y)_{ia} (grndEigVecs(mu,i)grndEigVecs(nu,a) 1860 ! + grndEigVecs(nu,i)grndEigVecs(mu,a)) 1861 ! complexity norb * norb * norb 1862 ! 1863 ! xpycc(mu,nu) = sum_ia (X+Y)_ia grndEigVecs(mu,i) grndEigVecs(nu,a) 1864 ! xpycc(mu, nu) += sum_ia (X+Y)_ia grndEigVecs(mu,a) grndEigVecs(nu,i) 1865 xpycc(:,:) = 0.0_dp 1866 do ia = 1, nxov 1867 call indxov(win, ia, getij, i, a) 1868 ! should replace with DSYR2 call : 1869 do nu = 1, norb 1870 do mu = 1, norb 1871 xpycc(mu,nu) = xpycc(mu,nu) + xpy(ia) *& 1872 & ( grndEigVecs(mu,i,1)*grndEigVecs(nu,a,1)& 1873 & + grndEigVecs(mu,a,1)*grndEigVecs(nu,i,1) ) 1874 end do 1875 end do 1876 end do 1877 1878 ! calculate wcc = c_mu,i * W_ij * c_j,nu. We have only W_ab b > a and W_ij j > i: 1879 ! wcc(m,n) = sum_{pq, p <= q} w_pq (grndEigVecs(mu,p)grndEigVecs(nu,q) 1880 ! + grndEigVecs(nu,p)grndEigVecs(mu,q)) 1881 ! complexity norb * norb * norb 1882 1883 ! calculate the occ-occ part 1884 wcc(:,:) = 0.0_dp 1885 1886 do ij = 1, nxoo 1887 call indxoo(ij, i, j) 1888 ! replace with DSYR2 call : 1889 do mu = 1, norb 1890 do nu = 1, norb 1891 wcc(mu,nu) = wcc(mu,nu) + woo(ij) *& 1892 & ( grndEigVecs(mu,i,1)*grndEigVecs(nu,j,1)& 1893 & + grndEigVecs(mu,j,1)*grndEigVecs(nu,i,1) ) 1894 end do 1895 end do 1896 1897 end do 1898 1899 ! calculate the occ-virt part : the same way as for xpycc 1900 do ia = 1, nxov 1901 call indxov(win, ia, getij, i, a) 1902 ! again replace with DSYR2 call : 1903 do nu = 1, norb 1904 do mu = 1, norb 1905 wcc(mu,nu) = wcc(mu,nu) + wov(ia) *& 1906 & ( grndEigVecs(mu,i,1)*grndEigVecs(nu,a,1)& 1907 & + grndEigVecs(mu,a,1)*grndEigVecs(nu,i,1) ) 1908 end do 1909 end do 1910 end do 1911 1912 ! calculate the virt - virt part 1913 do ab =1, nxvv 1914 call indxvv(homo, ab, a, b) 1915 ! replace with DSYR2 call : 1916 do mu = 1, norb 1917 do nu = 1, norb 1918 wcc(mu,nu) = wcc(mu,nu) + wvv(ab) *& 1919 & ( grndEigVecs(mu,a,1)*grndEigVecs(nu,b,1)& 1920 & + grndEigVecs(mu,b,1)*grndEigVecs(nu,a,1) ) 1921 end do 1922 end do 1923 end do 1924 1925 1926 ! now calculating the force complexity : norb * norb * 3 1927 1928 ! as have already performed norb**3 operation to get here, 1929 ! calculate for all atoms 1930 1931 ! BA: only for non-periodic systems! 1932 do iAt1 = 1, nAtom 1933 indalpha = iAtomStart(iAt1) 1934 indalpha1 = iAtomStart(iAt1 + 1) -1 1935 iSp1 = species0(iAt1) 1936 1937 do iAt2 = 1, iAt1 - 1 1938 indbeta = iAtomStart(iAt2) 1939 indbeta1 = iAtomStart(iAt2 + 1) -1 1940 iSp2 = species0(iAt2) 1941 1942 diffvec = coord0(:,iAt1) - coord0(:,iAt2) 1943 rab = sqrt(sum(diffvec**2)) 1944 1945 ! now holds unit vector in direction 1946 diffvec = diffvec / rab 1947 1948 ! calculate the derivative of gamma 1949 dgab(:) = diffvec(:) * (-1.0_dp/rab**2 - expGammaPrime(rab, HubbardU(iSp1), HubbardU(iSp2))) 1950 1951 tmp3a = dq(iAt1) * dqex(iAt2) + dqex(iAt1) * dq(iAt2) 1952 1953 if (sym == "S") then 1954 tmp3b = 4.0_dp * xpyq(iAt1) * xpyq(iAt2) 1955 else 1956 tmp3b = 0.0_dp 1957 end if 1958 1959 excgrad(:,iAt1) = excgrad(:,iAt1) + dgab(:) * ( tmp3a + tmp3b ) 1960 excgrad(:,iAt2) = excgrad(:,iAt2) - dgab(:) * ( tmp3a + tmp3b ) 1961 1962 tmp5 = shift_excited(iAt1) + shift_excited(iAt2) 1963 tmp7 = 2.0_dp * ( shxpyq(iAt1) + shxpyq(iAt2) ) 1964 1965 call derivator%getFirstDeriv(dH0, skHamCont, coord0, species0,& 1966 & iAt1, iAt2, orb) 1967 call derivator%getFirstDeriv(dS, skOverCont, coord0, species0,& 1968 & iAt1, iAt2, orb) 1969 1970 do xyz = 1, 3 1971 1972 tmp1 = 0.0_dp 1973 tmp2 = 0.0_dp 1974 tmp3 = 0.0_dp 1975 tmp4 = 0.0_dp 1976 tmp6 = 0.0_dp 1977 1978 do mu = indalpha, indalpha1 1979 do nu = indbeta, indbeta1 1980 m = mu - indalpha + 1 1981 n = nu - indbeta + 1 1982 1983 tmp1 = tmp1 + 2.0_dp * dH0(n,m,xyz) * pc(mu,nu) 1984 tmp2 = tmp2 + dS(n,m,xyz) * pc(mu,nu) * (shift(iAt1)+shift(iAt2)) 1985 tmp3 = tmp3 - dS(n,m,xyz) * wcc(mu,nu) 1986 tmp4 = tmp4 + tmp5 * dS(n,m,xyz) * rhoSqr(mu,nu) 1987 tmp6 = tmp6 + tmp7 * dS(n,m,xyz) * xpycc(mu,nu) 1988 end do 1989 end do 1990 excgrad(xyz,iAt1) = excgrad(xyz,iAt1)& 1991 & + tmp1 + tmp2 + tmp4 + tmp6 + tmp3 1992 excgrad(xyz,iAt2) = excgrad(xyz,iAt2)& 1993 & - tmp1 - tmp2 - tmp4 - tmp6 - tmp3 1994 end do 1995 end do 1996 end do 1997 1998 end subroutine addGradients 1999 2000 2001 !> Write out excitations projected onto ground state 2002 subroutine writeCoeffs(tt, grndEigVecs, occ, nocc, fdCoeffs, tCoeffs, tIncGroundState,& 2003 & occNatural, naturalOrbs) 2004 2005 !> T part of the matrix 2006 real(dp), intent(in) :: tt(:,:) 2007 2008 !> ground state eigenvectors 2009 real(dp), intent(in) :: grndEigVecs(:,:,:) 2010 2011 !> ground state occupations 2012 real(dp), intent(in) :: occ(:,:) 2013 2014 !> number of filled states 2015 integer, intent(in) :: nocc 2016 2017 !> file descriptor to write data into 2018 integer, intent(in) :: fdCoeffs 2019 2020 !> save the coefficients of the natural orbitals 2021 logical, intent(in) :: tCoeffs 2022 2023 !> include the ground state as well as the transition part 2024 logical, intent(in) :: tIncGroundState 2025 2026 !> Natural orbital occupation numbers 2027 real(dp), intent(out), optional :: occNatural(:) 2028 2029 !> Natural orbitals 2030 real(dp), intent(out), optional :: naturalOrbs(:,:,:) 2031 2032 real(dp), allocatable :: t2(:,:), occtmp(:) 2033 integer :: norb, ii, jj, mm 2034 2035 norb = size(tt, dim=1) 2036 2037 if (present(occNatural).or.tCoeffs) then 2038 2039 ALLOCATE(t2(norb, norb)) 2040 t2 = tt 2041 if (tIncGroundState) then 2042 do ii = 1, nocc 2043 t2(ii,ii) = t2(ii,ii) + occ(ii,1) 2044 end do 2045 end if 2046 2047 if (present(occNatural)) then 2048 naturalOrbs(:,:,1) = t2 2049 call evalCoeffs(naturalOrbs(:,:,1), occNatural, grndEigVecs(:,:,1)) 2050 if (tCoeffs) then 2051 ALLOCATE(occtmp(size(occ))) 2052 occTmp = occNatural 2053 end if 2054 else 2055 ALLOCATE(occtmp(size(occ))) 2056 occtmp = 0.0_dp 2057 call evalCoeffs(t2, occtmp, grndEigVecs(:,:,1)) 2058 end if 2059 2060 ! Better to get this by post-processing DFTB+ output, but here for 2061 ! compatibility at the moment 2062 if (tCoeffs) then 2063 open(fdCoeffs, file=excitedCoefsOut, position="append") 2064 write(fdCoeffs,*) 'T F' 2065 do ii = 1, norb 2066 jj = norb - ii + 1 2067 write(fdCoeffs, '(1x,i3,1x,f13.10,1x,f13.10)') ii, occtmp(jj), 2.0_dp 2068 write(fdCoeffs, '(6(f13.10,1x))') (cmplx(t2(mm,jj), kind=dp),& 2069 & mm = 1, norb) 2070 end do 2071 close(fdCoeffs) 2072 end if 2073 2074 end if 2075 2076 end subroutine writeCoeffs 2077 2078 2079 !> Project MO density matrix onto ground state orbitals 2080 subroutine evalCoeffs(t2, occ, eig) 2081 2082 !> density matrix 2083 real(dp), intent(inout) :: t2(:,:) 2084 2085 !> resulting natural orbital occupations 2086 real(dp), intent(out) :: occ(:) 2087 2088 !> 'natural' eigenvectors 2089 real(dp), intent(in) :: eig(:,:) 2090 2091 real(dp), allocatable :: coeffs(:,:) 2092 2093 ALLOCATE(coeffs(size(occ),size(occ))) 2094 2095 call heev(t2, occ, 'U', 'V') 2096 call gemm(coeffs, eig, t2) 2097 t2 = coeffs 2098 2099 end subroutine evalCoeffs 2100 2101 2102 !> Write out transitions from ground to excited state along with single particle transitions and 2103 !> dipole strengths 2104 subroutine writeExcitations(sym, osz, nexc, nmatup, getij, win, eval, evec, wij, fdXplusY,& 2105 & fdTrans, fdTradip, transitionDipoles, tWriteTagged, fdTagged, taggedWriter, fdExc, Ssq) 2106 2107 !> Symmetry label for the type of transition 2108 character, intent(in) :: sym 2109 2110 !> oscillator strengths for transitions from ground to excited states 2111 real(dp), intent(in) :: osz(:) 2112 2113 !> number of excited states to solve for 2114 integer, intent(in) :: nexc 2115 2116 !> number of same spin excitations 2117 integer, intent(in) :: nmatup 2118 2119 !> index array between transitions in square and 1D representations 2120 integer, intent(in) :: getij(:,:) 2121 2122 !> index array for single particle excitions 2123 integer, intent(in) :: win(:) 2124 2125 !> excitation energies 2126 real(dp), intent(in) :: eval(:) 2127 2128 !> eigenvectors of excited states 2129 real(dp), intent(in) :: evec(:,:) 2130 2131 !> single particle excitation energies 2132 real(dp), intent(in) :: wij(:) 2133 2134 !> single particle transition dipole moments 2135 real(dp), intent(in) :: transitionDipoles(:,:) 2136 2137 !> should tagged information be written out 2138 logical, intent(in) :: tWriteTagged 2139 2140 !> file unit for transition dipoles 2141 integer, intent(in) :: fdTradip 2142 2143 !> file unit for X+Y data 2144 integer, intent(in) :: fdXplusY 2145 2146 !> file unit for transitions 2147 integer, intent(in) :: fdTrans 2148 2149 !> file unit for tagged output (> -1 for write out) 2150 integer, intent(in) :: fdTagged 2151 2152 !> tagged writer 2153 type(TTaggedWriter), intent(inout) :: taggedWriter 2154 2155 !> file unit for excitation energies 2156 integer, intent(in) :: fdExc 2157 2158 !> For spin polarized systems, measure of spin 2159 real(dp), intent(in), optional :: Ssq(:) 2160 2161 integer :: nmat 2162 integer :: i, j, iweight, indo, m, n 2163 integer :: iDeg 2164 real(dp), allocatable :: wvec(:) 2165 real(dp), allocatable :: xply(:) 2166 real(dp), allocatable :: eDeg(:) 2167 real(dp), allocatable :: oDeg(:) 2168 integer, allocatable :: wvin(:) 2169 real(dp) :: rsqw, weight, wvnorm 2170 logical :: updwn, tSpin 2171 character :: sign 2172 2173 @:ASSERT(fdExc > 0) 2174 2175 tSpin = present(Ssq) 2176 nmat = size(wij) 2177 ALLOCATE(wvec(nmat)) 2178 ALLOCATE(wvin(nmat)) 2179 ALLOCATE(xply(nmat)) 2180 ALLOCATE(eDeg(nexc)) 2181 ALLOCATE(oDeg(nexc)) 2182 wvec = 0.0_dp 2183 wvin = 0 2184 xply = 0.0_dp 2185 eDeg = 0.0_dp 2186 oDeg = 0.0_dp 2187 2188 if(fdXplusY > 0) then 2189 write(fdXplusY,*) nmat, nexc 2190 end if 2191 2192 do i = 1, nexc 2193 if (eval(i) > 0.0_dp) then 2194 2195 ! calculate weight of single particle transitions 2196 rsqw = 1.0_dp / sqrt(eval(i)) 2197 ! (X+Y)^ia_I = sqrt(wij) / sqrt(omega) * F^ia_I 2198 xply(:) = sqrt(rsqw) * sqrt(wij(:)) * evec(:,i) 2199 wvec(:) = xply(:)**2 2200 wvnorm = 1.0_dp / sqrt(sum(wvec**2)) 2201 wvec(:) = wvec(:) * wvnorm 2202 2203 ! find largest coefficient in CI - should use maxloc 2204 call index_heap_sort(wvin,wvec) 2205 wvin = wvin(size(wvin):1:-1) 2206 wvec = wvec(wvin) 2207 2208 weight = wvec(1) 2209 iweight = wvin(1) 2210 2211 call indxov(win, iweight, getij, m, n) 2212 sign = sym 2213 if (tSpin) then 2214 sign = " " 2215 write(fdExc,& 2216 & '(1x,f10.3,4x,f14.8,2x,i5,3x,a,1x,i5,7x,f6.3,2x,f10.3,4x,& 2217 & f6.3)')& 2218 & Hartree__eV * sqrt(eval(i)), osz(i), m, '->', n, weight,& 2219 & Hartree__eV * wij(iweight), Ssq(i) 2220 else 2221 write(fdExc,& 2222 & '(1x,f10.3,4x,f14.8,5x,i5,3x,a,1x,i5,7x,f6.3,2x,f10.3,6x,a)')& 2223 & Hartree__eV * sqrt(eval(i)), osz(i), m, '->', n, weight,& 2224 & Hartree__eV * wij(iweight), sign 2225 end if 2226 2227 if(fdXplusY > 0) then 2228 if (tSpin) then 2229 updwn = (win(iweight) <= nmatup) 2230 sign = "D" 2231 if (updwn) sign = "U" 2232 end if 2233 write(fdXplusY,'(1x,i5,3x,a,3x,ES17.10)') i,sign, sqrt(eval(i)) 2234 write(fdXplusY,'(6(1x,ES17.10))') xply(:) 2235 endif 2236 2237 if (fdTrans > 0) then 2238 write(fdTrans, '(2x,a,T12,i5,T21,ES17.10,1x,a,2x,a)')& 2239 & 'Energy ', i, Hartree__eV * sqrt(eval(i)), 'eV', sign 2240 write(fdTrans,*) 2241 write(fdTrans,'(2x,a,9x,a,8x,a)')& 2242 & 'Transition', 'Weight', 'KS [eV]' 2243 write(fdTrans,'(1x,45("="))') 2244 2245 sign = " " 2246 do j = 1, nmat 2247 !if (wvec(j) < 1e-4_dp) exit ! ?????? 2248 indo = wvin(j) 2249 call indxov(win, indo, getij, m, n) 2250 if (tSpin) then 2251 updwn = (win(indo) <= nmatup) 2252 sign = "D" 2253 if (updwn) sign = "U" 2254 end if 2255 write(fdTrans,& 2256 & '(i5,3x,a,1x,i5,1x,1a,T22,f10.8,T33,f14.8)')& 2257 & m, '->', n, sign, wvec(j), Hartree__eV * wij(wvin(j)) 2258 end do 2259 write(fdTrans,*) 2260 end if 2261 2262 if(fdTradip > 0) then 2263 write(fdTradip, '(1x,i5,1x,f10.3,2x,3(ES13.6))')& 2264 & i, Hartree__eV * sqrt(eval(i)), (transitionDipoles(i,j)& 2265 & * au__Debye, j=1,3) 2266 endif 2267 else 2268 2269 ! find largest coefficient in CI - should use maxloc 2270 call index_heap_sort(wvin,wvec) 2271 wvin = wvin(size(wvin):1:-1) 2272 wvec = wvec(wvin) 2273 2274 weight = wvec(1) 2275 iweight = wvin(1) 2276 call indxov(win, iweight, getij, m, n) 2277 sign = sym 2278 2279 if (tSpin) then 2280 sign = " " 2281 write(fdExc,& 2282 & '(6x,A,T12,4x,f14.8,2x,i5,3x,a,1x,i5,7x,A,2x,f10.3,4x,f6.3)')& 2283 & '< 0', osz(i), m, '->', n, '-', Hartree__eV * wij(iweight),& 2284 & Ssq(i) 2285 else 2286 write(fdExc,& 2287 & '(6x,A,T12,4x,f14.8,2x,i5,3x,a,1x,i5,7x,f6.3,2x,f10.3,6x,a)')& 2288 & '< 0', osz(i), m, '->', n, weight,& 2289 & Hartree__eV * wij(iweight), sign 2290 end if 2291 2292 if(fdXplusY > 0) then 2293 if (tSpin) then 2294 updwn = (win(iweight) <= nmatup) 2295 sign = "D" 2296 if (updwn) sign = "U" 2297 end if 2298 write(fdXplusY,'(1x,i5,3x,a,3x,A)') i,sign, '-' 2299 endif 2300 2301 if (fdTrans > 0) then 2302 write(fdTrans, '(2x,a,1x,i5,5x,a,1x,a,3x,a)')& 2303 & 'Energy ', i, '-', 'eV', sign 2304 write(fdTrans,*) 2305 end if 2306 2307 if(fdTradip > 0) then 2308 write(fdTradip, '(1x,i5,1x,A)') i, '-' 2309 endif 2310 2311 end if 2312 2313 end do 2314 2315 ! Determine degenerate levels and sum oscillator strength over any degenerate levels 2316 iDeg = 1 2317 eDeg(1) = eval(1) 2318 oDeg(1) = osz(1) 2319 do i = 2, nexc 2320 if(abs(eval(i)-eval(i-1)) < elecTolMax) then 2321 oDeg(iDeg) = oDeg(iDeg) + osz(i) 2322 else 2323 iDeg = iDeg + 1 2324 eDeg(iDeg) = eval(i) 2325 oDeg(iDeg) = osz(i) 2326 endif 2327 end do 2328 if (tWriteTagged) then 2329 call taggedWriter%write(fdTagged, tagLabels%excEgy, eDeg(:iDeg)) 2330 call taggedWriter%write(fdTagged, tagLabels%excOsc, oDeg(:iDeg)) 2331 end if 2332 2333 end subroutine writeExcitations 2334 2335 2336 !> Create transition density matrix in MO basis P = T + 1/2 Z symmetric (paper has T + Z 2337 !> asymmetric) (Zab = Zij = 0, Tia = 0) 2338 subroutine calcPMatrix(t, rhs, win, getij, pc) 2339 2340 !> T matrix 2341 real(dp), intent(in) :: t(:,:) 2342 2343 !> Z matrix 2344 real(dp), intent(in) :: rhs(:) 2345 2346 !> index array for single particle transitions 2347 integer, intent(in) :: win(:) 2348 2349 !> array of the occupied->virtual pairs (nTransitions,occ 1 or virtual 2) 2350 integer, intent(in) :: getij(:,:) 2351 2352 !> resulting excited state density matrix 2353 real(dp), intent(out) :: pc(:,:) 2354 2355 integer :: ia, i, a 2356 2357 pc = 0.0_dp 2358 do ia = 1, size(rhs) 2359 call indxov(win, ia, getij, i, a) 2360 pc(i,a) = rhs(ia) 2361 end do 2362 pc = 0.5_dp * ( pc + transpose(pc) ) 2363 2364 pc = pc + t 2365 2366 end subroutine calcPMatrix 2367 2368 2369 !> Write single particle excitations to a file as well as potentially to tagged output file (in 2370 !> that case, summing over degeneracies) 2371 subroutine writeSPExcitations(wij, win, nmatup, getij, fdSPTrans, sposz, nxov, tSpin) 2372 2373 !> single particle excitation energies 2374 real(dp), intent(in) :: wij(:) 2375 2376 !> index array for single particle transitions 2377 integer, intent(in) :: win(:) 2378 2379 !> number of transitions within same spin channel 2380 integer, intent(in) :: nmatup 2381 2382 !> index from composite index to occupied and virtual single particle states 2383 integer, intent(in) :: getij(:,:) 2384 2385 !> file descriptor for the single particle excitation data 2386 integer, intent(in) :: fdSPTrans 2387 2388 !> single particle oscilation strengths 2389 real(dp), intent(in) :: sposz(:) 2390 2391 !> Number of included single particle excitations to print out (assumes that win and wij are 2392 !> sorted so that the wanted transitions are first in the array) 2393 integer, intent(in) :: nxov 2394 2395 !> is this a spin-polarized calculation? 2396 logical, intent(in) :: tSpin 2397 2398 integer :: indm, m, n 2399 logical :: updwn 2400 character :: sign 2401 2402 @:ASSERT(size(sposz)>=nxov) 2403 2404 if (fdSPTrans > 0) then 2405 ! single particle excitations 2406 open(fdSPTrans, file=singlePartOut, position="rewind", status="replace") 2407 write(fdSPTrans,*) 2408 write(fdSPTrans,'(7x,a,7x,a,8x,a)') '# w [eV]',& 2409 & 'Osc.Str.', 'Transition' 2410 write(fdSPTrans,*) 2411 write(fdSPTrans,'(1x,58("="))') 2412 write(fdSPTrans,*) 2413 do indm = 1, nxov 2414 call indxov(win, indm, getij, m, n) 2415 sign = " " 2416 if (tSpin) then 2417 updwn = (win(indm) <= nmatup) 2418 if (updwn) then 2419 sign = "U" 2420 else 2421 sign = "D" 2422 end if 2423 end if 2424 write(fdSPTrans,& 2425 & '(1x,i7,3x,f8.3,3x,f13.7,4x,i5,3x,a,1x,i5,1x,1a)')& 2426 & indm, Hartree__eV * wij(indm), sposz(indm), m, '->', n, sign 2427 end do 2428 write(fdSPTrans,*) 2429 close(fdSPTrans) 2430 end if 2431 2432 end subroutine writeSPExcitations 2433 2434end module dftbp_linrespgrad 2435