C @(#)irsbadpix.for	19.1 (ES0-DMD) 02/25/03 14:23:42
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 Massachusetss Ave, Cambridge, 
C MA 02139, USA.
C
C Corresponding 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
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.COPYRIGHT   (C) 1992 European Southern Observatory
C.IDENT       irsbadpix.for
C.AUTHOR      E. Oliva,  Firenze-Arcetri
C.KEYWORDS    Spectroscopy, IRSPEC
C
C.PURPOSE     Modify values of badpixels in a image (FRAMEI).
C             The coordinates of badpixels is contained inside an input
C             table (REFTAB) in the columns X_COORD,Y_COORD.
C             These coordinates are intended as -- pixel coordinates ---
C             => this program will not work if one define the 'badpixel'
C             table in a 'not-original' frame (i.e. a frame with starts
C             and steps not equl to unity)!
C             The output frame is FRAMEO 
C             This fortran code is called by "irsbadix.prg"
C
C.ALGORITHM   Define the value of each badpixel as the average
C             of either:
C             x: the two neighbouring pixels in X
C             y: the two neighbouring pixels in Y
C             b: the four neighbouring pixels in X+Y
C             In each mode the program uses only the good pixels =>
C             => if the bad-pixels are clustered some of them will
C             not be substituted, in which case a warning message
C             (with pixel coordinates) is printed.
C             The choice between x,y,b is done automatically if the input
C             keyword direct is set to "a" (the default), in this case
C             "b" is used whenever the gradients along X and Y do not
C             different by more than a factor of 2, otherwise take
C             the direction with the smaller gradient.
C             The 'direction option' can also be forced manually to
C             "x","y" or "b.
C
C
C.INPUT/OUTPUT keyword IN_A  --> name of input frame
C              keyword OUT_A --> name of output frame
C              keyword IN_B  --> name of output frame
C              local keyword direct/c/1/1 --> 'direction option', see above
C              local keyword debug/i/1/1 --> if >0 prints many details
C                                            (to be used in case of problems)
C
C
C.VERSION     1.0    Creation     02.09.1992   E. Oliva
C
C-------------------------------------------------------
C
      PROGRAM BADPIX
      IMPLICIT REAL(A-H,O-Z)
      IMPLICIT INTEGER(I-N)

      CHARACTER*60 FRAMEI,FRAMEO,REFTAB
      CHARACTER*1 DIRECT
      CHARACTER*64 CUNIT
      CHARACTER*72 IDENT
      LOGICAL    NULL
      INTEGER*8  INPNTR,OUPNTR
      INTEGER    MMPIX(2)
      INTEGER    NPIX(2),IXBAD(500),IYBAD(500)
      DOUBLE PRECISION START(2),STEP(2)
      REAL CUTS(2)
      COMMON /VMR/ MADRID(1)

      INCLUDE 'MID_INCLUDE:ST_DEF.INC'
      INCLUDE 'MID_INCLUDE:ST_DAT.INC'

      DATA MAXDIM/2/

      IRET=1
      CALL STSPRO('BADPIX')
C
C GET NAME OF INPUT FRAME AND MAP IT
C CHECK ALSO WHETHER IT IS A 2D FRAME.....
C
      CALL STKRDC('IN_A',1,1,60,IRET,FRAMEI,KUNIT,KNUL,ISTAT)
      CALL CLNFRA(FRAMEI,FRAMEI,0)
      CALL STIGET(FRAMEI,D_R4_FORMAT,F_I_MODE,F_IMA_TYPE,MAXDIM,
     ,            NAXIS,NPIX,START,STEP,
     ,            IDENT,CUNIT,INPNTR,NIN,ISTAT)
      IF(NAXIS.NE.2) 
     +     CALL STETER(1,'Input frame must be 2-D')
C
C GET NAME OF OUTPUT FRAME AND MAP IT
C
      CALL STKRDC('OUT_A',1,1,60,IRET,FRAMEO,KUNIT,KNUL,ISTAT)
      CALL CLNFRA(FRAMEO,FRAMEO,0)
      CALL STIPUT(FRAMEO,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,
     ,            NAXIS,NPIX,START,STEP,
     ,            IDENT,CUNIT,OUPNTR,NOU,ISTAT)
C
C GET FLAG TO DEFINE WHICH NEIGHBOURING PIXELS HAVE TO BE CONSIDERED
C
      CALL STKRDC('direct',1,1,1,IRET,DIRECT,KUNIT,KNUL,ISTAT)
C
C get debug option
C
      CALL STKRDI('debug',1,1,IRET,IDEBUG,KUNIT,KNUL,ISTAT)
C
C OPEN  FOR READING (IOPEN=0)
C THE TABLE CONTAINING THE COORDINATES OF THE
C BAD PIXELS WHICH MUST BE SUBSTITUTED BY THE AVERAGE OF THE
C 2 NEIGHBOURING PIXELS ALONG X (DIRECT=X) Y (DIRECT=Y), 
C THE 4 X+Y PIXELS (DIRECT=B) OR THE AUTOMATIC MODE
C
C
      CALL STKRDC('IN_B',1,1,60,IRET,REFTAB,KUNIT,KNUL,ISTAT)
      CALL CLNTAB(REFTAB,REFTAB,0)
      IOPEN=0
      CALL TBTOPN(REFTAB,IOPEN,IDETAB,ISTAT)
C
C GET NUMBERS CORRESPONDING TO XCOL AND YCOL
C
      CALL TBLSER(IDETAB,'X_COORD',NXCOL,ISTAT)
      CALL TBLSER(IDETAB,'Y_COORD',NYCOL,ISTAT)
C
C GET INFORMATION UPON THE TABLE SIZE (N.B. NROW = # OF BAD PIXELS....)
C
      CALL TBIGET(IDETAB,NCOL,NROW,NSORT,NCALL,NRALL,ISTAT)
      NBAD=NROW
C
C COPY TABLE ELEMENTS INTO VECTORS IXBAD,IYBAD
C
      DO IROW=1,NROW
        CALL TBERDR(IDETAB,IROW,NXCOL,RVAL,NULL,ISTAT)
        IXBAD(IROW)=RVAL
        CALL TBERDR(IDETAB,IROW,NYCOL,RVAL,NULL,ISTAT)
        IYBAD(IROW)=RVAL
      ENDDO
      CALL TBTCLO(IDETAB,ISTAT)
C
C CALL ROUTINE WHICH SUBSTITUTES THE BAD PIXELS LISTED IN THE
C
      CALL SUBSTI(MADRID(INPNTR),MADRID(OUPNTR),
     ,                NPIX(1),NPIX(2),IXBAD,IYBAD,NBAD,DIRECT,IDEBUG)
C
C Define and write cuts of output file
C
      CALL MNMX(MADRID(OUPNTR),NPIX,CUTS,MMPIX)
      CALL STDWRR(NOU,'LHCUTS',CUTS,3,2,KUNIT,ISTAT)
C
C RELEASE FILES, UPDATE KEYWORDS AND EXIT
C
      CALL STSEPI
      END
C
C
C
      SUBROUTINE SUBSTI(A,B,NX,NY,IXBAD,IYBAD,NBAD,DIRECT,IDEBUG)
C
C SUBSTITUTE THE VALUE OF THE BAD PIXELS HAVING (PIXEL) COORDINATES
C (IXBAD(J),IYBAD(J)),J=1,NBAD WITH THE AVERAGE VALUE OF THE 2 NEIGHBOURING
C PIXELS ALONG X (DIRECT=X), ALONG Y (DIRECT=Y) OR OF THE 4 PIXELS ALONG X+Y
C (DIRECT=B).
C In case direct=a makes automatic choice.
C WARNING! THE ROUTINE ASSUMES THAT THE BAD PIXELS ARE MOSTLY ISOLATED.
C IT CAN ALSO DEAL WITH 2-3 CONTIGUOS BAD PIXELS BUT IT MUST NOT BE 
C USED WHEN THE BAD PIXELS ARE CLUSTERED. IN PARTICULAR IT MUST NOT BE USED 
C WHEN MORE THAN 2 BAD PIXELS ARE ALIGNED.
C
      IMPLICIT REAL(A-H,O-Z)
      IMPLICIT INTEGER(I-N)
      CHARACTER*1 DIRECT,DMODE(4),CMODE(4)
      DIMENSION A(NX,NY),B(NX,NY)
      DIMENSION IXBAD(NBAD),IYBAD(NBAD)
      CHARACTER*80 OUTPUT
C
      DATA DMODE/'x','y','b','a'/
      DATA CMODE/'X','Y','B','A'/
C
C COPY INPUT IMAGE (A) INTO OUTPUT IMAGE (B)
C
      TOTVAL=0.0
      NGOOD=0
      NOZERO=0
      DO J=1,NY
        DO I=1,NX
          B(I,J)=A(I,J)
          IFLAG=GOODP(I,J,IXBAD,IYBAD,NBAD,NX,NY)
          IF(IFLAG.GT.0) THEN
            TOTVAL=TOTVAL+A(I,J)
            NGOOD=NGOOD+1
            IF(A(I,J).NE.0) NOZERO=1
          ENDIF
        ENDDO
      ENDDO
      IF(NGOOD.LE.0) THEN
        WRITE(OUTPUT,191)
191     FORMAT(
     + 'No good pixel in image, check your reference table')
         CALL STTPUT(OUTPUT,ISTAT)
        RETURN
      ENDIF
      IF(NOZERO.EQ.0) THEN
        WRITE(OUTPUT,192)
192     FORMAT(
     + 'All good pixel in image have intensities =0, check it please')
        CALL STTPUT(OUTPUT,ISTAT)
        RETURN
      ENDIF
      AVER_PIX=TOTVAL/NGOOD
C
      DO I=1,4
        IMODE=I
        IF(DIRECT.EQ.DMODE(I) .OR. DIRECT.EQ.CMODE(I)) GO TO 10
      ENDDO
      CALL STETER
     +(1,'Invalid direction option, only a x y b are recognized')
10    CONTINUE
      IF(AVER_PIX.EQ.0 .AND. IMODE.EQ.4) THEN
        IMODE=3
        WRITE(OUTPUT,193)
193     FORMAT(
     + 'Average=0, option=b used')
        CALL STTPUT(OUTPUT,ISTAT)
      ENDIF
      DO IBAD=1,NBAD
        I=IXBAD(IBAD)
        J=IYBAD(IBAD)
        CALL SIGXY(A,NX,NY,I,J,IXBAD,IYBAD,NBAD,SIGX,SIGY)
        IF(I.LT.1 .OR. J.LT.1 .OR. I.GT.NX .OR. J.GT.NY) GO TO 20
C
C STORE VALUES OF CONTIGUOS PIXELS AND TAKE CARE OF EDGE EFFECTS
C AND OF CONTIGUOS BAD PIXELS
C
        TOTX=0.
        GX1=GOODP(I-1,J,IXBAD,IYBAD,NBAD,NX,NY)
        TOTX=TOTX+GX1
        X1=0.
        IF(GX1.GT.0.) X1=A(I-1,J)
        GX2=GOODP(I+1,J,IXBAD,IYBAD,NBAD,NX,NY)
        TOTX=TOTX+GX2
        X2=0.
        IF(GX2.GT.0.) X2=A(I+1,J)
        TOTY=0.
        GY1=GOODP(I,J-1,IXBAD,IYBAD,NBAD,NX,NY)
        TOTY=TOTY+GY1
        Y1=0.
        IF(GY1.GT.0.) Y1=A(I,J-1)
        GY2=GOODP(I,J+1,IXBAD,IYBAD,NBAD,NX,NY)
        TOTY=TOTY+GY2
        Y2=0.
        IF(GY2.GT.0.) Y2=A(I,J+1)
        IF(IMODE.LE.3) THEN
          JMODE=IMODE
        ELSE
          IF(TOTX.LE.1 .AND. TOTY.LE.1) THEN
            JMODE=3
            GO TO 11
          ENDIF
          IF(TOTX.LE.1) THEN
            JMODE=2
            GO TO 11
          ENDIF
          IF(TOTY.LE.1) THEN
            JMODE=1
            GO TO 11
          ENDIF
          JMODE=3
          IF(SIGX.GT.(4*SIGY)) JMODE=2
          IF(SIGY.GT.(4*SIGX)) JMODE=1
        ENDIF
11      CONTINUE
        IF(IDEBUG.GT.0) THEN
          WRITE(OUTPUT,119) I,J,DMODE(JMODE)
119       FORMAT('Badpixel (' , I3 , ',' , I3 , ') dir= ', A)
          CALL STTPUT(OUTPUT,ISTAT)
        ENDIF
        IF(JMODE.EQ.1) THEN
          IF(TOTX.EQ.0.) THEN
            WRITE(OUTPUT,101) 
101         FORMAT(
     + '>2 bad pixels along X, (',I2,',',I2,') not modified')
            CALL STTPUT(OUTPUT,ISTAT)
          ELSE
            B(I,J)=(X1+X2)/TOTX
          ENDIF
        ENDIF
        IF(JMODE.EQ.2) THEN
          IF(TOTY.EQ.0.) THEN
            WRITE(OUTPUT,102) I,J
102         FORMAT(
     + '>2 bad pixels along Y, (',I2,',',I2,') not modified')
            CALL STTPUT(OUTPUT,ISTAT)
          ELSE
            B(I,J)=(Y1+Y2)/TOTY
          ENDIF
        ENDIF
        IF(JMODE.EQ.3) THEN
          TOT=TOTX+TOTY
          IF(TOT.EQ.0.) THEN
            WRITE(OUTPUT,103) I,J
103         FORMAT(
     + 'region crowded with bad pixels, (',I2,',',I2,') not modified')
            CALL STTPUT(OUTPUT,ISTAT)
          ELSE
            B(I,J)=(X1+X2+Y1+Y2)/TOT
          ENDIF
        ENDIF
20    CONTINUE
      ENDDO
C
      RETURN
      END
C
C
C
      FUNCTION GOODP(I,J,IBAD,JBAD,NBAD,NX,NY)
C
C CHECK WHETHER PIXEL (I,J) IS A BAD PIXEL...
C   GOODP = 0  BAD PIXEL
C   GOODP = 1  GOOD PIXEL
C N.B. GOODP=0 ALSO WHEN I OR J ARE OUTSIDE THE IMAGE
C
      IMPLICIT REAL(A-H,O-Z)
      IMPLICIT INTEGER(I-N)
      INTEGER IBAD(NBAD),JBAD(NBAD)

      GOODP=1
      IF(I.LT.1 .OR. J.LT.1 .OR. I.GT.NX .OR. J.GT.NY) THEN
        GOODP=0
        RETURN
      ENDIF
      DO K=1,NBAD
        IF(I.EQ.IBAD(K).AND.J.EQ.JBAD(K)) THEN
          GOODP=0
          RETURN
        ENDIF
      ENDDO
      RETURN
      END


      SUBROUTINE SIGXY(A,NX,NY,IX,IY,IXBAD,IYBAD,NBAD,SIGX,SIGY)

      IMPLICIT REAL(A-H,O-Z)
      IMPLICIT INTEGER(I-N)
      REAL A(NX,NY)
      INTEGER IXBAD(NBAD),IYBAD(NBAD)

C
C sigma of the neighbouring 10 pixels along Y --> SIGY
C
      SUM=0.0
      SUM2=0.0
      NTOT=0
      I=IX
      NPT=0
      DO J=IY+1,NY
        IFLAG=GOODP(I,J,IXBAD,IYBAD,NBAD,NX,NY)
        IF(IFLAG.GT.0) THEN
          VAL=A(I,J)
          SUM=SUM+VAL
          SUM2=SUM2+VAL*VAL
          NTOT=NTOT+1
          NPT=NPT+1
          IF(NPT.GE.5) GO TO 10
        ENDIF
      ENDDO
10    CONTINUE
      NPT=0
      DO J=IY-1,1,-1
        IFLAG=GOODP(I,J,IXBAD,IYBAD,NBAD,NX,NY)
        IF(IFLAG.GT.0) THEN
          VAL=A(I,J)
          SUM=SUM+VAL
          SUM2=SUM2+VAL*VAL
          NTOT=NTOT+1
          NPT=NPT+1
          IF(NPT.GE.5) GO TO 11
        ENDIF
      ENDDO
11    CONTINUE
      IF(NTOT.GT.0) THEN
        SIGY=SQRT((SUM2-SUM*SUM/NTOT)/(NTOT-1))
      ELSE
        SIGY=1e20
      ENDIF

C
C sigma of the neighbouring 10 pixels along X --> SIGX
C
      SUM=0.0
      SUM2=0.0
      NTOT=0
      J=IY
      NPT=0
      DO I=IX+1,NX
        IFLAG=GOODP(I,J,IXBAD,IYBAD,NBAD,NX,NY)
        IF(IFLAG.GT.0) THEN
          VAL=A(I,J)
          SUM=SUM+VAL
          SUM2=SUM2+VAL*VAL
          NTOT=NTOT+1
          NPT=NPT+1
          IF(NPT.GE.5) GO TO 20
        ENDIF
      ENDDO
20    CONTINUE
      NPT=0
      DO I=IX-1,1,-1
        IFLAG=GOODP(I,J,IXBAD,IYBAD,NBAD,NX,NY)
        IF(IFLAG.GT.0) THEN
          VAL=A(I,J)
          SUM=SUM+VAL
          SUM2=SUM2+VAL*VAL
          NTOT=NTOT+1
          NPT=NPT+1
          IF(NPT.GE.5) GO TO 21
        ENDIF
      ENDDO
21    CONTINUE
      IF(NTOT.GT.0) THEN
        SIGX=SQRT((SUM2-SUM*SUM/NTOT)/(NTOT-1))
      ELSE
        SIGX=1e20
      ENDIF

      RETURN
      END
