200 SUBROUTINE set_mo_occupation_2(mo_array, smear, eval_deriv, tot_zeff_corr, probe)
202 TYPE(
mo_set_type),
DIMENSION(:),
INTENT(INOUT) :: mo_array
204 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
205 REAL(KIND=
dp),
OPTIONAL :: tot_zeff_corr
209 CHARACTER(LEN=*),
PARAMETER :: routinen =
'set_mo_occupation_2'
211 INTEGER :: handle, i, lumo_a, lumo_b, &
212 multiplicity_new, multiplicity_old, &
214 REAL(kind=
dp) :: nelec_f, threshold
215 REAL(kind=
dp),
DIMENSION(:),
POINTER :: eigval_a, eigval_b
217 CALL timeset(routinen, handle)
220 IF (
SIZE(mo_array) == 1)
THEN
221 IF (
PRESENT(probe))
THEN
222 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
223 ELSE IF (
PRESENT(eval_deriv))
THEN
225 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
227 IF (
PRESENT(tot_zeff_corr))
THEN
228 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
230 CALL set_mo_occupation_1(mo_array(1), smear=smear)
233 CALL timestop(handle)
237 IF (
PRESENT(probe))
THEN
238 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
239 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
242 IF (smear%do_smear)
THEN
243 IF (smear%fixed_mag_mom < 0.0_dp)
THEN
244 IF (
PRESENT(tot_zeff_corr))
THEN
245 CALL cp_warn(__location__, &
246 "CORE_CORRECTION /= 0.0 might cause the cell to charge up "// &
247 "that will lead to application of different background "// &
248 "correction compared to the reference system. "// &
249 "Use FIXED_MAGNETIC_MOMENT >= 0.0 if using SMEAR keyword "// &
250 "to correct the electron density")
252 IF (smear%fixed_mag_mom /= -1.0_dp)
THEN
253 cpassert(.NOT. (
PRESENT(eval_deriv)))
254 CALL set_mo_occupation_3(mo_array, smear=smear)
255 CALL timestop(handle)
259 nelec_f = mo_array(1)%n_el_f + mo_array(2)%n_el_f
260 IF (abs((mo_array(1)%n_el_f - mo_array(2)%n_el_f) - smear%fixed_mag_mom) > smear%eps_fermi_dirac*nelec_f)
THEN
261 mo_array(1)%n_el_f = nelec_f/2.0_dp + smear%fixed_mag_mom/2.0_dp
262 mo_array(2)%n_el_f = nelec_f/2.0_dp - smear%fixed_mag_mom/2.0_dp
264 cpassert(.NOT. (
PRESENT(eval_deriv)))
265 IF (
PRESENT(tot_zeff_corr))
THEN
266 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
267 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
269 CALL set_mo_occupation_1(mo_array(1), smear=smear)
270 CALL set_mo_occupation_1(mo_array(2), smear=smear)
275 IF (.NOT. ((mo_array(1)%flexible_electron_count > 0.0_dp) .AND. &
276 (mo_array(2)%flexible_electron_count > 0.0_dp)))
THEN
277 IF (
PRESENT(probe))
THEN
278 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
279 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
280 ELSE IF (
PRESENT(eval_deriv))
THEN
281 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
282 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
284 IF (
PRESENT(tot_zeff_corr))
THEN
285 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
286 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
288 CALL set_mo_occupation_1(mo_array(1), smear=smear)
289 CALL set_mo_occupation_1(mo_array(2), smear=smear)
292 CALL timestop(handle)
296 nelec = mo_array(1)%nelectron + mo_array(2)%nelectron
298 multiplicity_old = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
300 IF (mo_array(1)%nelectron >= mo_array(1)%nmo) &
301 CALL cp_warn(__location__, &
302 "All alpha MOs are occupied. Add more alpha MOs to "// &
303 "allow for a higher multiplicity")
304 IF ((mo_array(2)%nelectron >= mo_array(2)%nmo) .AND. (mo_array(2)%nelectron /= mo_array(1)%nelectron)) &
305 CALL cp_warn(__location__,
"All beta MOs are occupied. Add more beta MOs to "// &
306 "allow for a lower multiplicity")
308 eigval_a => mo_array(1)%eigenvalues
309 eigval_b => mo_array(2)%eigenvalues
318 threshold = max(mo_array(1)%flexible_electron_count, mo_array(2)%flexible_electron_count)
319 IF ((eigval_a(lumo_a) - threshold) < eigval_b(lumo_b))
THEN
324 IF (lumo_a > mo_array(1)%nmo)
THEN
326 CALL cp_warn(__location__, &
327 "All alpha MOs are occupied. Add more alpha MOs to "// &
328 "allow for a higher multiplicity")
334 IF (lumo_b > mo_array(2)%nmo)
THEN
335 IF (lumo_b < lumo_a) &
336 CALL cp_warn(__location__, &
337 "All beta MOs are occupied. Add more beta MOs to "// &
338 "allow for a lower multiplicity")
346 mo_array(1)%homo = lumo_a - 1
347 mo_array(2)%homo = lumo_b - 1
349 IF (mo_array(2)%homo > mo_array(1)%homo)
THEN
350 CALL cp_warn(__location__, &
355 ") MOs are occupied. Resorting to low spin state")
356 mo_array(1)%homo = nelec/2 +
modulo(nelec, 2)
357 mo_array(2)%homo = nelec/2
360 mo_array(1)%nelectron = mo_array(1)%homo
361 mo_array(2)%nelectron = mo_array(2)%homo
362 multiplicity_new = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
364 IF (multiplicity_new /= multiplicity_old) &
365 CALL cp_warn(__location__, &
366 "Multiplicity changed from "// &
367 trim(adjustl(
cp_to_string(multiplicity_old)))//
" to "// &
370 IF (
PRESENT(probe))
THEN
371 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
372 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
373 ELSE IF (
PRESENT(eval_deriv))
THEN
374 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
375 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
377 IF (
PRESENT(tot_zeff_corr))
THEN
378 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
379 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
381 CALL set_mo_occupation_1(mo_array(1), smear=smear)
382 CALL set_mo_occupation_1(mo_array(2), smear=smear)
386 CALL timestop(handle)
409 SUBROUTINE set_mo_occupation_1(mo_set, smear, eval_deriv, xas_env, tot_zeff_corr, probe)
413 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
415 REAL(kind=
dp),
OPTIONAL :: tot_zeff_corr
419 CHARACTER(LEN=*),
PARAMETER :: routinen =
'set_mo_occupation_1'
421 CHARACTER(LEN=20) :: method_label
422 INTEGER :: handle, i_first, imo, ir, irmo, nmo, &
424 LOGICAL :: equal_size, is_large
425 REAL(kind=
dp) :: delectron, e1, e2, edelta, edist, &
426 el_count, nelec, occ_estate, &
427 total_zeff_corr, xas_nelectron
428 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: tmp_v
430 CALL timeset(routinen, handle)
432 cpassert(
ASSOCIATED(mo_set%eigenvalues))
433 cpassert(
ASSOCIATED(mo_set%occupation_numbers))
434 mo_set%occupation_numbers(:) = 0.0_dp
437 IF (mo_set%nelectron == 0)
THEN
438 CALL timestop(handle)
444 IF (
PRESENT(xas_env))
THEN
445 CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
446 nomo = ceiling(xas_nelectron + 1.0 - occ_estate - epsilon(0.0_dp))
448 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
449 IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
450 el_count = sum(mo_set%occupation_numbers(1:nomo))
451 IF (el_count > xas_nelectron) &
452 mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
453 el_count = sum(mo_set%occupation_numbers(1:nomo))
454 is_large = abs(el_count - xas_nelectron) > xas_nelectron*epsilon(el_count)
455 cpassert(.NOT. is_large)
457 IF (
modulo(mo_set%nelectron, int(mo_set%maxocc)) == 0)
THEN
458 nomo = nint(mo_set%nelectron/mo_set%maxocc)
460 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
462 nomo = int(mo_set%nelectron/mo_set%maxocc) + 1
464 mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
465 mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
472 IF (
PRESENT(tot_zeff_corr))
THEN
474 total_zeff_corr = tot_zeff_corr
475 IF (int(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
477 IF (total_zeff_corr < 0.0_dp)
THEN
479 delectron = abs(total_zeff_corr) - real(mo_set%maxocc, kind=
dp)
480 IF (delectron > 0.0_dp)
THEN
481 mo_set%occupation_numbers(nomo) = 0.0_dp
482 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
484 delectron = delectron - real(mo_set%maxocc, kind=
dp)
485 IF (delectron < 0.0_dp)
THEN
486 mo_set%occupation_numbers(nomo - ir) = -delectron
488 mo_set%occupation_numbers(nomo - ir) = 0.0_dp
492 IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
493 ELSEIF (delectron < 0.0_dp)
THEN
494 mo_set%occupation_numbers(nomo) = -delectron
496 mo_set%occupation_numbers(nomo) = 0.0_dp
499 ELSEIF (total_zeff_corr > 0.0_dp)
THEN
501 delectron = total_zeff_corr - real(mo_set%maxocc, kind=
dp)
502 IF (delectron > 0.0_dp)
THEN
503 mo_set%occupation_numbers(nomo + 1) = real(mo_set%maxocc, kind=
dp)
505 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
507 delectron = delectron - real(mo_set%maxocc, kind=
dp)
508 IF (delectron < 0.0_dp)
THEN
509 mo_set%occupation_numbers(nomo + ir) = delectron + real(mo_set%maxocc, kind=
dp)
511 mo_set%occupation_numbers(nomo + ir) = real(mo_set%maxocc, kind=
dp)
516 mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
522 nmo =
SIZE(mo_set%eigenvalues)
524 cpassert(nmo >= nomo)
525 cpassert((
SIZE(mo_set%occupation_numbers) == nmo))
528 mo_set%lfomo = nomo + 1
529 mo_set%mu = mo_set%eigenvalues(nomo)
532 IF (
PRESENT(eval_deriv))
THEN
533 equal_size = (
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(eval_deriv, 1))
538 IF (
PRESENT(probe))
THEN
540 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
541 nelec = real(mo_set%nelectron,
dp)
543 nelec = mo_set%n_el_f
546 mo_set%occupation_numbers(:) = 0.0_dp
548 CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
549 mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
554 DO imo = i_first, nmo
555 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
560 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
563 cpwarn(
"Hair-probes occupancy distribution includes the first MO")
566 DO imo = nmo, mo_set%lfomo, -1
567 IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp)
THEN
572 is_large = abs(minval(mo_set%occupation_numbers)) > probe(1)%eps_hp
574 CALL cp_warn(__location__, &
575 "Hair-probes occupancy distribution includes the last MO => "// &
576 "Add more MOs for proper smearing.")
579 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
581 cpwarn(
"Total number of electrons is not accurate")
586 IF (.NOT.
PRESENT(smear))
THEN
588 mo_set%uniform_occupation = .true.
589 IF (
PRESENT(eval_deriv))
THEN
592 CALL timestop(handle)
598 IF ((abs(mo_set%eigenvalues(1)) < 1.0e-12_dp) .AND. &
599 (abs(mo_set%eigenvalues(nmo)) < 1.0e-12_dp))
THEN
600 CALL timestop(handle)
606 IF (smear%do_smear)
THEN
607 IF (
PRESENT(xas_env))
THEN
608 i_first = xas_estate + 1
609 nelec = xas_nelectron
612 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
613 nelec = real(mo_set%nelectron,
dp)
615 nelec = mo_set%n_el_f
618 SELECT CASE (smear%method)
620 IF (.NOT.
PRESENT(eval_deriv))
THEN
621 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
622 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
624 xas_estate, occ_estate)
626 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
627 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
628 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
629 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
631 tmp_v, xas_estate, occ_estate)
635 DO imo = i_first, nmo
636 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
641 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > smear%eps_fermi_dirac
643 cpwarn_if(is_large,
"Fermi-Dirac smearing includes the first MO")
646 DO imo = nmo, mo_set%lfomo, -1
647 IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac)
THEN
652 is_large = abs(minval(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
654 CALL cp_warn(__location__, &
655 "Fermi-Dirac smearing includes the last MO => "// &
656 "Add more MOs for proper smearing.")
659 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
660 cpwarn_if(is_large,
"Total number of electrons is not accurate")
663 IF (.NOT.
PRESENT(eval_deriv))
THEN
664 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
665 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
666 smear%smearing_width, mo_set%maxocc, smear%method, &
667 xas_estate, occ_estate)
669 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
670 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
671 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
672 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
673 smear%smearing_width, mo_set%maxocc, smear%method, &
674 tmp_v, xas_estate, occ_estate)
678 SELECT CASE (smear%method)
680 method_label =
"Gaussian"
682 method_label =
"Methfessel-Paxton"
684 method_label =
"Marzari-Vanderbilt"
688 DO imo = i_first, nmo
689 IF (abs(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac)
THEN
694 is_large = abs(mo_set%occupation_numbers(1) - mo_set%maxocc) > smear%eps_fermi_dirac
695 cpwarn_if(is_large, trim(method_label)//
" smearing includes the first MO")
698 DO imo = nmo, mo_set%lfomo, -1
699 IF (abs(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac)
THEN
704 is_large = abs(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
706 CALL cp_warn(__location__, &
707 trim(method_label)//
" smearing includes the last MO => "// &
708 "Add more MOs for proper smearing.")
711 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
712 cpwarn_if(is_large,
"Total number of electrons is not accurate")
716 cpassert(.NOT.
PRESENT(eval_deriv))
719 e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
720 IF (e1 <= mo_set%eigenvalues(1))
THEN
721 cpwarn(
"Energy window for smearing includes the first MO")
724 e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
725 IF (e2 >= mo_set%eigenvalues(nmo)) &
726 CALL cp_warn(__location__, &
727 "Energy window for smearing includes the last MO => "// &
728 "Add more MOs for proper smearing.")
731 DO imo = i_first, nomo
732 IF (mo_set%eigenvalues(imo) > e1)
THEN
739 DO imo = nmo, nomo, -1
740 IF (mo_set%eigenvalues(imo) < e2)
THEN
750 DO imo = mo_set%lfomo, mo_set%homo
751 nelec = nelec + mo_set%occupation_numbers(imo)
752 edist = edist + abs(e2 - mo_set%eigenvalues(imo))
756 DO imo = mo_set%lfomo, mo_set%homo
757 edelta = abs(e2 - mo_set%eigenvalues(imo))
758 mo_set%occupation_numbers(imo) = min(mo_set%maxocc, nelec*edelta/edist)
759 nelec = nelec - mo_set%occupation_numbers(imo)
760 edist = edist - edelta
764 equal_size =
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(smear%list, 1)
766 mo_set%occupation_numbers = smear%list
768 IF (
PRESENT(eval_deriv))
THEN
777 IF (mo_set%lfomo == mo_set%homo)
THEN
779 mo_set%lfomo = nomo + 1
781 mo_set%uniform_occupation = .false.
789 IF (
ALLOCATED(tmp_v))
DEALLOCATE (tmp_v)
790 CALL timestop(handle)
subroutine, public get_xas_env(xas_env, exc_state, nao, nvirtual, nvirtual2, centers_wfn, atom_of_state, exc_atoms, nexc_states, type_of_state, mykind_of_atom, mykind_of_kind, state_of_atom, spectrum, groundstate_coeff, ostrength_sm, dip_fm_set, excvec_coeff, excvec_overlap, unoccupied_orbs, unoccupied_evals, unoccupied_max_iter, unoccupied_eps, all_vectors, all_evals, my_gto_basis, qs_loc_env, stogto_overlap, occ_estate, xas_nelectron, xas_estate, nexc_atoms, nexc_search, spin_channel, scf_env, scf_control)
...