ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/utils/interpolation.F90
Revision: 2708
Committed: Fri Apr 14 19:57:04 2006 UTC (18 years, 2 months ago) by gezelter
File size: 12491 byte(s)
Log Message:
Heavily modified interpolation module, also moved to "utils"

File Contents

# User Rev Content
1 gezelter 2708 !!
2     !! Copyright (c) 2006 The University of Notre Dame. All Rights Reserved.
3     !!
4     !! The University of Notre Dame grants you ("Licensee") a
5     !! non-exclusive, royalty free, license to use, modify and
6     !! redistribute this software in source and binary code form, provided
7     !! that the following conditions are met:
8     !!
9     !! 1. Acknowledgement of the program authors must be made in any
10     !! publication of scientific results based in part on use of the
11     !! program. An acceptable form of acknowledgement is citation of
12     !! the article in which the program was described (Matthew
13     !! A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14     !! J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15     !! Parallel Simulation Engine for Molecular Dynamics,"
16     !! J. Comput. Chem. 26, pp. 252-271 (2005))
17     !!
18     !! 2. Redistributions of source code must retain the above copyright
19     !! notice, this list of conditions and the following disclaimer.
20     !!
21     !! 3. Redistributions in binary form must reproduce the above copyright
22     !! notice, this list of conditions and the following disclaimer in the
23     !! documentation and/or other materials provided with the
24     !! distribution.
25     !!
26     !! This software is provided "AS IS," without a warranty of any
27     !! kind. All express or implied conditions, representations and
28     !! warranties, including any implied warranty of merchantability,
29     !! fitness for a particular purpose or non-infringement, are hereby
30     !! excluded. The University of Notre Dame and its licensors shall not
31     !! be liable for any damages suffered by licensee as a result of
32     !! using, modifying or distributing the software or its
33     !! derivatives. In no event will the University of Notre Dame or its
34     !! licensors be liable for any lost revenue, profit or data, or for
35     !! direct, indirect, special, consequential, incidental or punitive
36     !! damages, however caused and regardless of the theory of liability,
37     !! arising out of the use of or inability to use software, even if the
38     !! University of Notre Dame has been advised of the possibility of
39     !! such damages.
40     !!
41     !!
42     !! interpolation.F90
43     !!
44     !! Created by Charles F. Vardeman II on 03 Apr 2006.
45     !!
46     !! PURPOSE: Generic Spline interplelation routines. These routines assume that we are on a uniform grid for
47     !! precomputation of spline parameters.
48     !!
49     !! @author Charles F. Vardeman II
50     !! @version $Id: interpolation.F90,v 1.1 2006-04-14 19:57:04 gezelter Exp $
51    
52    
53     module INTERPOLATION
54     use definitions
55     use status
56     implicit none
57     PRIVATE
58    
59     character(len = statusMsgSize) :: errMSG
60    
61     type, public :: cubicSpline
62     private
63     integer :: np = 0
64     real(kind=dp) :: dx
65     real(kind=dp) :: dx_i
66     real (kind=dp), pointer,dimension(:) :: x => null()
67     real (kind=dp), pointer,dimension(4,:) :: c => null()
68     end type cubicSpline
69    
70     interface splineLookup
71     module procedure multiSplint
72     module procedure splintd
73     module procedure splintd1
74     module procedure splintd2
75     end interface
76    
77     interface newSpline
78     module procedure newSplineWithoutDerivs
79     module procedure newSplineWithDerivs
80     end interface
81    
82     public :: deleteSpline
83    
84     contains
85    
86    
87     subroutine newSplineWithoutDerivs(cs, x, y, yp1, ypn, boundary)
88    
89     !************************************************************************
90     !
91     ! newSplineWithoutDerivs solves for slopes defining a cubic spline.
92     !
93     ! Discussion:
94     !
95     ! A tridiagonal linear system for the unknown slopes S(I) of
96     ! F at x(I), I=1,..., N, is generated and then solved by Gauss
97     ! elimination, with S(I) ending up in cs%C(2,I), for all I.
98     !
99     ! Reference:
100     !
101     ! Carl DeBoor,
102     ! A Practical Guide to Splines,
103     ! Springer Verlag.
104     !
105     ! Parameters:
106     !
107     ! Input, real x(N), the abscissas or X values of
108     ! the data points. The entries of TAU are assumed to be
109     ! strictly increasing.
110     !
111     ! Input, real y(I), contains the function value at x(I) for
112     ! I = 1, N.
113     !
114     ! yp1 contains the slope at x(1) and ypn contains
115     ! the slope at x(N).
116     !
117     ! On output, the intermediate slopes at x(I) have been
118     ! stored in cs%C(2,I), for I = 2 to N-1.
119    
120     implicit none
121    
122     type (cubicSpline), intent(inout) :: cs
123     real( kind = DP ), intent(in) :: x(:), y(:)
124     real( kind = DP ), intent(in) :: yp1, ypn
125     character(len=*), intent(in) :: boundary
126     real( kind = DP ) :: g, divdif1, divdif3, dx
127     integer :: i, alloc_error, np
128    
129     alloc_error = 0
130    
131     if (cs%np .ne. 0) then
132     call handleWarning("interpolation::newSplineWithoutDerivs", &
133     "Type was already created")
134     call deleteSpline(cs)
135     end if
136    
137     ! make sure the sizes match
138    
139     if (size(x) .ne. size(y)) then
140     call handleError("interpolation::newSplineWithoutDerivs", &
141     "Array size mismatch")
142     end if
143    
144     np = size(x)
145     cs%np = np
146    
147     allocate(cs%x(np), stat=alloc_error)
148     if(alloc_error .ne. 0) then
149     call handleError("interpolation::newSplineWithoutDerivs", &
150     "Error in allocating storage for x")
151     endif
152    
153     allocate(cs%c(4,np), stat=alloc_error)
154     if(alloc_error .ne. 0) then
155     call handleError("interpolation::newSplineWithoutDerivs", &
156     "Error in allocating storage for c")
157     endif
158    
159     do i = 1, np
160     cs%x(i) = x(i)
161     cs%c(1,i) = y(i)
162     enddo
163    
164     if ((boundary.eq.'l').or.(boundary.eq.'L').or. &
165     (boundary.eq.'b').or.(boundary.eq.'B')) then
166     cs%c(2,1) = yp1
167     else
168     cs%c(2,1) = 0.0_DP
169     endif
170     if ((boundary.eq.'u').or.(boundary.eq.'U').or. &
171     (boundary.eq.'b').or.(boundary.eq.'B')) then
172     cs%c(2,1) = ypn
173     else
174     cs%c(2,1) = 0.0_DP
175     endif
176    
177     !
178     ! Set up the right hand side of the linear system.
179     !
180     do i = 2, cs%np - 1
181     cs%c(2,i) = 3.0_DP * ( &
182     (x(i) - x(i-1)) * (cs%c(1,i+1) - cs%c(1,i)) / (x(i+1) - x(i)) + &
183     (x(i+1) - x(i)) * (cs%c(1,i) - cs%c(1,i-1)) / (x(i) - x(i-1)))
184     end do
185     !
186     ! Set the diagonal coefficients.
187     !
188     cs%c(4,1) = 1.0_DP
189     do i = 2, cs%np - 1
190     cs%c(4,i) = 2.0_DP * ( x(i+1) - x(i-1) )
191     end do
192     cs%c(4,n) = 1.0_DP
193     !
194     ! Set the off-diagonal coefficients.
195     !
196     cs%c(3,1) = 0.0_DP
197     do i = 2, cs%np
198     cs%c(3,i) = x(i) - x(i-1)
199     end do
200     !
201     ! Forward elimination.
202     !
203     do i = 2, cs%np - 1
204     g = -cs%c(3,i+1) / cs%c(4,i-1)
205     cs%c(4,i) = cs%c(4,i) + g * cs%c(3,i-1)
206     cs%c(2,i) = cs%c(2,i) + g * cs%c(2,i-1)
207     end do
208     !
209     ! Back substitution for the interior slopes.
210     !
211     do i = cs%np - 1, 2, -1
212     cs%c(2,i) = ( cs%c(2,i) - cs%c(3,i) * cs%c(2,i+1) ) / cs%c(4,i)
213     end do
214     !
215     ! Now compute the quadratic and cubic coefficients used in the
216     ! piecewise polynomial representation.
217     !
218     do i = 1, cs%np - 1
219     dx = x(i+1) - x(i)
220     divdif1 = ( cs%c(1,i+1) - cs%c(1,i) ) / dx
221     divdif3 = cs%c(2,i) + cs%c(2,i+1) - 2.0_DP * divdif1
222     cs%c(3,i) = ( divdif1 - cs%c(2,i) - divdif3 ) / dx
223     cs%c(4,i) = divdif3 / ( dx * dx )
224     end do
225    
226     cs%c(3,np) = 0.0_DP
227     cs%c(4,np) = 0.0_DP
228    
229     cs%dx = dx
230     cs%dxi = 1.0_DP / dx
231     return
232     end subroutine newSplineWithoutDerivs
233    
234     subroutine newSplineWithDerivs(cs, x, y, yp)
235    
236     !************************************************************************
237     !
238     ! newSplineWithDerivs
239    
240     implicit none
241    
242     type (cubicSpline), intent(inout) :: cs
243     real( kind = DP ), intent(in) :: x(:), y(:), yp(:)
244     real( kind = DP ) :: g, divdif1, divdif3, dx
245     integer :: i, alloc_error, np
246    
247     alloc_error = 0
248    
249     if (cs%np .ne. 0) then
250     call handleWarning("interpolation::newSplineWithDerivs", &
251     "Type was already created")
252     call deleteSpline(cs)
253     end if
254    
255     ! make sure the sizes match
256    
257     if ((size(x) .ne. size(y)).or.(size(x) .ne. size(yp))) then
258     call handleError("interpolation::newSplineWithDerivs", &
259     "Array size mismatch")
260     end if
261    
262     np = size(x)
263     cs%np = np
264    
265     allocate(cs%x(np), stat=alloc_error)
266     if(alloc_error .ne. 0) then
267     call handleError("interpolation::newSplineWithDerivs", &
268     "Error in allocating storage for x")
269     endif
270    
271     allocate(cs%c(4,np), stat=alloc_error)
272     if(alloc_error .ne. 0) then
273     call handleError("interpolation::newSplineWithDerivs", &
274     "Error in allocating storage for c")
275     endif
276    
277     do i = 1, np
278     cs%x(i) = x(i)
279     cs%c(1,i) = y(i)
280     cs%c(2,i) = yp(i)
281     enddo
282     !
283     ! Set the diagonal coefficients.
284     !
285     cs%c(4,1) = 1.0_DP
286     do i = 2, cs%np - 1
287     cs%c(4,i) = 2.0_DP * ( x(i+1) - x(i-1) )
288     end do
289     cs%c(4,n) = 1.0_DP
290     !
291     ! Set the off-diagonal coefficients.
292     !
293     cs%c(3,1) = 0.0_DP
294     do i = 2, cs%np
295     cs%c(3,i) = x(i) - x(i-1)
296     end do
297     !
298     ! Forward elimination.
299     !
300     do i = 2, cs%np - 1
301     g = -cs%c(3,i+1) / cs%c(4,i-1)
302     cs%c(4,i) = cs%c(4,i) + g * cs%c(3,i-1)
303     cs%c(2,i) = cs%c(2,i) + g * cs%c(2,i-1)
304     end do
305     !
306     ! Back substitution for the interior slopes.
307     !
308     do i = cs%np - 1, 2, -1
309     cs%c(2,i) = ( cs%c(2,i) - cs%c(3,i) * cs%c(2,i+1) ) / cs%c(4,i)
310     end do
311     !
312     ! Now compute the quadratic and cubic coefficients used in the
313     ! piecewise polynomial representation.
314     !
315     do i = 1, cs%np - 1
316     dx = x(i+1) - x(i)
317     divdif1 = ( cs%c(1,i+1) - cs%c(1,i) ) / dx
318     divdif3 = cs%c(2,i) + cs%c(2,i+1) - 2.0_DP * divdif1
319     cs%c(3,i) = ( divdif1 - cs%c(2,i) - divdif3 ) / dx
320     cs%c(4,i) = divdif3 / ( dx * dx )
321     end do
322    
323     cs%c(3,np) = 0.0_DP
324     cs%c(4,np) = 0.0_DP
325    
326     cs%dx = dx
327     cs%dxi = 1.0_DP / dx
328    
329     return
330     end subroutine newSplineWithoutDerivs
331    
332     subroutine deleteSpline(this)
333    
334     type(cubicSpline) :: this
335    
336     if(associated(this%x)) then
337     deallocate(this%x)
338     this%x => null()
339     end if
340     if(associated(this%c)) then
341     deallocate(this%c)
342     this%c => null()
343     end if
344    
345     this%np = 0
346    
347     end subroutine deleteSpline
348    
349     subroutine lookup_nonuniform_spline(cs, xval, yval)
350    
351     !*************************************************************************
352     !
353     ! lookup_nonuniform_spline evaluates a piecewise cubic Hermite interpolant.
354     !
355     ! Discussion:
356     !
357     ! newSpline must be called first, to set up the
358     ! spline data from the raw function and derivative data.
359     !
360     ! Modified:
361     !
362     ! 06 April 1999
363     !
364     ! Reference:
365     !
366     ! Conte and de Boor,
367     ! Algorithm PCUBIC,
368     ! Elementary Numerical Analysis,
369     ! 1973, page 234.
370     !
371     ! Parameters:
372     !
373     implicit none
374    
375     type (cubicSpline), intent(in) :: cs
376     real( kind = DP ), intent(in) :: xval
377     real( kind = DP ), intent(out) :: yval
378     integer :: i, j
379     !
380     ! Find the interval J = [ cs%x(J), cs%x(J+1) ] that contains
381     ! or is nearest to xval.
382     !
383     j = cs%np - 1
384    
385     do i = 1, cs%np - 2
386    
387     if ( xval < cs%x(i+1) ) then
388     j = i
389     exit
390     end if
391    
392     end do
393     !
394     ! Evaluate the cubic polynomial.
395     !
396     dx = xval - cs%x(j)
397    
398     yval = cs%c(1,j) + dx * ( cs%c(2,j) + dx * ( cs%c(3,j) + dx * cs%c(4,j) ) )
399    
400     return
401     end subroutine lookup_nonuniform_spline
402    
403     subroutine lookup_uniform_spline(cs, xval, yval)
404    
405     !*************************************************************************
406     !
407     ! lookup_uniform_spline evaluates a piecewise cubic Hermite interpolant.
408     !
409     ! Discussion:
410     !
411     ! newSpline must be called first, to set up the
412     ! spline data from the raw function and derivative data.
413     !
414     ! Modified:
415     !
416     ! 06 April 1999
417     !
418     ! Reference:
419     !
420     ! Conte and de Boor,
421     ! Algorithm PCUBIC,
422     ! Elementary Numerical Analysis,
423     ! 1973, page 234.
424     !
425     ! Parameters:
426     !
427     implicit none
428    
429     type (cubicSpline), intent(in) :: cs
430     real( kind = DP ), intent(in) :: xval
431     real( kind = DP ), intent(out) :: yval
432     integer :: i, j
433     !
434     ! Find the interval J = [ cs%x(J), cs%x(J+1) ] that contains
435     ! or is nearest to xval.
436    
437     j = MAX(1, MIN(cs%np, idint((xval-cs%x(1)) * cs%dxi) + 1))
438    
439     dx = xval - cs%x(j)
440    
441     yval = cs%c(1,j) + dx * ( cs%c(2,j) + dx * ( cs%c(3,j) + dx * cs%c(4,j) ) )
442    
443     return
444     end subroutine lookup_uniform_spline
445    
446     end module INTERPOLATION