SUBROUTINE CSPLN(X,Y,C,N) * Calculation of spline coefficients from N pairs x,y in * arrays X(N) and Y(N) (array X in increasing order), using the * not-a-knot end conditions. * The array C, dimensioned C(5,N), contains after return * C(1,I) = F(X(I)) = Y(I) * C(2,I) = first derivative F'(X(I)) * C(3,I) = second derivative F''(X(I))/2.0 * C(4,I) = third derivative F'''(X(I))/6.0 * C(5,I) = X(I) * and can be used for interpolation. * Calculation of interpolated value for given X * with X(I) =< X =< X(I+1): * H=X-C(5,I) * F=C(1,I)+H*(C(2,I)+H*(C(3,I)+H*C(4,I))) * REAL C(5,*),X(*),Y(*) IF(N.LT.3) RETURN DO I=1,N C(1,I)=Y(I) C(5,I)=X(I) END DO * first differences of x and first divided differences of data DO I=2,N C(3,I)= C(5,I)-C(5,I-1) C(4,I)=(C(1,I)-C(1,I-1))/C(3,I) END DO * not-a-knot at left side C(4,1)=C(3,3) C(3,1)=C(3,2)+C(3,3) C(2,1)=((C(3,2)+2.0*C(3,1))*C(4,2)*C(3,3)+C(3,2)**2*C(4,3))/C(3,1) * generate equations and carry out forward pass DO I=2,N-1 G=-C(3,I+1)/C(4,I-1) C(2,I)=G*C(2,I-1)+3.0*(C(3,I)*C(4,I+1)+C(3,I+1)*C(4,I)) C(4,I)=G*C(3,I-1)+2.0*(C(3,I)+C(3,I+1)) END DO * not-a-knot at right side IF(N.EQ.3) THEN C(2,N)=2.0*C(4,N) C(4,N)=1.0 G=-1.0/C(4,N-1) ELSE G=C(3,N-1)+C(3,N) C(2,N)=((C(3,N)+2.0*G)*C(4,N)*C(3,N-1)+C(3,N)**2*(C(1,N-1) + -C(1,N-2))/C(3,N-1))/G G=-G/C(4,N-1) C(4,N)=C(3,N-1) END IF * complete forward pass C(4,N)=C(4,N)+G*C(3,N-1) C(2,N)=(G*C(2,N-1)+C(2,N))/C(4,N) * backward substitution DO I=N-1,1,-1 C(2,I)=(C(2,I)-C(3,I)*C(2,I+1))/C(4,I) END DO * generate coefficients DO I=2,N DX=C(3,I) DVD1=(C(1,I)-C(1,I-1))/DX DVD3=C(2,I-1)+C(2,I)-2.0*DVD1 C(3,I-1)=(DVD1-C(2,I-1)-DVD3)/DX C(4,I-1)=(DVD3/DX)/DX END DO * calculation of coefficients at x(n) (for completeness only) DX=C(5,N)-C(5,N-1) C(2,N)=C(2,N-1)+DX*(2.0*C(3,N-1)+DX*3.0*C(4,N-1)) C(3,N)=C(3,N-1)+DX*3.0*C(4,N-1) C(4,N)=C(4,N-1) END FUNCTION CSPF(X,C,N) * Calculate function value for given argument X, for spline * function in array C, dimensioned C(5,N), obtained by previous * call of CSPLN. REAL C(5,N) DATA I/1/ IF(I.GE.N) I=(N+1)/2 IF(X.GE.C(5,I)) THEN ! make use of previous index IH=MIN(I+2,N-1) IF(X.GE.C(5,IH)) IH=N-1 IL=I ELSE IL=MAX(I-2,1) IF(X.LT.C(5,IL)) IL=1 IH=I END IF 10 I=(IL+IH)/2 ! binary search IF(I.NE.IL) THEN IF(X.GE.C(5,I)) THEN IL=I ELSE IH=I END IF GOTO 10 END IF H=X-C(5,I) CSPF=C(1,I)+H*(C(2,I)+H*(C(3,I)+H*C(4,I))) END SUBROUTINE USPCN(Y,A,N,G,H) * Calculation of B-spline coefficients A(N) from equidistant function * values in array Y(N), using the not-a-knot condition. * Arrays Y(*) and A(*) may be identical. * G(N) and H(N) are auxiliary arrays used during computation. REAL Y(N),A(N),G(N),H(N) DO I=2,N G(I)=Y(I)-Y(I-1) END DO H(1)=(5.0*G(2)+G(3))/2.0 H(2)=-H(1)+3.0*(G(3)+G(2)) G(2)=2.0 DO I=3,N-1 H(I)=-H(I-1)/G(I-1)+3.0*(G(I+1)+G(I)) G(I)=4.0-1.0/G(I-1) END DO H(N)=(5.0*G(N)+Y(N-1)-Y(N-2))/2.0 G(N)=1.0-2.0/G(N-1) * backward ... H(N)=(-2.0*H(N-1)/G(N-1)+H(N))/G(N) DO I=N-1,2,-1 H(I)=(H(I)-H(I+1))/G(I) END DO H(1)=(H(1)-2.0*H(2)) * ... and forward solution ALN=Y(N)+Y(N)-Y(N-1)-(2.0*H(N)+H(N-1))/3.0 DO I=1,N-1 A(I)=Y(I)+Y(I)-Y(I+1)+(2.0*H(I)+H(I+1))/3.0 END DO A(N)=ALN END FUNCTION USPF(X,A,N,XA,XB) * Returned is the function value at X of B-spline function. * A(N) is array of coefficients, obtained from USPCN. * XA and XB are X-values of first and last function value * Extrapolation is done for X outside the range XA ... XB. REAL A(N) R=FLOAT(N-1)*(X-XA)/(XB-XA) I=MAX(1,MIN(INT(R),N-3)) Z=R-FLOAT(I) USPF + =(A(I)+4.0*A(I+1)+A(I+2)+Z*(3.0*(-A(I)+A(I+2)) + +Z*(3.0*(A(I)-2.0*A(I+1)+A(I+2)) + +Z*(-A(I)+3.0*A(I+1)-3.0*A(I+2)+A(I+3)))))/6.0 END SUBROUTINE BSPLNK(X,K,B,L,T) * Returned are B(1)...B(K) of B-spline values for given X and order K * K = order of spline (1=const, 2=linear...) up to limit K=KMAX * The array T(*) contains the knot positions. * In T(K-1) =< x < T(M+2-K) the K B-spline values add up to 1. * Multiple knots allowed: (K - mult)-th derivative is discontinuous. PARAMETER (KMAX=10) REAL B(K),DL(KMAX-1),DR(KMAX-1),SV,TR,T(*) IF(K.GT.KMAX) STOP ' BSPLNK: K too large ' B(1)=1.0 DO J=1,K-1 DR(J)=T(L+J)-X DL(J)=X-T(L-J+1) SV=0.0 DO I=1,J TR =B(I)/(DR(I)+DL(J-I+1)) B(I)=SV+TR*DR(I) SV = TR*DL(J-I+1) END DO B(J+1)=SV IF(B( 1)+1.0.EQ.1.0) B( 1)=0.0 ! avoid underflows IF(B(J+1)+1.0.EQ.1.0) B(J+1)=0.0 END DO END SUBROUTINE BSKFIT(X,Y,W,N,KS,T,NKN,C) * Least squares spline fit of B-spline of order KS to * data Y in array Y(N), with abscissa values X in arrays X(N) * and weights W in array W(N). * The array T(NKN) contains NKN (ordered) knot positions. * The resulting B-spline coefficients are in array of dimension * NDIM = NKN-KS+1, i.e. C(NKN-KS+1). * Limitation: NDIM <= ND; KS <= 10 REAL X(N),Y(N),W(N), T(NKN),C(*) ! C(NKN-KS+1) PARAMETER (ND=100) REAL Q(4*ND),B(10) DO I=1,NKN-KS+1 ! reset normal equation C(I)=0.0 END DO DO I=1,KS*(NKN-KS+1) Q(I)=0.0 END DO DO K=1,N L=MAX(KS-1,MIN(LEFT(X(K),T,NKN),NKN-KS+1)) !index within limits CALL BSPLNK(X(K),KS,B,L,T) ! calculate B-splines DO I=1,KS ! add to normal equation C(I+L-KS+1)=C(I+L-KS+1)+B(I)*Y(K)*W(K) IQ=1+KS*(I+L-KS)-I DO J=I,KS Q(J+IQ)=Q(J+IQ)+B(I)*B(J)*W(K) END DO END DO END DO CALL BMSOL(Q,C,KS,NKN-KS+1) ! solve band matrix equation END FUNCTION BSKFUN(X,K,T,NKN,C) * Returned is the function value at X of B-spline function of * order K within the knot range. * C is the array of coefficients, and T(NKN) is the knot array. PARAMETER (KMAX=10) REAL T(NKN),B(KMAX),C(*) DOUBLE PRECISION SUM L=MAX(K-1,MIN(LEFT(X,T,NKN),NKN-K+1)) ! index within limits CALL BSPLNK(X,K,B,L,T) ! calculate four B-splines SUM=B(1)*C(L-K+2) DO I=2,K SUM=SUM+B(I)*C(I+L-K+1) END DO BSKFUN=SUM END SUBROUTINE ORTHFT(X,Y,W,N,NPAR,Q,P) * Construction of orthogonal polynomials from * data Y in array Y(N), with abscissa values X in arrays X(N) * and weights W in array W(N) with NPAR parameters (up to order * NPAR-1 of the polynomial. * Q(2,N) is an auxiliary array, used during computation. * The array P, dimensioned P(5,NPAR), contains after return * the result of the fit, to be used in subroutine ORTHFE later. * P(1,i) = alpha P(1,1) = 100*N + NPAR * P(2,i) = beta P(2,1) = variance estimate * P(3,i) = gamma P(3,1) = p0(x) (constant) * P(4,i) = coefficient * P(5,i) = remaining chi**2 REAL X(N),Y(N),W(N),Q(2,N),P(5,NPAR) * Double precision for the accumulation of sums DOUBLE PRECISION ABGDS(5),AL,BE,GA,DE,SQSUM EQUIVALENCE (ABGDS(1),AL),(ABGDS(2),BE),(ABGDS(3),GA), + (ABGDS(4),DE),(ABGDS(5),SQSUM) NP=NPAR DO J=1,5 ABGDS(J)=0.0D0 END DO * determination of constant term DO I=1,N GA=GA+W(I) ! sum of weights DE=DE+W(I)*Y(I) ! weighted y sum END DO IF(GA.NE.0.0) GA=1.0D0/SQRT(GA) DE =GA*DE DO I=1,N SQSUM =SQSUM+W(I)*(Y(I)-GA*DE)**2 ! sum of squared residuals Q(1,I)=GA ! initialize Q array Q(2,I)=0.0 END DO DO J=1,5 P(J,1)=ABGDS(J) ! store parameters END DO * recursive loop for higher terms IAM=1 DO K=2,NP IAM=3-IAM DO J=1,4 ABGDS(J)=0.0D0 END DO DO I=1,N AL=AL+W(I)*X(I)*Q(3-IAM,I)**2 ! sum x*f(j-1)**2 BE=BE+W(i)*X(I)*Q(IAM,I)*Q(3-IAM,I) ! sum f(j-2)*f(j-2) END DO DO I=1,N Q(IAM,I)=(X(I)-AL)*Q(3-IAM,I)-BE*Q(IAM,I) ! unnormalized f(j) GA=GA+W(I)*Q(IAM,I)*Q(IAM,I) ! sum for normalization END DO IF(GA.NE.0.0) GA=1.0/DSQRT(GA) DO I=1,N Q(IAM,I)=GA*Q(IAM,I) ! normalize f(j) DE=DE+W(I)*Q(IAM,I)*Y(I) ! sum for coefficient END DO SQSUM=MAX(0.0D0,SQSUM-DE*DE) ! update sum of squares DO J=1,5 P(J,K)=ABGDS(J) ! store parameters END DO END DO P(1,1)=FLOAT(100*N+NP) ! dimension parameter P(2,1)=1.0 ! factor for error calculation END SUBROUTINE ORTHFE(X,P,Y,DY) * Return function value Y and error DY of the orthogonal polynomial * at the abscissa value X, using the array P (see ORTHFT) REAL X,Y,DY,P(5,*) DOUBLE PRECISION Q(2),F,DF NP=MOD(P(1,1),100.0)+0.5 Q(1)=P(3,1) ! constant term Q(2)=0.0 F =P(3,1)*P(4,1) DF=P(3,1)*P(3,1) IAM=1 DO K=2,NP IAM=3-IAM ! recurrence relation for higher terms Q(IAM)=((X-P(1,K))*Q(3-IAM)-P(2,K)*Q(IAM))*P(3,K) F =F +P(4,K)*Q(IAM) DF=DF+Q(IAM)*Q(IAM) END DO Y =F ! function value DY=SQRT(DF*P(2,1)) ! standard deviation END