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)
677
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 np = 200 ! hard coded value
717 dg = gmax/(np-1)
718 safe_allocate(xw(1:np))
719 safe_allocate(yw(1:np))
720 do i = 1, np
721 g = (i-1)*dg
722 xw(i) = g
723 end do
724 end if
725
726 ! The first point, xw(1) = 0.0 and it has to be treated separately.
727 !$omp parallel do simd
728 do j = 1, npoints
729 y2(j) = m_four*m_pi*y(j)*x(j)**2
730 end do
731 call spline_init(aux)
732 call spline_fit(npoints, x, y2, aux, m_zero)
733 yw(1) = oct_spline_eval_integ_full(aux%spl, aux%acc)
734 call spline_end(aux)
735
736 do i = 2, np
737 !$omp parallel do simd
738 do j = 1, npoints
739 y2(j) = (m_four*m_pi/xw(i))*y(j)*x(j)*sin(xw(i)*x(j))
740 end do
741 call spline_init(aux)
742 call spline_fit(npoints, x, y2, aux, m_zero)
743 yw(i) = oct_spline_eval_integ_full(aux%spl, aux%acc)
744 call spline_end(aux)
745 end do
746
747 call spline_init(splw)
748 call spline_fit(np, xw, yw, splw, threshold)
749
750 safe_deallocate_a(x)
751 safe_deallocate_a(y)
752 safe_deallocate_a(y2)
753 safe_deallocate_a(xw)
754 safe_deallocate_a(yw)
755
756 pop_sub(spline_3dft)
757 end subroutine spline_3dft
758
759
760 !------------------------------------------------------------
761 subroutine spline_besselft(spl, splw, l, threshold, gmax)
762 type(spline_t), intent(in) :: spl
763 type(spline_t), intent(inout) :: splw
764 integer, intent(in) :: l
765 real(real64), optional, intent(in) :: threshold
766 real(real64), optional, intent(in) :: gmax
767
768 type(spline_t) :: aux
769 real(real64) :: dg
770 integer :: np
771 integer :: npoints, i, j
772 real(real64), allocatable :: x(:), y(:), y2(:), xw(:), yw(:)
773
774 push_sub(spline_besselft)
775
776 npoints = oct_spline_npoints(spl%spl, spl%acc)
777 assert(npoints > 0)
778
779 safe_allocate( x(1:npoints))
780 safe_allocate( y(1:npoints))
781 safe_allocate(y2(1:npoints))
782
783 call oct_spline_x(spl%spl, x(1))
784 call oct_spline_y(spl%spl, y(1))
785
786 ! Check whether splw comes with a defined grid, or else build it.
787 if (c_associated(splw%spl)) then
788 np = oct_spline_npoints(splw%spl, splw%acc)
789 safe_allocate(xw(1:np))
790 safe_allocate(yw(1:np))
791 call oct_spline_x(splw%spl, xw(1))
792 ! But now we need to kill the input:
793 call spline_end(splw)
794 else
795 assert(present(gmax))
796 np = 1000 ! hard coded value
797 dg = gmax/(np-1)
798 safe_allocate(xw(1:np))
799 safe_allocate(yw(1:np))
800 !$omp parallel do
801 do i = 1, np
802 xw(i) = (i-1)*dg
803 end do
804 end if
805
806 do i = 1, np
807 !$omp parallel do
808 do j = 1, npoints
809 y2(j) = y(j) * x(j)**2 * loct_sph_bessel(l, x(j)*xw(i))
810 end do
811 call spline_init(aux)
812 call spline_fit(npoints, x, y2, aux)
813 yw(i) = sqrt(m_two/m_pi)*oct_spline_eval_integ_full(aux%spl, aux%acc)
814
815 call spline_end(aux)
816 end do
817
818 call spline_init(splw)
819 call spline_fit(np, xw, yw, splw, threshold)
820
821 safe_deallocate_a(x)
822 safe_deallocate_a(y)
823 safe_deallocate_a(y2)
824 safe_deallocate_a(xw)
825 safe_deallocate_a(yw)
826
827 pop_sub(spline_besselft)
828 end subroutine spline_besselft
829
830
831 !------------------------------------------------------------
832 subroutine spline_cut(spl, cutoff, beta, threshold)
833 type(spline_t), intent(inout) :: spl
834 real(real64), intent(in) :: cutoff
835 real(real64), intent(in) :: beta
836 real(real64), optional,intent(in) :: threshold
837
838 integer :: npoints, i
839 real(real64), allocatable :: x(:), y(:)
840 real(real64) :: exp_arg
841
842 push_sub(spline_cut)
843
844 npoints = oct_spline_npoints(spl%spl, spl%acc)
845 assert(npoints > 0)
846
847 safe_allocate(x(1:npoints))
848 safe_allocate(y(1:npoints))
849
850 call oct_spline_x(spl%spl, x(1))
851 call oct_spline_y(spl%spl, y(1))
852 call oct_spline_end(spl%spl, spl%acc)
853
854 do i = npoints, 1, -1
855 if (x(i)<cutoff) then
856 exit
857 end if
858
859 exp_arg = -beta*(x(i)/cutoff - m_one)**2
860 !To avoid underflows
861 if (exp_arg > m_min_exp_arg) then
862 y(i) = y(i) * exp(exp_arg)
863 else
864 y(i) = m_zero
865 end if
866 end do
867 call spline_fit(npoints, x, y, spl, threshold)
868
869 safe_deallocate_a(x)
870 safe_deallocate_a(y)
871
872 pop_sub(spline_cut)
873 end subroutine spline_cut
875
876 !------------------------------------------------------------
881 subroutine spline_div(spla, splb, threshold)
882 type(spline_t), intent(inout) :: spla
883 type(spline_t), intent(in) :: splb
884 real(real64), optional, intent(in) :: threshold
885
886 integer :: npoints, i, new_npoints
887 real(real64), allocatable :: x(:), y(:)
888 real(real64) :: aa
889
890 push_sub(spline_div)
891
892 npoints = oct_spline_npoints(spla%spl, spla%acc)
893 assert(npoints > 0)
894
895 safe_allocate(x(1:npoints))
896 safe_allocate(y(1:npoints))
897
898 call oct_spline_x(spla%spl, x(1))
899 call oct_spline_y(spla%spl, y(1))
900 call oct_spline_end(spla%spl, spla%acc)
901
902 assert(splb%x_limit(2) >= splb%x_limit(1))
903
904 ! As an output, the new spline only contains the new number of points
905 ! that goes up to the cutoff of the splb spline
906 new_npoints = 0
907 do i = npoints, 1, -1
908 if (x(i) > splb%x_limit(2)-tol_x) cycle
909 aa = spline_eval(splb, x(i))
910 y(i) = y(i)/aa
911 new_npoints = new_npoints + 1
912 end do
913
914 call spline_fit(new_npoints, x, y, spla, threshold)
915
916 safe_deallocate_a(x)
917 safe_deallocate_a(y)
918
919 pop_sub(spline_div)
920 end subroutine spline_div
921
922 !------------------------------------------------------------
923 !Force all the values of the spline to be positive
924 !------------------------------------------------------------
925 subroutine spline_force_pos(spl, threshold)
926 type(spline_t), intent(inout) :: spl
927 real(real64), intent(in) :: threshold
928
929 integer :: npoints, i
930 real(real64), allocatable :: x(:), y(:)
931
932 push_sub(spline_force_pos)
933
934 npoints = oct_spline_npoints(spl%spl, spl%acc)
935 assert(npoints > 0)
936
937 safe_allocate(x(1:npoints))
938 safe_allocate(y(1:npoints))
939
940 call oct_spline_x(spl%spl, x(1))
941 call oct_spline_y(spl%spl, y(1))
942 call oct_spline_end(spl%spl, spl%acc)
943
944 !$omp parallel do simd
945 do i = npoints, 1, -1
946 y(i) = max(y(i),m_zero)
947 end do
948
949 call spline_fit(npoints, x, y, spl, threshold)
950
951 safe_deallocate_a(x)
952 safe_deallocate_a(y)
953
954 pop_sub(spline_force_pos)
955 end subroutine spline_force_pos
956
957
958 !------------------------------------------------------------
959 subroutine spline_mult(spla, splb, threshold)
960 type(spline_t), intent(inout) :: spla
961 type(spline_t), intent(in) :: splb
962 real(real64), intent(in) :: threshold
963
964 integer :: npoints, i
965 real(real64), allocatable :: x(:), y(:)
966 real(real64) :: aa
967
968 push_sub(spline_mult)
969
970 npoints = oct_spline_npoints(spla%spl, spla%acc)
971 if(npoints <= 0) then
972 pop_sub(spline_mult)
973 return
974 end if
975
976 safe_allocate(x(1:npoints))
977 safe_allocate(y(1:npoints))
978
979 call oct_spline_x(spla%spl, x(1))
980 call oct_spline_y(spla%spl, y(1))
981 call oct_spline_end(spla%spl, spla%acc)
982
983 assert(splb%x_limit(2) >= splb%x_limit(1))
984
985 !$omp parallel do simd private(aa)
986 do i = npoints, 1, -1
987 if (x(i) > splb%x_limit(2) - tol_x) then
988 aa = m_zero
989 else
990 aa = spline_eval(splb, x(i))
991 end if
992 y(i) = y(i)*aa
993 end do
994
995 call spline_fit(npoints, x, y, spla, threshold)
996
997 safe_deallocate_a(x)
998 safe_deallocate_a(y)
999
1001 end subroutine spline_mult
1002
1003
1004 !------------------------------------------------------------
1005 subroutine spline_der(spl, dspl, threshold)
1006 type(spline_t), intent(in) :: spl
1007 type(spline_t), intent(inout) :: dspl
1008 real(real64), intent(in) :: threshold
1009
1010 integer :: npoints, i
1011 real(real64), allocatable :: x(:), y(:)
1012
1013 push_sub(spline_der)
1014
1015 ! Use the grid of dspl if it is present, otherwise use the same one of spl.
1016 if (.not. c_associated(dspl%spl)) then ! use the grid of spl
1017 npoints = oct_spline_npoints(spl%spl, spl%acc)
1018 assert(npoints > 0)
1019 safe_allocate(x(1:npoints))
1020 safe_allocate(y(1:npoints))
1021 call oct_spline_x(spl%spl, x(1))
1022 else ! use the grid of dspl
1023 npoints = oct_spline_npoints(dspl%spl, dspl%acc)
1024 assert(npoints > 0)
1025 safe_allocate(x(1:npoints))
1026 safe_allocate(y(1:npoints))
1027 call oct_spline_x(dspl%spl, x(1))
1028 end if
1029 do i = 1, npoints
1030 y(i) = oct_spline_eval_der(x(i), spl%spl, spl%acc)
1031 end do
1032 call spline_fit(npoints, x, y, dspl, threshold)
1033
1034 safe_deallocate_a(x)
1035 safe_deallocate_a(y)
1036
1037 pop_sub(spline_der)
1038 end subroutine spline_der
1039
1040
1041 !------------------------------------------------------------
1043 subroutine spline_der2(spl, dspl, threshold, grid)
1044 type(spline_t), intent(in) :: spl
1045 type(spline_t), intent(inout) :: dspl
1046 real(real64), intent(in) :: threshold
1047 real(real64), optional, intent(in) :: grid(:)
1048
1049 integer :: npoints, i
1050 real(real64), allocatable :: x(:), y(:)
1051
1052 push_sub(spline_der2)
1053
1054 ! Use the grid of dspl if it is present, otherwise use the same one of spl.
1055 if (.not. c_associated(dspl%spl)) then ! use the grid of spl
1056 npoints = oct_spline_npoints(spl%spl, spl%acc)
1057 assert(npoints > 0)
1058 safe_allocate(x(1:npoints))
1059 safe_allocate(y(1:npoints))
1060 if (present(grid)) then
1061 x = grid(:)
1062 else
1063 call oct_spline_x(spl%spl, x(1))
1064 end if
1065 else ! use the grid of dspl
1066 npoints = oct_spline_npoints(dspl%spl, dspl%acc)
1067 assert(npoints > 0)
1068 safe_allocate(x(1:npoints))
1069 safe_allocate(y(1:npoints))
1070 call oct_spline_x(dspl%spl, x(1))
1071 end if
1072 do i = 1, npoints
1073 y(i) = oct_spline_eval_der2(x(i), spl%spl, spl%acc)
1074 end do
1075 call spline_fit(npoints, x, y, dspl, threshold)
1076
1077 safe_deallocate_a(x)
1078 safe_deallocate_a(y)
1079
1080 pop_sub(spline_der2)
1081 end subroutine spline_der2
1082
1083
1084 !------------------------------------------------------------
1085 subroutine spline_print_0(spl, iunit)
1086 type(spline_t), intent(in) :: spl
1087 integer, intent(in) :: iunit
1088
1089 integer :: np, i
1090 real(real64), allocatable :: x(:), y(:)
1091
1092 push_sub(spline_print_0)
1093
1094 np = oct_spline_npoints(spl%spl, spl%acc)
1095 assert(np > 0)
1096 safe_allocate(x(1:np))
1097 safe_allocate(y(1:np))
1098
1099 call oct_spline_x(spl%spl, x(1))
1100 call oct_spline_y(spl%spl, y(1))
1101 do i = 1, np
1102 write(iunit, '(2es18.8E3)') x(i), y(i)
1103 end do
1104
1105 safe_deallocate_a(x)
1106 safe_deallocate_a(y)
1107
1108 pop_sub(spline_print_0)
1109 end subroutine spline_print_0
1110
1111
1112 !------------------------------------------------------------
1114 subroutine spline_print_1(spl, iunit)
1115 type(spline_t), intent(in) :: spl(:)
1116 integer, intent(in) :: iunit
1117
1118 character(len=4) :: fm
1119 integer :: np, i, n, j
1120 real(real64), allocatable :: x(:)
1121 real(real64) :: x_limit
1122
1124
1125 n = size(spl)
1126 if (n <= 0) then
1127 pop_sub(spline_print_1)
1128 return
1129 end if
1130
1131 write(fm,'(i4)') n + 1
1132 fm = adjustl(fm)
1133 np = oct_spline_npoints(spl(1)%spl, spl(1)%acc)
1134 x_limit = spl(1)%x_limit(2)
1135 safe_allocate(x(1:np))
1136
1137 call oct_spline_x(spl(1)%spl, x(1))
1138
1139 ! Not all splines have the same number of points
1140 do i = 2, n
1141 np = min(np, oct_spline_npoints(spl(i)%spl, spl(i)%acc))
1142 x_limit = min(x_limit, spl(i)%x_limit(2))
1143 end do
1144
1145 do i = 1, np
1146 if (x(i) > x_limit - tol_x) cycle
1147 write(iunit, '('//trim(fm)//'es18.8E3)') x(i), (spline_eval(spl(j), x(i)), j = 1, size(spl))
1148 end do
1149
1150 safe_deallocate_a(x)
1151
1152 pop_sub(spline_print_1)
1153 end subroutine spline_print_1
1154
1155
1156 !------------------------------------------------------------
1158 subroutine spline_print_2(spl, iunit)
1159 type(spline_t), intent(in) :: spl(:, :)
1160 integer, intent(in) :: iunit
1161
1162 character(len=4) :: fm
1163 integer :: np, i, n1, n2, j, k
1164 real(real64), allocatable :: x(:)
1165 real(real64) :: x_limit
1166
1167 push_sub(spline_print_2)
1168
1169 n1 = size(spl, 1)
1170 n2 = size(spl, 2)
1171 if (n1 * n2 <= 0) then
1172 pop_sub(spline_print_2)
1173 return
1174 end if
1175
1176 write(fm,'(i4)') n1*n2 + 1
1177 fm = adjustl(fm)
1178
1179 np = oct_spline_npoints(spl(1, 1)%spl, spl(1, 1)%acc)
1180 safe_allocate(x(1:np))
1181
1182 call oct_spline_x(spl(1, 1)%spl, x(1))
1183 x_limit = spl(1,1)%x_limit(2)
1184
1185 ! Not all splines have the same number of points
1186 do i = 2, n1
1187 do j = 1, n2
1188 np = min(np, oct_spline_npoints(spl(i, j)%spl, spl(i, j)%acc))
1189 x_limit = min(x_limit, spl(i,j)%x_limit(2))
1190 end do
1191 end do
1192
1193 do i = 1, np
1194 if (x(i) > x_limit - tol_x) cycle
1195 write(iunit, '('//trim(fm)//'es18.8E3)') x(i), &
1196 ((spline_eval(spl(j, k), x(i)), j = 1, n1), k = 1, n2)
1197 end do
1198
1199 safe_deallocate_a(x)
1200
1201 pop_sub(spline_print_2)
1202 end subroutine spline_print_2
1203
1204
1205 !------------------------------------------------------------
1208 real(real64) function spline_x_threshold(spl, threshold) result(r)
1209 type(spline_t), intent(in) :: spl
1210 real(real64), intent(in) :: threshold
1211
1212 integer :: ii, jj
1213 real(real64), parameter :: dx = 0.01_real64
1214
1215 ! No PUSH SUB, called too often.
1216 assert(spl%x_limit(2) >= spl%x_limit(1))
1217
1218 call profiling_in('SPLINE_CUTOFF_RADIUS')
1219
1220 jj = floor(spl%x_limit(2)/dx) + 1
1221 ! Numerical errors can lead to jj to be overestimated by 1
1222 ! This test prevents this to occur
1223 do while(dx*(jj-1) > spl%x_limit(2) - m_half * dx)
1224 jj = jj-1
1225 end do
1226
1227 do ii = jj, 1, -1
1228 r = dx*(ii-1)
1229 if (abs(spline_eval(spl, r)) > threshold) exit
1230 end do
1231
1232 call profiling_out('SPLINE_CUTOFF_RADIUS')
1233
1234 end function spline_x_threshold
1235
1236 ! -------------------------------------------------------
1237
1238 real(real64) pure function spline_range_min(this) result(range)
1239 type(spline_t), intent(in) :: this
1240
1241 range = this%x_limit(1)
1242
1243 end function spline_range_min
1244
1245 ! -------------------------------------------------------
1246
1247 real(real64) pure function spline_range_max(this) result(range)
1248 type(spline_t), intent(in) :: this
1249
1250 range = this%x_limit(2)
1251
1252 end function spline_range_max
1253
1254 ! -------------------------------------------------------
1255 subroutine spline_generate_shifted_grid(this, x_shifted)
1256 type(spline_t), intent(in) :: this
1257 real(real64), allocatable, intent(inout) :: x_shifted(:)
1258
1259 real(real64), allocatable :: x(:)
1260 integer :: npoints, i
1261
1263
1264 ! We shift the grid by half of a spacing to force interpolation of the function
1265 ! This is useful for getting back the derivative on the same grid
1266 npoints = oct_spline_npoints(this%spl, this%acc)
1267 safe_allocate(x(1:npoints))
1268 safe_allocate(x_shifted(1:npoints))
1269 call oct_spline_x(this%spl, x(1))
1270 do i = 1, npoints -1
1271 x_shifted(i) = m_half*(x(i) + x(i+1))
1272 end do
1273 x_shifted(npoints) = x(npoints)
1274 safe_deallocate_a(x)
1275
1277 end subroutine spline_generate_shifted_grid
1278
1279end module splines_oct_m
1280
1281!! Local Variables:
1282!! mode: f90
1283!! coding: utf-8
1284!! 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:921
subroutine spline_end_0(spl)
Definition: splines.F90:364
subroutine, public spline_force_pos(spl, threshold)
Definition: splines.F90:841
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:1124
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:959
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:677
real(real64) pure function, public spline_range_min(this)
Definition: splines.F90:1154
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:1030
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:1001
subroutine spline_print_2(spl, iunit)
Print debug information for a 2D array of splines.
Definition: splines.F90:1074
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:748
subroutine, public spline_div(spla, splb, threshold)
Returns the values of spla divided by the values of splb.
Definition: splines.F90:797
real(real64) pure function, public spline_range_max(this)
Definition: splines.F90:1163
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:875
subroutine spline_evalz_array(spl, nn, xf)
Definition: splines.F90:462
subroutine, public spline_generate_shifted_grid(this, x_shifted)
Definition: splines.F90:1171
the basic spline datatype
Definition: splines.F90:156