MPI-SCATCI  2.0
An MPI version of SCATCI
Contracted_Hamiltonian_module.f90
Go to the documentation of this file.
1 ! Copyright 2019
2 !
3 ! For a comprehensive list of the developers that contributed to these codes
4 ! see the UK-AMOR website.
5 !
6 ! This file is part of UKRmol-in (UKRmol+ suite).
7 !
8 ! UKRmol-in is free software: you can redistribute it and/or modify
9 ! it under the terms of the GNU General Public License as published by
10 ! the Free Software Foundation, either version 3 of the License, or
11 ! (at your option) any later version.
12 !
13 ! UKRmol-in is distributed in the hope that it will be useful,
14 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ! GNU General Public License for more details.
17 !
18 ! You should have received a copy of the GNU General Public License
19 ! along with UKRmol-in (in source/COPYING). Alternatively, you can also visit
20 ! <https://www.gnu.org/licenses/>.
21 
34 
35  use const_gbl, only: stdout
37  use integer_packing, only: pack8ints, unpack8ints
38  use mpi_gbl, only: mpi_reduceall_max
39  use precisn, only: longint, wp
40  use basematrix_module, only: basematrix
44  use parallelization_module, only: grid => process_grid
47  use timing_module, only: master_timer
49 
50  implicit none
51 
53 
54  private
55 
66 
67  class(target_rmat_ci), pointer :: rmat_ci(:)
68  integer :: start_l2
69  integer :: total_num_csf
70  integer :: num_l2_functions
71  integer :: l2_mat_offset
72  integer :: csf_skip
73  integer :: non_zero_prototype = 0
74 
75  contains
76 
77  procedure, public :: initialize => initialize_contracted_hamiltonian
78  procedure, public :: build_hamiltonian => build_contracted_hamiltonian
79 
80  !----------class routines----------------------!
81  procedure, private :: evaluate_class_1
82  procedure, private :: evaluate_class_2
83  procedure, private :: evaluate_class_3
84  procedure, private :: evaluate_class_4
85  procedure, private :: evaluate_class_5
86  procedure, private :: evaluate_class_6
87  procedure, private :: evaluate_class_7
88  procedure, private :: evaluate_class_8
89  procedure, private :: evaluate_class_2_and_8
90  !--------class routines------------------------!
91  !procedure, private :: evaluate_class_7
92  !---Contraction routines
93  procedure, private :: fast_contract_class_1_3_diag
94  procedure, private :: fast_contract_class_1_3_offdiag
95  procedure, private :: fast_contract_class_567
96 
97  !---------Expansion routines-------------------!
98  procedure, private :: expand_diagonal
99  procedure, private :: expand_off_diagonal
100  procedure, private :: expand_continuum_l2
101  procedure, private :: expand_off_diagonal_general
102 
103  procedure, private :: expand_continuum_l2_eval
104  procedure, private :: expand_diagonal_eval
105  procedure, private :: contr_expand_diagonal_eval
106  procedure, private :: contr_expand_off_diagonal_eval
107  procedure, private :: contr_expand_continuum_l2_eval
108  procedure, private :: expand_off_diagonal_eval
109  procedure, private :: expand_off_diagonal_gen_eval
110 
111  !-------auxilary--routines-----------------!
112  procedure, private :: compute_matrix_ij
113  procedure, private :: get_target_coeff
114  procedure, private :: reduce_prototypes
115  procedure, private :: get_starting_index
116 
117  end type contracted_hamiltonian
118 
119 contains
120 
128  subroutine initialize_contracted_hamiltonian (this, rmat_ci)
129  class(contracted_hamiltonian) :: this
130  class(target_rmat_ci), target, intent(in) :: rmat_ci(:)
131 
132  !Assign the rmat pointer
133  this % rmat_ci => rmat_ci
134  !Our skip value is 2 for the moment
135  this % csf_skip = 2
136  !Where the L2 starts
137  this % start_L2 = this % options % last_continuum + 1
138  !total number of CSFS
139  this % total_num_csf = this % options % num_csfs
140  !Calculate where each L2 CSF belongs in the matrix
141  this % L2_mat_offset = this % options % contracted_mat_size - this % total_num_csf
142  this % num_L2_functions = this % options % num_L2_CSF
143 
144  end subroutine initialize_contracted_hamiltonian
145 
146 
154  subroutine build_contracted_hamiltonian (this, matrix_elements)
155  class(contracted_hamiltonian) :: this
156  class(basematrix), intent(inout) :: matrix_elements
157  integer :: num_target_sym, target_sym, num_targets_per_sym, i1, i2, n1, n2, l1, loop_skip, loop_ido, my_idx, ido
158  integer :: num_csfs, m, n, num_continuum, total_l1_cont_elems, matrix_block_size, estimated_mat_size
159 
160  !The block size is the size of the continuum and continuum+L2 section of the matrix
161  matrix_block_size = this % options % contracted_mat_size - this % total_num_csf + this % options % last_continuum
162 
163  write (stdout, "('continuum block_size =',i8)") matrix_block_size
164  !call master_memory%track_memory(2*kind(target_sym) + maxval(this%options%num_target_state_sym)**2,2*maxval(this%options%num_ci_target_sym),0,"CONTRACTED_ESTIMATED_VALS")
165  !We tell the matrix storage class the contracted size, the block size and the fact that it is sparse
166  call matrix_elements % initialize_matrix_structure(this % options % contracted_mat_size, mat_sparse, matrix_block_size)
167 
168  !Get the number of target symmetries
169  num_target_sym = this % options % num_target_sym
170 
171  !------------------------------------------------------------------------------------------------------------------!
172  !-----------------------------CONTINUUM CALCULATIONS---------------------------------------------------------------!
173  !------------------------------------------------------------------------------------------------------------------!
174 
175  this % orbitals % MFLG = 0
176 
177  !-----------------------------------------------CLASS 1---------------------------------------------------------
178  call master_timer % start_timer("Class 1")
179 
180  !Perform a class one ('diagonal same target symmetry') calculation on all target symmetries
181  do i1 = 1, num_target_sym
182  call this % evaluate_class_1(i1, this % options % num_target_state_sym(i1), matrix_elements)
183  end do
184  call master_timer % stop_timer("Class 1")
185  write (stdout, "('Class 1 complete')")
186  flush(stdout)
187  call master_timer % report_timers
188  !stop
189  !-----------------------------------------------CLASS 3---------------------------------------------------------
190 
191 
192  !-----------------------------------------------CLASSES 567---------------------------------------------------------
193  !These classes deal with differing target symmetries
194  !call master_timer%start_timer("Class 56")
195  !Loop through every combination of target symmetry
196  !do i1 = 1, num_target_sym-1
197  ! do i2=i1+1,num_target_sym
198  ! if(i1==i2) cycle !We've already done same target symmetries so ignore
199  !Check if we have the same continuum symmetry
200  ! if(this%options%lambda_continuum_orbitals_target(i1) == this%options%lambda_continuum_orbitals_target(i2)) then
201  ! if(this%options%gerade_sym_continuum_orbital_target(i1) == this%options%gerade_sym_continuum_orbital_target(i2)) then
202 
203  ! cycle
204  ! endif
205  ! endif
206  ! enddo
207  !enddo
208  !call master_timer%stop_timer("Class 56")
209 
210  call master_memory % print_memory_report
211 
212  !Before moving to the pure L2 calculations we need to clear out any other continuum calculations from the matrix format
213  !call matrix_elements%update_continuum(.true.)
214 
215  !--------------------------------------------------------------------------------------------------------------------------!
216  !----------------------------------------------PURE L2 Calculations--------------------------------------------------------!
217  !--------------------------------------------------------------------------------------------------------------------------!
218 
219  this % orbitals % MFLG = 1
220 
221  call master_timer % start_timer("Class 3")
222  !Perform a class three ('off-diagonal same target symmetry') calculation on all target symmetries
223  do i1 = 1, num_target_sym
224  call this % evaluate_class_3(i1, this % options % num_target_state_sym(i1), matrix_elements)
225  end do
226  call master_timer % stop_timer("Class 3")
227 
228  !call master_timer%report_timers
229 
230  write (stdout, "('Class 3 complete')")
231  flush(stdout)
232 
233  call master_timer % report_timers
234  call master_memory % print_memory_report
235 
236  !-----------------------------------------------CLASS 4---------------------------------------------------------
237  !Class four is a difficult one as we have to loop through the entire L2 functions which are quite large
238  loop_skip = max(1, grid % gprocs)
239  my_idx = max(grid % grank, 0)
240 
241  call master_timer % start_timer("Class 4")
242  do i1 = 1, num_target_sym
243  total_l1_cont_elems = this % options % num_target_state_sym(i1) * this % options % num_continuum_orbitals_target(i1)
244  do loop_ido = this % start_L2, this % total_num_csf, loop_skip
245  l1 = my_idx + loop_ido
246 
247  if (l1 > this % total_num_csf) then
248  !This is dummy to ensure synchornization with other procs
249  do ido = 1, total_l1_cont_elems
250  call matrix_elements % update_pure_L2(.false.)
251  end do
252  else
253  !Class four (continuum-L2 calculation)
254  call this % evaluate_class_4(i1, this % options % num_target_state_sym(i1), l1, matrix_elements)
255  end if
256  end do
257  end do
258 
259  call master_timer % stop_timer("Class 4")
260  write (stdout, "('Class 4 complete')")
261  flush(stdout)
262 
263  call master_timer % report_timers
264  !call matrix_elements%update_pure_L2(.true.)
265  !call master_memory%print_memory_report
266 
267  !-----------------------------------------------CLASSES 2+8---------------------------------------------------------
268  call master_timer % start_timer("Class 567")
269 
270  do i1 = 1, num_target_sym - 1
271  do i2 = i1 + 1, num_target_sym
272 
273  if (i1 == i2) cycle !We've already done same target symmetries so ignore
274  !write(stdout,"('class 567: ',2i8)") i1,i2
275  !Check if we have the same continuum symmetry
276  if (this % options % lambda_continuum_orbitals_target(i1) == &
277  this % options % lambda_continuum_orbitals_target(i2)) then
278  if (this % options % gerade_sym_continuum_orbital_target(i1) == &
279  this % options % gerade_sym_continuum_orbital_target(i2)) then
280  !If we do then do class five ('diagonal same continuum symmetry') calculation
281  ! write(stdout,"('class 5')")
282  call this % evaluate_class_5(i1, this % options % num_target_state_sym(i1), i2, &
283  this % options % num_target_state_sym(i2), matrix_elements)
284  !Then a class six ('off-diagonal same continuum symmetry') calculation
285  ! write(stdout,"('class 6')")
286  call this % evaluate_class_6 (i1, this % options % num_target_state_sym(i1), i2, &
287  this % options % num_target_state_sym(i2), matrix_elements)
288  !call master_timer%report_timers
289  !call master_memory%print_memory_report
290  cycle
291  end if
292  end if
293 
294  !write(stdout,"('class 7')")
295  !Otherwise do a class seven ('differing continuum symmetry') calculation
296  call this % evaluate_class_7(i1, this % options % num_target_state_sym(i1), i2, &
297  this % options % num_target_state_sym(i2), matrix_elements)
298  !call master_timer%report_timers
299  !call master_memory%print_memory_report
300 
301  end do
302  end do
303 
304  call master_timer % stop_timer("Class 567")
305  write (stdout, "('Class 567 complete')")
306  flush(stdout)
307 
308  call master_timer % report_timers
309  call master_memory % print_memory_report
310  call master_timer % start_timer("Class 2+8")
311  !Here I've combined both class two ('L2 diagonal') and class eight ('L2 offdiagonal') calculations
312  !call this%evaluate_class_2(matrix_elements)
313  call this % evaluate_class_2_and_8(matrix_elements)
314  !call this%evaluate_class_8(matrix_elements)
315  call master_timer % stop_timer("Class 2+8")
316 
317  write (stdout, "('Class 2+8 complete')")
318  flush(stdout)
319 
320  call master_timer % report_timers
321  call master_memory % print_memory_report
322 
323  !Clear up remaining L2 elements in a matrix formats stash
324  call matrix_elements % update_pure_L2(.true.)
325 
326  !The matrix may have some last step thats required
327  call matrix_elements % finalize_matrix
328 
329  !Print out interesting information
330  n = (this % options % num_csfs * (this % options % num_csfs + 1)) / 2
331  m = (this % options % contracted_mat_size * (this % options % contracted_mat_size + 1)) / 2
332 
333  write (stdout, 6000) m, matrix_elements % get_size()
334  6000 format(//,' TOTAL H Matrix ELEMENTS =',i15,/,' NON-ZERO ELEMENTS evaluated =',i15)
335  write (stdout, 6010) n, this % non_zero_prototype
336  6010 format(' Total prototype ELEMENTS =',i15,/,' Non-zero prototype ELEMENTS =',i15)
337  ! WRITE(stdout,6020)nint0, nint00
338  6020 format(/,' Number (prototype) integrals =',i15,/,' Compressed (prototype) integrals =',i15)
339  write (stdout, 6030) this % number_of_integrals
340  6030 format(' Number integrals evaluated =',i15)
341 
342  end subroutine build_contracted_hamiltonian
343 
344 
356  subroutine evaluate_class_1 (this, i1, num_targets, matrix_elements)
357  class(contracted_hamiltonian) :: this
358  class(basematrix), intent(inout) :: matrix_elements
359  integer, intent(in) :: i1
360  integer, intent(in) :: num_targets
361 
363  type(contractedsymbolicelementvector) :: master_prototype
365  type(symbolicelementvector) :: temp_prototype
367  integer, allocatable :: matrix_index(:,:)
368 
370  integer :: num_ci
371  !------------------------------target state variables
372  integer :: n1, n2
373  !----------------------------Looping variables------------------------------!
374  integer :: starting_index, ido, jdo, ii, jj, ij, err
375  !----------------------------MPI looping variables--------------------------
376  integer :: loop_idx, loop_ido, my_idx, loop_skip
378  integer :: num_configurations
380  integer :: config_idx_a, config_idx_b
381  !The target coefficient
382  real(wp), allocatable :: alpha_coeffs(:,:)
383  !The resultant matrix coefficient
384  real(wp), allocatable :: mat_coeffs(:,:)
385  !Number of continuum orbitals
386  integer :: continuum_orbital, num_continuum_orbitals
387 
388  allocate(matrix_index(2,num_targets*(num_targets+1)/2), stat = err)
389  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS1::MATRIX_INDEX')
390  allocate(alpha_coeffs(num_targets*(num_targets+1)/2,1), stat = err)
391  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS1::alpha_coeffs')
392  allocate(mat_coeffs(num_targets*(num_targets+1)/2,1), stat = err)
393  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS1::mat_coeffs')
394  !Get number of continuum orbitals
395  num_continuum_orbitals = this % options % num_continuum_orbitals_target(i1)
396 
397  !number of target state combinations (triangular form)
398  num_ci = num_targets * (num_targets + 1) / 2
399 
400  ii = 1
401  do n1 = 1, this % options % num_target_state_sym(i1)
402  do n2 = n1, this % options % num_target_state_sym(i1)
403  !Construct a master prototype for each target state combo
404  !And get the starting matrix index
405  call this % compute_matrix_ij(i1, n1, 1, i1, n2, 1, matrix_index(1,ii), matrix_index(2,ii))
406  ii = ii + 1
407  end do
408  end do
409 
410  call master_prototype % construct(num_ci, 1)
411 
412  !Construct the temporary prototype
413  call temp_prototype % construct
414 
415  !get the starting index of the configurations
416  starting_index = this % get_starting_index(i1)
417 
418  !Get the number of configurations
419  num_configurations = this % options % num_ci_target_sym(i1)
420 
421  !Set up our mpi variables
422  loop_skip = max(1, grid % lprocs)
423  my_idx = max(grid % lrank, 0)
424  call master_timer % start_timer("Class 1 prototype")
425  !This loop is commonly found in a lot of the classes. Basically it involves striding the loop across mpi processes
426  !For example if nprocs is 5, process 0 will do indicies 1,6,11..etc while process 1 will do 2,7,12.. and so on
427  do loop_ido = 1, num_configurations, loop_skip
428  this % orbitals % MFLG = 0
429  !Calculate our real index
430  ido = loop_ido + my_idx
431  !If we've gon past (which is possible in this setup then skip
432  if (ido > num_configurations) cycle
433  !Calculate our diagonal configuration index
434  config_idx_a = starting_index + (ido - 1) * this % csf_skip
435  !Slater it to get our temporary prototypes
436  call this % slater_rules(this % csfs(config_idx_a), this % csfs(config_idx_a), temp_prototype, 0, .false.)
437  alpha_coeffs = 0.0_wp
438  !Loop through each target state
439  ii = 1
440  do n1 = 1, this % options % num_target_state_sym(i1)
441  do n2 = n1, this % options % num_target_state_sym(i1)
442  ! Apply our coefficeints for each combination to the master, Left hand of Eq. 6
443  alpha_coeffs(ii,1) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i1, ido, n2)
444  ii = ii + 1
445  end do
446  end do
447  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
448  !call this%fast_contract_class_1_3_diag(i1,num_targets,ido,temp_prototype,master_prototype)
449 
450  !Clear the temporary prototype for usage again
451  call temp_prototype % clear
452 
453  !Now the off diagonal
454  do jdo = 1, ido - 1
455 
456  !Get the index
457  config_idx_b = starting_index + (jdo - 1) * this % csf_skip
458  !Slater
459  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 1, .false.)
460 
461  !No prototypes? then we leave
462  if (temp_prototype % is_empty()) cycle
463 
464  !Now contract the 'off diagonal' diagonal
465  ii = 1
466  do n1 = 1, this % options % num_target_state_sym(i1)
467  do n2 = n1, this % options % num_target_state_sym(i1)
468  ! (cimn*cim'n' + cim'n*cimn')H_imj,imj' Right hand of Eq. 6
469  alpha_coeffs(ii,1) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i1, jdo, n2) &
470  + this % get_target_coeff(i1, jdo, n1) * this % get_target_coeff(i1, ido, n2)
471  ! call master_prototype(ii)%add_symbols(temp_prototype,alpha)
472  ii = ii + 1
473  end do
474  end do
475  !print *,temp_prototype%get_size()
476  !print *,jdo
477  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
478  !call this%fast_contract_class_1_3_offdiag(i1,num_targets,ido,jdo,temp_prototype,master_prototype)
479  !Clear the prototype for the next round
480  call temp_prototype % clear
481  end do
482  end do
483  call master_timer % stop_timer("Class 1 prototype")
484  ij = 1
485 
486  call master_prototype % synchronize_symbols()
487 
488  !Without expansion, evaluate the first elements
489  !do ii=1,num_targets
490  ! do jj=ii,num_targets
491  ! mat_coeff = this%evaluate_integrals(master_prototype(ij),NORMAL_PHASE)
492  !Insert
493  !these are special as they may add the eigenvalues after
494  !We just let the master rank add them since they'll be combined later on
495  ! if(myrank == master .and. this%diagonal_flag == NO_PURE_TARGET_INTEGRAL_DIFF) mat_coeff = mat_coeff + this%rmat_ci(i1)%eigenvalues(ii)
496  ! call matrix_elements%insert_matrix_element(matrix_index(2,ij),matrix_index(1,ij),mat_coeff,1)
497  !Possibly perform update (who knows really?)
498  ! call matrix_elements%update_continuum(.false.)
499  ! ij=ij+1
500  ! enddo
501  !enddo
502 
503  !now we have our prototype we can start the expansion
504  config_idx_a = starting_index + (num_configurations - 1) * this % csf_skip
505  !Get which continuum orbital this belongs to
506  continuum_orbital = this % csfs(config_idx_a) % orbital_sequence_number
507 
508  !Set up our mpi variables
509  loop_skip = max(1, grid % gprocs)
510  my_idx = max(grid % grank, 0)
511 
512  call master_timer % start_timer("Class 1 Expansion")
513  !Now loop through our J
514  do loop_ido = 1, num_continuum_orbitals, loop_skip
515  ido = loop_ido + my_idx
516  call matrix_elements % update_pure_L2(.false., num_targets * (num_targets - 1))
517 
518  if (ido > num_continuum_orbitals) cycle
519  !Loop through each target combo
520  mat_coeffs = 0
521  !Immediately expand the correct prototype and then immediately evaluate the matrix element
522  call this % contr_expand_diagonal_eval(continuum_orbital, master_prototype, ido, mat_coeffs)
523  ij = 1
524  do ii = 1, num_targets
525  do jj = ii, num_targets
526  !Insert into our matrix format
527  if (this % diagonal_flag == no_pure_target_integral_diff .and. ii == jj) then
528  mat_coeffs(ij,1) = mat_coeffs(ij,1) + this % rmat_ci(i1) % eigenvalues(ii)
529  end if
530  call matrix_elements % insert_matrix_element(matrix_index(2,ij) + ido - 1, &
531  matrix_index(1,ij) + ido - 1, mat_coeffs(ij,1), 8)
532  !An update may occur
533  ij = ij + 1
534  end do
535  end do
536  end do
537 
538  call master_timer % stop_timer("Class 1 Expansion")
539  !Destroy our temporary prototype
540  call temp_prototype %destroy
541  !Destroy all of the masters
542  !do ii=1,num_ci
543  call master_prototype % destroy
544  !enddo
545  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
546  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
547  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
548  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
549 
550  this % non_zero_prototype = this % non_zero_prototype + 1
551 
552  !call master_timer%report_timers
553  end subroutine evaluate_class_1
554 
555 
565  subroutine evaluate_class_2 (this, matrix_elements)
566  class(contracted_hamiltonian) :: this
567  class(basematrix), intent(inout) :: matrix_elements
568  type(symbolicelementvector) :: symbolic_elements
569  real(wp) :: mat_coeff
570  integer :: l1, mat_offset, loop_ido, loop_skip, my_idx
571 
572  this % diagonal_flag = 0
573 
574  !Construct our symbolic elements
575  call symbolic_elements % construct
576 
577  loop_skip = max(1, grid % gprocs)
578  my_idx = max(1, grid % grank)
579 
580  !Loop through the L2 functions
581  do l1 = this % start_L2, this % total_num_csf
582  call matrix_elements % update_pure_L2(.false.)
583  !Slater them for the prototypes
584  call this % slater_rules(this % csfs(l1), this % csfs(l1), symbolic_elements, 0)
585  !Empty? then leave!
586  if (symbolic_elements % is_empty()) cycle
587  !Evaluate the integral
588  mat_coeff = this % evaluate_integrals(symbolic_elements, normal_phase)
589  !Insert using an offset
590  call matrix_elements % insert_matrix_element(l1 + this % L2_mat_offset, l1 + this % L2_mat_offset, mat_coeff, 2)
591  !Clear the symbols for the next step
592  call symbolic_elements % clear
593 
594  this % non_zero_prototype = this % non_zero_prototype + 1
595  end do
596 
597  !Destroy the symbols
598  call symbolic_elements % destroy
599 
600  end subroutine evaluate_class_2
601 
602 
614  subroutine evaluate_class_3 (this, i1, num_targets, matrix_elements)
615  class(contracted_hamiltonian) :: this
616  class(basematrix), intent(inout) :: matrix_elements
617  integer, intent(in) :: i1, num_targets
618 
620  type(contractedsymbolicelementvector) :: master_prototype
622  type(symbolicelementvector) :: temp_prototype
624  integer, allocatable :: matrix_index(:,:)
626  integer :: num_ci
627  !------------------------------target state variables
628  integer :: n1, n2
629  !----------------------------Looping variables------------------------------!
630  integer :: starting_index, ido, jdo, ii
631  !----------------------------MPI looping variables--------------------------
632  integer :: loop_idx, loop_ido, my_idx, loop_skip, err
634  integer :: num_configurations
636  integer :: config_idx_a, config_idx_b
637  !The target coefficient
638  real(wp), allocatable :: alpha_coeffs(:,:)
639  !The resultant matrix coefficient
640  real(wp), allocatable :: mat_coeffs(:,:)
641  !Number of continuum orbitals
642  integer :: continuum_orbital_a, continuum_orbital_b, num_continuum_orbitals, total_orbs
643 
644  allocate(matrix_index(2,num_targets*(num_targets+1)/2), stat = err)
645  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS3::MATRIX_INDEX')
646 
647  allocate(alpha_coeffs(num_targets*(num_targets+1)/2,1), stat = err)
648  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS3::alpha_coeffs')
649 
650  allocate(mat_coeffs(num_targets*(num_targets+1)/2,1), stat = err)
651  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS3::mat_coeffs')
652 
653  !Get number of continuum orbitals
654  num_continuum_orbitals = this % options % num_continuum_orbitals_target(i1)
655 
656  !number of target state combinations (triangular form
657  num_ci = num_targets * (num_targets + 1) / 2
658 
659  ii = 1
660  do n1 = 1, this % options % num_target_state_sym(i1)
661  do n2 = n1, this % options % num_target_state_sym(i1)
662  !Construct a master prototype for each target state combo
663  !And get the starting matrix index
664  call this % compute_matrix_ij(i1, n1, 2, i1, n2, 1, matrix_index(1,ii), matrix_index(2,ii))
665  ii = ii + 1
666  end do
667  end do
668 
669  call master_prototype % construct(num_targets * (num_targets + 1) / 2, 1)
670 
671  !Construct the temporary prototype
672  call temp_prototype % construct
673 
674  !get the starting index of the configurations
675  starting_index = this % get_starting_index(i1)
676 
677  !Get the number of configurations
678  num_configurations = this % options % num_ci_target_sym(i1)
679 
680  !Set up our mpi variables
681  loop_skip = max(1, grid % lprocs)
682  my_idx = max(grid % lrank, 0)
683  call master_timer % start_timer("Class 3 Prototype")
684 
685  !Do the diagonal
686  do loop_ido = 1, num_configurations, loop_skip
687  !Calculate our real index
688  ido = loop_ido + my_idx
689  !If we've gon past (which is possible in this setup then skip
690  if (ido > num_configurations) cycle
691  !Calculate our diagonal configuration index
692  config_idx_a = starting_index + (ido - 1) * this % csf_skip
693  !The second configuration is simply offset by one
694  config_idx_b = config_idx_a + 1
695  !Slater it to get our temporary prototypes
696  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 0, .false.)
697 
698  alpha_coeffs = 0.0_wp
699  !Similar contraction with class 1 Left hand of Eq. 6
700  ii = 1
701  do n1 = 1, this % options % num_target_state_sym(i1)
702  do n2 = n1, this % options % num_target_state_sym(i1)
703  alpha_coeffs(ii,1) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i1, ido, n2)
704  ii = ii + 1
705  end do
706  end do
707  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
708  !call this%fast_contract_class_1_3_diag(i1,num_targets,ido,temp_prototype,master_prototype)
709  !Clear temporary prototype
710  call temp_prototype % clear
711 
712  !Now loop through offdiagonal
713  do jdo = ido + 1, num_configurations
714  !Get the second CSF index offset by one
715  config_idx_b = config_idx_a + 1 + (jdo - ido) * this % csf_skip
716  !Slater
717  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 1, .false.)
718 
719  !No prototypes? then we leave
720  if (temp_prototype % is_empty()) cycle
721  alpha_coeffs = 0.0_wp
722  !Contract similary to class 1
723  ! (cimn*cim'n' + cim'n*cimn')H_imj,imj' Right hand of Eq. 6
724  ii = 1
725  do n1 = 1, this % options % num_target_state_sym(i1)
726  do n2 = n1, this % options % num_target_state_sym(i1)
727  alpha_coeffs(ii,1) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i1, jdo, n2) &
728  + this % get_target_coeff(i1, jdo, n1) * this % get_target_coeff(i1, ido, n2)
729  ii = ii + 1
730  end do
731  end do
732  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
733  !call this%fast_contract_class_1_3_offdiag(i1,num_targets,ido,jdo,temp_prototype,master_prototype)
734  call temp_prototype % clear
735  end do
736  end do
737  call master_timer % stop_timer("Class 3 Prototype")
738  !call master_timer % report_timers
739  call master_prototype % synchronize_symbols()
740 
741  !Again without expansion, evaluate the first elements
742  !ii=1
743  !do n1=1,num_targets
744  ! do n2=n1,num_targets
745  ! cimn*cimn'
746 
747  ! call master_prototype(ii)%synchronize_symbols()
748 
749  ! if(myrank == master) then
750  ! mat_coeffs(1) = this%evaluate_integrals(master_prototype(ii),NORMAL_PHASE)
751  !
752  ! call matrix_elements%insert_matrix_element(matrix_index(1,ii),matrix_index(2,ii),mat_coeffs(1),8)
753  ! write(2014,*) matrix_index(1,ii),matrix_index(2,ii),mat_coeffs(1)
754  ! endif
755  ! call matrix_elements%update_pure_L2(.false.)
756  !this time it is possible that if the target states are not the same then we 'flip' the index over and insert it
757  ! if (n1 /= n2) then
758  ! if(myrank == master) then
759  ! call matrix_elements%insert_matrix_element(matrix_index(1,ii)-1,matrix_index(2,ii)+1,mat_coeffs(1),8)
760  ! write(2014,*) matrix_index(1,ii)-1,matrix_index(2,ii)+1,mat_coeffs(1)
761  ! endif
762  ! call matrix_elements%update_pure_L2(.false.)
763  ! endif
764  !Calaculate the next index
765  ! matrix_index(1,ii) = matrix_index(1,ii) - 1
766 
767  ! ii=ii+1
768 
769  ! enddo
770  !enddo
771 
772  !Now get expansion variable variables
773  config_idx_a = starting_index + (num_configurations - 1) * this % csf_skip
774  config_idx_b = config_idx_a + 1
775 
776  continuum_orbital_a = this % csfs(config_idx_a) % orbital_sequence_number
777  continuum_orbital_b = this % csfs(config_idx_b) % orbital_sequence_number
778  call master_timer % start_timer("Class 3 Expansion")
779 
780  !Set up our mpi variables
781  loop_skip = max(1, grid % gprocs)
782  my_idx = max(grid % grank, 0)
783 
784  total_orbs = compute_total_box(num_continuum_orbitals, num_continuum_orbitals)
785 
786  do loop_ido = 1, total_orbs, loop_skip
787 
788  loop_idx = loop_ido + my_idx
789  call matrix_elements % update_pure_L2(.false., num_targets * (num_targets - 1))
790  !Skip if beyond total
791  if (loop_idx > total_orbs) cycle
792  !Convert the 1-D index into 2-D
793  call box_index_to_ij(loop_idx, num_continuum_orbitals, ido, jdo)
794 
795  if (ido > num_continuum_orbitals) cycle
796  if (jdo > num_continuum_orbitals) cycle
797  if (jdo < ido + 1) cycle
798  if (ido == jdo) cycle
799 
800  !Loop through each continuum orbital
801  !do ido=1,num_continuum_orbitals-1
802  !do jdo=max(3,ido+1),num_continuum_orbitals
803  ii = 1
804  !Loop through each target state
805  !Expand and Evaluate the matrix element
806 
807  call this % contr_expand_off_diagonal_eval(continuum_orbital_a, continuum_orbital_b, &
808  master_prototype, ido, jdo, mat_coeffs)
809 
810  do n1 = 1, num_targets
811  do n2 = n1, num_targets
812  !Insert into the matrix
813  call matrix_elements % insert_matrix_element(matrix_index(2,ii) + jdo - 1, &
814  matrix_index(1,ii) + ido - 2, mat_coeffs(ii,1), 8)
815  !print *,matrix_index(2,ii)+jdo-2,matrix_index(1,ii)+ido-1
816  !write(2014,*) matrix_index(1,ii)+jdo-2,matrix_index(2,ii)+ido-1,mat_coeffs(ii)
817  !call matrix_elements%update_continuum(.false.)
818  !this time it is possible that if the target states are not the same then we 'flip' the index over and insert it
819  if (n1 /= n2) then
820  call matrix_elements % insert_matrix_element (matrix_index(2,ii) + ido - 1, &
821  matrix_index(1,ii) + jdo - 2, mat_coeffs(ii,1), 8)
822  !write(2014,*) matrix_index(1,ii)+ido-2,matrix_index(2,ii)+jdo-1,mat_coeffs(ii)
823  !call matrix_elements%update_continuum(.false.)
824  end if
825  ii = ii + 1
826  end do
827  end do
828  !enddo
829  end do
830 
831  call master_timer % stop_timer("Class 3 Expansion")
832  !call master_timer%report_timers
833 
834  !Clean up master
835  call master_prototype % destroy
836 
837  !Clean up temporary
838  call temp_prototype % destroy
839 
840  this % non_zero_prototype = this % non_zero_prototype + 1
841 
842  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
843  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
844  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
845  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
846 
847  end subroutine evaluate_class_3
848 
849 
862  subroutine evaluate_class_4 (this, i1, num_states, l1, matrix_elements)
863 
864  class(contracted_hamiltonian) :: this
865  class(basematrix), intent(inout) :: matrix_elements
866  integer, intent(in) :: i1, num_states, l1
867 
868  integer :: config_idx_a ! CSF index
869  integer :: num_continuum_orbitals ! Number of continuum orbitals
870  integer :: num_configurations ! Number of configurations within the target symmetry
871  integer :: n1 ! Target state index
872  integer :: continuum_orbital ! Continuum orbital index
873 
874  integer :: ido, jdo, starting_index, i, j ! Loop variables
875  integer :: loop_skip, loop_idx, my_idx, err ! MPI loop variables
876  integer, allocatable :: matrix_index(:) ! The starting matrix index for each state
877 
878  type(contractedsymbolicelementvector) :: master_prototype ! The contracted prototypes for each target state
879  type(symbolicelementvector) :: temp_prototype ! Resultant slater rule calculation of symbols before contracting for each state
880  real(wp), allocatable :: alpha_coeffs(:,:), mat_coeffs(:) ! Target coefficient and matrix element coefficient
881 
882  allocate(matrix_index(num_states), stat = err)
883  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS4::MATRIX_INDEX')
884 
885  allocate(alpha_coeffs(num_states,1), stat = err)
886  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS4::alpha_coeffs')
887 
888  allocate(mat_coeffs(num_states), stat = err)
889  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS4::mat_coeffs')
890 
891  !Get number of continuum orbitals
892  num_continuum_orbitals = this % options % num_continuum_orbitals_target(i1)
893  !Get number of configuration state functions for this symmtery
894  num_configurations = this % options % num_ci_target_sym(i1)
895 
896  !get the starting index of the configurations
897  starting_index = this % get_starting_index(i1)
898 
899  do n1 = 1, num_states
900  !Construct and clear a symbol list for each state
901  !Compute starting index for each state
902  call this % compute_matrix_ij(i1, n1, 1, 1, 1, 1, matrix_index(n1), j)
903  end do
904 
905  call master_prototype % construct(num_states, 1)
906 
907  !Construct our temporary symbols
908  call temp_prototype % construct
909  !Clear them just in case
910  call temp_prototype % clear
911 
912  !Setup our loop variables
913  !loop_skip = max(1,nprocs)
914  !my_idx = max(myrank,0)
915 
916  !Again like class 1 and 3 we loop in a strided fashion across mpi nodes (or in a normal fashion without mpi)
917  do ido = 1, num_configurations
918  !Calculate our real index
919  !loop_idx = ido + my_idx
920  !If we've gone past it then leave
921  !if(loop_idx > num_configurations) cycle
922  !Caculate our CSf index
923  config_idx_a = starting_index + (ido - 1) * this % csf_skip
924 
925  !Slater it with the L2 functions
926  call this % slater_rules(this % csfs(l1), this % csfs(config_idx_a), temp_prototype, 1, .false.)
927  !Nothing? Skip
928  if (temp_prototype % is_empty()) cycle
929 
930  !Contract of the form cimn*Himj,l (Eq. 7)
931  do n1 = 1, num_states
932  alpha_coeffs(n1,1) = this % get_target_coeff(i1, ido, n1)
933  end do
934 
935  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
936  call temp_prototype % clear
937  end do
938 
939  call temp_prototype % clear
940 
941  !Get last CSF in symmetry
942  config_idx_a = starting_index + (num_configurations - 1) * this % csf_skip
943  !Get the associated continuum orbital
944  continuum_orbital = this % csfs(config_idx_a) % orbital_sequence_number
945 
946  !This is the L2 matrix position
947  j = l1 + this % L2_mat_offset
948 
949  !do n1=1, num_states
950 
951  ! call master_prototype(n1)%synchronize_symbols
952  !enddo
953 
954  !For each state, evaluate the integrals without expansion and store
955  !do n1=1,num_states
956  ! mat_coeffs(n1) = this%evaluate_integrals(master_prototype(n1),NORMAL_PHASE)
957  ! call matrix_elements%insert_matrix_element(j,matrix_index(n1),mat_coeffs(n1),4)
958  ! call matrix_elements%update_continuum(.false.)
959  !enddo
960 
961  !Start of continuum orbital expansion
962  do ido = 1, num_continuum_orbitals
963  !ido = loop_idx + my_idx
964  !call matrix_elements%update_pure_L2(.false.,num_states)
965  !if(ido > num_continuum_orbitals) cycle
966 
967  call this % contr_expand_continuum_L2_eval(continuum_orbital, master_prototype, ido, mat_coeffs)
968 
969  do n1 = 1, num_states
970  !Expand and evaluate
971  !Store coefficient into matrix object
972  call matrix_elements % insert_matrix_element(j, matrix_index(n1) + ido - 1, mat_coeffs(n1), 8, 0.0_wp)
973  !Perform update if needed
974  call matrix_elements % update_pure_L2(.false.)
975  end do
976  end do
977 
978  !Clean up prototype symbols
979  call master_prototype % destroy
980  call temp_prototype % destroy
981 
982  this % non_zero_prototype = this % non_zero_prototype + 1
983 
984  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
985  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
986  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
987 
988  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
989 
990  end subroutine evaluate_class_4
991 
992 
1007  subroutine evaluate_class_5 (this, i1, num_target_1, i2, num_target_2, matrix_elements)
1008  class(contracted_hamiltonian) :: this
1009  class(basematrix), intent(inout) :: matrix_elements
1010  integer, intent(in) :: i1, i2, num_target_1, num_target_2
1011 
1013  !type(SymbolicElementVector),target :: master_prototype(num_target_1,num_target_2)
1014  !type(SymbolicElementVector),pointer :: mst_pntr(:)
1015  type(contractedsymbolicelementvector) :: master_prototype
1017  integer, allocatable :: matrix_index(:,:,:)
1018  real(wp), allocatable :: alpha_coeffs(:,:)
1020  type(symbolicelementvector) :: temp_prototype
1022  integer :: config_idx_a,config_idx_b,n1,n2
1024  integer :: num_continuum_orbitals
1026  integer :: num_configurations_a,num_configurations_b,total_configurations
1027  !------------------------------MPI LOOP VARIABLES----------------------------------!
1028  integer :: loop_idx,my_idx,loop_skip,loop_ido
1029  !---------------------------------LOOP VARIABLES--------------------------------!
1030  integer :: ido,jdo,starting_index_a,starting_index_b,i,j,err
1032  integer :: continuum_orbital
1033  !
1034 
1036  real(wp) :: alpha
1037  real(wp), allocatable :: mat_coeffs(:,:)
1038 
1039  allocate(matrix_index(2, num_target_1, num_target_2), stat = err)
1040  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS5::MATRIX_INDEX')
1041 
1042  allocate(alpha_coeffs(num_target_1, num_target_2), stat = err)
1043  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS5::alpha_coeffs')
1044 
1045  allocate(mat_coeffs(num_target_1, num_target_2), stat = err)
1046  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS5::mat_coeffs')
1047 
1048  !Get number of continuum orbitals, which is a minimum of the two
1049  num_continuum_orbitals = min(this % options % num_continuum_orbitals_target(i1), &
1050  this % options % num_continuum_orbitals_target(i2))
1051 
1052  !get the starting index of the configuration of target symmetry 1
1053  starting_index_a = this % get_starting_index(i1)
1054 
1055  !get the starting index of the configurations of target symmetry 2
1056  starting_index_b = this % get_starting_index(i2)
1057 
1058  !total number of configurations of target symmetry 1
1059  num_configurations_a = this % options % num_ci_target_sym(i1)
1060 
1061  !total number of configurations of target symmetry 2
1062  num_configurations_b = this % options % num_ci_target_sym(i2)
1063 
1064  !Compute starting matrix index and construct contracted symbolic prototypes for each combination of target states
1065  do n1 = 1, num_target_1
1066  do n2 = 1, num_target_2
1067  call this % compute_matrix_ij(i1, n1, 1, i2, n2, 1, matrix_index(1,n1,n2), matrix_index(2,n1,n2))
1068  end do
1069  end do
1070  call master_prototype % construct(num_target_1, num_target_2)
1071 
1072  !Construct
1073  call temp_prototype % construct
1074  call temp_prototype % clear
1075 
1076  !mst_pntr(1:num_target_1*num_target_2) => master_prototype(:,:)
1077  !mat_ptr(1:num_target_1*num_target_2) => mat_coeffs(:,:)
1078  !Compute the total number of configurations to loop through (num_config_a*num_config_b)
1079  total_configurations = compute_total_box(num_configurations_a, num_configurations_b)
1080 
1081  !Set up our mpi variables
1082  loop_skip = max(1, grid % lprocs)
1083  my_idx = max(grid % lrank, 0)
1084 
1085  call master_timer % start_timer("Class 5 prototype")
1086  !This loop differs from classes 1,3 and 4. Instead the 2 dimensional loop is collapsed into one dimension
1087  !And the expected CSFs are computed from the single index. This was done to improve load balancing significantly
1088  !and ensure better OpenMP looping when it is added eventually. If this wasn;t done then the last MPI process will have the largest
1089  !chunk of configurations to deal compared to the others.
1090  !Again this loop is strided by MPI processes
1091  do loop_ido = 1, total_configurations, loop_skip
1092  alpha_coeffs = 0.0_wp
1093 
1094  !Calculate the real loop index
1095  loop_idx = loop_ido + my_idx
1096  !Skip if beyond total
1097  if (loop_idx > total_configurations) cycle
1098  !Convert the 1-D index into 2-D
1099  call box_index_to_ij(loop_idx, num_configurations_a, ido, jdo)
1100 
1101  alpha_coeffs = 0.0_wp
1102 
1103  !Use the two dimensional id to calculate the CSF index
1104  config_idx_a = starting_index_a + (ido - 1) * this % csf_skip
1105  config_idx_b = starting_index_b + (jdo - 1) * this % csf_skip
1106 
1107  !Slater for prototype symbols
1108  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 1, .false.)
1109 
1110  if (temp_prototype % is_empty()) cycle
1111  !Perform contraction on each combination of target state of the form cimn*ci'm'n'*Himj,i'm'j' seen in Eq. 8
1112  !do n1=1,num_target_1
1113  ! do n2=1,num_target_2
1114  ! alpha = this%get_target_coeff(i1,ido,n1)*this%get_target_coeff(i2,jdo,n2)
1115  ! call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1116  ! enddo
1117  !enddo
1118  !call this%fast_contract_class_567(i1,i2,num_target_1,num_target_2,ido,jdo,temp_prototype,master_prototype)
1119  do n1 = 1, num_target_1
1120  do n2 = 1, num_target_2
1121  alpha_coeffs(n1,n2) = this % get_target_coeff(i1,ido,n1) * this % get_target_coeff(i2,jdo,n2)
1122  !call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1123  end do
1124  end do
1125  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
1126 
1127  !clear the temporary symbols
1128  call temp_prototype % clear
1129  end do
1130 
1131  call master_timer % stop_timer("Class 5 prototype")
1132  call temp_prototype % destroy
1133 
1134  !call master_memory%print_memory_report()
1135  !write(stdout,"('Class 5 num symbols ',4i16)") master_prototype%get_size(),num_target_1,num_target_2,master_prototype%get_size()*num_target_1*num_target_2
1136  !Get the last CSf and find the associated orbital
1137  config_idx_a = starting_index_a + (num_configurations_a - 1) * this % csf_skip
1138  continuum_orbital = this % csfs(config_idx_a) % orbital_sequence_number
1139 
1140  !Evaluate integrals for the first element without expansion. store and possible update the matrix.
1141  !do n1=1,num_target_1
1142  ! do n2=1,num_target_2
1143  ! mat_coeffs(n1,n2) = this%evaluate_integrals(master_prototype(n1,n2),NORMAL_PHASE)
1144  ! call matrix_elements%insert_matrix_element(matrix_index(2,n1,n2),matrix_index(1,n1,n2),mat_coeff,5)
1145  ! call matrix_elements%update_continuum(.false.)
1146  ! enddo
1147  !enddo
1148 
1149  call master_timer % start_timer("Class 5 Synchonize")
1150  !write(stdout,"('Synch-Start ')")
1151  !call master_prototype(n1,n2)%print
1152  call master_prototype % synchronize_symbols
1153  !write(stdout,"('Synch-End ')")
1154  call master_timer % stop_timer("Class 5 Synchonize")
1155 
1156  !Set up our mpi variables
1157  loop_skip = max(1, grid % gprocs)
1158  my_idx = max(grid % grank, 0)
1159 
1160  !write(stdout,"('Expand ')")
1161  do loop_ido = 1, num_continuum_orbitals, loop_skip
1162  !Calculate the real loop index
1163  ido = loop_ido + my_idx
1164  call matrix_elements % update_pure_L2(.false., num_target_1 * num_target_2)
1165  !Skip if beyond total
1166  if (ido > num_continuum_orbitals) cycle
1167  mat_coeffs = 0
1168  call this % contr_expand_diagonal_eval(continuum_orbital, master_prototype, ido, mat_coeffs)
1169  !write(stdout,"('Orb ',i8)") ido
1170  do n1 = 1, num_target_1
1171  do n2 = 1, num_target_2
1172  !Expand and evaluate
1173  !Insert into the matrix
1174  call matrix_elements % insert_matrix_element(matrix_index(2,n1,n2) + ido - 1, &
1175  matrix_index(1,n1,n2) + ido - 1, mat_coeffs(n1,n2), 8)
1176  !Update matrix if needed.
1177  end do
1178  end do
1179  end do
1180 
1181  !---Cleanup----!
1182 
1183  call master_prototype % destroy
1184 
1185  this % non_zero_prototype = this % non_zero_prototype + 1
1186 
1187  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
1188  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
1189  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
1190 
1191  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
1192 
1193  end subroutine evaluate_class_5
1194 
1195 
1210  subroutine evaluate_class_6 (this, i1, num_target_1, i2, num_target_2, matrix_elements)
1211  class(contracted_hamiltonian) :: this
1212  integer, intent(in) :: i1, i2, num_target_1, num_target_2
1213  class(basematrix), intent(inout) :: matrix_elements
1214 
1216  !type(SymbolicElementVector),target :: master_prototype(num_target_1,num_target_2)
1217  !type(SymbolicElementVector),pointer :: mst_pntr(:)
1218  type(contractedsymbolicelementvector) :: master_prototype
1219 
1221  integer, allocatable :: matrix_index(:,:,:)
1222  real(wp), allocatable :: alpha_coeffs(:,:)
1223 
1225  type(symbolicelementvector) :: temp_prototype
1226 
1228  integer :: config_idx_a, config_idx_b, n1, n2
1229 
1231  integer :: num_continuum_orbitals_a, num_continuum_orbitals_b
1232 
1234  integer :: num_configurations_a, num_configurations_b, total_configurations
1235 
1236  !------------------------------MPI LOOP VARIABLES----------------------------------!
1237  integer :: loop_idx, my_idx, loop_skip, loop_ido
1238 
1239  !---------------------------------LOOP VARIABLES--------------------------------!
1240  integer :: ido, jdo, starting_index_a, starting_index_b, i, j, err
1241 
1243  integer :: continuum_orbital_a, continuum_orbital_b, total_orbs
1244 
1246  real(wp) :: alpha
1247  real(wp), allocatable :: mat_coeffs(:,:)
1248 
1249  allocate(matrix_index(2, num_target_1, num_target_2), stat = err)
1250  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS6::MATRIX_INDEX')
1251 
1252  allocate(alpha_coeffs(num_target_1, num_target_2), stat = err)
1253  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS6::alpha_coeffs')
1254 
1255  allocate(mat_coeffs(num_target_1, num_target_2), stat = err)
1256  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS6::mat_coeffs')
1257 
1258  !Get number of continuum orbitals for target symmetry 1
1259  num_continuum_orbitals_a = this % options % num_continuum_orbitals_target(i1)
1260 
1261  !Get number of continuum orbitals for target symmetry 2
1262  num_continuum_orbitals_b = this % options % num_continuum_orbitals_target(i2)
1263 
1264  !get the starting index of the configurations for target symmetry 1
1265  starting_index_a = this % get_starting_index(i1)
1266 
1267  !get the starting index of the configurations for target symmetry 2
1268  starting_index_b = this % get_starting_index(i2)
1269 
1270  !get the number of CSFS for target symmetry 1
1271  num_configurations_a = this % options % num_ci_target_sym(i1)
1272 
1273  !get the number of CSFS for target symmetry 2
1274  num_configurations_b = this % options % num_ci_target_sym(i2)
1275 
1276  !Compute starting matrix index and construct contracted symbolic prototypes for each combination of target states
1277  do n1 = 1, num_target_1
1278  do n2 = 1, num_target_2
1279  call this % compute_matrix_ij(i1, n1, 1, i2, n2, 1, matrix_index(1,n1,n2), matrix_index(2,n1,n2))
1280  end do
1281  end do
1282  call master_prototype % construct(num_target_1, num_target_2)
1283 
1284  !Construct
1285  call temp_prototype % construct
1286  call temp_prototype % clear
1287  !mst_pntr(1:num_target_1*num_target_2) => master_prototype(:,:)
1288  !mat_ptr(1:num_target_1*num_target_2) => mat_coeffs(:,:)
1289  !Compute the total number of configurations to loop through (num_config_a*num_config_b)
1290  total_configurations = compute_total_box(num_configurations_a, num_configurations_b)
1291 
1292  !Set up our mpi variables
1293  loop_skip = max(1, grid % lprocs)
1294  my_idx = max(grid % lrank, 0)
1295 
1296  call master_timer % start_timer("Class 6 prototype")
1297  !This loop differs from classes 1,3 and 4. Instead the 2 dimensional loop is collapsed into one dimension
1298  !And the expected CSFs are computed from the single index. This was done to improve load balancing significantly
1299  !and ensure better OpenMP looping when it is added eventually. If this wasn't done then the last MPI process will have the largest
1300  !chunk of configurations to deal compared to the others.
1301  !Again this loop is strided by MPI processes
1302  do loop_ido = 1, total_configurations, loop_skip
1303  alpha_coeffs = 0.0_wp
1304 
1305  !Calculate the real loop index
1306  loop_idx = loop_ido + my_idx
1307  !Skip if beyond total
1308  if (loop_idx > total_configurations) cycle
1309  !Convert the 1-D index into 2-D
1310  call box_index_to_ij(loop_idx, num_configurations_a, ido, jdo)
1311 
1312  !Use the two dimensional id to calculate the CSF index
1313  config_idx_a = starting_index_a + (ido - 1) * this % csf_skip
1314  config_idx_b = starting_index_b + 1 + (jdo - 1) * this % csf_skip
1315 
1316  !Slater for prototype symbols
1317  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 1, .false.)
1318 
1319  if (temp_prototype % is_empty()) cycle
1320  !Perform contraction on each combination of target state of the form cimn*ci'm'n'*Himj,i'm'j' seen in Eq. 8
1321  !do n1=1,num_target_1
1322  ! do n2=1,num_target_2
1323  ! alpha = this%get_target_coeff(i1,ido,n1)*this%get_target_coeff(i2,jdo,n2)
1324  ! call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1325  ! enddo
1326  !enddo
1327  !call this%fast_contract_class_567(i1,i2,num_target_1,num_target_2,ido,jdo,temp_prototype,master_prototype)
1328  do n1 = 1, num_target_1
1329  do n2 = 1, num_target_2
1330  alpha_coeffs(n1,n2) = this % get_target_coeff(i1,ido,n1) * this % get_target_coeff(i2,jdo,n2)
1331  !call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1332  end do
1333  end do
1334  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
1335 
1336  !clear the temporary symbols
1337  call temp_prototype % clear
1338  end do
1339 
1340  call master_timer % stop_timer("Class 6 prototype")
1341  call temp_prototype % clear
1342 
1343  !Get the continuum orbital numbers for both of the last CSFS
1344  continuum_orbital_a = this % csfs(config_idx_a) % orbital_sequence_number
1345  continuum_orbital_b = this % csfs(config_idx_b) % orbital_sequence_number
1346 
1347  call master_timer % start_timer("Class 6 Synchonize")
1348 
1349  !call master_prototype(n1,n2)%print
1350  call master_prototype % synchronize_symbols
1351  call master_timer % stop_timer("Class 6 Synchonize")
1352 
1353  total_orbs = compute_total_box(num_continuum_orbitals_a, num_continuum_orbitals_b)
1354 
1355  !Set up our mpi variables
1356  loop_skip = max(1, grid % gprocs)
1357  my_idx = max(grid % grank, 0)
1358 
1359  !Loop through each orbital in target symmetry 1
1360  do loop_ido = 1, total_orbs, loop_skip
1361  !Loop through each orbital in target symmetry 2
1362  !do jdo=1,num_continuum_orbitals_b
1363  loop_idx = loop_ido + my_idx
1364  call matrix_elements%update_pure_L2(.false.,num_target_1*num_target_2)
1365 
1366  !Skip if beyond total
1367  if(loop_idx > total_orbs) cycle
1368 
1369  !Convert the 1-D index into 2-D
1370  call box_index_to_ij(loop_idx,num_continuum_orbitals_a,ido,jdo)
1371  if (ido == jdo) cycle !Class 5 already handled the diagonal so ignore
1372 
1373  !Loop through each state in target symmetry 1
1374  !Expand and evaluate immediately
1375  call this % contr_expand_off_diagonal_eval (continuum_orbital_a, continuum_orbital_b, &
1376  master_prototype, ido, jdo, mat_coeffs)
1377  do n1 = 1, num_target_1
1378  !Loop through each state in target symmetry 2
1379  do n2 = 1, num_target_2
1380  !Insert into the matrix
1381  call matrix_elements % insert_matrix_element (matrix_index(2,n1,n2) + jdo - 1, &
1382  matrix_index(1,n1,n2) + ido - 1, &
1383  mat_coeffs(n1,n2), 8)
1384  !Update if neccessary
1385  end do
1386  end do
1387  end do
1388 
1389  !Cleanup
1390 
1391  call master_prototype % destroy
1392  call temp_prototype % destroy
1393 
1394  this % non_zero_prototype = this % non_zero_prototype + 1
1395 
1396  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
1397  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
1398  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
1399 
1400  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
1401 
1402  end subroutine evaluate_class_6
1403 
1404 
1418  subroutine evaluate_class_7 (this, i1, num_target_1, i2, num_target_2, matrix_elements)
1419  class(contracted_hamiltonian) :: this
1420  integer, intent(in) :: i1, i2, num_target_1, num_target_2
1421  class(basematrix), intent(inout) :: matrix_elements
1422 
1423  ! Contracted prototypes for each target state combination
1424  !type(SymbolicElementVector), target :: master_prototype(num_target_1, num_target_2)
1425  !type(SymbolicElementVector), pointer :: mst_pntr(:)
1426  type(contractedsymbolicelementvector) :: master_prototype
1427 
1428  ! Starting index for each
1429  integer, allocatable :: matrix_index(:,:,:)
1430  real(wp), allocatable :: alpha_coeffs(:,:)
1431 
1432  ! Temporary storage of Slater rule calculations
1433  type(symbolicelementvector) :: temp_prototype
1434 
1435  ! Configuration and target state variables
1436  integer :: config_idx_a, config_idx_b, n1, n2
1437 
1438  ! Number of continuum orbitals
1439  integer :: num_continuum_orbitals_a, num_continuum_orbitals_b
1440 
1441  ! Counts for number of configurations of target symmetry 1,2 and in total TS1*TS2
1442  integer :: num_configurations_a, num_configurations_b, total_configurations
1443 
1444  !------------------------------MPI LOOP VARIABLES----------------------------------!
1445  integer :: loop_idx, my_idx, loop_skip, loop_ido
1446 
1447  !---------------------------------LOOP VARIABLES--------------------------------!
1448  integer :: ido, jdo, starting_index_a, starting_index_b, i, j, err
1449 
1450  ! Current continuum orbital for target symmetry 1 and 2
1451  integer :: continuum_orbital_a, continuum_orbital_b, total_orbs
1452 
1453  ! Target coefficient and matrix coefficient
1454  real(wp) :: alpha
1455  real(wp), allocatable :: mat_coeffs(:,:)
1456 
1457  allocate(matrix_index(2,num_target_1,num_target_2), stat = err)
1458  call master_memory % track_memory(kind(matrix_index), size(matrix_index), err, 'CLASS7::MATRIX_INDEX')
1459 
1460  allocate(alpha_coeffs(num_target_1,num_target_2), stat = err)
1461  call master_memory % track_memory(kind(alpha_coeffs), size(alpha_coeffs), err, 'CLASS7::alpha_coeffs')
1462 
1463  allocate(mat_coeffs(num_target_1,num_target_2), stat = err)
1464  call master_memory % track_memory(kind(mat_coeffs), size(mat_coeffs), err, 'CLASS7::mat_coeffs')
1465 
1466  config_idx_a = 0
1467  config_idx_b = 0
1468 
1469  !Get number of continuum orbitals for target symmetry 1
1470  num_continuum_orbitals_a = this % options % num_continuum_orbitals_target(i1)
1471  !Get number of continuum orbitals for target symmetry 2
1472  num_continuum_orbitals_b = this % options % num_continuum_orbitals_target(i2)
1473 
1474  !get the starting index of the configurations for target symmetry 1
1475  starting_index_a = this % get_starting_index(i1)
1476  !get the starting index of the configurations for target symmetry 2
1477  starting_index_b = this % get_starting_index(i2)
1478 
1479  !get the number of CSFS for target symmetry 1
1480  num_configurations_a = this % options % num_ci_target_sym(i1)
1481  !get the number of CSFS for target symmetry 2
1482  num_configurations_b = this % options % num_ci_target_sym(i2)
1483 
1484  !Compute starting matrix index and construct contracted symbolic prototypes for each combination of target states
1485  do n1 = 1, num_target_1
1486  do n2= 1, num_target_2
1487  call this % compute_matrix_ij(i1, n1, 1, i2, n2, 1, matrix_index(1,n1,n2), matrix_index(2,n1,n2))
1488  end do
1489  end do
1490 
1491  call master_prototype % construct(num_target_1, num_target_2)
1492 
1493  !Construct
1494  call temp_prototype % construct
1495  call temp_prototype % clear
1496  !mst_pntr(1:num_target_1*num_target_2) => master_prototype(:,:)
1497  !mat_ptr(1:num_target_1*num_target_2) => mat_coeffs(:,:)
1498  !Compute the total number of configurations to loop through (num_config_a*num_config_b)
1499  total_configurations = compute_total_box(num_configurations_a, num_configurations_b)
1500 
1501  !Set up our mpi variables
1502  loop_skip = max(1, grid % lprocs)
1503  my_idx = max(grid % lrank, 0)
1504 
1505  call master_timer % start_timer("Class 7 prototype")
1506  !This loop differs from classes 1,3 and 4. Instead the 2 dimensional loop is collapsed into one dimension
1507  !And the expected CSFs are computed from the single index. This was done to improve load balancing significantly
1508  !and ensure better OpenMP looping when it is added eventually. If this wasn't done then the last MPI process will have the largest
1509  !chunk of configurations to deal compared to the others.
1510  !Again this loop is strided by MPI processes
1511  do loop_ido = 1, total_configurations, loop_skip
1512  alpha_coeffs = 0.0_wp
1513 
1514  !Calculate the real loop index
1515  loop_idx = loop_ido + my_idx
1516  !Skip if beyond total
1517  if (loop_idx > total_configurations) cycle
1518  !Convert the 1-D index into 2-D
1519  call box_index_to_ij(loop_idx, num_configurations_a, ido, jdo)
1520 
1521  !Use the two dimensional id to calculate the CSF index
1522  config_idx_a = starting_index_a + (ido - 1) * this % csf_skip
1523  config_idx_b = starting_index_b + (jdo - 1) * this % csf_skip
1524 
1525  !Slater for prototype symbols
1526  call this % slater_rules(this % csfs(config_idx_b), this % csfs(config_idx_a), temp_prototype, 1, .false.)
1527 
1528  !Cycle if empty
1529  if (temp_prototype % is_empty()) cycle
1530  !Perform contraction on each combination of target state of the form cimn*ci'm'n'*Himj,i'm'j' seen in Eq. 8
1531  !do n1=1,num_target_1
1532  ! do n2=1,num_target_2
1533  ! alpha = this%get_target_coeff(i1,ido,n1)*this%get_target_coeff(i2,jdo,n2)
1534 
1535  ! call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1536  ! enddo
1537  !enddo
1538  !call this%fast_contract_class_567(i1,i2,num_target_1,num_target_2,ido,jdo,temp_prototype,master_prototype)
1539  do n1 = 1, num_target_1
1540  do n2 = 1, num_target_2
1541  alpha_coeffs(n1,n2) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i2, jdo, n2)
1542  !call master_prototype(n1,n2)%add_symbols(temp_prototype,alpha)
1543  end do
1544  end do
1545  call master_prototype % add_symbols(temp_prototype, alpha_coeffs)
1546 
1547  !clear the temporary symbols
1548  call temp_prototype % clear
1549  end do
1550 
1551  call master_timer % stop_timer("Class 7 prototype")
1552  call temp_prototype % clear
1553 
1554  ! When there are more ranks in the shared memory communicator than pairs of target CSFs,
1555  ! some ranks exit the previous DO cycle without setting config_idx_a and config_idx_b. These are needed
1556  ! just to get number of
1557  n1 = config_idx_a; call mpi_reduceall_max(n1, config_idx_a, grid % lcomm)
1558  n2 = config_idx_b; call mpi_reduceall_max(n2, config_idx_b, grid % lcomm)
1559 
1560  !Get the continuum orbital numbers for both of the last CSFS
1561  continuum_orbital_a = this % csfs(config_idx_a) % orbital_sequence_number
1562  continuum_orbital_b = this % csfs(config_idx_b) % orbital_sequence_number
1563 
1564  call master_timer % start_timer("Class 7 Synchonize")
1565  call master_prototype % synchronize_symbols
1566  call master_timer % stop_timer("Class 7 Synchonize")
1567 
1568  total_orbs = compute_total_box(num_continuum_orbitals_a, num_continuum_orbitals_b)
1569 
1570  !Set up our mpi variables
1571  loop_skip = max(1, grid % gprocs)
1572  my_idx = max(grid % grank, 0)
1573 
1574  call master_timer % start_timer("Class 7 expansion")
1575 
1576  !Loop through each orbital in target symmetry 1
1577  do loop_ido = 1, total_orbs, loop_skip
1578  !Loop through each orbital in target symmetry 2
1579  !do jdo=1,num_continuum_orbitals_b
1580  loop_idx = loop_ido + my_idx
1581  call matrix_elements % update_pure_L2(.false., num_target_1 * num_target_2)
1582  !Skip if beyond total
1583  if (loop_idx > total_orbs) cycle
1584  !Convert the 1-D index into 2-D
1585  call box_index_to_ij(loop_idx, num_continuum_orbitals_a, ido, jdo)
1586  !Loop through each state in target symmetry 1
1587  !Expand and evaluate immediately
1588  call this % expand_off_diagonal_gen_eval(continuum_orbital_a, continuum_orbital_b, master_prototype, &
1589  ido, jdo, mat_coeffs)
1590 
1591  do n1 = 1, num_target_1
1592  !Loop through each state in target symmetry 2
1593  do n2 = 1, num_target_2
1594  !Insert into the matrix
1595  call matrix_elements % insert_matrix_element(matrix_index(2,n1,n2) + jdo - 1, &
1596  matrix_index(1,n1,n2) + ido - 1, &
1597  mat_coeffs(n1,n2), 8)
1598  !Update if neccessary
1599  end do
1600  end do
1601  end do
1602 
1603  call master_timer % stop_timer("Class 7 expansion")
1604 
1605  !-------------Cleanup---------------!
1606  call temp_prototype % destroy
1607  call master_prototype % destroy
1608 
1609  this % non_zero_prototype = this % non_zero_prototype + 1
1610 
1611  call master_memory % free_memory(kind(matrix_index), size(matrix_index))
1612  call master_memory % free_memory(kind(alpha_coeffs), size(alpha_coeffs))
1613  call master_memory % free_memory(kind(mat_coeffs), size(mat_coeffs))
1614 
1615  deallocate(matrix_index, alpha_coeffs, mat_coeffs)
1616 
1617  end subroutine evaluate_class_7
1618 
1619 
1629  subroutine evaluate_class_8 (this, matrix_elements)
1630  class(contracted_hamiltonian) :: this
1631  class(basematrix), intent(inout) :: matrix_elements
1632 
1633  type(symbolicelementvector) :: symbolic_elements ! The smbolic elements
1634  integer :: l1, l2 ! L2 CSf indicies
1635  real(wp) :: mat_coeff ! The calculated matrix coefficient
1636  integer :: loop_ido, my_idx, loop_skip
1637 
1638  !Construct the symbolic element object
1639  call symbolic_elements % construct
1640 
1641  my_idx = max(1, grid % grank)
1642  loop_skip = max(1, grid % gprocs)
1643 
1644  !Loop through each L2 function
1645  do loop_ido = this % start_L2, this % total_num_csf - 1, loop_skip
1646  l1 = loop_ido + my_idx
1647  call matrix_elements % update_pure_L2(.false.)
1648 
1649  !Loop through the lower triangular of L2
1650  do l2 = this % start_L2, l1 - 1
1651 
1652  !Check for an update here to ensure synchonization with all processes
1653  if (l1 > this % total_num_csf - 1) exit
1654 
1655  !Slater the L2 functions
1656  call this % slater_rules(this % csfs(l1), this % csfs(l2), symbolic_elements, 1, .false.)
1657  !If empty then cycle
1658  if (symbolic_elements % is_empty()) cycle
1659  !Evaluate the integral
1660  mat_coeff = this % evaluate_integrals(symbolic_elements, normal_phase)
1661  !Insert the coffieicnt into the correct matrix position
1662  call matrix_elements % insert_matrix_element(l2 + this % L2_mat_offset, l1 + this % L2_mat_offset, mat_coeff, 8)
1663  !Clear for the next step
1664  call symbolic_elements % clear
1665 
1666  this % non_zero_prototype = this % non_zero_prototype + 1
1667  end do
1668  end do
1669 
1670  !Cleanup the symbols
1671  call symbolic_elements % destroy
1672 
1673  end subroutine evaluate_class_8
1674 
1675 
1687  subroutine evaluate_class_2_and_8 (this, matrix_elements)
1688  class(contracted_hamiltonian) :: this
1689  class(basematrix), intent(inout) :: matrix_elements
1690 
1691  integer :: l1, l2 ! L2 indicies to be calculated
1692  type(symbolicelementvector) :: symbolic_elements ! The symbolic elements evaluated from Slaters rules
1693  real(wp) :: mat_coeff ! The calculated matrix coefficients
1694  integer :: loop_idx, ido ! Looping indicies
1695  integer :: total_vals ! Total number of CSFS to loop through
1696  integer :: loop_skip, my_idx ! MPI variables
1697  integer :: trig_n ! The total number of L2 CSFS
1698  integer :: diag ! Wheter we are diagonal or not
1699 
1700  call symbolic_elements % construct ! Construct our symbol object
1701  trig_n = this % num_L2_functions ! Calculate the number of L2 functions
1702  total_vals = compute_total_box(trig_n, trig_n) ! Compute the total number of CSFS to loop through
1703 
1704  this % diagonal_flag = 0
1705 
1706  !Our MPI looping variasbles
1707  loop_skip = max(1, grid % gprocs)
1708  my_idx= max(grid % grank, 0)
1709 
1710  write (stdout, "('start,total: ',2i12)") this % start_L2, total_vals
1711 
1712  ! Whilst similar in concept to classes 5,6,7. Instead of collapsing an N^2 to one dimension it collapses an
1713  ! N(N+1)/2 loop into one dimension. The index calculation is a little mroe complex but offers the same performance
1714  ! benefits as classes 5,6 and 7
1715  do ido = 1, total_vals, loop_skip
1716 
1717  !Update if needed
1718  call matrix_elements % update_pure_L2(.false.)
1719  call symbolic_elements % clear
1720 
1721  !Calculate the real index
1722  loop_idx = ido + my_idx
1723  !If we've gone over then cycle
1724  if (loop_idx > total_vals) cycle
1725  !Convert the one dimensional index to two dimensions
1726  call box_index_to_ij(loop_idx, trig_n, l1, l2)
1727  !write (stdout, "('idx = ',i12,' l1 = ',i12,' l2 ',i12)") loop_idx, l1, l2
1728  !Get the correct L2 offsets
1729  l1 = l1 + this % start_L2 - 1
1730  l2 = l2 + this % start_L2 - 1
1731  !write (stdout, "('idx = ',i12,' d l1 = ',i12,'d l2 ',i12,'mat ',2i8)") loop_idx, l1, l2, l2 + this % L2_mat_offset, l1 + this % L2_mat_offset
1732 
1733  if ((l2 + this % L2_mat_offset) < (l1 + this % L2_mat_offset)) cycle
1734 
1735  !As a precaution, if we've gone past either, skip
1736  if (l1 > this % total_num_csf .or. l2 > this % total_num_csf) cycle
1737  if (l1 < this % start_L2 .or. l2 < this % start_L2 ) cycle
1738  !write(stdout,"('l1,2 = ',2i8)") l1,l2
1739  !stop "Error in L2 indexing"
1740  !endif
1741 
1742  diag = 1
1743  if (l1 == l2) diag = 0
1744 
1745  !Slater the CSFS
1746  call this % slater_rules(this % csfs(l1), this % csfs(l2), symbolic_elements, diag, .false.)
1747  !If empty, skip
1748  if (symbolic_elements % is_empty()) cycle
1749  !Evaluate normally
1750  mat_coeff = this % evaluate_integrals(symbolic_elements, normal_phase)
1751 
1752  !if(l2/=l1 .and. abs(mat_coeff) >= DEFAULT_MATELEM_THRESHOLD) write(1235,"(3i8,es16.5)") diag,l2+this%L2_mat_offset,l1+this%L2_mat_offset,mat_coeff
1753  !if(l1==l2) call this%rmat_ci(1)%modify_L2_diagonal(mat_coeff)
1754 
1755  !Insert the matrix element into the correct place
1756  call matrix_elements % insert_matrix_element(l2 + this % L2_mat_offset, l1 + this % L2_mat_offset, mat_coeff, 8)
1757 
1758  !Clear for the next cycle
1759  this % non_zero_prototype = this % non_zero_prototype + 1
1760 
1761  end do
1762 
1763  !Cleanup
1764  call symbolic_elements % destroy
1765 
1766  end subroutine evaluate_class_2_and_8
1767 
1768 
1783  subroutine compute_matrix_ij (this, i1, n1, j1, i2, n2, j2, i, j)
1784  class(contracted_hamiltonian) :: this
1785  integer, intent(in) :: i1, n1, j1, i2, n2, j2
1786  integer, intent(out) :: i, j
1787  integer :: ido
1788 
1789  i = 0
1790 
1791  do ido = 2, i1
1792  i = i + this % options % num_target_state_sym(ido - 1) &
1793  * this % options % num_continuum_orbitals_target(ido - 1)
1794  end do
1795 
1796  do ido = 2, n1
1797  i = i + this % options % num_continuum_orbitals_target(i1)
1798  end do
1799 
1800  i = i + j1
1801  j = 0
1802 
1803  do ido = 2, i2
1804  j = j + this % options % num_target_state_sym(ido - 1) &
1805  * this % options % num_continuum_orbitals_target(ido - 1)
1806  enddo
1807 
1808  do ido = 2, n2
1809  j = j + this % options % num_continuum_orbitals_target(i2)
1810  end do
1811 
1812  j = j + j2
1813 
1814  end subroutine compute_matrix_ij
1815 
1816 !----------------------------------EXPANSION-----------------------------------------------------!
1817 
1819  subroutine expand_diagonal (this, continuum_orbital, master_prototype, j1, expanded_prototype)
1820  class(contracted_hamiltonian) :: this
1821  class(symbolicelementvector), intent(in) :: master_prototype, expanded_prototype
1822  integer, intent(in) :: continuum_orbital, j1
1823 
1824  integer(longint) :: integral(2)
1825  real(wp) :: integral_coeff
1826  integer :: lwd(8), lw1, lw2, ido, i, num_integrals
1827 
1828  num_integrals = master_prototype % get_size()
1829 
1830  do ido = 1, num_integrals
1831 
1832  !Get the integral
1833  call master_prototype % get_coeff_and_integral(ido, integral_coeff, integral)
1834  call unpack8ints(integral, lwd)
1835 
1836  lw1 = 0
1837  lw2 = 0
1838 
1839  do i = 1, 4
1840  if (lwd(i) == continuum_orbital) then
1841  if(lw1 == 0) then
1842  lw1 = i
1843  else
1844  lw2 = i
1845  end if
1846  end if
1847  end do
1848 
1849  if (lw1 == 0) then
1850  call expanded_prototype % insert_symbol(integral, integral_coeff, .false.)
1851  cycle
1852  else if (lw2 == 0) then
1853  lwd(lw1) = continuum_orbital + j1 - 1
1854  else
1855  lwd(lw1) = continuum_orbital + j1 - 1
1856  lwd(lw2) = continuum_orbital + j1 - 1
1857  end if
1858 
1859  call expanded_prototype % insert_ijklm_symbol(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), integral_coeff, .false.)
1860 
1861  end do
1862 
1863  end subroutine expand_diagonal
1864 
1866  subroutine expand_off_diagonal (this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, expanded_prototype)
1867  class(contracted_hamiltonian) :: this
1868  class(symbolicelementvector), intent(in) :: master_prototype, expanded_prototype
1869  integer, intent(in) :: continuum_orbital_a, continuum_orbital_b, ja, jb
1870 
1871  integer(longint) :: integral(2)
1872  real(wp) :: integral_coeff
1873  integer :: lwd(8), lwa, lwb, ido, i, num_integrals
1874 
1875  num_integrals = master_prototype % get_size()
1876 
1877  do ido = 1, num_integrals
1878 
1879  !Get the integral
1880  call master_prototype % get_coeff_and_integral(ido, integral_coeff, integral)
1881  call unpack8ints(integral, lwd)
1882 
1883  lwa = 0
1884  lwb = 0
1885 
1886  do i = 1, 4
1887  if (lwd(i) == continuum_orbital_a) lwa = i
1888  if (lwd(i) == continuum_orbital_b) lwb = i
1889  end do
1890 
1891  !No occurances
1892  if (max(lwa, lwb) == 0) then
1893  call expanded_prototype % insert_symbol(integral, integral_coeff, .false.)
1894  cycle
1895  else if (lwb == 0) then
1896  lwd(lwa) = continuum_orbital_a + ja - 1
1897  else if (lwa == 0) then
1898  lwd(lwb) = continuum_orbital_b + jb - 2
1899  else
1900  lwd(lwa) = continuum_orbital_a + ja - 1
1901  lwd(lwb) = continuum_orbital_b + jb - 2
1902  endif
1903 
1904  !One occurance
1905 
1906  call expanded_prototype % insert_ijklm_symbol(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), integral_coeff, .false.)
1907 
1908  end do
1909 
1910  end subroutine expand_off_diagonal
1911 
1912 
1914  subroutine expand_continuum_l2 (this, continuum_orbital, master_prototype, j1, expanded_prototype)
1915  class(contracted_hamiltonian) :: this
1916  class(symbolicelementvector), intent(in) :: master_prototype, expanded_prototype
1917  integer, intent(in) :: continuum_orbital, j1
1918 
1919  integer(longint) :: integral(2)
1920  real(wp) :: integral_coeff
1921  integer :: lwd(8), lw, ido, i, num_integrals
1922 
1923  num_integrals = master_prototype % get_size()
1924 
1925  do ido = 1, num_integrals
1926 
1927  !Get the integral
1928  call master_prototype % get_coeff_and_integral(ido, integral_coeff, integral)
1929  call unpack8ints(integral, lwd)
1930 
1931  lw = 0
1932 
1933  do i = 1, 4
1934  if (lwd(i) == continuum_orbital) lw=i
1935  end do
1936 
1937  if (lw == 0) then
1938  call expanded_prototype % insert_symbol(integral, integral_coeff, .false.)
1939  cycle
1940  else
1941  lwd(lw) = continuum_orbital + j1 - 1
1942  end if
1943 
1944  call expanded_prototype % insert_ijklm_symbol(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), integral_coeff, .false.)
1945 
1946  end do
1947 
1948  end subroutine expand_continuum_l2
1949 
1950 
1952  subroutine expand_off_diagonal_general (this, continuum_orbital_a, continuum_orbital_b, master_prototype, &
1953  ja, jb, expanded_prototype)
1954  class(contracted_hamiltonian) :: this
1955  class(symbolicelementvector), intent(in) :: master_prototype, expanded_prototype
1956  integer, intent(in) :: continuum_orbital_a, continuum_orbital_b, ja, jb
1957 
1958  integer(longint) :: integral(2)
1959  real(wp) :: integral_coeff
1960  integer :: lwd(8), lwa, lwb, ido, i, num_integrals
1961 
1962  num_integrals = master_prototype % get_size()
1963 
1964  do ido = 1, num_integrals
1965 
1966  !Get the integral
1967  call master_prototype % get_coeff_and_integral(ido, integral_coeff, integral)
1968  call unpack8ints(integral, lwd)
1969 
1970  lwa = 0
1971  lwb = 0
1972 
1973  do i = 1, 4
1974  if (lwd(i) == continuum_orbital_a) lwa = i
1975  if (lwd(i) == continuum_orbital_b) lwb = i
1976  end do
1977 
1978  !No occurances
1979  if (max(lwa, lwb) == 0) then
1980  call expanded_prototype % insert_symbol(integral, integral_coeff, .false.)
1981  cycle
1982  else if(lwb == 0)then
1983  lwd(lwa) = continuum_orbital_a + ja - 1
1984  else if (lwa == 0) then
1985  lwd(lwb) = continuum_orbital_b + jb - 1
1986  else
1987  lwd(lwa) = continuum_orbital_a + ja - 1
1988  lwd(lwb) = continuum_orbital_b + jb - 1
1989  end if
1990 
1991  !IF(ipair(lwd(1))+lwd(2) > ipair(lwd(3))+lwd(4)) then
1992  call expanded_prototype % insert_ijklm_symbol(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), integral_coeff, .false.)
1993  !else
1994  !call expanded_prototype%insert_ijklm_symbol(lwd(3),lwd(4),lwd(1),lwd(2),lwd(5),integral_coeff)
1995  !endif
1996  end do
1997 
1998  end subroutine expand_off_diagonal_general
1999 
2000 
2011  subroutine expand_diagonal_eval (this, continuum_orbital, master_prototype, j1, mat_coeffs)
2012  class(contracted_hamiltonian) :: this
2013  integer, intent(in) :: continuum_orbital, j1
2014  type(symbolicelementvector), intent(in) :: master_prototype(:)
2015  real(wp), intent(out) :: mat_coeffs(:)
2016 
2017  integer(longint) :: integral(2)
2018  real(wp) :: integral_coeff
2019  integer :: lwd(8), lw1, lw2, ido, i, prototypes, num_prototypes, num_integrals
2020 
2021  num_prototypes = size(master_prototype)
2022  num_integrals = master_prototype(1) % get_size()
2023  mat_coeffs = 0
2024 
2025  if (num_integrals == 0) return
2026 
2027  do ido = 1, num_integrals
2028 
2029  !Get the integral
2030  call master_prototype(1) % get_coeff_and_integral(ido, integral_coeff, integral)
2031  call unpack8ints(integral, lwd)
2032 
2033  integral_coeff = 1.0_wp
2034 
2035  lw1 = 0
2036  lw2 = 0
2037 
2038  do i = 1, 4
2039  if (lwd(i) == continuum_orbital) then
2040  if (lw1 == 0) then
2041  lw1 = i
2042  else
2043  lw2 = i
2044  end if
2045  end if
2046  end do
2047 
2048  if (lw1 == 0) then
2049  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2050  do prototypes = 1, num_prototypes
2051  mat_coeffs(prototypes) = mat_coeffs(prototypes) &
2052  + master_prototype(prototypes) % get_coefficient(ido) * integral_coeff
2053  end do
2054  cycle
2055  else if (lw2 == 0) then
2056  lwd(lw1) = continuum_orbital + j1 - 1
2057  else
2058  lwd(lw1) = continuum_orbital + j1 - 1
2059  lwd(lw2) = continuum_orbital + j1 - 1
2060  end if
2061 
2062  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2063  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2064 
2065  do prototypes = 1, num_prototypes
2066  mat_coeffs(prototypes) = mat_coeffs(prototypes) + master_prototype(prototypes)%get_coefficient(ido) * integral_coeff
2067  end do
2068 
2069  end do
2070 
2071  end subroutine expand_diagonal_eval
2072 
2073 
2084  subroutine contr_expand_diagonal_eval (this, continuum_orbital, master_prototype, j1, mat_coeffs)
2085  class(contracted_hamiltonian) :: this
2086  type(contractedsymbolicelementvector), intent(in) :: master_prototype
2087  integer, intent(in) :: continuum_orbital, j1
2088  real(wp), intent(out) :: mat_coeffs(:,:)
2089 
2090  integer(longint) :: integral(2)
2091  real(wp) :: integral_coeff
2092 
2093  integer :: lwd(8), lw1, lw2, ido, i, prototypes, num_prototypes, num_integrals, num_targets_1, num_targets_2, n1, n2
2094 
2095  num_integrals = master_prototype % get_size()
2096  num_targets_1 = master_prototype % get_num_targets_sym1()
2097  num_targets_2 = master_prototype % get_num_targets_sym2()
2098  mat_coeffs = 0
2099 
2100  if (num_integrals == 0) return
2101 
2102  do ido = 1, num_integrals
2103 
2104  !Get the integral
2105  integral = master_prototype % get_integral_label(ido)
2106  call unpack8ints(integral, lwd)
2107 
2108  integral_coeff = 1.0_wp
2109  lw1 = 0
2110  lw2 = 0
2111 
2112  do i = 1, 4
2113  if (lwd(i) == continuum_orbital) then
2114  if (lw1 == 0) then
2115  lw1 = i
2116  else
2117  lw2 = i
2118  end if
2119  end if
2120  end do
2121 
2122  if (lw1 == 0) then
2123  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2124  do n1 = 1,num_targets_1
2125  do n2 = 1,num_targets_2
2126  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2127  end do
2128  end do
2129  cycle
2130  else if (lw2 == 0) then
2131  lwd(lw1) = continuum_orbital + j1 - 1
2132  else
2133  lwd(lw1) = continuum_orbital + j1 - 1
2134  lwd(lw2) = continuum_orbital + j1 - 1
2135  end if
2136 
2137  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2138  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2139 
2140  do n1 = 1,num_targets_1
2141  do n2 = 1,num_targets_2
2142  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2143  end do
2144  end do
2145 
2146  end do
2147 
2148  end subroutine contr_expand_diagonal_eval
2149 
2150 
2161  subroutine expand_continuum_l2_eval (this, continuum_orbital, master_prototype, j1, mat_coeffs)
2162  class(contracted_hamiltonian) :: this
2163  class(symbolicelementvector), intent(in) :: master_prototype(:)
2164  integer, intent(in) :: continuum_orbital, j1
2165  real(wp), intent(out) :: mat_coeffs(:)
2166 
2167  integer(longint) :: integral(2)
2168  real(wp) :: integral_coeff
2169  integer :: lwd(8), lw, ido, i, prototypes, num_prototypes, num_integrals
2170 
2171  num_prototypes = size(master_prototype)
2172  num_integrals = master_prototype(1) % get_size()
2173 
2174  mat_coeffs = 0.0_wp
2175 
2176  if (num_integrals == 0) return
2177 
2178  do ido = 1, num_integrals
2179 
2180  !Get the integral
2181  call master_prototype(1) % get_coeff_and_integral(ido, integral_coeff, integral)
2182  call unpack8ints(integral, lwd)
2183 
2184  integral_coeff = 1.0_wp
2185  lw = 0
2186 
2187  do i = 1, 4
2188  if (lwd(i) == continuum_orbital) lw = i
2189  end do
2190 
2191  if (lw == 0) then
2192  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2193  do prototypes = 1, num_prototypes
2194  mat_coeffs(prototypes) = mat_coeffs(prototypes) &
2195  + master_prototype(prototypes) % get_coefficient(ido) * integral_coeff
2196  end do
2197  else
2198  lwd(lw) = continuum_orbital + j1 - 1
2199  end if
2200 
2201  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2202 
2203  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2204 
2205  do prototypes = 1, num_prototypes
2206  mat_coeffs(prototypes) = mat_coeffs(prototypes) + master_prototype(prototypes)%get_coefficient(ido) * integral_coeff
2207  end do
2208 
2209  end do
2210 
2211  end subroutine expand_continuum_l2_eval
2212 
2213 
2224  subroutine contr_expand_continuum_l2_eval (this, continuum_orbital, master_prototype, j1, mat_coeffs)
2225  class(contracted_hamiltonian) :: this
2226  class(contractedsymbolicelementvector), intent(in) :: master_prototype
2227  integer, intent(in) :: continuum_orbital, j1
2228  real(wp), intent(out) :: mat_coeffs(:)
2229 
2230  integer(longint) :: integral(2)
2231  real(wp) :: integral_coeff
2232  integer :: lwd(8), lw, ido, i, num_targets_1, num_targets_2, n1, n2, num_integrals
2233 
2234  num_targets_1 = master_prototype % get_num_targets_sym1()
2235  num_integrals = master_prototype % get_size()
2236  mat_coeffs = 0.0_wp
2237 
2238  if (num_integrals == 0) return
2239 
2240  do ido = 1, num_integrals
2241 
2242  !Get the integral
2243  integral = master_prototype % get_integral_label(ido)
2244  call unpack8ints(integral, lwd)
2245 
2246  integral_coeff = 1.0_wp
2247 
2248  lw = 0
2249 
2250  do i = 1, 4
2251  if (lwd(i) == continuum_orbital) lw = i
2252  end do
2253 
2254  if (lw == 0) then
2255  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2256  do n1 = 1, num_targets_1
2257  mat_coeffs(n1) = mat_coeffs(n1) + master_prototype % get_coefficient(ido, n1, 1) * integral_coeff
2258  end do
2259  cycle
2260  else
2261  lwd(lw) = continuum_orbital + j1 - 1
2262  end if
2263 
2264  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2265 
2266  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2267 
2268  do n1 = 1, num_targets_1
2269  mat_coeffs(n1) = mat_coeffs(n1) + master_prototype % get_coefficient(ido, n1, 1) * integral_coeff
2270  end do
2271 
2272  end do
2273 
2274  end subroutine contr_expand_continuum_l2_eval
2275 
2276 
2289  subroutine expand_off_diagonal_eval (this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
2290  class(contracted_hamiltonian) :: this
2291  class(symbolicelementvector), intent(in) :: master_prototype(:)
2292  integer, intent(in) :: continuum_orbital_a, continuum_orbital_b, ja, jb
2293  real(wp), intent(out) :: mat_coeffs(:)
2294 
2295  integer(longint) :: integral(2)
2296  real(wp) :: integral_coeff
2297  integer :: lwd(8), lwa, lwb, ido, i, prototypes, num_prototypes, num_integrals
2298 
2299  num_prototypes = size(master_prototype)
2300  num_integrals = master_prototype(1) % get_size()
2301  mat_coeffs = 0
2302 
2303  if (num_integrals == 0) return
2304 
2305  do ido = 1, num_integrals
2306 
2307  !Get the integral
2308  call master_prototype(1) % get_coeff_and_integral(ido, integral_coeff, integral)
2309  call unpack8ints(integral, lwd)
2310 
2311  integral_coeff = 1.0_wp
2312 
2313  lwa = 0
2314  lwb = 0
2315 
2316  do i = 1, 4
2317  if (lwd(i) == continuum_orbital_a) lwa = i
2318  if (lwd(i) == continuum_orbital_b) lwb = i
2319  end do
2320 
2321  !No occurances
2322  if (max(lwa, lwb) == 0) then
2323  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2324 
2325  do prototypes = 1,num_prototypes
2326  mat_coeffs(prototypes) = mat_coeffs(prototypes) &
2327  + master_prototype(prototypes) % get_coefficient(ido) * integral_coeff
2328  end do
2329  !expand_off_diagonal_eval = expand_off_diagonal_eval+this%evaluate_integrals_singular(integral,integral_coeff,NORMAL_PHASE)
2330  cycle
2331  else if (lwb == 0) then
2332  lwd(lwa) = continuum_orbital_a + ja - 1
2333  else if (lwa == 0) then
2334  lwd(lwb) = continuum_orbital_b + jb - 2
2335  else
2336  lwd(lwa) = continuum_orbital_a + ja - 1
2337  lwd(lwb) = continuum_orbital_b + jb - 2
2338  end if
2339 
2340  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2341 
2342  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2343 
2344  do prototypes = 1,num_prototypes
2345  mat_coeffs(prototypes) = mat_coeffs(prototypes) + master_prototype(prototypes)%get_coefficient(ido) * integral_coeff
2346  end do
2347 
2348  end do
2349 
2350  end subroutine expand_off_diagonal_eval
2351 
2352 
2365  subroutine contr_expand_off_diagonal_eval (this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
2366  class(contracted_hamiltonian) :: this
2367  class(contractedsymbolicelementvector), intent(in) :: master_prototype
2368  integer, intent(in) :: continuum_orbital_a, continuum_orbital_b, ja, jb
2369  real(wp), intent(out) :: mat_coeffs(:,:)
2370 
2371  integer(longint) :: integral(2)
2372  real(wp) :: integral_coeff
2373 
2374  integer :: lwd(8), lwa, lwb, ido, i, prototypes, num_prototypes, num_integrals, num_targets_1, num_targets_2, n1, n2
2375 
2376 
2377  num_integrals = master_prototype % get_size()
2378  num_targets_1 = master_prototype % get_num_targets_sym1()
2379  num_targets_2 = master_prototype % get_num_targets_sym2()
2380  mat_coeffs = 0
2381 
2382  if (num_integrals == 0) return
2383 
2384  do ido = 1, num_integrals
2385 
2386  !Get the integral
2387  integral = master_prototype % get_integral_label(ido)
2388  call unpack8ints(integral, lwd)
2389 
2390  integral_coeff = 1.0_wp
2391 
2392  lwa = 0
2393  lwb = 0
2394 
2395  do i = 1, 4
2396  if (lwd(i) == continuum_orbital_a) lwa = i
2397  if (lwd(i) == continuum_orbital_b) lwb = i
2398  end do
2399 
2400  !No occurances
2401  if (max(lwa, lwb) == 0) then
2402  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2403 
2404  do n1 = 1, num_targets_1
2405  do n2 = 1, num_targets_2
2406  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2407  end do
2408  end do
2409  !expand_off_diagonal_eval = expand_off_diagonal_eval+this%evaluate_integrals_singular(integral,integral_coeff,NORMAL_PHASE)
2410  cycle
2411  else if (lwb == 0) then
2412  lwd(lwa) = continuum_orbital_a + ja - 1
2413  else if (lwa == 0) then
2414  lwd(lwb) = continuum_orbital_b + jb - 2
2415  else
2416  lwd(lwa) = continuum_orbital_a + ja - 1
2417  lwd(lwb) = continuum_orbital_b + jb - 2
2418  end if
2419 
2420  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2421 
2422  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2423 
2424  do n1 = 1, num_targets_1
2425  do n2 = 1, num_targets_2
2426  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2427  end do
2428  end do
2429 
2430  end do
2431 
2432  end subroutine contr_expand_off_diagonal_eval
2433 
2434 
2447  subroutine expand_off_diagonal_gen_eval (this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
2448  class(contracted_hamiltonian) :: this
2449  class(contractedsymbolicelementvector), intent(in) :: master_prototype
2450  integer, intent(in) :: continuum_orbital_a, continuum_orbital_b, ja, jb
2451  real(wp), intent(out) :: mat_coeffs(:,:)
2452 
2453  integer(longint) :: integral(2)
2454  real(wp) :: integral_coeff
2455  integer :: lwd(8), lwa, lwb, ido, i, n1, n2, num_targets_1, num_targets_2, ii, num_integrals
2456 
2457  num_targets_1 = master_prototype % get_num_targets_sym1()
2458  num_targets_2 = master_prototype % get_num_targets_sym2()
2459  num_integrals = master_prototype % get_size()
2460  mat_coeffs = 0
2461 
2462  if (num_integrals == 0) return
2463 
2464  do ido = 1, num_integrals
2465 
2466  !Get the integral
2467  integral = master_prototype % get_integral_label(ido)
2468  call unpack8ints(integral, lwd)
2469 
2470  integral_coeff = 1.0_wp
2471 
2472  lwa = 0
2473  lwb = 0
2474 
2475  do i = 1, 4
2476  if (lwd(i) == continuum_orbital_a) lwa = i
2477  if (lwd(i) == continuum_orbital_b) lwb = i
2478  end do
2479 
2480  !No occurances
2481  if (max(lwa, lwb) == 0) then
2482  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2483  do n1 = 1,num_targets_1
2484  do n2 = 1,num_targets_2
2485  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2486  end do
2487  end do
2488  cycle
2489  else if(lwb == 0)then
2490  lwd(lwa) = continuum_orbital_a + ja - 1
2491  else if (lwa == 0) then
2492  lwd(lwb) = continuum_orbital_b + jb - 1
2493  else
2494  lwd(lwa) = continuum_orbital_a + ja - 1
2495  lwd(lwb) = continuum_orbital_b + jb - 1
2496  end if
2497 
2498  call pack8ints(lwd(1), lwd(2), lwd(3), lwd(4), lwd(5), 0, 0, 0, integral)
2499 
2500  integral_coeff = this % evaluate_integrals_singular(integral, 1.0_wp, normal_phase)
2501 
2502  do n1 = 1, num_targets_1
2503  do n2 = 1, num_targets_2
2504  mat_coeffs(n1,n2) = mat_coeffs(n1,n2) + master_prototype % get_coefficient(ido, n1, n2) * integral_coeff
2505  end do
2506  end do
2507 
2508  end do
2509 
2510  end subroutine expand_off_diagonal_gen_eval
2511 
2512 
2522  subroutine reduce_prototypes (this, prototypes)
2523  class(contracted_hamiltonian), intent(in) :: this
2524  class(symbolicelementvector), intent(in) :: prototypes(:)
2525 
2526  integer :: num_prototypes, ido
2527 
2528  num_prototypes = size(prototypes)
2529 
2530  if (num_prototypes <= 1) return
2531 
2532  do ido = 2, num_prototypes
2533  call prototypes(1) % add_symbols(prototypes(ido))
2534  end do
2535 
2536  end subroutine reduce_prototypes
2537 
2538 
2548  integer function get_starting_index (this, symmetry)
2549  class(contracted_hamiltonian), intent(in) :: this
2550  integer, intent(in) :: symmetry
2551 
2552  integer :: ido
2553 
2554  get_starting_index = 1
2555  do ido = 2, symmetry
2556  get_starting_index = get_starting_index + this % options % num_ci_target_sym(ido - 1) * this % csf_skip
2557  end do
2558 
2559  end function get_starting_index
2560 
2561 
2573  real(wp) function get_target_coeff (this, i, m, n)
2574  class(contracted_hamiltonian), intent(in) :: this
2575 
2576  integer :: i, m, n
2577 
2578  get_target_coeff = this % rmat_ci(i) % eigenvectors(m, n)
2579 
2580  end function get_target_coeff
2581 
2582 
2583  subroutine fast_contract_class_1_3_diag (this, i1, num_targets, ido, temp_prototype, master_prototypes)
2584  class(contracted_hamiltonian) :: this
2585  integer, intent(in) :: i1, ido, num_targets
2586  class(symbolicelementvector), intent(in) :: temp_prototype, master_prototypes(num_targets * (num_targets + 1) / 2)
2587 
2588  integer(longint), dimension(2) :: label
2589 
2590  integer :: found_idx, ii, n1, n2, num_symbols, jdo
2591  real(wp) :: alpha(num_targets * (num_targets + 1) / 2), coeff
2592 
2593  ii = 1
2594 
2595  !get our coeffs
2596  do n1 = 1, num_targets
2597  do n2 = n1, num_targets
2598  ! Apply our coefficeints for each combination to the master, Left hand of Eq. 6
2599  alpha(ii) = this % get_target_coeff(i1, ido, n1) * this % get_target_coeff(i1, ido, n2)
2600  !call master_prototype(ii)%add_symbols(temp_prototype,alpha)
2601  ii = ii + 1
2602  end do
2603  end do
2604 
2605  num_symbols = temp_prototype % get_size()
2606 
2607  do jdo = 1, num_symbols
2608  call temp_prototype % get_coeff_and_integral(jdo, coeff, label)
2609  !We only need to perform the expensive check once per insertion
2610  if (master_prototypes(1) % check_same_integral(label, found_idx)) then
2611  ii = 1
2612  !get our coeffs
2613  do n1 = 1, num_targets
2614  do n2 = n1, num_targets
2615  call master_prototypes(ii) % modify_coeff(found_idx, alpha(ii) * coeff)
2616  ii = ii + 1
2617  end do
2618  end do
2619  else
2620  ii = 1
2621  !get our coeffs
2622  do n1 = 1, num_targets
2623  do n2 = n1, num_targets
2624  !Insert without a check
2625  call master_prototypes(ii) % insert_symbol(label, alpha(ii) * coeff, .false.)
2626  ii = ii + 1
2627  end do
2628  end do
2629  end if
2630  end do
2631 
2632  end subroutine fast_contract_class_1_3_diag
2633 
2634 
2635  subroutine fast_contract_class_1_3_offdiag (this, i1, num_targets, s1, s2, temp_prototype, master_prototypes)
2636  class(contracted_hamiltonian) :: this
2637  integer, intent(in) :: i1, s1, s2, num_targets
2638  class(symbolicelementvector), intent(in) :: temp_prototype, master_prototypes(num_targets * (num_targets + 1) / 2)
2639 
2640  integer(longint), dimension(2) :: label
2641 
2642  integer :: found_idx, ii, n1, n2, num_symbols, jdo
2643  real(wp) :: alpha(num_targets * (num_targets + 1) / 2), coeff
2644 
2645  ii = 1
2646 
2647  !get our coeffs
2648  do n1 = 1, num_targets
2649  do n2 = n1, num_targets
2650  ! Apply our coefficeints for each combination to the master, Left hand of Eq. 6
2651  alpha(ii) = this % get_target_coeff(i1, s1, n1) * this % get_target_coeff(i1, s2, n2) &
2652  + this % get_target_coeff(i1, s2, n1) * this % get_target_coeff(i1, s1, n2)
2653  !call master_prototype(ii)%add_symbols(temp_prototype,alpha)
2654  ii = ii + 1
2655  end do
2656  end do
2657 
2658  num_symbols = temp_prototype % get_size()
2659 
2660  do jdo = 1, num_symbols
2661  call temp_prototype % get_coeff_and_integral(jdo, coeff, label)
2662  !We only need to perform the expensive check once per insertion
2663  if (master_prototypes(1) % check_same_integral(label, found_idx)) then
2664  ii = 1
2665  !get our coeffs
2666  do n1 = 1, num_targets
2667  do n2 = n1, num_targets
2668  call master_prototypes(ii) % modify_coeff(found_idx, alpha(ii) * coeff)
2669  ii = ii + 1
2670  end do
2671  end do
2672  else
2673  ii = 1
2674  !get our coeffs
2675  do n1 = 1, num_targets
2676  do n2 = n1, num_targets
2677  !Insert without a check
2678  call master_prototypes(ii) % insert_symbol(label, alpha(ii) * coeff, .false.)
2679  ii = ii + 1
2680  end do
2681  end do
2682  end if
2683  end do
2684 
2685  end subroutine fast_contract_class_1_3_offdiag
2686 
2687 
2688  subroutine fast_contract_class_567 (this, i1, i2, num_targets1, num_targets2, s1, s2, temp_prototype, master_prototypes)
2689  class(contracted_hamiltonian) :: this
2690  integer, intent(in) :: i1, i2, s1, s2, num_targets1, num_targets2
2691  class(symbolicelementvector), intent(in) :: temp_prototype, master_prototypes(num_targets1, num_targets2)
2692 
2693  integer(longint), dimension(2) :: label
2694 
2695  integer :: found_idx, ii, n1, n2, num_symbols, jdo
2696  real(wp) :: alpha(num_targets1, num_targets2), coeff
2697 
2698  alpha = 0
2699  !get our coeffs
2700  do n1 = 1, num_targets1
2701  do n2 = 1, num_targets2
2702  ! Apply our coefficeints for each combination to the master, Left hand of Eq. 6
2703  alpha(n1,n2) = this % get_target_coeff(i1, s1, n1) * this % get_target_coeff(i2, s2, n2)
2704  !call master_prototype(ii)%add_symbols(temp_prototype,alpha)
2705  end do
2706  end do
2707 
2708  num_symbols = temp_prototype % get_size()
2709 
2710  do jdo = 1, num_symbols
2711  call temp_prototype % get_coeff_and_integral(jdo, coeff, label)
2712  !We only need to perform the expensive check once per insertion
2713  if (master_prototypes(1,1) % check_same_integral(label, found_idx)) then
2714  !get our coeffs
2715  do n1 = 1, num_targets1
2716  do n2 = 1, num_targets2
2717  call master_prototypes(n1,n2) % modify_coeff(found_idx, alpha(n1,n2) * coeff)
2718  end do
2719  end do
2720  else
2721  !get our coeffs
2722  do n1 = 1, num_targets1
2723  do n2 = 1, num_targets2
2724  !Insert without a check
2725  call master_prototypes(n1,n2) % insert_symbol(label, alpha(n1,n2) * coeff, .false.)
2726  end do
2727  end do
2728  end if
2729  end do
2730 
2731  end subroutine fast_contract_class_567
2732 
consts_mpi_ci::mat_sparse
integer, parameter mat_sparse
Matrix is sparse.
Definition: consts_mpi_ci.f90:120
contracted_hamiltonian_module::evaluate_class_5
subroutine evaluate_class_5(this, i1, num_target_1, i2, num_target_2, matrix_elements)
Builds the class 5 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:1008
contracted_hamiltonian_module::contracted_hamiltonian
Computation of Hamiltonian.
Definition: Contracted_Hamiltonian_module.f90:65
hamiltonian_module::basehamiltonian
This is an abstract class that contains the majority of functionality required to construct hamiltoni...
Definition: Hamiltonian_module.f90:57
utility_module::box_index_to_ij
subroutine, public box_index_to_ij(idx, height, i, j)
Extract indices from rectangular multi-index.
Definition: Utility_module.f90:73
contracted_symbolic_module
Symbolic module.
Definition: Contracted_Symbolic_Module.f90:33
contracted_hamiltonian_module::contr_expand_diagonal_eval
subroutine contr_expand_diagonal_eval(this, continuum_orbital, master_prototype, j1, mat_coeffs)
Expands the diagonal prototype symbols and evaluates for a single matrix element for co-ordiate (j1)
Definition: Contracted_Hamiltonian_module.f90:2085
contracted_hamiltonian_module::evaluate_class_3
subroutine evaluate_class_3(this, i1, num_targets, matrix_elements)
Builds the class 3 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:615
contracted_hamiltonian_module::evaluate_class_7
subroutine evaluate_class_7(this, i1, num_target_1, i2, num_target_2, matrix_elements)
Builds the class 7 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:1419
memorymanager_module
Memory manager module.
Definition: MemoryManager_module.f90:31
contracted_hamiltonian_module::initialize_contracted_hamiltonian
subroutine initialize_contracted_hamiltonian(this, rmat_ci)
Initializes the contracted hamiltonian and supplies target coefficients.
Definition: Contracted_Hamiltonian_module.f90:129
timing_module
Timing module.
Definition: Timing_Module.f90:28
contracted_hamiltonian_module::expand_diagonal
subroutine expand_diagonal(this, continuum_orbital, master_prototype, j1, expanded_prototype)
Deprecated.
Definition: Contracted_Hamiltonian_module.f90:1820
contracted_hamiltonian_module::evaluate_class_8
subroutine evaluate_class_8(this, matrix_elements)
Builds the class 8 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:1630
contracted_hamiltonian_module::build_contracted_hamiltonian
subroutine build_contracted_hamiltonian(this, matrix_elements)
Builds the Contracted Hamiltonian class by class.
Definition: Contracted_Hamiltonian_module.f90:155
contracted_hamiltonian_module::expand_off_diagonal_general
subroutine expand_off_diagonal_general(this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, expanded_prototype)
Deprecated.
Definition: Contracted_Hamiltonian_module.f90:1954
contracted_hamiltonian_module::fast_contract_class_1_3_offdiag
subroutine fast_contract_class_1_3_offdiag(this, i1, num_targets, s1, s2, temp_prototype, master_prototypes)
Definition: Contracted_Hamiltonian_module.f90:2636
utility_module::compute_total_triangular
integer(longint) function, public compute_total_triangular(n)
Calculate triangular area.
Definition: Utility_module.f90:47
contracted_hamiltonian_module::reduce_prototypes
subroutine reduce_prototypes(this, prototypes)
(Not used) Compresses several prototypes into a single prototype at position 1
Definition: Contracted_Hamiltonian_module.f90:2523
target_rmat_ci_module::target_rmat_ci
This class handles the storage of target CI coefficients.
Definition: Target_RMat_CI_module.f90:52
contracted_hamiltonian_module::evaluate_class_1
subroutine evaluate_class_1(this, i1, num_targets, matrix_elements)
Builds the class 1 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:357
contracted_hamiltonian_module::expand_diagonal_eval
subroutine expand_diagonal_eval(this, continuum_orbital, master_prototype, j1, mat_coeffs)
Expands the diagonal prototype symbols and evaluates for a single matrix element for co-ordiate (j1)
Definition: Contracted_Hamiltonian_module.f90:2012
contracted_hamiltonian_module::fast_contract_class_567
subroutine fast_contract_class_567(this, i1, i2, num_targets1, num_targets2, s1, s2, temp_prototype, master_prototypes)
Definition: Contracted_Hamiltonian_module.f90:2689
symbolic_module
Symbolic module.
Definition: Symbolic_Module.f90:33
parallelization_module::process_grid
type(processgrid) process_grid
Definition: Parallelization_module.F90:80
basematrix_module
Base matrix module.
Definition: BaseMatrix_module.f90:28
utility_module
Utility module.
Definition: Utility_module.f90:28
contracted_hamiltonian_module
Contracted Hamiltonian module.
Definition: Contracted_Hamiltonian_module.f90:33
contracted_hamiltonian_module::fast_contract_class_1_3_diag
subroutine fast_contract_class_1_3_diag(this, i1, num_targets, ido, temp_prototype, master_prototypes)
Definition: Contracted_Hamiltonian_module.f90:2584
consts_mpi_ci
MPI SCATCI Constants module.
Definition: consts_mpi_ci.f90:31
contracted_hamiltonian_module::expand_continuum_l2
subroutine expand_continuum_l2(this, continuum_orbital, master_prototype, j1, expanded_prototype)
Deprecated.
Definition: Contracted_Hamiltonian_module.f90:1915
symbolic_module::symbolicelementvector
This class handles the storage symbolic elements.
Definition: Symbolic_Module.f90:57
contracted_hamiltonian_module::contr_expand_continuum_l2_eval
subroutine contr_expand_continuum_l2_eval(this, continuum_orbital, master_prototype, j1, mat_coeffs)
Expands the continuum-L2 prototype symbols and evaluates for a single matrix element for co-ordinate ...
Definition: Contracted_Hamiltonian_module.f90:2225
contracted_hamiltonian_module::compute_matrix_ij
subroutine compute_matrix_ij(this, i1, n1, j1, i2, n2, j2, i, j)
Finds the starting matrix index for paticular target symmetries and target states.
Definition: Contracted_Hamiltonian_module.f90:1784
contracted_hamiltonian_module::evaluate_class_2
subroutine evaluate_class_2(this, matrix_elements)
Builds the class 2 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:566
basematrix_module::basematrix
Base matrix type.
Definition: BaseMatrix_module.f90:47
parallelization_module
Distribution of processes into a grid.
Definition: Parallelization_module.F90:29
contracted_hamiltonian_module::expand_off_diagonal_gen_eval
subroutine expand_off_diagonal_gen_eval(this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
Expands the off-diagonal generic prototype symbols and evaluates for a single matrix element for co-o...
Definition: Contracted_Hamiltonian_module.f90:2448
contracted_hamiltonian_module::expand_off_diagonal_eval
subroutine expand_off_diagonal_eval(this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
Expands the off-diagonal same/similar symmetry prototype symbols and evaluates for a single matrix el...
Definition: Contracted_Hamiltonian_module.f90:2290
consts_mpi_ci::no_pure_target_integral_diff
integer, parameter no_pure_target_integral_diff
Same as diff but dont evalute integrals belonging to the target state.
Definition: consts_mpi_ci.f90:79
contracted_hamiltonian_module::expand_continuum_l2_eval
subroutine expand_continuum_l2_eval(this, continuum_orbital, master_prototype, j1, mat_coeffs)
Expands the continuum-L2 prototype symbols and evaluates for a single matrix element for co-ordinate ...
Definition: Contracted_Hamiltonian_module.f90:2162
utility_module::compute_total_box
integer function, public compute_total_box(width, height)
Calculate rectangular product.
Definition: Utility_module.f90:61
contracted_symbolic_module::contractedsymbolicelementvector
This class handles the storage symbolic elements.
Definition: Contracted_Symbolic_Module.f90:62
contracted_hamiltonian_module::expand_off_diagonal
subroutine expand_off_diagonal(this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, expanded_prototype)
Deprecated.
Definition: Contracted_Hamiltonian_module.f90:1867
contracted_hamiltonian_module::get_starting_index
integer function get_starting_index(this, symmetry)
Gets the starting index configuration state functions at a specific symmetry.
Definition: Contracted_Hamiltonian_module.f90:2549
contracted_hamiltonian_module::contr_expand_off_diagonal_eval
subroutine contr_expand_off_diagonal_eval(this, continuum_orbital_a, continuum_orbital_b, master_prototype, ja, jb, mat_coeffs)
Expands the off-diagonal same/similar symmetry prototype symbols and evaluates for a single matrix el...
Definition: Contracted_Hamiltonian_module.f90:2366
contracted_hamiltonian_module::get_target_coeff
real(wp) function get_target_coeff(this, i, m, n)
Simply a wrapper to aid in clarity.
Definition: Contracted_Hamiltonian_module.f90:2574
utility_module::triangular_index_to_ij
subroutine, public triangular_index_to_ij(idx_f, N, row, column)
Extract indices from triangular multi-index.
Definition: Utility_module.f90:87
timing_module::master_timer
type(timer), public master_timer
Definition: Timing_Module.f90:74
hamiltonian_module
Base Hamiltonian module.
Definition: Hamiltonian_module.f90:33
contracted_hamiltonian_module::evaluate_class_4
subroutine evaluate_class_4(this, i1, num_states, l1, matrix_elements)
Builds the class 4 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:863
target_rmat_ci_module
Target Rmat CI module.
Definition: Target_RMat_CI_module.f90:31
memorymanager_module::master_memory
type(memorymanager), public master_memory
This is the global memory manager.
Definition: MemoryManager_module.f90:69
consts_mpi_ci::normal_phase
integer, parameter normal_phase
No phase correction.
Definition: consts_mpi_ci.f90:93
contracted_hamiltonian_module::evaluate_class_2_and_8
subroutine evaluate_class_2_and_8(this, matrix_elements)
Builds both the class 2 and class 8 (Pure L2) parts of the matrix elements.
Definition: Contracted_Hamiltonian_module.f90:1688
contracted_hamiltonian_module::evaluate_class_6
subroutine evaluate_class_6(this, i1, num_target_1, i2, num_target_2, matrix_elements)
Builds the class 6 part of the matrix.
Definition: Contracted_Hamiltonian_module.f90:1211