218 SUBROUTINE set_mo_occupation_2(mo_array, smear, eval_deriv, tot_zeff_corr, probe)
220 TYPE(
mo_set_type),
DIMENSION(:),
INTENT(INOUT) :: mo_array
222 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
223 REAL(KIND=
dp),
OPTIONAL :: tot_zeff_corr
227 CHARACTER(LEN=*),
PARAMETER :: routinen =
'set_mo_occupation_2'
229 INTEGER :: handle, i, lumo_a, lumo_b, &
230 multiplicity_new, multiplicity_old, &
232 REAL(kind=
dp) :: nelec_f, threshold
233 REAL(kind=
dp),
DIMENSION(:),
POINTER :: eigval_a, eigval_b
235 CALL timeset(routinen, handle)
238 IF (
SIZE(mo_array) == 1)
THEN
239 IF (
PRESENT(probe))
THEN
240 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
241 ELSE IF (
PRESENT(eval_deriv))
THEN
243 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
245 IF (
PRESENT(tot_zeff_corr))
THEN
246 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
248 CALL set_mo_occupation_1(mo_array(1), smear=smear)
251 CALL timestop(handle)
255 IF (
PRESENT(probe))
THEN
256 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
257 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
260 IF (smear%do_smear)
THEN
261 IF (smear%fixed_mag_mom < 0.0_dp)
THEN
262 IF (
PRESENT(tot_zeff_corr))
THEN
263 CALL cp_warn(__location__, &
264 "CORE_CORRECTION /= 0.0 might cause the cell to charge up "// &
265 "that will lead to application of different background "// &
266 "correction compared to the reference system. "// &
267 "Use FIXED_MAGNETIC_MOMENT >= 0.0 if using SMEAR keyword "// &
268 "to correct the electron density")
270 IF (smear%fixed_mag_mom /= -1.0_dp)
THEN
271 cpassert(.NOT. (
PRESENT(eval_deriv)))
272 CALL set_mo_occupation_3(mo_array, smear=smear)
273 CALL timestop(handle)
277 nelec_f = mo_array(1)%n_el_f + mo_array(2)%n_el_f
278 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
279 mo_array(1)%n_el_f = nelec_f/2.0_dp + smear%fixed_mag_mom/2.0_dp
280 mo_array(2)%n_el_f = nelec_f/2.0_dp - smear%fixed_mag_mom/2.0_dp
282 cpassert(.NOT. (
PRESENT(eval_deriv)))
283 IF (
PRESENT(tot_zeff_corr))
THEN
284 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
285 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
287 CALL set_mo_occupation_1(mo_array(1), smear=smear)
288 CALL set_mo_occupation_1(mo_array(2), smear=smear)
293 IF (.NOT. ((mo_array(1)%flexible_electron_count > 0.0_dp) .AND. &
294 (mo_array(2)%flexible_electron_count > 0.0_dp)))
THEN
295 IF (
PRESENT(probe))
THEN
296 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
297 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
298 ELSE IF (
PRESENT(eval_deriv))
THEN
299 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
300 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
302 IF (
PRESENT(tot_zeff_corr))
THEN
303 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
304 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
306 CALL set_mo_occupation_1(mo_array(1), smear=smear)
307 CALL set_mo_occupation_1(mo_array(2), smear=smear)
310 CALL timestop(handle)
314 nelec = mo_array(1)%nelectron + mo_array(2)%nelectron
316 multiplicity_old = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
318 IF (mo_array(1)%nelectron >= mo_array(1)%nmo) &
319 CALL cp_warn(__location__, &
320 "All alpha MOs are occupied. Add more alpha MOs to "// &
321 "allow for a higher multiplicity")
322 IF ((mo_array(2)%nelectron >= mo_array(2)%nmo) .AND. (mo_array(2)%nelectron /= mo_array(1)%nelectron)) &
323 CALL cp_warn(__location__,
"All beta MOs are occupied. Add more beta MOs to "// &
324 "allow for a lower multiplicity")
326 eigval_a => mo_array(1)%eigenvalues
327 eigval_b => mo_array(2)%eigenvalues
336 threshold = max(mo_array(1)%flexible_electron_count, mo_array(2)%flexible_electron_count)
337 IF ((eigval_a(lumo_a) - threshold) < eigval_b(lumo_b))
THEN
342 IF (lumo_a > mo_array(1)%nmo)
THEN
344 CALL cp_warn(__location__, &
345 "All alpha MOs are occupied. Add more alpha MOs to "// &
346 "allow for a higher multiplicity")
352 IF (lumo_b > mo_array(2)%nmo)
THEN
353 IF (lumo_b < lumo_a) &
354 CALL cp_warn(__location__, &
355 "All beta MOs are occupied. Add more beta MOs to "// &
356 "allow for a lower multiplicity")
364 mo_array(1)%homo = lumo_a - 1
365 mo_array(2)%homo = lumo_b - 1
367 IF (mo_array(2)%homo > mo_array(1)%homo)
THEN
368 CALL cp_warn(__location__, &
373 ") MOs are occupied. Resorting to low spin state")
374 mo_array(1)%homo = nelec/2 +
modulo(nelec, 2)
375 mo_array(2)%homo = nelec/2
378 mo_array(1)%nelectron = mo_array(1)%homo
379 mo_array(2)%nelectron = mo_array(2)%homo
380 multiplicity_new = mo_array(1)%nelectron - mo_array(2)%nelectron + 1
382 IF (multiplicity_new /= multiplicity_old) &
383 CALL cp_warn(__location__, &
384 "Multiplicity changed from "// &
385 trim(adjustl(
cp_to_string(multiplicity_old)))//
" to "// &
388 IF (
PRESENT(probe))
THEN
389 CALL set_mo_occupation_1(mo_array(1), smear=smear, probe=probe)
390 CALL set_mo_occupation_1(mo_array(2), smear=smear, probe=probe)
391 ELSE IF (
PRESENT(eval_deriv))
THEN
392 CALL set_mo_occupation_1(mo_array(1), smear=smear, eval_deriv=eval_deriv)
393 CALL set_mo_occupation_1(mo_array(2), smear=smear, eval_deriv=eval_deriv)
395 IF (
PRESENT(tot_zeff_corr))
THEN
396 CALL set_mo_occupation_1(mo_array(1), smear=smear, tot_zeff_corr=tot_zeff_corr)
397 CALL set_mo_occupation_1(mo_array(2), smear=smear, tot_zeff_corr=tot_zeff_corr)
399 CALL set_mo_occupation_1(mo_array(1), smear=smear)
400 CALL set_mo_occupation_1(mo_array(2), smear=smear)
404 CALL timestop(handle)
427 SUBROUTINE set_mo_occupation_1(mo_set, smear, eval_deriv, xas_env, tot_zeff_corr, probe)
431 REAL(KIND=
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: eval_deriv
433 REAL(kind=
dp),
OPTIONAL :: tot_zeff_corr
437 CHARACTER(LEN=*),
PARAMETER :: routinen =
'set_mo_occupation_1'
439 CHARACTER(LEN=20) :: method_label
440 INTEGER :: handle, i_first, imo, ir, irmo, nmo, &
442 LOGICAL :: equal_size, is_large
443 REAL(kind=
dp) :: delectron, e1, e2, edelta, edist, &
444 el_count, nelec, occ_estate, &
445 total_zeff_corr, xas_nelectron
446 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: tmp_v
448 CALL timeset(routinen, handle)
450 cpassert(
ASSOCIATED(mo_set%eigenvalues))
451 cpassert(
ASSOCIATED(mo_set%occupation_numbers))
452 mo_set%occupation_numbers(:) = 0.0_dp
455 IF (mo_set%nelectron == 0)
THEN
456 CALL timestop(handle)
462 IF (
PRESENT(xas_env))
THEN
463 CALL get_xas_env(xas_env=xas_env, xas_nelectron=xas_nelectron, occ_estate=occ_estate, xas_estate=xas_estate)
464 nomo = ceiling(xas_nelectron + 1.0 - occ_estate - epsilon(0.0_dp))
466 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
467 IF (xas_estate > 0) mo_set%occupation_numbers(xas_estate) = occ_estate
468 el_count = sum(mo_set%occupation_numbers(1:nomo))
469 IF (el_count > xas_nelectron) &
470 mo_set%occupation_numbers(nomo) = mo_set%occupation_numbers(nomo) - (el_count - xas_nelectron)
471 el_count = sum(mo_set%occupation_numbers(1:nomo))
472 is_large = abs(el_count - xas_nelectron) > xas_nelectron*epsilon(el_count)
473 cpassert(.NOT. is_large)
475 IF (
modulo(mo_set%nelectron, int(mo_set%maxocc)) == 0)
THEN
476 nomo = nint(mo_set%nelectron/mo_set%maxocc)
478 mo_set%occupation_numbers(1:nomo) = mo_set%maxocc
480 nomo = int(mo_set%nelectron/mo_set%maxocc) + 1
482 mo_set%occupation_numbers(1:nomo - 1) = mo_set%maxocc
483 mo_set%occupation_numbers(nomo) = mo_set%nelectron - (nomo - 1)*mo_set%maxocc
490 IF (
PRESENT(tot_zeff_corr))
THEN
492 total_zeff_corr = tot_zeff_corr
493 IF (int(mo_set%maxocc) == 1) total_zeff_corr = total_zeff_corr/2.0_dp
495 IF (total_zeff_corr < 0.0_dp)
THEN
497 delectron = abs(total_zeff_corr) - real(mo_set%maxocc, kind=
dp)
498 IF (delectron > 0.0_dp)
THEN
499 mo_set%occupation_numbers(nomo) = 0.0_dp
500 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
502 delectron = delectron - real(mo_set%maxocc, kind=
dp)
503 IF (delectron < 0.0_dp)
THEN
504 mo_set%occupation_numbers(nomo - ir) = -delectron
506 mo_set%occupation_numbers(nomo - ir) = 0.0_dp
510 IF (mo_set%occupation_numbers(nomo) == 0.0_dp) nomo = nomo - 1
511 ELSEIF (delectron < 0.0_dp)
THEN
512 mo_set%occupation_numbers(nomo) = -delectron
514 mo_set%occupation_numbers(nomo) = 0.0_dp
517 ELSEIF (total_zeff_corr > 0.0_dp)
THEN
519 delectron = total_zeff_corr - real(mo_set%maxocc, kind=
dp)
520 IF (delectron > 0.0_dp)
THEN
521 mo_set%occupation_numbers(nomo + 1) = real(mo_set%maxocc, kind=
dp)
523 irmo = ceiling(delectron/real(mo_set%maxocc, kind=
dp))
525 delectron = delectron - real(mo_set%maxocc, kind=
dp)
526 IF (delectron < 0.0_dp)
THEN
527 mo_set%occupation_numbers(nomo + ir) = delectron + real(mo_set%maxocc, kind=
dp)
529 mo_set%occupation_numbers(nomo + ir) = real(mo_set%maxocc, kind=
dp)
534 mo_set%occupation_numbers(nomo + 1) = total_zeff_corr
540 nmo =
SIZE(mo_set%eigenvalues)
542 cpassert(nmo >= nomo)
543 cpassert((
SIZE(mo_set%occupation_numbers) == nmo))
546 mo_set%lfomo = nomo + 1
547 mo_set%mu = mo_set%eigenvalues(nomo)
550 IF (
PRESENT(eval_deriv))
THEN
551 equal_size = (
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(eval_deriv, 1))
556 IF (
PRESENT(probe))
THEN
558 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
559 nelec = real(mo_set%nelectron,
dp)
561 nelec = mo_set%n_el_f
564 mo_set%occupation_numbers(:) = 0.0_dp
566 CALL probe_occupancy(mo_set%occupation_numbers, mo_set%mu, mo_set%kTS, &
567 mo_set%eigenvalues, mo_set%mo_coeff, mo_set%maxocc, &
572 DO imo = i_first, nmo
573 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
578 is_large = abs(maxval(mo_set%occupation_numbers) - mo_set%maxocc) > probe(1)%eps_hp
581 cpwarn(
"Hair-probes occupancy distribution includes the first MO")
584 DO imo = nmo, mo_set%lfomo, -1
585 IF (mo_set%occupation_numbers(imo) > probe(1)%eps_hp)
THEN
590 is_large = abs(minval(mo_set%occupation_numbers)) > probe(1)%eps_hp
592 CALL cp_warn(__location__, &
593 "Hair-probes occupancy distribution includes the last MO => "// &
594 "Add more MOs for proper smearing.")
597 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > probe(1)%eps_hp*nelec)
599 cpwarn(
"Total number of electrons is not accurate")
604 IF (.NOT.
PRESENT(smear))
THEN
606 mo_set%uniform_occupation = .true.
607 IF (
PRESENT(eval_deriv))
THEN
610 CALL timestop(handle)
616 IF ((abs(mo_set%eigenvalues(1)) < 1.0e-12_dp) .AND. &
617 (abs(mo_set%eigenvalues(nmo)) < 1.0e-12_dp))
THEN
618 CALL timestop(handle)
624 IF (smear%do_smear)
THEN
625 IF (
PRESENT(xas_env))
THEN
626 i_first = xas_estate + 1
627 nelec = xas_nelectron
630 IF (smear%fixed_mag_mom == -1.0_dp)
THEN
631 nelec = real(mo_set%nelectron,
dp)
633 nelec = mo_set%n_el_f
636 SELECT CASE (smear%method)
638 IF (.NOT.
PRESENT(eval_deriv))
THEN
639 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
640 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
642 xas_estate, occ_estate)
644 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
645 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
646 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
647 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
649 tmp_v, xas_estate, occ_estate)
653 DO imo = i_first, nmo
654 IF (mo_set%occupation_numbers(imo) < mo_set%maxocc)
THEN
659 IF (i_first <= nmo)
THEN
660 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
665 cpwarn_if(is_large,
"Fermi-Dirac smearing includes the first MO")
668 DO imo = nmo, mo_set%lfomo, -1
669 IF (mo_set%occupation_numbers(imo) > smear%eps_fermi_dirac)
THEN
674 is_large = abs(minval(mo_set%occupation_numbers)) > smear%eps_fermi_dirac
676 CALL cp_warn(__location__, &
677 "Fermi-Dirac smearing includes the last MO => "// &
678 "Add more MOs for proper smearing.")
681 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
682 cpwarn_if(is_large,
"Total number of electrons is not accurate")
685 IF (.NOT.
PRESENT(eval_deriv))
THEN
686 CALL smearfixed(mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, mo_set%kTS, &
687 mo_set%eigenvalues(1:mo_set%nmo), nelec, &
688 smear%smearing_width, mo_set%maxocc, smear%method, &
689 xas_estate, occ_estate)
691 IF (.NOT.
ALLOCATED(tmp_v))
ALLOCATE (tmp_v(
SIZE(eval_deriv)))
692 tmp_v(:) = eval_deriv - mo_set%eigenvalues + mo_set%mu
693 CALL smearfixedderivmv(eval_deriv, mo_set%occupation_numbers(1:mo_set%nmo), mo_set%mu, &
694 mo_set%kTS, mo_set%eigenvalues(1:mo_set%nmo), nelec, &
695 smear%smearing_width, mo_set%maxocc, smear%method, &
696 tmp_v, xas_estate, occ_estate)
700 SELECT CASE (smear%method)
702 method_label =
"Gaussian"
704 method_label =
"Methfessel-Paxton"
706 method_label =
"Marzari-Vanderbilt"
710 DO imo = i_first, nmo
711 IF (abs(mo_set%occupation_numbers(imo) - mo_set%maxocc) > smear%eps_fermi_dirac)
THEN
716 IF (i_first <= nmo)
THEN
717 is_large = abs(mo_set%occupation_numbers(i_first) - mo_set%maxocc) > smear%eps_fermi_dirac
721 cpwarn_if(is_large, trim(method_label)//
" smearing includes the first MO")
724 DO imo = nmo, mo_set%lfomo, -1
725 IF (abs(mo_set%occupation_numbers(imo)) > smear%eps_fermi_dirac)
THEN
730 is_large = abs(mo_set%occupation_numbers(nmo)) > smear%eps_fermi_dirac
732 CALL cp_warn(__location__, &
733 trim(method_label)//
" smearing includes the last MO => "// &
734 "Add more MOs for proper smearing.")
737 is_large = (abs(nelec -
accurate_sum(mo_set%occupation_numbers(:))) > smear%eps_fermi_dirac*nelec)
738 cpwarn_if(is_large,
"Total number of electrons is not accurate")
742 cpassert(.NOT.
PRESENT(eval_deriv))
745 e1 = mo_set%eigenvalues(mo_set%homo) - 0.5_dp*smear%window_size
746 IF (e1 <= mo_set%eigenvalues(1))
THEN
747 cpwarn(
"Energy window for smearing includes the first MO")
750 e2 = mo_set%eigenvalues(mo_set%homo) + 0.5_dp*smear%window_size
751 IF (e2 >= mo_set%eigenvalues(nmo)) &
752 CALL cp_warn(__location__, &
753 "Energy window for smearing includes the last MO => "// &
754 "Add more MOs for proper smearing.")
757 DO imo = i_first, nomo
758 IF (mo_set%eigenvalues(imo) > e1)
THEN
765 DO imo = nmo, nomo, -1
766 IF (mo_set%eigenvalues(imo) < e2)
THEN
776 DO imo = mo_set%lfomo, mo_set%homo
777 nelec = nelec + mo_set%occupation_numbers(imo)
778 edist = edist + abs(e2 - mo_set%eigenvalues(imo))
782 DO imo = mo_set%lfomo, mo_set%homo
783 edelta = abs(e2 - mo_set%eigenvalues(imo))
784 mo_set%occupation_numbers(imo) = min(mo_set%maxocc, nelec*edelta/edist)
785 nelec = nelec - mo_set%occupation_numbers(imo)
786 edist = edist - edelta
790 equal_size =
SIZE(mo_set%occupation_numbers, 1) ==
SIZE(smear%list, 1)
792 mo_set%occupation_numbers = smear%list
794 IF (
PRESENT(eval_deriv))
THEN
803 IF (mo_set%lfomo == mo_set%homo)
THEN
805 mo_set%lfomo = nomo + 1
807 mo_set%uniform_occupation = .false.
815 IF (
ALLOCATED(tmp_v))
DEALLOCATE (tmp_v)
816 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)
...