(git:4cf809f)
Loading...
Searching...
No Matches
qs_dos_utils.F
Go to the documentation of this file.
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 Utilities for broadened DOS and PDOS output.
10! **************************************************************************************************
17 USE kinds, ONLY: dp
18 USE mathconstants, ONLY: pi
19#include "./base/base_uses.f90"
20
21 IMPLICIT NONE
22
23 PRIVATE
24
25 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dos_utils'
26
27 INTEGER, PARAMETER, PUBLIC :: broadening_gaussian = 1, &
30 INTEGER, PARAMETER, PUBLIC :: dos_energy_unit_hartree = 1, &
32 INTEGER, PARAMETER, PUBLIC :: dos_energy_zero_auto = 1, &
36
40
41CONTAINS
42
43! **************************************************************************************************
44!> \brief Return the conversion factor from internal energy units to the selected DOS energy unit.
45!> \param energy_unit ...
46!> \return ...
47! **************************************************************************************************
48 FUNCTION dos_energy_scale(energy_unit) RESULT(scale)
49
50 INTEGER, INTENT(IN) :: energy_unit
51 REAL(kind=dp) :: scale
52
53 SELECT CASE (energy_unit)
55 scale = cp_unit_from_cp2k(value=1.0_dp, unit_str="eV")
56 CASE DEFAULT
57 scale = 1.0_dp
58 END SELECT
59
60 END FUNCTION dos_energy_scale
61
62! **************************************************************************************************
63!> \brief Return the DOS-density conversion factor for the selected energy unit.
64!> \param energy_unit ...
65!> \return ...
66! **************************************************************************************************
67 FUNCTION dos_density_scale(energy_unit) RESULT(scale)
68
69 INTEGER, INTENT(IN) :: energy_unit
70 REAL(kind=dp) :: scale
71
72 scale = 1.0_dp/dos_energy_scale(energy_unit)
73
74 END FUNCTION dos_density_scale
75
76! **************************************************************************************************
77!> \brief Return the energy-column label for DOS-like output.
78!> \param energy_unit ...
79!> \return ...
80! **************************************************************************************************
81 FUNCTION dos_energy_label(energy_unit) RESULT(label)
82
83 INTEGER, INTENT(IN) :: energy_unit
84 CHARACTER(LEN=16) :: label
85
86 SELECT CASE (energy_unit)
88 label = "Energy[eV]"
89 CASE DEFAULT
90 label = "Energy[a.u.]"
91 END SELECT
92
93 END FUNCTION dos_energy_label
94
95! **************************************************************************************************
96!> \brief Return the label for the selected DOS energy zero.
97!> \param energy_zero ...
98!> \return ...
99! **************************************************************************************************
100 FUNCTION dos_energy_zero_label(energy_zero) RESULT(label)
101
102 INTEGER, INTENT(IN) :: energy_zero
103 CHARACTER(LEN=16) :: label
104
105 SELECT CASE (energy_zero)
107 label = "ABSOLUTE"
109 label = "HOCO"
111 label = "AUTO"
112 CASE DEFAULT
113 label = "FERMI"
114 END SELECT
115
116 END FUNCTION dos_energy_zero_label
117
118! **************************************************************************************************
119!> \brief Resolve AUTO energy-zero selection for DOS-like output.
120!> \param energy_zero ...
121!> \param smearing_enabled ...
122!> \param fractional_occupation ...
123!> \return ...
124! **************************************************************************************************
125 FUNCTION dos_resolve_energy_zero(energy_zero, smearing_enabled, fractional_occupation) RESULT(resolved)
126
127 INTEGER, INTENT(IN) :: energy_zero
128 LOGICAL, INTENT(IN) :: smearing_enabled, fractional_occupation
129 INTEGER :: resolved
130
131 IF (energy_zero == dos_energy_zero_auto) THEN
132 IF (smearing_enabled .OR. fractional_occupation) THEN
133 resolved = dos_energy_zero_fermi
134 ELSE
135 resolved = dos_energy_zero_hoco
136 END IF
137 ELSE
138 resolved = energy_zero
139 END IF
140
141 END FUNCTION dos_resolve_energy_zero
142
143! **************************************************************************************************
144!> \brief Resolve projected-DOS requests from a DOS print section.
145!> \param dos_section DOS print section
146!> \param do_dos_output whether the DOS print key is active
147!> \param do_projected_dos whether any projected DOS output is requested
148!> \param do_pdos whether kind-resolved PDOS output is requested
149!> \param do_pdos_raw whether raw kind-resolved PDOS output is requested
150! **************************************************************************************************
151 SUBROUTINE get_dos_pdos_flags(dos_section, do_dos_output, do_projected_dos, do_pdos, do_pdos_raw)
152
153 TYPE(section_vals_type), POINTER :: dos_section
154 LOGICAL, INTENT(IN) :: do_dos_output
155 LOGICAL, INTENT(OUT) :: do_projected_dos, do_pdos, do_pdos_raw
156
157 INTEGER :: nrep
158 LOGICAL :: has_ldos, has_r_ldos
159 TYPE(section_vals_type), POINTER :: ldos_section, pdos_section
160
161 do_projected_dos = .false.
162 do_pdos = .false.
163 do_pdos_raw = .false.
164 has_ldos = .false.
165 has_r_ldos = .false.
166
167 IF (do_dos_output) THEN
168 pdos_section => section_vals_get_subs_vals(dos_section, "PDOS")
169 CALL section_vals_get(pdos_section, explicit=do_pdos)
170 IF (do_pdos) CALL section_vals_val_get(pdos_section, "RAW", l_val=do_pdos_raw)
171 ldos_section => section_vals_get_subs_vals(dos_section, "LDOS")
172 CALL section_vals_get(ldos_section, n_repetition=nrep)
173 has_ldos = (nrep > 0)
174 ldos_section => section_vals_get_subs_vals(dos_section, "R_LDOS")
175 CALL section_vals_get(ldos_section, n_repetition=nrep)
176 has_r_ldos = (nrep > 0)
177 END IF
178
179 do_projected_dos = do_pdos .OR. has_ldos .OR. has_r_ldos
180
181 END SUBROUTINE get_dos_pdos_flags
182
183! **************************************************************************************************
184!> \brief Add a broadened spectral line to a DOS curve.
185!> \param dos ...
186!> \param occ_dos ...
187!> \param emin ...
188!> \param de ...
189!> \param eig ...
190!> \param occ ...
191!> \param weight ...
192!> \param broaden_type ...
193!> \param broaden_width ...
194!> \param voigt_mixing ...
195! **************************************************************************************************
196 SUBROUTINE add_broadened_peak(dos, occ_dos, emin, de, eig, occ, weight, broaden_type, &
197 broaden_width, voigt_mixing)
198
199 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: dos, occ_dos
200 REAL(kind=dp), INTENT(IN) :: emin, de, eig, occ, weight
201 INTEGER, INTENT(IN) :: broaden_type
202 REAL(kind=dp), INTENT(IN) :: broaden_width, voigt_mixing
203
204 INTEGER :: i, iend, istart, nhist
205 REAL(kind=dp) :: eval, line_shape
206
207 nhist = SIZE(dos)
208 istart = max(1, floor((eig - broadening_cutoff(broaden_type, broaden_width) - emin)/de) + 1)
209 iend = min(nhist, ceiling((eig + broadening_cutoff(broaden_type, broaden_width) - emin)/de) + 1)
210 DO i = istart, iend
211 eval = emin + (i - 1)*de
212 line_shape = broadening_function(eval - eig, broaden_type, broaden_width, voigt_mixing)
213 dos(i) = dos(i) + weight*line_shape
214 occ_dos(i) = occ_dos(i) + weight*occ*line_shape
215 END DO
216
217 END SUBROUTINE add_broadened_peak
218
219! **************************************************************************************************
220!> \brief Add a broadened spectral line with a scalar weight to a curve.
221!> \param curve ...
222!> \param emin ...
223!> \param de ...
224!> \param eig ...
225!> \param weight ...
226!> \param broaden_type ...
227!> \param broaden_width ...
228!> \param voigt_mixing ...
229! **************************************************************************************************
230 SUBROUTINE add_broadened_value(curve, emin, de, eig, weight, broaden_type, &
231 broaden_width, voigt_mixing)
232
233 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: curve
234 REAL(kind=dp), INTENT(IN) :: emin, de, eig, weight
235 INTEGER, INTENT(IN) :: broaden_type
236 REAL(kind=dp), INTENT(IN) :: broaden_width, voigt_mixing
237
238 INTEGER :: i, iend, istart, nhist
239 REAL(kind=dp) :: eval, line_shape
240
241 nhist = SIZE(curve)
242 istart = max(1, floor((eig - broadening_cutoff(broaden_type, broaden_width) - emin)/de) + 1)
243 iend = min(nhist, ceiling((eig + broadening_cutoff(broaden_type, broaden_width) - emin)/de) + 1)
244 DO i = istart, iend
245 eval = emin + (i - 1)*de
246 line_shape = broadening_function(eval - eig, broaden_type, broaden_width, voigt_mixing)
247 curve(i) = curve(i) + weight*line_shape
248 END DO
249
250 END SUBROUTINE add_broadened_value
251
252! **************************************************************************************************
253!> \brief Broadening cutoff used for numerical accumulation.
254!> \param broaden_type ...
255!> \param broaden_width ...
256!> \return ...
257! **************************************************************************************************
258 PURE FUNCTION broadening_cutoff(broaden_type, broaden_width) RESULT(cutoff)
259
260 INTEGER, INTENT(IN) :: broaden_type
261 REAL(kind=dp), INTENT(IN) :: broaden_width
262 REAL(kind=dp) :: cutoff
263
264 IF (broaden_type == broadening_gaussian) THEN
265 cutoff = 8.0_dp*broaden_width
266 ELSE
267 cutoff = 50.0_dp*broaden_width
268 END IF
269
270 END FUNCTION broadening_cutoff
271
272! **************************************************************************************************
273!> \brief Normalized broadening function. BROADEN_WIDTH is FWHM.
274!> \param delta_e ...
275!> \param broaden_type ...
276!> \param broaden_width ...
277!> \param voigt_mixing ...
278!> \return ...
279! **************************************************************************************************
280 PURE FUNCTION broadening_function(delta_e, broaden_type, broaden_width, voigt_mixing) RESULT(value)
281
282 REAL(kind=dp), INTENT(IN) :: delta_e
283 INTEGER, INTENT(IN) :: broaden_type
284 REAL(kind=dp), INTENT(IN) :: broaden_width, voigt_mixing
285 REAL(kind=dp) :: value
286
287 REAL(kind=dp) :: eta, gamma, gaussian_value, sigma
288
289 IF (broaden_width <= 0.0_dp) THEN
290 value = 0.0_dp
291 RETURN
292 END IF
293
294 sigma = broaden_width/(2.0_dp*sqrt(2.0_dp*log(2.0_dp)))
295 gamma = 0.5_dp*broaden_width
296 gaussian_value = exp(-0.5_dp*(delta_e/sigma)**2)/(sigma*sqrt(2.0_dp*pi))
297
298 SELECT CASE (broaden_type)
300 value = gaussian_value
302 value = gamma/(pi*(delta_e**2 + gamma**2))
304 eta = min(1.0_dp, max(0.0_dp, voigt_mixing))
305 value = eta*gamma/(pi*(delta_e**2 + gamma**2)) + (1.0_dp - eta)*gaussian_value
306 CASE DEFAULT
307 value = gaussian_value
308 END SELECT
309
310 END FUNCTION broadening_function
311
312! **************************************************************************************************
313!> \brief Write broadening metadata.
314!> \param iw ...
315!> \param broaden_type ...
316!> \param broaden_width ...
317!> \param voigt_mixing ...
318! **************************************************************************************************
319 SUBROUTINE write_broadening_info(iw, broaden_type, broaden_width, voigt_mixing)
320
321 INTEGER, INTENT(IN) :: iw, broaden_type
322 REAL(kind=dp), INTENT(IN) :: broaden_width, voigt_mixing
323
324 REAL(kind=dp) :: broaden_width_ev
325
326 broaden_width_ev = cp_unit_from_cp2k(value=broaden_width, unit_str="eV")
327
328 SELECT CASE (broaden_type)
330 WRITE (unit=iw, fmt="(A,F10.8,A,F8.6,A)") &
331 "# Gaussian broadening, FWHM = ", broaden_width, " a.u. = ", broaden_width_ev, " eV"
333 WRITE (unit=iw, fmt="(A,F10.8,A,F8.6,A)") &
334 "# Lorentzian broadening, FWHM = ", broaden_width, " a.u. = ", broaden_width_ev, " eV"
336 WRITE (unit=iw, fmt="(A,F10.8,A,F8.6,A,F8.4)") &
337 "# Pseudo-Voigt broadening, FWHM = ", broaden_width, " a.u. = ", &
338 broaden_width_ev, " eV, Lorentzian fraction = ", min(1.0_dp, max(0.0_dp, voigt_mixing))
339 END SELECT
340
341 END SUBROUTINE write_broadening_info
342
343END MODULE qs_dos_utils
unit conversion facility
Definition cp_units.F:30
real(kind=dp) function, public cp_unit_from_cp2k(value, unit_str, defaults, power)
converts from the internal cp2k units to the given unit
Definition cp_units.F:1239
Calculation of the incomplete Gamma function F_n(t) for multi-center integrals over Cartesian Gaussia...
Definition gamma.F:15
objects that represent the structure of input sections and the data contained in an input section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
subroutine, public section_vals_get(section_vals, ref_count, n_repetition, n_subs_vals_rep, section, explicit)
returns various attributes about the section_vals
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
Utilities for broadened DOS and PDOS output.
subroutine, public add_broadened_peak(dos, occ_dos, emin, de, eig, occ, weight, broaden_type, broaden_width, voigt_mixing)
Add a broadened spectral line to a DOS curve.
pure real(kind=dp) function, public broadening_function(delta_e, broaden_type, broaden_width, voigt_mixing)
Normalized broadening function. BROADEN_WIDTH is FWHM.
subroutine, public write_broadening_info(iw, broaden_type, broaden_width, voigt_mixing)
Write broadening metadata.
subroutine, public add_broadened_value(curve, emin, de, eig, weight, broaden_type, broaden_width, voigt_mixing)
Add a broadened spectral line with a scalar weight to a curve.
integer, parameter, public dos_energy_zero_hoco
integer, parameter, public dos_energy_zero_auto
integer, parameter, public dos_energy_unit_ev
character(len=16) function, public dos_energy_label(energy_unit)
Return the energy-column label for DOS-like output.
integer function, public dos_resolve_energy_zero(energy_zero, smearing_enabled, fractional_occupation)
Resolve AUTO energy-zero selection for DOS-like output.
real(kind=dp) function, public dos_energy_scale(energy_unit)
Return the conversion factor from internal energy units to the selected DOS energy unit.
integer, parameter, public dos_energy_zero_absolute
integer, parameter, public broadening_gaussian
integer, parameter, public dos_energy_zero_fermi
pure real(kind=dp) function, public broadening_cutoff(broaden_type, broaden_width)
Broadening cutoff used for numerical accumulation.
subroutine, public get_dos_pdos_flags(dos_section, do_dos_output, do_projected_dos, do_pdos, do_pdos_raw)
Resolve projected-DOS requests from a DOS print section.
real(kind=dp) function, public dos_density_scale(energy_unit)
Return the DOS-density conversion factor for the selected energy unit.
integer, parameter, public dos_energy_unit_hartree
integer, parameter, public broadening_pseudo_voigt
character(len=16) function, public dos_energy_zero_label(energy_zero)
Return the label for the selected DOS energy zero.
integer, parameter, public broadening_lorentzian