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 Definition and initialisation of the mo data type.
10 : !> \par History
11 : !> - adapted to the new QS environment data structure (02.04.2002,MK)
12 : !> - set_mo_occupation added (17.04.02,MK)
13 : !> - correct_mo_eigenvalues added (18.04.02,MK)
14 : !> - calculate_density_matrix moved from qs_scf to here (22.04.02,MK)
15 : !> - mo_set_p_type added (23.04.02,MK)
16 : !> - PRIVATE attribute set for TYPE mo_set_type (23.04.02,MK)
17 : !> - started conversion to LSD (1.2003, Joost VandeVondele)
18 : !> - set_mo_occupation moved to qs_mo_occupation (11.12.14 MI)
19 : !> - correct_mo_eigenvalues moved to qs_scf_methods (03.2016, Sergey Chulkov)
20 : !> \author Matthias Krack (09.05.2001,MK)
21 : ! **************************************************************************************************
22 : MODULE qs_mo_types
23 :
24 : USE cp_cfm_types, ONLY: cp_cfm_create,&
25 : cp_cfm_get_info,&
26 : cp_cfm_release,&
27 : cp_cfm_to_cfm,&
28 : cp_cfm_type
29 : USE cp_dbcsr_api, ONLY: dbcsr_copy,&
30 : dbcsr_init_p,&
31 : dbcsr_release_p,&
32 : dbcsr_type
33 : USE cp_dbcsr_operations, ONLY: dbcsr_copy_columns_hack
34 : USE cp_fm_pool_types, ONLY: cp_fm_pool_type,&
35 : fm_pool_create_fm,&
36 : fm_pool_get_el_struct
37 : USE cp_fm_struct, ONLY: cp_fm_struct_type
38 : USE cp_fm_types, ONLY: cp_fm_create,&
39 : cp_fm_get_info,&
40 : cp_fm_release,&
41 : cp_fm_set_all,&
42 : cp_fm_to_fm,&
43 : cp_fm_type
44 : USE kinds, ONLY: dp
45 : #include "./base/base_uses.f90"
46 :
47 : IMPLICIT NONE
48 :
49 : PRIVATE
50 :
51 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_types'
52 :
53 : TYPE mo_set_type
54 : ! The actual MO coefficients as a matrix
55 : TYPE(cp_fm_type), POINTER :: mo_coeff => NULL()
56 : TYPE(cp_cfm_type), POINTER :: cmo_coeff => NULL()
57 : TYPE(dbcsr_type), POINTER :: mo_coeff_b => NULL()
58 : ! we are using the dbcsr mo_coeff_b
59 : LOGICAL :: use_mo_coeff_b = .FALSE.
60 : ! Number of molecular orbitals (# cols in mo_coeff)
61 : INTEGER :: nmo = -1
62 : ! Number of atomic orbitals (# rows in mo_coeff)
63 : INTEGER :: nao = -1
64 : ! MO occupation numbers and MO eigenvalues (if eigenstates)
65 : REAL(KIND=dp), DIMENSION(:), POINTER :: eigenvalues => NULL(), &
66 : occupation_numbers => NULL()
67 : ! Maximum allowed occupation number of an MO, i.e.
68 : ! 1 for spin unrestricted (polarized) and 2 for spin restricted
69 : REAL(KIND=dp) :: maxocc = -1
70 : ! Number of electrons (taking occupations into account)
71 : INTEGER :: nelectron = -1
72 : REAL(KIND=dp) :: n_el_f = -1.0_dp
73 : ! Highest orbital with non-zero occupation
74 : INTEGER :: homo = -1
75 : ! lowest non maxocc occupied orbital (e.g. fractional or zero)
76 : INTEGER :: lfomo = -1
77 : ! True, if all allocated MOs have the same occupation number.
78 : ! This is not the case for fractional occupations or for added MOs
79 : ! with zero occupation.
80 : LOGICAL :: uniform_occupation = .FALSE.
81 : ! The entropic energy contribution
82 : REAL(KIND=dp) :: kTS = -1.0_dp
83 : ! Fermi energy level
84 : REAL(KIND=dp) :: mu = 0.0_dp
85 : ! Threshold value for multiplicity change
86 : REAL(KIND=dp) :: flexible_electron_count = -1.0_dp
87 : END TYPE mo_set_type
88 :
89 : TYPE mo_set_p_type
90 : TYPE(mo_set_type), POINTER :: mo_set => NULL()
91 : END TYPE mo_set_p_type
92 :
93 : PUBLIC :: mo_set_p_type, &
94 : mo_set_type
95 :
96 : PUBLIC :: allocate_mo_set, &
97 : deallocate_mo_set, &
98 : duplicate_mo_set, &
99 : get_mo_set, &
100 : has_uniform_occupation, &
101 : init_mo_set, &
102 : mo_set_restrict, &
103 : reassign_allocated_mos, &
104 : set_mo_set
105 :
106 : CONTAINS
107 :
108 : ! **************************************************************************************************
109 : !> \brief reassign an already allocated mo_set
110 : !> \param mo_set_new ...
111 : !> \param mo_set_old ...
112 : !> \date 2019-05-16
113 : !> \par History
114 : !> \author Soumya Ghosh
115 : ! **************************************************************************************************
116 392 : SUBROUTINE reassign_allocated_mos(mo_set_new, mo_set_old)
117 : TYPE(mo_set_type), INTENT(INOUT) :: mo_set_new, mo_set_old
118 :
119 : INTEGER :: nmo
120 :
121 392 : mo_set_new%maxocc = mo_set_old%maxocc
122 392 : mo_set_new%nelectron = mo_set_old%nelectron
123 392 : mo_set_new%n_el_f = mo_set_old%n_el_f
124 392 : mo_set_new%nao = mo_set_old%nao
125 392 : mo_set_new%nmo = mo_set_old%nmo
126 392 : mo_set_new%homo = mo_set_old%homo
127 392 : mo_set_new%lfomo = mo_set_old%lfomo
128 392 : mo_set_new%uniform_occupation = mo_set_old%uniform_occupation
129 392 : mo_set_new%kTS = mo_set_old%kTS
130 392 : mo_set_new%mu = mo_set_old%mu
131 392 : mo_set_new%flexible_electron_count = mo_set_old%flexible_electron_count
132 :
133 392 : nmo = mo_set_new%nmo
134 :
135 392 : IF (ASSOCIATED(mo_set_old%cmo_coeff)) THEN
136 0 : CPASSERT(ASSOCIATED(mo_set_new%cmo_coeff))
137 0 : CALL cp_cfm_to_cfm(mo_set_old%cmo_coeff, mo_set_new%cmo_coeff)
138 : ELSE
139 392 : CALL cp_fm_to_fm(mo_set_old%mo_coeff, mo_set_new%mo_coeff)
140 : END IF
141 :
142 : !IF (ASSOCIATED(mo_set_old%mo_coeff_b)) THEN
143 : ! CALL dbcsr_copy(mo_set_new%mo_coeff_b, mo_set_old%mo_coeff_b)
144 : !END IF
145 : !mo_set_new%use_mo_coeff_b = mo_set_old%use_mo_coeff_b
146 :
147 1160 : mo_set_new%eigenvalues = mo_set_old%eigenvalues
148 :
149 1160 : mo_set_new%occupation_numbers = mo_set_old%occupation_numbers
150 :
151 392 : END SUBROUTINE reassign_allocated_mos
152 :
153 : ! **************************************************************************************************
154 : !> \brief allocate a new mo_set, and copy the old data
155 : !> \param mo_set_new ...
156 : !> \param mo_set_old ...
157 : !> \date 2009-7-19
158 : !> \par History
159 : !> \author Joost VandeVondele
160 : ! **************************************************************************************************
161 544 : SUBROUTINE duplicate_mo_set(mo_set_new, mo_set_old)
162 : TYPE(mo_set_type), INTENT(OUT) :: mo_set_new
163 : TYPE(mo_set_type), INTENT(IN) :: mo_set_old
164 :
165 : INTEGER :: nmo
166 :
167 544 : mo_set_new%maxocc = mo_set_old%maxocc
168 544 : mo_set_new%nelectron = mo_set_old%nelectron
169 544 : mo_set_new%n_el_f = mo_set_old%n_el_f
170 544 : mo_set_new%nao = mo_set_old%nao
171 544 : mo_set_new%nmo = mo_set_old%nmo
172 544 : mo_set_new%homo = mo_set_old%homo
173 544 : mo_set_new%lfomo = mo_set_old%lfomo
174 544 : mo_set_new%uniform_occupation = mo_set_old%uniform_occupation
175 544 : mo_set_new%kTS = mo_set_old%kTS
176 544 : mo_set_new%mu = mo_set_old%mu
177 544 : mo_set_new%flexible_electron_count = mo_set_old%flexible_electron_count
178 :
179 544 : nmo = mo_set_new%nmo
180 :
181 544 : IF (ASSOCIATED(mo_set_old%cmo_coeff)) THEN
182 0 : ALLOCATE (mo_set_new%cmo_coeff)
183 0 : CALL cp_cfm_create(mo_set_new%cmo_coeff, mo_set_old%cmo_coeff%matrix_struct)
184 0 : CALL cp_cfm_to_cfm(mo_set_old%cmo_coeff, mo_set_new%cmo_coeff)
185 : ELSE
186 544 : ALLOCATE (mo_set_new%mo_coeff)
187 544 : CALL cp_fm_create(mo_set_new%mo_coeff, mo_set_old%mo_coeff%matrix_struct)
188 544 : CALL cp_fm_to_fm(mo_set_old%mo_coeff, mo_set_new%mo_coeff)
189 : END IF
190 :
191 544 : NULLIFY (mo_set_new%mo_coeff_b)
192 544 : IF (ASSOCIATED(mo_set_old%mo_coeff_b)) THEN
193 530 : CALL dbcsr_init_p(mo_set_new%mo_coeff_b)
194 530 : CALL dbcsr_copy(mo_set_new%mo_coeff_b, mo_set_old%mo_coeff_b)
195 : END IF
196 544 : mo_set_new%use_mo_coeff_b = mo_set_old%use_mo_coeff_b
197 :
198 1606 : ALLOCATE (mo_set_new%eigenvalues(nmo))
199 1882 : mo_set_new%eigenvalues = mo_set_old%eigenvalues
200 :
201 1062 : ALLOCATE (mo_set_new%occupation_numbers(nmo))
202 1882 : mo_set_new%occupation_numbers = mo_set_old%occupation_numbers
203 :
204 544 : END SUBROUTINE duplicate_mo_set
205 :
206 : ! **************************************************************************************************
207 : !> \brief Allocates a mo set and partially initializes it (nao,nmo,nelectron,
208 : !> and flexible_electron_count are valid).
209 : !> For the full initialization you need to call init_mo_set
210 : !> \param mo_set the mo_set to allocate
211 : !> \param nao number of atom orbitals
212 : !> \param nmo number of molecular orbitals
213 : !> \param nelectron number of electrons
214 : !> \param n_el_f ...
215 : !> \param maxocc maximum occupation of an orbital (LDA: 2, LSD:1)
216 : !> \param flexible_electron_count the number of electrons can be changed
217 : !> \date 15.05.2001
218 : !> \par History
219 : !> 11.2002 splitted initialization in two phases [fawzi]
220 : !> \author Matthias Krack
221 : ! **************************************************************************************************
222 24404 : SUBROUTINE allocate_mo_set(mo_set, nao, nmo, nelectron, n_el_f, maxocc, &
223 : flexible_electron_count)
224 :
225 : TYPE(mo_set_type), INTENT(INOUT) :: mo_set
226 : INTEGER, INTENT(IN) :: nao, nmo, nelectron
227 : REAL(KIND=dp), INTENT(IN) :: n_el_f, maxocc, flexible_electron_count
228 :
229 24404 : mo_set%maxocc = maxocc
230 24404 : mo_set%nelectron = nelectron
231 24404 : mo_set%n_el_f = n_el_f
232 24404 : mo_set%nao = nao
233 24404 : mo_set%nmo = nmo
234 24404 : mo_set%homo = 0
235 24404 : mo_set%lfomo = 0
236 24404 : mo_set%uniform_occupation = .TRUE.
237 24404 : mo_set%kTS = 0.0_dp
238 24404 : mo_set%mu = 0.0_dp
239 24404 : mo_set%flexible_electron_count = flexible_electron_count
240 :
241 24404 : NULLIFY (mo_set%eigenvalues)
242 24404 : NULLIFY (mo_set%occupation_numbers)
243 24404 : NULLIFY (mo_set%mo_coeff)
244 24404 : NULLIFY (mo_set%cmo_coeff)
245 24404 : NULLIFY (mo_set%mo_coeff_b)
246 24404 : mo_set%use_mo_coeff_b = .FALSE.
247 :
248 24404 : END SUBROUTINE allocate_mo_set
249 :
250 : ! **************************************************************************************************
251 : !> \brief initializes an allocated mo_set.
252 : !> eigenvalues, mo_coeff, occupation_numbers are valid only
253 : !> after this call.
254 : !> \param mo_set the mo_set to initialize
255 : !> \param fm_pool a pool out which you initialize the mo_set
256 : !> \param fm_ref a reference matrix from which you initialize the mo_set
257 : !> \param fm_struct ...
258 : !> \param name ...
259 : !> \param counter ...
260 : !> \param complex_coeff allocate native complex coefficients instead of real coefficients
261 : !> \par History
262 : !> 11.2002 revamped [fawzi]
263 : !> \author Fawzi Mohamed
264 : ! **************************************************************************************************
265 23358 : SUBROUTINE init_mo_set(mo_set, fm_pool, fm_ref, fm_struct, name, counter, complex_coeff)
266 :
267 : TYPE(mo_set_type), INTENT(INOUT) :: mo_set
268 : TYPE(cp_fm_pool_type), INTENT(IN), OPTIONAL :: fm_pool
269 : TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_ref
270 : TYPE(cp_fm_struct_type), OPTIONAL, POINTER :: fm_struct
271 : CHARACTER(LEN=*), INTENT(in) :: name
272 : INTEGER, INTENT(INOUT), OPTIONAL :: counter
273 : LOGICAL, INTENT(IN), OPTIONAL :: complex_coeff
274 :
275 : INTEGER :: na, nao, nb, nmo, nomo
276 : LOGICAL :: use_complex
277 : TYPE(cp_fm_struct_type), POINTER :: coeff_struct
278 :
279 23358 : CPASSERT(.NOT. ASSOCIATED(mo_set%eigenvalues))
280 23358 : CPASSERT(.NOT. ASSOCIATED(mo_set%occupation_numbers))
281 23358 : CPASSERT(.NOT. ASSOCIATED(mo_set%mo_coeff))
282 23358 : CPASSERT(.NOT. ASSOCIATED(mo_set%cmo_coeff))
283 : MARK_USED(counter)
284 23358 : CPASSERT(PRESENT(fm_pool) .NEQV. (PRESENT(fm_ref) .NEQV. PRESENT(fm_struct)))
285 23358 : use_complex = .FALSE.
286 23358 : IF (PRESENT(complex_coeff)) use_complex = complex_coeff
287 8353 : IF (use_complex) THEN
288 8323 : IF (PRESENT(fm_pool)) THEN
289 8323 : coeff_struct => fm_pool_get_el_struct(fm_pool)
290 0 : ELSE IF (PRESENT(fm_ref)) THEN
291 0 : coeff_struct => fm_ref%matrix_struct
292 : ELSE
293 0 : CPASSERT(ASSOCIATED(fm_struct))
294 0 : coeff_struct => fm_struct
295 : END IF
296 8323 : ALLOCATE (mo_set%cmo_coeff)
297 8323 : CALL cp_cfm_create(mo_set%cmo_coeff, coeff_struct, name=name, set_zero=.TRUE.)
298 8323 : CALL cp_cfm_get_info(mo_set%cmo_coeff, nrow_global=nao, ncol_global=nmo)
299 : ELSE
300 15035 : IF (PRESENT(fm_pool)) THEN
301 10015 : ALLOCATE (mo_set%mo_coeff)
302 10015 : CALL fm_pool_create_fm(fm_pool, mo_set%mo_coeff, name=name)
303 5020 : ELSE IF (PRESENT(fm_ref)) THEN
304 1206 : ALLOCATE (mo_set%mo_coeff)
305 1206 : CALL cp_fm_create(mo_set%mo_coeff, fm_ref%matrix_struct, name=name)
306 3814 : ELSE IF (PRESENT(fm_struct)) THEN
307 3814 : ALLOCATE (mo_set%mo_coeff)
308 3814 : CPASSERT(ASSOCIATED(fm_struct))
309 3814 : CALL cp_fm_create(mo_set%mo_coeff, fm_struct, name=name)
310 : END IF
311 15035 : CALL cp_fm_set_all(mo_set%mo_coeff, 0.0_dp)
312 15035 : CALL cp_fm_get_info(mo_set%mo_coeff, nrow_global=nao, ncol_global=nmo)
313 : END IF
314 :
315 23358 : CPASSERT(nao >= mo_set%nao)
316 23358 : CPASSERT(nmo >= mo_set%nmo)
317 :
318 69888 : ALLOCATE (mo_set%eigenvalues(nmo))
319 344124 : mo_set%eigenvalues(:) = 0.0_dp
320 :
321 46530 : ALLOCATE (mo_set%occupation_numbers(nmo))
322 : ! Initialize MO occupations
323 344124 : mo_set%occupation_numbers(:) = 0.0_dp
324 : ! Quick return, if no electrons are available
325 23358 : IF (mo_set%nelectron == 0) THEN
326 1182 : RETURN
327 : END IF
328 :
329 22176 : IF (MODULO(mo_set%nelectron, INT(mo_set%maxocc)) == 0) THEN
330 22054 : nomo = NINT(mo_set%nelectron/mo_set%maxocc)
331 188502 : mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
332 : ELSE
333 122 : nomo = INT(mo_set%nelectron/mo_set%maxocc) + 1
334 : ! Initialize MO occupations
335 366 : mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
336 244 : mo_set%occupation_numbers(nomo - ((na - nb)/2):nomo) = 1
337 : END IF
338 :
339 22176 : CPASSERT(nmo >= nomo)
340 22176 : CPASSERT((SIZE(mo_set%occupation_numbers) == nmo))
341 :
342 22176 : mo_set%homo = nomo
343 22176 : mo_set%lfomo = nomo + 1
344 22176 : mo_set%mu = mo_set%eigenvalues(nomo)
345 :
346 : END SUBROUTINE init_mo_set
347 :
348 : ! **************************************************************************************************
349 : !> \brief make the beta orbitals explicitly equal to the alpha orbitals
350 : !> effectively copying the orbital data
351 : !> \param mo_array ...
352 : !> \param convert_dbcsr ...
353 : !> \par History
354 : !> 10.2004 created [Joost VandeVondele]
355 : ! **************************************************************************************************
356 910 : SUBROUTINE mo_set_restrict(mo_array, convert_dbcsr)
357 : TYPE(mo_set_type), DIMENSION(2), INTENT(IN) :: mo_array
358 : LOGICAL, INTENT(in), OPTIONAL :: convert_dbcsr
359 :
360 : CHARACTER(LEN=*), PARAMETER :: routineN = 'mo_set_restrict'
361 :
362 : INTEGER :: handle
363 : LOGICAL :: my_convert_dbcsr
364 :
365 910 : CALL timeset(routineN, handle)
366 :
367 910 : my_convert_dbcsr = .FALSE.
368 910 : IF (PRESENT(convert_dbcsr)) my_convert_dbcsr = convert_dbcsr
369 :
370 910 : CPASSERT(mo_array(1)%nmo >= mo_array(2)%nmo)
371 :
372 : ! first nmo_beta orbitals are copied from alpha to beta
373 910 : IF (my_convert_dbcsr) THEN !fm->dbcsr
374 : CALL dbcsr_copy_columns_hack(mo_array(2)%mo_coeff_b, mo_array(1)%mo_coeff_b, & !fm->dbcsr
375 : mo_array(2)%nmo, 1, 1, & !fm->dbcsr
376 : para_env=mo_array(1)%mo_coeff%matrix_struct%para_env, & !fm->dbcsr
377 844 : blacs_env=mo_array(1)%mo_coeff%matrix_struct%context) !fm->dbcsr
378 : ELSE !fm->dbcsr
379 66 : CALL cp_fm_to_fm(mo_array(1)%mo_coeff, mo_array(2)%mo_coeff, mo_array(2)%nmo)
380 : END IF
381 :
382 910 : CALL timestop(handle)
383 :
384 910 : END SUBROUTINE mo_set_restrict
385 :
386 : ! **************************************************************************************************
387 : !> \brief Deallocate a wavefunction data structure.
388 : !> \param mo_set ...
389 : !> \date 15.05.2001
390 : !> \author MK
391 : !> \version 1.0
392 : ! **************************************************************************************************
393 25088 : SUBROUTINE deallocate_mo_set(mo_set)
394 :
395 : TYPE(mo_set_type), INTENT(INOUT) :: mo_set
396 :
397 25088 : IF (ASSOCIATED(mo_set%eigenvalues)) THEN
398 24048 : DEALLOCATE (mo_set%eigenvalues)
399 : NULLIFY (mo_set%eigenvalues)
400 : END IF
401 25088 : IF (ASSOCIATED(mo_set%occupation_numbers)) THEN
402 24048 : DEALLOCATE (mo_set%occupation_numbers)
403 : NULLIFY (mo_set%occupation_numbers)
404 : END IF
405 25088 : IF (ASSOCIATED(mo_set%mo_coeff)) THEN
406 15725 : CALL cp_fm_release(mo_set%mo_coeff)
407 15725 : DEALLOCATE (mo_set%mo_coeff)
408 : NULLIFY (mo_set%mo_coeff)
409 : END IF
410 25088 : IF (ASSOCIATED(mo_set%cmo_coeff)) THEN
411 8323 : CALL cp_cfm_release(mo_set%cmo_coeff)
412 8323 : DEALLOCATE (mo_set%cmo_coeff)
413 : NULLIFY (mo_set%cmo_coeff)
414 : END IF
415 25088 : IF (ASSOCIATED(mo_set%mo_coeff_b)) CALL dbcsr_release_p(mo_set%mo_coeff_b)
416 :
417 25088 : END SUBROUTINE deallocate_mo_set
418 :
419 : ! **************************************************************************************************
420 : !> \brief Get the components of a MO set data structure.
421 : !> \param mo_set ...
422 : !> \param maxocc ...
423 : !> \param homo ...
424 : !> \param lfomo ...
425 : !> \param nao ...
426 : !> \param nelectron ...
427 : !> \param n_el_f ...
428 : !> \param nmo ...
429 : !> \param eigenvalues ...
430 : !> \param occupation_numbers ...
431 : !> \param mo_coeff ...
432 : !> \param mo_coeff_b ...
433 : !> \param uniform_occupation ...
434 : !> \param kTS ...
435 : !> \param mu ...
436 : !> \param flexible_electron_count ...
437 : !> \param cmo_coeff ...
438 : !> \date 22.04.2002
439 : !> \author MK
440 : !> \version 1.0
441 : ! **************************************************************************************************
442 1405247 : SUBROUTINE get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, &
443 : eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, &
444 : uniform_occupation, kTS, mu, flexible_electron_count, cmo_coeff)
445 :
446 : TYPE(mo_set_type), INTENT(IN) :: mo_set
447 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: maxocc
448 : INTEGER, INTENT(OUT), OPTIONAL :: homo, lfomo, nao, nelectron
449 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: n_el_f
450 : INTEGER, INTENT(OUT), OPTIONAL :: nmo
451 : REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER :: eigenvalues, occupation_numbers
452 : TYPE(cp_fm_type), OPTIONAL, POINTER :: mo_coeff
453 : TYPE(dbcsr_type), OPTIONAL, POINTER :: mo_coeff_b
454 : LOGICAL, INTENT(OUT), OPTIONAL :: uniform_occupation
455 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: kTS, mu, flexible_electron_count
456 : TYPE(cp_cfm_type), OPTIONAL, POINTER :: cmo_coeff
457 :
458 1405247 : IF (PRESENT(maxocc)) maxocc = mo_set%maxocc
459 1405247 : IF (PRESENT(homo)) homo = mo_set%homo
460 1405247 : IF (PRESENT(lfomo)) lfomo = mo_set%lfomo
461 1405247 : IF (PRESENT(nao)) nao = mo_set%nao
462 1405247 : IF (PRESENT(nelectron)) nelectron = mo_set%nelectron
463 1405247 : IF (PRESENT(n_el_f)) n_el_f = mo_set%n_el_f
464 1405247 : IF (PRESENT(nmo)) nmo = mo_set%nmo
465 1405247 : IF (PRESENT(eigenvalues)) eigenvalues => mo_set%eigenvalues
466 1405247 : IF (PRESENT(occupation_numbers)) THEN
467 527581 : occupation_numbers => mo_set%occupation_numbers
468 : END IF
469 1405247 : IF (PRESENT(mo_coeff)) mo_coeff => mo_set%mo_coeff
470 1405247 : IF (PRESENT(cmo_coeff)) cmo_coeff => mo_set%cmo_coeff
471 1405247 : IF (PRESENT(mo_coeff_b)) mo_coeff_b => mo_set%mo_coeff_b
472 1405247 : IF (PRESENT(uniform_occupation)) uniform_occupation = mo_set%uniform_occupation
473 1405247 : IF (PRESENT(kTS)) kTS = mo_set%kTS
474 1405247 : IF (PRESENT(mu)) mu = mo_set%mu
475 1405247 : IF (PRESENT(flexible_electron_count)) flexible_electron_count = mo_set%flexible_electron_count
476 :
477 1405247 : END SUBROUTINE get_mo_set
478 :
479 : ! **************************************************************************************************
480 : !> \brief Set the components of a MO set data structure.
481 : !> \param mo_set ...
482 : !> \param maxocc ...
483 : !> \param homo ...
484 : !> \param lfomo ...
485 : !> \param nao ...
486 : !> \param nelectron ...
487 : !> \param n_el_f ...
488 : !> \param nmo ...
489 : !> \param eigenvalues ...
490 : !> \param occupation_numbers ...
491 : !> \param uniform_occupation ...
492 : !> \param kTS ...
493 : !> \param mu ...
494 : !> \param flexible_electron_count ...
495 : !> \date 22.04.2002
496 : !> \author MK
497 : !> \version 1.0
498 : ! **************************************************************************************************
499 13912 : SUBROUTINE set_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, &
500 : eigenvalues, occupation_numbers, uniform_occupation, &
501 : kTS, mu, flexible_electron_count)
502 :
503 : TYPE(mo_set_type), INTENT(INOUT) :: mo_set
504 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: maxocc
505 : INTEGER, INTENT(IN), OPTIONAL :: homo, lfomo, nao, nelectron
506 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: n_el_f
507 : INTEGER, INTENT(IN), OPTIONAL :: nmo
508 : REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER :: eigenvalues, occupation_numbers
509 : LOGICAL, INTENT(IN), OPTIONAL :: uniform_occupation
510 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: kTS, mu, flexible_electron_count
511 :
512 13912 : IF (PRESENT(maxocc)) mo_set%maxocc = maxocc
513 13912 : IF (PRESENT(homo)) mo_set%homo = homo
514 13912 : IF (PRESENT(lfomo)) mo_set%lfomo = lfomo
515 13912 : IF (PRESENT(nao)) mo_set%nao = nao
516 13912 : IF (PRESENT(nelectron)) mo_set%nelectron = nelectron
517 13912 : IF (PRESENT(n_el_f)) mo_set%n_el_f = n_el_f
518 13912 : IF (PRESENT(nmo)) mo_set%nmo = nmo
519 13912 : IF (PRESENT(eigenvalues)) THEN
520 0 : IF (ASSOCIATED(mo_set%eigenvalues)) THEN
521 0 : DEALLOCATE (mo_set%eigenvalues)
522 : END IF
523 0 : mo_set%eigenvalues => eigenvalues
524 : END IF
525 13912 : IF (PRESENT(occupation_numbers)) THEN
526 0 : IF (ASSOCIATED(mo_set%occupation_numbers)) THEN
527 0 : DEALLOCATE (mo_set%occupation_numbers)
528 : END IF
529 0 : mo_set%occupation_numbers => occupation_numbers
530 : END IF
531 13912 : IF (PRESENT(uniform_occupation)) mo_set%uniform_occupation = uniform_occupation
532 13912 : IF (PRESENT(kTS)) mo_set%kTS = kTS
533 13912 : IF (PRESENT(mu)) mo_set%mu = mu
534 13912 : IF (PRESENT(flexible_electron_count)) mo_set%flexible_electron_count = flexible_electron_count
535 :
536 13912 : END SUBROUTINE set_mo_set
537 :
538 : ! **************************************************************************************************
539 : !> \brief Check if the set of MOs in mo_set specifed by the MO index range [first_mo,last_mo]
540 : !> an integer occupation within a tolerance.
541 : !> \param mo_set :: MO set for which the uniform occupation will be checked
542 : !> \param first_mo :: Index of first MO for the checked MO range
543 : !> \param last_mo :: Index of last MO for the checked MO range
544 : !> \param occupation :: Requested uniform MO occupation with the MO range
545 : !> \param tolerance :: Requested numerical tolerance for an integer occupation
546 : !> \return has_uniform_occupation :: boolean, true if an integer occupation is found otherwise false
547 : !> \par History
548 : !> 04.08.2021 Created (MK)
549 : !> \author Matthias Krack (MK)
550 : !> \version 1.0
551 : ! **************************************************************************************************
552 211474 : FUNCTION has_uniform_occupation(mo_set, first_mo, last_mo, occupation, tolerance)
553 :
554 : TYPE(mo_set_type), INTENT(IN) :: mo_set
555 : INTEGER, INTENT(IN), OPTIONAL :: first_mo, last_mo
556 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: occupation, tolerance
557 : LOGICAL :: has_uniform_occupation
558 :
559 : INTEGER :: my_first_mo, my_last_mo
560 : REAL(KIND=dp) :: my_occupation, my_tolerance
561 :
562 211474 : has_uniform_occupation = .FALSE.
563 :
564 211474 : IF (PRESENT(first_mo)) THEN
565 0 : CPASSERT(first_mo >= LBOUND(mo_set%eigenvalues, 1))
566 : my_first_mo = first_mo
567 : ELSE
568 211474 : my_first_mo = LBOUND(mo_set%eigenvalues, 1)
569 : END IF
570 :
571 211474 : IF (PRESENT(last_mo)) THEN
572 8962 : CPASSERT(last_mo <= UBOUND(mo_set%eigenvalues, 1))
573 : my_last_mo = last_mo
574 : ELSE
575 206790 : my_last_mo = UBOUND(mo_set%eigenvalues, 1)
576 : END IF
577 :
578 211474 : IF (PRESENT(occupation)) THEN
579 0 : my_occupation = occupation
580 : ELSE
581 211474 : my_occupation = mo_set%maxocc
582 : END IF
583 :
584 211474 : IF (PRESENT(tolerance)) THEN
585 0 : my_tolerance = tolerance
586 : ELSE
587 : my_tolerance = EPSILON(0.0_dp)
588 : END IF
589 :
590 1789322 : has_uniform_occupation = ALL(ABS(mo_set%occupation_numbers(my_first_mo:my_last_mo) - my_occupation) < my_tolerance)
591 :
592 211474 : END FUNCTION has_uniform_occupation
593 :
594 0 : END MODULE qs_mo_types
|