ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/utils/interpolation.F90
Revision: 2709
Committed: Fri Apr 14 20:04:31 2006 UTC (18 years, 2 months ago) by gezelter
File size: 12399 byte(s)
Log Message:
bug fixes for interpolation module

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 gezelter 2709 !! @version $Id: interpolation.F90,v 1.2 2006-04-14 20:04:31 gezelter Exp $
51 gezelter 2708
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 gezelter 2709 real (kind=dp), pointer,dimension(:,:) :: c => null()
68 gezelter 2708 end type cubicSpline
69    
70     interface newSpline
71     module procedure newSplineWithoutDerivs
72     module procedure newSplineWithDerivs
73     end interface
74    
75     public :: deleteSpline
76    
77     contains
78    
79    
80     subroutine newSplineWithoutDerivs(cs, x, y, yp1, ypn, boundary)
81    
82     !************************************************************************
83     !
84     ! newSplineWithoutDerivs solves for slopes defining a cubic spline.
85     !
86     ! Discussion:
87     !
88     ! A tridiagonal linear system for the unknown slopes S(I) of
89     ! F at x(I), I=1,..., N, is generated and then solved by Gauss
90     ! elimination, with S(I) ending up in cs%C(2,I), for all I.
91     !
92     ! Reference:
93     !
94     ! Carl DeBoor,
95     ! A Practical Guide to Splines,
96     ! Springer Verlag.
97     !
98     ! Parameters:
99     !
100     ! Input, real x(N), the abscissas or X values of
101     ! the data points. The entries of TAU are assumed to be
102     ! strictly increasing.
103     !
104     ! Input, real y(I), contains the function value at x(I) for
105     ! I = 1, N.
106     !
107     ! yp1 contains the slope at x(1) and ypn contains
108     ! the slope at x(N).
109     !
110     ! On output, the intermediate slopes at x(I) have been
111     ! stored in cs%C(2,I), for I = 2 to N-1.
112    
113     implicit none
114    
115     type (cubicSpline), intent(inout) :: cs
116     real( kind = DP ), intent(in) :: x(:), y(:)
117     real( kind = DP ), intent(in) :: yp1, ypn
118     character(len=*), intent(in) :: boundary
119     real( kind = DP ) :: g, divdif1, divdif3, dx
120     integer :: i, alloc_error, np
121    
122     alloc_error = 0
123    
124     if (cs%np .ne. 0) then
125     call handleWarning("interpolation::newSplineWithoutDerivs", &
126     "Type was already created")
127     call deleteSpline(cs)
128     end if
129    
130     ! make sure the sizes match
131    
132     if (size(x) .ne. size(y)) then
133     call handleError("interpolation::newSplineWithoutDerivs", &
134     "Array size mismatch")
135     end if
136    
137     np = size(x)
138     cs%np = np
139    
140     allocate(cs%x(np), stat=alloc_error)
141     if(alloc_error .ne. 0) then
142     call handleError("interpolation::newSplineWithoutDerivs", &
143     "Error in allocating storage for x")
144     endif
145    
146     allocate(cs%c(4,np), stat=alloc_error)
147     if(alloc_error .ne. 0) then
148     call handleError("interpolation::newSplineWithoutDerivs", &
149     "Error in allocating storage for c")
150     endif
151    
152     do i = 1, np
153     cs%x(i) = x(i)
154     cs%c(1,i) = y(i)
155     enddo
156    
157     if ((boundary.eq.'l').or.(boundary.eq.'L').or. &
158     (boundary.eq.'b').or.(boundary.eq.'B')) then
159     cs%c(2,1) = yp1
160     else
161     cs%c(2,1) = 0.0_DP
162     endif
163     if ((boundary.eq.'u').or.(boundary.eq.'U').or. &
164     (boundary.eq.'b').or.(boundary.eq.'B')) then
165     cs%c(2,1) = ypn
166     else
167     cs%c(2,1) = 0.0_DP
168     endif
169    
170     !
171     ! Set up the right hand side of the linear system.
172     !
173     do i = 2, cs%np - 1
174     cs%c(2,i) = 3.0_DP * ( &
175     (x(i) - x(i-1)) * (cs%c(1,i+1) - cs%c(1,i)) / (x(i+1) - x(i)) + &
176     (x(i+1) - x(i)) * (cs%c(1,i) - cs%c(1,i-1)) / (x(i) - x(i-1)))
177     end do
178     !
179     ! Set the diagonal coefficients.
180     !
181     cs%c(4,1) = 1.0_DP
182     do i = 2, cs%np - 1
183     cs%c(4,i) = 2.0_DP * ( x(i+1) - x(i-1) )
184     end do
185 gezelter 2709 cs%c(4,cs%np) = 1.0_DP
186 gezelter 2708 !
187     ! Set the off-diagonal coefficients.
188     !
189     cs%c(3,1) = 0.0_DP
190     do i = 2, cs%np
191     cs%c(3,i) = x(i) - x(i-1)
192     end do
193     !
194     ! Forward elimination.
195     !
196     do i = 2, cs%np - 1
197     g = -cs%c(3,i+1) / cs%c(4,i-1)
198     cs%c(4,i) = cs%c(4,i) + g * cs%c(3,i-1)
199     cs%c(2,i) = cs%c(2,i) + g * cs%c(2,i-1)
200     end do
201     !
202     ! Back substitution for the interior slopes.
203     !
204     do i = cs%np - 1, 2, -1
205     cs%c(2,i) = ( cs%c(2,i) - cs%c(3,i) * cs%c(2,i+1) ) / cs%c(4,i)
206     end do
207     !
208     ! Now compute the quadratic and cubic coefficients used in the
209     ! piecewise polynomial representation.
210     !
211     do i = 1, cs%np - 1
212     dx = x(i+1) - x(i)
213     divdif1 = ( cs%c(1,i+1) - cs%c(1,i) ) / dx
214     divdif3 = cs%c(2,i) + cs%c(2,i+1) - 2.0_DP * divdif1
215     cs%c(3,i) = ( divdif1 - cs%c(2,i) - divdif3 ) / dx
216     cs%c(4,i) = divdif3 / ( dx * dx )
217     end do
218    
219 gezelter 2709 cs%c(3,cs%np) = 0.0_DP
220     cs%c(4,cs%np) = 0.0_DP
221 gezelter 2708
222     cs%dx = dx
223 gezelter 2709 cs%dx_i = 1.0_DP / dx
224 gezelter 2708 return
225     end subroutine newSplineWithoutDerivs
226    
227     subroutine newSplineWithDerivs(cs, x, y, yp)
228    
229     !************************************************************************
230     !
231     ! newSplineWithDerivs
232    
233     implicit none
234    
235     type (cubicSpline), intent(inout) :: cs
236     real( kind = DP ), intent(in) :: x(:), y(:), yp(:)
237     real( kind = DP ) :: g, divdif1, divdif3, dx
238     integer :: i, alloc_error, np
239    
240     alloc_error = 0
241    
242     if (cs%np .ne. 0) then
243     call handleWarning("interpolation::newSplineWithDerivs", &
244     "Type was already created")
245     call deleteSpline(cs)
246     end if
247    
248     ! make sure the sizes match
249    
250     if ((size(x) .ne. size(y)).or.(size(x) .ne. size(yp))) then
251     call handleError("interpolation::newSplineWithDerivs", &
252     "Array size mismatch")
253     end if
254    
255     np = size(x)
256     cs%np = np
257    
258     allocate(cs%x(np), stat=alloc_error)
259     if(alloc_error .ne. 0) then
260     call handleError("interpolation::newSplineWithDerivs", &
261     "Error in allocating storage for x")
262     endif
263    
264     allocate(cs%c(4,np), stat=alloc_error)
265     if(alloc_error .ne. 0) then
266     call handleError("interpolation::newSplineWithDerivs", &
267     "Error in allocating storage for c")
268     endif
269    
270     do i = 1, np
271     cs%x(i) = x(i)
272     cs%c(1,i) = y(i)
273     cs%c(2,i) = yp(i)
274     enddo
275     !
276     ! Set the diagonal coefficients.
277     !
278     cs%c(4,1) = 1.0_DP
279     do i = 2, cs%np - 1
280     cs%c(4,i) = 2.0_DP * ( x(i+1) - x(i-1) )
281     end do
282 gezelter 2709 cs%c(4,cs%np) = 1.0_DP
283 gezelter 2708 !
284     ! Set the off-diagonal coefficients.
285     !
286     cs%c(3,1) = 0.0_DP
287     do i = 2, cs%np
288     cs%c(3,i) = x(i) - x(i-1)
289     end do
290     !
291     ! Forward elimination.
292     !
293     do i = 2, cs%np - 1
294     g = -cs%c(3,i+1) / cs%c(4,i-1)
295     cs%c(4,i) = cs%c(4,i) + g * cs%c(3,i-1)
296     cs%c(2,i) = cs%c(2,i) + g * cs%c(2,i-1)
297     end do
298     !
299     ! Back substitution for the interior slopes.
300     !
301     do i = cs%np - 1, 2, -1
302     cs%c(2,i) = ( cs%c(2,i) - cs%c(3,i) * cs%c(2,i+1) ) / cs%c(4,i)
303     end do
304     !
305     ! Now compute the quadratic and cubic coefficients used in the
306     ! piecewise polynomial representation.
307     !
308     do i = 1, cs%np - 1
309     dx = x(i+1) - x(i)
310     divdif1 = ( cs%c(1,i+1) - cs%c(1,i) ) / dx
311     divdif3 = cs%c(2,i) + cs%c(2,i+1) - 2.0_DP * divdif1
312     cs%c(3,i) = ( divdif1 - cs%c(2,i) - divdif3 ) / dx
313     cs%c(4,i) = divdif3 / ( dx * dx )
314     end do
315    
316 gezelter 2709 cs%c(3,cs%np) = 0.0_DP
317     cs%c(4,cs%np) = 0.0_DP
318 gezelter 2708
319     cs%dx = dx
320 gezelter 2709 cs%dx_i = 1.0_DP / dx
321 gezelter 2708
322     return
323 gezelter 2709 end subroutine newSplineWithDerivs
324 gezelter 2708
325     subroutine deleteSpline(this)
326    
327     type(cubicSpline) :: this
328    
329     if(associated(this%x)) then
330     deallocate(this%x)
331     this%x => null()
332     end if
333     if(associated(this%c)) then
334     deallocate(this%c)
335     this%c => null()
336     end if
337    
338     this%np = 0
339    
340     end subroutine deleteSpline
341    
342     subroutine lookup_nonuniform_spline(cs, xval, yval)
343    
344     !*************************************************************************
345     !
346     ! lookup_nonuniform_spline evaluates a piecewise cubic Hermite interpolant.
347     !
348     ! Discussion:
349     !
350     ! newSpline must be called first, to set up the
351     ! spline data from the raw function and derivative data.
352     !
353     ! Modified:
354     !
355     ! 06 April 1999
356     !
357     ! Reference:
358     !
359     ! Conte and de Boor,
360     ! Algorithm PCUBIC,
361     ! Elementary Numerical Analysis,
362     ! 1973, page 234.
363     !
364     ! Parameters:
365     !
366     implicit none
367    
368     type (cubicSpline), intent(in) :: cs
369     real( kind = DP ), intent(in) :: xval
370     real( kind = DP ), intent(out) :: yval
371 gezelter 2709 real( kind = DP ) :: dx
372 gezelter 2708 integer :: i, j
373     !
374     ! Find the interval J = [ cs%x(J), cs%x(J+1) ] that contains
375     ! or is nearest to xval.
376     !
377     j = cs%np - 1
378    
379     do i = 1, cs%np - 2
380    
381     if ( xval < cs%x(i+1) ) then
382     j = i
383     exit
384     end if
385    
386     end do
387     !
388     ! Evaluate the cubic polynomial.
389     !
390     dx = xval - cs%x(j)
391    
392     yval = cs%c(1,j) + dx * ( cs%c(2,j) + dx * ( cs%c(3,j) + dx * cs%c(4,j) ) )
393    
394     return
395     end subroutine lookup_nonuniform_spline
396    
397     subroutine lookup_uniform_spline(cs, xval, yval)
398    
399     !*************************************************************************
400     !
401     ! lookup_uniform_spline evaluates a piecewise cubic Hermite interpolant.
402     !
403     ! Discussion:
404     !
405     ! newSpline must be called first, to set up the
406     ! spline data from the raw function and derivative data.
407     !
408     ! Modified:
409     !
410     ! 06 April 1999
411     !
412     ! Reference:
413     !
414     ! Conte and de Boor,
415     ! Algorithm PCUBIC,
416     ! Elementary Numerical Analysis,
417     ! 1973, page 234.
418     !
419     ! Parameters:
420     !
421     implicit none
422    
423     type (cubicSpline), intent(in) :: cs
424     real( kind = DP ), intent(in) :: xval
425     real( kind = DP ), intent(out) :: yval
426 gezelter 2709 real( kind = DP ) :: dx
427 gezelter 2708 integer :: i, j
428     !
429     ! Find the interval J = [ cs%x(J), cs%x(J+1) ] that contains
430     ! or is nearest to xval.
431    
432 gezelter 2709 j = MAX(1, MIN(cs%np, idint((xval-cs%x(1)) * cs%dx_i) + 1))
433 gezelter 2708
434     dx = xval - cs%x(j)
435    
436     yval = cs%c(1,j) + dx * ( cs%c(2,j) + dx * ( cs%c(3,j) + dx * cs%c(4,j) ) )
437    
438     return
439     end subroutine lookup_uniform_spline
440    
441     end module INTERPOLATION