242 SUBROUTINE set_mo_occupation_2(mo_array, smear, eval_deriv, tot_zeff_corr, probe, gce)
244 TYPE(
mo_set_type),
DIMENSION(:),
INTENT(INOUT) :: mo_array
246 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
247 REAL(KIND=
dp),
OPTIONAL :: tot_zeff_corr
250 TYPE(
gce_type),
OPTIONAL,
POINTER :: gce
252 CHARACTER(LEN=*),
PARAMETER :: routineN =
'set_mo_occupation_2'
254 INTEGER :: handle, i, lumo_a, lumo_b, &
255 multiplicity_new, multiplicity_old, &
257 REAL(KIND=
dp) :: nelec_f, threshold
258 REAL(KIND=
dp),
DIMENSION(:),
POINTER :: eigval_a, eigval_b
260 CALL timeset(routinen, handle)
263 IF (
SIZE(mo_array) == 1)
THEN
264 IF (
PRESENT(probe))
THEN
265 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
266 ELSE IF (
PRESENT(eval_deriv))
THEN
268 IF (
PRESENT(gce))
THEN
269 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv, gce=gce)
271 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
274 IF (
PRESENT(tot_zeff_corr))
THEN
275 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
277 IF (
PRESENT(gce))
THEN
278 CALL set_mo_occupation_1(mo_array(1), smear=smear, gce=gce)
280 CALL set_mo_occupation_1(mo_array(1), smear=smear)
284 CALL timestop(handle)
288 IF (
PRESENT(probe))
THEN
289 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
290 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
293 IF (smear%do_smear)
THEN
294 IF (smear%fixed_mag_mom < 0.0_dp)
THEN
295 IF (
PRESENT(tot_zeff_corr))
THEN
296 CALL cp_warn(__location__, &
297 "CORE_CORRECTION /= 0.0 might cause the cell to charge up "// &
298 "that will lead to application of different background "// &
299 "correction compared to the reference system. "// &
300 "Use FIXED_MAGNETIC_MOMENT >= 0.0 if using SMEAR keyword "// &
301 "to correct the electron density")
303 IF (smear%fixed_mag_mom /= -1.0_dp)
THEN
304 cpassert(.NOT. (
PRESENT(eval_deriv)))
305 CALL set_mo_occupation_3(mo_array, smear=smear, gce=gce)
306 CALL timestop(handle)
310 nelec_f = mo_array(1)%n_el_f + mo_array(2)%n_el_f
311 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
312 mo_array(1)%n_el_f = nelec_f/2.0_dp + smear%fixed_mag_mom/2.0_dp
313 mo_array(2)%n_el_f = nelec_f/2.0_dp - smear%fixed_mag_mom/2.0_dp
315 cpassert(.NOT. (
PRESENT(eval_deriv)))
316 IF (
PRESENT(tot_zeff_corr))
THEN
317 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
318 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
320 CALL set_mo_occupation_1(mo_array(1), smear=smear)
321 CALL set_mo_occupation_1(mo_array(2), smear=smear)
326 IF (.NOT. ((mo_array(1)%flexible_electron_count > 0.0_dp) .AND. &
327 (mo_array(2)%flexible_electron_count > 0.0_dp)))
THEN
328 IF (
PRESENT(probe))
THEN
329 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
330 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
331 ELSE IF (
PRESENT(eval_deriv))
THEN
332 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
333 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
335 IF (
PRESENT(tot_zeff_corr))
THEN
336 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
337 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
339 CALL set_mo_occupation_1(mo_array(1), smear=smear)
340 CALL set_mo_occupation_1(mo_array(2), smear=smear)
343 CALL timestop(handle)
347 nelec = mo_array(1)%nelectron + mo_array(2)%nelectron
349 multiplicity_old = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
351 IF (mo_array(1)%nelectron >= mo_array(1)%nmo)
THEN
352 CALL cp_warn(__location__, &
353 "All alpha MOs are occupied. Add more alpha MOs to "// &
354 "allow for a higher multiplicity")
356 IF ((mo_array(2)%nelectron >= mo_array(2)%nmo) .AND. (mo_array(2)%nelectron /= mo_array(1)%nelectron))
THEN
357 CALL cp_warn(__location__,
"All beta MOs are occupied. Add more beta MOs to "// &
358 "allow for a lower multiplicity")
361 eigval_a => mo_array(1)%eigenvalues
362 eigval_b => mo_array(2)%eigenvalues
371 threshold = max(mo_array(1)%flexible_electron_count, mo_array(2)%flexible_electron_count)
372 IF ((eigval_a(lumo_a) - threshold) < eigval_b(lumo_b))
THEN
377 IF (lumo_a > mo_array(1)%nmo)
THEN
379 CALL cp_warn(__location__, &
380 "All alpha MOs are occupied. Add more alpha MOs to "// &
381 "allow for a higher multiplicity")
388 IF (lumo_b > mo_array(2)%nmo)
THEN
389 IF (lumo_b < lumo_a)
THEN
390 CALL cp_warn(__location__, &
391 "All beta MOs are occupied. Add more beta MOs to "// &
392 "allow for a lower multiplicity")
401 mo_array(1)%homo = lumo_a - 1
402 mo_array(2)%homo = lumo_b - 1
404 IF (mo_array(2)%homo > mo_array(1)%homo)
THEN
405 CALL cp_warn(__location__, &
410 ") MOs are occupied. Resorting to low spin state")
411 mo_array(1)%homo = nelec/2 +
modulo(nelec, 2)
412 mo_array(2)%homo = nelec/2
415 mo_array(1)%nelectron = mo_array(1)%homo
416 mo_array(2)%nelectron = mo_array(2)%homo
417 multiplicity_new = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
419 IF (multiplicity_new /= multiplicity_old)
THEN
420 CALL cp_warn(__location__, &
421 "Multiplicity changed from "// &
422 trim(adjustl(
cp_to_string(multiplicity_old)))//
" to "// &
426 IF (
PRESENT(probe))
THEN
427 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
428 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
429 ELSE IF (
PRESENT(eval_deriv))
THEN
430 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
431 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
433 IF (
PRESENT(tot_zeff_corr))
THEN
434 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
435 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
437 CALL set_mo_occupation_1(mo_array(1), smear=smear)
438 CALL set_mo_occupation_1(mo_array(2), smear=smear)
442 CALL timestop(handle)
467 SUBROUTINE set_mo_occupation_1(mo_set, smear, eval_deriv, xas_env, tot_zeff_corr, probe, gce, &
472 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
474 REAL(kind=
dp),
OPTIONAL :: tot_zeff_corr
477 TYPE(
gce_type),
OPTIONAL,
POINTER :: gce
478 LOGICAL,
INTENT(IN),
OPTIONAL :: emit_warnings
480 CHARACTER(LEN=*),
PARAMETER :: routineN =
'set_mo_occupation_1'
482 CHARACTER(LEN=20) :: method_label
483 INTEGER :: handle, i, i_first, imo, ir, irmo, nmo, &
485 LOGICAL :: do_gce, equal_size, is_large, &
487 REAL(KIND=
dp) :: delectron, e1, e2, edelta, edist, el_count, gce_mu, my_nelec, nelec, &
488 occ_estate, smear_width, total_zeff_corr, xas_nelectron
489 REAL(KIND=
dp),
ALLOCATABLE,
DIMENSION(:) :: tmp_v
491 CALL timeset(routinen, handle)
493 my_emit_warnings = .true.
494 IF (
PRESENT(emit_warnings)) my_emit_warnings = emit_warnings
496 cpassert(
ASSOCIATED(mo_set%eigenvalues))
497 cpassert(
ASSOCIATED(mo_set%occupation_numbers))
498 mo_set%occupation_numbers(:) = 0.0_dp
501 IF (mo_set%nelectron == 0)
THEN
502 CALL timestop(handle)
508 IF (
PRESENT(xas_env))
THEN
509 CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
510 nomo = ceiling(xas_nelectron + 1.0_dp - occ_estate - epsilon(0.0_dp))
512 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
513 IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
514 el_count = sum(mo_set%occupation_numbers(1:nomo))
515 IF (el_count > xas_nelectron)
THEN
516 mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
518 el_count = sum(mo_set%occupation_numbers(1:nomo))
519 is_large = abs(el_count - xas_nelectron) > xas_nelectron*epsilon(el_count)
520 cpassert(.NOT. is_large)
522 IF (
PRESENT(gce))
THEN
529 smear_width = smear%smearing_width
530 IF (smear%method ==
smear_fermi_dirac) smear_width = smear%electronic_temperature
531 IF (gce%prev_workfunction < -1000.0_dp)
THEN
532 my_nelec = real(mo_set%nelectron,
dp)
533 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
534 smear_width, mo_set%maxocc, smear%method)
535 gce%prev_workfunction = -501.0_dp
536 ELSE IF (gce%prev_workfunction < -500.0_dp)
THEN
537 my_nelec = real(mo_set%nelectron,
dp)
538 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
539 smear_width, mo_set%maxocc, smear%method)
540 gce%prev_workfunction = gce%ref_esp - mo_set%mu
542 gce_mu = gce%ref_esp - ((1.0_dp - gce%mixing_coef)*gce%prev_workfunction &
543 + gce%mixing_coef*gce%target_workfunction)
544 CALL smearocc(mo_set%occupation_numbers, my_nelec, mo_set%kTS, mo_set%eigenvalues, gce_mu, &
545 smear_width, mo_set%maxocc, smear%method)
547 gce%prev_workfunction = gce%ref_esp - mo_set%mu
548 is_large = abs(mo_set%occupation_numbers(1) - mo_set%maxocc) > smear%eps_fermi_dirac
549 cpwarn_if(is_large .AND. my_emit_warnings,
"Fermi-Dirac smearing includes the first MO")
551 DO i = 1,
SIZE(mo_set%occupation_numbers)
552 IF (mo_set%occupation_numbers(i) < mo_set%maxocc)
THEN
557 DO i =
SIZE(mo_set%occupation_numbers), 1, -1
558 IF (abs(mo_set%occupation_numbers(i)) > smear%eps_fermi_dirac)
THEN
563 mo_set%uniform_occupation = .false.
564 mo_set%n_el_f = my_nelec
565 CALL timestop(handle)
569 IF (
modulo(mo_set%nelectron, int(mo_set%maxocc)) == 0)
THEN
570 nomo = nint(mo_set%nelectron/mo_set%maxocc)
572 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
574 nomo = int(mo_set%nelectron/mo_set%maxocc) + 1
576 mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
577 mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
584 IF (
PRESENT(tot_zeff_corr))
THEN
586 total_zeff_corr = tot_zeff_corr
587 IF (int(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
589 IF (total_zeff_corr < 0.0_dp)
THEN
591 delectron = abs(total_zeff_corr) - real(mo_set%maxocc, kind=
dp)
592 IF (delectron > 0.0_dp)
THEN
593 mo_set%occupation_numbers(nomo) = 0.0_dp
594 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
596 delectron = delectron - real(mo_set%maxocc, kind=
dp)
597 IF (delectron < 0.0_dp)
THEN
598 mo_set%occupation_numbers(nomo - ir) = -delectron
600 mo_set%occupation_numbers(nomo - ir) = 0.0_dp
604 IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
605 ELSE IF (delectron < 0.0_dp)
THEN
606 mo_set%occupation_numbers(nomo) = -delectron
608 mo_set%occupation_numbers(nomo) = 0.0_dp
611 ELSE IF (total_zeff_corr > 0.0_dp)
THEN
613 delectron = total_zeff_corr - real(mo_set%maxocc, kind=
dp)
614 IF (delectron > 0.0_dp)
THEN
615 mo_set%occupation_numbers(nomo + 1) = real(mo_set%maxocc, kind=
dp)
617 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
619 delectron = delectron - real(mo_set%maxocc, kind=
dp)
620 IF (delectron < 0.0_dp)
THEN
621 mo_set%occupation_numbers(nomo + ir) = delectron + real(mo_set%maxocc, kind=
dp)
623 mo_set%occupation_numbers(nomo + ir) = real(mo_set%maxocc, kind=
dp)
628 mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
634 nmo =
SIZE(mo_set%eigenvalues)
636 cpassert(nmo >= nomo)
637 cpassert((
SIZE(mo_set%occupation_numbers) == nmo))
640 mo_set%lfomo = nomo + 1
641 mo_set%mu = mo_set%eigenvalues(nomo)
644 IF (
PRESENT(eval_deriv))
THEN
645 equal_size = (
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(eval_deriv, 1))
650 IF (
PRESENT(probe))
THEN
652 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
653 nelec = real(mo_set%nelectron,
dp)
655 nelec = mo_set%n_el_f
658 mo_set%occupation_numbers(:) = 0.0_dp
660 CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
661 mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
666 DO imo = i_first, nmo
667 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
672 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
674 IF (is_large .AND. my_emit_warnings)
THEN
675 cpwarn(
"Hair-probes occupancy distribution includes the first MO")
679 DO imo = nmo, mo_set%lfomo, -1
680 IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp)
THEN
685 is_large = abs(minval(mo_set%occupation_numbers)) > probe(1)%eps_hp
686 IF (is_large .AND. my_emit_warnings)
THEN
687 CALL cp_warn(__location__, &
688 "Hair-probes occupancy distribution includes the last MO => "// &
689 "Add more MOs for proper smearing.")
693 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
694 IF (is_large .AND. my_emit_warnings)
THEN
695 cpwarn(
"Total number of electrons is not accurate")
701 IF (.NOT.
PRESENT(smear))
THEN
703 mo_set%uniform_occupation = .true.
704 IF (
PRESENT(eval_deriv))
THEN
707 CALL timestop(handle)
713 IF ((abs(mo_set%eigenvalues(1)) < 1.0e-12_dp) .AND. &
714 (abs(mo_set%eigenvalues(nmo)) < 1.0e-12_dp))
THEN
715 CALL timestop(handle)
721 IF (smear%do_smear)
THEN
722 IF (
PRESENT(xas_env))
THEN
723 i_first = xas_estate + 1
724 nelec = xas_nelectron
727 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
728 nelec = real(mo_set%nelectron,
dp)
730 nelec = mo_set%n_el_f
733 SELECT CASE (smear%method)
735 IF (.NOT.
PRESENT(eval_deriv))
THEN
736 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
737 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
739 xas_estate, occ_estate)
741 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
742 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
743 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
744 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
746 tmp_v, xas_estate, occ_estate)
750 DO imo = i_first, nmo
751 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
756 IF (i_first <= nmo)
THEN
757 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
762 cpwarn_if(is_large .AND. my_emit_warnings,
"Fermi-Dirac smearing includes the first MO")
765 DO imo = nmo, mo_set%lfomo, -1
766 IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac)
THEN
771 is_large = abs(minval(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
772 IF (is_large .AND. my_emit_warnings)
THEN
773 CALL cp_warn(__location__, &
774 "Fermi-Dirac smearing includes the last MO => "// &
775 "Add more MOs for proper smearing.")
779 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
780 cpwarn_if(is_large .AND. my_emit_warnings,
"Total number of electrons is not accurate")
783 IF (.NOT.
PRESENT(eval_deriv))
THEN
784 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
785 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
786 smear%smearing_width, mo_set%maxocc, smear%method, &
787 xas_estate, occ_estate)
789 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
790 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
791 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
792 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
793 smear%smearing_width, mo_set%maxocc, smear%method, &
794 tmp_v, xas_estate, occ_estate)
798 SELECT CASE (smear%method)
800 method_label =
"Gaussian"
802 method_label =
"Methfessel-Paxton"
804 method_label =
"Marzari-Vanderbilt"
808 DO imo = i_first, nmo
809 IF (abs(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac)
THEN
814 IF (i_first <= nmo)
THEN
815 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
819 IF (is_large .AND. my_emit_warnings)
THEN
820 cpwarn(trim(method_label)//
" smearing includes the first MO")
824 DO imo = nmo, mo_set%lfomo, -1
825 IF (abs(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac)
THEN
830 is_large = abs(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
831 IF (is_large .AND. my_emit_warnings)
THEN
832 CALL cp_warn(__location__, &
833 trim(method_label)//
" smearing includes the last MO => "// &
834 "Add more MOs for proper smearing.")
838 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
839 cpwarn_if(is_large .AND. my_emit_warnings,
"Total number of electrons is not accurate")
843 cpassert(.NOT.
PRESENT(eval_deriv))
846 e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
847 IF (e1 <= mo_set%eigenvalues(1) .AND. my_emit_warnings)
THEN
848 cpwarn(
"Energy window for smearing includes the first MO")
851 e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
852 IF (e2 >= mo_set%eigenvalues(nmo) .AND. my_emit_warnings)
THEN
853 CALL cp_warn(__location__, &
854 "Energy window for smearing includes the last MO => "// &
855 "Add more MOs for proper smearing.")
859 DO imo = i_first, nomo
860 IF (mo_set%eigenvalues(imo) > e1)
THEN
867 DO imo = nmo, nomo, -1
868 IF (mo_set%eigenvalues(imo) < e2)
THEN
878 DO imo = mo_set%lfomo, mo_set%homo
879 nelec = nelec + mo_set%occupation_numbers(imo)
880 edist = edist + abs(e2 - mo_set%eigenvalues(imo))
884 DO imo = mo_set%lfomo, mo_set%homo
885 edelta = abs(e2 - mo_set%eigenvalues(imo))
886 mo_set%occupation_numbers(imo) = min(mo_set%maxocc, nelec*edelta/edist)
887 nelec = nelec - mo_set%occupation_numbers(imo)
888 edist = edist - edelta
892 equal_size =
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(smear%list, 1)
894 mo_set%occupation_numbers = smear%list
896 IF (
PRESENT(eval_deriv))
THEN
905 IF (mo_set%lfomo == mo_set%homo)
THEN
907 mo_set%lfomo = nomo + 1
909 mo_set%uniform_occupation = .false.
917 IF (
ALLOCATED(tmp_v))
DEALLOCATE (tmp_v)
918 CALL timestop(handle)