MPI-SCATCI 2.0
An MPI version of SCATCI
Loading...
Searching...
No Matches
Contracted_Symbolic_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 Symbolic module
23!> \authors A Al-Refaie
24!> \date 2017
25!>
26!> This module handles the storage of symbolic elements produced from Slater rules
27!> when integrating configuration state functions.
28!>
29!> \note 30/01/2017 - Ahmed Al-Refaie: Initial documentation version
30!> \note 16/01/2019 - Jakub Benda: Unifom coding style and expanded documentation.
31!> \note 22/02/2019 - Jakub Benda: Removed dependency on C++ std::map.
32!>
33module contracted_symbolic_module
34
35 use const_gbl, only: stdout
37 use containers, only: bstree
38 use iso_c_binding, only: c_loc, c_ptr, c_f_pointer
39 use mpi_gbl, only: myrank, mpiint, mpi_mod_allgather, mpi_mod_rotate_cfp_arrays_around_ring, &
40 mpi_mod_rotate_int_arrays_around_ring, mpi_xermsg, mpi_reduceall_max
41 use precisn, only: longint, wp
42 use memorymanager_module, only: master_memory
43 use parallelization_module, only: grid => process_grid
44 use symbolic_module, only: symbolicelementvector
45 use timing_module, only: master_timer
46 use utility_module, only: lexicographical_compare, pack_ints, unpack_ints
47
48 implicit none
49
50 public contractedsymbolicelementvector
51
52 private
53
54 !> \brief This class handles the storage symbolic elements
55 !> \authors A Al-Refaie
56 !> \date 2017
57 !>
58 !> This class handles the storage symbolic elements and also expands the vector size if we have reached max capacity
59 !> Additionaly, uses a binary search tree to perform a binary search on integrals labels during insertion to ensure no
60 !> repeating elements this is automatic and removes the compression stage in the original SCATCI code.
61 !>
62 type, extends(bstree) :: contractedsymbolicelementvector
63 private
64
65 integer(longint), allocatable :: electron_integral(:,:) !< The packed integral storage
66 real(wp), allocatable :: coeffs(:,:,:) !< The coefficients of the integral
67
68 integer :: n = 0 !< Number of elements in the array of both the integral and coefficients
69 logical :: constructed = .false. !< Whether this class has been constructed
70 real(wp) :: threshold = 0.0 !< The integral threshold
71 integer :: num_states_1 = 0
72 integer :: num_states_2 = 0
73 integer :: max_capacity = 0 !< The number of free slots in the array
74 integer :: expand_size = 100 !< How much we have to expand each
75 contains
76 ! type-bound procedures used by the bstree interface
77 procedure, public :: compare => bstree_compare
78
79 ! own type-bound procedures
80 procedure, public :: construct
81 procedure, public :: insert_ijklm_symbol
82 procedure, public :: insert_symbol
83 procedure, public :: remove_symbol_at
84 procedure, public :: is_empty
85 procedure, public :: clear
86 procedure, public :: check_same_integral
87 procedure, public :: get_integral_label
88 procedure, public :: synchronize_symbols
89 procedure, public :: estimate_synchronize_cost
90 procedure, public :: modify_coeff
91 procedure, public :: get_coefficient
92 procedure, public :: get_coeff_and_integral
93 procedure, public :: get_size
94 procedure, public :: get_num_targets_sym1
95 procedure, public :: get_num_targets_sym2
96 procedure, public :: add_symbols
97 procedure, public :: reduce_symbols
98 procedure, public :: print => print_symbols
99 !procedure, public :: prune_threshold
100 !procedure, public :: sort_symbols
101 procedure, private :: expand_array
102 procedure, private :: check_bounds
103 procedure, public :: destroy
104 procedure, private :: check_constructed
105 procedure, private :: synchronize_symbols_ii
106 !procedure, public :: count_occurance
107 !procedure, public :: construct
108 end type contractedsymbolicelementvector
109
110 class(contractedsymbolicelementvector), pointer :: to_be_synched
111
112contains
113
114 !> \brief Compare two integral index sets
115 !> \authors J Benda
116 !> \date 2019
117 !>
118 !> This is the predicate (order-defining function) used by the binary search tree. Given two pointers into the
119 !> electron integral array, it returns 0 when the corresponding integral index sets are equal, -1 when the
120 !> first one is (lexicographically) less, and +1 when the first one is (lexicographically) greater.
121 !>
122 !> When either of the indices is non-positive, the dummy value stored in the dummy argument `data` is used instead of
123 !> the corresponding index set.
124 !>
125 !> \param[in] this Symbolic vector containing the reference electron_integral storage.
126 !> \param[in] i Position of the first integral index set.
127 !> \param[in] j Position of the first integral index set.
128 !> \param[in] data Integral index set to which compare the set being processed.
129 !>
130 !> \returns -1/0/+1 as a lexicographical spaceship operator applied on the index sets.
131 !>
132 integer function bstree_compare (this, i, j, data) result (verdict)
133
134 class(contractedsymbolicelementvector), intent(in) :: this
135 integer, intent(in) :: i, j
136 type(c_ptr), optional, intent(in) :: data
137
138 integer(longint) :: ii(nidx), jj(nidx)
139 integer(longint), pointer :: kk(:)
140
141 ! get the default index set to compare with (if provided)
142 if (present(data)) call c_f_pointer(data, kk, (/ nidx /))
143
144 ! obtain pointers to the index sets
145 if (i <= 0) then; ii = kk; else; ii = this % electron_integral(:,i); end if
146 if (j <= 0) then; jj = kk; else; jj = this % electron_integral(:,j); end if
147
148 ! compare the index sets using lexicographical comparison
149 verdict = lexicographical_compare(ii, jj)
150
151 end function bstree_compare
152
153
154 !> \brief A simple class to check if this has been properly constructed
155 !> \authors A Al-Refaie
156 !> \date 2017
157 !>
158 subroutine check_constructed (this)
159 class(contractedsymbolicelementvector) :: this
160 if (.not. this % constructed) then
161 write (stdout, "('Vector::constructed - Vector is not constructed')")
162 stop "Vector::constructed - Vector is not constructed"
163 end if
164
165 end subroutine check_constructed
166
167
168 !> \brief Constructs the class by allocating space for the electron integrals.
169 !> \authors A Al-Refaie
170 !> \date 2017
171 !>
172 !> \param[inout] this Vector object to update.
173 !> \param[in] n1 Number of states 1.
174 !> \param[in] n2 Number of states 2.
175 !> \param[in] threshold The mininum integral coefficient threshold we should store
176 !> \param[in] initial_size Deprecated, doesnt do anything
177 !>
178 subroutine construct (this, n1, n2, threshold, initial_size)
179 class(contractedsymbolicelementvector) :: this
180 real(wp), optional, intent(in) :: threshold
181 integer, optional, intent(in) :: initial_size
182
183 integer :: err, n1, n2
184
185 if (present(threshold)) then
186 this % threshold = threshold
187 else
188 this % threshold = default_integral_threshold
189 end if
190
191 this % expand_size = 100
192 this % max_capacity = this % expand_size
193 this % num_states_1 = n1
194 this % num_states_2 = n2
195
196 !Allocate the vectors
197 allocate(this % electron_integral(nidx, this % max_capacity), this % coeffs(n1, n2, this % max_capacity), stat = err)
198 call master_memory % track_memory (storage_size(this % electron_integral)/8, &
199 size(this % electron_integral), err, 'CONSYMBOLIC::ELECTRONINT')
200 call master_memory % track_memory(storage_size(this % coeffs)/8, &
201 size(this % coeffs), err, 'CONSYMBOLIC::ELECTRONCOEFF')
202 if (err /= 0) then
203 call mpi_xermsg('Contracted_Symbolic_module', 'construct', 'SymbolicVector arrays not allocated', 1, 1)
204 end if
205
206 !Do an intial clear
207 call this % clear
208
209 !This has been succesfully constructed
210 this % constructed = .true.
211
212 end subroutine construct
213
214
215 !> \brief A function to check whether the same integral label exists
216 !> \authors A Al-Refaie
217 !> \date 2017
218 !>
219 !> \param[inout] this Vector object to query.
220 !> \param[in] integral Packed integral label
221 !> \param[out] idx The index to the electron integral array, -1 if not found, positive otherwise
222 !>
223 !> \result check_same_integral True: we found one the same one. False: there isn't one
224 !>
225 logical function check_same_integral (this, integral, idx) result (found)
226
227 class(contractedsymbolicelementvector), intent(in) :: this
228 integer(longint), target, intent(in) :: integral(nidx)
229 integer, intent(out) :: idx
230
231 call this % check_constructed
232
233 idx = this % locate(-1, c_loc(integral))
234 found = idx > 0
235
236 end function check_same_integral
237
238
239 !> \brief Insert unpacked integral labels.
240 !> \authors A Al-Refaie
241 !> \date 2017
242 !>
243 !> Wraps insert_symbol by automatically packing.
244 !>
245 !> \param[inout] this Vector object to update.
246 !> \param[in] i,j,k,l The integral labels
247 !> \param[in] m Positron label
248 !> \param[in] coeffs The integral coefficient
249 !> \param[in] check_same_ Deprecated, orginally used to debug but now does nothing
250 !>
251 subroutine insert_ijklm_symbol (this, i, j, k, l, m, coeffs, check_same_)
252 class(contractedsymbolicelementvector) :: this
253 integer, intent(in) :: i, j, k, l, m
254 real(wp), intent(in) :: coeffs(this % num_states_1, this % num_states_2)
255 logical, intent(in), optional :: check_same_
256
257 integer(longint) :: integral_label(NIDX)
258 logical :: check_same
259
260 if (present(check_same_)) then
261 check_same = check_same_
262 else
263 check_same = .true.
264 end if
265
266 call pack_ints(i, j, k, l, m, 0, 0, 0, integral_label)
267 call this%insert_symbol(integral_label, coeffs, check_same)
268
269 end subroutine insert_ijklm_symbol
270
271
272 !> \brief Insert a packed integral symbol into the class
273 !> \authors A Al-Refaie
274 !> \date 2017
275 !>
276 !> This subroutine is used to insert the integral into the class, it performs a check to see if it exists, if not then
277 !> it will insert (and expand if needed) into the integral array. Otherwise it will simply add the coefficients
278 !> to found integral index.
279 !>
280 !> \param[inout] this Vector object to update.
281 !> \param[in] integral_label Packed integral label
282 !> \param[in] coeffs The integral coefficient
283 !> \param[in] check_same_ Deprecated, orginally used to debug but now does nothing
284 !>
285 subroutine insert_symbol (this, integral_label, coeffs, check_same_)
286 class(contractedsymbolicelementvector) :: this
287 integer(longint), intent(in) :: integral_label(NIDX)
288 real(wp), intent(in) :: coeffs(this % num_states_1, this % num_states_2)
289 logical, intent(in), optional :: check_same_
290
291 integer :: idx = 0, check_idx
292 logical :: check_same
293
294 if (present(check_same_)) then
295 check_same = check_same_
296 else
297 check_same = .true.
298 end if
299
300 ! Filter small coefficients
301 !if(abs(coeff) < this%threshold) return
302
303 if (.not. this % check_same_integral(integral_label, idx)) then
304 !If not then update number of elements
305 this % n = this % n + 1
306 !The idx is the last element
307 idx = this % n
308 !If we've exceeded capacity then expand
309 if (this % n > this % max_capacity) then
310 call this % expand_array()
311 end if
312 !Place into the array
313 this % electron_integral(:,idx) = integral_label(:)
314 !Zero the coefficient since we can guareentee the compiler will do so
315 this % coeffs(:,:,idx) = 0.0_wp
316 !Insert it into the binary tree
317 call this % insert(idx)
318 end if
319
320 !Now we have an index, lets add in the coeffcient
321 this % coeffs(:,:,idx) = this % coeffs(:,:,idx) + coeffs(:,:)
322
323 end subroutine insert_symbol
324
325
326 !> \brief This is the array expansion subroutine.
327 !> \authors A Al-Refaie
328 !> \date 2017
329 !>
330 !> It simply copies the coeffcieint and integral array into a temporary one, reallocates a new array increased
331 !> by expand_size and then recopies the elements and updates max capacity.
332 !>
333 subroutine expand_array (this)
334 class(contractedsymbolicelementvector) :: this
335 integer(longint), allocatable :: temp_integral(:,:)
336 real(wp), allocatable :: temp_coeffs(:,:,:)
337 integer :: temp_capacity, ido, err
338
339 !write(stdout,"('Size of arrays = ',5i12)") this%max_capacity,this%num_states_1,this%num_states_2,size(this%electron_integral),size(this%coeffs)
340
341 !Of course lets check if we are constructed
342 call this % check_constructed
343
344 !Now the tempcapacity is the current max capacity
345 temp_capacity = this % max_capacity
346
347 allocate(temp_integral(nidx, this % max_capacity), &
348 temp_coeffs(this % num_states_1, this % num_states_2, this % max_capacity), stat = err)
349 call master_memory % track_memory(storage_size(temp_integral)/8, size(temp_integral), err, 'CONSYMBOLIC::EXP::TEMPINT')
350 call master_memory % track_memory(storage_size(temp_coeffs)/8, size(temp_coeffs), err, 'CONSYMBOLIC::EXP::TEMPCOEFF')
351
352 !Copy over the elements into the temporary array
353 do ido = 1, temp_capacity
354 temp_integral(:,ido) = this % electron_integral(:,ido)
355 temp_coeffs(:,:,ido) = this % coeffs(:,:,ido)
356 end do
357
358 call master_memory % free_memory(storage_size(this % electron_integral)/8, size(this % electron_integral))
359 call master_memory % free_memory(storage_size(this % coeffs)/8, size(this % coeffs))
360
361 !deallocate our old values
362 deallocate(this % electron_integral)
363 deallocate(this % coeffs)
364
365 !Increase the max capacity
366 this % max_capacity = this % max_capacity + this % expand_size
367
368 !Allocate our new array with the new max capacity
369 allocate(this % electron_integral(nidx, this % max_capacity), &
370 this % coeffs(this % num_states_1, this % num_states_2, this % max_capacity), stat = err)
371 call master_memory % track_memory (storage_size(this % electron_integral)/8, &
372 size(this % electron_integral), err,'CONSYMBOLIC::EXP::ELECTRONINT_EXP')
373 call master_memory % track_memory(storage_size(this % coeffs)/8, &
374 size(this % coeffs), err, 'CONSYMBOLIC::EXP::ELECTRONCOEFF_EXP')
375 !Zero the elements
376 this % electron_integral = -1
377 this % coeffs = 0.0_wp
378
379 do ido = 1, temp_capacity
380 !Copy our old values back
381 this % electron_integral(:,ido) = temp_integral(:,ido)
382 this % coeffs(:,:,ido) = temp_coeffs(:,:,ido)
383 end do
384
385 call master_memory % free_memory(storage_size(temp_integral)/8, size(temp_integral))
386 call master_memory % free_memory(storage_size(temp_coeffs)/8, size(temp_coeffs))
387
388 deallocate(temp_integral, temp_coeffs)
389
390 end subroutine expand_array
391
392
393 !> \brief Inserts one symbolic vector into another scaled by
394 !> \authors A Al-Refaie
395 !> \date 2017
396 !>
397 !> \param[inout] this Vector object to update.
398 !> \param[in] rhs The symbolic vector to add into this class
399 !> \param[in] alpha The scaling value to be applied to each coefficient
400 !>
401 subroutine add_symbols (this, rhs, alpha)
402 class(contractedsymbolicelementvector) :: this
403 class(symbolicelementvector), intent(in) :: rhs
404 real(wp) :: alpha(this % num_states_1, this % num_states_2), int_coeff
405 real(wp) :: coeffs(this % num_states_1, this % num_states_2)
406 integer :: ido
407 integer(longint) :: label(NIDX)
408
409 coeffs = 0._wp
410
411 !Loop through each rhs symbolic and add it to me scaled by alpha
412 do ido = 1, rhs % get_size()
413 call rhs % get_coeff_and_integral(ido, int_coeff, label)
414 coeffs = int_coeff * alpha
415 call this % insert_symbol(label, coeffs)
416 end do
417
418 end subroutine add_symbols
419
420
421 subroutine reduce_symbols (this, rhs)
422 class(contractedsymbolicelementvector) :: this
423 class(contractedsymbolicelementvector), intent(in) :: rhs
424 integer :: ido
425
426 !Loop through each rhs symbolic and add it to me scaled by alpha
427 do ido = 1, rhs % get_size()
428 call this % insert_symbol(rhs % electron_integral(:,ido), rhs % coeffs(:,:,ido))
429 end do
430
431 end subroutine reduce_symbols
432
433
434 subroutine synchronize_symbols (this)
435 class(contractedsymbolicelementvector) :: this
436
437 integer :: my_num_symbols, largest_num_symbols, ierr
438 integer :: ido, proc_id, jdo
439
440 integer(longint), allocatable, target :: labels(:,:)
441 integer(longint), pointer :: label_ptr(:)
442 integer(longint) :: procs_num_of_symbols_int, procs_num_of_symbols_coeff, size_labels, size_coeffs
443
444 real(wp), allocatable, target :: coeffs(:,:,:)
445 real(wp), pointer :: coeffs_ptr(:)
446
447 if (grid % gprocs <= 1) then
448 return
449 end if
450
451 call master_timer % start_timer("Symbol Synchronize")
452
453 my_num_symbols = this % get_size()
454 call mpi_reduceall_max(my_num_symbols, largest_num_symbols, grid % lcomm)
455
456 if (largest_num_symbols == 0) then
457 call master_timer % stop_timer("Symbol Synchronize")
458 return
459 end if
460
461 call master_memory % track_memory (storage_size(labels)/8, largest_num_symbols * nidx, 0, 'CONSYMBOLIC::MPISYNCH::LABELS')
462 call master_memory % track_memory (storage_size(coeffs)/8, largest_num_symbols * this % num_states_1 * this % num_states_2,&
463 0, 'CONSYMBOLIC::MPISYNCH::COEFFS')
464
465 allocate(labels(nidx, largest_num_symbols), &
466 coeffs(this % num_states_1, this % num_states_2, largest_num_symbols), &
467 stat = ierr)
468
469 size_labels = size(labels, kind = longint)
470 size_coeffs = size(coeffs, kind = longint)
471
472 label_ptr(1:size_labels) => labels(:,:)
473 coeffs_ptr(1:size_coeffs) => coeffs(:,:,:)
474
475 labels = 0
476 coeffs = 0
477
478 if (my_num_symbols > 0) then
479 labels(:,1:my_num_symbols) = this % electron_integral(:,1:my_num_symbols)
480 do ido = 1, my_num_symbols
481 coeffs(1:this%num_states_1,1:this%num_states_2,ido) = this % coeffs(1:this%num_states_1,1:this%num_states_2,ido)
482 end do
483 end if
484
485 procs_num_of_symbols_int = my_num_symbols * nidx
486 procs_num_of_symbols_coeff = my_num_symbols * this % num_states_1 * this % num_states_2
487 do proc_id = 1, grid % lprocs - 1
488 call mpi_mod_rotate_int_arrays_around_ring(procs_num_of_symbols_int, label_ptr, size_labels, grid % lcomm)
489 call mpi_mod_rotate_cfp_arrays_around_ring(procs_num_of_symbols_coeff, coeffs_ptr, size_coeffs, grid % lcomm)
490
491 do ido = 1, procs_num_of_symbols_int / nidx
492 call this % insert_symbol(labels(:,ido), coeffs(1:this%num_states_1,1:this%num_states_2,ido))
493 end do
494 end do
495
496 call master_timer % stop_timer("Symbol Synchronize")
497 call master_memory % free_memory(storage_size(labels)/8, size(labels))
498 call master_memory % free_memory(storage_size(coeffs)/8, size(coeffs))
499
500 deallocate(labels, coeffs)
501
502 end subroutine synchronize_symbols
503
504
505 subroutine synchronize_symbols_ii (this)
506 class(contractedsymbolicelementvector), target :: this
507
508 integer(longint), allocatable, target :: labels(:,:)
509 integer(longint), pointer :: label_ptr(:)
510
511 real(wp), allocatable, target :: coeffs(:,:,:)
512 real(wp), pointer :: coeffs_ptr(:)
513
514 integer :: my_num_symbols, largest_num_symbols, procs_num_of_symbols_int, procs_num_of_symbols_coeff, ido, proc_id, jdo
515 integer :: ierr, local_communicator, global_communicator, odd_even
516
517 integer(kind=mpiint) :: master_comm, global_rank, global_nprocs, error, proc, tag = 1
518
519 if (grid % gprocs <= 1) then
520 return
521 end if
522
523 end subroutine synchronize_symbols_ii
524
525
526 !> \brief Simply checks the index and wheter it exists within the array
527 !> \authors A Al-Refaie
528 !> \date 2017
529 !>
530 !> \param[inout] this Vector object to update.
531 !> \param[in] i The index we wish to access.
532 !>
533 logical function check_bounds (this, i)
534 class(contractedsymbolicelementvector) :: this
535 integer, intent(in) :: i
536
537 if (i <= 0 .or. i > this % n) then
538 write (stdout, "('SymbolicVector::check_bounds - Out of Bounds access')")
539 stop "SymbolicVector::check_bounds - Out of Bounds access"
540 check_bounds = .false.
541 else
542 check_bounds = .true.
543 end if
544
545 end function check_bounds
546
547
548 !> \brief Removes an integral and coefficient, never been used and pretty much useless.
549 !> \authors A Al-Refaie
550 !> \date 2017
551 !>
552 subroutine remove_symbol_at (this, idx)
553 class(contractedsymbolicelementvector) :: this
554 integer, intent(in) :: idx
555 integer :: ido
556
557 if (this % check_bounds(idx)) then
558 do ido = idx + 1, this % n
559 this % electron_integral(:, ido - 1) = this % electron_integral(:, ido)
560 !this%coeffs(ido-1) = this%coeffs(ido)
561 end do
562 this % electron_integral(:, this % n) = 0
563 !this % coeffs(this % n) = 0
564 this % n = this % n - 1
565 end if
566
567 end subroutine remove_symbol_at
568
569
570 !> @brief Simply returns whether we are storing integrals and coeffs or not
571 !> \authors A Al-Refaie
572 !> \date 2017
573 !>
574 !> \result True if empty or False if we have any symbols
575 !>
576 logical function is_empty (this)
577
578 class(contractedsymbolicelementvector) :: this
579
580 is_empty = (this % n == 0)
581
582 end function is_empty
583
584
585 !> \brief Clear our array (not really but it essentialy resets the symbol counter to zero which is way quicker).
586 !> \authors A Al-Refaie
587 !> \date 2017
588 !>
589 subroutine clear (this)
590
591 class(contractedsymbolicelementvector) :: this
592
593 this % n = 0
594 call this % bstree % destroy
595
596 end subroutine clear
597
598
599 subroutine modify_coeff (this, idx, coeff)
600 class(contractedsymbolicelementvector) :: this
601 integer, intent(in) :: idx
602 real(wp) :: coeff
603 !this%coeffs(idx) = this%coeffs(idx)+ coeff
604 end subroutine modify_coeff
605
606
607 !> @brief Get integral label at specific index
608 !> \authors A Al-Refaie
609 !> \date 2017
610 !>
611 function get_integral_label (this, idx)
612 class(contractedsymbolicelementvector) :: this
613 integer, intent(in) :: idx
614 integer(longint) :: get_integral_label(nidx)
615
616 if (this % check_bounds(idx)) get_integral_label(:) = this % electron_integral(:,idx)
617
618 end function get_integral_label
619
620
621 !> \brief Get coefficient at specific index
622 !> \authors A Al-Refaie
623 !> \date 2017
624 !>
625 real(wp) function get_coefficient(this, idx, n1, n2)
626 class(contractedsymbolicelementvector) :: this
627 integer, intent(in) :: idx, n1, n2
628
629 !if(this%check_bounds(idx)==.true.) get_coefficient=this%coeffs(idx)
630 get_coefficient = this % coeffs(n1, n2, idx)
631
632 end function get_coefficient
633
634
635 !> \brief Get both label and coeffcient at specific index
636 !> \authors A Al-Refaie
637 !> \date 2017
638 !>
639 subroutine get_coeff_and_integral (this, idx, coeff, label)
640 class(contractedsymbolicelementvector), intent(in) :: this
641 integer, intent(in) :: idx
642 real(wp), intent(out) :: coeff(this % num_states_1, this % num_states_2)
643 integer(longint), intent(out) :: label(:)
644
645 if (this % check_bounds(idx)) then
646 label = this % electron_integral(:,idx)
647 coeff = this % coeffs(:,:,idx)
648 end if
649
650 end subroutine get_coeff_and_integral
651
652
653 !> \brief Returns the number of symbolic elements stored
654 !> \authors A Al-Refaie
655 !> \date 2017
656 !>
657 integer function get_size (this)
658 class(contractedsymbolicelementvector) :: this
659 get_size = this % n
660 end function get_size
661
662
663 integer function get_num_targets_sym1 (this)
664 class(contractedsymbolicelementvector) :: this
665 get_num_targets_sym1 = this % num_states_1
666 end function get_num_targets_sym1
667
668
669 integer function get_num_targets_sym2 (this)
670 class(contractedsymbolicelementvector) :: this
671 get_num_targets_sym2 = this % num_states_2
672 end function get_num_targets_sym2
673
674
675 !> \brief Cleans up the class by deallocating arrays
676 !> \authors A Al-Refaie
677 !> \date 2017
678 !>
679 subroutine destroy (this)
680 class(contractedsymbolicelementvector) :: this
681
682 if (allocated(this % electron_integral)) then
683 call master_memory % free_memory(storage_size(this % electron_integral)/8, size(this % electron_integral))
684 deallocate(this % electron_integral)
685 end if
686 if(allocated(this % coeffs)) then
687 call master_memory % free_memory(storage_size(this % coeffs)/8, size(this % coeffs))
688 deallocate(this % coeffs)
689 end if
690
691 call this % bstree % destroy
692
693 this % constructed = .false.
694
695 end subroutine destroy
696
697
698 !> \brief Print currently stored symbols
699 !> \authors A Al-Refaie
700 !> \date 2017
701 !>
702 subroutine print_symbols (this)
703 class(contractedsymbolicelementvector) :: this
704 integer :: labels(8), ido
705 real(wp) :: coeff
706
707 if (.not. this % is_empty()) write (stdout, "('Outputting symbolic elements....')")
708
709 do ido = 1, this % n
710 call unpack_ints(this % electron_integral(:,ido), labels)
711 write (1923 + myrank, "(5i4,' -- ',5es14.3)") labels(1:5), this % coeffs(:,:,ido)
712 end do
713
714 end subroutine print_symbols
715
716
717 logical function estimate_synchronize_cost (this)
718 class(contractedsymbolicelementvector) :: this
719 integer(longint) :: memory_cost
720 integer :: my_num_symbols, largest_num_symbols
721 integer :: gathered_bool, global_bool(grid % gprocs)
722
723 if (grid % gprocs <= 1) then
724 estimate_synchronize_cost = .true.
725 return
726 end if
727
728 my_num_symbols = this % get_size()
729 gathered_bool = 0
730 estimate_synchronize_cost = .true.
731
732 call mpi_reduceall_max(my_num_symbols, largest_num_symbols, grid % gcomm)
733
734 memory_cost = 2 * largest_num_symbols * (2 + this % num_states_1 * this % num_states_2) * 8
735
736 if (memory_cost >= master_memory % get_scaled_available_memory(0.75_wp)) gathered_bool = 1
737
738 global_bool = 0
739
740 call mpi_mod_allgather(gathered_bool, global_bool, grid % gcomm)
741
742 if (sum(global_bool) /= 0) then
743 estimate_synchronize_cost = .false.
744 end if
745
746 end function estimate_synchronize_cost
747
748end module contracted_symbolic_module
MPI SCATCI Constants module.
integer, parameter nidx
Number of long integers used to store up to 8 (packed) integral indices.
real(wp), parameter default_integral_threshold
Default threshold to store integrals.