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 Environment type holding the work and accumulation arrays of the Floquet-Bloch
10 : !> band-structure calculation (floquet_main), plus the derived sizes.
11 : !> \par History
12 : !> \author Shridhar Shanbhag (27.01.2026)
13 : ! **************************************************************************************************
14 : MODULE floquet_types
15 : USE kinds, ONLY: dp
16 : USE post_scf_bandstructure_types, ONLY: post_scf_bandstructure_type
17 : #include "./base/base_uses.f90"
18 :
19 : IMPLICIT NONE
20 :
21 : PRIVATE
22 :
23 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'floquet_types'
24 :
25 : PUBLIC :: floquet_env_type, &
26 : floquet_env_create, &
27 : floquet_env_release, &
28 : floquet_active_band_count, &
29 : floquet_band_window
30 :
31 : ! **************************************************************************************************
32 : !> \brief Work and accumulation arrays for one Floquet-Bloch band-structure run, plus the derived
33 : !> sizes. The per-(k-point,spin) buffers are overwritten each iteration; the all_* arrays
34 : !> accumulate the results over all DOS k-points and spins.
35 : !> \param max_f_index Floquet truncation index M
36 : !> \param n_f_size size of the truncated Floquet Hamiltonian, n_mo*(1 + 2*M)
37 : !> \param n_E number of points on the DOS energy grid
38 : !> \param nkp_only_bs number of band-structure k-points (the k-points the Floquet loop runs over)
39 : !> \param n_mo number of active bands used by the Floquet calculation (the MAX_NMO band window,
40 : !> or the full molecular-orbital count when MAX_NMO <= 0); all work/output arrays are sized
41 : !> with this
42 : !> \param n_mo_full total number of molecular orbitals (full band count before windowing)
43 : !> \param n_lo lowest full-band index of the active window, per spin (n_spin)
44 : !> \param n_hi highest full-band index of the active window, per spin (n_spin)
45 : !> \param n_spin number of spin channels
46 : !> \param eigenvalues Floquet eigenvalues for the current (k-point,spin) (n_f_size)
47 : !> \param w0 central-sector weights (n_f_size)
48 : !> \param wE outermost-sector weights (n_f_size)
49 : !> \param a_k spectral function A(k,E) on the energy grid (n_E)
50 : !> \param quasi_energies quasi-energies (n_mo)
51 : !> \param m0_energies m=0 band energies (n_mo)
52 : !> \param m0_weights central-sector weight of each m=0 band (n_mo)
53 : !> \param e_k_kp_spin band energies for the current (k-point,spin) (n_mo)
54 : !> \param p_k_kp_spin momentum matrix elements for the current (k-point,spin) (3, n_mo, n_mo)
55 : !> \param all_quasi_energies quasi-energies for every (band, spin, bs k-point) (n_mo, n_spin, nkp_only_bs)
56 : !> \param all_a_k spectral function for every (energy, spin, bs k-point) (n_E, n_spin, nkp_only_bs)
57 : !> \param all_m0_energies m=0 band energies for every (band, spin, bs k-point) (n_mo, n_spin, nkp_only_bs)
58 : !> \param all_m0_weights central-sector weights for every (band, spin, bs k-point) (n_mo, n_spin, nkp_only_bs)
59 : ! **************************************************************************************************
60 : TYPE floquet_env_type
61 : INTEGER :: max_f_index = -1, &
62 : n_f_size = -1, &
63 : n_E = -1, &
64 : nkp_only_bs = -1, &
65 : n_mo = -1, &
66 : n_mo_full = -1, &
67 : n_spin = -1
68 : INTEGER, ALLOCATABLE, DIMENSION(:) :: n_lo, n_hi
69 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, w0, wE, a_k, &
70 : quasi_energies, m0_energies, &
71 : m0_weights, e_k_kp_spin
72 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: p_k_kp_spin
73 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: all_quasi_energies, all_a_k, &
74 : all_m0_energies, all_m0_weights
75 : END TYPE floquet_env_type
76 :
77 : CONTAINS
78 :
79 : ! **************************************************************************************************
80 : !> \brief Number of active bands used by the Floquet calculation: the MAX_NMO band window closest
81 : !> to the VBM, clamped to the full molecular-orbital count, or the full count when MAX_NMO <= 0.
82 : !> \param bs_env ...
83 : !> \return the active band count
84 : ! **************************************************************************************************
85 6 : FUNCTION floquet_active_band_count(bs_env) RESULT(n_active)
86 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
87 : INTEGER :: n_active
88 :
89 6 : IF (bs_env%max_nmo_floquet <= 0 .OR. bs_env%max_nmo_floquet >= bs_env%n_ao) THEN
90 6 : n_active = bs_env%n_ao
91 : ELSE
92 : n_active = bs_env%max_nmo_floquet
93 : END IF
94 :
95 6 : END FUNCTION floquet_active_band_count
96 :
97 : ! **************************************************************************************************
98 : !> \brief Full-band index bounds [n_lo, n_hi] of the active window for one spin, selecting the
99 : !> MAX_NMO Kohn-Sham eigenstates closest to the VBM. Mirrors the HOMO-centred windowing of
100 : !> qs_moment_kpoints (qs_moments.F), with a final reclamp so the window holds exactly
101 : !> floquet_active_band_count(bs_env) states regardless of the per-spin HOMO index.
102 : !> \param bs_env ...
103 : !> \param ispin spin channel
104 : !> \param n_lo lowest full-band index of the window
105 : !> \param n_hi highest full-band index of the window
106 : ! **************************************************************************************************
107 2 : SUBROUTINE floquet_band_window(bs_env, ispin, n_lo, n_hi)
108 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
109 : INTEGER, INTENT(IN) :: ispin
110 : INTEGER, INTENT(OUT) :: n_lo, n_hi
111 :
112 : INTEGER :: homo, max_nmo, n_mo_full
113 :
114 2 : n_mo_full = bs_env%n_ao
115 2 : max_nmo = bs_env%max_nmo_floquet
116 :
117 2 : IF (max_nmo <= 0 .OR. max_nmo >= n_mo_full) THEN
118 2 : n_lo = 1
119 2 : n_hi = n_mo_full
120 : ELSE
121 0 : homo = bs_env%n_occ(ispin)
122 0 : n_lo = MAX(1, homo - (max_nmo - 1)/2)
123 0 : n_hi = MIN(n_mo_full, n_lo + max_nmo - 1)
124 : ! reclamp so the window holds exactly max_nmo states (keeps the fixed-size buffers valid
125 : ! when n_occ(1) /= n_occ(2)); a no-op away from the band edges
126 0 : n_lo = MAX(1, n_hi - max_nmo + 1)
127 : END IF
128 :
129 2 : END SUBROUTINE floquet_band_window
130 :
131 : ! **************************************************************************************************
132 : !> \brief Set the derived sizes from bs_env and allocate all work and accumulation arrays.
133 : !> \param floquet_env ...
134 : !> \param bs_env ...
135 : ! **************************************************************************************************
136 2 : SUBROUTINE floquet_env_create(floquet_env, bs_env)
137 : TYPE(floquet_env_type), INTENT(OUT) :: floquet_env
138 : TYPE(post_scf_bandstructure_type), POINTER :: bs_env
139 :
140 : CHARACTER(LEN=*), PARAMETER :: routineN = 'floquet_env_create'
141 :
142 : INTEGER :: handle, ispin, n_mo, nE, nf, nk, ns
143 :
144 2 : CALL timeset(routineN, handle)
145 :
146 2 : floquet_env%n_spin = bs_env%n_spin
147 2 : floquet_env%n_mo_full = bs_env%n_ao
148 : ! n_mo is the active band count (the MAX_NMO window, or the full count when MAX_NMO <= 0);
149 : ! every work/output array below is sized with it
150 2 : floquet_env%n_mo = floquet_active_band_count(bs_env)
151 2 : floquet_env%max_f_index = bs_env%max_floquet_index
152 2 : floquet_env%n_f_size = floquet_env%n_mo*(1 + 2*floquet_env%max_f_index)
153 2 : floquet_env%n_E = NINT(2*bs_env%energy_window_floquet/bs_env%energy_step_floquet)
154 2 : floquet_env%nkp_only_bs = bs_env%nkp_only_bs
155 :
156 : ! Per-spin full-band index bounds of the active window (used to slice the full-band data)
157 8 : ALLOCATE (floquet_env%n_lo(floquet_env%n_spin), floquet_env%n_hi(floquet_env%n_spin))
158 4 : DO ispin = 1, floquet_env%n_spin
159 4 : CALL floquet_band_window(bs_env, ispin, floquet_env%n_lo(ispin), floquet_env%n_hi(ispin))
160 : END DO
161 :
162 2 : n_mo = floquet_env%n_mo
163 2 : nf = floquet_env%n_f_size
164 2 : nE = floquet_env%n_E
165 2 : ns = floquet_env%n_spin
166 2 : nk = floquet_env%nkp_only_bs
167 :
168 : ! per-(k-point,spin) work buffers
169 10 : ALLOCATE (floquet_env%eigenvalues(nf), floquet_env%w0(nf), floquet_env%wE(nf))
170 6 : ALLOCATE (floquet_env%a_k(nE))
171 0 : ALLOCATE (floquet_env%quasi_energies(n_mo), floquet_env%m0_energies(n_mo), &
172 10 : floquet_env%m0_weights(n_mo))
173 10 : ALLOCATE (floquet_env%e_k_kp_spin(n_mo), floquet_env%p_k_kp_spin(3, n_mo, n_mo))
174 :
175 : ! per-(spin,k-point) accumulation arrays, filled once by the owning subgroup source and
176 : ! summed across the global communicator after the k-point loop
177 30 : ALLOCATE (floquet_env%all_quasi_energies(n_mo, ns, nk), source=0.0_dp)
178 18 : ALLOCATE (floquet_env%all_a_k(nE, ns, nk), source=0.0_dp)
179 28 : ALLOCATE (floquet_env%all_m0_energies(n_mo, ns, nk), source=0.0_dp)
180 28 : ALLOCATE (floquet_env%all_m0_weights(n_mo, ns, nk), source=0.0_dp)
181 :
182 2 : CALL timestop(handle)
183 :
184 2 : END SUBROUTINE floquet_env_create
185 :
186 : ! **************************************************************************************************
187 : !> \brief Deallocate all arrays held by floquet_env.
188 : !> \param floquet_env ...
189 : ! **************************************************************************************************
190 2 : SUBROUTINE floquet_env_release(floquet_env)
191 : TYPE(floquet_env_type), INTENT(INOUT) :: floquet_env
192 :
193 : CHARACTER(LEN=*), PARAMETER :: routineN = 'floquet_env_release'
194 :
195 : INTEGER :: handle
196 :
197 2 : CALL timeset(routineN, handle)
198 :
199 2 : IF (ALLOCATED(floquet_env%n_lo)) DEALLOCATE (floquet_env%n_lo)
200 2 : IF (ALLOCATED(floquet_env%n_hi)) DEALLOCATE (floquet_env%n_hi)
201 2 : IF (ALLOCATED(floquet_env%eigenvalues)) DEALLOCATE (floquet_env%eigenvalues)
202 2 : IF (ALLOCATED(floquet_env%w0)) DEALLOCATE (floquet_env%w0)
203 2 : IF (ALLOCATED(floquet_env%wE)) DEALLOCATE (floquet_env%wE)
204 2 : IF (ALLOCATED(floquet_env%a_k)) DEALLOCATE (floquet_env%a_k)
205 2 : IF (ALLOCATED(floquet_env%quasi_energies)) DEALLOCATE (floquet_env%quasi_energies)
206 2 : IF (ALLOCATED(floquet_env%m0_energies)) DEALLOCATE (floquet_env%m0_energies)
207 2 : IF (ALLOCATED(floquet_env%m0_weights)) DEALLOCATE (floquet_env%m0_weights)
208 2 : IF (ALLOCATED(floquet_env%e_k_kp_spin)) DEALLOCATE (floquet_env%e_k_kp_spin)
209 2 : IF (ALLOCATED(floquet_env%p_k_kp_spin)) DEALLOCATE (floquet_env%p_k_kp_spin)
210 2 : IF (ALLOCATED(floquet_env%all_quasi_energies)) DEALLOCATE (floquet_env%all_quasi_energies)
211 2 : IF (ALLOCATED(floquet_env%all_a_k)) DEALLOCATE (floquet_env%all_a_k)
212 2 : IF (ALLOCATED(floquet_env%all_m0_energies)) DEALLOCATE (floquet_env%all_m0_energies)
213 2 : IF (ALLOCATED(floquet_env%all_m0_weights)) DEALLOCATE (floquet_env%all_m0_weights)
214 :
215 2 : CALL timestop(handle)
216 :
217 2 : END SUBROUTINE floquet_env_release
218 :
219 0 : END MODULE floquet_types
|