c--gnoise.f
c--orders a number of files according to noise content
c---------------------------------------------------------------------
      program GNOISE
      parameter(ndim=180000)
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      dimension x(ndim),y(ndim),f(400),rm(400),
     &          a(10,10),b(10)
      character*60 title
      character*40 fname1,fname2,fname(400)
      character*20 fmt,dunit,tunit
      character*5 fday
      character*3 fext
      character*1 ans
      common // x,y
c
c--initialise
      ideg = 9
      maxp = ideg+1
c
c--files opened :
c  (input)
c       1 = data (residual file)
c  (output)
c       2 = data with polynomial subtracted
c       3 = ordered list of files
c
c--choose which files to be processed
      write(*,'(/a)') ' Program GNOISE'
      write(*,'(a)')  ' -------------------------------------------'
      write(*,'(a$)') ' Input filename extension (e.g. plm) --> '
      read(*,*) fext
      write(*,'(a$)') ' Enter first day to be processed     --> '
      read(*,*) iday1
      write(*,'(a$)') ' ..... last day ................     --> '
      read(*,*) iday2
c--if polynomial not already removed, ask about output data
      if(fext.ne.'dmp') then
        write(*,'(a$)') ' Write data minus polynomial [y/n]   --> '
        read(*,'(a1)') ans
        zwpoly = .false.
        if(ans.eq.'y') zwpoly=.true.
      endif
c
c--try to find specified files for the days specified
      kk = 0
      kday = iday1
c
c--convert kday to a character string 'fday '
   5  call intch(kday,fday)
c--then transfer fday to the input filename
      call fnday(fname1,'g',fday,fext)
c--check to see if input file exists
      inquire(file = fname1,exist =zexist)
      if(zexist) goto 8
      write(*,'(a,i5)') ' No input file found for day ',kday
      goto 10
c
c--copy the filename to the array
   8  kk = kk+1
      fname(kk) = fname1
c--make sure first good file begins the sequence
      if(kk.eq.1) iday1 = kday
c--try another day
  10  kday = kday+1
      if(kday.le.iday2) goto 5
c--there are kmax days to be processed
      kmax = kk
      k = 1
c
c--select a day from the list
  15  fname1 = fname(k)
c--give filename extension for output file and extract fday
      fname2 = fname1
      call fnext2(fname2,fday,'dmp')
      call chint(fday,kday)
c
c--read the data
      write(*,*) '  reading: ',fname(k)
      open(1,file=fname1)
      read(1,'(a)') title
      read(1,'(i10,g12.5)') np,delt
      read(1,'(3a20)') fmt,dunit,tunit
      read(1,fmt) (y(i),i=1,np)
      close(1)
c
c--if this is alread a 'dmp' file, then go directly to the statistics
      if(fext.eq.'dmp') goto 65
c
c--find and subtract 9th degree polynomial using pfit subroutine
c      write(*,*) '  fitting polynomial'
      do 20 i=1,np
        x(i) = float(i)
  20  continue
      call pfit(x,y,1,np,maxp,a,b)
c      write(*,'(5f12.5)') (b(i),i=1,maxp)
      do 60 ii=1,np
        sum = b(maxp)
        do 40 jj=maxp-1,1,-1
          sum = x(ii)*sum+b(jj)
  40    continue
        y(ii) = y(ii)-sum
  60  continue
c
c--write the data minus polynomial
      if(zwpoly) then
        write(*,*) '  writing: ',fname2
        open(2,file=fname2)
        write(2,'(a)') ' data minus polynomial'
        write(2,'(i10,g12.5)') np,delt
        write(2,'(3a20)') fmt,dunit,tunit
        write(2,fmt) (y(i),i=1,np)
        close(2)
      endif
c
c--remove mean
  65  call meanv(y,np,ymean,1)
c
c--find the rms deviation
      rms = 0.d0
      do 70 i=1,np
        rms = rms+(y(i)-ymean)**2
  70  continue
      rms = dsqrt(rms/float(np))
      f(k) =  float(kday)
      rm(k) = rms
      write(*,'(a8,i8,a5,f10.5)') '   day: ',kday,' rms ',rms
