Octopus
splines.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
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
21!/*----------------------------------------------------------------------------
22! This module contains a data type (spline_t) to contain 1D functions,
23! along with a series of procedures to manage them (to define them, to obtain
24! its values, to operate on them, etc). The internal representation of the
25! functions is done through cubic splines, handled by the GSL library. For
26! the user of the module, this internal representation is hidden; one just
27! works with what are called hereafter "spline functions".
28!
29! To define a function, one must supply a set {x(i),y(i)} of pairs of values
30! -- the abscissa and the value of the function.
31!
32! [*] DATA TYPE:
33! To define a spline function:
34! type(spline_t) :: f
35!
36! [1] INITIALIZATION:
37! Before using any function, one should initialize it:
38!
39! Interface:
40! subroutine spline_init(spl)
41! type(spline_t), intent(out) :: spl [or spl(:) or spl(:, :)]
42! end subroutine spline_init
43!
44! Usage:
45! call spline_init(f)
46!
47! [2] FINALIZATION:
48! To empty any allocated space, one should finalize the function:
49!
50! Interface:
51! subroutine spline_end(spl)
52! type(spline_t), intent(inout) :: spl [or spl(:) or spl(:, :)]
53! end subroutine spline_end
54!
55! Usage
56! type(spline_t) :: f
57! call spline_end(f)
58!
59! [3] TO DEFINE A FUNCTION:
60! To "fill" an initialized function f,use spline_fit
61!
62! Interface:
63! subroutine spline_fit(n, x, y, spl, threshold)
64! integer, intent(in) :: nrc
65! real(X), intent(in) :: x(n), y(n)
66! type(spline_t), intent(out) :: spl
67! real(real64), optional, intent(in) :: threshold
68! end subroutine spline_fit
69!
70! (X may be 4 or eight, for single or double precision)
71!
72! Usage:
73! call spline_fit(n, x, y, f)
74! n is the number of values that are supplied, x the abscissas, and y
75! the value of the function to represent at each point.
76! The optional argument threshold is used to find the radius associated with the spline.
77!
78! [4] FUNCTION VALUES:
79! To retrieve the value of a function at a given point:
80!
81! Interface:
82!
83! real(real64) function spline_eval(spl, x)
84! type(spline_t), intent(in) :: spl
85! real(real64), intent(in) :: x
86! end function spline_eval
87!
88! Usage:
89! To retrieve the value of function f at point x, and place it into
90! real value val:
91! val = spline_eval(f, x)
92!
93! [5] SUM:
94! If you have two defined functions, f and g, and an initialized function
95! h, you may sum f and g and place the result onto g. For this purpose,
96! the grid that defined the first operand, f, will be used -- the values
97! of g will be interpolated to get the sum and place it in h.
98!
99! Interface:
100! subroutine spline_sum(spl1, spl2, splsum, threshold)
101! type(spline_t), intent(in) :: spl1, spl2
102! type(spline_t), intent(out) :: splsum
103! real(r8), optional, intent(in) :: threshold
104! end subroutine spline_sum
105!
106! Usage:
107! call spline_init(f)
108! call spline_init(g)
109! call spline_init(h)
110! call spline_fit(npointsf, xf, yf, f)
111! call spline_fit(npointsg, xg, yg, g)
112! call spline_sum(f, g, h)
113!
114! [6] MULTIPLICATION BY A SCALAR
115! You may multiply a given spline-represented spline by a real number:
116!
117! Interface:
118! subroutine spline_times(a, spl)
119! type(spline_t), intent(inout) :: spl
120! real(real64), intent(in) :: a
121! real(real64), optional, intent(in) :: threshold
122! end subroutine spline_times
123!
124! Usage:
125! call spline_init(f)
126! call spline_fit(npoints, x, y, f) ! Fill f with y values at x points
127! call spline_times(a, f) ! Now f contains a*y values at x points.
128!
129! [7] INTEGRAL:
130! Given a defined function, the function spline_integral returns its
131! integral. The interval of integration may or may not be supplied.
132!
133! Interface:
134! real(real64) function spline_integral(spl [,a,b])
135! type(spline_integral), intent(in) :: spl
136! real(real64), intent(in), optional :: a, b
137! end function spline_integral
138!
139! [8] DOT PRODUCT:
140! Given two defined functions f and g, the function spline_dotp returns
141! the value of their dot-product: int {dx f(x)*g(x)}. The mesh used to do
142! so the mesh of the fist-function (note that as a result the definition
143! is no longer conmutative).
144!
145! Interface:
146! real(real64) function spline_dotp(spl1, spl2)
147! type(spline_t), intent(in) :: spl1, spl2
148! end function spline_dotp
149!
150! Note: The following routines, spline_3dft, spline_cut and spline_filter,
151! assume that the spline functions are the radial part of a 3 dimensional function with
152! spherical symmetry. This is why the Fourier transform of F(\vec{r}) = f(r), is:
153! F(\vec{g}) = f(g) = \frac{4\pi}{g} \int_{0}^{\infty} { r*sin(g*r)*f(r) }
154! which coincides with the inverse Fourier transform, except that the inverse Fourier
155! transform should be multiplied by a (2*\pi)^{-3} factor.
157! [9] FOURIER TRANSFORM:
158! If a spline function f is representing the radial part of a spherically
159! symmetric function F(\vec{r}), its Fourier transform is:
160! F(\vec{g}) = f(g) = \frac{4\pi}{g} \int_{0}^{\infty} { r*sin(g*r)*f(r) }
161! It is assumed that f is defined in some interval [0,rmax], and that it is
162! null at rmax and beyond. One may obtain f(g) by using spline_3dft.
163! The result is placed on the spline data type splw. This has to be initialized,
164! and may or may not be filled. If it is filled, the abscissas that it has
165! are used to define the function. If it is not filled, an equally spaced
166! grid is constructed to define the function, in the interval [0, gmax], where
167! gmax has to be supplied by the caller.
168!
169! Interface:
170! subroutine spline_3dft(spl, splw, gmax)
171! type(spline_t), intent(in) :: spl
172! type(spline_t), intent(inout) :: splw
173! real(real64), intent(in), optional :: gmax
174! end subroutine spline_3dft
175!
176! [10] BESSEL TRANSFORM:
177!
178!
179! [11] CUTTING A FUNCTION:
180! spline_cut multiplies a given function by a cutoff-function, which
181! is defined to be one in [0, cutoff], and \exp\{-beta*(x/cutoff-1)^2\}
182!
183! Interface:
184! subroutine spline_cut(spl, cutoff, beta)
185! type(spline_t), intent(in) :: spl
186! real(real64), intent(in) :: cutoff, beta
187! end subroutine spline_cut
188!
189! [13] PRINTING A FUNCTION:
190! It prints to a file the (x,y) values that were used to define a function.
191! The file is pointed to by its Fortran unit given by argument iunit.
192!
193! Interface:
194! subroutine spline_print(spl, iunit)
195! type(spline_t), intent(in) :: spl [ or spl(:) or spl(:, :)]
196! integer, intent(in) :: iunit
197! end subroutine spline_print
198!
199! [14] DIFFERENTIATE A FUNCTION:
201!----------------------------------------------------------------------------*/!
202module splines_oct_m
203 use debug_oct_m
204 use global_oct_m
205 use iso_c_binding
206 use, intrinsic :: iso_fortran_env
210
211 implicit none
212
213 ! Define which routines can be seen from the outside.
214 private
215 public :: &
216 spline_t, & ! [*]
217 spline_init, & ! [1]
218 spline_end, & ! [2]
219 spline_fit, & ! [3]
220 spline_eval, & ! [4]
221 spline_eval_vec, & ! [4]
222 spline_sum, & ! [5]
223 spline_times, & ! [6]
224 spline_integral, & ! [7]
225 spline_dotp, & ! [8]
226 spline_3dft, & ! [9]
227 spline_besselft, & ! [10]
228 spline_cut, & ! [11]
229 spline_print, & ! [13]
230 spline_der, &
231 spline_der2, &
232 spline_div, &
233 spline_mult, &
239
241 type spline_t
242 private
243 real(real64) :: x_limit(2)
244 type(c_ptr) :: spl, acc
245 real(real64), public :: x_threshold
247 end type spline_t
248
251 interface spline_eval_vec
252 module procedure spline_eval8_array
253 module procedure spline_evalz_array
254 end interface spline_eval_vec
258 interface spline_integral
259 module procedure spline_integral_full
260 module procedure spline_integral_limits
261 end interface spline_integral
262
264 interface spline_init
265 module procedure spline_init_0
266 module procedure spline_init_1
267 module procedure spline_init_2
268 end interface spline_init
269
270 interface spline_end
271 module procedure spline_end_0
272 module procedure spline_end_1
273 module procedure spline_end_2
274 end interface spline_end
275
276 interface spline_print
277 module procedure spline_print_0
278 module procedure spline_print_1
279 module procedure spline_print_2
280 end interface spline_print
281
282 ! These are interfaces to functions defined in oct_gsl_f.c, which in turn
283 ! take care of calling the GSL library.
284 interface
285 subroutine oct_spline_end(spl, acc)
286 use iso_c_binding
287 implicit none
288 type(c_ptr), intent(inout) :: spl, acc
289 end subroutine oct_spline_end
290
291 subroutine oct_spline_fit(nrc, x, y, spl, acc)
292 use iso_c_binding
293 use, intrinsic :: iso_fortran_env
294 implicit none
295 integer, intent(in) :: nrc
296 real(real64), intent(in) :: x
297 real(real64), intent(in) :: y
298 type(c_ptr), intent(inout) :: spl
299 type(c_ptr), intent(inout) :: acc
300 end subroutine oct_spline_fit
301
302 real(real64) function oct_spline_eval(x, spl, acc)
303 use iso_c_binding
304 use, intrinsic :: iso_fortran_env
305 implicit none
306 real(real64), intent(in) :: x
307 type(c_ptr), intent(in) :: spl
308 type(c_ptr), intent(in) :: acc
309 end function oct_spline_eval
310
311 subroutine oct_spline_eval_array(nn, xf, spl, acc)
312 use iso_c_binding
313 use, intrinsic :: iso_fortran_env
314 implicit none
315 integer, intent(in) :: nn
316 real(real64), intent(inout) :: xf
317 type(c_ptr), intent(in) :: spl
318 type(c_ptr), intent(in) :: acc
319 end subroutine oct_spline_eval_array
320
321 subroutine oct_spline_eval_arrayz(nn, xf, spl, acc)
322 use iso_c_binding
323 use, intrinsic :: iso_fortran_env
324 implicit none
325 integer, intent(in) :: nn
326 complex(real64), intent(inout) :: xf
327 type(c_ptr), intent(in) :: spl
328 type(c_ptr), intent(in) :: acc
330
331 real(real64) function oct_spline_eval_der(x, spl, acc)
332 use iso_c_binding
333 use, intrinsic :: iso_fortran_env
334 implicit none
335 real(real64), intent(in) :: x
336 type(c_ptr), intent(in) :: spl
337 type(c_ptr), intent(in) :: acc
338 end function oct_spline_eval_der
339
340 real(real64) function oct_spline_eval_der2(x, spl, acc)
341 use iso_c_binding
342 use, intrinsic :: iso_fortran_env
343 implicit none
344 real(real64), intent(in) :: x
345 type(c_ptr), intent(in) :: spl
346 type(c_ptr), intent(in) :: acc
347 end function oct_spline_eval_der2
348
349 integer pure function oct_spline_npoints(spl, acc)
350 use iso_c_binding
351 implicit none
352 type(c_ptr), intent(in) :: spl
353 type(c_ptr), intent(in) :: acc
354 end function oct_spline_npoints
355
356 pure subroutine oct_spline_x(spl, x)
357 use iso_c_binding
358 use, intrinsic :: iso_fortran_env
359 implicit none
360 type(c_ptr), intent(in) :: spl
361 real(real64), intent(out) :: x
362 end subroutine oct_spline_x
364 subroutine oct_spline_y(spl, y)
365 use iso_c_binding
366 use, intrinsic :: iso_fortran_env
367 implicit none
368 type(c_ptr), intent(in) :: spl
369 real(real64), intent(out) :: y
370 end subroutine oct_spline_y
371
372 real(real64) pure function oct_spline_eval_integ(spl, a, b, acc)
373 use iso_c_binding
374 use, intrinsic :: iso_fortran_env
375 implicit none
376 type(c_ptr), intent(in) :: spl
377 real(real64), intent(in) :: a
378 real(real64), intent(in) :: b
379 type(c_ptr), intent(in) :: acc
380 end function oct_spline_eval_integ
381
382 real(real64) pure function oct_spline_eval_integ_full(spl, acc)
383 use iso_c_binding
384 use, intrinsic :: iso_fortran_env
385 implicit none
386 type(c_ptr), intent(in) :: spl
387 type(c_ptr), intent(in) :: acc
388 end function oct_spline_eval_integ_full
389 end interface
390
391 real(real64), parameter :: tol_x = 1e-14_real64
392
393contains
395 !------------------------------------------------------------
396 subroutine spline_init_0(spl)
397 type(spline_t), intent(out) :: spl
398
399 ! No PUSH SUB, called too often
400
401 spl%spl = c_null_ptr
402 spl%acc = c_null_ptr
403
404 ! deliberately illegal values, for checking
405 spl%x_limit(1) = -1_real64
406 spl%x_limit(2) = -2_real64
407
408 spl%x_threshold = m_zero
409
410 end subroutine spline_init_0
411
413 !------------------------------------------------------------
414 subroutine spline_init_1(spl)
415 type(spline_t), intent(out) :: spl(:)
416
417 integer :: i
418
419 push_sub(spline_init_1)
420
421 do i = 1, size(spl)
422 call spline_init_0(spl(i))
423 end do
424
425 pop_sub(spline_init_1)
426 end subroutine spline_init_1
427
428
429 !------------------------------------------------------------
430 subroutine spline_init_2(spl)
431 type(spline_t), intent(out) :: spl(:, :)
432
433 integer :: i, j
434
435 push_sub(spline_init_2)
436
437 do i = 1, size(spl, 1)
438 do j = 1, size(spl, 2)
439 call spline_init_0(spl(i, j))
440 end do
441 end do
442
443 pop_sub(spline_init_2)
444 end subroutine spline_init_2
445
446
447 !------------------------------------------------------------
448 subroutine spline_end_0(spl)
449 type(spline_t), intent(inout) :: spl
450
451 ! No PUSH SUB, called too often.
452
453 if (c_associated(spl%spl) .and. c_associated(spl%acc)) then
454 call oct_spline_end(spl%spl, spl%acc)
455 end if
456 spl%spl = c_null_ptr
457 spl%acc = c_null_ptr
458
459 end subroutine spline_end_0
460
462 !------------------------------------------------------------
463 subroutine spline_end_1(spl)
464 type(spline_t), intent(inout) :: spl(:)
465
466 integer :: i
467
468 push_sub(spline_end_1)
469
470 do i = 1, size(spl)
471 call spline_end_0(spl(i))
472 end do
473
474 pop_sub(spline_end_1)
475 end subroutine spline_end_1
476
477
478 !------------------------------------------------------------
479 subroutine spline_end_2(spl)
480 type(spline_t), intent(inout) :: spl(:, :)
481
482 integer :: i, j
483
484 push_sub(spline_end_2)
485
486 do i = 1, size(spl, 1)
487 do j = 1, size(spl, 2)
488 call spline_end_0(spl(i, j))
489 end do
490 end do
491
492 pop_sub(spline_end_2)
493 end subroutine spline_end_2
494
495
496 !------------------------------------------------------------
497 subroutine spline_fit(nrc, rofi, ffit, spl, threshold)
498 integer, intent(in) :: nrc
499 real(real64), intent(in) :: rofi(:)
500 real(real64), intent(in) :: ffit(:)
501 type(spline_t), intent(inout) :: spl
502 real(real64), optional, intent(in) :: threshold
503
504 !No PUSH SUB, called too often
505
506 assert(nrc > 0)
507
508 spl%x_limit(1) = rofi(1)
509 spl%x_limit(2) = rofi(nrc)
510 call oct_spline_fit(nrc, rofi(1), ffit(1), spl%spl, spl%acc)
511
512 if (present(threshold)) then
513 if (threshold > m_zero) then
514 spl%x_threshold = spline_x_threshold(spl, threshold)
515 else
516 spl%x_threshold = spl%x_limit(2)
517 end if
518 else
519 spl%x_threshold = m_zero
520 end if
521
522 end subroutine spline_fit
523
524 !------------------------------------------------------------
525 real(real64) function spline_eval(spl, x)
526 type(spline_t), intent(in) :: spl
527 real(real64), intent(in) :: x
528
529 spline_eval = oct_spline_eval(x, spl%spl, spl%acc)
530 end function spline_eval
531
532
533 !------------------------------------------------------------
534 subroutine spline_eval8_array(spl, nn, xf)
535 type(spline_t), intent(in) :: spl
536 integer, intent(in) :: nn
537 real(real64), intent(inout) :: xf(:)
538
539 assert(nn > 0)
540
541 call oct_spline_eval_array(nn, xf(1), spl%spl, spl%acc)
542 end subroutine spline_eval8_array
543
544
545 !------------------------------------------------------------
546 subroutine spline_evalz_array(spl, nn, xf)
547 type(spline_t), intent(in) :: spl
548 integer, intent(in) :: nn
549 complex(real64), intent(inout) :: xf(:)
550
551 assert(nn > 0)
552
553 call oct_spline_eval_arrayz(nn, xf(1), spl%spl, spl%acc)
554 end subroutine spline_evalz_array
555
556 !------------------------------------------------------------
557 subroutine spline_sum(spl1, spl2, splsum, threshold)
558 type(spline_t), intent(in) :: spl1
559 type(spline_t), intent(in) :: spl2
560 type(spline_t), intent(out) :: splsum
561 real(real64), intent(in) :: threshold
562
563 integer :: npoints, i
564 real(real64), allocatable :: x(:), y(:), y2(:)
565
566 push_sub(spline_sum)
567
568 npoints = oct_spline_npoints(spl1%spl, spl1%acc)
569 assert(npoints > 0)
570
571 safe_allocate( x(1:npoints))
572 safe_allocate( y(1:npoints))
573 safe_allocate(y2(1:npoints))
574
575 call oct_spline_x(spl1%spl, x(1))
576 call oct_spline_y(spl1%spl, y(1))
577
578 !$omp parallel do
579 do i = 1, npoints
580 y2(i) = spline_eval(spl2, x(i)) + y(i)
581 end do
582
583 call spline_fit(npoints, x, y2, splsum, threshold)
584
585 safe_deallocate_a(x)
586 safe_deallocate_a(y)
587 safe_deallocate_a(y2)
588
589 pop_sub(spline_sum)
590 end subroutine spline_sum
591
592
593 !------------------------------------------------------------
594 subroutine spline_times(a, spl, threshold)
595 real(real64), intent(in) :: a
596 type(spline_t), intent(inout) :: spl
597 real(real64), intent(in) :: threshold
599 integer :: npoints, i
600 real(real64), allocatable :: x(:), y(:)
601
602 push_sub(spline_times)
603
604 npoints = oct_spline_npoints(spl%spl, spl%acc)
605 assert(npoints > 0)
606
607 safe_allocate(x(1:npoints))
608 safe_allocate(y(1:npoints))
609
610 call oct_spline_x(spl%spl, x(1))
611 call oct_spline_y(spl%spl, y(1))
612 call oct_spline_end(spl%spl, spl%acc)
613 !$omp parallel do simd
614 do i = 1, npoints
615 y(i) = a*y(i)
616 end do
617 call spline_fit(npoints, x, y, spl, threshold)
618
619 safe_deallocate_a(x)
620 safe_deallocate_a(y)
621
622 pop_sub(spline_times)
623 end subroutine spline_times
624
625
626 !------------------------------------------------------------
627 real(real64) function spline_integral_full(spl) result(res)
628 type(spline_t), intent(in) :: spl
629
630 push_sub(spline_integral_full)
631
632 res = oct_spline_eval_integ_full(spl%spl, spl%acc)
633
634 pop_sub(spline_integral_full)
635 end function spline_integral_full
636
637
638 !------------------------------------------------------------
639 real(real64) pure function spline_integral_limits(spl, a, b) result(res)
640 type(spline_t), intent(in) :: spl
641 real(real64), intent(in) :: a
642 real(real64), intent(in) :: b
643
644 res = oct_spline_eval_integ(spl%spl, a, b, spl%acc)
645 end function spline_integral_limits
646
647
648 !------------------------------------------------------------
649 real(real64) function spline_dotp(spl1, spl2) result (res)
650 type(spline_t), intent(in) :: spl1
651 type(spline_t), intent(in) :: spl2
652
653 type(spline_t) :: aux
654 integer :: npoints, i
655 real(real64), allocatable :: x(:), y(:)
656
657 push_sub(spline_dotp)
658
659 npoints = oct_spline_npoints(spl1%spl, spl1%acc)
660 assert(npoints > 0)
661
662 safe_allocate(x(1:npoints))
663 safe_allocate(y(1:npoints))
664
665 call oct_spline_x(spl1%spl, x(1))
666 call oct_spline_y(spl1%spl, y(1))
667 !$omp parallel do
668 do i = 1, npoints
669 y(i) = y(i)*oct_spline_eval(x(i), spl2%spl, spl2%acc)
670 end do
671 call spline_init(aux)
672 call spline_fit(npoints, x, y, aux, m_zero)
673 res = oct_spline_eval_integ(aux%spl, x(1), x(npoints), aux%acc)
674
675 safe_deallocate_a(x)
676 safe_deallocate_a(y)
678 pop_sub(spline_dotp)
679 end function spline_dotp
680
681
682 !------------------------------------------------------------
683 subroutine spline_3dft(spl, splw, threshold, gmax)
684 type(spline_t), intent(in) :: spl
685 type(spline_t), intent(inout) :: splw
686 real(real64), intent(in) :: threshold
687 real(real64), optional, intent(in) :: gmax
688
689 type(spline_t) :: aux
690 real(real64) :: g, dg
691 integer :: np
692 integer :: npoints, i, j
693 real(real64), allocatable :: x(:), y(:), y2(:), xw(:), yw(:)
694
695 push_sub(spline_3dft)
696
697 npoints = oct_spline_npoints(spl%spl, spl%acc)
698 assert(npoints > 0)
699
700 safe_allocate( x(1:npoints))
701 safe_allocate( y(1:npoints))
702 safe_allocate(y2(1:npoints))
703
704 call oct_spline_x(spl%spl, x(1))
705 call oct_spline_y(spl%spl, y(1))
706
707 ! Check whether splw comes with a defined grid, or else build it.
708 if (c_associated(splw%spl)) then
709 np = oct_spline_npoints(splw%spl, splw%acc)
710 safe_allocate(xw(1:np))
711 safe_allocate(yw(1:np))
712 call oct_spline_x(splw%spl, xw(1))
713 ! But now we need to kill the input:
714 call spline_end(splw)
715 else
716 assert(present(gmax))
717 np = 200 ! hard coded value
718 dg = gmax/(np-1)
719 safe_allocate(xw(1:np))
720 safe_allocate(yw(1:np))
721 do i = 1, np
722 g = (i-1)*dg
723 xw(i) = g
724 end do
725 end if
726
727 ! The first point, xw(1) = 0.0 and it has to be treated separately.
728 !$omp parallel do simd
729 do j = 1, npoints
730 y2(j) = m_four*m_pi*y(j)*x(j)**2
731 end do
732 call spline_init(aux)
733 call spline_fit(npoints, x, y2, aux, m_zero)
734 yw(1) = oct_spline_eval_integ_full(aux%spl, aux%acc)
735 call spline_end(aux)
736
737 do i = 2, np
738 !$omp parallel do simd
739 do j = 1, npoints
740 y2(j) = (m_four*m_pi/xw(i))*y(j)*x(j)*sin(xw(i)*x(j))
741 end do
742 call spline_init(aux)
743 call spline_fit(npoints, x, y2, aux, m_zero)
744 yw(i) = oct_spline_eval_integ_full(aux%spl, aux%acc)
745 call spline_end(aux)
746 end do
747
748 call spline_init(splw)
749 call spline_fit(np, xw, yw, splw, threshold)
750
751 safe_deallocate_a(x)
752 safe_deallocate_a(y)
753 safe_deallocate_a(y2)
754 safe_deallocate_a(xw)
755 safe_deallocate_a(yw)
756
757 pop_sub(spline_3dft)
758 end subroutine spline_3dft
759
760
761 !------------------------------------------------------------
762 subroutine spline_besselft(spl, splw, l, threshold, gmax)
763 type(spline_t), intent(in) :: spl
764 type(spline_t), intent(inout) :: splw
765 integer, intent(in) :: l
766 real(real64), optional, intent(in) :: threshold
767 real(real64), optional, intent(in) :: gmax
768
769 type(spline_t) :: aux
770 real(real64) :: dg
771 integer :: np
772 integer :: npoints, i, j
773 real(real64), allocatable :: x(:), y(:), y2(:), xw(:), yw(:)
774
775 push_sub(spline_besselft)
776
777 npoints = oct_spline_npoints(spl%spl, spl%acc)
778 assert(npoints > 0)
779
780 safe_allocate( x(1:npoints))
781 safe_allocate( y(1:npoints))
782 safe_allocate(y2(1:npoints))
783
784 call oct_spline_x(spl%spl, x(1))
785 call oct_spline_y(spl%spl, y(1))
786
787 ! Check whether splw comes with a defined grid, or else build it.
788 if (c_associated(splw%spl)) then
789 np = oct_spline_npoints(splw%spl, splw%acc)
790 safe_allocate(xw(1:np))
791 safe_allocate(yw(1:np))
792 call oct_spline_x(splw%spl, xw(1))
793 ! But now we need to kill the input:
794 call spline_end(splw)
795 else
796 assert(present(gmax))
797 np = 1000 ! hard coded value
798 dg = gmax/(np-1)
799 safe_allocate(xw(1:np))
800 safe_allocate(yw(1:np))
801 !$omp parallel do
802 do i = 1, np
803 xw(i) = (i-1)*dg
804 end do
805 end if
806
807 do i = 1, np
808 !$omp parallel do
809 do j = 1, npoints
810 y2(j) = y(j) * x(j)**2 * loct_sph_bessel(l, x(j)*xw(i))
811 end do
812 call spline_init(aux)
813 call spline_fit(npoints, x, y2, aux)
814 yw(i) = sqrt(m_two/m_pi)*oct_spline_eval_integ_full(aux%spl, aux%acc)
815
816 call spline_end(aux)
817 end do
818
819 call spline_init(splw)
820 call spline_fit(np, xw, yw, splw, threshold)
821
822 safe_deallocate_a(x)
823 safe_deallocate_a(y)
824 safe_deallocate_a(y2)
825 safe_deallocate_a(xw)
826 safe_deallocate_a(yw)
827
828 pop_sub(spline_besselft)
829 end subroutine spline_besselft
830
831
832 !------------------------------------------------------------
833 subroutine spline_cut(spl, cutoff, beta, threshold)
834 type(spline_t), intent(inout) :: spl
835 real(real64), intent(in) :: cutoff
836 real(real64), intent(in) :: beta
837 real(real64), optional,intent(in) :: threshold
838
839 integer :: npoints, i
840 real(real64), allocatable :: x(:), y(:)
841 real(real64) :: exp_arg
843 push_sub(spline_cut)
844
845 npoints = oct_spline_npoints(spl%spl, spl%acc)
846 assert(npoints > 0)
847
848 safe_allocate(x(1:npoints))
849 safe_allocate(y(1:npoints))
850
851 call oct_spline_x(spl%spl, x(1))
852 call oct_spline_y(spl%spl, y(1))
853 call oct_spline_end(spl%spl, spl%acc)
854
855 do i = npoints, 1, -1
856 if (x(i)<cutoff) then
857 exit
858 end if
859
860 exp_arg = -beta*(x(i)/cutoff - m_one)**2
861 !To avoid underflows
862 if (exp_arg > m_min_exp_arg) then
863 y(i) = y(i) * exp(exp_arg)
864 else
865 y(i) = m_zero
866 end if
867 end do
868 call spline_fit(npoints, x, y, spl, threshold)
869
870 safe_deallocate_a(x)
871 safe_deallocate_a(y)
872
873 pop_sub(spline_cut)
874 end subroutine spline_cut
875
877 !------------------------------------------------------------
882 subroutine spline_div(spla, splb, threshold)
883 type(spline_t), intent(inout) :: spla
884 type(spline_t), intent(in) :: splb
885 real(real64), optional, intent(in) :: threshold
886
887 integer :: npoints, i, new_npoints
888 real(real64), allocatable :: x(:), y(:)
889 real(real64) :: aa
890
891 push_sub(spline_div)
892
893 npoints = oct_spline_npoints(spla%spl, spla%acc)
894 assert(npoints > 0)
895
896 safe_allocate(x(1:npoints))
897 safe_allocate(y(1:npoints))
898
899 call oct_spline_x(spla%spl, x(1))
900 call oct_spline_y(spla%spl, y(1))
901 call oct_spline_end(spla%spl, spla%acc)
902
903 assert(splb%x_limit(2) >= splb%x_limit(1))
904
905 ! As an output, the new spline only contains the new number of points
906 ! that goes up to the cutoff of the splb spline
907 new_npoints = 0
908 do i = npoints, 1, -1
909 if (x(i) > splb%x_limit(2)-tol_x) cycle
910 aa = spline_eval(splb, x(i))
911 y(i) = y(i)/aa
912 new_npoints = new_npoints + 1
913 end do
914 assert(new_npoints > 0)
915
916 call spline_fit(new_npoints, x, y, spla, threshold)
917
918 safe_deallocate_a(x)
919 safe_deallocate_a(y)
920
921 pop_sub(spline_div)
922 end subroutine spline_div
923
924 !------------------------------------------------------------
925 !Force all the values of the spline to be positive
926 !------------------------------------------------------------
927 subroutine spline_force_pos(spl, threshold)
928 type(spline_t), intent(inout) :: spl
929 real(real64), intent(in) :: threshold
930
931 integer :: npoints, i
932 real(real64), allocatable :: x(:), y(:)
933
934 push_sub(spline_force_pos)
935
936 npoints = oct_spline_npoints(spl%spl, spl%acc)
937 assert(npoints > 0)
938
939 safe_allocate(x(1:npoints))
940 safe_allocate(y(1:npoints))
941
942 call oct_spline_x(spl%spl, x(1))
943 call oct_spline_y(spl%spl, y(1))
944 call oct_spline_end(spl%spl, spl%acc)
945
946 !$omp parallel do simd
947 do i = npoints, 1, -1
948 y(i) = max(y(i),m_zero)
949 end do
950
951 call spline_fit(npoints, x, y, spl, threshold)
952
953 safe_deallocate_a(x)
954 safe_deallocate_a(y)
955
956 pop_sub(spline_force_pos)
957 end subroutine spline_force_pos
958
959
960 !------------------------------------------------------------
961 subroutine spline_mult(spla, splb, threshold)
962 type(spline_t), intent(inout) :: spla
963 type(spline_t), intent(in) :: splb
964 real(real64), intent(in) :: threshold
965
966 integer :: npoints, i
967 real(real64), allocatable :: x(:), y(:)
968 real(real64) :: aa
969
970 push_sub(spline_mult)
971
972 npoints = oct_spline_npoints(spla%spl, spla%acc)
973 if(npoints <= 0) then
974 pop_sub(spline_mult)
975 return
976 end if
977
978 safe_allocate(x(1:npoints))
979 safe_allocate(y(1:npoints))
980
981 call oct_spline_x(spla%spl, x(1))
982 call oct_spline_y(spla%spl, y(1))
983 call oct_spline_end(spla%spl, spla%acc)
984
985 assert(splb%x_limit(2) >= splb%x_limit(1))
986
987 !$omp parallel do simd private(aa)
988 do i = npoints, 1, -1
989 if (x(i) > splb%x_limit(2) - tol_x) then
990 aa = m_zero
991 else
992 aa = spline_eval(splb, x(i))
993 end if
994 y(i) = y(i)*aa
995 end do
996
997 call spline_fit(npoints, x, y, spla, threshold)
998
999 safe_deallocate_a(x)
1000 safe_deallocate_a(y)
1001
1003 end subroutine spline_mult
1004
1005
1006 !------------------------------------------------------------
1007 subroutine spline_der(spl, dspl, threshold)
1008 type(spline_t), intent(in) :: spl
1009 type(spline_t), intent(inout) :: dspl
1010 real(real64), intent(in) :: threshold
1011
1012 integer :: npoints, i
1013 real(real64), allocatable :: x(:), y(:)
1014
1015 push_sub(spline_der)
1016
1017 ! Use the grid of dspl if it is present, otherwise use the same one of spl.
1018 if (.not. c_associated(dspl%spl)) then ! use the grid of spl
1019 npoints = oct_spline_npoints(spl%spl, spl%acc)
1020 assert(npoints > 0)
1021 safe_allocate(x(1:npoints))
1022 safe_allocate(y(1:npoints))
1023 call oct_spline_x(spl%spl, x(1))
1024 else ! use the grid of dspl
1025 npoints = oct_spline_npoints(dspl%spl, dspl%acc)
1026 assert(npoints > 0)
1027 safe_allocate(x(1:npoints))
1028 safe_allocate(y(1:npoints))
1029 call oct_spline_x(dspl%spl, x(1))
1030 end if
1031 do i = 1, npoints
1032 y(i) = oct_spline_eval_der(x(i), spl%spl, spl%acc)
1033 end do
1034 call spline_fit(npoints, x, y, dspl, threshold)
1035
1036 safe_deallocate_a(x)
1037 safe_deallocate_a(y)
1038
1039 pop_sub(spline_der)
1040 end subroutine spline_der
1041
1042
1043 !------------------------------------------------------------
1045 subroutine spline_der2(spl, dspl, threshold, grid)
1046 type(spline_t), intent(in) :: spl
1047 type(spline_t), intent(inout) :: dspl
1048 real(real64), intent(in) :: threshold
1049 real(real64), optional, intent(in) :: grid(:)
1050
1051 integer :: npoints, i
1052 real(real64), allocatable :: x(:), y(:)
1053
1054 push_sub(spline_der2)
1055
1056 ! Use the grid of dspl if it is present, otherwise use the same one of spl.
1057 if (.not. c_associated(dspl%spl)) then ! use the grid of spl
1058 npoints = oct_spline_npoints(spl%spl, spl%acc)
1059 assert(npoints > 0)
1060 safe_allocate(x(1:npoints))
1061 safe_allocate(y(1:npoints))
1062 if (present(grid)) then
1063 x(:) = grid(:)
1064 else
1065 call oct_spline_x(spl%spl, x(1))
1066 end if
1067 else ! use the grid of dspl
1068 npoints = oct_spline_npoints(dspl%spl, dspl%acc)
1069 assert(npoints > 0)
1070 safe_allocate(x(1:npoints))
1071 safe_allocate(y(1:npoints))
1072 call oct_spline_x(dspl%spl, x(1))
1073 end if
1074 do i = 1, npoints
1075 y(i) = oct_spline_eval_der2(x(i), spl%spl, spl%acc)
1076 end do
1077 call spline_fit(npoints, x, y, dspl, threshold)
1078
1079 safe_deallocate_a(x)
1080 safe_deallocate_a(y)
1081
1082 pop_sub(spline_der2)
1083 end subroutine spline_der2
1084
1085
1086 !------------------------------------------------------------
1087 subroutine spline_print_0(spl, iunit)
1088 type(spline_t), intent(in) :: spl
1089 integer, intent(in) :: iunit
1090
1091 integer :: np, i
1092 real(real64), allocatable :: x(:), y(:)
1093
1094 push_sub(spline_print_0)
1095
1096 np = oct_spline_npoints(spl%spl, spl%acc)
1097 assert(np > 0)
1098 safe_allocate(x(1:np))
1099 safe_allocate(y(1:np))
1100
1101 call oct_spline_x(spl%spl, x(1))
1102 call oct_spline_y(spl%spl, y(1))
1103 do i = 1, np
1104 write(iunit, '(2es18.8E3)') x(i), y(i)
1105 end do
1106
1107 safe_deallocate_a(x)
1108 safe_deallocate_a(y)
1109
1110 pop_sub(spline_print_0)
1111 end subroutine spline_print_0
1112
1113
1114 !------------------------------------------------------------
1116 subroutine spline_print_1(spl, iunit)
1117 type(spline_t), intent(in) :: spl(:)
1118 integer, intent(in) :: iunit
1119
1120 character(len=4) :: fm
1121 integer :: np, i, n, j
1122 real(real64), allocatable :: x(:)
1123 real(real64) :: x_limit
1124
1126
1127 n = size(spl)
1128 if (n <= 0) then
1129 pop_sub(spline_print_1)
1130 return
1131 end if
1132
1133 write(fm,'(i4)') n + 1
1134 fm = adjustl(fm)
1135 np = oct_spline_npoints(spl(1)%spl, spl(1)%acc)
1136 x_limit = spl(1)%x_limit(2)
1137 safe_allocate(x(1:np))
1138
1139 call oct_spline_x(spl(1)%spl, x(1))
1140
1141 ! Not all splines have the same number of points
1142 do i = 2, n
1143 np = min(np, oct_spline_npoints(spl(i)%spl, spl(i)%acc))
1144 x_limit = min(x_limit, spl(i)%x_limit(2))
1145 end do
1146
1147 do i = 1, np
1148 if (x(i) > x_limit - tol_x) cycle
1149 write(iunit, '('//trim(fm)//'es18.8E3)') x(i), (spline_eval(spl(j), x(i)), j = 1, size(spl))
1150 end do
1151
1152 safe_deallocate_a(x)
1153
1154 pop_sub(spline_print_1)
1155 end subroutine spline_print_1
1156
1157
1158 !------------------------------------------------------------
1160 subroutine spline_print_2(spl, iunit)
1161 type(spline_t), intent(in) :: spl(:, :)
1162 integer, intent(in) :: iunit
1163
1164 character(len=4) :: fm
1165 integer :: np, i, n1, n2, j, k
1166 real(real64), allocatable :: x(:)
1167 real(real64) :: x_limit
1168
1169 push_sub(spline_print_2)
1170
1171 n1 = size(spl, 1)
1172 n2 = size(spl, 2)
1173 if (n1 * n2 <= 0) then
1174 pop_sub(spline_print_2)
1175 return
1176 end if
1177
1178 write(fm,'(i4)') n1*n2 + 1
1179 fm = adjustl(fm)
1180
1181 np = oct_spline_npoints(spl(1, 1)%spl, spl(1, 1)%acc)
1182 safe_allocate(x(1:np))
1183
1184 call oct_spline_x(spl(1, 1)%spl, x(1))
1185 x_limit = spl(1,1)%x_limit(2)
1186
1187 ! Not all splines have the same number of points
1188 do i = 2, n1
1189 do j = 1, n2
1190 np = min(np, oct_spline_npoints(spl(i, j)%spl, spl(i, j)%acc))
1191 x_limit = min(x_limit, spl(i,j)%x_limit(2))
1192 end do
1193 end do
1194
1195 do i = 1, np
1196 if (x(i) > x_limit - tol_x) cycle
1197 write(iunit, '('//trim(fm)//'es18.8E3)') x(i), &
1198 ((spline_eval(spl(j, k), x(i)), j = 1, n1), k = 1, n2)
1199 end do
1200
1201 safe_deallocate_a(x)
1202
1203 pop_sub(spline_print_2)
1204 end subroutine spline_print_2
1205
1206
1207 !------------------------------------------------------------
1210 real(real64) function spline_x_threshold(spl, threshold) result(r)
1211 type(spline_t), intent(in) :: spl
1212 real(real64), intent(in) :: threshold
1213
1214 integer :: ii, jj
1215 real(real64), parameter :: dx = 0.01_real64
1216
1217 ! No PUSH SUB, called too often.
1218 assert(spl%x_limit(2) >= spl%x_limit(1))
1219
1220 call profiling_in('SPLINE_CUTOFF_RADIUS')
1221
1222 jj = floor(spl%x_limit(2)/dx) + 1
1223 ! Numerical errors can lead to jj to be overestimated by 1
1224 ! This test prevents this to occur
1225 do while(dx*(jj-1) > spl%x_limit(2) - m_half * dx)
1226 jj = jj-1
1227 end do
1228
1229 do ii = jj, 1, -1
1230 r = dx*(ii-1)
1231 if (abs(spline_eval(spl, r)) > threshold) exit
1232 end do
1233
1234 call profiling_out('SPLINE_CUTOFF_RADIUS')
1235
1236 end function spline_x_threshold
1237
1238 ! -------------------------------------------------------
1239
1240 real(real64) pure function spline_range_min(this) result(range)
1241 type(spline_t), intent(in) :: this
1242
1243 range = this%x_limit(1)
1244
1245 end function spline_range_min
1246
1247 ! -------------------------------------------------------
1248
1249 real(real64) pure function spline_range_max(this) result(range)
1250 type(spline_t), intent(in) :: this
1251
1252 range = this%x_limit(2)
1253
1254 end function spline_range_max
1255
1256 ! -------------------------------------------------------
1257 subroutine spline_generate_shifted_grid(this, x_shifted)
1258 type(spline_t), intent(in) :: this
1259 real(real64), allocatable, intent(inout) :: x_shifted(:)
1260
1261 real(real64), allocatable :: x(:)
1262 integer :: npoints, i
1263
1265
1266 ! We shift the grid by half of a spacing to force interpolation of the function
1267 ! This is useful for getting back the derivative on the same grid
1268 npoints = oct_spline_npoints(this%spl, this%acc)
1269 safe_allocate(x(1:npoints))
1270 safe_allocate(x_shifted(1:npoints))
1271 call oct_spline_x(this%spl, x(1))
1272 do i = 1, npoints -1
1273 x_shifted(i) = m_half*(x(i) + x(i+1))
1274 end do
1275 x_shifted(npoints) = x(npoints)
1276 safe_deallocate_a(x)
1277
1279 end subroutine spline_generate_shifted_grid
1280
1281end module splines_oct_m
1282
1283!! Local Variables:
1284!! mode: f90
1285!! coding: utf-8
1286!! End:
Both the filling of the function, and the retrieval of the values may be done using single- or double...
Definition: splines.F90:166
Some operations may be done for one spline-function, or for an array of them.
Definition: splines.F90:179
The integral may be done with or without integration limits, but we want the interface to be common.
Definition: splines.F90:173
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
subroutine, public spline_der(spl, dspl, threshold)
Definition: splines.F90:923
subroutine spline_end_0(spl)
Definition: splines.F90:364
subroutine, public spline_force_pos(spl, threshold)
Definition: splines.F90:843
real(real64) pure function spline_integral_limits(spl, a, b)
Definition: splines.F90:555
subroutine, public spline_fit(nrc, rofi, ffit, spl, threshold)
Definition: splines.F90:413
real(real64) function, public spline_x_threshold(spl, threshold)
Determines the largest value of x for which the spline values are above the threshold.
Definition: splines.F90:1126
subroutine, public spline_sum(spl1, spl2, splsum, threshold)
Definition: splines.F90:473
subroutine, public spline_3dft(spl, splw, threshold, gmax)
Definition: splines.F90:599
subroutine, public spline_der2(spl, dspl, threshold, grid)
Returns a spline that contains the second derivative of the original spline.
Definition: splines.F90:961
subroutine spline_end_2(spl)
Definition: splines.F90:395
real(real64) function, public spline_dotp(spl1, spl2)
Definition: splines.F90:565
real(real64), parameter tol_x
Tolerance for checking if x is inside or outside the limits of the splines.
Definition: splines.F90:306
subroutine, public spline_besselft(spl, splw, l, threshold, gmax)
Definition: splines.F90:678
real(real64) pure function, public spline_range_min(this)
Definition: splines.F90:1156
subroutine spline_end_1(spl)
Definition: splines.F90:379
subroutine spline_print_1(spl, iunit)
Print debug information for a 1D array of splines.
Definition: splines.F90:1032
real(real64) function spline_integral_full(spl)
Definition: splines.F90:543
real(real64) function, public spline_eval(spl, x)
Definition: splines.F90:441
subroutine spline_init_0(spl)
Definition: splines.F90:312
subroutine spline_print_0(spl, iunit)
Definition: splines.F90:1003
subroutine spline_print_2(spl, iunit)
Print debug information for a 2D array of splines.
Definition: splines.F90:1076
subroutine spline_eval8_array(spl, nn, xf)
Definition: splines.F90:450
subroutine spline_init_1(spl)
Definition: splines.F90:330
subroutine, public spline_cut(spl, cutoff, beta, threshold)
Definition: splines.F90:749
subroutine, public spline_div(spla, splb, threshold)
Returns the values of spla divided by the values of splb.
Definition: splines.F90:798
real(real64) pure function, public spline_range_max(this)
Definition: splines.F90:1165
subroutine, public spline_times(a, spl, threshold)
Definition: splines.F90:510
subroutine spline_init_2(spl)
Definition: splines.F90:346
subroutine, public spline_mult(spla, splb, threshold)
Definition: splines.F90:877
subroutine spline_evalz_array(spl, nn, xf)
Definition: splines.F90:462
subroutine, public spline_generate_shifted_grid(this, x_shifted)
Definition: splines.F90:1173
the basic spline datatype
Definition: splines.F90:156