MPI-SCATCI 2.0
An MPI version of SCATCI
Loading...
Searching...
No Matches
CI_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
22!> \brief Target CI Hamiltonian module
23!> \authors A Al-Refaie
24!> \date 2017
25!>
26!> This module handles the computation of multiple target symmetry hamiltonians in a single run.
27!>
28!> \note 01/02/2017 - Ahmed Al-Refaie: Initial revision.
29!> \note 16/01/2019 - Jakub Benda: Unifom coding style and expanded documentation.
30!>
31module ci_hamiltonian_module
32
33 use const_gbl, only: stdout
35 use precisn, only: wp
36 use basematrix_module, only: basematrix
37 use hamiltonian_module, only: basehamiltonian
38 use options_module, only: options
39 use parallelization_module, only: grid => process_grid
40 use symbolic_module, only: symbolicelementvector
41 use utility_module, only: compute_total_box, box_index_to_ij
42
43 implicit none
44
45 public target_ci_hamiltonian
46
47 private
48
49 !> \brief Hamiltonian type
50 !> \authors A Al-Refaie
51 !> \date 2017
52 !>
53 !> This class differs from the Uncontracted as it allows for the computation of
54 !> multiple targets of differing symmetries in a single run.
55 !>
56 type, extends(basehamiltonian) :: target_ci_hamiltonian
57 integer :: target_symmetry !< The target symmetry hamiltonian to compute
58 integer :: csf_skip !< The CSF index stride
59 contains
60 procedure, public :: initialize => initialize_target_ci_hamiltonian
61 procedure, public :: build_hamiltonian => build_target_ci_hamiltonian_fast
62 end type target_ci_hamiltonian
63
64contains
65
66 !> \brief Sets up the hamiltonian to build for a specific target symmetry
67 !> \authors A Al-Refaie
68 !> \date 2017
69 !>
70 !> \param[inout] this hamiltonian object to update.
71 !> \param[in] target_symmetry The target symmetry hamiltonian to build
72 !>
73 subroutine initialize_target_ci_hamiltonian (this, target_symmetry)
74
75 class(target_ci_hamiltonian) :: this
76 integer, intent(in) :: target_symmetry
77
78 this % target_symmetry = target_symmetry
79 if (this % options % csf_type == normal_csf) then
80 this % csf_skip = this % options % num_continuum_orbitals_target(target_symmetry)
81 else
82 this % csf_skip = 2
83 end if
84
85 this % initialized = .true.
86 end subroutine initialize_target_ci_hamiltonian
87
88
89 !> \brief Builds the Target Hamiltonian of a specific target symmetry
90 !> \authors A Al-Refaie
91 !> \date 2017
92 !>
93 !> \param[inout] this Hamiltonian object to update.
94 !> \param[out] matrix_elements A BaseMatrix object, stores the calculated elements.
95 !>
96 subroutine build_target_ci_hamiltonian (this, matrix_elements)
97
98 class(target_ci_hamiltonian) :: this
99 class(basematrix), intent(inout) :: matrix_elements
100 type(symbolicelementvector) :: symbolic_elements, ref_symbolic_elements
101 integer :: starting_index, num_csfs, ido, jdo, csf_a_idx, csf_b_idx, pzero_, num_elements
102 real(wp) :: mat_coeff, element_one
103
104 !Just a quick check in the old diagonal flag
105 if (this % diagonal_flag == no_pure_target_integral) then
106 this % diagonal_flag = matrix_evaluate_full
107 else
108 this % diagonal_flag = matrix_evaluate_diff
109 end if
110
111 this % phase_flag = 0
112
113 !Get the total number of CSFs within the symmetry
114 num_csfs = this % options % num_ci_target_sym(this % target_symmetry)
115
116 !Initialize the matrix structure as DENSE with no block structure
117 call matrix_elements % initialize_matrix_structure(num_csfs, mat_dense, num_csfs)
118
119 !Construct the symbolic elements and clear
120 call symbolic_elements % construct
121 call symbolic_elements % clear
122 call ref_symbolic_elements % construct
123
124 starting_index = 1
125 !Get the start of the CSFs within the target symmetry
126 do ido = 2, this % target_symmetry
127 starting_index = starting_index + this % options % num_ci_target_sym(ido - 1) * this % csf_skip
128 end do
129
130 this % orbitals % MFLG = 0
131
132 !Do the (1,1) diagonal --------------------------------------------------------!
133 csf_a_idx = starting_index
134
135 !Everyone must have this
136 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_a_idx), ref_symbolic_elements, 0, .false.)
137
138 !Evaluate the symbols for the integral for the matrix element (1,1)
139 if (.not. ref_symbolic_elements % is_empty()) then
140 mat_coeff = this % evaluate_integrals(ref_symbolic_elements, 0)
141 this % element_one = mat_coeff
142 !Lets have the master keep it, it will eventually reach everyone else if they need it
143 if (grid % mygrow == 0 .and. grid % mygcol == 0) call matrix_elements % insert_matrix_element(1, 1, mat_coeff)
144 call matrix_elements % update_pure_L2(.false.)
145 end if
146 !write(stdout,*)this%element_one
147
148 !Clear the symbols
149 call symbolic_elements % clear
150
151 !------------Do the rest of diagonals---------------------------!
152 do ido = 2, num_csfs
153 call matrix_elements % update_pure_L2(.false.)
154 csf_a_idx = csf_a_idx + this % csf_skip
155 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_a_idx), symbolic_elements, 0)
156 if (symbolic_elements % is_empty()) cycle
157
158 if (this % diagonal_flag == 0) call symbolic_elements % add_symbols(ref_symbolic_elements, -1.0_wp)
159 mat_coeff = this%evaluate_integrals(symbolic_elements,0)
160 if (this % diagonal_flag == 0) mat_coeff = mat_coeff + this % element_one
161 num_elements = num_elements + 1
162
163 call matrix_elements % insert_matrix_element(ido, ido, mat_coeff)
164 call symbolic_elements % clear
165 end do
166
167 this % orbitals % MFLG = 1
168
169 csf_a_idx = starting_index - this % csf_skip
170 !Do the off-idagonal
171 do ido = 1, num_csfs - 1
172 !Get the first CSf index
173 csf_a_idx = csf_a_idx + this % csf_skip
174 !Start the second CSF index
175 csf_b_idx = csf_a_idx
176 !Loop thorugh the lower triangular
177 do jdo = ido + 1, num_csfs
178 !Compute the second CSf index
179 csf_b_idx = csf_b_idx + this % csf_skip
180 !Perform an update if necessary
181 call matrix_elements % update_pure_L2(.false.)
182 !Slater the CSF
183 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_b_idx), symbolic_elements, 1)
184 !If empty, skip
185 if (symbolic_elements % is_empty()) cycle
186
187 num_elements = num_elements + 1
188 !Evaulate the matrix coefficient
189 mat_coeff = this % evaluate_integrals(symbolic_elements, 0)
190
191 !Insert into the matrix
192 call matrix_elements % insert_matrix_element(jdo, ido, mat_coeff)
193 !Clear
194 call symbolic_elements % clear
195 end do
196 end do
197 !Force an update to clear the matrix cache if needed
198 call matrix_elements % update_pure_L2(.true.)
199
200 !Cleanup
201 call symbolic_elements % destroy
202 call ref_symbolic_elements % destroy
203
204 !Finalize if needed
205 call matrix_elements % finalize_matrix
206
207 end subroutine build_target_ci_hamiltonian
208
209
210 !> \brief Builds the Target Hamiltonian of a specific target symmetry fast, currently not working
211 !> \authors A Al-Refaie
212 !> \date 2017
213 !>
214 !> \todo Fix this so the results are correct.
215 !>
216 !> \param[inout] this Hamiltonian object to update.
217 !> \param[out] matrix_elements A BaseMatrix object, stores the calculated elements.
218 !>
219 subroutine build_target_ci_hamiltonian_fast (this, matrix_elements)
220
221 class(target_ci_hamiltonian) :: this
222 class(basematrix), intent(inout) :: matrix_elements
223 type(symbolicelementvector) :: symbolic_elements, ref_symbolic_elements
224 integer :: starting_index, num_csfs, ido, jdo, csf_a_idx, csf_b_idx, pzero_, loop_idx, total_vals
225 integer :: num_elements,begin_csf,loop_skip,my_idx,loop_ido,m_flag
226 real(wp) :: mat_coeff, element_one
227
228 !Just a quick check in the old diagonal flag
229 if (this % diagonal_flag == no_pure_target_integral) then
230 this % diagonal_flag = matrix_evaluate_full
231 else
232 this % diagonal_flag = matrix_evaluate_diff
233 end if
234
235 this % phase_flag = 0
236 num_elements = 0
237
238 !Get the total number of CSFs within the symmetry
239 num_csfs = this % options % num_ci_target_sym(this % target_symmetry)
240
241 !Initialize the matrix structure as DENSE with no block structure
242 call matrix_elements % initialize_matrix_structure(num_csfs, mat_dense, num_csfs)
243
244 !Construct the symbolic elements and clear
245 call symbolic_elements % construct
246 call symbolic_elements % clear
247 call ref_symbolic_elements % construct
248
249 starting_index = 1
250 !Get the start of the CSFs within the target symmetry
251 do ido = 2, this % target_symmetry
252 starting_index = starting_index + this % options % num_ci_target_sym(ido - 1) * this % csf_skip
253 end do
254
255 m_flag = 0
256
257 !Do the (1,1) diagonal --------------------------------------------------------!
258 csf_a_idx = starting_index
259
260 !Everyone must have this
261 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_a_idx), ref_symbolic_elements, m_flag, .false.)
262
263 !Evaluate the symbols for the integral for the matrix element (1,1)
264 if (.not. ref_symbolic_elements % is_empty()) then
265 mat_coeff = this % evaluate_integrals(ref_symbolic_elements, 0)
266 this % element_one = mat_coeff
267 !Lets have the master keep it, it will eventually reach everyone else if they need it
268 if (grid % mygrow == 0 .and. grid % mygcol == 0) call matrix_elements % insert_matrix_element(1, 1, mat_coeff)
269 call matrix_elements % update_pure_L2(.false.)
270 end if
271 !write(stdout,*)this%element_one
272
273 !Clear the symbols
274 call symbolic_elements % clear
275
276 !------------Do the rest of diagonals---------------------------!
277 do ido = 2,num_csfs
278 call matrix_elements % update_pure_L2(.false.)
279 csf_a_idx = csf_a_idx + this % csf_skip
280
281 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_a_idx), symbolic_elements, 0)
282 if (symbolic_elements % is_empty()) cycle
283
284 if (this % diagonal_flag == 0) call symbolic_elements % add_symbols(ref_symbolic_elements, -1.0_wp)
285 mat_coeff = this % evaluate_integrals(symbolic_elements, 0)
286 if (this % diagonal_flag == 0) mat_coeff = mat_coeff + this % element_one
287 num_elements = num_elements + 1
288
289 call matrix_elements % insert_matrix_element(ido, ido, mat_coeff)
290 call symbolic_elements % clear
291 end do
292
293 begin_csf = starting_index - this % csf_skip
294 total_vals = compute_total_box(num_csfs, num_csfs)
295 loop_skip = max(1, grid % gprocs)
296 my_idx = max(grid % grank, 0)
297
298 do loop_ido = 1, total_vals, loop_skip
299 loop_idx = loop_ido + my_idx
300 call matrix_elements % update_pure_L2(.false.)
301 if (loop_idx > total_vals) cycle
302
303 call box_index_to_ij(loop_idx, num_csfs, ido, jdo)
304 if (ido <= jdo) cycle
305
306 csf_a_idx = begin_csf + ido * this % csf_skip
307 csf_b_idx = begin_csf + jdo * this % csf_skip
308
309 call this % slater_rules(this % csfs(csf_a_idx), this % csfs(csf_b_idx), symbolic_elements, 1, .false.)
310
311 if (symbolic_elements % is_empty()) cycle
312
313 num_elements = num_elements + 1
314 mat_coeff = this % evaluate_integrals(symbolic_elements, this % options % phase_correction_flag)
315
316 call matrix_elements % insert_matrix_element(ido, jdo, mat_coeff)
317 call symbolic_elements % clear
318 end do
319
320 call matrix_elements % update_pure_L2(.true.)
321 call symbolic_elements % destroy
322 call matrix_elements % finalize_matrix
323
324 write (stdout, "('Num of elements = ',i0)") num_elements
325
326 end subroutine build_target_ci_hamiltonian_fast
327
328end module ci_hamiltonian_module
MPI SCATCI Constants module.
integer, parameter normal_csf
Use configuration state functions as is.
integer, parameter matrix_evaluate_diff
Matrix is evaluated as a difference from the first element.
integer, parameter no_pure_target_integral
Same as full but dont evalute integrals belonging to the target state.
integer, parameter mat_dense
Matrix is dense.
integer, parameter matrix_evaluate_full
Matrix is evaluated as full.