c
c--get another file
      k = k+1
      if(k.le.kmax) goto 15
c
c--sort the days according to rms
      call sort(rm,f,kmax)
c--write final output
      open(3,file='gnoise.out')
      write(3,'(a)') '     day      rms noise '
      write(3,'(a)') '------------------------'
      do 80 k=1,kmax
        kday = f(k)
        write(3,'(i10,f12.5)') kday,rm(k)
  80  continue
c
      stop
      end
c------------------------------------------------------------------------------
      subroutine meanv(y,n,ymean,kk)
c
c--find and possibly remove mean value from a data set
c--kk = 0 find mean
c--kk = 1 find and remove mean
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      dimension y(1)
c
      ymean = 0.d0
      do 10 i = 1,n
        ymean = ymean + y(i)
  10  continue
      ymean = ymean/float(n)
      if(kk.ne.1) return
c
      do 20 i = 1,n
        y(i) = y(i)-ymean
  20  continue
c
      return
      end
c----------------------------------------------------------------------------
      subroutine fnday(fname,p,fday,ext)
c
c--creates a filename fname from prefix 'p' plus
c--root 'fday' plus extension 'ext'
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      character*40 fname,fnamec
      character*5 fday,fdayc
      character*3 ext,extc
      character*1 p,dum(40),dum3(3),dum5(5)
      equivalence (fnamec,dum),(extc,dum3),(fdayc,dum5)

c--length of prefix is 1, fday is 5 and extension 3, total 10

      fdayc = fday
      extc = ext
      dum(1) = p
      do 10 i = 2,6
        dum(i) = dum5(i-1)
 10   continue
      dum(7) = '.'
      dum(8) = dum3(1)
      dum(9) = dum3(2)
      dum(10) = dum3(3)
      do 20 i = 11,40
        dum(i) = ' '
 20   continue
      fname = fnamec

      return
      end
c---------------------------------------------------------------------
      subroutine fnext2(fname2,fday,ext)
c
c changes the name of file fname2
c gives extension '.ext', where 'ext' is provided on input
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      character*40 fname2,fnamec
      character*5 fday,fdayc
      character*3 ext,extc
      character*1 dum(40),dum3(3),dum5(5)
      equivalence (fnamec,dum),(extc,dum3),(fdayc,dum5)
c
c original length of filename is 'len0'
c find length of extension 'len3' by searching last 4 characters
c
      fnamec = fname2
      len0 = lstr(fnamec,-40)
      len3 = 0
      ltmp = 0
      do 5 i = 1,4
        l = len0-i+1
        if(l.eq.0) goto 6
        if(dum(l).eq.'.') then
          len3 = ltmp+1
          goto 6
        endif
        ltmp = ltmp+1
   5  continue
c
c set fday to first segment name minus the 'g'
c
   6  do 10 i = 1,5
        dum5(i) = dum(i+1)
  10  continue
      fday = fdayc
c
c  add extension '.ext'
c
  20  extc = ext
      len2 = len0-len3
      dum(len2+4) = dum3(3)
      dum(len2+3) = dum3(2)
      dum(len2+2) = dum3(1)
      dum(len2+1) = '.'
      fname2 = fnamec
c
      return
      end
c------------------------------------------------------------------
      subroutine intch(iday,fday)
c
c--convert integer 'iday' to character string 'fday'
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      character*5 fday,fdayc
      character*1 dum(5)
      equivalence (fdayc,dum)
c
      n = iday
      do 10 i = 1,5
        k = n-10*(n/10)
        dum(6-i) = char(k+48)
        n = n/10
 10   continue
      fday = fdayc

      return
      end
c-----------------------------------------------------------------------------
      subroutine chint(fday,kday)
c
c--converts a 5-character string to an integer
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      character*5 fday,fdayc
      character*1 dum(5)
      equivalence (fdayc,dum)
c
      fdayc = fday
      kday = 0
      do 10 i = 1,5
        k = ichar(dum(6-i))-48
        kday = kday+ k*(10**(i-1))
 10   continue
c
      return
      end
c----------------------------------------------------------------------
      subroutine sort(d,t,n)
