• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gyrokinetics / utils / 2413445047

27 Mar 2026 12:30PM UTC coverage: 6.984% (+7.0%) from 0.0%
2413445047

push

gitlab-ci

David Dickinson
Add missing side and trans arguments

743 of 10639 relevant lines covered (6.98%)

16175.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.71
/spl.f90
1
!> FIXME : Add documentation
2
module splines
3
  use warning_helpers, only: is_not_zero, is_zero, not_exactly_equal, exactly_equal
4
  implicit none
5

6
  private
7

8
  public :: spline, new_spline, delete_spline
9
  public :: periodic_spline, new_periodic_spline, delete_periodic_spline
10
  public :: splint, dsplint, periodic_splint, periodic_dsplint
11
  public :: fitp_curv1, fitp_curvp1, fitp_curv2, fitp_curvp2
12
  public :: fitp_surf1, fitp_surf2, fitp_curvd, inter_d_cspl, inter_cspl
13

14
  interface handle_spline_error
15
     module procedure handle_spline_error_logical
16
  end interface handle_spline_error
17

18
  !> Holds data representing a non-periodic spline. Should be set up
19
  !> by calling [[new_spline]].
20
  type :: spline
21
     private
22
     !> Length of the data arrays represented by the spline
23
     integer :: n = 0
24
     !> Holds the independent and dependent values of the
25
     !> splined data in `x` and `y`. The second derivative
26
     !> is held in `y2` and calculated automatically.
27
     real, dimension (:), allocatable :: x, y, y2
28
     !> Indicates if the spline corresponding to this data is valid
29
     !> and can be used with the spline evaluation routines.
30
     logical, public :: valid = .false.
31
     !> The tension used in computing the splined data, note this
32
     !> must be the value used in the initialisation when passed
33
     !> to the spline evaluation routines.
34
     real :: tension = 1.0
35
   contains
36
     procedure :: interpolate => spline_interp
37
     procedure :: derivative => spline_deriv
38
     procedure :: integrate => spline_integrate
39
  end type spline
40

41
  !> Constructor for spline
42
  interface spline
43
     module procedure new_spline
44
  end interface spline
45

46
  !> Holds data representing a periodic spline. Should be set up by
47
  !> calling [[new_periodic_spline]].
48
  type :: periodic_spline
49
     private
50
     !> Length of the data arrays represented by the spline
51
     integer :: n = 0
52
     !> The actual size of the periodic domain
53
     real :: period = 0
54
     !> Holds the independent and dependent values of the
55
     !> splined data in `x` and `y`. The second derivative
56
     !> is held in `y2` and calculated automatically.
57
     real, dimension (:), allocatable :: x, y, y2
58
     !> Indicates if the spline corresponding to this data is valid
59
     !> and can be used with the spline evaluation routines.
60
     logical, public :: valid = .false.
61
     !> The tension used in computing the splined data, note this
62
     !> must be the value used in the initialisation when passed
63
     !> to the spline evaluation routines.
64
     real :: tension = 1.0
65
   contains
66
     procedure :: interpolate => periodic_spline_interp
67
     procedure :: derivative => periodic_spline_deriv
68
     procedure :: integrate => periodic_spline_integrate
69
  end type periodic_spline
70

71
  !> Constructor for periodic_spline
72
  interface periodic_spline
73
     module procedure new_periodic_spline
74
  end interface periodic_spline
75

76
contains
77

78
  !> Populates a spline instance `spl` representing the non-periodic
79
  !> data y(x).
80
  pure type(spline) function new_spline (x, y, tension) result(spl)
32✔
81
    use optionals, only: get_option_with_default
82
    implicit none
83
    real, dimension (:), intent (in) :: x, y
84
    real, intent(in), optional :: tension
85
    real, dimension(:), allocatable :: temp
32✔
86
    integer :: ierr
87
    spl%valid = .false.
32✔
88
    spl%tension = get_option_with_default(tension, 1.0)
32✔
89
    spl%n = size(x)
32✔
90
    allocate(spl%x, source = x) ; allocate(spl%y, source = y)
1,052,768✔
91
    allocate (spl%y2(spl%n), temp(spl%n))
32✔
92
    call fitp_curv1 (spl%n, spl%x, spl%y, 0.0, 0.0, 3, spl%y2, temp, spl%tension, ierr)
32✔
93
    spl%valid = ierr == 0
32✔
94
  end function new_spline
64✔
95

96
  !> Populates a periodic_spline instance `spl` representing the
97
  !> periodic data y(x) of length n and periodic on `period`.  Note
98
  !> that the spline library expects `period > x(n) - x(1)`, which
99
  !> means the input data shouldn't include the duplicate periodic
100
  !> point.  As a convenience the user can pass data with the
101
  !> duplicate point and set `drop_last_point = .true.` to
102
  !> automatically exclude the duplicate point.
103
  pure type(periodic_spline) function new_periodic_spline (x, y, period, &
36✔
104
       drop_last_point, tension) result(spl)
36✔
105
    use optionals, only: get_option_with_default
106
    implicit none
107
    real, dimension (:), intent (in) :: x, y
108
    real, intent (in) :: period
109
    logical, intent(in), optional :: drop_last_point
110
    real, intent(in), optional :: tension
111
    logical :: drop_point
112
    real, dimension (:), allocatable :: temp
36✔
113
    integer :: ierr
114
    spl%valid = .false.
36✔
115
    drop_point = get_option_with_default(drop_last_point, .false.)
36✔
116
    spl%tension = get_option_with_default(tension, 1.0)
36✔
117
    spl%n = size(x)
36✔
118
    if (drop_point) spl%n = spl%n - 1
36✔
119
    allocate(spl%x, source = x(:spl%n)) ; allocate(spl%y, source = y(:spl%n))
1,184,304✔
120
    allocate (spl%y2(spl%n), temp(2*spl%n))
36✔
121
    spl%period = period
36✔
122
    call fitp_curvp1 (spl%n,spl%x,spl%y,spl%period,spl%y2,temp,spl%tension,ierr)
36✔
123
    spl%valid = ierr == 0
36✔
124
  end function new_periodic_spline
72✔
125

126
  !> Reset and deallocate variables in passed spline
127
  pure subroutine delete_spline (spl)
32✔
128
    implicit none
129
    type (spline), intent (in out) :: spl
130
    spl%n = 0
32✔
131
    if (allocated(spl%x)) deallocate (spl%x,spl%y)
32✔
132
    if (allocated(spl%y2)) deallocate (spl%y2)
32✔
133
    spl%valid = .false.
32✔
134
    spl%tension = 1.0
32✔
135
  end subroutine delete_spline
32✔
136

137
  !> Reset and deallocate variables in passed periodic spline
138
  pure subroutine delete_periodic_spline (spl)
30✔
139
    implicit none
140
    type (periodic_spline), intent (in out) :: spl
141
    spl%n = 0
30✔
142
    spl%period = 0.0
30✔
143
    if (allocated(spl%x)) deallocate (spl%x,spl%y)
30✔
144
    if (allocated(spl%y2)) deallocate (spl%y2)
30✔
145
    spl%valid = .false.
30✔
146
    spl%tension = 1.0
30✔
147
  end subroutine delete_periodic_spline
30✔
148

149
  !> Bound wrapper to splint
150
  real function spline_interp(self, x)
×
151
    implicit none
152
    class (spline), intent(in) :: self
153
    real, intent(in) :: x
154
    spline_interp = splint(x, self)
×
155
  end function spline_interp
×
156

157
  !> Bound wrapper to dsplint
158
  real function spline_deriv(self, x)
×
159
    implicit none
160
    class (spline), intent(in) :: self
161
    real, intent(in) :: x
162
    spline_deriv = dsplint(x, self)
×
163
  end function spline_deriv
×
164

165
  !> Bound wrapper to splintint
166
  real function spline_integrate(self, x0, x1)
×
167
    implicit none
168
    class (spline), intent(in) :: self
169
    real, intent(in) :: x0, x1
170
    spline_integrate = splintint(x0, x1, self)
×
171
  end function spline_integrate
×
172

173
  !> FIXME : Add documentation  
174
  real function splint (x, spl)
526,344✔
175
    implicit none
176
    real, intent (in) :: x
177
    type (spline), intent (in) :: spl
178
    call handle_spline_error(spl%valid, 'splint')
526,344✔
179
    splint = fitp_curv2(x, spl%n, spl%x, spl%y, spl%y2, spl%tension)
526,344✔
180
  end function splint
526,344✔
181

182
  !> Bound wrapper to splint
183
  real function periodic_spline_interp(self, x)
×
184
    implicit none
185
    class (periodic_spline), intent(in) :: self
186
    real, intent(in) :: x
187
    periodic_spline_interp = periodic_splint(x, self)
×
188
  end function periodic_spline_interp
×
189

190
  !> Bound wrapper to dsplint
191
  real function periodic_spline_deriv(self, x)
×
192
    implicit none
193
    class (periodic_spline), intent(in) :: self
194
    real, intent(in) :: x
195
    periodic_spline_deriv = periodic_dsplint(x, self)
×
196
  end function periodic_spline_deriv
×
197

198
  !> Bound wrapper to periodic_splintint
199
  real function periodic_spline_integrate(self, x0, x1)
×
200
    implicit none
201
    class (periodic_spline), intent(in) :: self
202
    real, intent(in) :: x0, x1
203
    periodic_spline_integrate = periodic_splintint(x0, x1, self)
×
204
  end function periodic_spline_integrate
×
205

206
  !> FIXME : Add documentation
207
  real function periodic_splint (x, spl)
394,758✔
208
    implicit none
209
    real, intent (in) :: x
210
    type (periodic_spline), intent (in) :: spl
211
    call handle_spline_error(spl%valid, 'periodic_splint')
394,758✔
212
    periodic_splint = fitp_curvp2(x, spl%n, spl%x, spl%y, spl%period, spl%y2, spl%tension)
394,758✔
213
  end function periodic_splint
394,758✔
214

215
  !> FIXME : Add documentation
216
  real function dsplint (x, spl)
×
217
    implicit none
218
    real, intent (in) :: x
219
    type (spline), intent (in) :: spl
220
    call handle_spline_error(spl%valid, 'dsplint')
×
221
    dsplint = fitp_curvd(x, spl%n, spl%x, spl%y, spl%y2, spl%tension)
×
222
  end function dsplint
×
223

224
  !> FIXME : Add documentation
225
  real function periodic_dsplint (x, spl)
×
226
    implicit none
227
    real, intent (in) :: x
228
    type (periodic_spline), intent (in) :: spl
229
    call handle_spline_error(spl%valid, 'periodic_dsplint')
×
230
    periodic_dsplint = fitp_curvpd(x, spl%n, spl%x, spl%y, spl%period, spl%y2, spl%tension)
×
231
  end function periodic_dsplint
×
232

233
  !> FIXME : Add documentation
234
  real function splintint (x0, x1, spl)
×
235
    implicit none
236
    real, intent (in) :: x0, x1
237
    type (spline), intent (in) :: spl
238
    call handle_spline_error(spl%valid, 'splintint')
×
239
    splintint = fitp_curvi(x0, x1, spl%n, spl%x, spl%y, spl%y2, spl%tension)
×
240
  end function splintint
×
241

242
  !> FIXME : Add documentation
243
  real function periodic_splintint (x0, x1, spl)
×
244
    implicit none
245
    real, intent (in) :: x0, x1
246
    type (periodic_spline), intent (in) :: spl
247
    call handle_spline_error(spl%valid, 'periodic_splintint')
×
248
    periodic_splintint = fitp_curvpi(x0, x1, spl%n, spl%x, spl%y, spl%period, spl%y2, spl%tension)
×
249
  end function periodic_splintint
×
250

251
  !> If not valid abort with error noting invalid spline and which method was invoked
252
  subroutine handle_spline_error_logical(valid, routine_name)
921,102✔
253
    use mp, only: mp_abort
254
    implicit none
255
    logical, intent(in) :: valid
256
    character(len = *), intent(in) :: routine_name
