Octopus
chebyshev_coefficients.F90
Go to the documentation of this file.
1!! Copyright (C) 2024 S. Ohlmann
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
22 use debug_oct_m
23 use fftw_oct_m
25 use global_oct_m
26 use, intrinsic :: iso_c_binding
27 use, intrinsic :: iso_fortran_env
29 use math_oct_m
32
33 implicit none
34
35 private
36 public :: &
41
42 type, abstract :: chebyshev_function_t
43 private
44 real(real64) :: half_span
45 real(real64) :: middle_point
46 real(real64) :: deltat
47 contains
48 procedure(chebyshev_get_coefficients), deferred :: get_coefficients
49 procedure(chebyshev_get_error), deferred :: get_error
50 procedure :: set_parameters => chebyshev_set_parameters
52
53 abstract interface
54 subroutine chebyshev_get_coefficients(this, order, coefficients)
56 import real64
57 implicit none
58 class(chebyshev_function_t), intent(in) :: this
59 integer, intent(in) :: order
60 complex(real64), allocatable, intent(out) :: coefficients(:)
61 end subroutine chebyshev_get_coefficients
62
63 real(real64) function chebyshev_get_error(this, order)
65 import real64
66 implicit none
67 class(chebyshev_function_t), intent(in) :: this
68 integer, intent(in) :: order
69 end function chebyshev_get_error
70 end interface
71
72
74 contains
75 procedure :: get_coefficients => chebyshev_exp_coefficients
76 procedure :: get_error => chebyshev_exp_error
77 end type chebyshev_exp_t
78
79 interface chebyshev_exp_t
80 procedure chebyshev_exp_constructor
81 end interface chebyshev_exp_t
82
83
85 contains
86 procedure :: get_coefficients => chebyshev_exp_imagtime_coefficients
87 procedure :: get_error => chebyshev_exp_imagtime_error
89
91 procedure chebyshev_exp_imagtime_constructor
92 end interface chebyshev_exp_imagtime_t
93
94 ! interface needed to save function pointer in type
95 abstract interface
96 complex(real64) function complex_function_i(z)
97 import real64
98 implicit none
99 complex(real64), intent(in) :: z
100 end function complex_function_i
101 end interface
102
103
105 procedure(complex_function_i), pointer, nopass :: complex_function
106 contains
107 procedure :: get_coefficients => chebyshev_numerical_coefficients
108 procedure :: get_error => chebyshev_numerical_error
109 end type chebyshev_numerical_t
110
111 interface chebyshev_numerical_t
112 procedure chebyshev_numerical_constructor
113 end interface chebyshev_numerical_t
115contains
116
117 subroutine chebyshev_set_parameters(this, half_span, middle_point, deltat)
118 class(chebyshev_function_t), intent(inout) :: this
119 real(real64), intent(in) :: half_span
120 real(real64), intent(in) :: middle_point
121 real(real64), intent(in) :: deltat
122
124
125 this%half_span = half_span
126 this%middle_point = middle_point
127 this%deltat = deltat
128
130 end subroutine chebyshev_set_parameters
131
132 function chebyshev_exp_constructor(half_span, middle_point, deltat) result(chebyshev_function)
133 class(chebyshev_exp_t), pointer :: chebyshev_function
134 real(real64), intent(in) :: half_span
135 real(real64), intent(in) :: middle_point
136 real(real64), intent(in) :: deltat
140 allocate(chebyshev_function)
141 call chebyshev_function%set_parameters(half_span, middle_point, deltat)
144 end function chebyshev_exp_constructor
145
146 subroutine chebyshev_exp_coefficients(this, order, coefficients)
147 class(chebyshev_exp_t), intent(in) :: this
148 integer, intent(in) :: order
149 complex(real64), allocatable, intent(out) :: coefficients(:)
150
151 integer :: i
152
154 safe_allocate(coefficients(0:order))
155 do i = 0, order
156 coefficients(i) = exp(-m_zi*this%middle_point*this%deltat) * &
157 (-m_zi)**i * m_two * loct_bessel(i, this%half_span*this%deltat)
158 end do
159 coefficients(0) = coefficients(0) / m_two
161 end subroutine chebyshev_exp_coefficients
162
165 real(real64) function chebyshev_exp_error(this, order)
166 class(chebyshev_exp_t), intent(in) :: this
167 integer, intent(in) :: order
169 real(real64) :: r, inv_r
170
171 push_sub(chebyshev_exp_error)
172 if (order >= this%half_span*this%deltat) then
173 r = m_two*(order+1)/abs(this%half_span*this%deltat)
174 inv_r = m_one/r
175 chebyshev_exp_error = m_two*inv_r**(order+1)/(m_one - inv_r) * exp(abs(this%half_span*this%deltat)*(r-inv_r)/m_two)
176 else
178 end if
181
182 function chebyshev_exp_imagtime_constructor(half_span, middle_point, deltat) result(chebyshev_function)
183 class(chebyshev_exp_imagtime_t), pointer :: chebyshev_function
184 real(real64), intent(in) :: half_span
185 real(real64), intent(in) :: middle_point
186 real(real64), intent(in) :: deltat
187
190 allocate(chebyshev_function)
191 call chebyshev_function%set_parameters(half_span, middle_point, deltat)
192
195
196 subroutine chebyshev_exp_imagtime_coefficients(this, order, coefficients)
197 class(chebyshev_exp_imagtime_t), intent(in) :: this
198 integer, intent(in) :: order
199 complex(real64), allocatable, intent(out) :: coefficients(:)
201 integer :: i
202
204 safe_allocate(coefficients(0:order))
205 do i = 0, order
206 coefficients(i) = exp(-this%middle_point*this%deltat) * &
207 m_two * loct_bessel_in(i, -this%half_span*this%deltat)
208 end do
209 coefficients(0) = coefficients(0) / m_two
212
217 real(real64) function chebyshev_exp_imagtime_error(this, order)
218 class(chebyshev_exp_imagtime_t), intent(in) :: this
219 integer, intent(in) :: order
220
221 real(real64) :: upper_bound, lower_bound
222 real(real64), parameter :: b = 0.618, d = 0.438
223
225 upper_bound = this%half_span+this%middle_point
226 lower_bound = -this%half_span+this%middle_point
227 if (order <= upper_bound*this%deltat) then
228 chebyshev_exp_imagtime_error = m_two*exp(-lower_bound*this%deltat)*exp(-b*(order+1)**2/(upper_bound*this%deltat))*&
229 (m_one+sqrt(upper_bound*this%deltat*m_pi/(m_four*b))) + m_two*d**(upper_bound*this%deltat)/(m_one-d)
230 else
231 chebyshev_exp_imagtime_error = m_two*exp(-lower_bound*this%deltat)*d**order/(m_one-d)
232 end if
235
236 function chebyshev_numerical_constructor(half_span, middle_point, deltat, complex_function) result(chebyshev_function)
237 class(chebyshev_numerical_t), pointer :: chebyshev_function
238 real(real64), intent(in) :: half_span
239 real(real64), intent(in) :: middle_point
240 real(real64), intent(in) :: deltat
241 procedure(complex_function_i) :: complex_function
242
244
245 allocate(chebyshev_function)
246 call chebyshev_function%set_parameters(half_span, middle_point, deltat)
247 chebyshev_function%complex_function => complex_function
248
251
254 subroutine chebyshev_numerical_coefficients(this, order, coefficients)
255 class(chebyshev_numerical_t), intent(in) :: this
256 integer, intent(in) :: order
257 complex(real64), allocatable, intent(out) :: coefficients(:)
259 integer :: i
260 complex(real64) :: values(0:order)
261 real(real64) :: re_values(0:order), im_values(0:order)
262 real(real64) :: re_coefficients(0:order), im_coefficients(0:order)
263 real(real64) :: theta
264 type(c_ptr) :: plan
265
267 safe_allocate(coefficients(0:order))
268 ! compute values for DCT
269 do i = 0, order
270 theta = m_pi*i/order
271 values(i) = this%complex_function(-m_zi*this%deltat*(this%half_span*cos(theta)+this%middle_point))
272 re_values(i) = real(values(i), real64)
273 im_values(i) = aimag(values(i))
274 end do
275 plan = fftw_plan_r2r_1d(order+1, re_values, re_coefficients, fftw_redft00, fftw_estimate)
276 call fftw_execute_r2r(plan, re_values, re_coefficients)
277 call fftw_execute_r2r(plan, im_values, im_coefficients)
278 call fftw_destroy_plan(plan)
279 do i = 0, order
280 ! normalize correctly, also need factor 2 for expansion coefficients
281 coefficients(i) = cmplx(re_coefficients(i), im_coefficients(i), real64)/order
282 end do
283 ! need to divide first and last coefficient by 2
284 coefficients(0) = coefficients(0) / m_two
285 coefficients(order) = coefficients(order) / m_two
286
292 real(real64) function chebyshev_numerical_error(this, order)
293 class(chebyshev_numerical_t), intent(in) :: this
294 integer, intent(in) :: order
295
296 real(real64) :: r
297 real(real64) :: inv_r
298
300 if (order >= this%half_span*this%deltat) then
301 r = m_two*order/abs(this%half_span*this%deltat)
302 inv_r = m_one/r
303 chebyshev_numerical_error = m_two*inv_r**order/(m_one - inv_r) * &
304 real(this%complex_function(cmplx(abs(this%half_span*this%deltat)*(r-inv_r)/M_TWO, M_ZERO, real64)), real64)
305 else
307 end if
309 end function chebyshev_numerical_error
311
312!! Local Variables:
313!! mode: f90
314!! coding: utf-8
315!! End:
double exp(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
class(chebyshev_numerical_t) function, pointer chebyshev_numerical_constructor(half_span, middle_point, deltat, complex_function)
class(chebyshev_exp_t) function, pointer chebyshev_exp_constructor(half_span, middle_point, deltat)
real(real64) function chebyshev_exp_error(this, order)
Use the error estimate from Lubich, C. From Quantum to Classical Molecular Dynamics: Reduced Models a...
class(chebyshev_exp_imagtime_t) function, pointer chebyshev_exp_imagtime_constructor(half_span, middle_point, deltat)
subroutine chebyshev_numerical_coefficients(this, order, coefficients)
use a discrete cosine transform to compute the coefficients because no analytical formula is availabl...
subroutine chebyshev_set_parameters(this, half_span, middle_point, deltat)
real(real64) function chebyshev_numerical_error(this, order)
use the error estimate from Lubich, C. From Quantum to Classical Molecular Dynamics: Reduced Models a...
subroutine chebyshev_exp_coefficients(this, order, coefficients)
subroutine chebyshev_exp_imagtime_coefficients(this, order, coefficients)
real(real64) function chebyshev_exp_imagtime_error(this, order)
Use the error estimate from Hochbruck, M. & Ostermann, A. Exponential integrators....
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
real(real64) function values(xx)
Definition: test.F90:1867