c
c Subroutine to sort vector t into ascending order of vector d
c Algorithm is based on Shell-Metzner sort (Miller, A.R., 1982. FORTRAN
c programs for scientists and engineers. Sybex)
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      dimension d(1),t(1)
c
      jump = n
  10  jump = jump/2
      if(jump.eq.0) return
      j2 = n-jump
      do 30 j = 1,j2
        i = j
  20    j3 = i+jump
        if(d(i).le.d(j3)) goto 30
        call swap(d(i),d(j3))
        call swap(t(i),t(j3))
        i = i-jump
        if(i.gt.0) goto 20
  30  continue
      goto 10
c
      end
c....................................................
      subroutine swap(a,b)
c
c swaps any two real variables
c
      implicit real*8(a-h,o-y)
c
      hold = a
      a = b
      b = hold
c
      return
      end
c------------------------------------------------------------------------------
      subroutine pfit(x,y,i1,i2,m,a,b)
c
c--fits a polynomial to data in arrays (x(i), y(i), i=i1,i2)
c--the number of coefficients of the polynomial is m (degree = m-1)
c--the arrays must be dimensioned as follows :
c--       x, y : any length
c--       a    : (10,10)
c--       b    : (10)
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      dimension x(1),y(1),
     &          a(10,10),alud(10,10),b(10)
      data np/10/
c
c--zero arrays
c
      do 5 j = 1,10
        b(j) = 0.d0
        do 5 i = 1,10
          a(i,j) = 0.d0
          alud(i,j) = 0.d0
   5  continue
c
c--set up arrays
c
      do 40 j = 1,m
        sumb = 0.d0
        j1 = j-1
        do 10 i = i1,i2
          sumb = sumb+y(i)*(x(i)**j1)
  10    continue
        b(j) = sumb
        do 30 k =1,m
          jk = j+k-2
          suma = 0.d0
          do 20 i = i1,i2
            suma = suma + x(i)**jk
  20      continue
          a(j,k) = suma
  30    continue
  40  continue
c--solve
      call deqn(.false.,a,alud,b,m,np,6,*999)
c
c--coefficients are returned to main program in array b
        return
 999    write(6,'(a)') ' error returned from deqn '
        stop
        end
c-----------------------------------------------------------------------------
      subroutine deqn(zdet,a,alud,b,n,np,iout,*)
c
c  organises equation solution and determinant calculation
c  equations are   a . x = b   on exit solution is in b
c  if zdet=.true. only determinant of matrix a is returned in b(1)
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      parameter(nmax=20)
      real*8 a(np,np),b(np),indx(nmax),alud(np,np),bsave(nmax)
      data big/1.d50/
c
c if zdet=.true. find the determinant of matrix a
c do lu decomposition, note a is replaced
c
      if(zdet) then
        call ludcmp(a,n,np,indx,d,iout,*99)
        do 11 j=1,n
          if(dabs(d).gt.big) then
            write(iout,'(a)') ' error from deqn. determinant too big'
            goto 99
          endif
          d=d*a(j,j)
  11      continue
        b(1)=d
      else
c
c solve linear system, copy a to alud and b to bsave
c
        do 12 j=1,n
          bsave(j)=b(j)
          do 12 i=1,n
            alud(i,j)=a(i,j)
  12        continue
c--lu decomposition returned in alud
        call ludcmp(alud,n,np,indx,d,iout,*99)
c--back substitution destroys b, leaves alud unchanged
        call lubksb(alud,n,np,indx,b)
c--iterative improvement of b requires original a matrix and b vector
        call mprove(a,alud,n,np,indx,bsave,b)
      endif
      return
c
  99  return 1
      end
c---------------------------------------------------------------------------
      subroutine ludcmp(a,n,np,indx,d,iout,*)
c
c lower-upper decomposition
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      parameter (nmax=20)
      real*8 a(np,np),indx(n),vv(nmax)
      data tiny/1.d-20/
