libSUFR
a LIBrary of Some Useful Fortran Routines
All Classes Namespaces Files Functions Variables Pages
interpolate.f90
Go to the documentation of this file.
1!> \file interpolate.f90 Procedures to do interpolation (and fitting?)
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libSUFR package,
7! see: http://libsufr.sourceforge.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the European Union
10! Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
11! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12! PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
13! Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
14!
15!
16
17
18
19
20!***********************************************************************************************************************************
21!> \brief Procedures to do interpolation (and fitting?)
22
24 implicit none
25 save
26
27contains
28
29 !*********************************************************************************************************************************
30 !> \brief Do linear interpolation using the data points x1,x2, and y1,y2 to find the value y corresponding to x
31 !!
32 !! \param x1 X value 1
33 !! \param x2 X value 2
34 !! \param y1 Y value 1, belonging to x1
35 !! \param y2 Y value 2, belonging to x2
36 !!
37 !! \param x X value to find y value for
38 !!
39 !! \retval linear_interpolation Y value found
40
41 pure function linear_interpolation(x1,x2, y1,y2, x)
42 use sufr_kinds, only: double
43 implicit none
44 real(double), intent(in) :: x1,x2, y1,y2, x
45 real(double) :: linear_interpolation, a,b,y
46
47 a = (y2-y1)/(x2-x1)
48 b = y1 - a*x1
49 y = a*x + b
50
52
53 end function linear_interpolation
54 !*********************************************************************************************************************************
55
56
57 !*********************************************************************************************************************************
58 !> \brief Do linear interpolation using the data points x1,x2, and y1,y2 to find the value y corresponding to x,
59 !! using single-precision variables
60 !!
61 !! \param x1 X value 1
62 !! \param x2 X value 2
63 !! \param y1 Y value 1, belonging to x1
64 !! \param y2 Y value 2, belonging to x2
65 !!
66 !! \param x X value to find y value for
67 !!
68 !! \retval linear_interpolation_sp Y value found
69
70 pure function linear_interpolation_sp(x1,x2, y1,y2, x)
71 implicit none
72 real, intent(in) :: x1,x2, y1,y2, x
74
75 linear_interpolation_sp = real(linear_interpolation( dble(x1),dble(x2), dble(y1),dble(y2), dble(x) ))
76
77 end function linear_interpolation_sp
78 !*********************************************************************************************************************************
79
80
81 !*********************************************************************************************************************************
82 !> \brief Do linear interpolation using the data arrays xArr,yArr to find the value y corresponding to x
83 !!
84 !! \param xArr X-array, sorted to increasing value
85 !! \param yArr Y-array
86 !!
87 !! \param xVal X value to find y value for
88 !!
89 !! \retval linear_interpolate_array Y value found
90
91 function linear_interpolate_array(xArr, yArr, xVal)
92 use sufr_kinds, only: double
93 use sufr_system, only: warn
94 implicit none
95 real(double), intent(in) :: xarr(:), yarr(:), xval
96 integer :: ind
98
99 if(size(xarr)*size(yarr).eq.0) then
100 call warn('linear_interpolate_array(): at least one of the arrays has no elements.')
102 return
103 end if
104
105 ind = locate_value_in_array(xval, xarr) ! Find index ind such that xArr(ind) <= x <= xArr(ind+1)
106 linear_interpolate_array = linear_interpolation(xarr(ind),xarr(ind+1), yarr(ind),yarr(ind+1), xval) ! Interpolate
107
108 end function linear_interpolate_array
109 !*********************************************************************************************************************************
110
111
112 !*********************************************************************************************************************************
113 !> \brief Fit a parabola perfectly to three sets of data points x1,y1, x2,y2 and x3,y3
114 !!
115 !! \param x1 X value 1
116 !! \param x2 X value 2
117 !! \param x3 X value 3
118 !!
119 !! \param y1 Y value 1, belonging to x1
120 !! \param y2 Y value 2, belonging to x2
121 !! \param y3 Y value 3, belonging to x3
122 !!
123 !! \param a Coefficient a in y = a*x^2 + b*x + c (output)
124 !! \param b Coefficient b in y = a*x^2 + b*x + c (output)
125 !! \param c Coefficient c in y = a*x^2 + b*x + c (output)
126
127 pure subroutine perfect_parabolic_fit(x1,x2,x3, y1,y2,y3, a,b,c)
128 use sufr_kinds, only: double
129 implicit none
130 real(double), intent(in) :: x1,x2,x3, y1,y2,y3
131 real(double), intent(out) :: a,b,c
132 real(double) :: x12,x22,x32, d
133
134 x12 = x1*x1
135 x22 = x2*x2
136 x32 = x3*x3
137
138 d = (x3-x1)/(x2-x1)
139
140 a = ((y3-y1) - (y2-y1)*d) / ((x32-x12) - (x22-x12)*d)
141 b = ((y2-y1) - a*(x22-x12)) / (x2-x1)
142 c = y1 - a*x12 - b*x1
143
144 end subroutine perfect_parabolic_fit
145 !*********************************************************************************************************************************
146
147
148 !*********************************************************************************************************************************
149 !> \brief Compute a parabola a*x^2 + b*x + c
150 !!
151 !! \param x X value
152 !! \param a Coefficient a in y = a*x^2 +b*x + c
153 !! \param b Coefficient b in y = a*x^2 +b*x + c
154 !! \param c Coefficient c in y = a*x^2 +b*x + c
155 !!
156 !! \retval parabola The value of the parabola at x.
157
158 pure function parabola(x, a,b,c)
159 use sufr_kinds, only: double
160 implicit none
161 real(double), intent(in) :: x,a,b,c
162 real(double) :: parabola
163
164 parabola = a*x*x + b*x + c
165 end function parabola
166 !*********************************************************************************************************************************
167
168
169
170 !*********************************************************************************************************************************
171 !> \brief Locate the index in a monotonic array, such that a given value lies between array(index) and array(index+1).
172 !! 0 or nArr+1 is returned if the value lies outside the array.
173 !!
174 !! \param xVal Value to locate
175 !! \param xArray Array to locate value in. xArray must be monotonic, either ascending or descending
176 !!
177 !! \retval locate_value_in_array Index such that the value lies between array(index) and array(index+1).
178 !!
179 !! \see Numerical Recipes in Fortran, Sect.3.4
180
181 pure function locate_value_in_array(xVal, xArray)
182 use sufr_kinds, only: double
183 use sufr_numerics, only: deq
184
185 implicit none
186 real(double), intent(in) :: xval, xarray(:)
187 integer :: locate_value_in_array, narr,ilow,imid,iup
188 logical :: ascending
189
190 narr = size(xarray)
191 ascending = (xarray(narr).ge.xarray(1)) ! Array is ascending (T/F)
192 ilow = 0
193 iup = narr+1
194
195 do
196 if(iup-ilow.le.1) exit ! We've converged
197
198 imid = (iup+ilow)/2 ! Bisect
199 if(ascending .eqv. (xval.ge.xarray(imid))) then ! xVal >= array_m and ascending, or xVal < array_m and descending
200 ilow = imid ! -> replace lower index
201 else ! xVal < array_m and ascending, or xVal >= array_m and descending
202 iup = imid ! -> replace upper index
203 end if
204 end do
205
206 ! Assign the index to the return value:
207 if(deq(xval, xarray(1))) then ! Double equality
209 else if(deq(xval, xarray(narr))) then ! Double equality
210 locate_value_in_array = narr-1
211 else
212 locate_value_in_array = ilow ! = iUp
213 end if
214
215 end function locate_value_in_array
216 !*********************************************************************************************************************************
217
218end module sufr_interpolate
219!***********************************************************************************************************************************
220
221
222
223
224
Procedures to do interpolation (and fitting?)
real(double) function linear_interpolate_array(xarr, yarr, xval)
Do linear interpolation using the data arrays xArr,yArr to find the value y corresponding to x.
pure real(double) function linear_interpolation(x1, x2, y1, y2, x)
Do linear interpolation using the data points x1,x2, and y1,y2 to find the value y corresponding to x...
pure real(double) function parabola(x, a, b, c)
Compute a parabola a*x^2 + b*x + c.
pure integer function locate_value_in_array(xval, xarray)
Locate the index in a monotonic array, such that a given value lies between array(index) and array(in...
pure real function linear_interpolation_sp(x1, x2, y1, y2, x)
Do linear interpolation using the data points x1,x2, and y1,y2 to find the value y corresponding to x...
pure subroutine perfect_parabolic_fit(x1, x2, x3, y1, y2, y3, a, b, c)
Fit a parabola perfectly to three sets of data points x1,y1, x2,y2 and x3,y3.
Provides kinds and related constants/routines.
Definition kinds.f90:26
integer, parameter double
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:35
Procedures for numerical operations.
Definition numerics.f90:23
elemental logical function deq(x1, x2, eps)
Test whether two double-precision variables are equal to better than a given value (default: 2x machi...
Definition numerics.f90:90
System-related procedures.
Definition system.f90:23
subroutine warn(message, unit)
Print a warning to StdOut or StErr.
Definition system.f90:646