58 type,
abstract :: basehamiltonian
59 class(orbitaltable),
pointer :: orbitals
60 class(options),
pointer :: options
61 class(baseintegral),
pointer :: integral
62 class(csfobject),
pointer :: csfs(:)
65 integer :: diagonal_flag
66 integer :: positron_flag
68 logical :: constructed = .false.
69 logical :: initialized = .false.
71 integer :: number_of_integrals = 0
72 real(wp) :: element_one = 0.0
73 real(wp) :: enh_factor
74 integer :: enh_factor_type
76 type(symbolicelementvector) :: reference_symbol
79 procedure,
public :: construct => construct_base_hamiltonian
80 procedure(generic_build),
deferred :: build_hamiltonian
83 procedure,
public :: slater_rules
85 procedure,
public :: evaluate_integrals
86 procedure,
public :: evaluate_integrals_singular
90 procedure,
private :: handle_two_pair
91 procedure,
private :: handle_one_pair
92 procedure,
private :: handle_same
93 procedure,
public :: my_job
94 end type basehamiltonian
124 subroutine construct_base_hamiltonian (this, option, csfs, orbitals, integral)
125 class(basehamiltonian),
intent(inout) :: this
126 class(options),
target,
intent(in) :: option
127 class(csfobject),
target,
intent(in) :: csfs(:)
128 class(orbitaltable),
target,
intent(in) :: orbitals
129 class(baseintegral),
target,
intent(in) :: integral
132 this % options => option
134 this % orbitals => orbitals
135 this % integral => integral
136 this % phase_flag = this % options % phase_correction_flag
137 this % positron_flag = this % options % positron_flag
138 this % enh_factor = this % options % enh_factor
139 this % enh_factor_type = this % options % enh_factor_type
142 this % diagonal_flag = min(this % options % matrix_eval, 2)
143 this % constructed = .true.
164 subroutine slater_rules (this, csf_a, csf_b, sym_elements, flag, job_)
165 class(basehamiltonian),
intent(in) :: this
166 class(csfobject),
intent(in) :: csf_a, csf_b
167 class(symbolicelementvector),
intent(inout) :: sym_elements
168 integer,
intent(in) :: flag
169 logical,
optional,
intent(in) :: job_
171 integer :: diag, num_differences, dtr_diff(4), dtr_diff_fast(4), dtr_idx_a, dtr_idx_b
175 if (
present(job_))
then
182 call sym_elements % clear()
187 if (.not. this % my_job())
return
191 if (csf_a % id /= csf_b % id)
then
193 if (csf_a % check_slater(csf_b) > 4)
return
198 do dtr_idx_a = 1, csf_a % num_orbitals
200 do dtr_idx_b = 1, csf_b % num_orbitals
203 call csf_a % orbital(dtr_idx_a) % compare_excitations_fast(csf_b % orbital(dtr_idx_b), &
204 this % options % num_electrons, &
210 select case (num_differences)
214 call this % handle_two_pair(dtr_diff, coeff, sym_elements, flag)
216 call this % handle_one_pair(dtr_diff, coeff, sym_elements, csf_a % orbital(dtr_idx_a), flag)
218 call this % handle_same(dtr_diff, coeff, sym_elements, csf_a % orbital(dtr_idx_a), flag)
237 subroutine handle_two_pair (this, dtrs, coeff, sym_element, flag)
238 class(basehamiltonian) :: this
239 class(symbolicelementvector) :: sym_element
240 integer,
intent(in) :: dtrs(4)
241 real(wp),
intent(in) :: coeff
242 integer,
intent(in) :: flag
244 if (this % diagonal_flag> 1 .and. this % orbitals % get_minimum_mcon(dtrs) > 0)
return
247 call this % orbitals % evaluate_IJKL_and_coeffs(dtrs, coeff, 0, sym_element, flag)
263 subroutine handle_one_pair (this, dtrs, coeff, sym_element, csf, flag)
264 class(basehamiltonian) :: this
265 class(symbolicelementvector) :: sym_element
266 class(csforbital),
intent(in) :: csf
267 integer,
intent(inout) :: dtrs(4)
268 real(wp),
intent(in) :: coeff
269 integer,
intent(in) :: flag
271 type(spinorbital) :: so1, so2
273 integer :: ref_dtrs(this % options % num_electrons)
274 integer :: num_electrons, N, M, ido, ia1, ia2, lnadd
281 num_electrons = this % options % num_electrons
293 call csf % get_determinants(ref_dtrs, num_electrons)
296 if (this % diagonal_flag > 1 .and. this % orbitals % get_two_minimum_mcon(dtrs(3), dtrs(4)) > 0)
then
303 do ido = 1, num_electrons
305 if (ref_dtrs(ido) == dtrs(3)) cycle
307 if (nchk == 1 .and. this % orbitals % get_mcon(ref_dtrs(ido)) > 0) cycle
309 dtrs(1) = ref_dtrs(ido)
310 dtrs(2) = ref_dtrs(ido)
312 call this % orbitals % evaluate_IJKL_and_coeffs(dtrs, coeff, 0, sym_element, flag)
316 if (this % positron_flag /= 0) lnadd = this % orbitals % add_positron(dtrs, 3, 4)
317 if (nchk == 1)
return
320 so1 = this % orbitals % spin_orbitals(dtrs(3))
321 so2 = this % orbitals % spin_orbitals(dtrs(4))
324 if (so1 % m_quanta /= so2 % m_quanta .or. so1 % spin /= so2 % spin)
return
325 if (so1 % orbital_number < so2 % orbital_number)
then
326 ia1 = so2 % orbital_number
327 ia2 = so1 % orbital_number
329 ia1 = so1 % orbital_number
330 ia2 = so2 % orbital_number
334 call sym_element % insert_ijklm_symbol(0, ia1, 0, ia2, lnadd, coeff)
350 subroutine handle_same (this, dtrs, coeff, sym_element, csf, flag)
351 class(basehamiltonian) :: this
352 class(symbolicelementvector) :: sym_element
353 class(csforbital),
intent(in) :: csf
354 integer,
intent(inout) :: dtrs(4)
356 real(wp),
intent(in) :: coeff
357 integer,
intent(in) :: flag
359 type(spinorbital) :: so1, so2
361 integer :: ref_dtrs(this % options % num_electrons)
362 integer :: num_electrons, N, M, ido, jdo, ia1, ia2, lnadd
369 num_electrons = this % options % num_electrons
381 call csf % get_determinants(ref_dtrs, num_electrons)
383 do ido = 2, num_electrons
384 dtrs(1) = ref_dtrs(ido)
387 dtrs(3) = ref_dtrs(jdo)
389 if (this % diagonal_flag > 1 .and. this % orbitals % get_two_minimum_mcon(dtrs(1), dtrs(3)) > 0) cycle
391 call this % orbitals % evaluate_IJKL_and_coeffs(dtrs, coeff, 0, sym_element, flag)
395 if (this % NFLG /= 0) this % NFLG = 2
396 do ido = 1, num_electrons
398 if (this % diagonal_flag > 1 .and. this % orbitals%get_mcon(n) /= 0) cycle
400 m = this % orbitals % get_orbital_number(n)
401 if (this % positron_flag /= 0)
then
404 lnadd = this % orbitals % add_positron(pdtrs, 1, 2)
406 call sym_element % insert_ijklm_symbol(0, m, 0, m, lnadd, coeff)
423 real(wp) function evaluate_integrals_singular (this, label, coeff, dummy_orb)
424 USE ukrmol_interface_gbl,
ONLY : get_orb_energy
426 class(basehamiltonian),
intent(inout) :: this
427 integer,
intent(in) :: dummy_orb
428 real(wp),
intent(in) :: coeff
429 integer(longint),
intent(in) :: label(
nidx)
431 integer :: ido, jdo, num_elements, lwd(8), i, orb_n, orb_num, &
432 belec_orb, velec_orb, posi_orb, enh_factor_type
434 real(wp):: integralf, orb_diff, oe, mp2_corr, x1
436 real(kind=wp),
dimension(4) :: occu_orbe, virt_orbe
440 evaluate_integrals_singular = 0.0
442 if (coeff == 0.0_wp)
return
445 if (this % phase_flag > 0)
then
446 call unpack_ints(label, lwd)
448 if (lwd(jdo) == this % phase_flag)
return
450 else if (this % phase_flag == 0)
then
451 call unpack_ints(label, lwd)
453 if (lwd(jdo) <= 0) cycle
454 if (this % orbitals % mcorb(lwd(jdo)) == 0)
return
458 integralf = this % integral % get_integralf(label)
459 call unpack_ints(label,lwd)
465 if (this % orbitals % mcorb(lwd(i)) .ne. lwd(i))
then
471 if (this%enh_factor_type .gt. 1)
then
478 virt_orbe(orb_n) = 0.0
479 occu_orbe(orb_n) = 0.0
481 orb_num = this % orbitals % mcorb(lwd(orb_n))
483 oe = get_orb_energy(orb_num)
484 if (oe .gt. 0.0)
then
485 virt_orbe(orb_n) = oe
486 if (this % orbitals % mcorb(lwd(orb_n)) .ne. lwd(orb_n))
then
487 velec_orb = velec_orb + 1
489 posi_orb = posi_orb + 1
492 occu_orbe(orb_n) = oe
493 if (this % orbitals % mcorb(lwd(orb_n)) .ne. lwd(orb_n))
then
494 belec_orb = belec_orb + 1
496 posi_orb = posi_orb + 1
501 if (belec_orb .eq. 1 .and. velec_orb .eq. 1)
then
504 orb_diff = sum(occu_orbe(1:4)) - sum(virt_orbe(1:4))
506 elseif (this % orbitals % mcorb(lwd(1)) .eq. this % orbitals % mcorb(lwd(2)) .and. &
507 this % orbitals % mcorb(lwd(3)) .eq. this % orbitals % mcorb(lwd(4)) .and. &
508 this % orbitals % mcorb(lwd(1)) .eq. this % orbitals % mcorb(lwd(3)) .and. &
509 velec_orb .ne. 0)
then
516 if (orb_diff .ne. 0.0)
then
517 if (integralf .ge. 0)
then
518 mp2_corr = ( (integralf*x1) / orb_diff) * this%enh_factor
520 mp2_corr = (-(integralf*x1) / orb_diff) * this%enh_factor
522 integralf = integralf + mp2_corr
527 integralf = integralf * this%enh_factor
532 evaluate_integrals_singular = coeff * integralf
535 this % number_of_integrals = this % number_of_integrals + 1
550 real(wp) function evaluate_integrals (this, symbolic_elements, dummy_orb)
551 class(basehamiltonian),
intent(inout) :: this
552 class(symbolicelementvector),
intent(in) :: symbolic_elements
553 integer,
intent(in) :: dummy_orb
555 integer :: ido, num_elements
556 integer(longint) :: label(nidx)
559 num_elements = symbolic_elements % get_size()
561 evaluate_integrals = 0.0_wp
562 if (num_elements == 0)
return
563 do ido = 1, num_elements
564 call symbolic_elements % get_coeff_and_integral(ido, coeff, label)
565 evaluate_integrals = evaluate_integrals + this % evaluate_integrals_singular(label, coeff, dummy_orb)
572 logical function my_job (this)
573 class(basehamiltonian) :: this
577 if (grid % gprocs == 1 .or. grid % grank == -1)
return
579 if (this % job_id /= grid % grank)
then
583 this % job_id = this % job_id + 1
584 if (this % job_id == grid % gprocs)
then
597 integer function fast_slat (rep1, rep2, fin1, fin2, num_rep1, num_rep2, spin_orbs, tot_num_spin_orbs)
598 integer,
intent(in) :: num_rep1, rep1(num_rep1), fin1(num_rep1)
599 integer,
intent(in) :: num_rep2, rep2(num_rep2), fin2(num_rep2), tot_num_spin_orbs
600 integer,
intent(inout) :: spin_orbs(tot_num_spin_orbs)
604 integer :: i_spin_orbital
606 integer :: orb_remove
608 do i_dtrs = 1, num_rep1
609 orb_remove = (rep1(i_dtrs) + 1) / 2
610 orb_add = (fin1(i_dtrs) + 1) / 2
611 spin_orbs(orb_remove) = spin_orbs(orb_remove) - 1
612 spin_orbs(orb_add) = spin_orbs(orb_add) + 1
615 do i_dtrs = 1, num_rep2
616 orb_remove = (rep2(i_dtrs) + 1) / 2
617 orb_add = (fin2(i_dtrs) + 1) / 2
618 spin_orbs(orb_remove) = spin_orbs(orb_remove) + 1
619 spin_orbs(orb_add) = spin_orbs(orb_add) - 1
624 do i_dtrs = 1, num_rep1
625 orb_remove = (rep1(i_dtrs) + 1) / 2
626 orb_add = (fin1(i_dtrs) + 1) / 2
627 fast_slat = fast_slat + spin_orbs(orb_remove)
628 spin_orbs(orb_remove) = 0
629 fast_slat = fast_slat + spin_orbs(orb_add)
630 spin_orbs(orb_add) = 0
633 do i_dtrs = 1, num_rep2
634 orb_remove = (rep2(i_dtrs) + 1) / 2
635 orb_add = (fin2(i_dtrs) + 1) / 2
636 fast_slat = fast_slat + spin_orbs(orb_remove)
637 spin_orbs(orb_remove) = 0
638 fast_slat = fast_slat + spin_orbs(orb_add)
639 spin_orbs(orb_add) = 0