46 type,
extends(baseintegral) :: alchemyintegral
49 real(wp),
pointer :: one_electron_integral(:)
50 real(wp),
pointer :: two_electron_integral(:)
51 integer :: num_one_electron_integrals
52 integer :: num_two_electron_integrals
53 integer :: integral_ordering
54 integer :: use_scf = 0
57 integer :: num_unique_pairs
59 integer(longint),
allocatable :: pair_labels(:,:)
61 integer,
allocatable :: num_orbitals_sym(:)
63 integer :: max_number_pair_sets
64 integer,
allocatable :: num_two_electron_blocks(:)
65 integer,
allocatable :: num_one_electron_blocks(:)
66 integer,
allocatable :: one_electron_pointer(:)
67 integer,
allocatable :: two_electron_pointer(:)
69 integer :: num_pq, num_rs
70 integer :: num_pair_idx
73 integer,
allocatable :: pair_idx(:)
74 integer,
allocatable :: orbital_idx(:)
75 integer,
allocatable :: symmetry_idx(:)
79 procedure,
public :: initialize_self => initialize_alchemy
80 procedure,
public :: finalize_self => finalize_alchemy
81 procedure,
public :: load_integrals => load_integrals_alchemy
82 procedure,
public :: get_integral_ijklm => get_integral_alchemy
83 procedure,
public :: destroy_integrals => destroy_integral_alchemy
84 procedure,
public :: write_geometries => write_geometries_alchemy
85 procedure,
private :: count_num_pairs
86 procedure,
private :: generate_pairs
87 procedure,
private :: generate_pointer_table
88 procedure,
private :: generate_pair_index
89 procedure,
private :: generate_orbital_index
92 procedure,
private :: get_one_electron_index
93 procedure,
private :: get_two_electron_index
95 end type alchemyintegral
103 integer function count_num_pairs (this)
104 class(alchemyintegral) :: this
105 integer :: pair_number, mdo, ndo, ido, jdo, nn(5), msym, begin, pass, istart, num_sym
107 num_sym = this % num_symmetries
108 msym = num_sym + num_sym - 1
111 if (this % use_SCF == 0)
then
116 do ndo = begin, num_sym
118 nn(3) = abs(ndo - mdo)
121 nn(5) = abs(ido - mdo)
122 count_num_pairs = count_num_pairs + 1
131 do ndo = mdo / 2 + pass, num_sym
133 nn(3) = abs(ndo - mdo)
134 istart = ndo + 1 - pass
135 if (mdo /= 1 .and. pass == 1) begin = istart
136 do ido = begin, istart
138 nn(5) = abs(ido - mdo)
139 count_num_pairs = count_num_pairs + 1
154 subroutine generate_pairs (this)
155 class(alchemyintegral) :: this
156 integer :: pair_number, npqrs, nn(5), mdo, ndo, ido, jdo, I, IBGN, IF, IPASS, J, K, M, MSYM, N, NBGN, begin, pass, num_sym
157 integer(longint) :: packed_label(NIDX)
158 integer,
allocatable :: lpqrs(:,:)
160 num_sym = this % num_symmetries
161 msym = num_sym + num_sym - 1
163 allocate(lpqrs(5, this % num_unique_pairs))
167 if (this % use_SCF == 0)
then
172 do ndo = begin, num_sym
174 nn(3) = abs(ndo - mdo)
177 nn(5) = abs(ido - mdo)
178 pair_number = pair_number + 1
180 lpqrs(jdo,pair_number) = nn(jdo)
190 do n = m / 2 + ipass, num_sym
194 if (m /= 1 .and. ipass == 1) ibgn =
IF
198 pair_number = pair_number + 1
200 lpqrs(j,pair_number) = nn(j)
209 if (pair_number /= this % num_unique_pairs) stop
"Error in pair count"
211 do ido = 1, this % num_unique_pairs
212 call pack_ints(lpqrs(2,ido), lpqrs(3,ido), lpqrs(4,ido), lpqrs(5,ido), 0, 0, 0, 0, packed_label)
213 if (lpqrs(2,ido) + lpqrs(3,ido) /= lpqrs(1,ido)) packed_label(1) = -packed_label(1)
214 this % pair_labels(:,ido) = packed_label
217 write (stdout,
"(' NMPRS=',I5//' LPQRS'/(2X,5(2X,I3)))") this % num_unique_pairs, &
218 ((lpqrs(ido,jdo), ido = 1, 5), jdo = 1, this % num_unique_pairs)
225 subroutine generate_pointer_table (this)
226 class(alchemyintegral) :: this
227 integer :: label(8), num_orbs(4), size_two_pointer
228 integer(longint) :: packed_label(NIDX)
229 integer :: ido, jdo, nam1, nam2, num_pq, num_rs, num_pr
230 integer :: block_number, mvl, md, mm, m, mpa, mpb, mp
234 size_two_pointer = this % num_symmetries * (this % num_symmetries + 1) / 2
235 do ido = 2, this % num_symmetries
236 size_two_pointer = size_two_pointer + (this % num_symmetries - ido + 2) * (this % num_symmetries - ido + 1)
239 allocate(this % num_two_electron_blocks(2 * this % num_symmetries + 1))
241 this % num_two_electron_blocks(1) = 0
242 this % num_two_electron_blocks(2) = indfunc(this % num_symmetries + 1, 0)
244 mvl = 2 * this% num_symmetries - 1
248 mm = this % num_symmetries - md - 1
249 this% num_two_electron_blocks(ido + 1) = this % num_two_electron_blocks(ido) + indfunc(mm + 1, 0)
252 allocate(this % one_electron_pointer(this % num_symmetries + 1))
254 this % one_electron_pointer(1) = 1
256 do ido = 1, this % num_symmetries
257 this % one_electron_pointer(ido + 1) = this % one_electron_pointer(ido) + indfunc(this % num_orbitals_sym(ido) + 1, 0)
260 allocate(this % two_electron_pointer(this % num_two_electron_blocks(mvl + 1)))
262 do ido =1, this % num_two_electron_blocks(mvl + 1)
263 this % two_electron_pointer(ido) = 0
266 this % num_one_electron_integrals = this % one_electron_pointer(this % num_symmetries + 1) - 1
267 this % num_two_electron_integrals = 1
269 write (stdout,
"(//,5X,'Integral Storage Table follows : ',/)")
271 do ido = 1, this % num_unique_pairs
273 packed_label(:) = this % pair_labels(:,ido)
275 if (packed_label(1) > 0)
then
279 packed_label(1) = -packed_label(1)
282 call unpack_ints(packed_label, label)
285 num_orbs(jdo) = this % num_orbitals_sym(label(jdo) + 1)
289 m = label(1) + label(2)
291 m = abs(label(1) - label(2))
303 mp = (mpb * (mpb - 1)) / 2 + mpa + this % num_two_electron_blocks(m + 1)
306 mp = (mpa * (mpa - 1)) / 2 + mpb + this % num_two_electron_blocks(m + 1)
309 this % two_electron_pointer(mp) = this % num_two_electron_integrals
311 if (label(1) == label(2))
then
312 num_pq = indfunc(num_orbs(1) + 1, 0)
314 num_pq = num_orbs(1) * num_orbs(2)
317 if (label(3) == label(4))
then
318 num_rs = indfunc(num_orbs(3) + 1, 0)
320 num_rs = num_orbs(3) * num_orbs(4)
322 this % max_number_pair_sets = max(this % max_number_pair_sets, num_pq, num_rs)
323 if (label(1) == label(3) .and. label(2) == label(4))
then
324 this % num_two_electron_integrals = this % num_two_electron_integrals + indfunc(num_pq + 1, 0)
326 this % num_two_electron_integrals = this % num_two_electron_integrals + num_pq * num_rs
330 this % num_two_electron_integrals = this % num_two_electron_integrals - 1
332 write (stdout,
"('No of 1 electron integrals = ',i8)") this % num_one_electron_integrals
333 write (stdout,
"('No of 2 electron integrals = ',i8)") this % num_two_electron_integrals
338 subroutine generate_orbital_index (this)
339 class(alchemyintegral) :: this
340 integer :: total_num_orbitals, orbital, iorb, isym, max_orbitals, ifail
342 total_num_orbitals = sum(this % num_orbitals_sym(:))
344 allocate(this % orbital_idx(total_num_orbitals), &
345 this % symmetry_idx(total_num_orbitals), stat = ifail)
347 call master_memory % track_memory(storage_size(this%orbital_idx)/8,
size(this % orbital_idx), ifail,
'SWEDEN::pair_idx')
348 call master_memory % track_memory(storage_size(this%symmetry_idx)/8,
size(this % symmetry_idx), ifail, &
349 'SWEDEN::symmetry_idx')
351 this % orbital_idx(:) = 0
352 this % symmetry_idx(:) = 0
357 do isym = 1,this % num_symmetries
358 max_orbitals = max(max_orbitals, this % num_orbitals_sym(isym)**2)
359 do iorb = 1, this % num_orbitals_sym(isym)
360 orbital = orbital + 1
361 this % orbital_idx(orbital) = iorb
362 this % symmetry_idx(orbital) = isym - 1
366 this % num_pair_idx = max((this% num_symmetries**2 + this % num_symmetries) / 2 + 1, &
367 this % max_number_pair_sets, &
374 subroutine generate_pair_index (this)
375 class(alchemyintegral) :: this
376 integer :: ido, idx, ifail
378 allocate(this % pair_idx(0:this % num_pair_idx), stat = ifail)
380 call master_memory % track_memory(storage_size(this % pair_idx)/8,
size(this % pair_idx), ifail,
'SWEDEN::pair_idx')
383 this % pair_idx(0) = 0
384 do ido = 1, this % num_pair_idx
385 this % pair_idx(ido) = idx
392 subroutine initialize_alchemy (this, option)
393 class(alchemyintegral) :: this
394 class(options),
intent(in) :: option
397 write (stdout,
"('Using ALCHEMY integral')")
399 this % num_unique_pairs = 0
400 this % num_symmetries = option % num_syms
401 this % integral_ordering = option % integral_ordering
402 this % use_SCF = option % use_SCF
406 allocate(this % num_orbitals_sym(this % num_symmetries))
408 this % num_orbitals_sym(:) = option % num_electronic_orbitals_sym(:)
409 this % num_unique_pairs = this % count_num_pairs()
411 write (stdout, *)
'Number of pairs =',this % num_unique_pairs
413 allocate(this % pair_labels(2, this % num_unique_pairs))
415 write (stdout,*)
'ALCHEMY Integral -- Generating pairs'
418 call this % generate_pairs
419 call this % generate_orbital_index
420 call this % generate_pair_index
422 write (stdout,
"('1',/,10x,'D2h Two Electron Integral Box ','Information')")
423 write (stdout,
"( /,10x,'No. of Boxes = ',i4,/)") this % num_unique_pairs
424 write (stdout,
"( 10x,'Box Descriptions: ',/)")
425 write (stdout, *)
'ALCHEMY Integral -- Generating block pointers'
427 call this % generate_pointer_table
439 subroutine load_integrals_alchemy (this, iounit)
440 use params,
only: ctrans1, cpoly
441 use global_utils,
only: intape
442 use scatci_routines,
only: search, chn2e
444 class(alchemyintegral) :: this
445 integer,
intent(in) :: iounit
447 character(len=4),
dimension(4) :: LABEL
448 character(len=4),
dimension(33) :: NAM1
449 integer,
dimension(8) :: NAO, NCORE
450 integer,
dimension(20) :: NHE, NOB
451 real(wp),
allocatable :: xtempe(:), xtempp(:)
453 integer :: I, NSYM, IONEIN, NT, ND, LTRI, NNUC, N, IA, IAT, NALM
454 integer :: ifail, k, l, ind, IMAX, IMIN, NEND, IMAXP
455 real(wp) :: EN, SIGN, x1e
456 real(wp) :: vsmall = 1.e-10_wp
457 real(kind=wp),
dimension(20) :: charg, xnuc
459 write (stdout, *)
' Loading ALCHEMY Integrals into core'
463 allocate(this % one_electron_integral(2 * this % num_one_electron_integrals), stat = ifail)
464 if (ifail /= 0) stop
"could not allocate 1 electron integral"
467 allocate(this % two_electron_integral(this % num_two_electron_integrals), stat = ifail)
468 if (ifail /= 0) stop
"could not allocate 2 electron integral"
470 read (iounit) (nam1(i), i = 1, 33), nsym, nt, nnuc, nd, ltri, (nob(i), i = 1, nsym), (nd, i = 1, nt), (nd, i = 1, nt), &
471 (charg(i), i = 1, nnuc), (xnuc(i), i = 1, nnuc)
473 write (stdout,
"(/' Transformed integrals read:',/5X,30A4)") (nam1(i), i = 1, 30)
477 if (abs(charg(n)) < vsmall) cycle
479 if (abs(charg(i)) < vsmall) cycle
480 en = en + charg(n) * charg(i) / abs(xnuc(n) - xnuc(i))
484 this % core_energy = en
486 write (stdout,
"(' NSYM =',I5,3X,'NOB =',20I5)") nsym, (nob(i), i = 1, nsym)
487 write (stdout,
"(/,10x,'Nuclear repulsion energy = ',f15.7)") en
488 write (stdout,
"(' NNUC =',I5,3X,'CHARG=',10F10.0/21X,10F10.0)") nnuc, (charg(i), i = 1, nnuc)
489 write (stdout,
"(15X,'XNUC =',10F10.5/21X,10F10.5)") (xnuc(i), i = 1, nnuc)
492 call rdints(iounit, nsym, nob, ltri, this % num_one_electron_integrals + 1, ia, this % one_electron_integral, nalm)
494 if (nalm /= 0) stop
"UNABLE TO READ ALCHEMY INTEGRALS"
497 call rdints(iounit, nsym, nob, ltri, this % num_one_electron_integrals + 1, ia, this % one_electron_integral, nalm)
499 if (nalm /= 0) stop
"UNABLE TO READ ALCHEMY INTEGRALS"
503 allocate(xtempp(this % num_one_electron_integrals))
504 call rdints(iounit, nsym, nob, ltri, this % num_one_electron_integrals + 1, ia, xtempp, nalm)
508 if (iat /= this % num_one_electron_integrals) stop
"INCORRECT NUMBER OF INTEGRALS"
510 if(abs(this % positron_flag) == 1) sign = -1.0
512 x1e = this % one_electron_integral(i) + xtempp(i)
513 this % one_electron_integral(i) = x1e
525 call rdint(imin, imax, nend, imaxp, iounit, ia, this % num_two_electron_integrals + 1, this % two_electron_integral)
526 if (nend /= 1) stop
"UNABLE TO READ ALCHEMY INTEGRALS"
532 1600
FORMAT(
' Integrals read successfully:', /, &
533 ' 1-electron integrals, NINT1e =',i10, /, &
534 ' 2-electron integrals, NINT2e =',i10)
535 write (stdout, 1600) this % num_one_electron_integrals, this % num_two_electron_integrals
537 this % nhe(:) = nhe(:)
541 this % nhe(:) = nob(:)
542 this % dtnuc(22:21+nnuc) = xnuc(1:nnuc)
543 this % dtnuc(2:1+nnuc) = charg(1:nnuc)
548 function get_integral_alchemy (this, i, j, k, l, m)
result(coeff)
549 class(alchemyintegral) :: this
550 integer,
intent(in) :: i,j,k,l,m
552 integer :: ia, ib, integral_idx
558 integral_idx = this % get_one_electron_index(j, l, m)
559 coeff = this % one_electron_integral(integral_idx)
562 integral_idx = this % get_two_electron_index(i, j, k, l, m)
563 coeff = this % two_electron_integral(integral_idx)
573 integer function get_one_electron_index (this, i, j, pos)
574 class(alchemyintegral),
intent(in) :: this
575 integer,
intent(in) :: i, j, pos
576 integer :: m, p, q, ii, jj
578 ii = this % orbital_mapping(i)
579 jj = this % orbital_mapping(j)
581 p = this % orbital_idx(ii)
582 q = this % orbital_idx(jj)
584 m = this % symmetry_idx(ii)
587 get_one_electron_index = this % pair_idx(q) + p + this % one_electron_pointer(m + 1) - 1
589 get_one_electron_index = this % pair_idx(p) + q + this % one_electron_pointer(m + 1) - 1
592 if (pos /= 0) get_one_electron_index = get_one_electron_index + this % num_one_electron_integrals
598 integer function get_two_electron_index (this, i, j, k, l, m)
599 class(alchemyintegral),
intent(in) :: this
600 integer,
intent(in) :: i, j, k, l, m
601 integer :: symmetry, mpp(4), nbp(4), npp(4), mapped(4), npq(4), ido, block_pointer, ipqrs, mv, md, mpq, mrs, mpr
603 mapped(1) = this % orbital_mapping(i)
604 mapped(2) = this % orbital_mapping(j)
605 mapped(3) = this % orbital_mapping(k)
606 mapped(4) = this % orbital_mapping(l)
609 npp(ido) = this % orbital_idx(mapped(ido))
610 symmetry = this % symmetry_idx(mapped(ido))
612 nbp(ido) = this % num_orbitals_sym(symmetry + 1)
618 mv = abs(mpp(1) - mpp(2))
629 mpr = this % pair_idx(mpq) + mrs + this % num_two_electron_blocks(mv + 1)
631 block_pointer = this % two_electron_pointer(mpr) - 1
634 if (mpp(ido) /= mpp(ido + 1))
then
635 npq(ido) = nbp(ido) * (npp(ido + 1) - 1) + npp(ido)
636 npq(ido + 1) = nbp(ido) * nbp(ido + 1)
638 if (npp(ido) < npp(ido + 1))
then
639 npq(ido) = this % pair_idx(npp(ido + 1)) + npp(ido)
641 npq(ido) = this % pair_idx(npp(ido)) + npp(ido + 1)
643 npq(ido + 1) = this % pair_idx(nbp(ido) + 1)
647 if (mpp(1) == mpp(3) .and. mpp(2) == mpp(4))
then
648 if (npq(1) < npq(3))
then
649 ipqrs = this % pair_idx(npq(3)) + npq(1)
651 ipqrs = this % pair_idx(npq(1)) + npq(3)
654 if (this % integral_ordering == 0)
then
655 ipqrs = npq(2) * (npq(3) - 1) + npq(1)
657 ipqrs = npq(4) * (npq(1) - 1) + npq(3)
661 get_two_electron_index = ipqrs + block_pointer
687 subroutine destroy_integral_alchemy (this)
688 class(alchemyintegral) :: this
690 if (
associated(this % one_electron_integral))
deallocate(this % one_electron_integral)
691 if (
associated(this % two_electron_integral))
deallocate(this % two_electron_integral)
693 if (
allocated(this % pair_labels))
deallocate(this % pair_labels)
696 if (
allocated(this % num_orbitals_sym))
deallocate(this % num_orbitals_sym)
698 if (
allocated(this % one_electron_pointer))
deallocate(this % one_electron_pointer)
699 if (
allocated(this % two_electron_pointer))
deallocate(this % two_electron_pointer)
701 if (
allocated(this % pair_idx))
deallocate(this % pair_idx)
702 if (
allocated(this % orbital_idx))
deallocate(this % orbital_idx)
703 if (
allocated(this % symmetry_idx))
deallocate(this % symmetry_idx)
705 if (
allocated(this % num_two_electron_blocks))
deallocate(this % num_two_electron_blocks)
706 if (
allocated(this % num_one_electron_blocks))
deallocate(this % num_one_electron_blocks)