Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Common selection and union operations for contiguous molecular-orbital windows.
10 : ! **************************************************************************************************
11 : MODULE mo_window
12 : USE kinds, ONLY: dp
13 : #include "./base/base_uses.f90"
14 :
15 : IMPLICIT NONE
16 :
17 : PRIVATE
18 :
19 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mo_window'
20 :
21 : TYPE mo_window_type
22 : INTEGER :: first_mo = 1
23 : INTEGER :: last_mo = 0
24 : END TYPE mo_window_type
25 :
26 : PUBLIC :: combine_mo_windows, determine_mo_window, mo_window_type
27 :
28 : CONTAINS
29 :
30 : ! **************************************************************************************************
31 : !> \brief Selects one contiguous MO window from an ordered reference spectrum.
32 : !>
33 : !> The input spectrum is supplied by the caller because different workflows may store more
34 : !> entries than the number of physical MOs to which a cutoff applies. The returned bounds are
35 : !> absolute, one-based indices in the caller's MO numbering.
36 : !> \param eigenvalues Reference eigenvalues for one spin channel.
37 : !> \param n_mo Number of physical MOs covered by the reference spectrum.
38 : !> \param n_occ Number of occupied MOs in that channel.
39 : !> \param cutoff_occ Occupied-state energy window; non-positive means no occupied cutoff.
40 : !> \param cutoff_empty Empty-state energy window; non-positive means no empty-state cutoff.
41 : !> \param window Selected absolute MO window (OUT).
42 : ! **************************************************************************************************
43 114 : SUBROUTINE determine_mo_window(eigenvalues, n_mo, n_occ, cutoff_occ, cutoff_empty, window)
44 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: eigenvalues
45 : INTEGER, INTENT(IN) :: n_mo, n_occ
46 : REAL(KIND=dp), INTENT(IN) :: cutoff_occ, cutoff_empty
47 : TYPE(mo_window_type), INTENT(OUT) :: window
48 :
49 : INTEGER :: i
50 :
51 114 : IF (n_mo < 1 .OR. n_mo > SIZE(eigenvalues)) THEN
52 0 : CALL cp_abort(__LOCATION__, "determine_mo_window: invalid number of physical MOs")
53 : END IF
54 114 : IF (n_occ < 1 .OR. n_occ >= n_mo) THEN
55 0 : CALL cp_abort(__LOCATION__, "determine_mo_window: invalid occupied-state boundary")
56 : END IF
57 :
58 114 : window%first_mo = 1
59 114 : window%last_mo = n_mo
60 :
61 114 : IF (cutoff_occ > 0.0_dp .OR. cutoff_empty > 0.0_dp) THEN
62 1900 : DO i = 2, n_mo
63 1900 : IF (eigenvalues(i) < eigenvalues(i - 1)) THEN
64 : CALL cp_abort(__LOCATION__, &
65 : "determine_mo_window: reference eigenvalues are not ascending. "// &
66 0 : "Use the DFT/SCF energy axis; the G0W0 axis is not ordered.")
67 : END IF
68 : END DO
69 :
70 90 : IF (cutoff_occ > 0.0_dp) THEN
71 70 : DO i = 1, n_occ
72 70 : IF (eigenvalues(n_occ) - eigenvalues(i) <= cutoff_occ) THEN
73 70 : window%first_mo = i
74 70 : EXIT
75 : END IF
76 : END DO
77 : END IF
78 :
79 90 : IF (cutoff_empty > 0.0_dp) THEN
80 1108 : DO i = n_occ + 1, n_mo
81 1108 : IF (eigenvalues(i) - eigenvalues(n_occ + 1) > cutoff_empty) THEN
82 90 : window%last_mo = i - 1
83 90 : EXIT
84 : END IF
85 : END DO
86 : END IF
87 : END IF
88 :
89 114 : END SUBROUTINE determine_mo_window
90 :
91 : ! **************************************************************************************************
92 : !> \brief Forms the smallest contiguous window covering all supplied spin windows.
93 : !> \param spin_windows Per-spin absolute MO windows.
94 : !> \param combined_window Union of the supplied windows (OUT).
95 : !> \param windows_differ True if at least two input windows have different bounds (OUT).
96 : ! **************************************************************************************************
97 10 : SUBROUTINE combine_mo_windows(spin_windows, combined_window, windows_differ)
98 : TYPE(mo_window_type), DIMENSION(:), INTENT(IN) :: spin_windows
99 : TYPE(mo_window_type), INTENT(OUT) :: combined_window
100 : LOGICAL, INTENT(OUT) :: windows_differ
101 :
102 : INTEGER :: i
103 :
104 10 : IF (SIZE(spin_windows) < 1) THEN
105 0 : CALL cp_abort(__LOCATION__, "combine_mo_windows: no spin windows supplied")
106 : END IF
107 :
108 10 : combined_window%first_mo = spin_windows(1)%first_mo
109 10 : combined_window%last_mo = spin_windows(1)%last_mo
110 10 : windows_differ = .FALSE.
111 :
112 18 : DO i = 2, SIZE(spin_windows)
113 8 : combined_window%first_mo = MIN(combined_window%first_mo, spin_windows(i)%first_mo)
114 8 : combined_window%last_mo = MAX(combined_window%last_mo, spin_windows(i)%last_mo)
115 : windows_differ = windows_differ .OR. &
116 : spin_windows(i)%first_mo /= spin_windows(1)%first_mo .OR. &
117 26 : spin_windows(i)%last_mo /= spin_windows(1)%last_mo
118 : END DO
119 :
120 10 : END SUBROUTINE combine_mo_windows
121 :
122 0 : END MODULE mo_window
|