(git:f2099e5)
Loading...
Searching...
No Matches
greenx_interface.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 Interface to the Greenx library
10!> \par History
11!> 07.2025 Refactored from RPA and BSE modules [Frederick Stein]
12! **************************************************************************************************
14 USE kinds, ONLY: dp
24 USE machine, ONLY: m_flush
25 USE physcon, ONLY: evolt
26#if defined (__GREENX)
27 USE gx_ac, ONLY: create_thiele_pade, &
28 evaluate_thiele_pade_at, &
29 free_params, &
30 params
31 USE gx_minimax, ONLY: gx_minimax_grid
32#endif
33
34#include "./base/base_uses.f90"
35
36 IMPLICIT NONE
37
38 PRIVATE
39
40 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'greenx_interface'
41
43
44CONTAINS
45
46! **************************************************************************************************
47!> \brief Get a minimax grid from GreenX when it is available.
48!> \param unit_nr Output unit for diagnostics.
49!> \param num_integ_points Number of minimax points.
50!> \param emin Lower energy bound.
51!> \param emax Upper energy bound.
52!> \param regularization_minimax Regularization of the minimax fit.
53!> \param imaginary_time Imaginary-time grid points.
54!> \param time_weights_at_zero_frequency Imaginary-time weights.
55!> \param frequency Frequency grid points.
56!> \param frequency_weights Frequency weights.
57!> \param cosine_time_to_frequency_weights Cosine time-to-frequency weights.
58!> \param cosine_frequency_to_time_weights Cosine frequency-to-time weights.
59!> \param sine_time_to_frequency_weights Sine time-to-frequency weights.
60!> \param ierr Zero if GreenX supplied a grid, nonzero otherwise.
61! **************************************************************************************************
62 SUBROUTINE greenx_get_minimax_grid(unit_nr, num_integ_points, emin, emax, regularization_minimax, &
63 imaginary_time, time_weights_at_zero_frequency, frequency, &
64 frequency_weights, cosine_time_to_frequency_weights, &
65 cosine_frequency_to_time_weights, sine_time_to_frequency_weights, ierr)
66
67 INTEGER, INTENT(IN) :: unit_nr, num_integ_points
68 REAL(kind=dp), INTENT(IN) :: emin, emax, regularization_minimax
69 REAL(kind=dp), ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: imaginary_time, &
70 time_weights_at_zero_frequency, &
71 frequency, frequency_weights
72 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: cosine_time_to_frequency_weights, &
73 cosine_frequency_to_time_weights, &
74 sine_time_to_frequency_weights
75 INTEGER, INTENT(OUT) :: ierr
76
77#if defined (__GREENX)
78 INTEGER :: gi
79 REAL(kind=dp) :: cosft_duality_error_greenx, &
80 max_errors_greenx(3)
81
82 CALL gx_minimax_grid(num_integ_points, emin, emax, imaginary_time, &
83 time_weights_at_zero_frequency, frequency, frequency_weights, &
84 cosine_time_to_frequency_weights, cosine_frequency_to_time_weights, &
85 sine_time_to_frequency_weights, max_errors_greenx, cosft_duality_error_greenx, ierr, &
86 bare_cos_sin_weights=.true., regularization=regularization_minimax)
87 IF (ierr == 0) THEN
88 ! Factor 4 is hard-coded in the RPA weights in the internal CP2K minimax routines
89 frequency_weights(:) = frequency_weights(:)*4.0_dp
90 IF (unit_nr > 0) THEN
91 WRITE (unit=unit_nr, fmt="(T3,A,T75,i6)") &
92 "GREENX MINIMAX_INFO| Number of integration points:", num_integ_points
93 WRITE (unit=unit_nr, fmt="(T3,A,T61,3F20.7)") &
94 "GREENX MINIMAX_INFO| Gap (Emin):", emin
95 WRITE (unit=unit_nr, fmt="(T3,A,T61,3F20.7)") &
96 "GREENX MINIMAX_INFO| Maximum eigenvalue difference (Emax):", emax
97 WRITE (unit=unit_nr, fmt="(T3,A,T61,3F20.4)") &
98 "GREENX MINIMAX_INFO| Energy range (Emax/Emin):", emax/emin
99 WRITE (unit=unit_nr, fmt="(T3,A,T54,A,T72,A)") &
100 "GREENX MINIMAX_INFO| Frequency grid (scaled):", "Weights", "Abscissas"
101 DO gi = 1, num_integ_points
102 WRITE (unit=unit_nr, fmt="(T41,F20.10,F20.10)") frequency_weights(gi), frequency(gi)
103 END DO
104 WRITE (unit=unit_nr, fmt="(T3,A,T54,A,T72,A)") &
105 "GREENX MINIMAX_INFO| Time grid (scaled):", "Weights", "Abscissas"
106 DO gi = 1, num_integ_points
107 WRITE (unit=unit_nr, fmt="(T41,F20.10,F20.10)") &
108 time_weights_at_zero_frequency(gi), imaginary_time(gi)
109 END DO
110 CALL m_flush(unit_nr)
111 END IF
112 ELSE
113 IF (unit_nr > 0) THEN
114 WRITE (unit=unit_nr, fmt="(T3,A,T75)") &
115 "GREENX MINIMAX_INFO| Grid not available, use internal CP2K grids"
116 CALL m_flush(unit_nr)
117 END IF
118 END IF
119#else
120 ierr = 1
121 mark_used(unit_nr)
122 mark_used(num_integ_points)
123 mark_used(emin)
124 mark_used(emax)
125 mark_used(regularization_minimax)
126 mark_used(imaginary_time)
127 mark_used(time_weights_at_zero_frequency)
128 mark_used(frequency)
129 mark_used(frequency_weights)
130 mark_used(cosine_time_to_frequency_weights)
131 mark_used(cosine_frequency_to_time_weights)
132 mark_used(sine_time_to_frequency_weights)
133#endif
134
135 END SUBROUTINE greenx_get_minimax_grid
136
137! **************************************************************************************************
138!> \brief Refines Pade approximants using GreenX, skips this step if GreenX is not available
139!> \param e_min ...
140!> \param e_max ...
141!> \param x_eval ...
142!> \param number_of_simulation_steps ...
143!> \param number_of_pade_points ...
144!> \param logger ...
145!> \param ft_section ...
146!> \param bse_unit ...
147!> \param omega_series ...
148!> \param ft_full_series ...
149! **************************************************************************************************
150 SUBROUTINE greenx_refine_pade(e_min, e_max, x_eval, number_of_simulation_steps, number_of_pade_points, &
151 logger, ft_section, bse_unit, omega_series, ft_full_series)
152 REAL(kind=dp), INTENT(IN) :: e_min, e_max
153 COMPLEX(KIND=dp), DIMENSION(:), POINTER :: x_eval
154 INTEGER, INTENT(IN) :: number_of_simulation_steps, number_of_pade_points
155 TYPE(cp_logger_type), POINTER :: logger
156 TYPE(section_vals_type), POINTER :: ft_section
157 INTEGER, INTENT(IN) :: bse_unit
158 REAL(kind=dp), DIMENSION(number_of_simulation_steps + 2), INTENT(INOUT) :: omega_series
159 REAL(kind=dp), DIMENSION(6, number_of_simulation_steps + 2), INTENT(INOUT) :: ft_full_series
160#if defined (__GREENX)
161 INTEGER :: i, ft_unit
162 COMPLEX(kind=dp), DIMENSION(:), ALLOCATABLE :: omega_complex, &
163 moments_ft_complex
164 COMPLEX(kind=dp), DIMENSION(:, :), ALLOCATABLE :: moments_eval_complex
165
166 ! Report Padé refinement
167 IF (bse_unit > 0) WRITE (bse_unit, '(A10,A27,E23.8E3,E20.8E3)') &
168 " PADE_FT| ", "Evaluation grid bounds [eV]", e_min, e_max
169 ALLOCATE (omega_complex(number_of_simulation_steps + 2))
170 ALLOCATE (moments_ft_complex(number_of_simulation_steps + 2))
171 ALLOCATE (moments_eval_complex(3, number_of_pade_points))
172 omega_complex(:) = cmplx(omega_series(:), 0.0, kind=dp)
173 DO i = 1, 3
174 moments_ft_complex(:) = cmplx(ft_full_series(2*i - 1, :), &
175 ft_full_series(2*i, :), &
176 kind=dp)
177 ! Copy the fitting parameters
178 ! TODO : Optional direct setting of parameters?
179 CALL greenx_refine_ft(e_min, e_max, omega_complex, moments_ft_complex, x_eval, moments_eval_complex(i, :))
180 END DO
181 ! Write into alternative file
182 ft_unit = cp_print_key_unit_nr(logger, ft_section, extension="_PADE.dat", &
183 file_form="FORMATTED", file_position="REWIND")
184 IF (ft_unit > 0) THEN
185 DO i = 1, number_of_pade_points
186 WRITE (ft_unit, '(E20.8E3,E20.8E3,E20.8E3,E20.8E3,E20.8E3,E20.8E3,E20.8E3)') &
187 REAL(x_eval(i)), REAL(moments_eval_complex(1, i)), aimag(moments_eval_complex(1, i)), &
188 REAL(moments_eval_complex(2, i)), aimag(moments_eval_complex(2, i)), &
189 REAL(moments_eval_complex(3, i)), aimag(moments_eval_complex(3, i))
190 END DO
191 END IF
192 CALL cp_print_key_finished_output(ft_unit, logger, ft_section)
193 DEALLOCATE (omega_complex)
194 DEALLOCATE (moments_ft_complex)
195 DEALLOCATE (moments_eval_complex)
196#else
197 IF (bse_unit > 0) WRITE (bse_unit, '(A10,A70)') &
198 " PADE_FT| ", "GreenX library is not available. Refinement is skipped"
199 mark_used(e_min)
200 mark_used(e_max)
201 mark_used(x_eval)
202 mark_used(number_of_simulation_steps)
203 mark_used(number_of_pade_points)
204 mark_used(logger)
205 mark_used(ft_section)
206 mark_used(omega_series)
207 mark_used(ft_full_series)
208#endif
209 END SUBROUTINE greenx_refine_pade
210! **************************************************************************************************
211!> \brief Outputs the isotropic polarizability tensor element alpha _ ij = mu_i(omega)/E_j(omega),
212!> where i and j are provided by the configuration. The tensor element is energy dependent and
213!> has real and imaginary parts
214!> \param logger ...
215!> \param pol_section ...
216!> \param bse_unit ...
217!> \param pol_elements ...
218!> \param x_eval ...
219!> \param polarizability_refined ...
220! **************************************************************************************************
221 SUBROUTINE greenx_output_polarizability(logger, pol_section, bse_unit, pol_elements, x_eval, polarizability_refined)
222 TYPE(cp_logger_type), POINTER :: logger
223 TYPE(section_vals_type), POINTER :: pol_section
224 INTEGER, INTENT(IN) :: bse_unit
225 INTEGER, DIMENSION(:, :), POINTER :: pol_elements
226 COMPLEX(KIND=dp), DIMENSION(:), POINTER :: x_eval
227 COMPLEX(kind=dp), DIMENSION(:, :), INTENT(IN) :: polarizability_refined
228#if defined(__GREENX)
229 INTEGER :: pol_unit, &
230 i, k, n_elems
231
232 n_elems = SIZE(pol_elements, 1)
233 ! Print out the refined polarizability to a file
234 pol_unit = cp_print_key_unit_nr(logger, pol_section, extension="_PADE.dat", &
235 file_form="FORMATTED", file_position="REWIND")
236 ! Printing for both the stdout and separate file
237 IF (pol_unit > 0) THEN
238 IF (pol_unit == bse_unit) THEN
239 ! Print the stdout preline
240 WRITE (pol_unit, '(A21)', advance="no") " POLARIZABILITY_PADE|"
241 ELSE
242 ! Print also the energy in atomic units
243 WRITE (pol_unit, '(A1,A19)', advance="no") "#", "omega [a.u.]"
244 END IF
245 ! Common - print the energy in eV
246 WRITE (pol_unit, '(A20)', advance="no") "Energy [eV]"
247 ! Print a header for each polarizability element
248 DO k = 1, n_elems - 1
249 WRITE (pol_unit, '(A16,I2,I2,A16,I2,I2)', advance="no") &
250 "Real pol.", pol_elements(k, 1), pol_elements(k, 2), &
251 "Imag pol.", pol_elements(k, 1), pol_elements(k, 2)
252 END DO
253 WRITE (pol_unit, '(A16,I2,I2,A16,I2,I2)') &
254 "Real pol.", pol_elements(n_elems, 1), pol_elements(n_elems, 2), &
255 "Imag pol.", pol_elements(n_elems, 1), pol_elements(n_elems, 2)
256 DO i = 1, SIZE(x_eval)
257 IF (pol_unit == bse_unit) THEN
258 ! Print the stdout preline
259 WRITE (pol_unit, '(A21)', advance="no") " POLARIZABILITY_PADE|"
260 ELSE
261 ! omega in a.u.
262 WRITE (pol_unit, '(E20.8E3)', advance="no") real(x_eval(i), kind=dp)
263 END IF
264 ! Common values
265 WRITE (pol_unit, '(E20.8E3)', advance="no") real(x_eval(i), kind=dp)*evolt
266 DO k = 1, n_elems - 1
267 WRITE (pol_unit, '(E20.8E3,E20.8E3)', advance="no") &
268 REAL(polarizability_refined(k, i)), aimag(polarizability_refined(k, i))
269 END DO
270 ! Print the final value and advance
271 WRITE (pol_unit, '(E20.8E3,E20.8E3)') &
272 REAL(polarizability_refined(n_elems, i)), aimag(polarizability_refined(n_elems, i))
273 END DO
274 CALL cp_print_key_finished_output(pol_unit, logger, pol_section)
275 END IF
276#else
277 mark_used(logger)
278 mark_used(pol_section)
279 mark_used(bse_unit)
280 mark_used(pol_elements)
281 mark_used(x_eval)
282 mark_used(polarizability_refined)
283#endif
284 END SUBROUTINE greenx_output_polarizability
285! **************************************************************************************************
286!> \brief Refines the FT grid using Padé approximants
287!> \param fit_e_min ...
288!> \param fit_e_max ...
289!> \param x_fit Input x-variables
290!> \param y_fit Input y-variables
291!> \param x_eval Refined x-variables
292!> \param y_eval Refined y-variables
293!> \param n_pade_opt ...
294! **************************************************************************************************
295 SUBROUTINE greenx_refine_ft(fit_e_min, fit_e_max, x_fit, y_fit, x_eval, y_eval, n_pade_opt)
296 REAL(kind=dp) :: fit_e_min, &
297 fit_e_max
298 COMPLEX(kind=dp), DIMENSION(:) :: x_fit, &
299 y_fit, &
300 x_eval, &
301 y_eval
302 INTEGER, OPTIONAL :: n_pade_opt
303#if defined (__GREENX)
304 CHARACTER(len=*), PARAMETER :: routinen = 'greenx_refine_ft'
305
306 INTEGER :: fit_start, &
307 fit_end, &
308 max_fit, &
309 n_fit, &
310 n_pade, &
311 n_eval, &
312 i, &
313 handle, &
314 unit_nr
315 TYPE(cp_logger_type), POINTER :: logger
316 TYPE(params) :: pade_params
317
318 CALL timeset(routinen, handle)
319
320 ! Get the sizes from arrays
321 max_fit = SIZE(x_fit)
322 n_eval = SIZE(x_eval)
323
324 ! Search for the fit start and end indices
325 fit_start = -1
326 fit_end = -1
327 ! Search for the subset of FT points which is within energy limits given by
328 ! the input
329 ! Do not search when automatic request of highest energy is made
330 IF (fit_e_max < 0) fit_end = max_fit
331 DO i = 1, max_fit
332 IF (fit_start == -1 .AND. real(x_fit(i)) >= fit_e_min) fit_start = i
333 IF (fit_end == -1 .AND. real(x_fit(i)) > fit_e_max) fit_end = i - 1
334 IF (fit_start > 0 .AND. fit_end > 0) EXIT
335 END DO
336 IF (fit_start == -1) fit_start = 1
337 IF (fit_end == -1) fit_end = max_fit
338 n_fit = fit_end - fit_start + 1
339
340 n_pade = n_fit/2
341 IF (PRESENT(n_pade_opt)) n_pade = n_pade_opt
342
343 ! Too few FT points (e.g. very short propagation with &FT on) leave n_pade < 1;
344 ! the Thiele recurrence would then divide by zero. Skip, returning zeros.
345 IF (n_pade < 1) THEN
346 cpwarn("FT deck too short for Padé; raise STEPS or disable &FT.")
347 y_eval(1:n_eval) = cmplx(0.0, 0.0, kind=dp)
348 CALL timestop(handle)
349 RETURN
350 END IF
351
352 ! Warn about a large number of Padé parameters
353 IF (n_pade > 1000) THEN
354 cpwarn("More then 1000 Padé parameters requested - may reduce with FIT_E_MIN/FIT_E_MAX.")
355 END IF
356
357 ! The Padé order is derived from the FT bins inside [FIT_E_MIN, FIT_E_MAX]; report it so a
358 ! spectrum's fit is reconstructable from the log. Distinct from the GW AC Padé (nparam_pade).
359 logger => cp_get_default_logger()
360 unit_nr = cp_logger_get_default_io_unit(logger)
361 IF (unit_nr > 0) THEN
362 WRITE (unit=unit_nr, fmt="(T3,A,T45,I6,I8,2F11.4)") &
363 "GREENX FT_PADE| n_pade, n_fit, window [eV]", n_pade, n_fit, &
364 REAL(x_fit(fit_start), kind=dp)*evolt, real(x_fit(fit_end), kind=dp)*evolt
365 END IF
366
367 ! TODO : Symmetry mode settable?
368 ! Here, we assume that ft corresponds to transform of real trace
369 pade_params = create_thiele_pade(n_pade, x_fit(fit_start:fit_end), y_fit(fit_start:fit_end), &
370 enforce_symmetry="conjugate")
371
372 ! Check whetner the splice is needed or not
373 y_eval(1:n_eval) = evaluate_thiele_pade_at(pade_params, x_eval)
374
375 CALL free_params(pade_params)
376 CALL timestop(handle)
377#else
378 ! Mark used
379 mark_used(fit_e_min)
380 mark_used(fit_e_max)
381 mark_used(x_fit)
382 mark_used(y_fit)
383 mark_used(x_eval)
384 mark_used(y_eval)
385 mark_used(n_pade_opt)
386 cpabort("Calls to GreenX require CP2K to be compiled with support for GreenX.")
387#endif
388 END SUBROUTINE greenx_refine_ft
389
390END MODULE greenx_interface
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
integer, parameter, public low_print_level
integer, parameter, public medium_print_level
character(len=default_path_length) function, public cp_print_key_generate_filename(logger, print_key, middle_name, extension, my_local)
Utility function that returns a unit number to write the print key. Might open a file with a unique f...
subroutine, public cp_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, on_file, mpi_io)
should be called after you finish working with a unit obtained with cp_print_key_unit_nr,...
Interface to the Greenx library.
subroutine, public greenx_refine_ft(fit_e_min, fit_e_max, x_fit, y_fit, x_eval, y_eval, n_pade_opt)
Refines the FT grid using Padé approximants.
subroutine, public greenx_refine_pade(e_min, e_max, x_eval, number_of_simulation_steps, number_of_pade_points, logger, ft_section, bse_unit, omega_series, ft_full_series)
Refines Pade approximants using GreenX, skips this step if GreenX is not available.
subroutine, public greenx_output_polarizability(logger, pol_section, bse_unit, pol_elements, x_eval, polarizability_refined)
Outputs the isotropic polarizability tensor element alpha _ ij = mu_i(omega)/E_j(omega),...
subroutine, public greenx_get_minimax_grid(unit_nr, num_integ_points, emin, emax, regularization_minimax, imaginary_time, time_weights_at_zero_frequency, frequency, frequency_weights, cosine_time_to_frequency_weights, cosine_frequency_to_time_weights, sine_time_to_frequency_weights, ierr)
Get a minimax grid from GreenX when it is available.
objects that represent the structure of input sections and the data contained in an input section
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Machine interface based on Fortran 2003 and POSIX.
Definition machine.F:17
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
Definition machine.F:124
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public evolt
Definition physcon.F:183
type of a logger, at the moment it contains just a print level starting at which level it should be l...