Branch data Line data Source code
1 : : ! **************************************************************************************************
2 : : ! Copyright (C) 2020-2023 Green-X library
3 : : ! This file is distributed under the terms of the APACHE2 License.
4 : : !
5 : : ! **************************************************************************************************
6 : : !> \brief Routines to calculate frequency and time grids (integration points and weights)
7 : : !> for correlation methods as well as weights for the inhomogeneous cosine/sine transform.
8 : : !>
9 : : !> NB: When dealing with runtime exceptions, we set ierr to a non-zero value and return immediately
10 : : ! to the caller so we don't need to goto to a cleanup section at the end of the procedure.
11 : : ! Assume -std=f2008: i.e. allocatable arrays are automatically deallocated when going out of scope.
12 : : !> reference: [https://doi.org/10.1021/ct5001268](https://doi.org/10.1021/ct5001268)
13 : : !> reference: [https://doi.org/10.1103/PhysRevB.94.165109](https://doi.org/10.1103/PhysRevB.94.165109)
14 : : ! **************************************************************************************************
15 : :
16 : : module minimax_grids
17 : : #if defined HAVE_CONFIG_H
18 : : #include "config.h"
19 : : #endif
20 : : #include "abi_common.h"
21 : :
22 : : #include "gx_common.h"
23 : : use defs_basis, only: dp, pi
24 : : use m_errors
25 : : !use kinds, only: dp
26 : : !use error_handling, only: register_exc
27 : : !use constants, only: pi
28 : : use minimax_tau, only: get_points_weights_tau
29 : : use minimax_omega, only: get_points_weights_omega
30 : : use minimax_utils, only: cosine_wt, cosine_tw, sine_tw
31 : : !use lapack_interfaces, only: dgemm, dgesdd
32 : :
33 : : implicit none
34 : :
35 : : private
36 : :
37 : : !> Main entry point for client code.
38 : : public :: gx_minimax_grid, gx_minimax_grid_frequency
39 : :
40 : : contains
41 : :
42 : : !> \brief Compute minimax grid for GW calculation on imaginary time/frequency domain.
43 : : !! @param[in] num_points: Number of mesh points.
44 : : !! @param[in] e_min: Minimum transition energy. Arbitrary units as we only need e_max/e_min
45 : : !! @param[in] e_max: Maximum transition energy.
46 : : !! @param[out] tau_points: imaginary time grid points
47 : : !! @param[out] tau_weights: weights for imaginary time grid points weights
48 : : !! @param[out] omega_points: imaginary frequency grid points
49 : : !! @param[out] omega_weights: weights for imaginary frequency grid points
50 : : !! @param[out] cosft_wt: weights for tau -> omega cosine transform. cos(w*t) factor is included.
51 : : !! @param[out] cosft_tw: weights for omega -> tau cosine transform. cos(w*t) factor is included.
52 : : !! @param[out] sinft_wt: weights for tau -> omega sine transform. sin(w*t) factor is included.
53 : : !! @param[out] max_errors: Max error for the three kind of transforms (same order as previous args)
54 : : !! @param[out] cosft_duality_error. Max_{ij} |AB - I| where A and B are the cosft_wt and cosft_tw matrices.
55 : : !! @param[out] ierr: Exit status
56 : : !! @param[in] bare_cos_sin_weights: whether the cosine and sine weights are multiplied by cos and sin term, optional
57 : 2 : subroutine gx_minimax_grid(num_points, e_min, e_max, &
58 : : tau_points, tau_weights, omega_points, omega_weights, &
59 : : cosft_wt, cosft_tw, sinft_wt, &
60 : : max_errors, cosft_duality_error, ierr, bare_cos_sin_weights, regterm)
61 : :
62 : : integer, intent(in) :: num_points
63 : : real(kind=dp), intent(in) :: e_min, e_max
64 : : real(kind=dp), allocatable, dimension(:), &
65 : : intent(out) :: tau_points, tau_weights
66 : : real(kind=dp), allocatable, dimension(:), &
67 : : intent(out) :: omega_points, omega_weights
68 : : real(kind=dp), allocatable, dimension(:, :), &
69 : : intent(out) :: cosft_wt, cosft_tw, sinft_wt
70 : : real(kind=dp), intent(out) :: max_errors(3), cosft_duality_error
71 : : logical, intent(in), optional :: bare_cos_sin_weights
72 : : integer, intent(out) :: ierr
73 : : real(kind=dp),optional,intent(in) :: regterm
74 : :
75 : : ! Internal variables
76 : : logical :: my_bare_cos_sin_weights
77 : : integer, parameter :: cos_t_to_cos_w = 1
78 : : integer, parameter :: cos_w_to_cos_t = 2
79 : : integer, parameter :: sin_t_to_sin_w = 3
80 : : integer :: i_point, j_point
81 : : real(kind=dp) :: e_range, scaling, regterm__
82 : 2 : real(kind=dp), dimension(:), allocatable :: x_tw
83 : 2 : real(kind=dp), dimension(:, :), allocatable :: mat
84 : 2 : real(kind=dp), dimension(:, :), allocatable :: tmp_cosft_wt, tmp_cosft_tw
85 : :
86 : 2 : my_bare_cos_sin_weights = .false.
87 [ - + ]: 2 : if (present(bare_cos_sin_weights)) then
88 : 0 : my_bare_cos_sin_weights = bare_cos_sin_weights
89 : : endif
90 : :
91 [ - + ]: 2 : regterm__ = 0.0_dp; if (present(regterm)) regterm__ = regterm
92 : :
93 : : ! Begin work
94 : 2 : e_range = e_max/e_min
95 : 2 : ierr = 0
96 : :
97 : : ! Allocations
98 [ + - - + : 6 : allocate (x_tw(2*num_points))
+ - + - +
- - + -
+ ]
99 [ + - ]: 2 : if (.not. allocated(omega_points)) then
100 [ - + + - : 6 : allocate (omega_points(num_points))
+ - + - -
+ - + -
+ ]
101 : : end if
102 [ + - ]: 2 : if (.not. allocated(omega_weights)) then
103 [ - + + - : 6 : allocate (omega_weights(num_points))
+ - + - -
+ - + -
+ ]
104 : : end if
105 [ + - ]: 2 : if (.not. allocated(tau_points)) then
106 [ - + + - : 6 : allocate (tau_points(num_points))
+ - + - -
+ - + -
+ ]
107 : : end if
108 [ + - ]: 2 : if (.not. allocated(tau_weights)) then
109 [ - + + - : 6 : allocate (tau_weights(num_points))
+ - + - -
+ - + -
+ ]
110 : : end if
111 : :
112 : : ! Get the frequency grid points and weights
113 : 2 : call get_points_weights_omega(num_points, e_range, x_tw, ierr)
114 [ + - ]: 2 : if (ierr /= 0) return
115 : :
116 : : ! Scale the frequency grid points and weights from [1,R] to [e_min,e_max]
117 : : ! Note: the frequency grid points and weights include a factor of two
118 : 2 : scaling = e_min
119 [ + + ]: 32 : omega_points(:) = x_tw(1: num_points) *scaling
120 [ + + ]: 32 : omega_weights(:) = x_tw(num_points+1: 2* num_points) *scaling
121 : :
122 : : ! Get the time grid points and weights
123 : 2 : call get_points_weights_tau(num_points, e_range, x_tw, ierr)
124 [ + - ]: 2 : if (ierr /= 0) return
125 : :
126 : : ! Scale the time grid points and weights from [1,R] to [e_min,e_max]
127 : 2 : scaling = 2.0_dp *e_min
128 [ + + ]: 32 : tau_points(:) = x_tw(1:num_points) / scaling
129 [ + + ]: 32 : tau_weights(:) = x_tw(num_points+1:2*num_points) / scaling
130 : :
131 [ - + + - : 8 : allocate (cosft_wt(num_points, num_points))
- + + - +
- + - - +
- + - + ]
132 [ - + + - : 6 : allocate (cosft_tw(num_points, num_points))
- + + - -
+ - + -
+ ]
133 [ - + + - : 6 : allocate (sinft_wt(num_points, num_points))
- + + - -
+ - + -
+ ]
134 [ - + + - : 6 : allocate (tmp_cosft_wt(num_points, num_points))
- + + - -
+ - + ]
135 [ - + + - : 6 : allocate (tmp_cosft_tw(num_points, num_points))
- + + - -
+ - + ]
136 : :
137 : : ! get the weights for the cosine transform W^c(it) -> W^c(iw)
138 : : call get_transformation_weights(num_points, tau_points, omega_points, cosft_wt, e_min, e_max, &
139 : 2 : max_errors(1), cos_t_to_cos_w, regterm__, ierr)
140 [ + - ]: 2 : if (ierr /= 0) return
141 : :
142 : : ! get the weights for the cosine transform W^c(iw) -> W^c(it)
143 : : call get_transformation_weights(num_points, tau_points, omega_points, cosft_tw, e_min, e_max, &
144 : 2 : max_errors(2), cos_w_to_cos_t, regterm__, ierr)
145 [ + - ]: 2 : if (ierr /= 0) return
146 : :
147 : : ! get the weights for the sine transform Sigma^sin(it) -> Sigma^sin(iw) (PRB 94, 165109 (2016), Eq. 71)
148 : : call get_transformation_weights(num_points, tau_points, omega_points, sinft_wt, e_min, e_max, &
149 : 2 : max_errors(3), sin_t_to_sin_w, regterm__, ierr)
150 [ + - ]: 2 : if (ierr /= 0) return
151 : :
152 : : ! Compute the actual weights used for the inhomogeneous cosine/ FT and check whether
153 : : ! the two matrices for the forward/backward transform are the inverse of each other.
154 [ + - ]: 2 : if(.not.my_bare_cos_sin_weights) then
155 [ + + ]: 32 : do j_point = 1, num_points
156 [ + + ]: 532 : do i_point = 1, num_points
157 : 500 : cosft_wt(j_point, i_point) = cosft_wt(j_point, i_point)*cos(tau_points(i_point)*omega_points(j_point))
158 : 500 : cosft_tw(i_point, j_point) = cosft_tw(i_point, j_point)*cos(tau_points(i_point)*omega_points(j_point))
159 : 530 : sinft_wt(j_point, i_point) = sinft_wt(j_point, i_point)*sin(tau_points(i_point)*omega_points(j_point))
160 : : end do
161 : : end do
162 : : else
163 [ # # ]: 0 : do j_point = 1, num_points
164 [ # # ]: 0 : do i_point = 1, num_points
165 : 0 : tmp_cosft_wt(j_point, i_point) = cosft_wt(j_point, i_point)*cos(tau_points(i_point)*omega_points(j_point))
166 : 0 : tmp_cosft_tw(i_point, j_point) = cosft_tw(i_point, j_point)*cos(tau_points(i_point)*omega_points(j_point))
167 : : end do
168 : : end do
169 : : end if
170 : :
171 [ - + + - : 6 : allocate (mat(num_points, num_points))
- + + - -
+ - + ]
172 [ + - ]: 2 : if(.not.my_bare_cos_sin_weights) then
173 [ + - + + : 37062 : mat(:,:) = matmul(cosft_wt, cosft_tw)
+ + + + +
+ + + + -
+ - + - +
- ]
174 : : else
175 [ # # # # : 0 : mat(:,:) = matmul(tmp_cosft_wt, tmp_cosft_tw)
# # # # #
# # # ]
176 : : endif
177 : :
178 [ + + ]: 32 : do i_point = 1, num_points
179 : 32 : mat(i_point, i_point) = mat(i_point, i_point) - 1.0_dp
180 : : end do
181 [ + + + + : 532 : cosft_duality_error = maxval(abs(mat))
+ + + - -
+ - - ]
182 : :
183 [ - + ]: 2 : deallocate (mat)
184 [ - + ]: 2 : deallocate (x_tw)
185 [ - + - + ]: 2 : deallocate (tmp_cosft_wt,tmp_cosft_tw)
186 : :
187 [ - - - - : 4 : end subroutine gx_minimax_grid
- - ]
188 : :
189 : : !> \brief Retrieves the frequency grid for a canonical GW/RPA calculation
190 : : !! @param[in] num_points: Number of mesh points.
191 : : !! @param[in] e_min: Minimum transition energy. Arbitrary units as we only need e_max/e_min
192 : : !! @param[in] e_max: Maximum transition energy.
193 : : !! @param[out] omega_points: imaginary frequency grid points
194 : : !! @param[out] omega_weights: weights for imaginary frequency grid points
195 : : !! @param[out] ierr: Exit status
196 : 0 : subroutine gx_minimax_grid_frequency (num_points, e_min, e_max, omega_points, omega_weights, ierr)
197 : : integer, intent(in) :: num_points
198 : : real(kind=dp), intent(in) :: e_min, e_max
199 : : real(kind=dp), allocatable, dimension(:), &
200 : : intent(out) :: omega_points(:), omega_weights(:)
201 : : integer, intent(out) :: ierr
202 : :
203 : : ! Internal variables
204 : : real(kind=dp) :: e_range, scaling
205 : 0 : real(kind=dp), dimension(:), allocatable :: x_tw
206 : :
207 : : ! Begin work
208 : 0 : e_range = e_max/e_min
209 : 0 : ierr = 0
210 : :
211 : : ! Allocations
212 [ # # # # : 0 : allocate (x_tw(2*num_points))
# # # # #
# # # #
# ]
213 [ # # ]: 0 : if (.not. allocated(omega_points)) then
214 [ # # # # : 0 : allocate (omega_points(num_points))
# # # # #
# # # #
# ]
215 : : end if
216 [ # # ]: 0 : if (.not. allocated(omega_weights)) then
217 [ # # # # : 0 : allocate (omega_weights(num_points))
# # # # #
# # # #
# ]
218 : : end if
219 : :
220 : : ! Get the frequency grid points and weights
221 : 0 : call get_points_weights_omega(num_points, e_range, x_tw, ierr)
222 [ # # ]: 0 : if (ierr /= 0) return
223 : :
224 : : ! Scale the frequency grid points and weights from [1,R] to [e_min,e_max]
225 : : ! Note: the frequency grid points and weights include a factor of two
226 : 0 : scaling = e_min
227 [ # # ]: 0 : omega_points(:) = x_tw(1: num_points) *scaling
228 [ # # ]: 0 : omega_weights(:) = x_tw(num_points+1: 2* num_points) *scaling
229 : :
230 [ # # ]: 0 : deallocate (x_tw)
231 : :
232 [ # # ]: 0 : end subroutine gx_minimax_grid_frequency
233 : :
234 : :
235 : : !> \brief Get the weights eiter for the cosine/sin transformation for tau to omega or viceversa
236 : : !! @param[in] num_points: Number of mesh points.
237 : : !! @param[in] tau_points: imaginary time grid points
238 : : !! @param[in] omega_points: imaginary frequency grid points
239 : : !! @param[inout] weights: corresponding tranformation weights
240 : : !! @param[in] e_min: Minimum transition energy.
241 : : !! @param[in] e_max: Maximum transition energy.
242 : : !! @param[inout] max_error: Max error for the transform
243 : : !! @param[in] transformation type : 1 the cosine transform cos(it) -> cos(iw)
244 : : !! : 2 the cosine transform cos(iw) -> cos(it)
245 : : !! : 3 the sine transform sin(it) -> sin(iw)
246 : : !! @param[in] ierr: exit status
247 : 6 : subroutine get_transformation_weights(num_points, tau_points, omega_points, weights, e_min, e_max, &
248 : : max_error, transformation_type, regterm, ierr)
249 : :
250 : : integer, intent(in) :: num_points
251 : : real(kind=dp), allocatable, dimension(:), &
252 : : intent(in) :: tau_points
253 : : real(kind=dp), allocatable, dimension(:), &
254 : : intent(in) :: omega_points
255 : : real(kind=dp), allocatable, dimension(:, :), &
256 : : intent(inout) :: weights
257 : : real(kind=dp), intent(in) :: e_min, e_max
258 : : real(kind=dp), intent(inout) :: max_error
259 : : integer, intent(in) :: transformation_type
260 : : integer, intent(out) :: ierr
261 : : real(kind=dp),intent(in) :: regterm
262 : :
263 : : ! Internal variables
264 : : integer :: i_node, i_point, j_point, k_point, &
265 : : num_x_nodes
266 : : integer, parameter :: nodes_factor = 200
267 : : real(kind=dp) :: current_point, x_factor
268 : : real(kind=dp), allocatable, dimension(:) :: weights_work, x_mu, psi
269 : : real(kind=dp), allocatable, dimension(:, :) :: mat_A
270 : :
271 : : integer :: lwork
272 : 6 : integer, allocatable, dimension(:) :: iwork
273 : 6 : real(kind=dp), allocatable, dimension(:) :: vec_S, vec_UT_psi, work
274 : 6 : real(kind=dp), allocatable, dimension(:, :) :: mat_U, mat_VT, mat_VT_s
275 : :
276 : : ! Begin work
277 : 6 : ierr = 0
278 : :
279 [ - + + - : 108 : allocate (weights_work(num_points), source=0.0_dp)
+ - + - -
+ - + +
+ ]
280 : :
281 : : ! compute the number of x nodes per magnitude points per 10-interval
282 : 6 : num_x_nodes = (int(log10(e_max/e_min)) + 1)*nodes_factor
283 : :
284 : : ! make sure that the number of x nodes are at least as many integration points
285 : 6 : num_x_nodes = max(num_x_nodes, num_points)
286 : :
287 [ - + + - : 3018 : allocate (x_mu(num_x_nodes), source=0.0_dp)
+ - + - -
+ - + +
+ ]
288 [ - + + - : 3012 : allocate (psi(num_x_nodes), source=0.0_dp)
- + - + +
+ ]
289 : :
290 : : ! Allocations for the BLAS routines
291 : : ! double the value nessary for 'A' to achieve good performance
292 : 6 : lwork = 8*num_points*num_points + 12*num_points + 2*num_x_nodes
293 [ + - - + : 738 : allocate (iwork(8*num_points), source=0)
+ - + - +
- - + - +
+ + ]
294 [ - + + - : 19098 : allocate (work(lwork), source=0.0_dp)
+ - + - -
+ - + +
+ ]
295 : :
296 [ - + + - : 42114 : allocate (mat_A(num_x_nodes, num_points), source=0.0_dp)
- + + - +
- + - - +
- + + + +
+ ]
297 [ - + + - : 1563024 : allocate (mat_U(num_x_nodes, num_x_nodes), source=0.0_dp)
- + + - +
- + - - +
- + + + +
+ ]
298 [ - + + - : 42108 : allocate (mat_VT(num_x_nodes, num_points), source=0.0_dp)
- + + - -
+ - + + +
+ + ]
299 [ - + + - : 45018 : allocate (mat_VT_s(num_points, num_x_nodes), source=0.0_dp)
- + + - -
+ - + + +
+ + ]
300 [ - + + - : 102 : allocate (vec_S(num_points), source=0.0_dp)
- + - + +
+ ]
301 [ - + + - : 3012 : allocate (vec_UT_psi(num_x_nodes), source=0.0_dp)
- + - + +
+ ]
302 : :
303 : : ! set the x-mu logarithmically in the interval [e_min,e_max]
304 : 6 : x_factor = (e_max/e_min)**(1.0_dp/(real(num_x_nodes, kind=dp) - 1.0_dp))
305 [ + + ]: 3006 : do i_node = 1, num_x_nodes
306 : 3006 : x_mu(i_node) = e_min*x_factor**(i_node - 1)
307 : : end do
308 : :
309 : 6 : current_point = 0.0_dp
310 : 6 : max_error = 0.0_dp
311 : :
312 : : ! loop over all grid points
313 [ + + ]: 96 : do i_point = 1, num_points
314 : : ! calculate psi and mat_A
315 : : call calculate_psi_and_mat_A(num_points, tau_points, omega_points, num_x_nodes, x_mu, psi, &
316 : 90 : mat_A, i_point, current_point, transformation_type)
317 : :
318 : : ! Singular value decomposition of mat_A = U*Sigma*V^T
319 : : call dgesdd('A', num_x_nodes, num_points, mat_A, num_x_nodes, vec_S, mat_U, num_x_nodes, &
320 : 90 : mat_VT, num_x_nodes, work, lwork, iwork, ierr)
321 : :
322 [ - + ]: 90 : if (ierr /= 0) then
323 : 0 : _REGISTER_EXC("DGESDD returned ierr != 0")
324 : 0 : return
325 : : end if
326 : :
327 : : ! integration weights = (V Sigma^-1 U^T)*psi
328 : :
329 : : ! 1) V * Sigma^-1
330 : : !regterm = 0.01_dp
331 [ + + ]: 1590 : do j_point = 1, num_points
332 [ + + ]: 28590 : do k_point = 1, num_points
333 [ - + ]: 28500 : if (regterm > tiny(regterm)) then
334 : : mat_VT_s(k_point, j_point) = mat_VT(j_point, k_point)*vec_S(j_point) / &
335 : 0 : (vec_S(j_point)**2+regterm**2)
336 : : else
337 : 27000 : mat_VT_s(k_point, j_point) = mat_VT(j_point, k_point) / vec_S(j_point)
338 : : end if
339 : : end do ! k_point
340 : : end do ! j_point
341 : :
342 : : ! 2) (U^T)*psi
343 : : call dgemm('T', 'N', num_x_nodes, 1, num_x_nodes, 1.0_dp, mat_U, num_x_nodes, psi, num_x_nodes, &
344 : 90 : 0.0_dp, vec_UT_psi, num_x_nodes)
345 : :
346 : : ! 3) (V*Sigma^-1) * (U^T*psi)
347 : : call dgemm('N', 'N', num_points, 1, num_x_nodes, 1.0_dp, mat_VT_s, num_points, vec_UT_psi, &
348 : 90 : num_x_nodes, 0.0_dp, weights_work, num_points)
349 : :
350 [ + + ]: 1590 : weights(i_point, :) = weights_work(:)
351 : :
352 : : ! calculate the maximum error of the fitting
353 : : call calculate_max_error(num_points, tau_points, omega_points, weights_work, num_x_nodes, x_mu, &
354 : 96 : psi, current_point, max_error, transformation_type)
355 : : end do ! i_point
356 : :
357 [ - + - + : 6 : deallocate (x_mu, psi, mat_A, weights_work, vec_S, mat_U, mat_VT, work, iwork, mat_VT_s, vec_UT_psi)
- + - + -
+ - + - +
- + - + -
+ - + ]
358 : :
359 [ - + - + : 6 : end subroutine get_transformation_weights
- + - + -
+ - + - +
- + - + -
+ - + ]
360 : :
361 : : !> \brief Calculate the auxiliary matrix for cosine/sin transformation for tau to omega or viceversa
362 : : !! @param[in] num_points: Number of mesh points.
363 : : !! @param[in] tau_points: imaginary time grid points
364 : : !! @param[in] omega_points: imaginary frequency grid points
365 : : !! @param[in] num_x_nodes: Number of node in the interval [e_min,e_max]
366 : : !! @param[in] x_mu : Transition energy (nodes in the interval [e_min,e_max])
367 : : !! @param[inout] psi: corresponding auxiliary function (see transformation type definition)
368 : : !! @param[inout] mat_A: auxiliary matrix (see transformation type definition)
369 : : !! @param[in] i_point: pointer for the current grid point
370 : : !! @param[inout] current_point: current grid point ether omega(i_point) or tau_(i_point)
371 : : !! @param[in] transformation type :
372 : : !! (1) the cosine transform cos(it) -> cos(iw): psi(omega,x), mat_A = cos(omega*tau)*psi(tau,x)
373 : : !! (2) the cosine transform cos(iw) -> cos(it): psi(tau,x) , mat_A = cos(omega*tau)*psi(omega,x)
374 : : !! (3) the sine transform sin(it) -> sin(iw): psi(omega,x), mat_A = sin(omega*tau)*psi(tau,x)
375 : 90 : subroutine calculate_psi_and_mat_A(num_points, tau_points, omega_points, num_x_nodes, x_mu, psi, &
376 : : mat_A, i_point, current_point, transformation_type)
377 : :
378 : : integer, intent(in) :: num_points, num_x_nodes, i_point
379 : : real(kind=dp), allocatable, dimension(:), &
380 : : intent(in) :: tau_points, omega_points, x_mu
381 : : real(kind=dp), allocatable, dimension(:), &
382 : : intent(inout) :: psi
383 : : real(kind=dp), allocatable, dimension(:, :), &
384 : : intent(inout) :: mat_A
385 : : real(kind=dp), intent(inout) :: current_point
386 : : integer, intent(in) :: transformation_type
387 : :
388 : : ! Internal variables
389 : : integer :: i_node, j_point
390 : : real(kind=dp) :: tau, omega
391 : :
392 : : ! Begin work
393 : :
394 : : ! the cosine transform cos(it) -> cos(iw)
395 [ + + ]: 90 : if (transformation_type == cosine_tw) then
396 : 30 : omega = omega_points(i_point)
397 : 30 : current_point = omega
398 : :
399 : : ! psi(omega_k,x) = 2x/(x^2+omega_k^2)
400 [ + + ]: 14030 : do i_node = 1, num_x_nodes
401 : 14030 : psi(i_node) = 2.0_dp*x_mu(i_node)/((x_mu(i_node))**2 + omega**2)
402 : : end do
403 : :
404 : : ! mat_A = cos(omega_k * tau) psi(tau,x)
405 [ + + ]: 530 : do j_point = 1, num_points
406 : 500 : tau = tau_points(j_point)
407 [ + + ]: 220530 : do i_node = 1, num_x_nodes
408 : 220500 : mat_A(i_node, j_point) = cos(omega*tau)*exp(-x_mu(i_node)*tau)
409 : : end do
410 : : end do
411 : :
412 : : ! the cosine transform cos(iw) -> cos(it)
413 [ + + ]: 60 : else if (transformation_type == cosine_wt) then
414 : 30 : tau = tau_points(i_point)
415 : 30 : current_point = tau
416 : :
417 : : ! psi(tau_k,x) = =exp(-x*|tau_k|)
418 [ + + ]: 14030 : do i_node = 1, num_x_nodes
419 : 14030 : psi(i_node) = exp(-x_mu(i_node)*tau)
420 : : end do
421 : :
422 : : ! mat_A = cos(tau_k,omega) psi(omega,x)
423 [ + + ]: 530 : do j_point = 1, num_points
424 : 500 : omega = omega_points(j_point)
425 [ + + ]: 220530 : do i_node = 1, num_x_nodes
426 : 220500 : mat_A(i_node, j_point) = cos(tau*omega)*2.0_dp*x_mu(i_node)/(x_mu(i_node)**2 + omega**2)
427 : : end do
428 : : end do
429 : :
430 : : ! the sine transform sin(it) -> sin(iw)
431 [ + - ]: 30 : else if (transformation_type == sine_tw) then
432 : 30 : omega = omega_points(i_point)
433 : 30 : current_point = omega
434 : :
435 : : ! psi(omega_k,x) = 2*omega_k/(x^2+omega_k^2)
436 [ + + ]: 14030 : do i_node = 1, num_x_nodes
437 : 14030 : psi(i_node) = 2.0_dp*omega/(x_mu(i_node)**2 + omega**2)
438 : : end do
439 : :
440 : : ! mat_A = sin(omega_k,tau)*phi(tau,x)
441 [ + + ]: 530 : do j_point = 1, num_points
442 : 500 : tau = tau_points(j_point)
443 [ + + ]: 220530 : do i_node = 1, num_x_nodes
444 : 220500 : mat_A(i_node, j_point) = sin(omega*tau)*exp(-x_mu(i_node)*tau)
445 : : end do
446 : : end do
447 : : end if
448 : :
449 : 90 : end subroutine calculate_psi_and_mat_A
450 : :
451 : : !> /brief calculate the error of the fit function for the cosine/sin transformation for tau to omega or viceversa
452 : : !! @param[in] num_points: Number of mesh points.
453 : : !! @param[in] tau_points: imaginary time grid points
454 : : !! @param[in] omega_points: imaginary frequency grid points
455 : : !! @param[in] weights_work: work vector for the transformation weights
456 : : !! @param[in] num_x_nodes: Number of node in the interval [e_min,e_max]
457 : : !! @param[in] x_mu : Transition energy (nodes in the interval [e_min,e_max])
458 : : !! @param[in] psi: corresponding auxiliary function (see transformation type definition)
459 : : !! @param[in] current_point: current grid point ether omega(i_point) or tau_(i_point)
460 : : !! @param[out] max_error: Max error for the transform.
461 : : !! @param[in] transformation type : 1 fit function for the cosine transform cos(it) -> cos(iw), psi(omeaga,x)
462 : : !! : 2 fit function for the cosine transform cos(iw) -> cos(it), psi(tau,x)
463 : : !! : 3 fit function for the sine transform sin(it) -> sin(iw), psi(omega,x)
464 : 90 : subroutine calculate_max_error(num_points, tau_points, omega_points, weights_work, num_x_nodes, x_mu, &
465 : : psi, current_point, max_error, transformation_type)
466 : :
467 : : real(kind=dp), intent(out) :: max_error
468 : : real(kind=dp), intent(in) :: current_point
469 : : real(kind=dp), allocatable, dimension(:), &
470 : : intent(in) :: tau_points, omega_points, x_mu, psi, &
471 : : weights_work
472 : : integer, intent(in) :: num_points, num_x_nodes
473 : : integer, intent(in) :: transformation_type
474 : :
475 : : ! Internal variables
476 : : integer :: i_node,i_point
477 : : real(kind=dp) :: func_val, func_val_temp, max_error_tmp, &
478 : : tau, omega, x_val
479 : :
480 : : ! Begin work
481 : 90 : max_error_tmp = 0.0_dp
482 : :
483 : : ! the cosine transform cos(it) -> cos(iw)
484 [ + + ]: 90 : if (transformation_type == cosine_tw) then
485 : 30 : omega=current_point
486 : :
487 [ + + ]: 14030 : do i_node = 1, num_x_nodes
488 : 14000 : func_val = 0.0_dp
489 : : ! calculate value of the fit function f(x) = f(x) + weights(omega)cos(omega*tau)psi(tau.x)
490 [ + + ]: 234000 : do i_point = 1, num_points
491 : 220000 : tau = tau_points(i_point)
492 : 234000 : func_val = func_val + weights_work(i_point)*cos(omega*tau)*exp(-x_mu(i_node)*tau)
493 : : end do
494 : :
495 : 14030 : if (abs(psi(i_node) - func_val) > max_error_tmp) then
496 : : max_error_tmp = abs(psi(i_node) - func_val)
497 : : func_val_temp = func_val
498 : : end if
499 : : end do
500 : :
501 : : ! the cosine transform cos(iw) -> cos(it)
502 [ + + ]: 60 : else if (transformation_type == cosine_wt) then
503 : 30 : tau = current_point
504 : :
505 [ + + ]: 14030 : do i_node = 1, num_x_nodes
506 : 14000 : func_val = 0.0_dp
507 : 14000 : x_val=x_mu(i_node)
508 : : ! calculate value of the fit function f(x) = f(x) + weights(tau)cos(omega*tau)psi(omega.x)
509 [ + + ]: 234000 : do i_point = 1, num_points
510 : 220000 : omega = omega_points(i_point)
511 : 234000 : func_val = func_val + weights_work(i_point)*cos(tau*omega)*2.0_dp*x_val/(x_val**2 + omega**2)
512 : : end do
513 : :
514 : 14030 : if (abs(psi(i_node) - func_val) > max_error_tmp) then
515 : : max_error_tmp = abs(psi(i_node) - func_val)
516 : : func_val_temp = func_val
517 : : end if
518 : : end do
519 : :
520 : : ! the sine transform sin(it) -> sin(iw)
521 [ + - ]: 30 : else if (transformation_type == sine_tw) then
522 : 30 : omega = current_point
523 : :
524 [ + + ]: 14030 : do i_node = 1, num_x_nodes
525 : 14000 : func_val = 0.0_dp
526 : : ! calculate value of the fit function f(x) = f(x) + weights(omega)sin(omega*tau)psi(tau.x)
527 [ + + ]: 234000 : do i_point = 1, num_points
528 : 220000 : tau = tau_points(i_point)
529 : 234000 : func_val = func_val + weights_work(i_point)*sin(omega*tau)*exp(-x_mu(i_node)*tau)
530 : : end do
531 : :
532 : 14030 : if (abs(psi(i_node) - func_val) > max_error_tmp) then
533 : : max_error_tmp = abs(psi(i_node) - func_val)
534 : : func_val_temp = func_val
535 : : end if
536 : : end do
537 : : end if
538 : :
539 [ + + ]: 90 : if (max_error_tmp > max_error) then
540 : 13 : max_error = max_error_tmp
541 : : end if
542 : :
543 : 90 : end subroutine calculate_max_error
544 : :
545 : : end module minimax_grids
|