MPI-SCATCI 2.0
An MPI version of SCATCI
Loading...
Searching...
No Matches
Orbital_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 construction of the spin orbital table and of generating symbolic elements from determinants
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 orbital_module
32
33 use const_gbl, only: stdout
35 use mpi_gbl, only: mpi_xermsg
36 use precisn, only: wp
37 use scatci_routines, only: mkorbs, pmkorbs
38 use symbolic_module, only: symbolicelementvector
39
40 implicit none
41
42 private
43
44 public spinorbital, orbitaltable
45
46 !> \brief This type holds a single spin orbital
47 !> \authors A Al-Refaie
48 !> \date 2017
49 !>
50 !> Basic building block of \ref OrbitalTable.
51 !>
52 type :: spinorbital
53 integer :: orbital_number !< MN
54 integer :: gerude !< MG
55 integer :: m_quanta !< MM
56 integer :: spin !< MS
57 integer :: positron_flag !< MPOS
58 integer :: electron_idx !< Electron number for the references
59 end type spinorbital
60
61
62 !> \brief This class generates the molecular and spin orbitals, stores them and generates symblic elements from determinants
63 !> \authors A Al-Refaie
64 !> \date 2017
65 !>
66 !> Consists of an array of objects \ref SpinOrbital. Provides access functions for retrieval of properties
67 !> of individual orbitals.
68 !>
69 type :: orbitaltable
70 logical :: initialized = .false. !< Whether the class has been initialized
71 integer :: total_num_spin_orbitals !< The total number of spin orbitals
72 integer :: total_num_orbitals !< The total number of molecular orbitals
73 integer :: symmetry_type !< Which symmetry group we are dealing with
74 integer :: num_symmetries !< How many symmetries we have
75 integer :: positron_flag !< Whether we have exotic matter
76 integer :: mflg = 0
77 integer, allocatable :: mcorb(:), mcon(:), nsrb(:) !< MCORB - Orbital mapping?
78 type(spinorbital), allocatable :: spin_orbitals(:) !< Our table of spin orbitals
79 integer, allocatable :: orbital_map(:) !< Mapping of determinants to spin orbitals
80 contains
81 procedure, public :: initialize => initialize_table
82 procedure, public :: construct => construct_table
83 procedure, public :: get_orbital_number
84 procedure, public :: get_spin
85 procedure, public :: get_gerude
86 procedure, public :: get_electron_number
87 procedure, public :: compute_electron_index
88 procedure, public :: check_max_mcon_in_determinants
89 procedure, public :: evaluate_ijkl_and_coeffs
90 procedure, public :: get_mcon
91 procedure, public :: get_minimum_mcon
92 procedure, public :: get_two_minimum_mcon
93 procedure, public :: add_positron
94 procedure, private :: evaluate_case_one
95 procedure, private :: evaluate_case_two
96 procedure, private :: evaluate_case_three
97 procedure, private :: evaluate_case_other
98 end type orbitaltable
99
100contains
101
102 !> \brief Basic initialization of the data structure
103 !> \authors A Al-Refaie
104 !> \date 2017
105 !>
106 !> Stores given arguments and allocates memory for all spin-orbitals.
107 !>
108 !> \param[inout] this Orbital object to update.
109 !> \param[in] nsrb Number of spin-orbitals.
110 !> \param[in] norb Number of orbitals.
111 !> \param[in] symtype Symmetry type (group class). Expects named constant from \ref consts_mpi_ci.
112 !> \param[in] nsym Number of symmetries (irreducible representations).
113 !> \param[in] positron_flag Non-zero value indicates positron.
114 !>
115 subroutine initialize_table (this, nsrb, norb, symtype, nsym, positron_flag)
116 class(orbitaltable), intent(inout) :: this
117 integer, intent(in) :: nsrb, nsym, norb, symtype, positron_flag
118
119 this % total_num_spin_orbitals = nsrb
120 this % total_num_orbitals = norb
121 this % symmetry_type = symtype
122 this % num_symmetries = nsym
123 this % positron_flag = positron_flag
124
125 if (allocated(this % spin_orbitals)) deallocate (this % spin_orbitals)
126 if (allocated(this % mcon)) deallocate (this % mcon)
127 if (allocated(this % nsrb)) deallocate (this % nsrb)
128 if (allocated(this % mcorb)) deallocate (this % mcorb)
129 if (allocated(this % orbital_map)) deallocate (this % orbital_map)
130
131 allocate(this % spin_orbitals(this % total_num_spin_orbitals))
132 allocate(this % mcon(this % total_num_spin_orbitals))
133 allocate(this % nsrb(this % total_num_spin_orbitals))
134 allocate(this % mcorb(this % total_num_orbitals))
135 allocate(this % orbital_map(this % total_num_orbitals))
136
137 this % mcorb(:) = 0
138
139 end subroutine initialize_table
140
141
142 !> \brief Define all spin-orbitals
143 !> \authors A Al-Refaie
144 !> \date 2017
145 !>
146 !> Assumes that \ref initialize_table has been called before.
147 !>
148 !> Sets all attributes of the individual spin-orbital data structures. This is actually a simple
149 !> wrapper around the original SCATCI subroutines MKORBS and PMKORBS,
150 !> where the construction of the spin-orbitals is carried out.
151 !>
152 !> On exit from this subroutine, all spin-orbitals contained in this type have correctly defined attributes
153 !> (quantum numbers).
154 !>
155 subroutine construct_table (this, num_orbital_target_sym, num_orbital_target_sym_dinf, &
156 num_orbitals, num_elec_orbitals, num_orbitals_congen)
157 class(orbitaltable), intent(inout) :: this
158 integer, intent(in) :: num_orbital_target_sym(this % num_symmetries), &
159 num_orbital_target_sym_dinf(this % num_symmetries), &
160 num_orbitals(this % num_symmetries), &
161 num_elec_orbitals(this % num_symmetries), &
162 num_orbitals_congen(this % num_symmetries)
163
164 integer :: MN(this % total_num_spin_orbitals), MG(this % total_num_spin_orbitals), &
165 MM(this % total_num_spin_orbitals), MS(this % total_num_spin_orbitals), MPOS(this % total_num_spin_orbitals)
166 integer :: dummy_iposit = 0, dummy_lusme = 0, ido
167
168 if (this % positron_flag /= 0 .and. this % symmetry_type == symtype_d2h) then
169 call pmkorbs(num_orbitals, num_elec_orbitals, num_orbitals_congen, this % num_symmetries, &
170 mn, mg, mm, ms, this % mcon, this % mcorb, this % total_num_orbitals, &
171 this % total_num_spin_orbitals, this % orbital_map, mpos, this % positron_flag, &
172 this % symmetry_type, dummy_lusme, stdout)
173 else
174 call mkorbs(this % num_symmetries, mn, mg, mm, ms, this % total_num_orbitals, &
175 this % total_num_spin_orbitals, this % orbital_map, mpos, this % mcon, &
176 this % mcorb, this % positron_flag, num_orbital_target_sym, &
177 num_orbital_target_sym_dinf, this % symmetry_type, dummy_lusme, stdout)
178 end if
179
180 do ido = 1, this % total_num_spin_orbitals
181 this % spin_orbitals(ido) % orbital_number = mn(ido)
182 this % spin_orbitals(ido) % gerude = mg(ido)
183 this % spin_orbitals(ido) % m_quanta = mm(ido)
184 this % spin_orbitals(ido) % spin = ms(ido)
185 this % spin_orbitals(ido) % positron_flag = mpos(ido)
186 this % spin_orbitals(ido) % electron_idx = 0
187 end do
188
189 end subroutine construct_table
190
191
192 !> \brief Assign electrons to reference spin-orbitals
193 !> \authors A Al-Refaie
194 !> \date 2017
195 !>
196 !> Assign consecutive electron index to all stored spin-orbitals of the reference determinant.
197 !>
198 subroutine compute_electron_index (this, num_electrons, reference_determinants)
199 class(orbitaltable), intent(inout) :: this
200 integer, intent(in) :: num_electrons
201 integer, intent(in) :: reference_determinants(num_electrons)
202
203 integer :: ido
204
205 do ido = 1, num_electrons
206 this % spin_orbitals(reference_determinants(ido)) % electron_idx = ido
207 end do
208
209 end subroutine compute_electron_index
210
211
212 integer function check_max_mcon_in_determinants (this, n, determinants)
213 class(orbitaltable), intent(inout) :: this
214 integer, intent(in) :: determinants(:), n
215
216 integer :: i
217
218 check_max_mcon_in_determinants = 0
219 do i = 1, n
220 check_max_mcon_in_determinants = max(check_max_mcon_in_determinants, this % mcon(determinants(i)))
221 end do
222
223 end function check_max_mcon_in_determinants
224
225
226 !> \brief This compares the determinants and generates the proper coefficents and ijklm values needed for the symbols
227 !>
228 subroutine evaluate_ijkl_and_coeffs (this, dtrs, coeff, symmetry_type, symbol, flag)
229 class(orbitaltable), intent(inout) :: this
230 integer, intent(in) :: dtrs(4), symmetry_type, flag
231 real(wp), intent(in) :: coeff
232 class(symbolicelementvector) :: symbol
233
234 type(spinorbital) :: P,R !Determinants A
235 type(spinorbital) :: Q,S !Determinants B
236 integer :: KA, KB, lpositron = 0
237 integer :: NSFA, NSFB, MLA, MLB !I'm not 100% what these do alpha/beta?
238 real(wp) :: SIGN
239
240 if (this % positron_flag /= 0) lpositron = this % add_positron(dtrs, 1, 4)
241
242 !Get our spin orbitals
243 p = this % spin_orbitals(dtrs(1))
244 q = this % spin_orbitals(dtrs(2))
245 r = this % spin_orbitals(dtrs(3))
246 s = this % spin_orbitals(dtrs(4))
247
248 !If there are opposing spins
249 if(p % spin + q % spin == 1 .or. r % spin + s % spin == 1 .or. p % positron_flag /= q % positron_flag) then
250 nsfa = 0
251 else
252 nsfa = 1
253 mla = 0
254 if (symmetry_type < symtype_d2h) then
255 ka = max(dtrs(1), dtrs(2))
256 kb = max(dtrs(3), dtrs(4))
257 if (ka < kb) then
258 if (r % m_quanta * s % m_quanta < 0) mla = 1
259 else
260 if(p % m_quanta * q % m_quanta < 0) mla = 1
261 end if
262 end if
263 end if
264
265 !If there are opposing spins or if there is a single positron
266 if (p % spin + s % spin == 1 .or. q % spin + r % spin == 1 .or. p % positron_flag /= s % positron_flag) then
267 nsfb = 0
268 else
269 nsfb = 1
270 mlb = 0
271 if (symmetry_type < symtype_d2h) then
272 ka = max(dtrs(1), dtrs(4))
273 kb = max(dtrs(3), dtrs(2))
274 if (ka < kb) then
275 if (q % m_quanta * r % m_quanta < 0) mlb = 1
276 else
277 if (p % m_quanta * s % m_quanta < 0) mlb = 1
278 end if
279 end if
280 end if
281
282 !No exchange so ignore
283 if (nsfa == 0 .and. nsfb == 0) return
284
285 sign = 1_wp
286 if (lpositron == 1) sign = -1_wp
287
288 if (flag == 1) then
289 if (nsfa /= 0) then
290 call this % evaluate_case_other(p % orbital_number, q % orbital_number, r % orbital_number, &
291 s % orbital_number, mla, 0, sign * coeff, symbol)
292 end if
293 if (nsfb /= 0) then
294 call this % evaluate_case_other(p % orbital_number, s % orbital_number, r % orbital_number, &
295 q % orbital_number, mlb, 1, sign * coeff, symbol)
296 end if
297 else if (p % orbital_number == q % orbital_number .and. r % orbital_number == s % orbital_number) then
298
299 call this % evaluate_case_one(p % orbital_number, r % orbital_number, nsfa, nsfb, mla, mlb, sign * coeff, symbol)
300
301 else if (p % orbital_number == q % orbital_number .or. r % orbital_number == s % orbital_number) then
302 if (nsfa /= 0) then
303 call this % evaluate_case_other(p % orbital_number, q % orbital_number, r % orbital_number, &
304 s % orbital_number, mla, 0, sign * coeff, symbol)
305 end if
306 if (nsfb /= 0) then
307 call this % evaluate_case_other(p % orbital_number, s % orbital_number, r % orbital_number, &
308 q % orbital_number, mlb, 1, sign * coeff, symbol)
309 end if
310 else if (p % orbital_number == r % orbital_number .and. q % orbital_number == s % orbital_number) then
311
312 call this % evaluate_case_three(p % orbital_number, r % orbital_number, nsfa, nsfb, mla, mlb, sign * coeff, symbol)
313
314 else if (p % orbital_number == r % orbital_number) then
315 if (nsfa /= 0) then
316 call this % evaluate_case_other(p % orbital_number, q % orbital_number, r % orbital_number, &
317 s % orbital_number, mla, 0, sign * coeff, symbol)
318 end if
319 if (nsfb /= 0) then
320 call this % evaluate_case_other(p % orbital_number, s % orbital_number, r % orbital_number, &
321 q % orbital_number, mlb, 1, sign * coeff, symbol)
322 end if
323 else if(p % orbital_number == s % orbital_number .and. q % orbital_number == r % orbital_number) then
324
325 call this % evaluate_case_two(p % orbital_number, r % orbital_number, nsfa, nsfb, mla, mlb, sign * coeff, symbol)
326
327 else
328 if (nsfa /= 0) then
329 call this % evaluate_case_other(p % orbital_number, q % orbital_number, r % orbital_number, &
330 s % orbital_number, mla, 0, sign * coeff, symbol)
331 end if
332 if (nsfb /= 0) then
333 call this % evaluate_case_other(p % orbital_number, s % orbital_number, r % orbital_number, &
334 q % orbital_number, mlb, 1, sign * coeff, symbol)
335 end if
336 end if
337
338 end subroutine evaluate_ijkl_and_coeffs
339
340
341 subroutine evaluate_case_one (this, p, r, nsfa, nsfb, mla, mlb, coeff, symbol)
342 class(orbitaltable), intent(inout) :: this
343 integer, intent(in) :: p, r, NSFA, NSFB, MLA, MLB
344 real(wp), intent(in) :: coeff
345 class(symbolicelementvector) :: symbol
346
347 integer :: I, J
348
349 if (p < r) then
350 i = r
351 j = p
352 else
353 i = p
354 j = r
355 end if
356
357 if (nsfa /= 0) then
358 if (mla == 0) then
359 call symbol % insert_ijklm_symbol(i, i, j, j, 1, coeff)
360 else
361 call symbol % insert_ijklm_symbol(i, i, j, j, 0, coeff)
362 end if
363 end if
364
365 if (nsfb /= 0) then
366 if (mlb == 0) then
367 call symbol % insert_ijklm_symbol(i, j, i, j, 1, -coeff)
368 else
369 call symbol % insert_ijklm_symbol(i, j, i, j, 0, -coeff)
370 end if
371 end if
372
373 end subroutine evaluate_case_one
374
375
376 subroutine evaluate_case_two (this, p, q, nsfa, nsfb, mla, mlb, coeff, symbol)
377 class(orbitaltable), intent(inout) :: this
378 integer, intent(in) :: p, q, NSFA, NSFB, MLA, MLB
379 real(wp), intent(in) :: coeff
380 class(symbolicelementvector) :: symbol
381
382 integer :: I, J
383
384 if (p < q) then
385 i = q
386 j = p
387 else
388 i = p
389 j = q
390 end if
391
392 if (nsfa /= 0) then
393 if (mla == 0) then
394 call symbol % insert_ijklm_symbol(i, j, i, j, 1, coeff)
395 else
396 call symbol % insert_ijklm_symbol(i, j, i, j, 0, coeff)
397 end if
398 end if
399
400 if (nsfb /= 0) then
401 if (mlb == 0) then
402 call symbol % insert_ijklm_symbol(i, i, j, j, 1, -coeff)
403 else
404 call symbol % insert_ijklm_symbol(i, i, j, j, 0, -coeff)
405 end if
406 end if
407
408 end subroutine evaluate_case_two
409
410
411 subroutine evaluate_case_three (this, p, q, nsfa, nsfb, mla, mlb, coeff, symbol)
412 class(orbitaltable), intent(inout) :: this
413 integer, intent(in) :: p, q, NSFA, NSFB, MLA, MLB
414 real(wp), intent(in) :: coeff
415 class(symbolicelementvector) :: symbol
416
417 integer :: I, J
418
419 if (p < q) then
420 i = q
421 j = p
422 else
423 i = p
424 j = q
425 end if
426
427 if (nsfa /= 0) then
428 if (mla == 0) then
429 call symbol % insert_ijklm_symbol(i, j, i, j, 1, coeff)
430 else
431 call symbol % insert_ijklm_symbol(i, j, i, j, 0, coeff)
432 end if
433 end if
434
435 if (nsfb /= 0) then
436 if (mlb == 0) then
437 call symbol % insert_ijklm_symbol(i, j, i, j, 1, -coeff)
438 else
439 call symbol % insert_ijklm_symbol(i, j, i, j, 0, -coeff)
440 end if
441 end if
442
443 end subroutine evaluate_case_three
444
445
446 subroutine evaluate_case_other (this, p, q, r, s, mla, ms, coeff, symbol)
447 class(orbitaltable), intent(inout) :: this
448 integer, intent(in) :: p, q, r, s, mla, ms
449 real(wp), intent(in) :: coeff
450 class(symbolicelementvector) :: symbol
451
452 real(wp) :: cfd
453 integer :: I, J, K, L
454
455 if (p < q) then
456 i = q
457 j = p
458 else
459 i = p
460 j = q
461 end if
462 if (r < s) then
463 k = s
464 l = r
465 else
466 k = r
467 l = s
468 end if
469
470 cfd = coeff
471 if (ms /= 0) cfd = -cfd
472
473 if (i > k .or. (i == k .and. j > l)) then
474 call symbol % insert_ijklm_symbol(i, j, k, l, mla, cfd)
475 else
476 call symbol % insert_ijklm_symbol(k, l, i, j, mla, cfd)
477 end if
478
479 end subroutine evaluate_case_other
480
481
482 !> Simple function to get orbital number for a specific spin orbital
483 integer function get_orbital_number (this, spin_orbital)
484
485 class(orbitaltable), intent(in) :: this
486 integer, intent(in) :: spin_orbital
487
488 if (spin_orbital > this % total_num_spin_orbitals .or. spin_orbital < 1) then
489 write (stdout, "('Orbital selected: ',2i12)") spin_orbital, this % total_num_spin_orbitals
490 flush(stdout)
491 call mpi_xermsg('Orbital_module', 'get_orbital_number', 'Selected orbital not within range', 1, 1)
492 end if
493
494 get_orbital_number = this % spin_orbitals(spin_orbital) % orbital_number
495
496 end function get_orbital_number
497
498
499 !> Simple function to get orbital number for a specific spin orbital
500 integer function get_spin (this, spin_orbital)
501 class(orbitaltable), intent(in) :: this
502 integer, intent(in) :: spin_orbital
503
504 if (spin_orbital > this % total_num_spin_orbitals .or. spin_orbital < 1) then
505 write (stdout, "('Orbital selected: ',2i12)") spin_orbital, this % total_num_spin_orbitals
506 flush(stdout)
507 call mpi_xermsg('Orbital_module', 'get_spin', 'Selected orbital not within range', 1, 1)
508 end if
509
510 get_spin = this % spin_orbitals(spin_orbital) % spin
511
512 end function get_spin
513
514
515 integer function get_gerude (this, spin_orbital)
516 class(orbitaltable), intent(in) :: this
517 integer, intent(in) :: spin_orbital
518
519 if (spin_orbital > this % total_num_spin_orbitals .or. spin_orbital < 1) then
520 write (stdout, "('Orbital selected: ',2i12)") spin_orbital, this % total_num_spin_orbitals
521 flush(stdout)
522 call mpi_xermsg('Orbital_module', 'get_gerude', 'Selected orbital not within range', 1, 1)
523 end if
524
525 get_gerude = this % spin_orbitals(spin_orbital) % gerude
526
527 end function get_gerude
528
529
530 integer function get_electron_number (this, spin_orbital)
531 class(orbitaltable), intent(in) :: this
532 integer, intent(in) :: spin_orbital
533
534 if (spin_orbital > this % total_num_spin_orbitals .or. spin_orbital < 1) then
535 write (stdout, "('Orbital selected: ',2i12)") spin_orbital, this % total_num_spin_orbitals
536 flush(stdout)
537 call mpi_xermsg('Orbital_module', 'get_electron_number', 'Selected orbital not within range', 1, 1)
538 end if
539
540 get_electron_number = this % spin_orbitals(spin_orbital) % electron_idx
541
542 end function get_electron_number
543
544
545 integer function get_minimum_mcon (this, determinants)
546 class(orbitaltable), intent(in) :: this
547 integer, intent(in) :: determinants(4)
548
549 !get_minimum_mcon = min(this%get_two_minimum_mcon(determinants(1),determinants(2)), &
550 ! & this%get_two_minimum_mcon(determinants(3),determinants(4)))
551
552 get_minimum_mcon = min(this % mcon(determinants(1)), &
553 this % mcon(determinants(2)), &
554 this % mcon(determinants(3)), &
555 this % mcon(determinants(4)))
556
557 end function get_minimum_mcon
558
559
560 integer function get_mcon (this, spin_orbital)
561 class(orbitaltable), intent(in) :: this
562 integer, intent(in) :: spin_orbital
563
564 if (spin_orbital > this % total_num_spin_orbitals .or. spin_orbital < 1) then
565 write (stdout, "('Orbital selected: ',2i12)") spin_orbital, this % total_num_spin_orbitals
566 flush(stdout)
567 call mpi_xermsg('Orbital_module', 'get_mcon', 'Selected orbital not within range', 1, 1)
568 end if
569
570 get_mcon = this % mcon(spin_orbital)
571
572 end function get_mcon
573
574
575 integer function get_two_minimum_mcon (this, determinant_one, determinant_two)
576 class(orbitaltable), intent(in) :: this
577 integer, intent(in) :: determinant_one, determinant_two
578
579 get_two_minimum_mcon = min(this % mcon(determinant_one), this % mcon(determinant_two))
580
581 end function get_two_minimum_mcon
582
583
584 integer function add_positron (this, determinants, ia, ib)
585 class(orbitaltable), intent(in) :: this
586 integer, intent(in) :: determinants(4), ia, ib
587 integer :: icount, ido, ip
588
589 add_positron = 0
590 icount = 0
591
592 do ido = ia, ib
593 ip = determinants(ido)
594 if (this % spin_orbitals(ip) % positron_flag /= 0) icount = icount + 1
595 end do
596
597 if (icount == 0) return
598 if (icount == 2) then
599 add_positron = 1
600 return
601 end if
602
603 write (stdout, "(' ICOUNT ',i4,' NDTC = ',4i4)") icount, determinants(:)
604 flush(stdout)
605 call mpi_xermsg('Orbital_module', 'add_positron', 'Invalid count', 1, 1)
606
607 end function add_positron
608
609end module orbital_module
MPI SCATCI Constants module.
integer, parameter symtype_cinfv
This describes C_inf_v symmetries.
integer, parameter symtype_dinfh
This describes D_inf_h symmetries.
integer, parameter symtype_d2h
This describes D_2_h symmetries.