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)
466 SUBROUTINE set_mo_occupation_1(mo_set, smear, eval_deriv, xas_env, tot_zeff_corr, probe, gce)
470 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
472 REAL(kind=
dp),
OPTIONAL :: tot_zeff_corr
475 TYPE(
gce_type),
OPTIONAL,
POINTER :: gce
477 CHARACTER(LEN=*),
PARAMETER :: routineN =
'set_mo_occupation_1'
479 CHARACTER(LEN=20) :: method_label
480 INTEGER :: handle, i, i_first, imo, ir, irmo, nmo, &
482 LOGICAL :: do_gce, equal_size, is_large
483 REAL(KIND=
dp) :: delectron, e1, e2, edelta, edist, &
484 el_count, gce_mu, my_nelec, nelec, &
485 occ_estate, total_zeff_corr, &
487 REAL(KIND=
dp),
ALLOCATABLE,
DIMENSION(:) :: tmp_v
489 CALL timeset(routinen, handle)
491 cpassert(
ASSOCIATED(mo_set%eigenvalues))
492 cpassert(
ASSOCIATED(mo_set%occupation_numbers))
493 mo_set%occupation_numbers(:) = 0.0_dp
496 IF (mo_set%nelectron == 0)
THEN
497 CALL timestop(handle)
503 IF (
PRESENT(xas_env))
THEN
504 CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
505 nomo = ceiling(xas_nelectron + 1.0 - occ_estate - epsilon(0.0_dp))
507 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
508 IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
509 el_count = sum(mo_set%occupation_numbers(1:nomo))
510 IF (el_count > xas_nelectron)
THEN
511 mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
513 el_count = sum(mo_set%occupation_numbers(1:nomo))
514 is_large = abs(el_count - xas_nelectron) > xas_nelectron*epsilon(el_count)
515 cpassert(.NOT. is_large)
517 IF (
PRESENT(gce))
THEN
525 cpabort(
"Grand canonical ensemble DFT SCF now only support Fermi Dirac smearing.")
527 IF (gce%prev_workfunction < -1000.0_dp)
THEN
528 my_nelec = real(mo_set%nelectron,
dp)
529 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
531 gce%prev_workfunction = -501.0_dp
532 ELSE IF (gce%prev_workfunction < -500.0_dp)
THEN
533 my_nelec = real(mo_set%nelectron,
dp)
534 CALL smearfixed(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, mo_set%eigenvalues, my_nelec, &
536 gce%prev_workfunction = gce%ref_esp - mo_set%mu
538 gce_mu = gce%ref_esp - ((1.0_dp - gce%mixing_coef)*gce%prev_workfunction &
539 + gce%mixing_coef*gce%target_workfunction)
540 CALL smearocc(mo_set%occupation_numbers, my_nelec, mo_set%kTS, mo_set%eigenvalues, gce_mu, &
543 gce%prev_workfunction = gce%ref_esp - mo_set%mu
544 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > smear%eps_fermi_dirac
545 cpwarn_if(is_large,
"Fermi-Dirac smearing includes the first MO")
547 DO i = 1,
SIZE(mo_set%occupation_numbers)
548 IF (mo_set%occupation_numbers(i) < mo_set%maxocc)
THEN
553 DO i =
SIZE(mo_set%occupation_numbers), 1, -1
554 IF (mo_set%occupation_numbers(i) > smear%eps_fermi_dirac)
THEN
559 mo_set%uniform_occupation = .false.
560 mo_set%n_el_f = my_nelec
561 CALL timestop(handle)
565 IF (
modulo(mo_set%nelectron, int(mo_set%maxocc)) == 0)
THEN
566 nomo = nint(mo_set%nelectron/mo_set%maxocc)
568 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
570 nomo = int(mo_set%nelectron/mo_set%maxocc) + 1
572 mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
573 mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
580 IF (
PRESENT(tot_zeff_corr))
THEN
582 total_zeff_corr = tot_zeff_corr
583 IF (int(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
585 IF (total_zeff_corr < 0.0_dp)
THEN
587 delectron = abs(total_zeff_corr) - real(mo_set%maxocc, kind=
dp)
588 IF (delectron > 0.0_dp)
THEN
589 mo_set%occupation_numbers(nomo) = 0.0_dp
590 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
592 delectron = delectron - real(mo_set%maxocc, kind=
dp)
593 IF (delectron < 0.0_dp)
THEN
594 mo_set%occupation_numbers(nomo - ir) = -delectron
596 mo_set%occupation_numbers(nomo - ir) = 0.0_dp
600 IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
601 ELSE IF (delectron < 0.0_dp)
THEN
602 mo_set%occupation_numbers(nomo) = -delectron
604 mo_set%occupation_numbers(nomo) = 0.0_dp
607 ELSE IF (total_zeff_corr > 0.0_dp)
THEN
609 delectron = total_zeff_corr - real(mo_set%maxocc, kind=
dp)
610 IF (delectron > 0.0_dp)
THEN
611 mo_set%occupation_numbers(nomo + 1) = real(mo_set%maxocc, kind=
dp)
613 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
615 delectron = delectron - real(mo_set%maxocc, kind=
dp)
616 IF (delectron < 0.0_dp)
THEN
617 mo_set%occupation_numbers(nomo + ir) = delectron + real(mo_set%maxocc, kind=
dp)
619 mo_set%occupation_numbers(nomo + ir) = real(mo_set%maxocc, kind=
dp)
624 mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
630 nmo =
SIZE(mo_set%eigenvalues)
632 cpassert(nmo >= nomo)
633 cpassert((
SIZE(mo_set%occupation_numbers) == nmo))
636 mo_set%lfomo = nomo + 1
637 mo_set%mu = mo_set%eigenvalues(nomo)
640 IF (
PRESENT(eval_deriv))
THEN
641 equal_size = (
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(eval_deriv, 1))
646 IF (
PRESENT(probe))
THEN
648 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
649 nelec = real(mo_set%nelectron,
dp)
651 nelec = mo_set%n_el_f
654 mo_set%occupation_numbers(:) = 0.0_dp
656 CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
657 mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
662 DO imo = i_first, nmo
663 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
668 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
671 cpwarn(
"Hair-probes occupancy distribution includes the first MO")
675 DO imo = nmo, mo_set%lfomo, -1
676 IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp)
THEN
681 is_large = abs(minval(mo_set%occupation_numbers)) > probe(1)%eps_hp
683 CALL cp_warn(__location__, &
684 "Hair-probes occupancy distribution includes the last MO => "// &
685 "Add more MOs for proper smearing.")
689 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
691 cpwarn(
"Total number of electrons is not accurate")
697 IF (.NOT.
PRESENT(smear))
THEN
699 mo_set%uniform_occupation = .true.
700 IF (
PRESENT(eval_deriv))
THEN
703 CALL timestop(handle)
709 IF ((abs(mo_set%eigenvalues(1)) < 1.0e-12_dp) .AND. &
710 (abs(mo_set%eigenvalues(nmo)) < 1.0e-12_dp))
THEN
711 CALL timestop(handle)
717 IF (smear%do_smear)
THEN
718 IF (
PRESENT(xas_env))
THEN
719 i_first = xas_estate + 1
720 nelec = xas_nelectron
723 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
724 nelec = real(mo_set%nelectron,
dp)
726 nelec = mo_set%n_el_f
729 SELECT CASE (smear%method)
731 IF (.NOT.
PRESENT(eval_deriv))
THEN
732 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
733 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
735 xas_estate, occ_estate)
737 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
738 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
739 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
740 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
742 tmp_v, xas_estate, occ_estate)
746 DO imo = i_first, nmo
747 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
752 IF (i_first <= nmo)
THEN
753 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
758 cpwarn_if(is_large,
"Fermi-Dirac smearing includes the first MO")
761 DO imo = nmo, mo_set%lfomo, -1
762 IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac)
THEN
767 is_large = abs(minval(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
769 CALL cp_warn(__location__, &
770 "Fermi-Dirac smearing includes the last MO => "// &
771 "Add more MOs for proper smearing.")
775 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
776 cpwarn_if(is_large,
"Total number of electrons is not accurate")
779 IF (.NOT.
PRESENT(eval_deriv))
THEN
780 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
781 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
782 smear%smearing_width, mo_set%maxocc, smear%method, &
783 xas_estate, occ_estate)
785 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
786 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
787 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
788 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
789 smear%smearing_width, mo_set%maxocc, smear%method, &
790 tmp_v, xas_estate, occ_estate)
794 SELECT CASE (smear%method)
796 method_label =
"Gaussian"
798 method_label =
"Methfessel-Paxton"
800 method_label =
"Marzari-Vanderbilt"
804 DO imo = i_first, nmo
805 IF (abs(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac)
THEN
810 IF (i_first <= nmo)
THEN
811 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
815 cpwarn_if(is_large, trim(method_label)//
" smearing includes the first MO")
818 DO imo = nmo, mo_set%lfomo, -1
819 IF (abs(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac)
THEN
824 is_large = abs(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
826 CALL cp_warn(__location__, &
827 trim(method_label)//
" smearing includes the last MO => "// &
828 "Add more MOs for proper smearing.")
832 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
833 cpwarn_if(is_large,
"Total number of electrons is not accurate")
837 cpassert(.NOT.
PRESENT(eval_deriv))
840 e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
841 IF (e1 <= mo_set%eigenvalues(1))
THEN
842 cpwarn(
"Energy window for smearing includes the first MO")
845 e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
846 IF (e2 >= mo_set%eigenvalues(nmo))
THEN
847 CALL cp_warn(__location__, &
848 "Energy window for smearing includes the last MO => "// &
849 "Add more MOs for proper smearing.")
853 DO imo = i_first, nomo
854 IF (mo_set%eigenvalues(imo) > e1)
THEN
861 DO imo = nmo, nomo, -1
862 IF (mo_set%eigenvalues(imo) < e2)
THEN
872 DO imo = mo_set%lfomo, mo_set%homo
873 nelec = nelec + mo_set%occupation_numbers(imo)
874 edist = edist + abs(e2 - mo_set%eigenvalues(imo))
878 DO imo = mo_set%lfomo, mo_set%homo
879 edelta = abs(e2 - mo_set%eigenvalues(imo))
880 mo_set%occupation_numbers(imo) = min(mo_set%maxocc, nelec*edelta/edist)
881 nelec = nelec - mo_set%occupation_numbers(imo)
882 edist = edist - edelta
886 equal_size =
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(smear%list, 1)
888 mo_set%occupation_numbers = smear%list
890 IF (
PRESENT(eval_deriv))
THEN
899 IF (mo_set%lfomo == mo_set%homo)
THEN
901 mo_set%lfomo = nomo + 1
903 mo_set%uniform_occupation = .false.
911 IF (
ALLOCATED(tmp_v))
DEALLOCATE (tmp_v)
912 CALL timestop(handle)