aboutsummaryrefslogtreecommitdiff
path: root/math/iminterp/asider.x
blob: 73e93b4ddc2776528744cf05a1b1cd216b8b892d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include <math/iminterp.h>
include "im1interpdef.h"

# ASIDER -- Calculate nder derivatives assuming that x lands in the region
# 1 <= x <= npts.

procedure asider (asi, x, der, nder)

pointer	asi		# interpolant descriptor
real	x[ARB]		# x value
real	der[ARB]	# derivatives, der[1] is value der[2] is f prime 
int	nder		# number items returned = 1 + number of derivatives

int	nearx, i, j, k, nterms, nd
pointer	c0ptr, n0
real	deltax, accum, tmpx[2], pcoeff[MAX_NDERIVS], diff[MAX_NDERIVS]

begin
	# Return zero for derivatives that are zero.
	do i = 1, nder
	    der[i] = 0.

	# Nterms is number of terms in case polynomial type.
	nterms = 0

	# (c0ptr + 1) is the pointer to the first data point in COEFF.
	c0ptr = ASI_COEFF(asi) - 1 + ASI_OFFSET(asi)

	switch (ASI_TYPE(asi))	{

	case II_NEAREST:
	    der[1] = COEFF(c0ptr + int(x[1] + 0.5))
	    return

	case II_LINEAR:
	    nearx = x[1]
	    der[1] = (x[1] - nearx) * COEFF(c0ptr + nearx + 1) +
		     (nearx + 1 - x[1]) * COEFF(c0ptr + nearx)
	    if (nder > 1)
		der[2] = COEFF(c0ptr + nearx + 1) - COEFF(c0ptr + nearx)
	    return

	case II_SINC, II_LSINC:
	    call ii_sincder (x[1], der, nder,
		COEFF(ASI_COEFF(asi) + ASI_OFFSET(asi)), ASI_NCOEFF(asi),
		ASI_NSINC(asi), DX)
	    return

	case II_DRIZZLE:
	    if (ASI_PIXFRAC(asi) >= 1.0)
	        call ii_driz1 (x, der[1], 1, COEFF(ASI_COEFF(asi) +
	            ASI_OFFSET(asi)), ASI_BADVAL(asi))
	    else
	        call ii_driz (x, der[1], 1, COEFF(ASI_COEFF(asi) +
	            ASI_OFFSET(asi)), ASI_PIXFRAC(asi), ASI_BADVAL(asi))
	    if (nder > 1) {
		deltax = x[2] - x[1]
		if (deltax == 0.0)
		    der[2] = 0.0
		else {
		    tmpx[1] = x[1]
		    tmpx[2] = (x[1] + x[2]) / 2.0
	    	    if (ASI_PIXFRAC(asi) >= 1.0)
	                call ii_driz1 (tmpx, accum, 1, COEFF(ASI_COEFF(asi) +
	                    ASI_OFFSET(asi)), ASI_BADVAL(asi))
		    else
	                call ii_driz (tmpx, accum, 1, COEFF(ASI_COEFF(asi) +
	                    ASI_OFFSET(asi)), ASI_PIXFRAC(asi), ASI_BADVAL(asi))
		    tmpx[1] = tmpx[2]
		    tmpx[2] = x[2]
	    	    if (ASI_PIXFRAC(asi) >= 1.0)
	                call ii_driz1 (tmpx, der[2], 1, COEFF(ASI_COEFF(asi) +
	                    ASI_OFFSET(asi)), ASI_BADVAL(asi))
		    else
	                call ii_driz (tmpx, der[2], 1, COEFF(ASI_COEFF(asi) +
	                    ASI_OFFSET(asi)), ASI_PIXFRAC(asi), ASI_BADVAL(asi))
		    der[2] = 2.0 * (der[2] - accum) / deltax
		}
	    }
	    return

	case II_POLY3:
	    nterms = 4

	case II_POLY5:
	    nterms = 6

	case II_SPLINE3:
	    nterms = 4

	default:
	    call error (0, "ASIDER: Unknown interpolant type")
	}

	# Routines falls through to this point if the interpolant is one of
	# the higher order polynomial types or a third order spline.

	nearx = x[1]
	n0 = c0ptr + nearx
	deltax = x[1] - nearx

	# Compute the number of derivatives needed.
	nd = nder
	if (nder > nterms)
	    nd = nterms

	# Generate the polynomial coefficients.

	if (ASI_TYPE(asi) == II_SPLINE3) {

	    pcoeff[1] = COEFF(n0-1) + 4. * COEFF(n0) + COEFF(n0+1)
	    pcoeff[2] = 3. * (COEFF(n0+1) - COEFF(n0-1))
	    pcoeff[3] = 3. * (COEFF(n0-1) - 2. * COEFF(n0) + COEFF(n0+1))
	    pcoeff[4] = -COEFF(n0-1) + 3. * COEFF(n0) - 3. * COEFF(n0+1) +
				    COEFF(n0+2)

	# Newton's form written in line to get polynomial from data
	} else {

	    # Load data.
	    do i = 1, nterms
		diff[i] = COEFF(n0 - nterms/2 + i)

	    # Generate difference table.
	    do k = 1, nterms - 1
		do i = 1, nterms - k
		    diff[i] = (diff[i+1] - diff[i]) / k

	    # Shift to generate polynomial coefficients.
	    do k = nterms, 2, -1
		do i = 2,k
		    diff[i] = diff[i] + diff[i-1] * (k - i - nterms/2)
	    do i = 1,nterms
		pcoeff[i] = diff[nterms + 1 - i]
	}

	# Compute the derivatives. As the loop progresses pcoeff contains
	# coefficients of higher and higher derivatives.

	do k = 1, nd {

	    # Evaluate using nested multiplication.
	    accum = pcoeff[nterms - k + 1]
	    do j = nterms - k, 1, -1
		accum = pcoeff[j] + deltax * accum
	    der[k] = accum

	    # Differentiate polynomial.
	    do j = 1, nterms - k
		pcoeff[j] = j * pcoeff[j + 1]
	}
end