(git:374b731)
Loading...
Searching...
No Matches
negf_integr_utils.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Helper functions for integration routines.
10!> \par History
11!> * 06.2017 created [Sergey Chulkov]
12! **************************************************************************************************
14 USE kinds, ONLY: dp
15 USE mathconstants, ONLY: pi
16#include "./base/base_uses.f90"
17 IMPLICIT NONE
18 PRIVATE
19
20 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_integr_utils'
21 LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .true.
22
26
27 INTEGER, PARAMETER, PUBLIC :: contour_shape_linear = 0, &
29
31 MODULE PROCEDURE equidistant_dnodes_a_b
32 MODULE PROCEDURE equidistant_znodes_a_b
33 END INTERFACE
34
35CONTAINS
36
37! **************************************************************************************************
38!> \brief Compute equidistant nodes on an interval [a, b], where a and b are complex numbers.
39!> \param a lower bound
40!> \param b upper bound
41!> \param nnodes number of nodes
42!> \param xnodes array to store the nodes
43!> \par History
44!> * 05.2017 created [Sergey Chulkov]
45! **************************************************************************************************
46 SUBROUTINE equidistant_dnodes_a_b(a, b, nnodes, xnodes)
47 REAL(kind=dp), INTENT(in) :: a, b
48 INTEGER, INTENT(in) :: nnodes
49 REAL(kind=dp), DIMENSION(nnodes), INTENT(out) :: xnodes
50
51 INTEGER :: i
52 REAL(kind=dp) :: rscale
53
54 cpassert(nnodes >= 1)
55
56 rscale = (b - a)/real(nnodes - 1, kind=dp)
57 DO i = 1, nnodes
58 xnodes(i) = a + rscale*real(i - 1, kind=dp)
59 END DO
60 END SUBROUTINE equidistant_dnodes_a_b
61! **************************************************************************************************
62!> \brief Compute equidistant nodes on an interval [a, b], where a and b are complex numbers.
63!> \param a lower bound
64!> \param b upper bound
65!> \param nnodes number of nodes
66!> \param xnodes array to store the nodes
67!> \par History
68!> * 05.2017 created [Sergey Chulkov]
69! **************************************************************************************************
70 SUBROUTINE equidistant_znodes_a_b(a, b, nnodes, xnodes)
71 COMPLEX(kind=dp), INTENT(in) :: a, b
72 INTEGER, INTENT(in) :: nnodes
73 COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out) :: xnodes
74
75 INTEGER :: i
76 COMPLEX(kind=dp) :: rscale
77
78 cpassert(nnodes >= 1)
79
80 rscale = (b - a)/real(nnodes - 1, kind=dp)
81 DO i = 1, nnodes
82 xnodes(i) = a + rscale*real(i - 1, kind=dp)
83 END DO
84 END SUBROUTINE equidistant_znodes_a_b
85
86 SUBROUTINE rescale_normalised_nodes(nnodes, tnodes, a, b, shape_id, xnodes, weights)
87 INTEGER, INTENT(in) :: nnodes
88 REAL(kind=dp), DIMENSION(nnodes), INTENT(in) :: tnodes
89 COMPLEX(kind=dp), INTENT(in) :: a, b
90 INTEGER, INTENT(in) :: shape_id
91 COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out), &
92 OPTIONAL :: xnodes, weights
93
94 CHARACTER(len=*), PARAMETER :: routinen = 'rescale_normalised_nodes'
95
96 INTEGER :: handle, i
97 REAL(kind=dp) :: rscale
98 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: tnodes_angle
99
100 CALL timeset(routinen, handle)
101
102 SELECT CASE (shape_id)
104 IF (PRESENT(xnodes)) &
105 CALL rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
106
107 IF (PRESENT(weights)) &
108 weights(:) = b - a
109
110 CASE (contour_shape_arc)
111 ALLOCATE (tnodes_angle(nnodes))
112
113 tnodes_angle(:) = tnodes(:)
114 CALL rescale_nodes_pi_phi(a, b, nnodes, tnodes_angle)
115
116 IF (PRESENT(xnodes)) &
117 CALL rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
118
119 IF (PRESENT(weights)) THEN
120 rscale = (pi - get_arc_smallest_angle(a, b))*get_arc_radius(a, b)
121
122 DO i = 1, nnodes
123 weights(i) = rscale*cmplx(sin(tnodes_angle(i)), -cos(tnodes_angle(i)), kind=dp)
124 END DO
125 END IF
126
127 DEALLOCATE (tnodes_angle)
128 CASE DEFAULT
129 cpabort("Unimplemented integration shape")
130 END SELECT
131
132 CALL timestop(handle)
133 END SUBROUTINE rescale_normalised_nodes
134
135! **************************************************************************************************
136!> \brief Compute arc radius.
137!> \param a lower bound
138!> \param b upper bound
139!> \return radius
140!> \par History
141!> * 05.2017 created [Sergey Chulkov]
142!> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
143! c *
144! r * B-------+------
145! a * / . |
146! * r / . | delta
147! * / phi . |
148! A---------*-----------+------
149! <--- r --><-l->
150! <--- r --->
151! **************************************************************************************************
152 PURE FUNCTION get_arc_radius(a, b) RESULT(radius)
153 COMPLEX(kind=dp), INTENT(in) :: a, b
154 REAL(kind=dp) :: radius
155
156 COMPLEX(kind=dp) :: b_minus_a
157
158 b_minus_a = b - a
159
160 ! l = REAL(B - A); delta = AIMAG(B - A)
161 ! radius = (l^2 + delta^2) / (2 * l)
162 radius = 0.5_dp*real(b_minus_a*conjg(b_minus_a), kind=dp)/real(b_minus_a, kind=dp)
163 END FUNCTION get_arc_radius
164
165! **************************************************************************************************
166!> \brief Compute the angle phi.
167!> \param a lower bound
168!> \param b upper bound
169!> \return angle
170!> \par History
171!> * 05.2017 created [Sergey Chulkov]
172!> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
173! c *
174! r * B-------+------
175! a * / . |
176! * r / . | delta
177! * / phi . |
178! A---------*-----------+------
179! <--- r --><-l->
180! <--- r --->
181! **************************************************************************************************
182 PURE FUNCTION get_arc_smallest_angle(a, b) RESULT(phi)
183 COMPLEX(kind=dp), INTENT(in) :: a, b
184 REAL(kind=dp) :: phi
185
186 COMPLEX(kind=dp) :: b_minus_a
187 REAL(kind=dp) :: delta2, l2
188
189 b_minus_a = b - a
190
191 ! l = REAL(B - A); delta = AIMAG(B - A)
192 ! phi = arccos((l - radius)/radius) = arccos((l^2 - delta^2) / (l^2 + delta^2))
193 l2 = real(b_minus_a, dp)
194 l2 = l2*l2
195 delta2 = aimag(b_minus_a)
196 delta2 = delta2*delta2
197
198 phi = acos((l2 - delta2)/(l2 + delta2))
199 END FUNCTION get_arc_smallest_angle
200
201 PURE FUNCTION get_axis_rotation_angle(a, b) RESULT(phi)
202 COMPLEX(kind=dp), INTENT(in) :: a, b
203 REAL(kind=dp) :: phi
204
205 COMPLEX(kind=dp) :: b_minus_a
206
207 b_minus_a = b - a
208 phi = acos(real(b_minus_a, dp)/abs(b_minus_a))
209 END FUNCTION get_axis_rotation_angle
210
211! **************************************************************************************************
212!> \brief Rescale nodes [pi, phi] -> arc[a, b] .
213!> \param nnodes number of nodes
214!> \param tnodes_angle parametrically-defined nodes to rescale
215!> \param a lower bound
216!> \param b upper bound
217!> \param xnodes rescaled nodes (initialised on exit)
218!> \par History
219!> * 05.2017 created [Sergey Chulkov]
220!> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
221! **************************************************************************************************
222 SUBROUTINE rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
223 INTEGER, INTENT(in) :: nnodes
224 REAL(kind=dp), DIMENSION(:), INTENT(in) :: tnodes_angle
225 COMPLEX(kind=dp), INTENT(in) :: a, b
226 COMPLEX(kind=dp), DIMENSION(:), INTENT(out) :: xnodes
227
228 COMPLEX(kind=dp) :: origin
229 INTEGER :: i
230 REAL(kind=dp) :: radius
231
232 radius = get_arc_radius(a, b)
233 origin = a + cmplx(radius, 0.0_dp, kind=dp)
234
235 DO i = 1, nnodes
236 xnodes(i) = origin + radius*cmplx(cos(tnodes_angle(i)), sin(tnodes_angle(i)), kind=dp)
237 END DO
238 END SUBROUTINE rescale_nodes_arc
239
240! **************************************************************************************************
241!> \brief Rescale nodes tnodes(i) = cos(pi/2 * (1-tnodes(i))); tnodes \in [-1 .. 1] .
242!> \param tnodes parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
243!> \par History
244!> * 05.2017 created [Sergey Chulkov]
245!> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
246! **************************************************************************************************
247 SUBROUTINE rescale_nodes_cos(nnodes, tnodes)
248 INTEGER, INTENT(in) :: nnodes
249 REAL(kind=dp), DIMENSION(nnodes), INTENT(inout) :: tnodes
250
251 tnodes(:) = cos(0.5_dp*pi*(1.0_dp - tnodes(:)))
252 END SUBROUTINE rescale_nodes_cos
253
254! **************************************************************************************************
255!> \brief Rescale nodes [-1, 1] -> [a, b] .
256!> \param nnodes number of nodes
257!> \param tnodes parametrically-defined nodes to rescale
258!> \param a lower bound
259!> \param b upper bound
260!> \param xnodes rescaled nodes (initialised on exit)
261!> \par History
262!> * 05.2017 created [Sergey Chulkov]
263! **************************************************************************************************
264 SUBROUTINE rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
265 INTEGER, INTENT(in) :: nnodes
266 REAL(kind=dp), DIMENSION(nnodes), INTENT(in) :: tnodes
267 COMPLEX(kind=dp), INTENT(in) :: a, b
268 COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out) :: xnodes
269
270 COMPLEX(kind=dp) :: half_len, median
271
272 median = 0.5_dp*(b + a)
273 half_len = 0.5_dp*(b - a)
274
275 xnodes(:) = median + half_len*tnodes(:)
276 END SUBROUTINE rescale_nodes_linear
277
278! **************************************************************************************************
279!> \brief Rescale nodes [-1, 1] -> [pi, phi] .
280!> \param nnodes number of nodes
281!> \param a lower bound
282!> \param b upper bound
283!> \param tnodes parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
284!> \par History
285!> * 05.2017 created [Sergey Chulkov]
286!> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
287! **************************************************************************************************
288 SUBROUTINE rescale_nodes_pi_phi(a, b, nnodes, tnodes)
289 COMPLEX(kind=dp), INTENT(in) :: a, b
290 INTEGER, INTENT(in) :: nnodes
291 REAL(kind=dp), DIMENSION(nnodes), INTENT(inout) :: tnodes
292
293 REAL(kind=dp) :: half_pi_minus_phi, phi
294
295 phi = get_arc_smallest_angle(a, b)
296 half_pi_minus_phi = 0.5_dp*(pi - phi)
297
298 tnodes(:) = phi + half_pi_minus_phi*(1.0_dp - tnodes(:))
299 END SUBROUTINE rescale_nodes_pi_phi
300END MODULE negf_integr_utils
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
Helper functions for integration routines.
subroutine, public rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
Rescale nodes [pi, phi] -> arc[a, b] .
pure real(kind=dp) function, public get_arc_smallest_angle(a, b)
Compute the angle phi.
subroutine, public rescale_normalised_nodes(nnodes, tnodes, a, b, shape_id, xnodes, weights)
subroutine, public rescale_nodes_cos(nnodes, tnodes)
Rescale nodes tnodes(i) = cos(pi/2 * (1-tnodes(i))); tnodes \in [-1 .. 1] .
pure real(kind=dp) function, public get_arc_radius(a, b)
Compute arc radius.
integer, parameter, public contour_shape_arc
subroutine, public rescale_nodes_pi_phi(a, b, nnodes, tnodes)
Rescale nodes [-1, 1] -> [pi, phi] .
integer, parameter, public contour_shape_linear
subroutine, public rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
Rescale nodes [-1, 1] -> [a, b] .