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, &
488 el_count, gce_mu, my_nelec, nelec, &
489 occ_estate, total_zeff_corr, &
491 REAL(KIND=
dp),
ALLOCATABLE,
DIMENSION(:) :: tmp_v
493 CALL timeset(routinen, handle)
495 my_emit_warnings = .true.
496 IF (
PRESENT(emit_warnings)) my_emit_warnings = emit_warnings
498 cpassert(
ASSOCIATED(mo_set%eigenvalues))
499 cpassert(
ASSOCIATED(mo_set%occupation_numbers))
500 mo_set%occupation_numbers(:) = 0.0_dp
503 IF (mo_set%nelectron == 0)
THEN
504 CALL timestop(handle)
510 IF (
PRESENT(xas_env))
THEN
511 CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
512 nomo = ceiling(xas_nelectron + 1.0 - occ_estate - epsilon(0.0_dp))
514 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
515 IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
516 el_count = sum(mo_set%occupation_numbers(1:nomo))
517 IF (el_count > xas_nelectron)
THEN
518 mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
520 el_count = sum(mo_set%occupation_numbers(1:nomo))
521 is_large = abs(el_count - xas_nelectron) > xas_nelectron*epsilon(el_count)
522 cpassert(.NOT. is_large)
524 IF (
PRESENT(gce))
THEN
532 cpabort(
"Grand canonical ensemble DFT SCF now only support Fermi Dirac smearing.")
534 IF (gce%prev_workfunction < -1000.0_dp)
THEN
535 my_nelec = real(mo_set%nelectron,
dp)
536 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
538 gce%prev_workfunction = -501.0_dp
539 ELSE IF (gce%prev_workfunction < -500.0_dp)
THEN
540 my_nelec = real(mo_set%nelectron,
dp)
541 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
543 gce%prev_workfunction = gce%ref_esp - mo_set%mu
545 gce_mu = gce%ref_esp - ((1.0_dp - gce%mixing_coef)*gce%prev_workfunction &
546 + gce%mixing_coef*gce%target_workfunction)
547 CALL smearocc(mo_set%occupation_numbers, my_nelec, mo_set%kTS, mo_set%eigenvalues, gce_mu, &
550 gce%prev_workfunction = gce%ref_esp - mo_set%mu
551 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > smear%eps_fermi_dirac
552 cpwarn_if(is_large .AND. my_emit_warnings,
"Fermi-Dirac smearing includes the first MO")
554 DO i = 1,
SIZE(mo_set%occupation_numbers)
555 IF (mo_set%occupation_numbers(i) < mo_set%maxocc)
THEN
560 DO i =
SIZE(mo_set%occupation_numbers), 1, -1
561 IF (mo_set%occupation_numbers(i) > smear%eps_fermi_dirac)
THEN
566 mo_set%uniform_occupation = .false.
567 mo_set%n_el_f = my_nelec
568 CALL timestop(handle)
572 IF (
modulo(mo_set%nelectron, int(mo_set%maxocc)) == 0)
THEN
573 nomo = nint(mo_set%nelectron/mo_set%maxocc)
575 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
577 nomo = int(mo_set%nelectron/mo_set%maxocc) + 1
579 mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
580 mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
587 IF (
PRESENT(tot_zeff_corr))
THEN
589 total_zeff_corr = tot_zeff_corr
590 IF (int(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
592 IF (total_zeff_corr < 0.0_dp)
THEN
594 delectron = abs(total_zeff_corr) - real(mo_set%maxocc, kind=
dp)
595 IF (delectron > 0.0_dp)
THEN
596 mo_set%occupation_numbers(nomo) = 0.0_dp
597 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
599 delectron = delectron - real(mo_set%maxocc, kind=
dp)
600 IF (delectron < 0.0_dp)
THEN
601 mo_set%occupation_numbers(nomo - ir) = -delectron
603 mo_set%occupation_numbers(nomo - ir) = 0.0_dp
607 IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
608 ELSE IF (delectron < 0.0_dp)
THEN
609 mo_set%occupation_numbers(nomo) = -delectron
611 mo_set%occupation_numbers(nomo) = 0.0_dp
614 ELSE IF (total_zeff_corr > 0.0_dp)
THEN
616 delectron = total_zeff_corr - real(mo_set%maxocc, kind=
dp)
617 IF (delectron > 0.0_dp)
THEN
618 mo_set%occupation_numbers(nomo + 1) = real(mo_set%maxocc, kind=
dp)
620 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
622 delectron = delectron - real(mo_set%maxocc, kind=
dp)
623 IF (delectron < 0.0_dp)
THEN
624 mo_set%occupation_numbers(nomo + ir) = delectron + real(mo_set%maxocc, kind=
dp)
626 mo_set%occupation_numbers(nomo + ir) = real(mo_set%maxocc, kind=
dp)
631 mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
637 nmo =
SIZE(mo_set%eigenvalues)
639 cpassert(nmo >= nomo)
640 cpassert((
SIZE(mo_set%occupation_numbers) == nmo))
643 mo_set%lfomo = nomo + 1
644 mo_set%mu = mo_set%eigenvalues(nomo)
647 IF (
PRESENT(eval_deriv))
THEN
648 equal_size = (
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(eval_deriv, 1))
653 IF (
PRESENT(probe))
THEN
655 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
656 nelec = real(mo_set%nelectron,
dp)
658 nelec = mo_set%n_el_f
661 mo_set%occupation_numbers(:) = 0.0_dp
663 CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
664 mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
669 DO imo = i_first, nmo
670 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
675 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
677 IF (is_large .AND. my_emit_warnings)
THEN
678 cpwarn(
"Hair-probes occupancy distribution includes the first MO")
682 DO imo = nmo, mo_set%lfomo, -1
683 IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp)
THEN
688 is_large = abs(minval(mo_set%occupation_numbers)) > probe(1)%eps_hp
689 IF (is_large .AND. my_emit_warnings)
THEN
690 CALL cp_warn(__location__, &
691 "Hair-probes occupancy distribution includes the last MO => "// &
692 "Add more MOs for proper smearing.")
696 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
697 IF (is_large .AND. my_emit_warnings)
THEN
698 cpwarn(
"Total number of electrons is not accurate")
704 IF (.NOT.
PRESENT(smear))
THEN
706 mo_set%uniform_occupation = .true.
707 IF (
PRESENT(eval_deriv))
THEN
710 CALL timestop(handle)
716 IF ((abs(mo_set%eigenvalues(1)) < 1.0e-12_dp) .AND. &
717 (abs(mo_set%eigenvalues(nmo)) < 1.0e-12_dp))
THEN
718 CALL timestop(handle)
724 IF (smear%do_smear)
THEN
725 IF (
PRESENT(xas_env))
THEN
726 i_first = xas_estate + 1
727 nelec = xas_nelectron
730 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
731 nelec = real(mo_set%nelectron,
dp)
733 nelec = mo_set%n_el_f
736 SELECT CASE (smear%method)
738 IF (.NOT.
PRESENT(eval_deriv))
THEN
739 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
740 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
742 xas_estate, occ_estate)
744 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
745 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
746 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
747 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
749 tmp_v, xas_estate, occ_estate)
753 DO imo = i_first, nmo
754 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
759 IF (i_first <= nmo)
THEN
760 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
765 cpwarn_if(is_large .AND. my_emit_warnings,
"Fermi-Dirac smearing includes the first MO")
768 DO imo = nmo, mo_set%lfomo, -1
769 IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac)
THEN
774 is_large = abs(minval(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
775 IF (is_large .AND. my_emit_warnings)
THEN
776 CALL cp_warn(__location__, &
777 "Fermi-Dirac smearing includes the last MO => "// &
778 "Add more MOs for proper smearing.")
782 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
783 cpwarn_if(is_large .AND. my_emit_warnings,
"Total number of electrons is not accurate")
786 IF (.NOT.
PRESENT(eval_deriv))
THEN
787 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
788 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
789 smear%smearing_width, mo_set%maxocc, smear%method, &
790 xas_estate, occ_estate)
792 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
793 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
794 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
795 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
796 smear%smearing_width, mo_set%maxocc, smear%method, &
797 tmp_v, xas_estate, occ_estate)
801 SELECT CASE (smear%method)
803 method_label =
"Gaussian"
805 method_label =
"Methfessel-Paxton"
807 method_label =
"Marzari-Vanderbilt"
811 DO imo = i_first, nmo
812 IF (abs(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac)
THEN
817 IF (i_first <= nmo)
THEN
818 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
822 IF (is_large .AND. my_emit_warnings)
THEN
823 cpwarn(trim(method_label)//
" smearing includes the first MO")
827 DO imo = nmo, mo_set%lfomo, -1
828 IF (abs(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac)
THEN
833 is_large = abs(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
834 IF (is_large .AND. my_emit_warnings)
THEN
835 CALL cp_warn(__location__, &
836 trim(method_label)//
" smearing includes the last MO => "// &
837 "Add more MOs for proper smearing.")
841 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
842 cpwarn_if(is_large .AND. my_emit_warnings,
"Total number of electrons is not accurate")
846 cpassert(.NOT.
PRESENT(eval_deriv))
849 e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
850 IF (e1 <= mo_set%eigenvalues(1) .AND. my_emit_warnings)
THEN
851 cpwarn(
"Energy window for smearing includes the first MO")
854 e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
855 IF (e2 >= mo_set%eigenvalues(nmo) .AND. my_emit_warnings)
THEN
856 CALL cp_warn(__location__, &
857 "Energy window for smearing includes the last MO => "// &
858 "Add more MOs for proper smearing.")
862 DO imo = i_first, nomo
863 IF (mo_set%eigenvalues(imo) > e1)
THEN
870 DO imo = nmo, nomo, -1
871 IF (mo_set%eigenvalues(imo) < e2)
THEN
881 DO imo = mo_set%lfomo, mo_set%homo
882 nelec = nelec + mo_set%occupation_numbers(imo)
883 edist = edist + abs(e2 - mo_set%eigenvalues(imo))
887 DO imo = mo_set%lfomo, mo_set%homo
888 edelta = abs(e2 - mo_set%eigenvalues(imo))
889 mo_set%occupation_numbers(imo) = min(mo_set%maxocc, nelec*edelta/edist)
890 nelec = nelec - mo_set%occupation_numbers(imo)
891 edist = edist - edelta
895 equal_size =
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(smear%list, 1)
897 mo_set%occupation_numbers = smear%list
899 IF (
PRESENT(eval_deriv))
THEN
908 IF (mo_set%lfomo == mo_set%homo)
THEN
910 mo_set%lfomo = nomo + 1
912 mo_set%uniform_occupation = .false.
920 IF (
ALLOCATED(tmp_v))
DEALLOCATE (tmp_v)
921 CALL timestop(handle)