Fortran 90 Toolkit to Accompany "A Class of Fast Methods for Processing Irregularly Sampled or Otherwise Inhomogeneous One-Dimensional Data" by George B. Rybicki and William H. Press What this file is: This file contains several Fortran 90 modules, with *very* brief explanations, which collectively implement the methods described in the above-named paper. The purpose of this file is to make algorithmically precise the necessarily abbreviated descriptions in the paper. It is intended that the user treat this file as a "toolkit", using bits and pieces as needed for implementing his/her own applications. What this file IS NOT: It is NOT polished, ready-to-use software. It is NOT guaranteed to be free of all bugs, or to treat properly all exceptional cases that might arise. It is NOT the authors' last word on this subject -- our development of algorithms and applications continues. (This file, as accompanying the above-named paper, will NOT be updated after the paper is published in final form.) And, it is NOT a programming text in Fortran 90. Why Fortran 90? A couple of reasons. (1) That language's vector and matrix constructions allow for quite concise (and potentially quite elegant) expression of our algorithms. (2) This research happened to overlap in time one author's (WHP) work a forthcoming new version of the book "Numerical Recipes", which will be in Fortran 90. The best introduction to Fortran 90 is the book "Fortran 90 Explained" by Metcalf and Reid (Oxford University Press, 1992). Fortran 90 compilers for most types of workstations are in late stages of development and will be available (if not already) by late 1994. This work was done on a DEC 3000/600 (Alpha) workstation, using a Field Test version of DEC Fortran 90. Copyright Notice: Portions of this file (those derived from the Numerical Recipes books) are Copyright 1986-1992 by Numerical Recipes Software. Permission is granted for the unlimited noncommercial use of the routines included herein, PROVIDED THAT such use (unless authorized by an additional license) is exclusively in support of, and incidental to, the use of the algorithms described in the above-named paper. ********file reestimate.f90***************************** ! This module contains the user-callable routines remap and reest. ! Remap "rectifies" irregularly spaced data (y) known (with errors sig) on ! one set of x's to data (yout) on a different, generally interleaved, ! set of xout's. The data is characterized by a single scalar population ! variance (psig**2) and a single inverse decorrelation distance w. ! All quantities are input, except yout, which is output. ! Reest is a lower-level routine that reestimates a single data set ! (x,y,sig) onto a set of improved y values yout, located at the same ! data points x. Now psig and w are general vectors. The optional ! argument ybar, if present, causes an unbiased (Gauss-Markov) estimate ! to be used (essentially removing and then restoring the mean of the ! data) and returns the value of the data's mean. The optional argument ! chisq, if present, causes the chi-square of the data's internal ! consistency to be returned as chisq. ! A trivial test routine is appended (commented out). MODULE reestimate CONTAINS SUBROUTINE remap(x,y,sig,psig,w,xout,yout) IMPLICIT NONE INTEGER :: n,nout,i,j,k,m,ntot REAL :: psig,w,ave REAL, DIMENSION(:) :: x,y,sig,xout,yout REAL, DIMENSION(:), ALLOCATABLE :: xx,yy,ppsig,ssig,ww,yyout INTEGER, DIMENSION(:), ALLOCATABLE :: iflag n=size(x) nout=size(xout) if (size(y) /= n .or. size(sig) /= n .or. size(yout) /= nout) & call nrerror('remap: wrong sizes') if (any(x(2:n)<=x(1:n-1)).or.any(xout(2:nout)<=xout(1:nout-1))) & call nrerror('remap: values must be distinct and ordered') ave=sum(y)/n ntot=n+nout allocate(xx(ntot),yy(ntot),ppsig(ntot),ssig(ntot),ww(ntot), & yyout(ntot),iflag(ntot)) iflag=0 j=1 k=1 do m=1,ntot if(j>n.or.k>nout) exit if (x(j)<=xout(k)) then iflag(m)=j j=j+1 else ! (x(j)>xout(k)) iflag(m)=-k k=k+1 endif enddo if (j<=n) iflag(m:ntot)=(/ (i,i=j,n) /) if (k<=nout) iflag(m:ntot)=(/ (-i,i=k,nout) /) where (iflag>0) xx=x(iflag) yy=y(iflag) ssig=sig(iflag) ppsig=psig ww=w elsewhere xx=xout(-iflag) yy=ave ssig=100.*psig ppsig=psig ww=w end where call reest(xx,yy,ppsig,ssig,ww(1:ntot-1),yyout) yout=pack(yyout,iflag<0) END SUBROUTINE SUBROUTINE reest(x,y,psig,sig,w,yout,ybar,chisq) IMPLICIT NONE REAL, DIMENSION(:) :: x,y,psig,sig,w,yout REAL, OPTIONAL :: ybar,chisq REAL, PARAMETER :: TINY=1.e-4 INTEGER :: n REAL, DIMENSION(size(x)) :: b,temp,bb,e REAL, DIMENSION(size(x)-1) :: a,c,r,aa,cc n=size(x) if (size(y) /= n.or.size(psig) /= n.or.size(sig) /= n.or.size(yout) & /= n.or.size(w) /= n-1) call nrerror('reest: wrong sizes') if (any(x(2:n) irc(1) icol => irc(2) n=size(a,1) m=size(b,2) ipiv=0 do i=1,n mask = spread(ipiv==0,1,n).and.spread(ipiv==0,2,n) irc=maxloc(abs(a),mask) ipiv(icol)=ipiv(icol)+1 if(count(ipiv>1)/=0) call nrerror('singular matrix') if(irow/=icol) then call SWAP(a(irow,:),a(icol,:)) call SWAP(b(irow,:),b(icol,:)) endif indxr(i)=irow indxc(i)=icol if(a(icol,icol)==0.) call nrerror('SINGULAR MATRIX') pivinv=1./a(icol,icol) a(icol,icol)=1. a(icol,:)=a(icol,:)*pivinv b(icol,:)=b(icol,:)*pivinv dumc=a(:,icol) a(:,icol)=0. a(icol,icol)=pivinv mask=.true. mask(icol,:)=.false. where(mask) a=a-spread(a(icol,:),1,n)*spread(dumc,2,n) maskb=.true. maskb(icol,:)=.false. where(maskb) b=b-spread(b(icol,:),1,n)*spread(dumc,2,m) enddo do l=n,1,-1 call SWAP(a(:,indxr(l)),a(:,indxc(l))) enddo return END SUBROUTINE gaussj SUBROUTINE swap(a,b) REAL, DIMENSION(:) :: a,b REAL, DIMENSION(SIZE(a)) :: dum dum=a a=b b=dum END SUBROUTINE swap SUBROUTINE mux(x1,x2,flag) IMPLICIT NONE REAL, DIMENSION(:) :: x1,x2 LOGICAL, DIMENSION(:) :: flag INTEGER :: n1,n2,nt,j,k,m n1=size(x1) n2=size(x2) nt=n1+n2 if (size(flag) /= nt) call nrerror('mux: flag wrong size') if (any(x1(2:n1)n1.or.k>n2) exit if (x1(j)<=x2(k)) then flag(m)=.true. j=j+1 else flag(m)=.false. k=k+1 endif enddo if (j<=n1) then flag(m:nt)=.true. else if (k<=n2) then flag(m:nt)=.false. endif END SUBROUTINE mux END MODULE ! program test_fast_fitting ! USE fast_fitting ! INTEGER, PARAMETER :: N=200,NEL=199 ! REAL :: x(N),y(N),sig(N),xel(NEL),el(NEL,3),q(3) !1 write (*,*) 'guess f (20 is right):' ! read (*,*) f ! eps=0.001 ! x=(/ (i+0.5*sin(197.*i),i=1,N) /) ! xel=(/ (i+.33,i=1,NEL) /) ! y=7.0*sin(x/20.)+5.0*sin(x/30.) +eps*sin(1000.*x) ! el(:,1)=sin(xel/f) ! el(:,2)=sin(xel/30.) ! el(:,3)=1. ! sig=eps ! psig=100. ! pw=1./30. ! call fastfit(x,y,sig,psig,pw,xel,el,q,chisq) ! write (*,*) 'q=',q,' chisq=',chisq ! goto 1 ! END ******************end file***************************