c
      d=1.d0
      do 12 i=1,n
        aamax=0.d0
        do 11 j=1,n
          aamax=dmax1(aamax,dabs(a(i,j)))
  11      continue
        if(aamax.eq.0.d0) then
          write(iout,'(a)') ' error from ludcmp. singular matrix '
          return 1
        endif
        vv(i)=1.d0/aamax
  12    continue
      do 19 j=1,n
        if(j.gt.1) then
          do 14 i=1,j-1
            sum=a(i,j)
            if(i.gt.1) then
              do 13 k=1,i-1
                sum=sum-a(i,k)*a(k,j)
  13            continue
              a(i,j)=sum
            endif
  14      continue
        endif
        aamax=0.d0
        do 16 i=j,n
          sum=a(i,j)
          if(j.gt.1) then
            do 15 k=1,j-1
              sum=sum-a(i,k)*a(k,j)
   15         continue
            a(i,j)=sum
          endif
          dum=vv(i)*dabs(sum)
          if(dum.ge.aamax) then
            imax=i
            aamax=dum
          endif
  16      continue
        if(j.ne.imax) then
          do 17 k=1,n
            dum=a(imax,k)
            a(imax,k)=a(j,k)
            a(j,k)=dum
  17        continue
          d=-d
          vv(imax)=vv(j)
        endif
        indx(j)=imax
        if(j.ne.n) then
          if(a(j,j).eq.0.d0) a(j,j)=tiny
          dum=1.d0/a(j,j)
          do 18 i=j+1,n
            a(i,j)=a(i,j)*dum
  18        continue
        endif
  19    continue
      if(a(n,n).eq.0.d0) a(n,n)=tiny
c
      return
      end
c----------------------------------------------------------------------------
      subroutine lubksb(a,n,np,indx,b)
c
c backsubstitution
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      real*8 a(np,np),indx(n),b(n)
c
      ii=0
      do 12 i=1,n
        ll=indx(i)
        sum=b(ll)
        b(ll)=b(i)
        if(ii.ne.0) then
          do 11 j=ii,i-1
            sum=sum-a(i,j)*b(j)
  11        continue
        elseif(sum.ne.0.d0) then
          ii=i
        endif
        b(i)=sum
  12    continue
      do 14 i=n,1,-1
        sum=b(i)
        if(i.lt.n) then
          do 13 j=i+1,n
            sum=sum-a(i,j)*b(j)
  13        continue
        endif
        b(i)=sum/a(i,i)
  14    continue
c
      return
      end
c-------------------------------------------------------------------
      subroutine mprove(a,alud,n,np,indx,b,x)
c
c improves solution to de's
c
      implicit real*8(a-h,o-y),integer*4(i-n),logical(z)
      parameter (nmax=20)
      real*8 a(np,np),alud(np,np),indx(n),b(n),x(n),r(nmax)
c
      do 12 i=1,n
        sdp=-b(i)
        do 11 j=1,n
          sdp=sdp+a(i,j)*x(j)
  11      continue
        r(i)=sdp
  12    continue
      call lubksb(alud,n,np,indx,r)
      do 13 i=1,n
        x(i)=x(i)-r(i)
  13    continue
c
      return
      end
c----------------------------------------------------------------------------
      function lstr(name,n)
c
c function to return the length of a string. On input the string
c 'name' has a nominal length n; if n is negative, blank characters
c at the beginning of 'name' are first truncated.
c
      character*1 name(1)
c
c--zero length case first
      if(n.eq.0) then
        lstr = 0
        return
      endif
      k = 0
      ld = n
c
c--ld is negative, we truncate leading blanks
      if(ld.lt.0) then
        ld = -ld
        j = 0
  10    j = j+1
        if(name(j).eq.' ') goto 10
        nb = j-1
c
c--there are nb blanks to be erased in front of 'name'
        if(nb.gt.0) then
          do 20 i = nb+1,ld
            name(i-nb) = name(i)
            name(i) = ' '
  20      continue
c
c--reduce length of string by number of blanks
          ld = ld-nb
        endif
      endif
c
c--ld is non-zero, find length of string
c--first set true length equal to nominal length
      k = ld+1
c--and decrease k until a non-blank character appears or beginning
c--of string is reached
  40  k = k-1
      if(k.gt.0.and.name(k).eq.' ') goto 40
      lstr = k
c
      return
      end
