Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Unified smearing module supporting four methods:
10 : !> smear_fermi_dirac — Fermi-Dirac distribution
11 : !> smear_gaussian — Gaussian broadening
12 : !> smear_mp — Methfessel-Paxton first order
13 : !> smear_mv — Marzari-Vanderbilt (cold smearing)
14 : !>
15 : !> All methods share the bisection framework, LFOMO/HOMO logic, and the
16 : !> analytical rank-1 Jacobian. Only the per-state math (f, kTS, g_i)
17 : !> differs, selected via a method integer from input_constants.
18 : !>
19 : !> \par History
20 : !> 09.2008: Created (fermi_utils.F)
21 : !> 02.2026: Extended to more smearing method and renamed
22 : !> \author Joost VandeVondele
23 : ! **************************************************************************************************
24 : MODULE smearing_utils
25 :
26 : USE bibliography, ONLY: FuHo1983,&
27 : Marzari1999,&
28 : Mermin1965,&
29 : MethfesselPaxton1989,&
30 : cite_reference,&
31 : dosSantos2023
32 : USE input_constants, ONLY: smear_fermi_dirac,&
33 : smear_gaussian,&
34 : smear_mp,&
35 : smear_mv
36 : USE kahan_sum, ONLY: accurate_sum
37 : USE kinds, ONLY: dp
38 : USE mathconstants, ONLY: rootpi,&
39 : sqrt2,&
40 : sqrthalf
41 : #include "base/base_uses.f90"
42 :
43 : IMPLICIT NONE
44 :
45 : PRIVATE
46 :
47 : ! Unified interface (method as parameter)
48 : PUBLIC :: SmearOcc, SmearFixed, SmearFixedDeriv, SmearFixedDerivMV
49 : PUBLIC :: Smearkp, Smearkp2
50 : PUBLIC :: smearing_response_weight
51 : PUBLIC :: smearing_separate_spin, smearing_spin_targets
52 : PRIVATE :: cite_smearing
53 :
54 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'smearing_utils'
55 : INTEGER, PARAMETER, PRIVATE :: BISECT_MAX_ITER = 400
56 : INTEGER, PARAMETER, PRIVATE :: NEWTON_MAX_ITER = 50
57 : INTEGER, PARAMETER, PRIVATE :: NEWTON_MAX_BACKTRACK = 20
58 : REAL(KIND=dp), PARAMETER, PRIVATE :: MPMV_MAX_NEWTON_STEP = 2.0_dp
59 :
60 : CONTAINS
61 : ! **************************************************************************************************
62 : !> \brief Whether a smearing constraint fixes the separate spin populations.
63 : !> \param fixed_mag_mom Requested spin difference, or a negative constraint selector.
64 : !> \return True for a prescribed moment or the integer-population selector -1.
65 : ! **************************************************************************************************
66 40606 : PURE LOGICAL FUNCTION smearing_separate_spin(fixed_mag_mom)
67 : REAL(KIND=dp), INTENT(IN) :: fixed_mag_mom
68 :
69 40606 : smearing_separate_spin = fixed_mag_mom >= 0.0_dp .OR. fixed_mag_mom == -1.0_dp
70 40606 : END FUNCTION smearing_separate_spin
71 :
72 : ! **************************************************************************************************
73 : !> \brief Resolve real-valued spin targets without rounding a prescribed moment.
74 : !> \param nelectron Initial integer spin populations.
75 : !> \param fixed_mag_mom Prescribed difference, or a negative constraint selector.
76 : !> \return Target populations. Negative selectors preserve the initial populations.
77 : ! **************************************************************************************************
78 41622 : PURE FUNCTION smearing_spin_targets(nelectron, fixed_mag_mom) RESULT(targets)
79 : INTEGER, DIMENSION(2), INTENT(IN) :: nelectron
80 : REAL(KIND=dp), INTENT(IN) :: fixed_mag_mom
81 : REAL(KIND=dp), DIMENSION(2) :: targets
82 :
83 : REAL(KIND=dp) :: total
84 :
85 124866 : targets(:) = REAL(nelectron, dp)
86 41622 : IF (fixed_mag_mom >= 0.0_dp) THEN
87 840 : total = SUM(targets)
88 280 : targets(1) = 0.5_dp*(total + fixed_mag_mom)
89 280 : targets(2) = 0.5_dp*(total - fixed_mag_mom)
90 : END IF
91 41622 : END FUNCTION smearing_spin_targets
92 :
93 : ! **************************************************************************************************
94 : !> \brief Citation of Smearing methods
95 : !> \param method ...
96 : ! **************************************************************************************************
97 70926 : SUBROUTINE cite_smearing(method)
98 : INTEGER, INTENT(IN) :: method
99 :
100 112234 : SELECT CASE (method)
101 : CASE (smear_fermi_dirac)
102 41308 : CALL cite_reference(Mermin1965)
103 : CASE (smear_gaussian)
104 29334 : CALL cite_reference(FuHo1983)
105 : CASE (smear_mp)
106 142 : CALL cite_reference(FuHo1983)
107 142 : CALL cite_reference(MethfesselPaxton1989)
108 142 : CALL cite_reference(dosSantos2023)
109 : CASE (smear_mv)
110 142 : CALL cite_reference(FuHo1983)
111 142 : CALL cite_reference(Marzari1999)
112 71068 : CALL cite_reference(dosSantos2023)
113 : END SELECT
114 70926 : END SUBROUTINE cite_smearing
115 :
116 : ! **************************************************************************************************
117 : !> \brief Returns occupations and smearing correction for a given set of
118 : !> energies and chemical potential, using one of four smearing methods.
119 : !>
120 : !> Fermi-Dirac: f_i = occ / [1 + exp((e_i - mu)/sigma)]
121 : !> Gaussian: f_i = (occ/2) * erfc[(e_i - mu)/sigma]
122 : !> MP-1: f_i = (occ/2) * erfc(x) - occ*x/(2*sqrt(pi)) * exp(-x^2)
123 : !> MV: f_i = (occ/2) * erfc(u) + occ/(sqrt(2*pi)) * exp(-u^2), u = x + 1/sqrt(2)
124 : !>
125 : !> kTS is the smearing correction to the free energy (physically -TS
126 : !> for Fermi-Dirac; a variational correction term for the other methods).
127 : !> It enters the total energy and the Gillan extrapolation E(0) = E - kTS/2.
128 : !>
129 : !> \param f occupations (output)
130 : !> \param N total number of electrons (output)
131 : !> \param kTS smearing correction to the free energy (output)
132 : !> \param e eigenvalues (input)
133 : !> \param mu chemical potential (input)
134 : !> \param sigma smearing width: kT for Fermi-Dirac, sigma for others (input)
135 : !> \param maxocc maximum occupation of an orbital (input)
136 : !> \param method smearing method selector from input_constants (input)
137 : !> \param estate excited state index for core-level spectroscopy (optional)
138 : !> \param festate occupation of the excited state (optional)
139 : ! **************************************************************************************************
140 1506476 : SUBROUTINE SmearOcc(f, N, kTS, e, mu, sigma, maxocc, method, estate, festate)
141 :
142 : REAL(KIND=dp), INTENT(OUT) :: f(:), N, kTS
143 : REAL(KIND=dp), INTENT(IN) :: e(:), mu, sigma, maxocc
144 : INTEGER, INTENT(IN) :: method
145 : INTEGER, INTENT(IN), OPTIONAL :: estate
146 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: festate
147 :
148 : INTEGER :: i, Nstate
149 : REAL(KIND=dp) :: arg, expu2, expx2, occupation, term1, &
150 : term2, tmp, tmp2, tmp3, tmp4, tmplog, &
151 : u, x
152 :
153 1506476 : Nstate = SIZE(e)
154 1506476 : kTS = 0.0_dp
155 :
156 43752920 : DO i = 1, Nstate
157 42246444 : IF (PRESENT(estate) .AND. PRESENT(festate)) THEN
158 42202196 : IF (i == estate) THEN
159 4834 : occupation = festate
160 : ELSE
161 42197362 : occupation = maxocc
162 : END IF
163 : ELSE
164 44248 : occupation = maxocc
165 : END IF
166 :
167 1506476 : SELECT CASE (method)
168 : CASE (smear_fermi_dirac)
169 39909538 : IF (e(i) > mu) THEN
170 24635239 : arg = -(e(i) - mu)/sigma
171 24635239 : tmp = EXP(arg)
172 24635239 : tmp4 = tmp + 1.0_dp
173 24635239 : tmp2 = tmp/tmp4
174 24635239 : tmp3 = 1.0_dp/tmp4
175 24635239 : tmplog = -LOG(tmp4)
176 24635239 : term1 = tmp2*(arg + tmplog)
177 24635239 : term2 = tmp3*tmplog
178 : ELSE
179 15274299 : arg = (e(i) - mu)/sigma
180 15274299 : tmp = EXP(arg)
181 15274299 : tmp4 = tmp + 1.0_dp
182 15274299 : tmp2 = 1.0_dp/tmp4
183 15274299 : tmp3 = tmp/tmp4
184 15274299 : tmplog = -LOG(tmp4)
185 15274299 : term1 = tmp2*tmplog
186 15274299 : term2 = tmp3*(arg + tmplog)
187 : END IF
188 39909538 : f(i) = occupation*tmp2
189 39909538 : kTS = kTS + sigma*occupation*(term1 + term2)
190 :
191 : CASE (smear_gaussian)
192 2330218 : x = (e(i) - mu)/sigma
193 2330218 : expx2 = EXP(-x*x)
194 2330218 : f(i) = occupation*0.5_dp*ERFC(x)
195 2330218 : kTS = kTS - (sigma/(2.0_dp*rootpi))*occupation*expx2
196 :
197 : CASE (smear_mp)
198 2128 : x = (e(i) - mu)/sigma
199 2128 : expx2 = EXP(-x*x)
200 2128 : f(i) = occupation*(0.5_dp*ERFC(x) - x/(2.0_dp*rootpi)*expx2)
201 2128 : kTS = kTS + (sigma/(4.0_dp*rootpi))*occupation*(2.0_dp*x*x - 1.0_dp)*expx2
202 :
203 : CASE (smear_mv)
204 4560 : x = (e(i) - mu)/sigma
205 4560 : u = x + sqrthalf
206 4560 : expu2 = EXP(-u*u)
207 4560 : f(i) = occupation*(0.5_dp*ERFC(u) + expu2/(sqrt2*rootpi))
208 4560 : kTS = kTS - (sigma/(sqrt2*rootpi))*occupation*u*expu2
209 :
210 : CASE DEFAULT
211 42246444 : CPABORT("SmearOcc: unknown smearing method")
212 : END SELECT
213 : END DO
214 :
215 1506476 : N = accurate_sum(f)
216 :
217 1506476 : END SUBROUTINE SmearOcc
218 :
219 : ! **************************************************************************************************
220 : !> \brief k-point version of SmearOcc (module-private).
221 : !> Computes occupations and kTS for a 2D array of eigenvalues
222 : !> (nmo x nkp) weighted by k-point weights.
223 : !> Falls back to a step function when sigma < 1e-14.
224 : !>
225 : !> \param f occupations (nmo x nkp, output)
226 : !> \param nel total number of electrons (output)
227 : !> \param kTS smearing correction (output)
228 : !> \param e eigenvalues (nmo x nkp, input)
229 : !> \param mu chemical potential (input)
230 : !> \param wk k-point weights (input)
231 : !> \param sigma smearing width (input)
232 : !> \param maxocc maximum occupation (input)
233 : !> \param method smearing method selector (input)
234 : ! **************************************************************************************************
235 353742 : SUBROUTINE Smear2(f, nel, kTS, e, mu, wk, sigma, maxocc, method)
236 :
237 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: f
238 : REAL(KIND=dp), INTENT(OUT) :: nel, kTS
239 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: e
240 : REAL(KIND=dp), INTENT(IN) :: mu
241 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wk
242 : REAL(KIND=dp), INTENT(IN) :: sigma, maxocc
243 : INTEGER, INTENT(IN) :: method
244 :
245 : INTEGER :: ik, is, nkp, nmo
246 : REAL(KIND=dp) :: arg, expu2, expx2, term1, term2, tmp, &
247 : tmp2, tmp3, tmp4, tmplog, u, x
248 :
249 353742 : nmo = SIZE(e, 1)
250 353742 : nkp = SIZE(e, 2)
251 353742 : kTS = 0.0_dp
252 :
253 353742 : IF (sigma > 1.0e-14_dp) THEN
254 1177366 : DO ik = 1, nkp
255 20880204 : DO is = 1, nmo
256 907722 : SELECT CASE (method)
257 : CASE (smear_fermi_dirac)
258 18593568 : IF (e(is, ik) > mu) THEN
259 10886776 : arg = -(e(is, ik) - mu)/sigma
260 10886776 : tmp = EXP(arg)
261 10886776 : tmp4 = tmp + 1.0_dp
262 10886776 : tmp2 = tmp/tmp4
263 10886776 : tmp3 = 1.0_dp/tmp4
264 10886776 : tmplog = -LOG(tmp4)
265 10886776 : term1 = tmp2*(arg + tmplog)
266 10886776 : term2 = tmp3*tmplog
267 : ELSE
268 7706792 : arg = (e(is, ik) - mu)/sigma
269 7706792 : tmp = EXP(arg)
270 7706792 : tmp4 = tmp + 1.0_dp
271 7706792 : tmp2 = 1.0_dp/tmp4
272 7706792 : tmp3 = tmp/tmp4
273 7706792 : tmplog = -LOG(tmp4)
274 7706792 : term1 = tmp2*tmplog
275 7706792 : term2 = tmp3*(arg + tmplog)
276 : END IF
277 18593568 : f(is, ik) = maxocc*tmp2
278 18593568 : kTS = kTS + sigma*maxocc*(term1 + term2)*wk(ik)
279 :
280 : CASE (smear_gaussian)
281 1001750 : x = (e(is, ik) - mu)/sigma
282 1001750 : expx2 = EXP(-x*x)
283 1001750 : f(is, ik) = maxocc*0.5_dp*ERFC(x)
284 1001750 : kTS = kTS - (sigma/(2.0_dp*rootpi))*maxocc*expx2*wk(ik)
285 :
286 : CASE (smear_mp)
287 50096 : x = (e(is, ik) - mu)/sigma
288 50096 : expx2 = EXP(-x*x)
289 50096 : f(is, ik) = maxocc*(0.5_dp*ERFC(x) - x/(2.0_dp*rootpi)*expx2)
290 50096 : kTS = kTS + (sigma/(4.0_dp*rootpi))*maxocc*(2.0_dp*x*x - 1.0_dp)*expx2*wk(ik)
291 :
292 : CASE (smear_mv)
293 57424 : x = (e(is, ik) - mu)/sigma
294 57424 : u = x + sqrthalf
295 57424 : expu2 = EXP(-u*u)
296 57424 : f(is, ik) = maxocc*(0.5_dp*ERFC(u) + expu2/(sqrt2*rootpi))
297 57424 : kTS = kTS - (sigma/(sqrt2*rootpi))*maxocc*u*expu2*wk(ik)
298 :
299 : CASE DEFAULT
300 19702838 : CPABORT("Smear2: unknown smearing method")
301 : END SELECT
302 : END DO
303 : END DO
304 : ELSE
305 : ! Zero-width limit: step function
306 345408 : DO ik = 1, nkp
307 2799428 : DO is = 1, nmo
308 2715330 : IF (e(is, ik) <= mu) THEN
309 1571842 : f(is, ik) = maxocc
310 : ELSE
311 882178 : f(is, ik) = 0.0_dp
312 : END IF
313 : END DO
314 : END DO
315 : END IF
316 :
317 353742 : nel = 0.0_dp
318 1522774 : DO ik = 1, nkp
319 1522774 : nel = nel + accurate_sum(f(1:nmo, ik))*wk(ik)
320 : END DO
321 :
322 353742 : END SUBROUTINE Smear2
323 :
324 : ! **************************************************************************************************
325 : !> \brief Bisection search for the chemical potential mu such that the total
326 : !> electron count equals N, for a given smearing method (Gamma point).
327 : !> Brackets mu by expanding outward from [min(e), max(e)] in steps
328 : !> of sigma, then bisects to machine precision.
329 : !>
330 : !> For MP-1 and MV: the occupation function is non-monotonic, so it's
331 : !> possible that pure bisection find a spurious root.
332 : !> We first bisect with Gaussian smearing to get a reliable initial mu,
333 : !> then refine with Newton's method using the actual method's dN/dmu.
334 : !> (dos Santos & Marzari, PRB 2023)
335 : !>
336 : !> \param f occupations (output)
337 : !> \param mu chemical potential found by bisection (output)
338 : !> \param kTS smearing correction (output)
339 : !> \param e eigenvalues (input)
340 : !> \param N target number of electrons (input)
341 : !> \param sigma smearing width (input)
342 : !> \param maxocc maximum occupation (input)
343 : !> \param method smearing method selector (input)
344 : !> \param estate excited state index for core-level spectroscopy (optional)
345 : !> \param festate occupation of the excited state (optional)
346 : ! **************************************************************************************************
347 26856 : SUBROUTINE SmearFixed(f, mu, kTS, e, N, sigma, maxocc, method, estate, festate)
348 :
349 : REAL(KIND=dp), INTENT(OUT) :: f(:), mu, kTS
350 : REAL(KIND=dp), INTENT(IN) :: e(:), N, sigma, maxocc
351 : INTEGER, INTENT(IN) :: method
352 : INTEGER, INTENT(IN), OPTIONAL :: estate
353 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: festate
354 :
355 : INTEGER :: iback, iter, my_estate, Nstate
356 : REAL(KIND=dp) :: Gsum, mu_best, mu_max, mu_min, mu_now, mu_trial, my_festate, N_now, N_tmp, &
357 : N_trial, res_best, res_now, res_trial, step, step_try
358 26856 : REAL(KIND=dp), ALLOCATABLE :: gvec(:)
359 :
360 26856 : IF (PRESENT(estate) .AND. PRESENT(festate)) THEN
361 26800 : my_estate = estate
362 26800 : my_festate = festate
363 : ELSE
364 56 : my_estate = NINT(maxocc)
365 56 : my_festate = my_estate
366 : END IF
367 :
368 26856 : Nstate = SIZE(e)
369 :
370 26856 : CALL cite_smearing(method)
371 :
372 26856 : SELECT CASE (method)
373 :
374 : ! Non-monotonic methods: Gaussian bisection + Newton refinement
375 : CASE (smear_mp, smear_mv)
376 : ! Step 1: Gaussian bisection for a reliable initial mu
377 160 : mu_min = MINVAL(e)
378 8 : iter = 0
379 6 : DO
380 14 : iter = iter + 1
381 14 : CALL SmearOcc(f, N_tmp, kTS, e, mu_min, sigma, maxocc, smear_gaussian, my_estate, my_festate)
382 14 : IF (N_tmp <= N) EXIT
383 6 : IF (iter > 20) THEN
384 0 : CPABORT("SmearFixed: failed to bracket lower chemical potential")
385 : END IF
386 6 : mu_min = mu_min - sigma
387 : END DO
388 :
389 160 : mu_max = MAXVAL(e)
390 8 : iter = 0
391 0 : DO
392 8 : iter = iter + 1
393 8 : CALL SmearOcc(f, N_tmp, kTS, e, mu_max, sigma, maxocc, smear_gaussian, my_estate, my_festate)
394 8 : IF (N_tmp >= N) EXIT
395 0 : IF (iter > 20) THEN
396 0 : CPABORT("SmearFixed: failed to bracket upper chemical potential")
397 : END IF
398 0 : mu_max = mu_max + sigma
399 : END DO
400 :
401 : iter = 0
402 378 : DO WHILE (mu_max - mu_min > EPSILON(mu)*MAX(1.0_dp, ABS(mu_max), ABS(mu_min)))
403 370 : iter = iter + 1
404 370 : mu_now = (mu_max + mu_min)/2.0_dp
405 370 : CALL SmearOcc(f, N_now, kTS, e, mu_now, sigma, maxocc, smear_gaussian, my_estate, my_festate)
406 370 : IF (N_now <= N) THEN
407 192 : mu_min = mu_now
408 : ELSE
409 178 : mu_max = mu_now
410 : END IF
411 378 : IF (iter > BISECT_MAX_ITER) EXIT
412 : END DO
413 8 : mu = (mu_max + mu_min)/2.0_dp
414 :
415 : ! Step 2: damped Newton refinement with the actual method. MP/MV
416 : ! occupations are not monotonic functions of mu, therefore an
417 : ! unrestricted Newton step can jump to a remote root or increase the
418 : ! electron-count residual. Keep the root closest to the Gaussian
419 : ! solution by accepting only residual-reducing, size-limited steps.
420 24 : ALLOCATE (gvec(Nstate))
421 8 : CALL SmearOcc(f, N_now, kTS, e, mu, sigma, maxocc, method, my_estate, my_festate)
422 8 : res_best = ABS(N_now - N)
423 8 : mu_best = mu
424 30 : DO iter = 1, NEWTON_MAX_ITER
425 30 : res_now = ABS(N_now - N)
426 30 : IF (res_now < N*1.0e-12_dp) EXIT
427 : CALL smearing_response_weight( &
428 22 : gvec, f, e, mu, sigma, maxocc, Nstate, method, my_estate, my_festate)
429 22 : Gsum = accurate_sum(gvec)
430 22 : IF (ABS(Gsum) < EPSILON(Gsum)) EXIT
431 :
432 22 : step = (N - N_now)/Gsum
433 22 : step = SIGN(MIN(ABS(step), MPMV_MAX_NEWTON_STEP*sigma), step)
434 22 : step_try = step
435 22 : DO iback = 1, NEWTON_MAX_BACKTRACK
436 22 : mu_trial = mu + step_try
437 : CALL SmearOcc(f, N_trial, kTS, e, mu_trial, sigma, maxocc, method, &
438 22 : my_estate, my_festate)
439 22 : res_trial = ABS(N_trial - N)
440 22 : IF (res_trial < res_now) THEN
441 22 : mu = mu_trial
442 22 : N_now = N_trial
443 22 : IF (res_trial < res_best) THEN
444 22 : res_best = res_trial
445 22 : mu_best = mu
446 : END IF
447 : EXIT
448 : END IF
449 0 : step_try = 0.5_dp*step_try
450 : END DO
451 8 : IF (iback > NEWTON_MAX_BACKTRACK) EXIT
452 : END DO
453 8 : DEALLOCATE (gvec)
454 8 : mu = mu_best
455 :
456 : ! Final evaluation
457 8 : CALL SmearOcc(f, N_now, kTS, e, mu, sigma, maxocc, method, my_estate, my_festate)
458 8 : IF (ABS(N_now - N) >= N*1.0e-12_dp) THEN
459 0 : CPWARN("SmearFixed: MP/MV smearing did not reach the requested electron count")
460 : END IF
461 :
462 : ! Monotonic methods (FD, Gaussian): pure bisection
463 : CASE DEFAULT
464 774420 : mu_min = MINVAL(e)
465 26848 : iter = 0
466 22 : DO
467 26870 : iter = iter + 1
468 26870 : CALL SmearOcc(f, N_tmp, kTS, e, mu_min, sigma, maxocc, method, my_estate, my_festate)
469 26870 : IF (N_tmp <= N) EXIT
470 22 : IF (iter > 20) THEN
471 0 : CPABORT("SmearFixed: failed to bracket lower chemical potential")
472 : END IF
473 22 : mu_min = mu_min - sigma
474 : END DO
475 :
476 774420 : mu_max = MAXVAL(e)
477 26848 : iter = 0
478 0 : DO
479 26848 : iter = iter + 1
480 26848 : CALL SmearOcc(f, N_tmp, kTS, e, mu_max, sigma, maxocc, method, my_estate, my_festate)
481 26848 : IF (N_tmp >= N) EXIT
482 0 : IF (iter > 20) THEN
483 0 : CPABORT("SmearFixed: failed to bracket upper chemical potential")
484 : END IF
485 0 : mu_max = mu_max + sigma
486 : END DO
487 :
488 : iter = 0
489 1451588 : DO WHILE (mu_max - mu_min > EPSILON(mu)*MAX(1.0_dp, ABS(mu_max), ABS(mu_min)))
490 1424740 : iter = iter + 1
491 1424740 : mu_now = (mu_max + mu_min)/2.0_dp
492 1424740 : CALL SmearOcc(f, N_now, kTS, e, mu_now, sigma, maxocc, method, my_estate, my_festate)
493 1424740 : IF (N_now <= N) THEN
494 700587 : mu_min = mu_now
495 : ELSE
496 724153 : mu_max = mu_now
497 : END IF
498 1451588 : IF (iter > BISECT_MAX_ITER) THEN
499 0 : CPWARN("SmearFixed: maximum bisection iterations reached")
500 0 : EXIT
501 : END IF
502 : END DO
503 :
504 26848 : mu = (mu_max + mu_min)/2.0_dp
505 53704 : CALL SmearOcc(f, N_now, kTS, e, mu, sigma, maxocc, method, my_estate, my_festate)
506 :
507 : END SELECT
508 :
509 26856 : END SUBROUTINE SmearFixed
510 :
511 : ! **************************************************************************************************
512 : !> \brief Bisection search for mu given a target electron count (k-point case,
513 : !> single spin channel or spin-degenerate).
514 : !> Initial bracket width is max(10*sigma, 0.5) for Gaussian/MP/MV,
515 : !> or sigma*ln[(1-eps)/eps] for Fermi-Dirac, reflecting the different
516 : !> tail decay rates.
517 : !>
518 : !> For MP-1 and MV: Gaussian bisection + Newton refinement
519 : !> (dos Santos & Marzari, PRB 2023).
520 : !>
521 : !> \param f occupations (nmo x nkp, output)
522 : !> \param mu chemical potential (output)
523 : !> \param kTS smearing correction (output)
524 : !> \param e eigenvalues (nmo x nkp, input)
525 : !> \param nel target number of electrons (input)
526 : !> \param wk k-point weights (input)
527 : !> \param sigma smearing width (input)
528 : !> \param maxocc maximum occupation (input)
529 : !> \param method smearing method selector (input)
530 : ! **************************************************************************************************
531 43538 : SUBROUTINE Smearkp(f, mu, kTS, e, nel, wk, sigma, maxocc, method)
532 :
533 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: f
534 : REAL(KIND=dp), INTENT(OUT) :: mu, kTS
535 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: e
536 : REAL(KIND=dp), INTENT(IN) :: nel
537 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wk
538 : REAL(KIND=dp), INTENT(IN) :: sigma, maxocc
539 : INTEGER, INTENT(IN) :: method
540 :
541 : REAL(KIND=dp), PARAMETER :: epsocc = 1.0e-12_dp
542 :
543 : INTEGER :: bisect_method, iback, ik, is, iter, nkp, &
544 : nmo
545 : REAL(KIND=dp) :: de, dNdmu, expu2, expx2, mu_best, &
546 : mu_max, mu_min, N_now, N_trial, &
547 : res_best, res_now, res_trial, step, &
548 : step_try, u, x
549 :
550 43538 : nmo = SIZE(e, 1)
551 43538 : nkp = SIZE(e, 2)
552 :
553 43538 : CALL cite_smearing(method)
554 :
555 : ! Choose bisection method: Gaussian for MP/MV, actual method for FD/Gaussian
556 43814 : SELECT CASE (method)
557 : CASE (smear_mp, smear_mv)
558 276 : bisect_method = smear_gaussian
559 : CASE DEFAULT
560 43538 : bisect_method = method
561 : END SELECT
562 :
563 : ! Initial bracket
564 15524 : SELECT CASE (bisect_method)
565 : CASE (smear_fermi_dirac)
566 15524 : de = sigma*LOG((1.0_dp - epsocc)/epsocc)
567 : CASE DEFAULT
568 43538 : de = 10.0_dp*sigma
569 : END SELECT
570 43538 : de = MAX(de, 0.5_dp)
571 :
572 : ! Bisection with bisect_method
573 2380080 : mu_min = MINVAL(e) - de
574 2380080 : mu_max = MAXVAL(e) + de
575 43538 : iter = 0
576 299670 : DO WHILE (mu_max - mu_min > EPSILON(mu)*MAX(1.0_dp, ABS(mu_max), ABS(mu_min)))
577 299652 : iter = iter + 1
578 299652 : mu = (mu_max + mu_min)/2.0_dp
579 299652 : CALL Smear2(f, N_now, kTS, e, mu, wk, sigma, maxocc, bisect_method)
580 :
581 299652 : IF (ABS(N_now - nel) < nel*epsocc) EXIT
582 :
583 256132 : IF (N_now <= nel) THEN
584 137440 : mu_min = mu
585 : ELSE
586 118692 : mu_max = mu
587 : END IF
588 :
589 299670 : IF (iter > BISECT_MAX_ITER) THEN
590 0 : CPWARN("Smearkp: maximum bisection iterations reached")
591 0 : EXIT
592 : END IF
593 : END DO
594 43538 : mu = (mu_max + mu_min)/2.0_dp
595 :
596 : ! Damped Newton refinement for non-monotonic methods. Accept only
597 : ! residual-reducing steps and limit the displacement from the local
598 : ! Gaussian solution to avoid jumping to a remote MP/MV root.
599 276 : SELECT CASE (method)
600 : CASE (smear_mp, smear_mv)
601 276 : CALL Smear2(f, N_now, kTS, e, mu, wk, sigma, maxocc, method)
602 276 : res_best = ABS(N_now - nel)
603 276 : mu_best = mu
604 1132 : DO iter = 1, NEWTON_MAX_ITER
605 1132 : res_now = ABS(N_now - nel)
606 1132 : IF (res_now < nel*epsocc) EXIT
607 :
608 : ! Compute dN/dmu = sum_{ik} wk * g_i(k) inline
609 : dNdmu = 0.0_dp
610 8448 : DO ik = 1, nkp
611 76544 : DO is = 1, nmo
612 68096 : x = (e(is, ik) - mu)/sigma
613 7592 : SELECT CASE (method)
614 : CASE (smear_mp)
615 30384 : expx2 = EXP(-x*x)
616 30384 : dNdmu = dNdmu + maxocc*(3.0_dp - 2.0_dp*x*x)/(2.0_dp*sigma*rootpi)*expx2*wk(ik)
617 : CASE (smear_mv)
618 37712 : u = x + sqrthalf
619 37712 : expu2 = EXP(-u*u)
620 68096 : dNdmu = dNdmu + maxocc*(2.0_dp + sqrt2*x)/(sigma*rootpi)*expu2*wk(ik)
621 : END SELECT
622 : END DO
623 : END DO
624 :
625 856 : IF (ABS(dNdmu) < EPSILON(dNdmu)) EXIT
626 856 : step = (nel - N_now)/dNdmu
627 856 : step = SIGN(MIN(ABS(step), MPMV_MAX_NEWTON_STEP*sigma), step)
628 856 : step_try = step
629 856 : DO iback = 1, NEWTON_MAX_BACKTRACK
630 856 : CALL Smear2(f, N_trial, kTS, e, mu + step_try, wk, sigma, maxocc, method)
631 856 : res_trial = ABS(N_trial - nel)
632 856 : IF (res_trial < res_now) THEN
633 856 : mu = mu + step_try
634 856 : N_now = N_trial
635 856 : IF (res_trial < res_best) THEN
636 856 : res_best = res_trial
637 856 : mu_best = mu
638 : END IF
639 : EXIT
640 : END IF
641 0 : step_try = 0.5_dp*step_try
642 : END DO
643 276 : IF (iback > NEWTON_MAX_BACKTRACK) EXIT
644 : END DO
645 43814 : mu = mu_best
646 : END SELECT
647 :
648 : ! Final evaluation with the actual method
649 43538 : CALL Smear2(f, N_now, kTS, e, mu, wk, sigma, maxocc, method)
650 276 : SELECT CASE (method)
651 : CASE (smear_mp, smear_mv)
652 43538 : IF (ABS(N_now - nel) >= nel*epsocc) THEN
653 0 : CPWARN("Smearkp: MP/MV smearing did not reach the requested electron count")
654 : END IF
655 : END SELECT
656 :
657 43538 : END SUBROUTINE Smearkp
658 :
659 : ! **************************************************************************************************
660 : !> \brief Bisection search for mu (k-point, spin-polarised with a shared
661 : !> chemical potential across both spin channels).
662 : !> Asserts that the third dimension of f and e is exactly 2.
663 : !>
664 : !> For MP-1 and MV: Gaussian bisection + Newton refinement.
665 : !>
666 : !> \param f occupations (nmo x nkp x 2, output)
667 : !> \param mu chemical potential (output)
668 : !> \param kTS smearing correction (output)
669 : !> \param e eigenvalues (nmo x nkp x 2, input)
670 : !> \param nel target total number of electrons (input)
671 : !> \param wk k-point weights (input)
672 : !> \param sigma smearing width (input)
673 : !> \param method smearing method selector (input)
674 : ! **************************************************************************************************
675 532 : SUBROUTINE Smearkp2(f, mu, kTS, e, nel, wk, sigma, method)
676 :
677 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT) :: f
678 : REAL(KIND=dp), INTENT(OUT) :: mu, kTS
679 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: e
680 : REAL(KIND=dp), INTENT(IN) :: nel
681 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wk
682 : REAL(KIND=dp), INTENT(IN) :: sigma
683 : INTEGER, INTENT(IN) :: method
684 :
685 : REAL(KIND=dp), PARAMETER :: epsocc = 1.0e-12_dp
686 :
687 : INTEGER :: bisect_method, iback, ik, is, ispin, &
688 : iter, nkp, nmo
689 : REAL(KIND=dp) :: de, dNdmu, expu2, expx2, kTSa, kTSb, mu_best, mu_max, mu_min, N_now, &
690 : N_trial, na, nb, res_best, res_now, res_trial, step, step_try, u, x
691 :
692 532 : CPASSERT(SIZE(f, 3) == 2 .AND. SIZE(e, 3) == 2)
693 :
694 532 : nmo = SIZE(e, 1)
695 532 : nkp = SIZE(e, 2)
696 :
697 532 : CALL cite_smearing(method)
698 :
699 532 : SELECT CASE (method)
700 : CASE (smear_mp, smear_mv)
701 0 : bisect_method = smear_gaussian
702 : CASE DEFAULT
703 532 : bisect_method = method
704 : END SELECT
705 :
706 500 : SELECT CASE (bisect_method)
707 : CASE (smear_fermi_dirac)
708 500 : de = sigma*LOG((1.0_dp - epsocc)/epsocc)
709 : CASE DEFAULT
710 532 : de = 10.0_dp*sigma
711 : END SELECT
712 532 : de = MAX(de, 0.5_dp)
713 :
714 : ! Bisection with bisect_method
715 32472 : mu_min = MINVAL(e) - de
716 32472 : mu_max = MAXVAL(e) + de
717 532 : iter = 0
718 4178 : DO WHILE (mu_max - mu_min > EPSILON(mu)*MAX(1.0_dp, ABS(mu_max), ABS(mu_min)))
719 4178 : iter = iter + 1
720 4178 : mu = (mu_max + mu_min)/2.0_dp
721 4178 : CALL Smear2(f(:, :, 1), na, kTSa, e(:, :, 1), mu, wk, sigma, 1.0_dp, bisect_method)
722 4178 : CALL Smear2(f(:, :, 2), nb, kTSb, e(:, :, 2), mu, wk, sigma, 1.0_dp, bisect_method)
723 4178 : N_now = na + nb
724 :
725 4178 : IF (ABS(N_now - nel) < nel*epsocc) EXIT
726 :
727 3646 : IF (N_now <= nel) THEN
728 1822 : mu_min = mu
729 : ELSE
730 1824 : mu_max = mu
731 : END IF
732 :
733 4178 : IF (iter > BISECT_MAX_ITER) THEN
734 0 : CPWARN("Smearkp2: maximum bisection iterations reached")
735 0 : EXIT
736 : END IF
737 : END DO
738 532 : mu = (mu_max + mu_min)/2.0_dp
739 :
740 : ! Damped Newton refinement for non-monotonic methods. Accept only
741 : ! residual-reducing steps and limit the displacement from the local
742 : ! Gaussian solution to avoid jumping to a remote MP/MV root.
743 0 : SELECT CASE (method)
744 : CASE (smear_mp, smear_mv)
745 0 : CALL Smear2(f(:, :, 1), na, kTSa, e(:, :, 1), mu, wk, sigma, 1.0_dp, method)
746 0 : CALL Smear2(f(:, :, 2), nb, kTSb, e(:, :, 2), mu, wk, sigma, 1.0_dp, method)
747 0 : N_now = na + nb
748 0 : res_best = ABS(N_now - nel)
749 0 : mu_best = mu
750 0 : DO iter = 1, NEWTON_MAX_ITER
751 0 : res_now = ABS(N_now - nel)
752 0 : IF (res_now < nel*epsocc) EXIT
753 :
754 : ! dN/dmu across both spin channels (maxocc=1 per spin)
755 : dNdmu = 0.0_dp
756 0 : DO ispin = 1, 2
757 0 : DO ik = 1, nkp
758 0 : DO is = 1, nmo
759 0 : x = (e(is, ik, ispin) - mu)/sigma
760 0 : SELECT CASE (method)
761 : CASE (smear_mp)
762 0 : expx2 = EXP(-x*x)
763 0 : dNdmu = dNdmu + (3.0_dp - 2.0_dp*x*x)/(2.0_dp*sigma*rootpi)*expx2*wk(ik)
764 : CASE (smear_mv)
765 0 : u = x + sqrthalf
766 0 : expu2 = EXP(-u*u)
767 0 : dNdmu = dNdmu + (2.0_dp + sqrt2*x)/(sigma*rootpi)*expu2*wk(ik)
768 : END SELECT
769 : END DO
770 : END DO
771 : END DO
772 :
773 0 : IF (ABS(dNdmu) < EPSILON(dNdmu)) EXIT
774 0 : step = (nel - N_now)/dNdmu
775 0 : step = SIGN(MIN(ABS(step), MPMV_MAX_NEWTON_STEP*sigma), step)
776 0 : step_try = step
777 0 : DO iback = 1, NEWTON_MAX_BACKTRACK
778 0 : CALL Smear2(f(:, :, 1), na, kTSa, e(:, :, 1), mu + step_try, wk, sigma, 1.0_dp, method)
779 0 : CALL Smear2(f(:, :, 2), nb, kTSb, e(:, :, 2), mu + step_try, wk, sigma, 1.0_dp, method)
780 0 : N_trial = na + nb
781 0 : res_trial = ABS(N_trial - nel)
782 0 : IF (res_trial < res_now) THEN
783 0 : mu = mu + step_try
784 0 : N_now = N_trial
785 0 : IF (res_trial < res_best) THEN
786 0 : res_best = res_trial
787 0 : mu_best = mu
788 : END IF
789 : EXIT
790 : END IF
791 0 : step_try = 0.5_dp*step_try
792 : END DO
793 0 : IF (iback > NEWTON_MAX_BACKTRACK) EXIT
794 : END DO
795 532 : mu = mu_best
796 : END SELECT
797 :
798 : ! Final evaluation with the actual method
799 532 : CALL Smear2(f(:, :, 1), na, kTSa, e(:, :, 1), mu, wk, sigma, 1.0_dp, method)
800 532 : CALL Smear2(f(:, :, 2), nb, kTSb, e(:, :, 2), mu, wk, sigma, 1.0_dp, method)
801 532 : N_now = na + nb
802 532 : kTS = kTSa + kTSb
803 0 : SELECT CASE (method)
804 : CASE (smear_mp, smear_mv)
805 532 : IF (ABS(N_now - nel) >= nel*epsocc) THEN
806 0 : CPWARN("Smearkp2: MP/MV smearing did not reach the requested electron count")
807 : END IF
808 : END SELECT
809 :
810 532 : END SUBROUTINE Smearkp2
811 :
812 : ! **************************************************************************************************
813 : !> \brief Computes the smearing weight vector g_i = -df_i/de_i with mu held
814 : !> fixed.
815 : !>
816 : !> Fermi-Dirac: g_i = occ * f_norm * (1 - f_norm) / sigma
817 : !> where f_norm = f_i/occ_i (overflow-safe, uses
818 : !> pre-computed f rather than re-evaluating exp)
819 : !> Gaussian: g_i = occ / (sigma*sqrt(pi)) * exp(-x^2)
820 : !> MP-1: g_i = occ * (3 - 2*x^2) / (2*sigma*sqrt(pi)) * exp(-x^2)
821 : !> MV: g_i = occ * (2 + sqrt(2)*x) / (sigma*sqrt(pi)) * exp(-u^2)
822 : !>
823 : !> Note: g_i can be negative for MP-1 (|x| > sqrt(3/2)) and MV
824 : !> (x < -sqrt(2)). Consequently, N(mu) is not guaranteed to be
825 : !> monotone and the Jacobian routines must guard against G = sum(g_i)
826 : !> being near zero.
827 : !>
828 : !> \param gvec weight vector (Nstate, output)
829 : !> \param f occupations from a prior SmearOcc/SmearFixed call (input)
830 : !> \param e eigenvalues (input)
831 : !> \param mu chemical potential (input)
832 : !> \param sigma smearing width (input)
833 : !> \param maxocc maximum occupation (input)
834 : !> \param Nstate number of states (input)
835 : !> \param method smearing method selector (input)
836 : !> \param estate excited state index (optional)
837 : !> \param festate occupation of the excited state (optional)
838 : ! **************************************************************************************************
839 4590 : SUBROUTINE smearing_response_weight( &
840 4590 : gvec, f, e, mu, sigma, maxocc, Nstate, method, estate, festate)
841 :
842 : REAL(KIND=dp), INTENT(OUT) :: gvec(:)
843 : REAL(KIND=dp), INTENT(IN) :: f(:), e(:), mu, sigma, maxocc
844 : INTEGER, INTENT(IN) :: Nstate, method
845 : INTEGER, INTENT(IN), OPTIONAL :: estate
846 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: festate
847 :
848 : INTEGER :: i
849 : REAL(KIND=dp) :: expu2, expx2, fi_norm, occ_i, u, x
850 :
851 35620 : DO i = 1, Nstate
852 31030 : IF (PRESENT(estate) .AND. PRESENT(festate)) THEN
853 418 : IF (i == estate) THEN
854 22 : occ_i = festate
855 : ELSE
856 396 : occ_i = maxocc
857 : END IF
858 : ELSE
859 30612 : occ_i = maxocc
860 : END IF
861 :
862 31030 : IF (occ_i < EPSILON(occ_i)) THEN
863 0 : gvec(i) = 0.0_dp
864 0 : CYCLE
865 : END IF
866 :
867 31030 : x = (e(i) - mu)/sigma
868 :
869 4590 : SELECT CASE (method)
870 : CASE (smear_fermi_dirac)
871 27864 : fi_norm = f(i)/occ_i
872 27864 : gvec(i) = occ_i*fi_norm*(1.0_dp - fi_norm)/sigma
873 :
874 : CASE (smear_gaussian)
875 916 : expx2 = EXP(-x*x)
876 916 : gvec(i) = occ_i/(sigma*rootpi)*expx2
877 :
878 : CASE (smear_mp)
879 1030 : expx2 = EXP(-x*x)
880 1030 : gvec(i) = occ_i*(3.0_dp - 2.0_dp*x*x)/(2.0_dp*sigma*rootpi)*expx2
881 :
882 : CASE (smear_mv)
883 1220 : u = x + sqrthalf
884 1220 : expu2 = EXP(-u*u)
885 31030 : gvec(i) = occ_i*(2.0_dp + sqrt2*x)/(sigma*rootpi)*expu2
886 :
887 : END SELECT
888 : END DO
889 :
890 4590 : END SUBROUTINE smearing_response_weight
891 :
892 : ! **************************************************************************************************
893 : !> \brief Analytical Jacobian df_i/de_j for any smearing method under the
894 : !> electron-number constraint sum(f) = N.
895 : !>
896 : !> Differentiating f_i(e, mu(e)) where mu is implicitly defined by
897 : !> the constraint yields:
898 : !>
899 : !> df_i/de_j = -delta_{ij} * g_i + g_i * g_j / G
900 : !>
901 : !> where g_i = -df_i/de_i (mu fixed) and G = sum(g_i).
902 : !> This is a diagonal matrix plus a symmetric rank-1 update.
903 : !> Building it costs O(N) for g, plus O(N^2) for the outer product.
904 : !>
905 : !> Replaces the original numerical finite-difference FermiFixedDeriv
906 : !> which required 2N bisection solves. Exact to machine precision
907 : !> for all four methods.
908 : !>
909 : !> \param dfde Jacobian matrix dfde(i,j) = df_i/de_j (Nstate x Nstate, output)
910 : !> \param f occupations (output)
911 : !> \param mu chemical potential (output)
912 : !> \param kTS smearing correction (output)
913 : !> \param e eigenvalues (input)
914 : !> \param N target number of electrons (input)
915 : !> \param sigma smearing width (input)
916 : !> \param maxocc maximum occupation (input)
917 : !> \param method smearing method selector (input)
918 : !> \param estate excited state index (optional)
919 : !> \param festate occupation of the excited state (optional)
920 : ! **************************************************************************************************
921 0 : SUBROUTINE SmearFixedDeriv(dfde, f, mu, kTS, e, N, sigma, maxocc, method, estate, festate)
922 :
923 : REAL(KIND=dp), INTENT(OUT) :: dfde(:, :), f(:), mu, kTS
924 : REAL(KIND=dp), INTENT(IN) :: e(:), N, sigma, maxocc
925 : INTEGER, INTENT(IN) :: method
926 : INTEGER, INTENT(IN), OPTIONAL :: estate
927 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: festate
928 :
929 : CHARACTER(len=*), PARAMETER :: routineN = 'SmearFixedDeriv'
930 :
931 : INTEGER :: handle, i, j, Nstate
932 : REAL(KIND=dp) :: Gsum
933 0 : REAL(KIND=dp), ALLOCATABLE :: gvec(:)
934 :
935 0 : CALL timeset(routineN, handle)
936 :
937 : ! Step 1: find mu and f
938 0 : CALL SmearFixed(f, mu, kTS, e, N, sigma, maxocc, method, estate, festate)
939 :
940 : ! Step 2: build g vector
941 0 : Nstate = SIZE(e)
942 0 : ALLOCATE (gvec(Nstate))
943 0 : CALL smearing_response_weight(gvec, f, e, mu, sigma, maxocc, Nstate, method, estate, festate)
944 0 : Gsum = accurate_sum(gvec)
945 :
946 : ! Step 3: assemble dfde(i,j) = -delta_{ij}*g_i + g_i*g_j/G
947 0 : IF (ABS(Gsum) > EPSILON(Gsum)) THEN
948 0 : DO j = 1, Nstate
949 0 : DO i = 1, Nstate
950 0 : dfde(i, j) = gvec(i)*gvec(j)/Gsum
951 : END DO
952 0 : dfde(j, j) = dfde(j, j) - gvec(j)
953 : END DO
954 : ELSE
955 0 : dfde(:, :) = 0.0_dp
956 : END IF
957 :
958 0 : DEALLOCATE (gvec)
959 0 : CALL timestop(handle)
960 :
961 0 : END SUBROUTINE SmearFixedDeriv
962 :
963 : ! **************************************************************************************************
964 : !> \brief Apply TRANSPOSE(df/de) to a vector WITHOUT forming the full N x N
965 : !> Jacobian. O(N) time and O(N) memory for all four methods.
966 : !>
967 : !> Exploiting the rank-1 structure of the constrained Jacobian:
968 : !>
969 : !> [J^T v]_j = g_j * (g . v / G - v_j)
970 : !>
971 : !> This replaces the pattern used in qs_mo_occupation:
972 : !> ALLOCATE(dfde(nmo,nmo))
973 : !> CALL SmearFixedDeriv(dfde, ...)
974 : !> RESULT = MATMUL(TRANSPOSE(dfde), v)
975 : !> DEALLOCATE(dfde)
976 : !> turning O(N^2) storage + O(N^2) MATMUL into O(N) throughout.
977 : !>
978 : !> Currently the sole caller (qs_ot_scf do_ener) is dead code, but
979 : !> this routine is ready for when it is enabled.
980 : !>
981 : !> \param RESULT output vector = TRANSPOSE(df/de) * v (Nstate, output)
982 : !> \param f occupations (output)
983 : !> \param mu chemical potential (output)
984 : !> \param kTS smearing correction (output)
985 : !> \param e eigenvalues (input)
986 : !> \param N_el target number of electrons (input)
987 : !> \param sigma smearing width (input)
988 : !> \param maxocc maximum occupation (input)
989 : !> \param method smearing method selector (input)
990 : !> \param v input vector to multiply (Nstate, input)
991 : !> \param estate excited state index (optional)
992 : !> \param festate occupation of the excited state (optional)
993 : ! **************************************************************************************************
994 0 : SUBROUTINE SmearFixedDerivMV(RESULT, f, mu, kTS, e, N_el, sigma, maxocc, method, v, estate, festate)
995 :
996 : REAL(KIND=dp), INTENT(OUT) :: RESULT(:), f(:), mu, kTS
997 : REAL(KIND=dp), INTENT(IN) :: e(:), N_el, sigma, maxocc
998 : INTEGER, INTENT(IN) :: method
999 : REAL(KIND=dp), INTENT(IN) :: v(:)
1000 : INTEGER, INTENT(IN), OPTIONAL :: estate
1001 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: festate
1002 :
1003 : CHARACTER(len=*), PARAMETER :: routineN = 'SmearFixedDerivMV'
1004 :
1005 : INTEGER :: handle, i, Nstate
1006 : REAL(KIND=dp) :: gdotv, Gsum
1007 0 : REAL(KIND=dp), ALLOCATABLE :: gvec(:)
1008 :
1009 0 : CALL timeset(routineN, handle)
1010 :
1011 : ! Step 1: find mu and f
1012 0 : CALL SmearFixed(f, mu, kTS, e, N_el, sigma, maxocc, method, estate, festate)
1013 :
1014 : ! Step 2: build g vector
1015 0 : Nstate = SIZE(e)
1016 0 : ALLOCATE (gvec(Nstate))
1017 0 : CALL smearing_response_weight(gvec, f, e, mu, sigma, maxocc, Nstate, method, estate, festate)
1018 0 : Gsum = accurate_sum(gvec)
1019 :
1020 : ! Step 3: RESULT_j = g_j * (g.v / G - v_j)
1021 0 : IF (ABS(Gsum) > EPSILON(Gsum)) THEN
1022 : gdotv = 0.0_dp
1023 0 : DO i = 1, Nstate
1024 0 : gdotv = gdotv + gvec(i)*v(i)
1025 : END DO
1026 0 : DO i = 1, Nstate
1027 0 : RESULT(i) = gvec(i)*(gdotv/Gsum - v(i))
1028 : END DO
1029 : ELSE
1030 0 : RESULT(:) = 0.0_dp
1031 : END IF
1032 :
1033 0 : DEALLOCATE (gvec)
1034 0 : CALL timestop(handle)
1035 :
1036 0 : END SUBROUTINE SmearFixedDerivMV
1037 :
1038 : END MODULE smearing_utils
|