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