C @(#)smosub3.for	13.1.1.1 (ESO-DMD) 06/02/98 18:11:31
C===========================================================================
C Copyright (C) 1995 European Southern Observatory (ESO)
C
C This program is free software; you can redistribute it and/or 
C modify it under the terms of the GNU General Public License as 
C published by the Free Software Foundation; either version 2 of 
C the License, or (at your option) any later version.
C
C This program is distributed in the hope that it will be useful,
C but WITHOUT ANY WARRANTY; without even the implied warranty of
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
C GNU General Public License for more details.
C
C You should have received a copy of the GNU General Public 
C License along with this program; if not, write to the Free 
C Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
C MA 02139, USA.
C
C Correspondence concerning ESO-MIDAS should be addressed as follows:
C	Internet e-mail: midas@eso.org
C	Postal address: European Southern Observatory
C			Data Management Division 
C			Karl-Schwarzschild-Strasse 2
C			D 85748 Garching bei Muenchen 
C			GERMANY
C===========================================================================
C
      SUBROUTINE NORMIT(A,NDIM)
C
      IMPLICIT NONE
C
      INTEGER  NDIM,N
      REAL     A(NDIM),R
      DOUBLE PRECISION   SUM,DR
C
      SUM = 0.D0
      DO 1000, N=1,NDIM
         SUM = SUM + A(N)
1000  CONTINUE
C 
      IF (SUM.GT.10.D-20) THEN
         DR = 1.D0 / SUM
         R = SNGL(DR)
         DO 2000, N=1,NDIM
            A(N) = A(N) * R
2000     CONTINUE
      ENDIF
C 
      RETURN
      END

      SUBROUTINE TEMPLB(FLAG,A,B,NPIX,WEITS,RADIUS,CUTS,STAT)
C
C ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C	
C.IDENTIFICATION
C  subroutine TEMPLB			version 1.50	860610
C  K. Banse				ESO - Garching
C
C.KEYWORDS
C  template matching, neighbourhood
C
C.PURPOSE
C replace pixels by weighted sum of nw*nw matrix (nw = 2*radius + 1)
C
C.ALGORITHM
C  filter image by taking the weighted sum W(x,y) of all points in neighbourhood
C  of x,y with given radius, and replace original value I(x,y) by W(x,y)
C	
C.INPUT/OUTPUT
C  call as TEMPLATE(A,B,NPIX,WEITS,RADIUS,STAT)
C
C input par:
C  FLAG:	I*4 		function flag:
C				= 1 for Gauss filter
C				= 2 for digital filter
C				= 3 for max filter
C				= 4 for min filter
C  A:		R*4 array	input array
C  B:		R*4 array	output array
C  NPIX:	I*4 array	no. of pixels per line, no. of lines
C  WEITS:	R*4 array	weights for NWX*NWY matrix, ordered as
C				1 2 3 ... NWX
C				NWX+1 ... 2NWX
C				............
C				(NWY-1)*NWX+1 ... NWX*NWY
C  RADIUS:	I*4 array	radius of template matrix in x,y
C	
C  output par:
C  CUTS:	R*4 array	cut values of result frame
C  STAT:	I*4		return status, should be = 0, else problems...
C	
C --------------------------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER     FLAG,NPIX(*),RADIUS(*)
      INTEGER     NX,NY,DIAMX,DIAMY,RADYNX
      INTEGER     N,NP,NL,BINDX,STAT
      INTEGER     WINDX,OFFSET,OFF
      INTEGER     NRDXP1,RADXP1,NXRADX,LEFT
C
      REAL        A(*),B(*),WEITS(*),CUTS(*)
      REAL        TEST
C 
      DOUBLE PRECISION  DTEST
C
C  init variables + test size of template
      BINDX = 1                                !index for frame B
      NX = NPIX(1)
      NY = NPIX(2)
      DIAMX = RADIUS(1) * 2
      DIAMY = RADIUS(2) * 2
      IF ((DIAMX.GE.NX).OR.(DIAMY.GE.NY)) THEN        !data matrix at least NW
         STAT = 1
         RETURN
      ELSE
         STAT = 0
      ENDIF
C
      RADYNX = RADIUS(2) * NX                  !all following constants for
      RADXP1 = RADIUS(1) + 1                   !speed reasons...
      NXRADX = NX - RADIUS(1)
      NRDXP1 = NXRADX + 1
      LEFT = RADYNX + RADIUS(1)            !lower left corner of template matrix
      OFFSET = RADYNX
C
C  branch according to filter type
      IF (FLAG.GE.3) GOTO 5000
C
C*******
C
C  main loop over inner lines
C
C*******
C
      DO 2000, NL=RADIUS(2)+1,NY-RADIUS(2)            !step through each line
C
C  step through each pixel of data frame
C  i.e., OFFSET+RADIUS(1)+1  >>>  OFF SET+NX-RADIUS(1)
C 
         DO 1500, NP=OFFSET+RADXP1,OFFSET+NXRADX 
            DTEST = 0.D0                              !clear sum
            WINDX = 1                                !index for weight matrix
C
C  sum + weigh inner part
            DO 1000, OFF=NP-LEFT,NP+LEFT,NX        !step through lines of window
               DO 800, N=OFF,OFF+DIAMX
                  DTEST = DTEST + ( A(N) * WEITS(WINDX) )
                  WINDX = WINDX + 1
800            CONTINUE
1000        CONTINUE
C
            B(BINDX) = DTEST                     !fill output frame
            BINDX = BINDX + 1
1500     CONTINUE
C
C  update main offset
         OFFSET = OFFSET + NX
C
2000  CONTINUE
C
C finally update the cuts
      CALL CHCUTS(B,BINDX,CUTS)
      RETURN
C
C  here for min/max filter
C 
5000  IF (FLAG.EQ.3) THEN
C 
C  max filter
         DO 7000, NL=RADIUS(2)+1,NY-RADIUS(2)            !step through each line
C
C  step through each pixel of data frame
C  i.e., OFFSET+RADIUS(1)+1  >>>  OFF SET+NX-RADIUS(1)
C
            DO 6000, NP=OFFSET+RADXP1,OFFSET+NXRADX
               TEST = A(NP-LEFT)                        !take lower left pixel
C
C  find max in inner part
               DO 5500, OFF=NP-LEFT,NP+LEFT,NX    
                  DO 5400, N=OFF,OFF+DIAMX
                     IF (A(N).GT.TEST) TEST = A(N)
5400              CONTINUE
5500           CONTINUE
C
               B(BINDX) = TEST                     !fill output frame
               BINDX = BINDX + 1
6000        CONTINUE
C
            OFFSET = OFFSET + NX                   !update main offset
7000     CONTINUE
C 
      ELSE
C 
C  min filter
         DO 9000, NL=RADIUS(2)+1,NY-RADIUS(2)            !step through each line
C
C  step through each pixel of data frame
C  i.e., OFFSET+RADIUS(1)+1  >>>  OFF SET+NX-RADIUS(1)
C
            DO 8800, NP=OFFSET+RADXP1,OFFSET+NXRADX
               TEST = A(NP-LEFT)                        !take lower left pixel
C
C  find min in inner part
               DO 8600, OFF=NP-LEFT,NP+LEFT,NX   
                  DO 8400, N=OFF,OFF+DIAMX
                     IF (A(N).LT.TEST) TEST = A(N)
8400              CONTINUE
8600           CONTINUE
C
               B(BINDX) = TEST                     !fill output frame
               BINDX = BINDX + 1
8800        CONTINUE
C
            OFFSET = OFFSET + NX                   !update main offset
9000     CONTINUE
      ENDIF
C
C finally update the cuts
      CALL CHCUTS(B,BINDX,CUTS)
      RETURN
C
      END

      SUBROUTINE CHCUTS(A,ASZ1,CUTS)
C 
      INTEGER     ASZ1
      INTEGER     N,NDIM
C 
      REAL        A(*),CUTS(*)
      REAL        TEST
C 
      NDIM = ASZ1 - 1
      IF (NDIM.LT.3) RETURN
C 
      IF (A(1).GT.A(2)) THEN
         CUTS(1) = A(2)
         CUTS(2) = A(1)
      ELSE
         CUTS(1) = A(1)
         CUTS(2) = A(2)
      ENDIF
C 
      DO 1000, N=3,NDIM
         TEST = A(N)
         IF (TEST.LT.CUTS(1)) THEN
            CUTS(1) = TEST
         ELSE IF (TEST.GT.CUTS(2)) THEN
            CUTS(2) = TEST
         ENDIF
1000  CONTINUE
C 
      RETURN
      END

      SUBROUTINE EXPAX(IMNOA,OFFPIX,OUTFR,INBUF,RSTAT)
C
C++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.IDENTIFICATION
C  subroutine EXPX
C  K. Banse				ESO - Garching
C  1.00    910517
C
C.KEYWORDS
C  border regions
C
C.PURPOSE
C  expand image by duplicating border lines + columns
C
C.ALGORITHM
C  get the no. of columns to expand at left + at right
C  get the no. of lines to expand in the beginning + end
C  flip columns in x, lines in y and add to image
C
C.INPUT/OUTPUT
C  call via
C   EXPAX(IMNOA,OFFPIX,OUTFR,INBUF,RSTAT)
C
C  input par:
C  IMNOA	integer         file no. of input frame
C  OFFPIX	integer		offset for 1. pixel to map
C  OUTFR	char. array	output frame
C  INBUF	integer array	xl,xr,yb,ye: no. of cols (left/right)
C					     no. of lines (beginning/end)
C  output par:
C  RSTAT	integer         return status, 0 = o.k.
C
C.VERSIONS
C  1.00   creation
C	
C--------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER      INBUF(4),RSTAT,OFFPIX
      INTEGER      IAV,N,NN,LOOPLM,RMAIND,CHUNKI,CHUNKO
      INTEGER      NAXISA,MOFF,LOFF,NOLIN
      INTEGER*8    PNTRX,PNTRY
      INTEGER      IMNOA,IMNOC,IMNOX,IMNOY
      INTEGER      TRUSIZ,SIZE,STAT
      INTEGER      NPIXA(2),NPIXC(2)
      INTEGER      UNI(1),NULO,MADRID(1)
C
      CHARACTER*(*) OUTFR
      CHARACTER    CUNITA*64,IDENTA*72
C 
      REAL         CUTVAL(4)
C
      DOUBLE PRECISION    STEPA(2),STARTA(2)
      DOUBLE PRECISION    STARTC(2)
C
      COMMON  /VMR/  MADRID
C
      INCLUDE 'MID_INCLUDE:ST_DEF.INC'
C
      DATA    NPIXA  /1,1/,   NPIXC /1,1/
      DATA    STARTA /0.0,0.0/,  STEPA  /1.0,1.0/
      DATA    CUNITA /' '/,   IDENTA /' '/
C 
      INCLUDE 'MID_INCLUDE:ST_DAT.INC'
C
C 
      RSTAT = 0
      CALL STDRDI(IMNOA,'NAXIS',1,1,IAV,NAXISA,UNI,NULO,STAT)
      IF (NAXISA.GT.2) NAXISA = 2                                !max 2-dim 
      CALL STDRDI(IMNOA,'NPIX',1,NAXISA,IAV,NPIXA,UNI,NULO,STAT)
      CALL STDRDD(IMNOA,'START',1,NAXISA,IAV,STARTA,UNI,NULO,STAT)
      CALL STDRDD(IMNOA,'STEP',1,NAXISA,IAV,STEPA,UNI,NULO,STAT)
      CALL STDRDC(IMNOA,'IDENT',1,1,72,IAV,IDENTA,UNI,NULO,STAT)
      N = (NAXISA+1) * 16
      CALL STDRDC(IMNOA,'CUNIT',1,1,N,IAV,CUNITA,UNI,NULO,STAT)
      CALL STDRDR(IMNOA,'LHCUTS',1,4,IAV,CUTVAL,UNI,NULO,STAT)
C
C  get size of input + output frame
      SIZE = NPIXA(1) * NPIXA(2)
      IF ( (INBUF(1).GT.NPIXA(1)) .OR.
     +     (INBUF(2).GT.NPIXA(1)) .OR.
     +     (INBUF(1).LT.0) .OR.
     +     (INBUF(2).LT.0) ) THEN
         RSTAT = 1
         RETURN
      ENDIF
C 
      NPIXC(1) = NPIXA(1) + INBUF(1) + INBUF(2)
      IF (NAXISA.GT.1) THEN
         IF ( (INBUF(3).GT.NPIXA(2)) .OR.
     +        (INBUF(4).GT.NPIXA(2)) .OR.
     +        (INBUF(3).LT.0) .OR.
     +        (INBUF(4).LT.0) ) THEN
            RSTAT = 2
            RETURN
         ENDIF
         NPIXC(2) = NPIXA(2) + INBUF(3) + INBUF(4)
      ENDIF
C
C create result frame
      IF (OFFPIX.LE.0) THEN
         TRUSIZ = NPIXC(1) * NPIXC(2)
         CALL STFCRE(OUTFR,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,
     +               TRUSIZ,IMNOC,STAT)
C 
         CALL STDWRI(IMNOC,'NAXIS',NAXISA,1,1,UNI,STAT)
         CALL STDWRI(IMNOC,'NPIX',NPIXC,1,NAXISA,UNI,STAT)
         STARTC(1) = STARTA(1) - (INBUF(1)*STEPA(1))
         IF (NAXISA.GT.1)
     +      STARTC(2) = STARTA(2) - (INBUF(3)*STEPA(2))
         CALL STDWRD(IMNOC,'START',STARTC,1,NAXISA,UNI,STAT)
         CALL STDWRD(IMNOC,'STEP',STEPA,1,NAXISA,UNI,STAT)
         CALL STDWRC(IMNOC,'IDENT',1,IDENTA,1,72,UNI,STAT)
         N = (NAXISA+1) * 16
         CALL STDWRC(IMNOC,'CUNIT',1,CUNITA,1,N,UNI,STAT)
         CALL STDWRR(IMNOC,'LHCUTS',CUTVAL,1,4,UNI,STAT)
      ELSE
         CALL STFOPN(OUTFR,D_R4_FORMAT,0,F_IMA_TYPE,IMNOC,STAT)
      ENDIF
C 
C  get buffersize of at least one line but no more than total size
      NN = 40000                                !first guess ...
      IF (NN.LT.NPIXA(1)) NN = NPIXA(1)
      IF (NN.GT.SIZE) NN = SIZE
      NOLIN = NN / NPIXA(1)                     !buffer = NOLIN * NPIXA(1)
      CHUNKI = NOLIN * NPIXA(1)
      CHUNKO = NOLIN * NPIXC(1)
      IF (NAXISA.GT.1) THEN
         LOOPLM = NPIXA(2) / NOLIN              !get no. of passes through loop
         RMAIND = NPIXA(2) - (LOOPLM*NOLIN)     !and remainder
      ELSE
         LOOPLM = 1
         RMAIND = 0
      ENDIF
C 
      CALL STFCRE('expaxi',D_R4_FORMAT,F_X_MODE,F_IMA_TYPE,
     +            CHUNKI,IMNOX,STAT)
      CALL STFMAP(IMNOX,F_X_MODE,1,CHUNKI,IAV,PNTRX,STAT)
      CALL STFCRE('expaxo',D_R4_FORMAT,F_X_MODE,F_IMA_TYPE,
     +            CHUNKO,IMNOY,STAT)
      CALL STFMAP(IMNOY,F_X_MODE,1,CHUNKO,IAV,PNTRY,STAT)
C 
C  now we loop through input frame
      MOFF = 1 + OFFPIX                        !point to 1. pixel in input fr.
      IF (NAXISA.GT.1) THEN                    !point to 1. pixel in output fr.
         LOFF = (INBUF(3)*NPIXC(1)) + 1       
      ELSE
         LOFF = 1
      ENDIF
C 
      DO 2000, N=1,LOOPLM
         CALL STFGET(IMNOA,MOFF,CHUNKI,IAV,MADRID(PNTRX),STAT)    !data in
         CALL EXPA1(MADRID(PNTRX),MADRID(PNTRY),NOLIN,NPIXA(1),
     +              NPIXC(1),INBUF)
         CALL STFPUT(IMNOC,LOFF,CHUNKO,MADRID(PNTRY),STAT)          !data out
         MOFF = MOFF + CHUNKI
         LOFF = LOFF + CHUNKO
2000  CONTINUE
C 
      IF (RMAIND.GT.0) THEN
         CHUNKI = RMAIND * NPIXA(1)
         CHUNKO = RMAIND * NPIXC(1)
         CALL STFGET(IMNOA,MOFF,CHUNKI,IAV,MADRID(PNTRX),STAT) 
         CALL EXPA1(MADRID(PNTRX),MADRID(PNTRY),RMAIND,NPIXA(1),
     +              NPIXC(1),INBUF)
         CALL STFPUT(IMNOC,LOFF,CHUNKO,MADRID(PNTRY),STAT)  
      ENDIF
C 
C  for 1-dim frames we are finished
      CALL STFCLO(IMNOX,STAT)
      CALL STFCLO(IMNOY,STAT)
      IF (NAXISA.EQ.1) GOTO 8000
C 
C  get buffersize of INBUF(3/4)*2 lines
      IF (INBUF(3).GE.INBUF(4)) THEN
         NN = INBUF(3)
      ELSE
         NN = INBUF(4)
      ENDIF
      IF (NN.EQ.0) GOTO 8000                !nothing to do in Y
C 
      NN = (2*NN + 1) * NPIXC(1)
      CALL STFCRE('expaxz',D_R4_FORMAT,F_X_MODE,F_IMA_TYPE,
     +            NN,IMNOX,STAT)
      CALL STFMAP(IMNOX,F_X_MODE,1,NN,IAV,PNTRX,STAT)
C  
      NN = 2*INBUF(3) + 1
      CHUNKI = NN * NPIXC(1)
      IF (CHUNKI.GT.0) THEN
         CALL STFGET(IMNOC,1,CHUNKI,IAV,MADRID(PNTRX),STAT) 
         CALL EXPA2(1,MADRID(PNTRX),NPIXC,INBUF(3))
         CALL STFPUT(IMNOC,1,CHUNKI,MADRID(PNTRX),STAT)  
      ENDIF
C  
      NN = 2*INBUF(4) + 1
      CHUNKI = NN * NPIXC(1)
      IF (CHUNKI.GT.0) THEN
         MOFF = ((NPIXC(2)-NN)*NPIXC(1)) + 1
         CALL STFGET(IMNOC,MOFF,CHUNKI,IAV,MADRID(PNTRX),STAT) 
         CALL EXPA2(2,MADRID(PNTRX),NPIXC,INBUF(4))
         CALL STFPUT(IMNOC,MOFF,CHUNKI,MADRID(PNTRX),STAT)  
      ENDIF
      CALL STFCLO(IMNOX,STAT)
C 
8000  CALL STFCLO(IMNOC,STAT)
      RETURN
C 
      END

      SUBROUTINE EXPA1(X,Y,NOLIN,NPIXA,NPIXC,INBUF)
C 
      IMPLICIT NONE
C 
      REAL     X(*),Y(*)
C 
      INTEGER  NOLIN,NPIXA,NPIXC,INBUF(*)
      INTEGER  N,NN,IDX,KDX,IOFF,KOFF
C 
C  loop over all lines
      IOFF = 0
      KOFF = 0
      DO 5000, NN=1,NOLIN
C 
C fill first Y pixels with first flipped X pixels
         IF (INBUF(1).GT.0) THEN
            IDX = 1 + IOFF
            KDX = INBUF(1) + KOFF + 1
            DO 1000, N=1,INBUF(1)
               Y(IDX) = X(KDX)
               IDX = IDX + 1
               KDX = KDX - 1
1000        CONTINUE
         ELSE
            IDX = 1 + IOFF
            KDX = 1 + KOFF
         ENDIF
C 
C copy center Y pixels from all X pixels
         DO 2000, N=1,NPIXA
            Y(IDX) = X(KDX)
            IDX = IDX + 1
            KDX = KDX + 1
2000     CONTINUE
C 
C fill last Y pixels with last flipped X pixels
         KDX = KDX - 1
         IF (INBUF(2).GT.0) THEN
            DO 3000, N=1,INBUF(2)
               KDX = KDX - 1
               Y(IDX) = X(KDX)
               IDX = IDX + 1
3000        CONTINUE
         ENDIF
C 
         IOFF = IOFF + NPIXC
         KOFF = KOFF + NPIXA
5000  CONTINUE
C 
      RETURN
      END

      SUBROUTINE EXPA2(FLAG,X,NPIXC,INB)
C 
      IMPLICIT NONE
C 
      REAL     X(*)
C 
      INTEGER  FLAG,NPIXC(*),INB
      INTEGER  N,NN,IDX,KDX,IOFF,KOFF,MX,MMX
C 
      MX = NPIXC(1)
C 
      IF (FLAG.EQ.1) THEN
         IOFF = 0
         KOFF = 2*INB * MX
         MMX = MX
      ELSE
         IOFF = 2*INB * MX
         KOFF = 0
         MMX = -MX
      ENDIF
C 
      DO 2000, NN=1,INB
         IDX = IOFF + 1
         KDX = KOFF + 1
         DO 1000, N=1,MX
            X(IDX) = X(KDX)
            IDX = IDX + 1
            KDX = KDX + 1
1000     CONTINUE
C 
         IOFF = IOFF + MMX
         KOFF = KOFF - MMX
2000  CONTINUE
C 
      RETURN
      END

      SUBROUTINE SORTIT(RA,N,NH,LL)
C 
C  N  = full dimension of RA
C  NH = index of median - we only sort fully until NH
C  then we insert
C 
C  this is the Heapsort algorithm from "Numerical Recipes", page 231
C 
      IMPLICIT NONE
C 
      INTEGER   N,NH,LL
      INTEGER   L,IR,J,I
      INTEGER   JL,JU,JM,M
C 
      REAL      RA(N),RRA
C 
      L = LL                      !that is L = NH/2 + 1  
      IR = NH
C 
10    IF (L.GT.1) THEN            !still hiring
         L = L - 1
         RRA = RA(L)
      ELSE                        !in retirement + promotion phase
         RRA = RA(IR)             !clear a space at end of array
         RA(IR) = RA(1)           !retire the top of the heap into it
         IR = IR - 1           !decrease the size of the corporation
         IF (IR.EQ.1) THEN        !done with last promotion
            RA(1) = RRA           !the least competent guy of all...
            GOTO 1000             !now move to insertion part
         ELSE
         ENDIF
      ENDIF
C 
      I = L                       !in hiring as well as in promotion phase
      J = L + L              !we here set up to sift down RRA to its right level
C 
20    IF (J.LE.IR) THEN           !"Do while J<=IR"
         IF (J.LT.IR) THEN
            IF (RA(J).LT.RA(J+1)) J = J + 1   !compare to the better underling
         ENDIF
         IF (RRA.LT.RA(J)) THEN   !demote RRA
            RA(I) = RA(J)
            I = J
            J = J + J
         ELSE
            J = IR + 1
         ENDIF
         GOTO 20
      ENDIF
C 
      RA(I) = RRA                 !put RRA into its slot
      GOTO 10
C 
C 
1000  I = NH + 1
      DO 2000 L=I,N
         IF (RA(L).LT.RA(NH)) THEN
            RRA = RA(L)
            JL = 0
            JU = I
C 
1010        JM = (JU+JL) / 2
            IF (RRA.LT.RA(JM)) THEN
               JU = JM
            ELSE
               JL = JM
            ENDIF
            IF ((JU-JL).GT.1) GOTO 1010               !loop
C 
CC            DO 1100 M=L,JL+2,-1          !RA kept intact
            DO 1100 M=NH,JL+2,-1           !ojo - RA not kept intact that way!
               RA(M) = RA(M-1)             !but faster
1100        CONTINUE
            RA(JL+1) = RRA
         ENDIF
2000  CONTINUE
C 
      RETURN
      END

      SUBROUTINE XSORT1(RA,NDIM,NH,RINDX)
C 
C  RA  = real array of which the elements were used for sorting INDARR
C  NDIM  = full dimension of RA
C  NH = index of median - we only sort fully until NH
C  then we insert
C 
C  this is the Heapsort algorithm from "Numerical Recipes", page 233
C 
      IMPLICIT NONE
C 
      PARAMETER (IXXSIZ = 25000)
C 
      INTEGER   NDIM,NH,RINDX
      INTEGER   L,IR,J,I
      INTEGER   INDXT
C 
      INTEGER   INDARR(IXXSIZ),BACKAR(IXXSIZ),SAVARR(IXXSIZ)
      COMMON    /TMPARR/  INDARR,BACKAR,SAVARR
C 
      REAL      RA(NDIM),RRA
C 
      DO 5, J=1,NDIM
         INDARR(J) = J
5     CONTINUE
C 
      L = NDIM/2 + 1
      IR = NDIM
C 
10    IF (L.GT.1) THEN            !still hiring
         L = L - 1
         INDXT = INDARR(L)
         RRA = RA(INDXT)
      ELSE                        !in retirement + promotion phase
         INDXT = INDARR(IR)
         RRA = RA(INDXT)          !clear a space at end of array
         INDARR(IR) = INDARR(1)   !retire the top of the heap into it
         IR = IR - 1              !decrease the size of the corporation
         IF (IR.EQ.1) THEN        !done with last promotion
            INDARR(1) = INDXT     !the least competent guy of all...
            GOTO 1000
         ENDIF
      ENDIF
C 
      I = L                 !in hiring as well as in promotion phase
      J = L + L             !we here set up to sift down RRA to its right level
C 
20    IF (J.LE.IR) THEN                    !"Do while J<=IR"
         IF (J.LT.IR) THEN
            IF (RA(INDARR(J)).LT.RA(INDARR(J+1)))
     +         J = J + 1                   !compare to the better underling
         ENDIF
         IF (RRA.LT.RA(INDARR(J))) THEN    !demote RRA
            INDARR(I) = INDARR(J)
            I = J
            J = J + J
         ELSE
            J = IR + 1
         ENDIF
         GOTO 20
      ENDIF
C 
      INDARR(I) = INDXT                 !put RRA into its slot
      GOTO 10
C
1000  DO 4000, J=1,NDIM                 !set up the back index array
         BACKAR(INDARR(J)) = J
4000  CONTINUE
C 
      RINDX = INDARR(NH)
C 
      RETURN
      END

      SUBROUTINE XSORT2(RA,NDIM,NH,JWOFF,NEWRA,XSIZE,NCOUNT,RINDX)
C 
C  RA  = real array of which the elements were used for sorting INDARR
C  NDIM  = full dimension of RA
C  NH = index of median - we only sorted fully until NH then we inserted
C  IOFF = index of RA element in question
C  INDARR = semi sorted index array from last sorting of RA
C 
C 
      IMPLICIT NONE
C 
      PARAMETER (IXXSIZ = 25000)
C 
      INTEGER   NDIM,NH,JWOFF,XSIZE,NCOUNT,RINDX
      INTEGER   IOFF,INDXT,JL,JU,JM,M,N
C 
      INTEGER   INDARR(IXXSIZ),BACKAR(IXXSIZ),SAVARR(IXXSIZ)
      COMMON    /TMPARR/  INDARR,BACKAR,SAVARR
C 
      REAL      RA(NDIM),NEWRA(NCOUNT)
      REAL      NEWR,QR
C 
      IOFF = JWOFF
C 
      DO 5000, N=1,NCOUNT
C 
         NEWR = NEWRA(N) 
         RA(IOFF) = NEWR               !new value
         INDXT = BACKAR(IOFF)
C 
         IF (INDXT.EQ.1) THEN
            IF (NEWR.LE.RA(INDARR(2)))             !it stays very first
     +         GOTO 4900
         ELSE
            IF (NEWR.LE.RA(INDARR(1))) THEN        !it's very first
               DO 1000, M=INDXT,2,-1               !remove old entry
                  INDARR(M) = INDARR(M-1)          !by shifting up
                  BACKAR(INDARR(M)) = M
1000           CONTINUE
               INDARR(1) = IOFF 
               BACKAR(IOFF) = 1
               GOTO 4900
            ENDIF
         ENDIF
C 
         IF (INDXT.EQ.NDIM) THEN
            IF (NEWR.GE.RA(INDARR(NDIM-1)))        !it stays very last
     +         GOTO 4900
         ELSE
            IF (NEWR.GE.RA(INDARR(NDIM))) THEN     !it very last
               DO 2000, M=INDXT,NDIM-1             !remove old entry
                  INDARR(M) = INDARR(M+1)          !by shifting down
                  BACKAR(INDARR(M)) = M
2000           CONTINUE
               INDARR(NDIM) = IOFF
               BACKAR(IOFF) = NDIM
               GOTO 4900
            ENDIF
         ENDIF
C 
         IF (INDXT.EQ.1) THEN
            QR = NEWR - 1.0                        !so we satisy following test
         ELSE
            QR = RA(INDARR(INDXT-1))
         ENDIF
C 
         IF (NEWR.GT.QR) THEN                      !INDXT = 1 also done here...
            IF (NEWR.LE.RA(INDARR(INDXT+1))) GOTO 4900
            JL = INDXT
            JU = NDIM + 1
C
2010        JM = (JU+JL) / 2
            IF (NEWR.LT.RA(INDARR(JM))) THEN
               JU = JM
            ELSE
               JL = JM
            ENDIF
            IF ((JU-JL).GT.1) GOTO 2010          !loop
C
            DO 2100, M=INDXT,JL-1
               INDARR(M) = INDARR(M+1)
               BACKAR(INDARR(M)) = M
2100        CONTINUE
            INDARR(JL) = IOFF
            BACKAR(IOFF) = JL 
C            
         ELSE IF (NEWR.LT.QR) THEN
            JL = 0
            JU = INDXT
C
3010        JM = (JU+JL) / 2
            IF (NEWR.LT.RA(INDARR(JM))) THEN
               JU = JM
            ELSE
               JL = JM
            ENDIF
            IF ((JU-JL).GT.1) GOTO 3010          !loop
C
            DO 3100, M=INDXT,JL+2,-1
               INDARR(M) = INDARR(M-1)
               BACKAR(INDARR(M)) = M
3100        CONTINUE
            INDARR(JL+1) = IOFF
            BACKAR(IOFF) = JL + 1
         ENDIF
C 
4900     IOFF = IOFF + XSIZE
5000  CONTINUE
C 
      RINDX = INDARR(NH)
C
      RETURN
      END

      SUBROUTINE XSAVX(DIRFLG,NDIM)
C 
      INTEGER   DIRFLG, NDIM
      INTEGER   N,TEST
C
      PARAMETER (IXXSIZ = 25000)
C 
      INTEGER   INDARR(IXXSIZ),BACKAR(IXXSIZ),SAVARR(IXXSIZ)
      COMMON    /TMPARR/  INDARR,BACKAR,SAVARR
C 
      IF (DIRFLG.EQ.1) THEN
         DO 100, N=1,NDIM
            TEST = INDARR(N)
            SAVARR(N) = TEST
100      CONTINUE
      ELSE
C 
         DO 500, N=1,NDIM
            TEST = SAVARR(N)
            INDARR(N) = TEST
500      CONTINUE
         DO 600, N=1,NDIM                       !rebuild back index array
            BACKAR(INDARR(N)) = N
600      CONTINUE
      ENDIF
C 
      RETURN
      END