257
    if (.not. valid) call mp_abort('Attempt to use invalid spline in '//routine_name, .true.)
×
258
  end subroutine handle_spline_error_logical
921,102✔
259

260
  !> FIXME : Add documentation
261
  subroutine inter_d_cspl(r,data,x,dint,ddint)
×
262
    implicit none
263
    real, dimension(:), intent(in) :: r, data
264
    real, dimension(:), intent(in) :: x
265
    real, dimension(:), intent(out) :: dint, ddint
266
    integer :: i, m
267
    type(spline) :: spl
×
268
    real, parameter :: tension = 1.0
269
    spl = new_spline(r, data, tension)
×
270
    m = size(x)
×
271
    do i = 1, m
×
272
       dint(i) = spl%interpolate(x(i))
×
273
       ddint(i)= spl%derivative(x(i))
×
274
    end do
275
  end subroutine inter_d_cspl
×
276

277
  !> FIXME : Add documentation  
278
  subroutine inter_cspl(r,data,x,dint)
×
279
    implicit none
280
    real, dimension(:), intent(in) :: r, data
281
    real, dimension(:), intent(in) :: x
282
    real, dimension(:), intent(out) :: dint
283
    integer :: i, m
284
    type(spline) :: spl
×
285
    real, parameter :: tension = 1.0
286
    spl = new_spline(r, data, tension)
×
287
    m = size(x)
×
288
    do i = 1, m
×
289
       dint(i) = spl%interpolate(x(i))
×
290
    end do
291
  end subroutine inter_cspl
×
292

293
! From inet!cs.utexas.edu!cline Tue Oct 31 17:10:31 CST 1989
294
! Received: from mojave.cs.utexas.edu by cs.utexas.edu (5.59/1.44)
295
!       id AA29509; Tue, 31 Oct 89 17:11:51 CST
296
! Posted-Date: Tue, 31 Oct 89 17:10:31 CST
297
! Message-Id: <8910312310.AA04442@mojave.cs.utexas.edu>
298
! Received: by mojave.cs.utexas.edu (14.5/1.4-Client)
299
!       id AA04442; Tue, 31 Oct 89 17:10:34 cst
300
! Date: Tue, 31 Oct 89 17:10:31 CST
301
! X-Mailer: Mail User's Shell (6.5 4/17/89)
302
! From: cline@cs.utexas.edu (Alan Cline)
303
! To: ehg@research.att.com
304
! Subject: New FITPACK Subset for netlib
305
! 
306
! 
307
! This new version of FITPACK distributed by netlib is about 20% of 
308
! the total package in terms of characters, lines of code, and num-
309
! ber of subprograms. However, these 25 subprograms represent about
310
! 95% of usages of the package.  What has been omitted are such ca-
311
! pabilities as:
312
!   1. Automatic tension determination,
313
!   2. Derivatives, arclengths, and enclosed areas for planar 
314
!      curves,
315
!   3. Three dimensional curves,
316
!   4. Special surface fitting using equispacing assumptions,
317
!   5. Surface fitting in annular, wedge, polar, toroidal, lunar,
318
!      and spherical geometries,
319
!   6. B-splines in tension generation and usage,
320
!   7. General surface fitting in three dimensional space.
321
! 
322
! (The code previously circulated in netlib is less than 10% of the
323
! total  package  and is more than a decade old.  Its usage is dis-
324
! couraged.)
325
! 
326
! Please note:  Two versions of the subroutine snhcsh are included.
327
! Both serve the same purpose:  obtaining approximations to certain
328
! hyperbolic trigonometric-like functions.  The first is less accu-
329
! rate (but more efficient) than the second.  Installers should se- 
330
! lect the one with the precision they desire.
331
! 
332
! Interested parties can obtain the entire package on disk or  tape
333
! from Pleasant  Valley Software, 8603 Altus Cove, Austin TX (USA),
334
! 78759 at a cost of $495 US. A 340 page manual  is  available  for
335
! $30  US  per  copy.  The  package  includes  examples and machine
336
! readable documentation.
337

338
  !> FIXME : Add documentation (or tidyup above)
339
  pure subroutine fitp_curv1 (n,x,y,slp1,slpn,islpsw,yp,temp,sigma,ierr)
96✔
340
    implicit none
341
    integer, intent(in) :: n, islpsw
342
    integer, intent(out) :: ierr
343
    real, dimension(n), intent(in) :: x, y
344
    real, dimension(n), intent(out) :: yp, temp
345
    real, intent(in) :: slp1,slpn,sigma
346
!
347
!                                 coded by alan kaylor cline
348
!                           from fitpack -- january 26, 1987
349
!                        a curve and surface fitting package
350
!                      a product of pleasant valley software
351
!                  8603 altus cove, austin, texas 78759, usa
352
!
353
! this subroutine determines the parameters necessary to
354
! compute an interpolatory spline under tension through
355
! a sequence of functional values. the slopes at the two
356
! ends of the curve may be specified or omitted.  for actual
357
! computation of points on the curve it is necessary to call
358
! the function curv2.
359
!
360
! on input--
361
!
362
!   n is the number of values to be interpolated (n.ge.2).
363
!
364
!   x is an array of the n increasing abscissae of the
365
!   functional values.
366
!
367
!   y is an array of the n ordinates of the values, (i. e.
368
!   y(k) is the functional value corresponding to x(k) ).
369
!
370
!   slp1 and slpn contain the desired values for the first
371
!   derivative of the curve at x(1) and x(n), respectively.
372
!   the user may omit values for either or both of these
373
!   parameters and signal this with islpsw.
374
!
375
!   islpsw contains a switch indicating which slope data
376
!   should be used and which should be estimated by this
377
!   subroutine,
378
!          = 0 if slp1 and slpn are to be used,
379
!          = 1 if slp1 is to be used but not slpn,
380
!          = 2 if slpn is to be used but not slp1,
381
!          = 3 if both slp1 and slpn are to be estimated
382
!              internally.
383
!
384
!   yp is an array of length at least n.
385
!
386
!   temp is an array of length at least n which is used for
387
!   scratch storage.
388
!
389
! and
390
!
391
!   sigma contains the tension factor. this value indicates
392
!   the curviness desired. if abs(sigma) is nearly zero
393
!   (e.g. .001) the resulting curve is approximately a
394
!   cubic spline. if abs(sigma) is large (e.g. 50.) the
395
!   resulting curve is nearly a polygonal line. if sigma
396
!   equals zero a cubic spline results.  a standard value
397
!   for sigma is approximately 1. in absolute value.
398
!
399
! on output--
400
!
401
!   yp contains the values of the second derivative of the
402
!   curve at the given nodes.
403
!
404
!   ierr contains an error flag,
405
!        = 0 for normal return,
406
!        = 1 if n is less than 2,
407
!        = 2 if x-values are not strictly increasing.
408
!
409
! and
410
!
411
!   n, x, y, slp1, slpn, islpsw and sigma are unaltered.
412
!
413
! this subroutine references package modules ceez, terms,
414
! and snhcsh.
415
!
416
!-----------------------------------------------------------
417
    integer :: i, ibak, nm1, np1
418
    real :: sdiag1, diag1, delxnm, dx1, diag, sdiag2, dx2, diag2
419
    real :: delxn, slpp1, delx1, sigmap, c3, c2, c1, slppn, delx2
420
    
421
    nm1 = n-1
32✔
422
    np1 = n+1
32✔
423
    ierr = 0
32✔
424
    if (n .le. 1) go to 8
32✔
425
    if (x(n) .le. x(1)) go to 9
32✔
426
!
427
! denormalize tension factor
428
!
429
    sigmap = abs(sigma) * (n - 1) / (x(n) - x(1))
32✔
430
!
431
! approximate end slopes
432
!
433
    if (islpsw .ge. 2) go to 1
32✔
434
    slpp1 = slp1
×
435
    go to 2
×
436
1   delx1 = x(2)-x(1)
32✔
437
    delx2 = delx1+delx1
32✔
438
    if (n .gt. 2) delx2 = x(3)-x(1)
32✔
439
    if (delx1 .le. 0. .or. delx2 .le. delx1) go to 9
32✔
440
    call fitp_ceez (delx1,delx2,sigmap,c1,c2,c3,n)
32✔
441
    slpp1 = c1*y(1)+c2*y(2)
32✔
442
    if (n .gt. 2) slpp1 = slpp1+c3*y(3)
32✔
443
2   if (islpsw .eq. 1 .or. islpsw .eq. 3) go to 3
32✔
444
    slppn = slpn
×
445
    go to 4
×
446
3   delxn = x(n)-x(nm1)
32✔
447
    delxnm = delxn+delxn
32✔
448
    if (n .gt. 2) delxnm = x(n)-x(n-2)
32✔
449
    if (delxn .le. 0. .or. delxnm .le. delxn) go to 9
32✔
450
    call fitp_ceez (-delxn,-delxnm,sigmap,c1,c2,c3,n)
32✔
451
    slppn = c1*y(n)+c2*y(nm1)
32✔
452
    if (n .gt. 2) slppn = slppn+c3*y(n-2)
32✔
453
!
454
! set up right hand side and tridiagonal system for yp and
455
! perform forward elimination
456
!
457
4   delx1 = x(2)-x(1)
32✔
458
    if (delx1 .le. 0.) go to 9
32✔
459
    dx1 = (y(2)-y(1))/delx1
32✔
460
    call fitp_terms (diag1,sdiag1,sigmap,delx1)
32✔
461
    yp(1) = (dx1-slpp1)/diag1
32✔
462
    temp(1) = sdiag1/diag1
32✔
463
    if (n .eq. 2) go to 6
32✔
464
    do i = 2,nm1
526,336✔
465
       delx2 = x(i+1)-x(i)
526,304✔
466
       if (delx2 .le. 0.) go to 9
526,304✔
467
       dx2 = (y(i+1)-y(i))/delx2
526,304✔
468
       call fitp_terms (diag2,sdiag2,sigmap,delx2)
526,304✔
469
       diag = diag1+diag2-sdiag1*temp(i-1)
526,304✔
470
       yp(i) = (dx2-dx1-sdiag1*yp(i-1))/diag
526,304✔
471
       temp(i) = sdiag2/diag
526,304✔
472
       dx1 = dx2
526,304✔
473
       diag1 = diag2
526,304✔
474
       sdiag1 = sdiag2
1,052,640✔
475
    end do
476
6   diag = diag1-sdiag1*temp(nm1)
32✔
477
    yp(n) = (slppn-dx1-sdiag1*yp(nm1))/diag
32✔
478
!
479
! perform back substitution
480
!
481
    do i = 2,n
526,368✔
482
       ibak = np1-i
526,336✔
483
       yp(ibak) = yp(ibak)-temp(ibak)*yp(ibak+1)
526,368✔
484
    end do
485
    return
32✔
486
!
487
! too few points
488
!
489
8   ierr = 1
×
490
    return
×
491
!
492
! x-values not strictly increasing
493
!
494
9   ierr = 2
×
495
    return
×
496
  end subroutine fitp_curv1
497

498
  !> FIXME : Add documentation
499
  real function fitp_curv2 (t,n,x,y,yp,sigma)
526,344✔
500
    implicit none
501
    integer, intent(in) :: n
502
    real, dimension(n), intent(in) :: x, y, yp
503
    real, intent(in) :: t, sigma
504
!
505
!                                 coded by alan kaylor cline
506
!                           from fitpack -- january 26, 1987
507
!                        a curve and surface fitting package
508
!                      a product of pleasant valley software
509
!                  8603 altus cove, austin, texas 78759, usa
510
!
511
! this function interpolates a curve at a given point
512
! using a spline under tension. the subroutine curv1 should
513
! be called earlier to determine certain necessary
514
! parameters.
515
!
516
! on input--
517
!
518
!   t contains a real value to be mapped onto the interpo-
519
!   lating curve.
520
!
521
!   n contains the number of points which were specified to
522
!   determine the curve.
523
!
524
!   x and y are arrays containing the abscissae and
525
!   ordinates, respectively, of the specified points.
526
!
527
!   yp is an array of second derivative values of the curve
528
!   at the nodes.
529
!
530
! and
531
!
532
!   sigma contains the tension factor (its sign is ignored).
533
!
534
! the parameters n, x, y, yp, and sigma should be input
535
! unaltered from the output of curv1.
536
!
537
! on output--
538
!
539
!   curv2 contains the interpolated value.
540
!
541
! none of the input parameters are altered.
542
!
543
! this function references package modules intrvl and
544
! snhcsh.
545
!
546
!-----------------------------------------------------------
547
    integer :: i, im1
548
    real :: ss, sigdel, s1, s2, sum, sigmap
549
    real :: del1, del2, dels
550
!
551
! determine interval
552
!
553
    im1 = fitp_intrvl(t,x,n)
526,344✔
554
    i = im1+1
526,344✔
555
!
556
! denormalize tension factor
557
!
558
    sigmap = abs(sigma) * (n - 1) / (x(n) - x(1))
526,344✔
559
!
560
! set up and perform interpolation
561
!
562
    del1 = t-x(im1)
526,344✔
563
    del2 = x(i)-t
526,344✔
564
    dels = x(i)-x(im1)
526,344✔
565
    sum = (y(i)*del1+y(im1)*del2)/dels
526,344✔
566
    if (is_zero(sigmap)) then
526,344✔
567
       fitp_curv2 = sum-del1*del2*(yp(i)*(del1+dels)+yp(im1)*(del2+dels))/(6.*dels)
×
568
    else
569
       sigdel = sigmap*dels
526,344✔
570
       ss = sinhm_fun(sigdel)
526,344✔
571
       s1 = sinhm_fun(sigmap * del1)
526,344✔
572
       s2 = sinhm_fun(sigmap * del2)
526,344✔
573
       fitp_curv2 = sum+(yp(i)*del1*(s1-ss)+yp(im1)*del2*(s2-ss))/(sigdel*sigmap*(1.+ss))
526,344✔
574
    end if
575
  end function fitp_curv2
526,344✔
576

577
  !> FIXME : Add documentation  
578
  real function fitp_curvd (t,n,x,y,yp,sigma)
×
579
    implicit none
580
    integer, intent(in) :: n
581
    real, dimension(n), intent(in) :: x, y, yp
582
    real, intent(in) :: t, sigma
583
!
584
!                                 coded by alan kaylor cline
585
!                           from fitpack -- january 26, 1987
586
!                        a curve and surface fitting package
587
!                      a product of pleasant valley software
588
!                  8603 altus cove, austin, texas 78759, usa
589
!
590
! this function differentiates a curve at a given point
591
! using a spline under tension. the subroutine curv1 should
592
! be called earlier to determine certain necessary
593
! parameters.
594
!
595
! on input--
596
!
597
!   t contains a real value at which the derivative is to be
598
!   determined.
599
!
600
!   n contains the number of points which were specified to
601
!   determine the curve.
602
!
603
!   x and y are arrays containing the abscissae and
604
!   ordinates, respectively, of the specified points.
605
!
606
!   yp is an array of second derivative values of the curve
607
!   at the nodes.
608
!
609
! and
610
!
611
!   sigma contains the tension factor (its sign is ignored).
612
!
613
! the parameters n, x, y, yp, and sigma should be input
614
! unaltered from the output of curv1.
615
!
616
! on output--
617
!
618
!   curvd contains the derivative value.
619
!
620
! none of the input parameters are altered.
621
!
622
! this function references package modules intrvl and
623
! snhcsh.
624
!
625
!-----------------------------------------------------------
626
    integer :: i, im1
627
    real :: ss, sigdel, c1, c2, sum, sigmap
628
    real :: del1, del2, dels
629
!
630
! determine interval
631
!
632
    im1 = fitp_intrvl(t,x,n)
×
633
    i = im1+1
×
634
!
635
! denormalize tension factor
636
!
637
    sigmap = abs(sigma) * (n - 1) / (x(n) - x(1))
×
638
!
639
! set up and perform differentiation
640
!
641
    del1 = t-x(im1)
×
642
    del2 = x(i)-t
×
643
    dels = x(i)-x(im1)
×
644
    sum = (y(i)-y(im1))/dels
×
645
    if (is_zero(sigmap)) then
×
646
       fitp_curvd = sum+(yp(i)*(2.*del1*del1-del2*(del1+dels))- &
×
647
            yp(im1)*(2.*del2*del2-del1*(del2+dels))) &
×
648
            /(6.*dels)
×
649
    else
650
       sigdel = sigmap*dels
×
651
       ss = sinhm_fun(sigdel)
×
652
       c1 = coshm_fun(sigmap * del1)
×
653
       c2 = coshm_fun(sigmap * del2)
×
654
       fitp_curvd = sum+(yp(i)*(c1-ss)-yp(im1)*(c2-ss))/(sigdel*sigmap*(1.+ss))
×
655
    end if
656
  end function fitp_curvd
×
657

658
  !> FIXME : Add documentation  
659
  real function fitp_curvi (xl,xu,n,x,y,yp,sigma)
×
660
    implicit none
661
    integer, intent(in) :: n
662
    real, intent(in) :: xl, xu, sigma
663
    real, dimension(n), intent(in) :: x, y, yp
664
!
665
!                                 coded by alan kaylor cline
666
!                           from fitpack -- january 26, 1987
667
!                        a curve and surface fitting package
668
!                      a product of pleasant valley software
669
!                  8603 altus cove, austin, texas 78759, usa
670
!
671
! this function integrates a curve specified by a spline
672
! under tension between two given limits. the subroutine
673
! curv1 should be called earlier to determine necessary
674
! parameters.
675
!
676
! on input--
677
!
678
!   xl and xu contain the upper and lower limits of inte-
679
!   gration, respectively. (sl need not be less than or
680
!   equal to xu, curvi (xl,xu,...) .eq. -curvi (xu,xl,...) ).
681
!
682
!   n contains the number of points which were specified to
683
!   determine the curve.
684
!
685
!   x and y are arrays containing the abscissae and
686
!   ordinates, respectively, of the specified points.
687
!
688
!   yp is an array from subroutine curv1 containing
689
!   the values of the second derivatives at the nodes.
690
!
691
! and
692
!
693
!   sigma contains the tension factor (its sign is ignored).
694
!
695
! the parameters n, x, y, yp, and sigma should be input
696
! unaltered from the output of curv1.
697
!
698
! on output--
699
!
700
!   curvi contains the integral value.
701
!
702
! none of the input parameters are altered.
703
!
704
! this function references package modules intrvl and
705
! snhcsh.
706
!
707
!-----------------------------------------------------------
708
    integer :: i, ilp1, ilm1, il, ium1, iu
709
    real :: delu1, delu2, c2, ss, cs, cu2, cl1, cl2, cu1
710
    real :: dell1, dell2, deli, c1, ssign, sigmap
711
    real :: xxl, xxu, t1, t2, dels, sum, del1, del2
712

713
    ! denormalize tension factor
714
    sigmap = abs(sigma) * (n - 1) / (x(n) - x(1))
×
715

716
    ! determine actual upper and lower bounds
717
    if (xl < xu) then
×
718
       xxl = xl
×
719
       xxu = xu
×
720
       ssign = 1.
×
721
    else if (xl > xu) then
×
722
       xxl = xu
×
723
       xxu = xl
×
724
       ssign = -1.
×
725
    else
726
       ! return zero if xl .eq. xu
727
       fitp_curvi = 0.
×
728
       return
×
729
    end if
730

731
    ! search for proper intervals
732
    ilm1 = fitp_intrvl (xxl,x,n)
×
733
    il = ilm1+1
×
734
    ium1 = fitp_intrvl (xxu,x,n)
×
735
    iu = ium1+1
×
736
    if (il == iu) then
×
737
       ! integrate from xxl to xxu
738
       delu1 = xxu-x(ium1)
×
739
       delu2 = x(iu)-xxu
×
740
       dell1 = xxl-x(ium1)
×
741
       dell2 = x(iu)-xxl
×
742
       dels = x(iu)-x(ium1)
×
743
       deli = xxu-xxl
×
744
       t1 = (delu1+dell1)*deli/(2.*dels)
×
745
       t2 = (delu2+dell2)*deli/(2.*dels)
×
746
       sum = t1*y(iu)+t2*y(ium1)
×
747
       if (is_not_zero(sigma)) then
×
748
          cu1 = coshmm_fun(sigmap*delu1)
×
749
          cu2 = coshmm_fun(sigmap*delu2)
×
750
          cl1 = coshmm_fun(sigmap*dell1)
×
751
          cl2 = coshmm_fun(sigmap*dell2)
×
752
          ss = sinhm_fun(sigmap*dels)
×
753

754
          sum = sum+(yp(iu)*(delu1*delu1*(cu1-ss/2.) &
×
755
               -dell1*dell1*(cl1-ss/2.)) &
756
               +yp(ium1)*(dell2*dell2*(cl2-ss/2.) &
×
757
               -delu2*delu2*(cu2-ss/2.)))/ &
758
               (sigmap*sigmap*dels*(1.+ss))
×
759
       else
760
          sum = sum-t1*(delu2*(dels+delu1)+dell2*(dels+dell1))* &
761
               yp(iu)/12. &
×
762
               -t2*(dell1*(dels+dell2)+delu1*(dels+delu2))* &
763
               yp(ium1)/12.
×
764
       end if
765
    else
766
       ! integrate from xxl to x(il)
767
       sum = 0.
×
768
       if (not_exactly_equal(xxl, x(il))) then
×
769
          del1 = xxl-x(ilm1)
×
770
          del2 = x(il)-xxl
×
771
          dels = x(il)-x(ilm1)
×
772
          t1 = (del1+dels)*del2/(2.*dels)
×
773
          t2 = del2*del2/(2.*dels)
×
774
          sum = t1*y(il)+t2*y(ilm1)
×
775
          if (is_not_zero(sigma)) then
×
776
             c1 = coshmm_fun(sigmap*del1)
×
777
             c2 = coshmm_fun(sigmap*del2)
×
778
             cs = coshmm_fun(sigmap*dels)
×
779
             ss = sinhm_fun(sigmap*dels)
×
780
             sum = sum+((dels*dels*(cs-ss/2.)-del1*del1*(c1-ss/2.)) &
781
                  *yp(il)+del2*del2*(c2-ss/2.)*yp(ilm1))/ &
×
782
                  (sigmap*sigmap*dels*(1.+ss))
×
783
          else
784
             sum = sum-t1*t1*dels*yp(il)/6. &
×
785
                  -t2*(del1*(del2+dels)+dels*dels)*yp(ilm1)/12.
×
786
          end if
787
       end if
788

789
       ! integrate over interior intervals
790
       if (iu-il /= 1) then
×
791
          ilp1 = il+1
×
792
          do i = ilp1,ium1
×
793
             dels = x(i)-x(i-1)
×
794
             sum = sum+(y(i)+y(i-1))*dels/2.
×
795
             if (is_not_zero(sigma)) then
×
796
                cs = coshmm_fun(sigmap*dels)
×
797
                ss = sinhm_fun(sigmap*dels)
×
798
                sum = sum+(yp(i)+yp(i-1))*dels*(cs-ss/2.)/(sigmap*sigmap*(1.+ss))
×
799
             else
800
                sum = sum-(yp(i)+yp(i-1))*dels*dels*dels/24.
×
801
             end if
802
          end do
803
       end if
804

805
       ! integrate from x(iu-1) to xxu
806
       if (not_exactly_equal(xxu, x(ium1))) then
×
807
          del1 = xxu-x(ium1)
×
808
          del2 = x(iu)-xxu
×
809
          dels = x(iu)-x(ium1)
×
810
          t1 = del1*del1/(2.*dels)
×
811
          t2 = (del2+dels)*del1/(2.*dels)
×
812
          sum = sum+t1*y(iu)+t2*y(ium1)
×
813
          if (is_not_zero(sigma)) then
×
814
             c1 = coshmm_fun(sigmap*del1)
×
815
             c2 = coshmm_fun(sigmap*del2)
×
816
             cs = coshmm_fun(sigmap*dels)
×
817
             ss = sinhm_fun(sigmap*dels)
×
818
             sum = sum+(yp(iu)*del1*del1*(c1-ss/2.)+yp(ium1)* &
×
819
                  (dels*dels*(cs-ss/2.)-del2*del2*(c2-ss/2.))) &
820
                  /(sigmap*sigmap*dels*(1.+ss))
×
821
          else
822
             sum = sum-t1*(del2*(del1+dels)+dels*dels)*yp(iu)/12.-t2*t2*dels*yp(ium1)/6.
×
823
          end if
824
       end if
825
    end if
826

827
    ! correct sign and return
828
    fitp_curvi = ssign*sum
×
829
  end function fitp_curvi
×
830

831
  !> FIXME : Add documentation
832
  pure subroutine fitp_curvp1 (n,x,y,p,yp,temp,sigma,ierr)
36✔
833
    implicit none
834
    integer, intent(in) :: n
835
    integer, intent(out) :: ierr
836
    real, intent(in) :: sigma, p
837
    real, dimension(:), intent(in) :: x, y
838
    real, dimension(:), intent(out) :: yp, temp
839
!
840
!                                 coded by alan kaylor cline
841
!                           from fitpack -- january 26, 1987
842
!                        a curve and surface fitting package
843
!                      a product of pleasant valley software
844
!                  8603 altus cove, austin, texas 78759, usa
845
!
846
! this subroutine determines the parameters necessary to
847
! compute a periodic interpolatory spline under tension
848
! through a sequence of functional values. for actual ends
849
! of the curve may be specified or omitted.  for actual
850
! computation of points on the curve it is necessary to call
851
! the function curvp2.
852
!
853
! on input--
854
!
855
!   n is the number of values to be interpolated (n.ge.2).
856
!
857
!   x is an array of the n increasing abscissae of the
858
!   functional values.
859
!
860
!   y is an array of the n ordinates of the values, (i. e.
861
!   y(k) is the functional value corresponding to x(k) ).
862
!
863
!   p is the period (p .gt. x(n)-x(1)).
864
!
865
!   yp is an array of length at least n.
866
!
867
!   temp is an array of length at least 2*n which is used
868
!   for scratch storage.
869
!
870
! and
871
!
872
!   sigma contains the tension factor.  this value indicates
873
!   the curviness desired. if abs(sigma) is nearly zero
874
!   (e.g. .001) the resulting curve is approximately a
875
!   cubic spline. if abs(sigma) is large (e.g. 50.) the
876
!   resulting curve is nearly a polygonal line. if sigma
877
!   equals zero a cubic spline results.  a standard value
878
!   for sigma is approximately 1. in absolute value.
879
!
880
! on output--
881
!
882
!   yp contains the values of the second derivative of the
883
!   curve at the given nodes.
884
!
885
!   ierr contains an error flag,
886
!        = 0 for normal return,
887
!        = 1 if n is less than 2,
888
!        = 2 if p is less than or equal to x(n)-x(1),
889
!        = 3 if x-values are not strictly increasing.
890
!
891
! and
892
!
893
!  n, x, y, and sigma are unaltered.
894
!
895
! this subroutine references package modules terms and
896
! snhcsh.
897
!
898
!-----------------------------------------------------------
899
    integer :: i, npibak, npi, ibak, nm1, np1
900
    real :: diag, diag2, sdiag2, ypn, dx2, sigmap, delx1
901
    real :: sdiag1, delx2, dx1, diag1
902

903
    nm1 = n-1
36✔
904
    np1 = n+1
36✔
905
    ierr = 0
36✔
906
    if (n .le. 1) go to 6
36✔
907
    if (p .le. x(n)-x(1) .or. p .le. 0.) go to 7
36✔
908
!
909
! denormalize tension factor
910
!
911
    sigmap = abs(sigma) * n / p
30✔
912
!
913
! set up right hand side and tridiagonal system for yp and
914
! perform forward elimination
915
!
916
    delx1 = p-(x(n)-x(1))
30✔
917
    dx1 = (y(1)-y(n))/delx1
30✔
918
    call fitp_terms (diag1,sdiag1,sigmap,delx1)
30✔
919
    delx2 = x(2)-x(1)
30✔
920
    if (delx2 .le. 0.) go to 8
30✔
921
    dx2 = (y(2)-y(1))/delx2
30✔
922
    call fitp_terms (diag2,sdiag2,sigmap,delx2)
30✔
923
    diag = diag1+diag2
30✔
924
    yp(1) = (dx2-dx1)/diag
30✔
925
    temp(np1) = -sdiag1/diag
30✔
926
    temp(1) = sdiag2/diag
30✔
927
    dx1 = dx2
30✔
928
    diag1 = diag2
30✔
929
    sdiag1 = sdiag2
30✔
930
    if (n .eq. 2) go to 2
30✔
931
    do i = 2,nm1
493,410✔
932
       npi = n+i
493,380✔
933
       delx2 = x(i+1)-x(i)
493,380✔
934
       if (delx2 .le. 0.) go to 8
493,380✔
935
       dx2 = (y(i+1)-y(i))/delx2
493,380✔
936
       call fitp_terms (diag2,sdiag2,sigmap,delx2)
493,380✔
937
       diag = diag1+diag2-sdiag1*temp(i-1)
493,380✔
938
       yp(i) = (dx2-dx1-sdiag1*yp(i-1))/diag
493,380✔
939
       temp(npi) = -temp(npi-1)*sdiag1/diag
493,380✔
940
       temp(i) = sdiag2/diag
493,380✔
941
       dx1 = dx2
493,380✔
942
       diag1 = diag2
493,380✔
943
       sdiag1 = sdiag2
986,790✔
944
    end do
945
2   delx2 = p-(x(n)-x(1))
30✔
946
    dx2 = (y(1)-y(n))/delx2
30✔
947
    call fitp_terms (diag2,sdiag2,sigmap,delx2)
30✔
948
    yp(n) = dx2-dx1
30✔
949
    temp(nm1) = temp(2*n-1)-temp(nm1)
30✔
950
    if (n .eq. 2) go to 4
30✔
951
!
952
! perform first step of back substitution
953
    !
954
    do i = 3,n
493,410✔
955
       ibak = np1-i
493,380✔
956
       npibak =n+ibak
493,380✔
957
       yp(ibak) = yp(ibak)-temp(ibak)*yp(ibak+1)
493,380✔
958
       temp(ibak) =temp(npibak)-temp(ibak)*temp(ibak+1)
493,410✔
959
    end do
960
4   yp(n) = (yp(n)-sdiag2*yp(1)-sdiag1*yp(nm1))/ &
90✔
961
         (diag1+diag2+sdiag2*temp(1)+sdiag1*temp(nm1))
90✔
962
!
963
! perform second step of back substitution
964
!
965
    ypn =   yp(n)
30✔
966
    do i = 1,nm1
493,440✔
967
       yp(i) = yp(i)+temp(i)*ypn
493,440✔
968
    end do
969
    return
30✔
970
!
971
! too few points
972
!
973
6   ierr = 1
×
974
    return
×
975
!
976
! period too small
977
!
978
7   ierr = 2
6✔
979
    return
6✔
980
!
981
! x-values not strictly increasing
982
!
983
8   ierr = 3
×
984
    return
×
985
  end subroutine fitp_curvp1
986

987
  !> FIXME : Add documentation  
988
  real function fitp_curvp2 (t,n,x,y,p,yp,sigma)
394,758✔
989
    implicit none
990
    real, intent(in) :: t, p, sigma
991
    integer, intent(in) :: n
992
    real, dimension(:), intent(in) :: x, y, yp
993
!
994
!                                 coded by alan kaylor cline
995
!                           from fitpack -- january 26, 1987
996
!                        a curve and surface fitting package
997
!                      a product of pleasant valley software
998
!                  8603 altus cove, austin, texas 78759, usa
999
!
1000
! this function interpolates a curve at a given point using
1001
! a periodic spline under tension. the subroutine curvp1
1002
! should be called earlier to determine certain necessary
1003
! parameters.
1004
!
1005
! on input--
1006
!
1007
!   t contains a real value to be mapped onto the interpo-
1008
!   lating curve.
1009
!
1010
!   n contains the number of points which were specified to
1011
!   determine the curve.
1012
!
1013
!   x and y are arrays containing the abscissae and
1014
!   ordinates, respectively, of the specified points.
1015
!
1016
!   p contains the period.
1017
!
1018
!   yp is an array of second derivative values of the curve
1019
!   at the nodes.
1020
!
1021
! and
1022
!
1023
!   sigma contains the tension factor (its sign is ignored).
1024
!
1025
! the parameters n, x, y, p, yp, and sigma should be input
1026
! unaltered from the output of curvp1.
1027
!
1028
! on output--
1029
!
1030
!   curvp2 contains the interpolated value.
1031
!
1032
! none of the input parameters are altered.
1033
!
1034
! this function references package modules intrvp and
1035
! snhcsh.
1036
!
1037
!-----------------------------------------------------------
1038
    integer :: i, im1
1039
    real :: ss, sigdel, sum, s2, s1
1040
    real :: tp, sigmap, dels, del2, del1
1041

1042
!
1043
! determine interval
1044
!
1045
    tp = fitp_periodic_wrap_value(t, x(1), p)
394,758✔
1046
    im1 = fitp_intrvp (tp, x, n)
394,758✔
1047
    i = im1+1
394,758✔
1048
!
1049
! denormalize tension factor
1050
!
1051
    sigmap = abs(sigma) * n / p
394,758✔
1052
!
1053
! set up and perform interpolation
1054
!
1055
    del1 = tp-x(im1)
394,758✔
1056
    if (im1 == n) then
394,758✔
1057
       i = 1
18✔
1058
       del2 = x(1)+p-tp
18✔
1059
       dels = p-(x(n)-x(1))
18✔
1060
    else
1061
       del2 = x(i)-tp
394,740✔
1062
       dels = x(i)-x(im1)
394,740✔
1063
    end if
1064
    sum = (y(i)*del1+y(im1)*del2)/dels
394,758✔
1065
    if (is_zero(sigmap)) then
394,758✔
1066
       fitp_curvp2 = sum-del1*del2*(yp(i)*(del1+dels)+yp(im1)*(del2+dels))/(6.*dels)
×
1067
    else
1068
       sigdel = sigmap*dels
394,758✔
1069
       ss = sinhm_fun(sigdel)
394,758✔
1070
       s1 = sinhm_fun(sigmap * del1)
394,758✔
1071
       s2 = sinhm_fun(sigmap * del2)
394,758✔
1072
       fitp_curvp2 = sum+(yp(i)*del1*(s1-ss)+yp(im1)*del2*(s2-ss))/(sigdel*sigmap*(1.+ss))
394,758✔
1073
    end if
1074
  end function fitp_curvp2
394,758✔
1075

1076
  !> FIXME : Add documentation  
1077
  real function fitp_curvpd (t,n,x,y,p,yp,sigma)
×
1078
    real, intent(in) :: t, p, sigma
1079
    integer, intent(in) :: n
1080
    real, dimension(:), intent(in) :: x, y, yp
1081
!
1082
!                                 coded by alan kaylor cline
1083
!                           from fitpack -- january 26, 1987
1084
!                        a curve and surface fitting package
1085
!                      a product of pleasant valley software
1086
!                  8603 altus cove, austin, texas 78759, usa
1087
!
1088
! this function is the derivative of curvp2
1089
! interpolates a curve at a given point using
1090
! a periodic spline under tension. the subroutine curvp1
1091
! should be called earlier to determine certain necessary
1092
! parameters.
1093
!
1094
! on input--
1095
!
1096
!   t contains a real value to be mapped onto the interpo-
1097
!   lating curve.
1098
!
1099
!   n contains the number of points which were specified to
1100
!   determine the curve.
1101
!
1102
!   x and y are arrays containing the abscissae and
1103
!   ordinates, respectively, of the specified points.
1104
!
1105
!   p contains the period.
1106
!
1107
!   yp is an array of second derivative values of the curve
1108
!   at the nodes.
1109
!
1110
! and
1111
!
1112
!   sigma contains the tension factor (its sign is ignored).
1113
!
1114
! the parameters n, x, y, p, yp, and sigma should be input
1115
! unaltered from the output of curvp1.
1116
!
1117
! on output--
1118
!
1119
!   curvpd contains the interpolated derivative
1120
!
1121
! none of the input parameters are altered.
1122
!
1123
! this function references package modules intrvp and
1124
! snhcsh.
1125
!
1126
!-----------------------------------------------------------
1127
    integer :: i, im1
1128
    real :: ss, sigdel, sum, c2, c1
1129
    real :: tp, sigmap, dels, del2, del1
1130
!
1131
! determine interval
1132
!
1133
    tp = fitp_periodic_wrap_value(t, x(1), p)
×
1134
    im1 = fitp_intrvp (tp, x, n)
×
1135
    i = im1+1
×
1136
!
1137
! denormalize tension factor
1138
!
1139
    sigmap = abs(sigma) * n / p
×
1140
!
1141
! set up and perform interpolation
1142
!
1143
    del1 = tp-x(im1)
×
1144
    if (im1 .eq. n) then
×
1145
       i = 1
×
1146
       del2 = x(1)+p-tp
×
1147
       dels = p-(x(n)-x(1))
×
1148
    else
1149
       del2 = x(i)-tp
×
1150
       dels = x(i)-x(im1)
×
1151
    end if
1152
    ! Here on identical to fitp_curvd
1153
    sum = (y(i)-y(im1))/dels
×
1154
    if (is_zero(sigmap)) then
×
1155
       fitp_curvpd = sum+(yp(i)*(2.*del1*del1-del2*(del1+dels))- &
×
1156
            yp(im1)*(2.*del2*del2-del1*(del2+dels))) &
×
1157
            /(6.*dels)
×
1158
    else
1159
       sigdel = sigmap*dels
×
1160
       ss = sinhm_fun(sigdel)
×
1161
       c1 = coshm_fun(sigmap * del1)
×
1162
       c2 = coshm_fun(sigmap * del2)
×
1163
       fitp_curvpd = sum+(yp(i)*(c1-ss)-yp(im1)*(c2-ss))/(sigdel*sigmap*(1.+ss))
×
1164
    end if
1165
  end function fitp_curvpd
×
1166

1167
  !> FIXME : Add documentation
1168
  real function fitp_curvpi (xl,xu,n,x,y,p,yp,sigma)
×
1169
    implicit none
1170
    integer, intent(in) :: n
1171
    real, intent(in) :: xl, xu, p, sigma
1172
    real, dimension(n), intent(in) :: x, y, yp
1173
!
1174
!                                 coded by alan kaylor cline
1175
!                           from fitpack -- january 26, 1987
1176
!                        a curve and surface fitting package
1177
!                      a product of pleasant valley software
1178
!                  8603 altus cove, austin, texas 78759, usa
1179
!
1180
! this function integrates a curve specified by a periodic
1181
! spline under tension between two given limits. the
1182
! subroutine curvp1 should be called earlier to determine
1183
! necessary parameters.
1184
!
1185
! on input--
1186
!
1187
!   xl and xu contain the upper and lower limits of inte-
1188
!   gration, respectively. (sl need not be less than or
1189
!   equal to xu, curvpi (xl,xu,...) .eq. -curvpi (xu,xl,...) ).
1190
!
1191
!   n contains the number of points which were specified to
1192
!   determine the curve.
1193
!
1194
!   x and y are arrays containing the abscissae and
1195
!   ordinates, respectively, of the specified points.
1196
!
1197
!   p contains the period.
1198
!
1199
!   yp is an array from subroutine curvp1 containing
1200
!   the values of the second derivatives at the nodes.
1201
!
1202
! and
1203
!
1204
!   sigma contains the tension factor (its sign is ignored).
1205
!
1206
! the parameters n, x, y, p, yp, and sigma should be input
1207
! unaltered from the output of curvp1.
1208
!
1209
! on output--
1210
!
1211
!
1212
!   curvpi contains the integral value.
1213
!
1214
! none of the input parameters are altered.
1215
!
1216
! this function references package modules intrvp and
1217
! snhcsh.
1218
!
1219
!--------------------------------------------------------------
1220
    integer :: np1, im1, ii, iup1, ilp1, ideltp
1221
    real :: s7, s6, s3, c2, c1, s5, s4, cl1, cu2, cu1, si, so
1222
    real :: cl2, delu2, delu1, s8, deli, dell2, dell1
1223
    integer :: ium1, il, isave, isign, lper, ilm1, iu, i
1224
    real :: xxu, xsave, x1pp, sigmap, xxl, xil, del1, s2, cs
1225
    real :: t2, t1, del2, s1, xiu, ss, dels
1226

1227
    integer :: uper
1228
    logical :: bdy
1229
!
1230
! denormalize tension factor
1231
!
1232
    sigmap = abs(sigma) * n / p
×
1233
!
1234
! determine actual upper and lower bounds
1235
!
1236
    x1pp = x(1)+p
×
1237
    isign = 1
×
1238
    xxl = fitp_periodic_wrap_value(xl, x(1), p)
×
1239
    ilm1 = fitp_intrvp (xxl, x, n)
×
1240
    lper = int((xl-x(1))/p)
×
1241
    if (xl .lt. x(1)) lper = lper-1
×
1242
    xxu = fitp_periodic_wrap_value(xu, x(1), p)
×
1243
    ium1 = fitp_intrvp (xxu, x, n)
×
1244
    uper = int((xu-x(1))/p)
×
1245
    if (xu .lt. x(1)) uper = uper-1
×
1246
    ideltp = uper-lper
×
1247
    bdy = ideltp * (xxu-xxl) .lt. 0.
×
1248
    if ((ideltp .eq. 0 .and. xxu .lt. xxl) .or. ideltp .lt. 0) isign = -1
×
1249
    if (bdy) ideltp = ideltp-isign
×
1250
    if (xxu .ge. xxl) go to 1
×
1251
    xsave = xxl
×
1252
    xxl = xxu
×
1253
    xxu = xsave
×
1254
    isave = ilm1
×
1255
    ilm1 = ium1
×
1256
    ium1 = isave
×
1257
1   il = ilm1+1
×
1258
    if (ilm1 .eq. n) il = 1
×
1259
    xil = x(il)
×
1260
    if (ilm1 .eq. n) xil = x1pp
×
1261
    iu = ium1+1
×
1262
    if (ium1 .eq. n) iu = 1
×
1263
    xiu = x(iu)
×
1264
    if (ium1 .eq. n) xiu = x1pp
×
1265
    s1 = 0.
×
1266
    if (ilm1 .eq. 1 .or. (ideltp .eq. 0 .and..not. bdy)) go to 4
×
1267
!
1268
! integrate from x(1) to x(ilm1), store in s1
1269
!
1270
    do i = 2,ilm1
×
1271
       dels = x(i)-x(i-1)
×
1272
       s1 = s1+(y(i)+y(i-1))*dels/2.
×
1273
       if (is_not_zero(sigma)) then
×
1274
          ss = sinhm_fun(sigmap * dels)
×
1275
          cs = coshmm_fun(sigmap * dels)
×
1276
          s1 = s1+(yp(i)+yp(i-1))*dels*(cs-ss/2.)/(sigmap*sigmap*(1.+ss))
×
1277
       else
1278
          s1 = s1-(yp(i)+yp(i-1))*dels*dels*dels/24.
×
1279
       end if
1280
    end do
1281
4   s2 = 0.
×
1282
    if (x(ilm1) .ge. xxl .or. (ideltp .eq. 0 .and. .not. bdy)) go to 6
×
1283
!
1284
! integrate from x(ilm1) to xxl, store in s2
1285
!
1286
    del1 = xxl-x(ilm1)
×
1287
    del2 = xil-xxl
×
1288
    dels = xil-x(ilm1)
×
1289
    t1 = del1*del1/(2.*dels)
×
1290
    t2 = (del2+dels)*del1/(2.*dels)
×
1291
    s2 = t1*y(il)+t2*y(ilm1)
×
1292
    if (is_not_zero(sigma)) then
×
1293
       c1 = coshmm_fun(sigmap * del1)
×
1294
       c2 = coshmm_fun(sigmap * del2)
×
1295
       ss = sinhm_fun(sigmap * dels)
×
1296
       cs = coshmm_fun(sigmap * dels)
×
1297
       s2 = s2+(yp(il)*del1*del1*(c1-ss/2.)+yp(ilm1)* &
×
1298
            (dels*dels*(cs-ss/2.)-del2*del2*(c2-ss/2.))) &
1299
            /(sigmap*sigmap*dels*(1.+ss))
×
1300
    else
1301
       s2 = s2-t1*(del2*(del1+dels) &
1302
            +dels*dels)*yp(il)/12. &
×
1303
            -t2*t2*dels*yp(ilm1)/6.
×
1304
    end if
1305

1306
6   s3 = 0.
×
1307
    if (xxl .ge. xil .or. (ideltp .eq. 0 .and. bdy).or. ilm1 .eq. ium1) go to 8
×
1308

1309

1310
!
1311
! integrate from xxl to xil, store in s3
1312
!
1313
    del1 = xxl-x(ilm1)
×
1314
    del2 = xil-xxl
×
1315
    dels = xil-x(ilm1)
×
1316
    t1 = (del1+dels)*del2/(2.*dels)
×
1317
    t2 = del2*del2/(2.*dels)
×
1318
    s3 = t1*y(il)+t2*y(ilm1)
×
1319
    if (is_not_zero(sigma)) then
×
1320
       c1 = coshmm_fun(sigmap * del1)
×
1321
       c2 = coshmm_fun(sigmap * del2)
×
1322
       ss = sinhm_fun(sigmap * dels)
×
1323
       cs = coshmm_fun(sigmap * dels)
×
1324
       s3 = s3+((dels*dels*(cs-ss/2.)-del1*del1*(c1-ss/2.)) &
1325
            *yp(il)+del2*del2*(c2-ss/2.)*yp(ilm1))/ &
×
1326
            (sigmap*sigmap*dels*(1.+ss))
×
1327
    else
1328
       s3 = s3-t1*t1*dels*yp(il)/6. &
×
1329
            -t2*(del1*(del2+dels)+dels*dels)* &
1330
            yp(ilm1)/12.
×
1331
    end if
1332
8   s4 = 0.
×
1333
    if (ilm1 .ge. ium1-1 .or. (ideltp .eq. 0 .and. bdy)) go to 11
×
1334
!
1335
! integrate from xil to x(ium1), store in s4
1336
!
1337
    ilp1 = il+1
×
1338
    do i = ilp1,ium1
×
1339
       dels = x(i)-x(i-1)
×
1340
       s4 = s4+(y(i)+y(i-1))*dels/2.
×
1341
       if (is_not_zero(sigma)) then
×
1342
          ss = sinhm_fun(sigmap * dels)
×
1343
          cs = coshmm_fun(sigmap * dels)
×
1344
          s4 = s4+(yp(i)+yp(i-1))*dels*(cs-ss/2.)/(sigmap*sigmap*(1.+ss))
×
1345
       else
1346
          s4 = s4-(yp(i)+yp(i-1))*dels*dels*dels/24.
×
1347
       end if
1348
    end do
1349
11  s5 = 0.
×
1350
    if (x(ium1) .ge. xxu .or. (ideltp .eq. 0 .and. bdy) .or. ilm1 .eq. ium1) go to 13
×
1351
!
1352
! integrate from x(ium1) to xxu, store in s5
1353
!
1354
    del1 = xxu-x(ium1)
×
1355
    del2 = xiu-xxu
×
1356
    dels = xiu-x(ium1)
×
1357
    t1 = del1*del1/(2.*dels)
×
1358
    t2 = (del2+dels)*del1/(2.*dels)
×
1359
    s5 = t1*y(iu)+t2*y(ium1)
×
1360
    if (is_not_zero(sigma)) then
×
1361
       c1 = coshmm_fun(sigmap * del1)
×
1362
       c2 = coshmm_fun(sigmap * del2)
×
1363
       ss = sinhm_fun(sigmap * dels)
×
1364
       cs = coshmm_fun(sigmap * dels)
×
1365
       s5 = s5+(yp(iu)*del1*del1*(c1-ss/2.)+yp(ium1)* &
×
1366
            (dels*dels*(cs-ss/2.)-del2*del2*(c2-ss/2.))) &
1367
            /(sigmap*sigmap*dels*(1.+ss))
×
1368
    else
1369
       s5 = s5-t1*(del2*(del1+dels)+dels*dels)*yp(iu)/12.-t2*t2*dels*yp(ium1)/6.
×
1370
    end if
1371
13  s6 = 0.
×
1372
    if (xxu .ge. xiu .or. (ideltp .eq. 0 .and. .not. bdy)) go to 15
×
1373
!
1374
! integrate from xxu to xiu, store in s6
1375
!
1376
    del1 = xxu-x(ium1)
×
1377
    del2 = xiu-xxu
×
1378
    dels = xiu-x(ium1)
×
1379
    t1 = (del1+dels)*del2/(2.*dels)
×
1380
    t2 = del2*del2/(2.*dels)
×
1381
    s6 = t1*y(iu)+t2*y(ium1)
×
1382
    if (is_not_zero(sigma)) then
×
1383
       c1 = coshmm_fun(sigmap * del1)
×
1384
       c2 = coshmm_fun(sigmap * del2)
×
1385
       ss = sinhm_fun(sigmap * dels)
×
1386
       cs = coshmm_fun(sigmap * dels)
×
1387
       s6 = s6+((dels*dels*(cs-ss/2.)-del1*del1*(c1-ss/2.)) &
1388
            *yp(iu)+del2*del2*(c2-ss/2.)*yp(ium1))/ &
×
1389
            (sigmap*sigmap*dels*(1.+ss))
×
1390
    else
1391
       s6 = s6-t1*t1*dels*yp(iu)/6.-t2*(del1*(del2+dels)+dels*dels)*yp(ium1)/12.
×
1392
    end if
1393
15  s7 = 0.
×
1394
    if (iu .eq. 1 .or. (ideltp .eq. 0 .and. .not. bdy)) go to 18
×
1395
!
1396
! integrate from xiu to x1pp, store in s7
1397
!
1398
    np1 = n+1
×
1399
    iup1 = iu+1
×
1400
    do ii = iup1,np1
×
1401
       im1 = ii-1
×
1402
       i = ii
×
1403
       if (i .eq. np1) i=1
×
1404
       dels = x(i)-x(im1)
×
1405
       if (dels .le. 0.) dels=dels+p
×
1406
       s7 = s7+(y(i)+y(im1))*dels/2.
×
1407
       if (is_not_zero(sigma)) then
×
1408
          ss = sinhm_fun(sigmap * dels)
×
1409
          cs = coshmm_fun(sigmap * dels)
×
1410
          s7 = s7+(yp(i)+yp(im1))*dels*(cs-ss/2.)/(sigmap*sigmap*(1.+ss))
×
1411
       else
1412
          s7 = s7-(yp(i)+yp(im1))*dels*dels*dels/24.
×
1413
       end if
1414
    end do
1415
18  s8 = 0.
×
1416
    if (ilm1 .lt. ium1 .or. (ideltp .eq. 0 .and. bdy))go to 20
×
1417

1418
!
1419
! integrate from xxl to xxu, store in s8
1420
!
1421
    delu1 = xxu-x(ium1)
×
1422
    delu2 = xiu-xxu
×
1423
    dell1 = xxl-x(ium1)
×
1424
    dell2 = xiu-xxl
×
1425
    dels = xiu-x(ium1)
×
1426
    deli = xxu-xxl
×
1427
    t1 = (delu1+dell1)*deli/(2.*dels)
×
1428
    t2 = (delu2+dell2)*deli/(2.*dels)
×
1429
    s8 = t1*y(iu)+t2*y(ium1)
×
1430
    if (is_not_zero(sigma)) then
×
1431
       cu1 = coshmm_fun(sigmap * delu1)
×
1432
       cu2 = coshmm_fun(sigmap * delu2)
×
1433
       cl1 = coshmm_fun(sigmap * dell1)
×
1434
       cl2 = coshmm_fun(sigmap * dell2)
×
1435
       ss = sinhm_fun(sigmap * dels)
×
1436
       s8 = s8+(yp(iu)*(delu1*delu1*(cu1-ss/2.) &
×
1437
            -dell1*dell1*(cl1-ss/2.)) &
1438
            +yp(ium1)*(dell2*dell2*(cl2-ss/2.) &
×
1439
            -delu2*delu2*(cu2-ss/2.)))/ &
1440
            (sigmap*sigmap*dels*(1.+ss))
×
1441
    else
1442
       s8 = s8-t1*(delu2*(dels+delu1) &
1443
            +dell2*(dels+dell1))*yp(iu)/12. &
×
1444
            -t2*(dell1*(dels+dell2) &
1445
            +delu1*(dels+delu2))*yp(ium1)/12.
×
1446
    end if
1447
20  so = s1+s2+s6+s7
×
1448
    si = s3+s4+s5+s8
×
1449
    if (bdy) then
×
1450
      fitp_curvpi = ideltp * (so+si) + isign * so
×
1451
    else
1452
      fitp_curvpi = ideltp * (so+si) + isign * si
×
1453
    end if
1454
  end function fitp_curvpi
×
1455

1456
  !> FIXME : Add documentation
1457
  pure subroutine fitp_surf1 (m,n,x,y,z,iz,zx1,zxm,zy1,zyn,zxy11, &
×
1458
       zxym1,zxy1n,zxymn,islpsw,zp,temp,sigma,ierr)
×
1459
    implicit none
1460
    integer, intent(in) :: m, n, iz, islpsw
1461
    real, dimension(m), intent(in) :: x, zy1, zyn
1462
    real, dimension(n), intent(in) :: y, zx1, zxm
1463
    real, dimension(iz,n), intent(in) :: z
1464
    real, intent(in) :: zxy11, zxym1, zxy1n, zxymn, sigma
1465
    real, dimension(m,n,3), intent(out) :: zp
1466
    real, dimension(n+n+m), intent(out) :: temp
1467
    integer, intent(out) :: ierr
1468
!
1469
!                                 coded by alan kaylor cline
1470
!                           from fitpack -- january 26, 1987
1471
!                        a curve and surface fitting package
1472
!                      a product of pleasant valley software
1473
!                  8603 altus cove, austin, texas 78759, usa
1474
!
1475
! this subroutine determines the parameters necessary to
1476
! compute an interpolatory surface passing through a rect-
1477
! angular grid of functional values. the surface determined
1478
! can be represented as the tensor product of splines under
1479
! tension. the x- and y-partial derivatives around the
1480
! boundary and the x-y-partial derivatives at the four
1481
! corners may be specified or omitted. for actual mapping
1482
! of points onto the surface it is necessary to call the
1483
! function surf2.
1484
!
1485
! on input--
1486
!
1487
!   m is the number of grid lines in the x-direction, i. e.
1488
!   lines parallel to the y-axis (m .ge. 2).
1489
!
1490
!   n is the number of grid lines in the y-direction, i. e.
1491
!   lines parallel to the x-axis (n .ge. 2).
1492
!
1493
!   x is an array of the m x-coordinates of the grid lines
1494
!   in the x-direction. these should be strictly increasing.
1495
!
1496
!   y is an array of the n y-coordinates of the grid lines
1497
!   in the y-direction. these should be strictly increasing.
1498
!
1499
!   z is an array of the m * n functional values at the grid
1500
!   points, i. e. z(i,j) contains the functional value at
1501
!   (x(i),y(j)) for i = 1,...,m and j = 1,...,n.
1502
!
1503
!   iz is the row dimension of the matrix z used in the
1504
!   calling program (iz .ge. m).
1505
!
1506
!   zx1 and zxm are arrays of the m x-partial derivatives
1507
!   of the function along the x(1) and x(m) grid lines,
1508
!   respectively. thus zx1(j) and zxm(j) contain the x-part-
1509
!   ial derivatives at the points (x(1),y(j)) and
1510
!   (x(m),y(j)), respectively, for j = 1,...,n. either of
1511
!   these parameters will be ignored (and approximations
1512
!   supplied internally) if islpsw so indicates.
1513
!
1514
!   zy1 and zyn are arrays of the n y-partial derivatives
1515
!   of the function along the y(1) and y(n) grid lines,
1516
!   respectively. thus zy1(i) and zyn(i) contain the y-part-
1517
!   ial derivatives at the points (x(i),y(1)) and
1518
!   (x(i),y(n)), respectively, for i = 1,...,m. either of
1519
!   these parameters will be ignored (and estimations
1520
!   supplied internally) if islpsw so indicates.
1521
!
1522
!   zxy11, zxym1, zxy1n, and zxymn are the x-y-partial
1523
!   derivatives of the function at the four corners,
1524
!   (x(1),y(1)), (x(m),y(1)), (x(1),y(n)), and (x(m),y(n)),
1525
!   respectively. any of the parameters will be ignored (and
1526
!   estimations supplied internally) if islpsw so indicates.
1527
!
1528
!   islpsw contains a switch indicating which boundary
1529
!   derivative information is user-supplied and which
1530
!   should be estimated by this subroutine. to determine
1531
!   islpsw, let
1532
!        i1 = 0 if zx1 is user-supplied (and = 1 otherwise),
1533
!        i2 = 0 if zxm is user-supplied (and = 1 otherwise),
1534
!        i3 = 0 if zy1 is user-supplied (and = 1 otherwise),
1535
!        i4 = 0 if zyn is user-supplied (and = 1 otherwise),
1536
!        i5 = 0 if zxy11 is user-supplied
1537
!                                       (and = 1 otherwise),
1538
!        i6 = 0 if zxym1 is user-supplied
1539
!                                       (and = 1 otherwise),
1540
!        i7 = 0 if zxy1n is user-supplied
1541
!                                       (and = 1 otherwise),
1542
!        i8 = 0 if zxymn is user-supplied
1543
!                                       (and = 1 otherwise),
1544
!   then islpsw = i1 + 2*i2 + 4*i3 + 8*i4 + 16*i5 + 32*i6
1545
!                   + 64*i7 + 128*i8
1546
!   thus islpsw = 0 indicates all derivative information is
1547
!   user-supplied and islpsw = 255 indicates no derivative
1548
!   information is user-supplied. any value between these
1549
!   limits is valid.
1550
!
1551
!   zp is an array of at least 3*m*n locations.
1552
!
1553
!   temp is an array of at least n+n+m locations which is
1554
!   used for scratch storage.
1555
!
1556
! and
1557
!
1558
!   sigma contains the tension factor. this value indicates
1559
!   the curviness desired. if abs(sigma) is nearly zero
1560
!   (e. g. .001) the resulting surface is approximately the
1561
!   tensor product of cubic splines. if abs(sigma) is large
1562
!   (e. g. 50.) the resulting surface is approximately
1563
!   bi-linear. if sigma equals zero tensor products of
1564
!   cubic splines result. a standard value for sigma is
1565
!   approximately 1. in absolute value.
1566
!
1567
! on output--
1568
!
1569
!   zp contains the values of the xx-, yy-, and xxyy-partial
1570
!   derivatives of the surface at the given nodes.
1571
!
1572
!   ierr contains an error flag,
1573
!        = 0 for normal return,
1574
!        = 1 if n is less than 2 or m is less than 2,
1575
!        = 2 if the x-values or y-values are not strictly
1576
!            increasing.
1577
!
1578
! and
1579
!
1580
!   m, n, x, y, z, iz, zx1, zxm, zy1, zyn, zxy11, zxym1,
1581
!   zxy1n, zxymn, islpsw, and sigma are unaltered.
1582
!
1583
! this subroutine references package modules ceez, terms,
1584
! and snhcsh.
1585
!
1586
!-----------------------------------------------------------
1587
    integer :: jbak, jbakp1, jm1, jp1, im1, ibakp1
1588
    integer :: npibak, ip1, ibak, nm1, np1, mm1, mp1, npm, j
1589
    integer :: npmpj, i, npi
1590
    real :: diagi, sdiag1, del2, zxymns, delxmm, del1
1591
    real :: diag1, deli, diag2, diagin, sdiag2, t
1592
    real :: delxm, sigmay, dely1, c1, dely2, c2
1593
    real :: delx1, delx2, zxy1ns, c3, delyn, sigmax, delynm
1594

1595
    mm1 = m-1
×
1596
    mp1 = m+1
×
1597
    nm1 = n-1
×
1598
    np1 = n+1
×
1599
    npm = n+m
×
1600
    ierr = 0
×
1601
    if (n .le. 1 .or. m .le. 1) go to 46
×
1602
    if (y(n) .le. y(1)) go to 47
×
1603
!
1604
! denormalize tension factor in y-direction
1605
!
1606
    sigmay = abs(sigma) * (n - 1) / (y(n) - y(1))
×
1607
!
1608
! obtain y-partial derivatives along y = y(1)
1609
!
1610
    if ((islpsw/8)*2 .ne. (islpsw/4)) go to 2
×
1611
    do i = 1,m
×
1612
       zp(i,1,1) = zy1(i)
×
1613
    end do
1614
    go to 5
×
1615
2   dely1 = y(2)-y(1)
×
1616
    dely2 = dely1+dely1
×
1617
    if (n .gt. 2) dely2 = y(3)-y(1)
×
1618
    if (dely1 .le. 0. .or. dely2 .le. dely1) go to 47
×
1619
    call fitp_ceez (dely1,dely2,sigmay,c1,c2,c3,n)
×
1620
    do i = 1,m
×
1621
       zp(i,1,1) = c1*z(i,1)+c2*z(i,2)
×
1622
    end do
1623
    if (n .eq. 2) go to 5
×
1624
    do i = 1,m
×
1625
       zp(i,1,1) = zp(i,1,1)+c3*z(i,3)
×
1626
    end do
1627
!
1628
! obtain y-partial derivatives along y = y(n)
1629
!
1630
5   if ((islpsw/16)*2 .ne. (islpsw/8)) go to 7
×
1631
    do i = 1,m
×
1632
       npi = n+i
×
1633
       temp(npi) = zyn(i)
×
1634
    end do
1635
    go to 10
×
1636
7   delyn = y(n)-y(nm1)
×
1637
    delynm = delyn+delyn
×
1638
    if (n .gt. 2) delynm = y(n)-y(n-2)
×
1639
    if (delyn .le. 0. .or. delynm .le. delyn) go to 47
×
1640
    call fitp_ceez (-delyn,-delynm,sigmay,c1,c2,c3,n)
×
1641
    do i = 1,m
×
1642
       npi = n+i
×
1643
       temp(npi) = c1*z(i,n)+c2*z(i,nm1)
×
1644
    end do
1645
    if (n .eq. 2) go to 10
×
1646
    do i = 1,m
×
1647
       npi = n+i
×
1648
       temp(npi) = temp(npi)+c3*z(i,n-2)
×
1649
    end do
1650
10  if (x(m) .le. x(1)) go to 47
×
1651
!
1652
! denormalize tension factor in x-direction
1653
!
1654
    sigmax = abs(sigma) * (m - 1) / (x(m) - x(1))
×
1655
!
1656
! obtain x-partial derivatives along x = x(1)
1657
!
1658
    if ((islpsw/2)*2 .ne. islpsw) go to 12
×
1659
    do j = 1,n
×
1660
       zp(1,j,2) = zx1(j)
×
1661
    end do
1662
    if ((islpsw/32)*2 .eq. (islpsw/16) .and. (islpsw/128)*2  .eq. (islpsw/64)) go to 15
×
1663
12  delx1 = x(2)-x(1)
×
1664
    delx2 = delx1+delx1
×
1665
    if (m .gt. 2) delx2 = x(3)-x(1)
×
1666
    if (delx1 .le. 0. .or. delx2 .le. delx1) go to 47
×
1667
    call fitp_ceez (delx1,delx2,sigmax,c1,c2,c3,m)
×
1668
    if ((islpsw/2)*2 .eq. islpsw) go to 15
×
1669
    do j = 1,n
×
1670
       zp(1,j,2) = c1*z(1,j)+c2*z(2,j)
×
1671
    end do
1672
    if (m .eq. 2) go to 15
×
1673
    do j = 1,n
×
1674
       zp(1,j,2) = zp(1,j,2)+c3*z(3,j)
×
1675
    end do
1676
!
1677
! obtain x-y-partial derivative at (x(1),y(1))
1678
!
1679
15  if ((islpsw/32)*2 .ne. (islpsw/16)) go to 16
×
1680
    zp(1,1,3) = zxy11
×
1681
    go to 17
×
1682
16  zp(1,1,3) = c1*zp(1,1,1)+c2*zp(2,1,1)
×
1683
    if (m .gt. 2) zp(1,1,3) = zp(1,1,3)+c3*zp(3,1,1)
×
1684
!
1685
! obtain x-y-partial derivative at (x(1),y(n))
1686
!
1687
17  if ((islpsw/128)*2 .ne. (islpsw/64)) go to 18
×
1688
    zxy1ns = zxy1n
×
1689
    go to 19
×
1690
18  zxy1ns = c1*temp(n+1)+c2*temp(n+2)
×
1691
    if (m .gt. 2) zxy1ns = zxy1ns+c3*temp(n+3)
×
1692
!
1693
! obtain x-partial derivative along x = x(m)
1694
!
1695
19  if ((islpsw/4)*2 .ne. (islpsw/2)) go to 21
×
1696
    do j = 1,n
×
1697
       npmpj = npm+j
×
1698
       temp(npmpj) = zxm(j)
×
1699
    end do
1700
    if ((islpsw/64)*2 .eq. (islpsw/32) .and.(islpsw/256)*2 .eq. (islpsw/128)) go to 24
×
1701
21  delxm = x(m)-x(mm1)
×
1702
    delxmm = delxm+delxm
×
1703
    if (m .gt. 2) delxmm = x(m)-x(m-2)
×
1704
    if (delxm .le. 0. .or. delxmm .le. delxm) go to 47
×
1705
    call fitp_ceez (-delxm,-delxmm,sigmax,c1,c2,c3,m)
×
1706
    if ((islpsw/4)*2 .eq. (islpsw/2)) go to 24
×
1707
    do j = 1,n
×
1708
       npmpj = npm+j
×
1709
       temp(npmpj) = c1*z(m,j)+c2*z(mm1,j)
×
1710
    end do
1711
    if (m .eq. 2) go to 24
×
1712
    do j = 1,n
×
1713
       npmpj = npm+j
×
1714
       temp(npmpj) = temp(npmpj)+c3*z(m-2,j)
×
1715
    end do
1716
!
1717
! obtain x-y-partial derivative at (x(m),y(1))
1718
!
1719
24  if ((islpsw/64)*2 .ne. (islpsw/32)) go to 25
×
1720
    zp(m,1,3) = zxym1
×
1721
    go to 26
×
1722
25  zp(m,1,3) = c1*zp(m,1,1)+c2*zp(mm1,1,1)
×
1723
    if (m .gt. 2) zp(m,1,3) = zp(m,1,3)+c3*zp(m-2,1,1)
×
1724
!
1725
! obtain x-y-partial derivative at (x(m),y(n))
1726
!
1727
26  if ((islpsw/256)*2 .ne. (islpsw/128)) go to 27
×
1728
    zxymns = zxymn
×
1729
    go to 28
×
1730
27  zxymns = c1*temp(npm)+c2*temp(npm-1)
×
1731
    if (m .gt. 2) zxymns = zxymns+c3*temp(npm-2)
×
1732
!
1733
! set up right hand sides and tridiagonal system for y-grid
1734
! perform forward elimination
1735
!
1736
28  del1 = y(2)-y(1)
×
1737
    if (del1 .le. 0.) go to 47
×
1738
    deli = 1./del1
×
1739
    do i = 1,m
×
1740
       zp(i,2,1) = deli*(z(i,2)-z(i,1))
×
1741
    end do
1742
    zp(1,2,3) = deli*(zp(1,2,2)-zp(1,1,2))
×
1743
    zp(m,2,3) = deli*(temp(npm+2)-temp(npm+1))
×
1744
    call fitp_terms (diag1,sdiag1,sigmay,del1)
×
1745
    diagi = 1./diag1
×
1746
    do i = 1,m
×
1747
       zp(i,1,1) = diagi*(zp(i,2,1)-zp(i,1,1))
×
1748
    end do
1749
    zp(1,1,3) = diagi*(zp(1,2,3)-zp(1,1,3))
×
1750
    zp(m,1,3) = diagi*(zp(m,2,3)-zp(m,1,3))
×
1751
    temp(1) = diagi*sdiag1
×
1752
    if (n .eq. 2) go to 34
×
1753
    do j = 2,nm1
×
1754
       jm1 = j-1
×
1755
       jp1 = j+1
×
1756
       npmpj = npm+j
×
1757
       del2 = y(jp1)-y(j)
×
1758
       if (del2 .le. 0.) go to 47
×
1759
       deli = 1./del2
×
1760
       do i = 1,m
×
1761
          zp(i,jp1,1) = deli*(z(i,jp1)-z(i,j))
×
1762
       end do
1763
       zp(1,jp1,3) = deli*(zp(1,jp1,2)-zp(1,j,2))
×
1764
       zp(m,jp1,3) = deli*(temp(npmpj+1)-temp(npmpj))
×
1765
       call fitp_terms (diag2,sdiag2,sigmay,del2)
×
1766
       diagin = 1./(diag1+diag2-sdiag1*temp(jm1))
×
1767
       do i = 1,m
×
1768
          zp(i,j,1) = diagin*(zp(i,jp1,1)-zp(i,j,1)-sdiag1*zp(i,jm1,1))
×
1769
       end do
1770
       zp(1,j,3) = diagin*(zp(1,jp1,3)-zp(1,j,3)-sdiag1*zp(1,jm1,3))
×
1771
       zp(m,j,3) = diagin*(zp(m,jp1,3)-zp(m,j,3)-sdiag1*zp(m,jm1,3))
×
1772
       temp(j) = diagin*sdiag2
×
1773
       diag1 = diag2
×
1774
       sdiag1 = sdiag2
×
1775
    end do
1776
34  diagin = 1./(diag1-sdiag1*temp(nm1))
×
1777
    do i = 1,m
×
1778
       npi = n+i
×
1779
       zp(i,n,1) = diagin*(temp(npi)-zp(i,n,1)-sdiag1*zp(i,nm1,1))
×
1780
    end do
1781
    zp(1,n,3) = diagin*(zxy1ns-zp(1,n,3)-sdiag1*zp(1,nm1,3))
×
1782
    temp(n) = diagin*(zxymns-zp(m,n,3)-sdiag1*zp(m,nm1,3))
×
1783
!
1784
! perform back substitution
1785
!
1786
    do j = 2,n
×
1787
       jbak = np1-j
×
1788
       jbakp1 = jbak+1
×
1789
       t = temp(jbak)
×
1790
       do i = 1,m
×
1791
          zp(i,jbak,1) = zp(i,jbak,1)-t*zp(i,jbakp1,1)
×
1792
       end do
1793
       zp(1,jbak,3) = zp(1,jbak,3)-t*zp(1,jbakp1,3)
×
1794
       temp(jbak) = zp(m,jbak,3)-t*temp(jbakp1)
×
1795
    end do
1796
!
1797
! set up right hand sides and tridiagonal system for x-grid
1798
! perform forward elimination
1799
!
1800
    del1 = x(2)-x(1)
×
1801
    if (del1 .le. 0.) go to 47
×
1802
    deli = 1./del1
×
1803
    do j = 1,n
×
1804
       zp(2,j,2) = deli*(z(2,j)-z(1,j))
×
1805
       zp(2,j,3) = deli*(zp(2,j,1)-zp(1,j,1))
×
1806
    end do
1807
    call fitp_terms (diag1,sdiag1,sigmax,del1)
×
1808
    diagi = 1./diag1
×
1809
    do j = 1,n
×
1810
       zp(1,j,2) = diagi*(zp(2,j,2)-zp(1,j,2))
×
1811
       zp(1,j,3) = diagi*(zp(2,j,3)-zp(1,j,3))
×
1812
    end do
1813
    temp(n+1) = diagi*sdiag1
×
1814
    if (m  .eq. 2) go to 43
×
1815
    do i = 2,mm1
×
1816
       im1 = i-1
×
1817
       ip1 = i+1
×
1818
       npi = n+i
×
1819
       del2 = x(ip1)-x(i)
×
1820
       if (del2 .le. 0.) go to 47
×
1821
       deli = 1./del2
×
1822
       do j = 1,n
×
1823
          zp(ip1,j,2) = deli*(z(ip1,j)-z(i,j))
×
1824
          zp(ip1,j,3) = deli*(zp(ip1,j,1)-zp(i,j,1))
×
1825
       end do
1826
       call fitp_terms (diag2,sdiag2,sigmax,del2)
×
1827
       diagin = 1./(diag1+diag2-sdiag1*temp(npi-1))
×
1828
       do j = 1,n
×
1829
          zp(i,j,2) = diagin*(zp(ip1,j,2)-zp(i,j,2)-sdiag1*zp(im1,j,2))
×
1830
          zp(i,j,3) = diagin*(zp(ip1,j,3)-zp(i,j,3)-sdiag1*zp(im1,j,3))
×
1831
       end do
1832
       temp(npi) = diagin*sdiag2
×
1833
       diag1 = diag2
×
1834
       sdiag1 = sdiag2
×
1835
    end do
1836
43  diagin = 1./(diag1-sdiag1*temp(npm-1))
×
1837
    do j = 1,n
×
1838
       npmpj = npm+j
×
1839
       zp(m,j,2) = diagin*(temp(npmpj)-zp(m,j,2)-sdiag1*zp(mm1,j,2))
×
1840
       zp(m,j,3) = diagin*(temp(j)-zp(m,j,3)-sdiag1*zp(mm1,j,3))
×
1841
    end do
1842
!
1843
! perform back substitution
1844
!
1845
    do i = 2,m
×
1846
       ibak = mp1-i
×
1847
       ibakp1 = ibak+1
×
1848
       npibak = n+ibak
×
1849
       t = temp(npibak)
×
1850
       do j = 1,n
×
1851
          zp(ibak,j,2) = zp(ibak,j,2)-t*zp(ibakp1,j,2)
×
1852
          zp(ibak,j,3) = zp(ibak,j,3)-t*zp(ibakp1,j,3)
×
1853
       end do
1854
    end do
1855
    return
×
1856
!
1857
! too few points
1858
!
1859
46  ierr = 1
×
1860
    return
×
1861
!
1862
! points not strictly increasing
1863
!
1864
47  ierr = 2
×
1865
    return
×
1866
  end subroutine fitp_surf1
1867

1868
  !> FIXME : Add documentation
1869
  real function fitp_surf2 (xx,yy,m,n,x,y,z,iz,zp,sigma)
×
1870
    implicit none
1871
    
1872
    real, intent(in) :: xx, yy, sigma
1873
    integer, intent(in) :: m, n, iz
1874
    real, dimension(m), intent(in) :: x
1875
    real, dimension(n), intent(in) :: y
1876
    real, dimension(iz,n), intent(in) :: z
1877
    real, dimension(m,n,3), intent(in) :: zp
1878
!
1879
!                                 coded by alan kaylor cline
1880
!                           from fitpack -- january 26, 1987
1881
!                        a curve and surface fitting package
1882
!                      a product of pleasant valley software
1883
!                  8603 altus cove, austin, texas 78759, usa
1884
!
1885
! this function interpolates a surface at a given coordinate
1886
! pair using a bi-spline under tension. the subroutine surf1
1887
! should be called earlier to determine certain necessary
1888
! parameters.
1889
!
1890
! on input--
1891
!
1892
!   xx and yy contain the x- and y-coordinates of the point
1893
!   to be mapped onto the interpolating surface.
1894
!
1895
!   m and n contain the number of grid lines in the x- and
1896
!   y-directions, respectively, of the rectangular grid
1897
!   which specified the surface.
1898
!
1899
!   x and y are arrays containing the x- and y-grid values,
1900
!   respectively, each in increasing order.
1901
!
1902
!   z is a matrix containing the m * n functional values
1903
!   corresponding to the grid values (i. e. z(i,j) is the
1904
!   surface value at the point (x(i),y(j)) for i = 1,...,m
1905
!   and j = 1,...,n).
1906
!
1907
!   iz contains the row dimension of the array z as declared
1908
!   in the calling program.
1909
!
1910
!   zp is an array of 3*m*n locations stored with the
1911
!   various surface derivative information determined by
1912
!   surf1.
1913
!
1914
! and
1915
!
1916
!   sigma contains the tension factor (its sign is ignored).
1917
!
1918
! the parameters m, n, x, y, z, iz, zp, and sigma should be
1919
! input unaltered from the output of surf1.
1920
!
1921
! on output--
1922
!
1923
!   surf2 contains the interpolated surface value.
1924
!
1925
! none of the input parameters are altered.
1926
!
1927
! this function references package modules intrvl and
1928
! snhcsh.
1929
!
1930
!-----------------------------------------------------------
1931
    integer :: im1, i, j, jm1
1932
    real :: zxxi, zxxim1, zim1, zi
1933
    real :: sigmax, del1, del2
1934
    real :: sinhms, sinhm2, sinhm1, dels, sigmay
1935
!
1936
! inline one dimensional cubic spline interpolation
1937
!
1938
!/Moved to contained function
1939
!    hermz (f1,f2,fp1,fp2) = (f2*del1+f1*del2)/dels-del1* &
1940
!         del2*(fp2*(del1+dels)+ &
1941
!         fp1*(del2+dels))/(6.*dels)
1942
!
1943
! inline one dimensional spline under tension interpolation
1944
!
1945
!/Moved to contained function
1946
!    hermnz (f1,f2,fp1,fp2,sigmap) = (f2*del1+f1*del2)/dels &
1947
!         +(fp2*del1*(sinhm1-sinhms) &
1948
!         +fp1*del2*(sinhm2-sinhms) &
1949
!         )/(sigmap*sigmap*dels*(1.+sinhms))
1950

1951
!
1952
! denormalize tension factor in x and y direction
1953
!
1954
    sigmax = abs(sigma) * (m - 1) / (x(m) - x(1))
×
1955
    sigmay = abs(sigma) * (n - 1) / (y(n) - y(1))
×
1956
!
1957
! determine y interval
1958
!
1959
    jm1 = fitp_intrvl (yy,y,n)
×
1960
    j = jm1+1
×
1961
!
1962
! determine x interval
1963
!
1964
    im1 = fitp_intrvl (xx,x,m)
×
1965
    i = im1+1
×
1966
    del1 = yy-y(jm1)
×
1967
    del2 = y(j)-yy
×
1968
    dels = y(j)-y(jm1)
×
1969
    if (is_zero(sigmay)) then
×
1970
       ! perform four interpolations in y-direction
1971
       zim1 = hermz(z(i-1,j-1),z(i-1,j),zp(i-1,j-1,1),zp(i-1,j,1))
×
1972
       zi = hermz(z(i,j-1),z(i,j),zp(i,j-1,1),zp(i,j,1))
×
1973
       zxxim1 = hermz(zp(i-1,j-1,2),zp(i-1,j,2),zp(i-1,j-1,3),zp(i-1,j,3))
×
1974
       zxxi = hermz(zp(i,j-1,2),zp(i,j,2),zp(i,j-1,3),zp(i,j,3))
×
1975
    else
1976
       sinhm1 = sinhm_fun(sigmay * del1)
×
1977
       sinhm2 = sinhm_fun(sigmay * del2)
×
1978
       sinhms = sinhm_fun(sigmay * dels)
×
1979
       zim1 = hermnz(z(i-1,j-1),z(i-1,j),zp(i-1,j-1,1),zp(i-1,j,1),sigmay)
×
1980
       zi = hermnz(z(i,j-1),z(i,j),zp(i,j-1,1),zp(i,j,1),sigmay)
×
1981
       zxxim1 = hermnz(zp(i-1,j-1,2),zp(i-1,j,2),zp(i-1,j-1,3),zp(i-1,j,3),sigmay)
×
1982
       zxxi = hermnz(zp(i,j-1,2),zp(i,j,2),zp(i,j-1,3),zp(i,j,3),sigmay)
×
1983
    end if
1984

1985
    ! perform final interpolation in x-direction
1986

1987
    del1 = xx-x(im1)
×
1988
    del2 = x(i)-xx
×
1989
    dels = x(i)-x(im1)
×
1990

1991
    if (is_zero(sigmax)) then
×
1992
       fitp_surf2 = hermz(zim1,zi,zxxim1,zxxi)
×
1993
    else
1994
       sinhm1 = sinhm_fun(sigmax * del1)
×
1995
       sinhm2 = sinhm_fun(sigmax * del2)
×
1996
       sinhms = sinhm_fun(sigmax * dels)
×
1997
       fitp_surf2 = hermnz(zim1,zi,zxxim1,zxxi,sigmax)
×
1998
    end if
1999
  contains
2000
    !> FIXME : Add documentation
2001
    elemental real function hermz(f1,f2,fp1,fp2)
×
2002
      !Note del1,sinhm1 etc. are known because we are in subroutine scope
2003
      implicit none
2004
      real, intent(in) :: f1,f2,fp1,fp2
2005
      hermz= (f2*del1+f1*del2)/dels-del1* &
2006
           del2*(fp2*(del1+dels)+ &
2007
           fp1*(del2+dels))/(6.*dels)
×
2008
    end function hermz
×
2009

2010
    !> FIXME : Add documentation
2011
    elemental real function hermnz(f1,f2,fp1,fp2,sigmap)
×
2012
      !Note del1,sinhm1 etc. are known because we are in subroutine scope
2013
      implicit none
2014
      real, intent(in) :: f1,f2,fp1,fp2,sigmap
2015
      hermnz= (f2*del1+f1*del2)/dels &
2016
           +(fp2*del1*(sinhm1-sinhms) &
2017
           +fp1*del2*(sinhm2-sinhms) &
2018
           )/(sigmap*sigmap*dels*(1.+sinhms))
×
2019
    end function hermnz
×
2020
  end function fitp_surf2
2021

2022
  !> FIXME : Add documentation  
2023
  pure subroutine fitp_ceez (del1,del2,sigma,c1,c2,c3,n)
64✔
2024
    implicit none
2025
    integer, intent(in) :: n
2026
    real, intent(in) :: del1, del2, sigma
2027
    real, intent(out) :: c1, c2, c3
2028
!
2029
!                                 coded by alan kaylor cline
2030
!                           from fitpack -- january 26, 1987
2031
!                        a curve and surface fitting package
2032
!                      a product of pleasant valley software
2033
!                  8603 altus cove, austin, texas 78759, usa
2034
!
2035
! this subroutine determines the coefficients c1, c2, and c3
2036
! used to determine endpoint slopes. specifically, if
2037
! function values y1, y2, and y3 are given at points x1, x2,
2038
! and x3, respectively, the quantity c1*y1 + c2*y2 + c3*y3
2039
! is the value of the derivative at x1 of a spline under
2040
! tension (with tension factor sigma) passing through the
2041
! three points and having third derivative equal to zero at
2042
! x1. optionally, only two values, c1 and c2 are determined.
2043
!
2044
! on input--
2045
!
2046
!   del1 is x2-x1 (.gt. 0.).
2047
!
2048
!   del2 is x3-x1 (.gt. 0.). if n .eq. 2, this parameter is
2049
!   ignored.
2050
!
2051
!   sigma is the tension factor.
2052
!
2053
! and
2054
!
2055
!   n is a switch indicating the number of coefficients to
2056
!   be returned. if n .eq. 2 only two coefficients are
2057
!   returned. otherwise all three are returned.
2058
!
2059
! on output--
2060
!
2061
!   c1, c2, and c3 contain the coefficients.
2062
!
2063
! none of the input parameters are altered.
2064
!
2065
! this subroutine references package module snhcsh.
2066
!
2067
!-----------------------------------------------------------
2068
    real :: delm, delp, sinhmp, denom, sinhmm, del, coshm2, coshm1
2069

2070
    if (n == 2) then
64✔
2071
      ! two coefficients
2072
      c1 = -1./del1
×
2073
      c2 = -c1
×
2074
    else if (is_zero(sigma)) then
64✔
2075
      ! tension .eq. 0.
2076
      del = del2-del1
×
2077
      c1 = -(del1+del2)/(del1*del2)
×
2078
      c2 = del2/(del1*del)
×
2079
      c3 = -del1/(del2*del)
×
2080
   else
2081
      ! tension .ne. 0.
2082
      coshm1 = coshm_fun(sigma * del1)
64✔
2083
      coshm2 = coshm_fun(sigma * del2)
64✔
2084
      delp = sigma*(del2+del1)/2.
64✔
2085
      delm = sigma*(del2-del1)/2.
64✔
2086
      sinhmp = sinhm_fun(delp)
64✔
2087
      sinhmm = sinhm_fun(delm)
64✔
2088
      denom = coshm1*(del2-del1)-2.*del1*delp*delm*(1.+sinhmp)*(1.+sinhmm)
64✔
2089
      c1 = 2.*delp*delm*(1.+sinhmp)*(1.+sinhmm)/denom
64✔
2090
      c2 = -coshm2/denom
64✔
2091
      c3 = coshm1/denom
64✔
2092
   end if
2093
  end subroutine fitp_ceez
64✔
2094

2095
  !> FIXME : Add documentation  
2096
  integer function fitp_intrvl (t,x,n)
526,344✔
2097
    implicit none
2098
    integer, intent(in) :: n
2099
    real, intent(in) :: t
2100
    real, dimension(n), intent(in) :: x
2101
!
2102
!                                 coded by alan kaylor cline
2103
!                           from fitpack -- january 26, 1987
2104
!                        a curve and surface fitting package
2105
!                      a product of pleasant valley software
2106
!                  8603 altus cove, austin, texas 78759, usa
2107
!
2108
! this function determines the index of the interval
2109
! (determined by a given increasing sequence) in which
2110
! a given value lies.
2111
!
2112
! on input--
2113
!
2114
!   t is the given value.
2115
!
2116
!   x is a vector of strictly increasing values.
2117
!
2118
! and
2119
!
2120
!   n is the length of x (n .ge. 2).
2121
!
2122
! on output--
2123
!
2124
!   intrvl returns an integer i such that
2125
!
2126
!          i =  1       if         e   t .lt. x(2)  ,
2127
!          i =  n-1     if x(n-1) .le. t            ,
2128
!          otherwise       x(i)  .le. t .le. x(i+1),
2129
!
2130
! none of the input parameters are altered.
2131
!
2132
!-----------------------------------------------------------
2133
    fitp_intrvl = fitp_intrv_helper(t, x, n, .false.)
526,344✔
2134
  end function fitp_intrvl
526,344✔
2135

2136
  !> FIXME : Add documentation  
2137
  integer function fitp_intrvp (t,x,n)
394,758✔
2138
    implicit none
2139
    integer, intent(in) :: n
2140
    real, intent(in) :: t
2141
    real, dimension(n), intent(in) :: x
2142
!
2143
!                                 coded by alan kaylor cline
2144
!                           from fitpack -- january 26, 1987
2145
!                        a curve and surface fitting package
2146
!                      a product of pleasant valley software
2147
!                  8603 altus cove, austin, texas 78759, usa
2148
!
2149
! this function determines the index of the interval
2150
! (determined by a given increasing sequence) in which a
2151
! given value lies, after translating the value to within
2152
! the correct period.  it also returns this translated value.
2153
!
2154
! on input--
2155
!
2156
!   t is the given value.
2157
!
2158
!   x is a vector of strictly increasing values.
2159
!
2160
!   n is the length of x (n .ge. 2).
2161
!
2162
! on output--
2163
!
2164
!   intrvl returns an integer i such that
2165
!
2166
!          i = 1       if             tp .lt. x(2)  ,
2167
!          i = n       if   x(n) .le. tp            ,
2168
!          otherwise       x(i)  .le. tp .lt. x(i+1),
2169
!
2170
! none of the input parameters are altered.
2171
!
2172
!-----------------------------------------------------------
2173
    fitp_intrvp = fitp_intrv_helper(t, x, n, .true.)
394,758✔
2174
  end function fitp_intrvp
394,758✔
2175

2176
  !> Given a value t, and stating value of abscissae, x, periodic with period p
2177
  !> map t to the equivalent value in the range of x (i.e. between x(1) and x(1) + p)
2178
  elemental real function fitp_periodic_wrap_value(t, x_start, p) result(wrapped_value)
394,758✔
2179
    real, intent(in) :: t, x_start, p
2180
    integer :: nper
2181
    nper = int((t - x_start) / p)
394,758✔
2182
    wrapped_value = t - nper * p
394,758✔
2183
    if (wrapped_value < x_start) wrapped_value = wrapped_value + p
394,758✔
2184
  end function fitp_periodic_wrap_value
394,758✔
2185

2186
  integer function fitp_intrv_helper(tt, x, n, periodic) result(index)
921,102✔
2187
    implicit none
2188
    integer, intent(in) :: n
2189
    real, intent(in) :: tt
2190
    real, dimension(n), intent(in) :: x
2191
    logical, intent(in) :: periodic
2192
    ! The save attribute on i prevents a number of routines from being marked pure
2193
    integer, save :: i = 1
2194
    integer :: il, ih, upper
2195
    if (periodic) then
921,102✔
2196
       upper = n
394,758✔
2197
    else
2198
       upper = n - 1
526,344✔
2199
    end if
2200

2201
!
2202
! check for illegal i
2203
!
2204
    if (i .ge. n) i = n / 2
921,102✔
2205
!
2206
! check old interval and extremes
2207
!
2208
    if (tt .lt. x(i)) then
921,102✔
2209
       if (tt .le. x(2)) then
55✔
2210
          i = 1
55✔
2211
          index = 1
55✔
2212
          return
55✔
2213
       else
2214
          il = 2
×
2215
          ih = i
×
2216
       end if
2217
    else if (tt .le. x(i+1)) then
921,047✔
2218
       index = i
115,143✔
2219
       return
115,143✔
2220
    else if (tt .ge. x(upper)) then
805,904✔
2221
       i = upper
50✔
2222
       index = upper
50✔
2223
       return
50✔
2224
    else
2225
       il = i+1
805,854✔
2226
       ih = upper
805,854✔
2227
    end if
2228

2229
    !
2230
    ! binary search loop
2231
    !
2232
    do while (.true.)
10,336,844✔
2233
       i = (il + ih) / 2
11,142,698✔
2234
       if (tt < x(i)) then
11,142,698✔
2235
          ih = i
10,336,844✔
2236
       else if (tt > x(i + 1)) then
805,854✔
2237
          il = i + 1
×
2238
       else
2239
          index = i
805,854✔
2240
          exit
805,854✔
2241
       end if
2242
    end do
2243
  end function fitp_intrv_helper
805,854✔
2244

2245
  !> Calculate sinhm(x) = sinh(x) / x - 1
2246
  elemental real function sinhm_fun(x)
3,783,240✔
2247
    real, intent(in) :: x
2248
    if (is_zero(x)) then
3,783,240✔
2249
       sinhm_fun = 0
230,286✔
2250
    else
2251
       sinhm_fun = sinh(x) / x - 1
3,552,954✔
2252
    end if
2253
  end function sinhm_fun
3,783,240✔
2254

2255
  !> Calculate coshm(x) = cosh(x) - 1
2256
  elemental real function coshm_fun(x)
1,019,934✔
2257
    real, intent(in) :: x
2258
    coshm_fun = cosh(x) - 1
1,019,934✔
2259
  end function coshm_fun
1,019,934✔
2260

2261
  !> Calculate coshmm(x) = (cosh(x) - 1 - x * x / 2) / (x * x)
2262
  elemental real function coshmm_fun(x)
×
2263
    real, intent(in) :: x
2264
    if (is_zero(x)) then
×
2265
       coshmm_fun = 0
×
2266
    else
2267
       coshmm_fun = (cosh(x) - 1 - x*x/2) / (x*x)
×
2268
    end if
2269
  end function coshmm_fun
×
2270

2271
  !> FIXME : Add documentation  
2272
  pure subroutine fitp_terms (diag,sdiag,sigma,del)
1,019,806✔
2273
    implicit none
2274
    real, intent(in) :: sigma, del
2275
    real, intent(out) :: diag, sdiag
2276
!
2277
!                                 coded by alan kaylor cline
2278
!                           from fitpack -- january 26, 1987
2279
!                        a curve and surface fitting package
2280
!                      a product of pleasant valley software
2281
!                  8603 altus cove, austin, texas 78759, usa
2282
!
2283
! this subroutine computes the diagonal and superdiagonal
2284
! terms of the tridiagonal linear system associated with
2285
! spline under tension interpolation.
2286
!
2287
! on input--
2288
!
2289
!   sigma contains the tension factor.
2290
!
2291
! and
2292
!
2293
!   del contains the step size.
2294
!
2295
! on output--
2296
!
2297
!                sigma*del*cosh(sigma*del) - sinh(sigma*del)
2298
!   diag = del*--------------------------------------------.
2299
!                     (sigma*del)**2 * sinh(sigma*del)
2300
!
2301
!                   sinh(sigma*del) - sigma*del
2302
!   sdiag = del*----------------------------------.
2303
!                (sigma*del)**2 * sinh(sigma*del)
2304
!
2305
! and
2306
!
2307
!   sigma and del are unaltered.
2308
!
2309
! this subroutine references package module snhcsh.
2310
!
2311
!-----------------------------------------------------------
2312
    real :: coshm, denom, sigdel, sinhm
2313

2314
    if (is_zero(sigma)) then
1,019,806✔
2315
       diag = del/3.
×
2316
       sdiag = del/6.
×
2317
    else
2318
       sigdel = sigma*del
1,019,806✔
2319
       sinhm = sinhm_fun(sigdel)
1,019,806✔
2320
       coshm = coshm_fun(sigdel)
1,019,806✔
2321
       denom = sigma*sigdel*(1.+sinhm)
1,019,806✔
2322
       diag = (coshm-sinhm)/denom
1,019,806✔
2323
       sdiag = sinhm/denom
1,019,806✔
2324
       ! Note we could use the cosh and sinh intrinsics to evalute the expression
2325
       ! directly as below. This is found to agree very well with the existing form.
2326
       !diag = del * (sigdel*cosh(sigdel) - sinh(sigdel))/(sigdel*sigdel*sinh(sigdel))
2327
       !sdiag = del * (sinh(sigdel) - sigdel)/(sigdel*sigdel*sinh(sigdel))
2328
    end if
2329
  end subroutine fitp_terms
1,019,806✔
2330
end module splines
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc