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 Definition and construction of time/frequency grids for correlation methods.
10 : !> \par History
11 : !> 05.2019 Refactored from rpa_ri_gpw [Frederick Stein]
12 : ! **************************************************************************************************
13 : MODULE time_frequency_grids
14 : USE greenx_interface, ONLY: greenx_get_minimax_grid
15 : USE kinds, ONLY: dp
16 : USE mathconstants, ONLY: pi,&
17 : z_zero
18 : USE minimax_exp, ONLY: get_exp_minimax_coeff
19 : USE minimax_exp_gw, ONLY: get_exp_minimax_coeff_gw
20 : USE minimax_rpa, ONLY: get_rpa_minimax_coeff,&
21 : get_rpa_minimax_coeff_larger_grid
22 : #include "./base/base_uses.f90"
23 :
24 : IMPLICIT NONE
25 :
26 : PRIVATE
27 :
28 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'time_frequency_grids'
29 :
30 : TYPE time_frequency_grid_type
31 : REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: frequency
32 : REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: frequency_weights
33 : REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: imaginary_time
34 : REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: time_weights_at_zero_frequency
35 : ! Complete discrete transforms, including cosine/sine factors.
36 : ! Matrix rows index output grid points, columns index input grid points.
37 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: cosine_time_to_frequency
38 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: cosine_frequency_to_time
39 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: sine_time_to_frequency
40 : END TYPE time_frequency_grid_type
41 :
42 : INTEGER, PARAMETER :: cosine_time_to_frequency = 1, &
43 : sine_time_to_frequency = 2, &
44 : cosine_frequency_to_time = 3
45 : INTEGER, PARAMETER, PUBLIC :: positive_time = 1, negative_time = 2
46 :
47 : PUBLIC :: build_clenshaw_grid, build_minimax_time_frequency_grid, test_least_square_ft, &
48 : time_frequency_grid_release, time_frequency_grid_type, transform_time_to_frequency
49 :
50 : CONTAINS
51 :
52 : ! **************************************************************************************************
53 : !> \brief Release all data owned by a time_frequency_grid_type object.
54 : !> \param grid The grid object to release.
55 : ! **************************************************************************************************
56 1130 : SUBROUTINE time_frequency_grid_release(grid)
57 :
58 : TYPE(time_frequency_grid_type), INTENT(INOUT) :: grid
59 :
60 1130 : IF (ALLOCATED(grid%frequency)) DEALLOCATE (grid%frequency)
61 1130 : IF (ALLOCATED(grid%frequency_weights)) DEALLOCATE (grid%frequency_weights)
62 1130 : IF (ALLOCATED(grid%imaginary_time)) DEALLOCATE (grid%imaginary_time)
63 1130 : IF (ALLOCATED(grid%time_weights_at_zero_frequency)) DEALLOCATE (grid%time_weights_at_zero_frequency)
64 1130 : IF (ALLOCATED(grid%cosine_time_to_frequency)) DEALLOCATE (grid%cosine_time_to_frequency)
65 1130 : IF (ALLOCATED(grid%cosine_frequency_to_time)) DEALLOCATE (grid%cosine_frequency_to_time)
66 1130 : IF (ALLOCATED(grid%sine_time_to_frequency)) DEALLOCATE (grid%sine_time_to_frequency)
67 :
68 1130 : END SUBROUTINE time_frequency_grid_release
69 :
70 : ! **************************************************************************************************
71 : !> \brief Transform real positive/negative-time samples to complex positive-frequency values.
72 : !> The even part uses the cosine transform and the odd part the sine transform.
73 : !> \param grid Valid grid with complete cosine/sine time-to-frequency matrices of matching dimensions.
74 : !> \param samples_tau Real samples indexed (state, time, branch), with branches
75 : !> positive_time and negative_time. The samples include their physical signs.
76 : !> \param values_omega Complex output indexed (state, frequency), evaluated at the leading
77 : !> SIZE(values_omega, 2) positive-frequency nodes of grid.
78 : ! **************************************************************************************************
79 680 : SUBROUTINE transform_time_to_frequency(grid, samples_tau, values_omega)
80 : TYPE(time_frequency_grid_type), INTENT(IN) :: grid
81 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: samples_tau
82 : COMPLEX(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: values_omega
83 :
84 : CHARACTER(LEN=*), PARAMETER :: routineN = 'transform_time_to_frequency'
85 :
86 : INTEGER :: handle, ifreq, itime, nstate
87 : REAL(KIND=dp) :: weight_cos, weight_sin
88 680 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: samples_even, samples_odd
89 :
90 680 : CALL timeset(routineN, handle)
91 :
92 680 : nstate = SIZE(samples_tau, 1)
93 680 : CPASSERT(SIZE(samples_tau, 3) == 2)
94 680 : CPASSERT(SIZE(values_omega, 1) == nstate)
95 680 : CPASSERT(SIZE(samples_tau, 2) == SIZE(grid%cosine_time_to_frequency, 2))
96 680 : CPASSERT(SIZE(values_omega, 2) <= SIZE(grid%cosine_time_to_frequency, 1))
97 :
98 2720 : ALLOCATE (samples_even(nstate), samples_odd(nstate))
99 32548 : values_omega = z_zero
100 7226 : DO itime = 1, SIZE(samples_tau, 2)
101 73796 : samples_even(:) = 0.5_dp*(samples_tau(:, itime, positive_time) + samples_tau(:, itime, negative_time))
102 73796 : samples_odd(:) = 0.5_dp*(samples_tau(:, itime, positive_time) - samples_tau(:, itime, negative_time))
103 39662 : DO ifreq = 1, SIZE(values_omega, 2)
104 32436 : weight_cos = grid%cosine_time_to_frequency(ifreq, itime)
105 32436 : weight_sin = grid%sine_time_to_frequency(ifreq, itime)
106 : values_omega(:, ifreq) = values_omega(:, ifreq) + &
107 423510 : CMPLX(weight_cos*samples_even, weight_sin*samples_odd, KIND=dp)
108 : END DO
109 : END DO
110 :
111 680 : CALL timestop(handle)
112 :
113 1360 : END SUBROUTINE transform_time_to_frequency
114 :
115 : ! **************************************************************************************************
116 : !> \brief Build a Clenshaw-Curtis frequency grid.
117 : !> \param num_points Number of integration points.
118 : !> \param grid Grid object to fill.
119 : ! **************************************************************************************************
120 128 : SUBROUTINE build_clenshaw_grid(num_points, grid)
121 :
122 : INTEGER, INTENT(IN) :: num_points
123 : TYPE(time_frequency_grid_type), INTENT(OUT) :: grid
124 :
125 : CHARACTER(LEN=*), PARAMETER :: routineN = 'build_clenshaw_grid'
126 :
127 : INTEGER :: handle, jquad
128 :
129 128 : CALL timeset(routineN, handle)
130 :
131 128 : CPASSERT(num_points > 0)
132 :
133 512 : ALLOCATE (grid%frequency(num_points), grid%frequency_weights(num_points))
134 :
135 5550 : DO jquad = 1, num_points - 1
136 5422 : grid%frequency(jquad) = jquad*pi/(2.0_dp*num_points)
137 5550 : grid%frequency_weights(jquad) = pi/(num_points*SIN(grid%frequency(jquad))**2)
138 : END DO
139 128 : grid%frequency(num_points) = pi/2.0_dp
140 : grid%frequency_weights(num_points) = &
141 128 : pi/(2.0_dp*num_points*SIN(grid%frequency(num_points))**2)
142 :
143 128 : CALL timestop(handle)
144 :
145 128 : END SUBROUTINE build_clenshaw_grid
146 :
147 : ! **************************************************************************************************
148 : !> \brief Build a minimax time/frequency grid through the common backend boundary.
149 : !> \param num_points Number of minimax points.
150 : !> \param energy_min Lower end of the physical energy interval.
151 : !> \param energy_max Upper end of the physical energy interval.
152 : !> \param regularization Regularization used for the fitted transform weights.
153 : !> \param num_points_per_magnitude Number of fitting points per decade.
154 : !> \param grid Grid object to fill.
155 : !> \param build_frequency Whether to construct the frequency components.
156 : !> \param build_time Whether to construct the imaginary-time components.
157 : !> \param build_transforms Whether to construct the complete time/frequency transform matrices.
158 : !> \param build_sine Whether to construct the sine time-to-frequency matrix.
159 : !> \param time_scaling Scaling applied to the imaginary-time abscissas.
160 : !> \param time_weight_scaling Scaling applied to the imaginary-time weights.
161 : !> \param max_fit_error Maximum fitting error across all requested transforms.
162 : !> \param print_warning Whether the minimax coefficient routine prints warnings.
163 : !> \param unit_nr Output unit used by an external backend.
164 : !> \param prefer_external_backend Whether to try an available external backend first.
165 : !> \param used_external_backend Whether the external backend supplied the grid.
166 : ! **************************************************************************************************
167 352 : SUBROUTINE build_minimax_time_frequency_grid(num_points, energy_min, energy_max, regularization, &
168 : num_points_per_magnitude, grid, build_frequency, build_time, &
169 : build_transforms, build_sine, time_scaling, time_weight_scaling, &
170 : max_fit_error, print_warning, unit_nr, prefer_external_backend, &
171 : used_external_backend)
172 :
173 : INTEGER, INTENT(IN) :: num_points
174 : REAL(KIND=dp), INTENT(IN) :: energy_min, energy_max, regularization
175 : INTEGER, INTENT(IN) :: num_points_per_magnitude
176 : TYPE(time_frequency_grid_type), INTENT(OUT) :: grid
177 : LOGICAL, INTENT(IN) :: build_frequency, build_time, &
178 : build_transforms, build_sine
179 : REAL(KIND=dp), INTENT(IN) :: time_scaling, time_weight_scaling
180 : REAL(KIND=dp), INTENT(OUT) :: max_fit_error
181 : LOGICAL, INTENT(IN) :: print_warning
182 : INTEGER, INTENT(IN) :: unit_nr
183 : LOGICAL, INTENT(IN) :: prefer_external_backend
184 : LOGICAL, INTENT(OUT), OPTIONAL :: used_external_backend
185 :
186 : CHARACTER(LEN=*), PARAMETER :: routineN = 'build_minimax_time_frequency_grid'
187 :
188 : INTEGER :: external_ierr, handle, ierr
189 : REAL(KIND=dp) :: e_range, max_error
190 352 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: points_and_weights
191 :
192 352 : CALL timeset(routineN, handle)
193 :
194 352 : IF (PRESENT(used_external_backend)) used_external_backend = .FALSE.
195 352 : IF (prefer_external_backend) THEN
196 : CALL greenx_get_minimax_grid(unit_nr, num_points, energy_min, energy_max, regularization, &
197 : grid%imaginary_time, grid%time_weights_at_zero_frequency, &
198 : grid%frequency, grid%frequency_weights, &
199 : grid%cosine_time_to_frequency, &
200 : grid%cosine_frequency_to_time, &
201 214 : grid%sine_time_to_frequency, external_ierr)
202 214 : IF (external_ierr == 0) THEN
203 78 : max_fit_error = 0.0_dp
204 78 : IF (PRESENT(used_external_backend)) used_external_backend = .TRUE.
205 78 : CALL timestop(handle)
206 : RETURN
207 : END IF
208 136 : CALL time_frequency_grid_release(grid)
209 : END IF
210 :
211 274 : CPASSERT(num_points > 0)
212 274 : CPASSERT(energy_min > 0.0_dp)
213 274 : CPASSERT(energy_max >= energy_min)
214 274 : CPASSERT(time_scaling > 0.0_dp)
215 274 : CPASSERT(time_weight_scaling > 0.0_dp)
216 274 : CPASSERT(.NOT. build_transforms .OR. (build_frequency .AND. build_time))
217 274 : CPASSERT(.NOT. build_sine .OR. build_transforms)
218 274 : max_error = 0.0_dp
219 :
220 274 : e_range = energy_max/energy_min
221 822 : ALLOCATE (points_and_weights(2*num_points))
222 :
223 274 : IF (build_frequency) THEN
224 210 : IF (num_points <= 20) THEN
225 210 : CALL get_rpa_minimax_coeff(num_points, e_range, points_and_weights, ierr, print_warning)
226 : ELSE
227 0 : CALL get_rpa_minimax_coeff_larger_grid(num_points, e_range, points_and_weights)
228 : END IF
229 :
230 630 : ALLOCATE (grid%frequency(num_points))
231 420 : ALLOCATE (grid%frequency_weights(num_points))
232 2554 : grid%frequency(:) = points_and_weights(1:num_points)*energy_min
233 2554 : grid%frequency_weights(:) = points_and_weights(num_points + 1:)*energy_min
234 210 : IF (num_points >= 26) grid%frequency_weights(:) = grid%frequency_weights(:)*4.0_dp
235 : END IF
236 :
237 274 : IF (build_time) THEN
238 244 : IF (num_points <= 20) THEN
239 244 : CALL get_exp_minimax_coeff(num_points, e_range, points_and_weights)
240 : ELSE
241 0 : CALL get_exp_minimax_coeff_gw(num_points, e_range, points_and_weights)
242 : END IF
243 :
244 732 : ALLOCATE (grid%imaginary_time(num_points))
245 488 : ALLOCATE (grid%time_weights_at_zero_frequency(num_points))
246 2712 : grid%imaginary_time(:) = points_and_weights(1:num_points)/time_scaling/energy_min
247 2712 : grid%time_weights_at_zero_frequency(:) = points_and_weights(num_points + 1:)/time_weight_scaling/energy_min
248 :
249 244 : IF (build_transforms) THEN
250 720 : ALLOCATE (grid%cosine_time_to_frequency(num_points, num_points))
251 : CALL fit_l_sq_weights(cosine_time_to_frequency, num_points, grid%imaginary_time, &
252 : grid%cosine_time_to_frequency, grid%frequency, energy_min, energy_max, &
253 180 : max_error, num_points_per_magnitude, regularization)
254 :
255 540 : ALLOCATE (grid%cosine_frequency_to_time(num_points, num_points))
256 : CALL fit_l_sq_weights(cosine_frequency_to_time, num_points, grid%imaginary_time, &
257 : grid%cosine_frequency_to_time, grid%frequency, energy_min, energy_max, &
258 180 : max_error, num_points_per_magnitude, regularization)
259 :
260 180 : IF (build_sine) THEN
261 444 : ALLOCATE (grid%sine_time_to_frequency(num_points, num_points))
262 : CALL fit_l_sq_weights(sine_time_to_frequency, num_points, grid%imaginary_time, &
263 : grid%sine_time_to_frequency, grid%frequency, energy_min, energy_max, &
264 148 : max_error, num_points_per_magnitude, regularization)
265 : END IF
266 : END IF
267 : END IF
268 :
269 274 : max_fit_error = max_error
270 :
271 274 : CALL timestop(handle)
272 :
273 626 : END SUBROUTINE build_minimax_time_frequency_grid
274 :
275 : ! **************************************************************************************************
276 : !> \brief Calculate a complete least-squares time/frequency transform matrix.
277 : !> \param transform_kind Type of transform to fit.
278 : !> \param num_integ_points Number of integration points.
279 : !> \param tau_tj Imaginary-time integration points.
280 : !> \param weights Complete transform coefficients, including cosine/sine factors.
281 : !> Rows index output grid points, columns index input grid points.
282 : !> \param omega_tj Frequency integration points.
283 : !> \param E_min Lower end of the fitting interval.
284 : !> \param E_max Upper end of the fitting interval.
285 : !> \param max_error Maximum fitting error.
286 : !> \param num_points_per_magnitude Number of fitting points per decade.
287 : !> \param regularization Regularization parameter for the pseudoinverse.
288 : ! **************************************************************************************************
289 508 : SUBROUTINE fit_l_sq_weights(transform_kind, num_integ_points, tau_tj, weights, omega_tj, E_min, E_max, &
290 : max_error, num_points_per_magnitude, regularization)
291 :
292 : INTEGER, INTENT(IN) :: transform_kind, num_integ_points
293 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: tau_tj
294 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: weights
295 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: omega_tj
296 : REAL(KIND=dp), INTENT(IN) :: E_min, E_max
297 : REAL(KIND=dp), INTENT(OUT) :: max_error
298 : INTEGER, INTENT(IN) :: num_points_per_magnitude
299 : REAL(KIND=dp), INTENT(IN) :: regularization
300 :
301 : CHARACTER(LEN=*), PARAMETER :: routineN = 'fit_l_sq_weights'
302 :
303 : INTEGER :: handle, iii, info, jjj, jquad, lwork, &
304 : num_x_nodes
305 508 : INTEGER, ALLOCATABLE, DIMENSION(:) :: iwork
306 : LOGICAL :: sine_transform, time_to_frequency
307 : REAL(KIND=dp) :: func_val, max_error_tmp, multiplicator, &
308 : omega, tau, x_value
309 508 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: sing_values, vec_UTy, weight_work, work, &
310 508 : x_values, y_values
311 508 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: mat_A, mat_SinvVSinvSigma, &
312 508 : mat_SinvVSinvT, mat_U
313 :
314 508 : CALL timeset(routineN, handle)
315 :
316 508 : CPASSERT(transform_kind >= cosine_time_to_frequency)
317 508 : CPASSERT(transform_kind <= cosine_frequency_to_time)
318 508 : CPASSERT(SIZE(tau_tj) == num_integ_points)
319 508 : CPASSERT(SIZE(omega_tj) == num_integ_points)
320 508 : CPASSERT(SIZE(weights, 1) == num_integ_points)
321 508 : CPASSERT(SIZE(weights, 2) == num_integ_points)
322 :
323 508 : time_to_frequency = transform_kind /= cosine_frequency_to_time
324 508 : sine_transform = transform_kind == sine_time_to_frequency
325 :
326 : ! take num_points_per_magnitude points per 10-interval
327 508 : num_x_nodes = (INT(LOG10(E_max/E_min)) + 1)*num_points_per_magnitude
328 :
329 : ! take at least as many x points as integration points to have clear
330 : ! input for the singular value decomposition
331 508 : num_x_nodes = MAX(num_x_nodes, num_integ_points)
332 :
333 : ALLOCATE (x_values(num_x_nodes), y_values(num_x_nodes), mat_A(num_x_nodes, num_integ_points), &
334 : weight_work(num_integ_points), sing_values(num_integ_points), mat_U(num_x_nodes, num_x_nodes), &
335 : mat_SinvVSinvT(num_x_nodes, num_integ_points), work(8*num_integ_points*num_integ_points + &
336 : 12*num_integ_points + 2*num_x_nodes), iwork(8*num_integ_points), &
337 11176 : mat_SinvVSinvSigma(num_integ_points, num_x_nodes), vec_UTy(num_x_nodes))
338 508 : mat_SinvVSinvSigma = 0.0_dp
339 :
340 : ! double the value nessary for 'A' to achieve good performance
341 508 : lwork = SIZE(work)
342 :
343 508 : multiplicator = (E_max/E_min)**(1.0_dp/(REAL(num_x_nodes, KIND=dp) - 1.0_dp))
344 157308 : DO iii = 1, num_x_nodes
345 157308 : x_values(iii) = E_min*multiplicator**(iii - 1)
346 : END DO
347 :
348 508 : max_error = 0.0_dp
349 :
350 7044 : DO jquad = 1, num_integ_points
351 :
352 6536 : IF (time_to_frequency) THEN
353 4328 : omega = omega_tj(jquad)
354 :
355 4328 : IF (sine_transform) THEN
356 : ! y=2*omega/(x^2+omega^2)
357 562120 : DO iii = 1, num_x_nodes
358 562120 : y_values(iii) = 2.0_dp*omega/(x_values(iii)**2 + omega**2)
359 : END DO
360 : ELSE
361 : ! y=2*x/(x^2+omega^2)
362 593408 : DO iii = 1, num_x_nodes
363 593408 : y_values(iii) = 2.0_dp*x_values(iii)/(x_values(iii)**2 + omega**2)
364 : END DO
365 : END IF
366 :
367 76824 : DO jjj = 1, num_integ_points
368 17544824 : DO iii = 1, num_x_nodes
369 17540496 : IF (sine_transform) THEN
370 8689600 : mat_A(iii, jjj) = SIN(omega*tau_tj(jjj))*EXP(-x_values(iii)*tau_tj(jjj))
371 : ELSE
372 8778400 : mat_A(iii, jjj) = COS(omega*tau_tj(jjj))*EXP(-x_values(iii)*tau_tj(jjj))
373 : END IF
374 : END DO
375 : END DO
376 : ELSE
377 2208 : tau = tau_tj(jquad)
378 :
379 : ! y=exp(-x*|tau|)
380 593408 : DO iii = 1, num_x_nodes
381 593408 : y_values(iii) = EXP(-x_values(iii)*tau)
382 : END DO
383 :
384 38580 : DO jjj = 1, num_integ_points
385 36372 : omega = omega_tj(jjj)
386 8816980 : DO iii = 1, num_x_nodes
387 8778400 : x_value = x_values(iii)
388 8814772 : mat_A(iii, jjj) = COS(tau*omega)*2.0_dp*x_value/(x_value**2 + omega**2)
389 : END DO
390 : END DO
391 : END IF
392 :
393 : ! Singular value decomposition of mat_A
394 : CALL DGESDD('A', num_x_nodes, num_integ_points, mat_A, num_x_nodes, sing_values, mat_U, num_x_nodes, &
395 6536 : mat_SinvVSinvT, num_x_nodes, work, lwork, iwork, info)
396 6536 : CPASSERT(info == 0)
397 :
398 : ! integration weights = V Sigma U^T y
399 115404 : DO jjj = 1, num_integ_points
400 2129468 : DO iii = 1, num_integ_points
401 : mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)*sing_values(jjj) &
402 2122932 : /(regularization**2 + sing_values(jjj)**2)
403 : END DO
404 : END DO
405 :
406 : CALL DGEMM('T', 'N', num_x_nodes, 1, num_x_nodes, 1.0_dp, mat_U, num_x_nodes, y_values, num_x_nodes, &
407 6536 : 0.0_dp, vec_UTy, num_x_nodes)
408 : CALL DGEMM('N', 'N', num_integ_points, 1, num_x_nodes, 1.0_dp, mat_SinvVSinvSigma, num_integ_points, &
409 6536 : vec_UTy, num_x_nodes, 0.0_dp, weight_work, num_integ_points)
410 :
411 6536 : IF (sine_transform) THEN
412 38244 : weights(jquad, :) = weight_work(:)*SIN(omega*tau_tj(:))
413 4416 : ELSE IF (time_to_frequency) THEN
414 38580 : weights(jquad, :) = weight_work(:)*COS(omega*tau_tj(:))
415 : ELSE
416 38580 : weights(jquad, :) = weight_work(:)*COS(tau*omega_tj(:))
417 : END IF
418 :
419 6536 : max_error_tmp = 0.0_dp
420 1748936 : DO iii = 1, num_x_nodes
421 1742400 : func_val = 0.0_dp
422 1742400 : IF (time_to_frequency) THEN
423 18619200 : DO jjj = 1, num_integ_points
424 18619200 : func_val = func_val + weights(jquad, jjj)*EXP(-x_values(iii)*tau_tj(jjj))
425 : END DO
426 : ELSE
427 9369600 : DO jjj = 1, num_integ_points
428 8778400 : omega = omega_tj(jjj)
429 : func_val = func_val + weights(jquad, jjj)*2.0_dp*x_values(iii) &
430 9369600 : /(x_values(iii)**2 + omega**2)
431 : END DO
432 : END IF
433 1748936 : max_error_tmp = MAX(max_error_tmp, ABS(y_values(iii) - func_val))
434 : END DO
435 7044 : max_error = MAX(max_error, max_error_tmp)
436 :
437 : END DO
438 :
439 508 : CALL timestop(handle)
440 :
441 1016 : END SUBROUTINE fit_l_sq_weights
442 :
443 : ! **************************************************************************************************
444 : !> \brief test the singular value decomposition for the computation of integration weights for the
445 : !> Fourier transform between time and frequency grid in cubic-scaling RPA
446 : !> \param nR ...
447 : !> \param iw ...
448 : ! **************************************************************************************************
449 0 : SUBROUTINE test_least_square_ft(nR, iw)
450 : INTEGER, INTENT(IN) :: nR, iw
451 :
452 : REAL(KIND=dp), PARAMETER :: Rc_max = 1.0E+07_dp
453 :
454 : INTEGER :: ierr, iR, num_integ_points
455 : REAL(KIND=dp) :: max_error, multiplicator, Rc
456 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: tau_tj, tj, x_tw
457 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: weights_cos_tf_t_to_w
458 :
459 0 : multiplicator = Rc_max**(1.0_dp/(REAL(nR, KIND=dp) - 1.0_dp))
460 :
461 0 : DO num_integ_points = 1, 20
462 :
463 0 : ALLOCATE (x_tw(2*num_integ_points))
464 0 : x_tw = 0.0_dp
465 0 : ALLOCATE (tau_tj(num_integ_points))
466 0 : tau_tj = 0.0_dp
467 0 : ALLOCATE (weights_cos_tf_t_to_w(num_integ_points, num_integ_points))
468 0 : weights_cos_tf_t_to_w = 0.0_dp
469 0 : ALLOCATE (tj(num_integ_points))
470 0 : tj = 0.0_dp
471 :
472 0 : DO iR = 0, nR - 1
473 :
474 0 : Rc = 2.0_dp*multiplicator**iR
475 :
476 0 : ierr = 0
477 0 : CALL get_rpa_minimax_coeff(num_integ_points, Rc, x_tw, ierr, print_warning=.FALSE.)
478 :
479 0 : tj(:) = x_tw(1:num_integ_points)
480 :
481 0 : x_tw = 0.0_dp
482 :
483 0 : CALL get_exp_minimax_coeff(num_integ_points, Rc, x_tw)
484 :
485 0 : tau_tj(:) = x_tw(1:num_integ_points)/2.0_dp
486 :
487 : CALL fit_l_sq_weights(cosine_time_to_frequency, num_integ_points, tau_tj, &
488 0 : weights_cos_tf_t_to_w, tj, 1.0_dp, Rc, max_error, 200, 0.0_dp)
489 :
490 0 : IF (iw > 0) THEN
491 0 : WRITE (iw, '(T2, I3, F12.1, ES12.3)') num_integ_points, Rc, max_error
492 : END IF
493 :
494 : END DO
495 :
496 0 : DEALLOCATE (x_tw, tau_tj, weights_cos_tf_t_to_w, tj)
497 :
498 : END DO
499 :
500 0 : END SUBROUTINE test_least_square_ft
501 :
502 0 : END MODULE time_frequency_grids
|