Skip to content

Commit 150b234

Browse files
committed
Added 1D routines with matching interfaces for the sub and oo modules. Fixes #3
1 parent 6c74bd7 commit 150b234

File tree

6 files changed

+249
-10
lines changed

6 files changed

+249
-10
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ Multidimensional B-Spline Interpolation of Data on a Regular Grid
99

1010
# Brief description
1111

12-
The library provides subroutines for 2D-6D interpolation using b-splines. The code is written in modern Fortran (i.e., Fortran 2003+).
12+
The library provides subroutines for 1D-6D interpolation using b-splines. The code is written in modern Fortran (i.e., Fortran 2003+).
1313

1414
The core routines are:
1515

1616
```Fortran
1717
18+
!f(x)
19+
subroutine db1ink(x,nx,fcn,kx,tx,bcoef,iflag)
20+
subroutine db1val(xval,idx,tx,nx,kx,bcoef,f,iflag)
21+
1822
!f(x,y)
1923
subroutine db2ink(x,nx,y,ny,fcn,kx,ky,tx,ty,bcoef,iflag)
2024
subroutine db2val(xval,yval,idx,idy,tx,ty,nx,ny,kx,ky,bcoef,f,iflag)

bspline-fortran.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ graph: true
1818
Brief description
1919
---------------
2020

21-
The library provides subroutines for 2D-6D interpolation using b-splines. The code is written in modern Fortran (i.e., Fortran 2003+).
21+
The library provides subroutines for 1D-6D interpolation using b-splines. The code is written in modern Fortran (i.e., Fortran 2003+).
2222

2323
License
2424
---------------

src/bspline_oo_module.f90

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
!*****************************************************************************************
2-
!
32
!> author: Jacob Williams
43
! license: BSD
54
!
65
!# Description
76
!
87
! Object-oriented style wrappers to [[bspline_sub_module]].
9-
! This module provides classes ([[bspline_2d]], [[bspline_3d]],
10-
! [[bspline_4d]], [[bspline_5d]], and [[bspline_6d]]) which can
11-
! be used instead of the main subroutine interface.
8+
! This module provides classes ([[bspline_1d]], [[bspline_2d]],
9+
! [[bspline_3d]], [[bspline_4d]], [[bspline_5d]], and [[bspline_6d]])
10+
! which can be used instead of the main subroutine interface.
1211
!
1312
!# History
1413
!
@@ -38,6 +37,19 @@ subroutine destroy_func(me) !! interface for bspline destructor routines
3837
end subroutine destroy_func
3938
end interface
4039

40+
type,extends(bspline_class),public :: bspline_1d
41+
!! Class for 1d b-spline interpolation.
42+
private
43+
integer :: nx = 0
44+
integer :: kx = 0
45+
real(wp),dimension(:),allocatable :: bcoef
46+
real(wp),dimension(:),allocatable :: tx
47+
contains
48+
procedure,public :: initialize => initialize_1d
49+
procedure,public :: evaluate => evaluate_1d
50+
procedure,public :: destroy => destroy_1d
51+
end type bspline_1d
52+
4153
type,extends(bspline_class),public :: bspline_2d
4254
!! Class for 2d b-spline interpolation.
4355
private
@@ -166,7 +178,72 @@ end subroutine destroy_func
166178

167179
contains
168180
!*****************************************************************************************
181+
182+
!*****************************************************************************************
183+
!> Destructor for [[bspline_1d]] type.
184+
185+
subroutine destroy_1d(me)
186+
187+
implicit none
188+
189+
class(bspline_1d),intent(out) :: me
190+
191+
end subroutine destroy_1d
192+
!*****************************************************************************************
193+
194+
!*****************************************************************************************
195+
!> Initialize a [[bspline_1d]] type. This is a wrapper for [[db1ink]].
196+
197+
subroutine initialize_1d(me,x,fcn,kx,iflag)
198+
199+
implicit none
200+
201+
class(bspline_1d),intent(inout) :: me
202+
real(wp),dimension(:),intent(in) :: x
203+
real(wp),dimension(:),intent(in) :: fcn
204+
integer,intent(in) :: kx
205+
integer,intent(out) :: iflag
206+
207+
integer :: iknot
208+
integer :: nx
169209

210+
call me%destroy()
211+
212+
nx = size(x)
213+
214+
me%nx = nx
215+
me%kx = kx
216+
217+
allocate(me%tx(nx+kx))
218+
allocate(me%bcoef(nx))
219+
220+
iknot = 0 !knot sequence chosen by db2ink
221+
222+
call db1ink(x,nx,fcn,kx,me%tx,me%bcoef,iknot)
223+
224+
iflag = iknot !status flag
225+
226+
end subroutine initialize_1d
227+
!*****************************************************************************************
228+
229+
!*****************************************************************************************
230+
!> Evaluate a [[bspline_1d]] interpolate. This is a wrapper for [[db1val]].
231+
232+
subroutine evaluate_1d(me,xval,idx,f,iflag)
233+
234+
implicit none
235+
236+
class(bspline_1d),intent(in) :: me
237+
real(wp),intent(in) :: xval
238+
integer,intent(in) :: idx
239+
real(wp),intent(out) :: f
240+
integer,intent(out) :: iflag
241+
242+
call db1val(xval,idx,me%tx,me%nx,me%kx,me%bcoef,f,iflag,me%inbvx)
243+
244+
end subroutine evaluate_1d
245+
!*****************************************************************************************
246+
170247
!*****************************************************************************************
171248
!> Destructor for [[bspline_2d]] type.
172249

src/bspline_sub_module.f90

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
!
66
!# Description
77
!
8-
! Multidimensional (2D-6D) B-Spline interpolation of data on a regular grid.
8+
! Multidimensional (1D-6D) B-Spline interpolation of data on a regular grid.
99
! Basic subroutine interface.
1010
!
1111
!# Notes
@@ -14,7 +14,7 @@
1414
! The original Fortran 77 routines were converted to free-form source.
1515
! Some of them are relatively unchanged from the originals, but some have
1616
! been extensively refactored. In addition, new routines for
17-
! 4d, 5d, and 6d interpolation were also created (these are simply
17+
! 1d, 4d, 5d, and 6d interpolation were also created (these are simply
1818
! extensions of the same algorithm into higher dimensions).
1919
!
2020
!# See also
@@ -48,6 +48,7 @@ module bspline_sub_module
4848
integer,parameter :: wp = real64 !! Real precision
4949

5050
!main routines:
51+
public :: db1ink, db1val
5152
public :: db2ink, db2val
5253
public :: db3ink, db3val
5354
public :: db4ink, db4val
@@ -58,6 +59,134 @@ module bspline_sub_module
5859

5960
!*****************************************************************************************
6061

62+
!*****************************************************************************************
63+
!> Determines the parameters of a function that interpolates
64+
! the one-dimensional gridded data
65+
! $$ [x(i),\mathrm{fcn}(i)] ~\mathrm{for}~ i=1,..,n_x $$
66+
! The interpolating function and its derivatives may
67+
! subsequently be evaluated by the function [[db1val]].
68+
!
69+
!# History
70+
!
71+
! * Jacob Williams, 10/30/2015 : Created 1D routine.
72+
73+
subroutine db1ink(x,nx,fcn,kx,tx,bcoef,iflag)
74+
75+
implicit none
76+
77+
integer,intent(in) :: nx !! Number of x abcissae
78+
integer,intent(in) :: kx !! The order of spline pieces in x (>= 2, < nx). (order = polynomial degree + 1)
79+
real(wp),dimension(nx),intent(in) :: x !! Array of x abcissae. Must be strictly increasing.
80+
real(wp),dimension(nx),intent(in) :: fcn !! Array of function values to interpolate. fcn(i) should
81+
!! contain the function value at the point x(i)
82+
real(wp),dimension(nx+kx),intent(inout) :: tx !! The knots in the x direction for the spline interpolant.
83+
!! If iflag=0 these are chosen by db1ink.
84+
!! If iflag=1 these are specified by the user.
85+
!! Must be non-decreasing.
86+
real(wp),dimension(nx),intent(out) :: bcoef !! Array of coefficients of the b-spline interpolant.
87+
integer,intent(inout) :: iflag !! **on input:** 0 = knot sequence chosen by db1ink.
88+
!! 1 = knot sequence chosen by user.
89+
!! **on output:** 1 = successful execution.
90+
!! 2 = iflag out of range.
91+
!! 3 = nx out of range.
92+
!! 4 = kx out of range.
93+
!! 5 = x not strictly increasing.
94+
!! 6 = tx not non-decreasing.
95+
96+
97+
real(wp),dimension(nx) :: temp
98+
real(wp),dimension(2*kx*(nx+1)) :: work
99+
logical :: status_ok
100+
101+
!check validity of inputs
102+
103+
call check_inputs('db1ink',&
104+
iflag,&
105+
nx=nx,&
106+
kx=kx,&
107+
x=x,&
108+
tx=tx,&
109+
status_ok=status_ok)
110+
111+
if (status_ok) then
112+
113+
!choose knots
114+
115+
if (iflag == 0) then
116+
call dbknot(x,nx,kx,tx)
117+
end if
118+
119+
!construct b-spline coefficients
120+
121+
call dbtpcf(x,nx,fcn,nx,1,tx,kx,bcoef,work)
122+
123+
iflag = 1
124+
125+
end if
126+
127+
end subroutine db1ink
128+
!*****************************************************************************************
129+
130+
!*****************************************************************************************
131+
!> Evaluates the tensor product piecewise polynomial
132+
! interpolant constructed by the routine [[db1ink]] or one of its
133+
! derivatives at the point xval.
134+
!
135+
! To evaluate the interpolant itself, set idx=0,
136+
! to evaluate the first partial with respect to x, set idx=1, and so on.
137+
!
138+
! db1val returns 0.0 if (xval,yval) is out of range. that is, if
139+
!```fortran
140+
! xval < tx(1) .or. xval > tx(nx+kx)
141+
!```
142+
! if the knots tx were chosen by [[db1ink]], then this is equivalent to:
143+
!```fortran
144+
! xval < x(1) .or. xval > x(nx)+epsx
145+
!```
146+
! where
147+
!```fortran
148+
! epsx = 0.1*(x(nx)-x(nx-1))
149+
!```
150+
!
151+
! The input quantities tx, nx, kx, and bcoef should be
152+
! unchanged since the last call of [[db1ink]].
153+
!
154+
!# History
155+
!
156+
! * Jacob Williams, 10/30/2015 : Created 1D routine.
157+
158+
subroutine db1val(xval,idx,tx,nx,kx,bcoef,f,iflag,inbvx_in)
159+
160+
implicit none
161+
162+
integer,intent(in) :: idx !! x derivative of piecewise polynomial to evaluate.
163+
integer,intent(in) :: nx !! the number of interpolation points in x. (same as in last call to db1ink)
164+
integer,intent(in) :: kx !! order of polynomial pieces in x. (same as in last call to db1ink)
165+
real(wp),intent(in) :: xval !! x coordinate of evaluation point.
166+
real(wp),dimension(nx+kx),intent(in) :: tx !! sequence of knots defining the piecewise polynomial in the x direction. (same as in last call to db1ink)
167+
real(wp),dimension(nx),intent(in) :: bcoef !! the b-spline coefficients computed by db1ink.
168+
real(wp),intent(out) :: f !! interpolated value
169+
integer,intent(out) :: iflag !! status flag: 0 : no errors, /=0 : error
170+
integer,intent(in),optional :: inbvx_in !! inbvx initialization parameter from class
171+
172+
real(wp),dimension(3*kx) :: work
173+
174+
integer,save :: inbvx = 1
175+
176+
if (present(inbvx_in)) inbvx = inbvx_in
177+
178+
f = 0.0_wp
179+
iflag = 1
180+
181+
if (xval<tx(1) .or. xval>tx(nx+kx)) return
182+
183+
iflag = 0
184+
185+
f = dbvalu(tx,bcoef,nx,kx,idx,xval,inbvx,work)
186+
187+
end subroutine db1val
188+
!*****************************************************************************************
189+
61190
!*****************************************************************************************
62191
!> Determines the parameters of a function that interpolates
63192
! the two-dimensional gridded data

src/tests/test.f90

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ program bspline_test
2525

2626
real(wp) :: x(nx),y(ny),z(nz),q(nq),r(nr),s(ns)
2727
real(wp) :: tx(nx+kx),ty(ny+ky),tz(nz+kz),tq(nq+kq),tr(nr+kr),ts(ns+ks)
28+
real(wp) :: fcn_1d(nx)
2829
real(wp) :: fcn_2d(nx,ny)
2930
real(wp) :: fcn_3d(nx,ny,nz)
3031
real(wp) :: fcn_4d(nx,ny,nz,nq)
@@ -64,6 +65,7 @@ program bspline_test
6465
s(n) = dble(n-1)/dble(ns-1)
6566
end do
6667
do i=1,nx
68+
fcn_1d(i) = f1(x(i))
6769
do j=1,ny
6870
fcn_2d(i,j) = f2(x(i),y(j))
6971
do k=1,nz
@@ -83,6 +85,8 @@ program bspline_test
8385

8486
! interpolate
8587

88+
iflag = 0
89+
call db1ink(x,nx,fcn_1d,kx,tx,fcn_1d,iflag)
8690
iflag = 0
8791
call db2ink(x,nx,y,ny,fcn_2d,kx,ky,tx,ty,fcn_2d,iflag)
8892
iflag = 0
@@ -98,6 +102,11 @@ program bspline_test
98102

99103
errmax = 0.0_wp
100104
do i=1,nx
105+
call db1val(x(i),idx,&
106+
tx,nx,kx,fcn_1d,val(1),iflag)
107+
tru(1) = f1(x(i))
108+
err(1) = abs(tru(1)-val(1))
109+
errmax(1) = max(err(1),errmax(1))
101110
do j=1,ny
102111
call db2val(x(i),y(j),idx,idy,&
103112
tx,ty,nx,ny,kx,ky,fcn_2d,val(2),iflag)
@@ -136,7 +145,7 @@ program bspline_test
136145
end do
137146

138147
! check max error against tolerance
139-
do i=2,6
148+
do i=1,6
140149
write(*,*) i,'D: max error:', errmax(i)
141150
if (errmax(i) >= tol) then
142151
write(*,*) ' ** test failed ** '
@@ -147,6 +156,12 @@ program bspline_test
147156
end do
148157

149158
contains
159+
160+
real(wp) function f1(x) !! 1d test function
161+
implicit none
162+
real(wp) :: x
163+
f1 = 0.5_wp * (x*exp(-x) + sin(x) )
164+
end function f1
150165

151166
real(wp) function f2(x,y) !! 2d test function
152167
implicit none

0 commit comments

Comments
 (0)