1
C @(#)modcol.for 13.1.1.2 (ESO-DMD) 02/12/99 19:14:48
2
C===========================================================================
3
C Copyright (C) 1995 European Southern Observatory (ESO)
5
C This program is free software; you can redistribute it and/or
6
C modify it under the terms of the GNU General Public License as
7
C published by the Free Software Foundation; either version 2 of
8
C the License, or (at your option) any later version.
10
C This program is distributed in the hope that it will be useful,
11
C but WITHOUT ANY WARRANTY; without even the implied warranty of
12
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
C GNU General Public License for more details.
15
C You should have received a copy of the GNU General Public
16
C License along with this program; if not, write to the Free
17
C Software Foundation, Inc., 675 Massachusetts Ave, Cambridge,
20
C Correspondence concerning ESO-MIDAS should be addressed as follows:
21
C Internet e-mail: midas@eso.org
22
C Postal address: European Southern Observatory
23
C Data Management Division
24
C Karl-Schwarzschild-Strasse 2
25
C D 85748 Garching bei Muenchen
27
C===========================================================================
29
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
32
C program MODCOL version 1.00 881028
33
C K. Banse ESO - Garching
34
C M.Peron 910417 modif in the call of TCLSER
35
C S. Wolf 980113 not selected table-rows has not
36
C to be processed (swolf@eso.org)!
38
C bulk data frame, bad pixels
42
C to replace a column or row of undefined or bad pixels values by quadratic
43
C interpolation of adjacent columns or rows.The bad columns or rows are
44
C defined via the cursor or coordinates or taken from a table.
48
C The adjacent pixels are used to compute the coefficients of a least-squares
49
C approximating second order polynomial
52
C the following keywords are used:
53
C P1/C/1/60 input frame, table
58
C IN_A/C/1/60 input frame, if P1 does not indicate table use
59
C OUT_A/C/1/60 result frame
60
C ACTION/C/1/2 C or R, for column or row
61
C V or C for variable or constant offset
62
C of column/row in question
63
C P4/C/1/80 column or row world coords. if P1 holds just
68
C 1.00 from program MODICOL version 2.20 as of 850212
69
C use FORTRAN 77 + new ST interfaces
71
C-------------------------------------------------------------------
77
INTEGER N,NCOUNT,IAV,ISTAT
78
INTEGER*8 PNTRA,PNTRB,PNTRX,PNTRY
79
INTEGER IMNOA,IMNOB,STAT
80
INTEGER INDXFL,SIZE,NAXIS,SLEN,SLEN1,TBLFLG
82
INTEGER IBUF(2),KINDEX,OFF,KROW,KROW1,KROW2
83
INTEGER TIDI,TABCLN(1)
84
INTEGER UNI(1),NULO,MADRID(1)
87
CHARACTER CUNITA*48,IDENTA*72,ACTION*2,COLROW*80
88
CHARACTER FRAMEA*80,FRAMEB*80,TABLE*80
89
CHARACTER OUTPUT*80,COLNAM*20
90
CHARACTER MESS(2)*50,ERRMS1*40,ERRMS2*40
91
CHARACTER SUBPAR(40)*30
93
REAL TEMP,CUTS(4),FMIN,FMAX,RMIN,RMAX,RR
95
DOUBLE PRECISION STARTA(2),STEPA(2),DD
97
LOGICAL TABNUL(1),SELFLG
101
INCLUDE 'MID_INCLUDE:ST_DEF.INC'
103
DATA FRAMEA /' '/, FRAMEB /' '/
104
DATA IDENTA /' '/, CUNITA /' '/
105
DATA OUTPUT /' '/, TABLE /' '/
106
DATA MESS /'column/row too close to image boundary... ',
107
+ 'column/row too large...'/
108
DATA ERRMS1 /'col/row no.s missing...'/
109
DATA ERRMS2 /'invalid syntax for col/row no.s ...'/
111
INCLUDE 'MID_INCLUDE:ST_DAT.INC'
113
C get into MIDAS environment
114
CALL STSPRO('MODCOL')
116
C get input option (frame or frame,table) + read keys
117
CALL STKRDC('IN_A',1,1,80,IAV,OUTPUT,UNI,NULO,STAT)
118
CALL STKRDC('ACTION',1,1,2,IAV,ACTION,UNI,NULO,STAT)
119
CALL UPCAS(ACTION,ACTION)
120
IF (ACTION(1:1).EQ.'C') THEN
121
INDXFL = 1 !index = 1 for columns...
123
INDXFL = 2 !index = 2 for rows
126
N = INDEX(OUTPUT,',')
129
FRAMEA(1:) = OUTPUT(1:N-1)
130
CALL CLNFRA(FRAMEA,FRAMEA,0) !because it's not isolated
131
TABLE(1:) = OUTPUT(N+1:)
135
IF (TABLE(N+1:N+1).EQ.':') IAV = N + 1
136
COLNAM(1:) = TABLE(IAV+1:)//' '
139
IF (ACTION(1:1).EQ.'C') THEN !default column labels
145
CALL TBTOPN(TABLE,F_I_MODE,TIDI,STAT)
146
CALL TBIGET(TIDI,NCOL,NROW,N,N,N,STAT)
147
CALL TBLSER(TIDI,COLNAM,TABCLN(1),STAT) !find columns...
148
IF (TABCLN(1).LE.0) THEN
149
N = INDEX(COLNAM,' ')
150
OUTPUT(1:) = 'column '//COLNAM(1:N)//
151
+ ' not found in input table...'
152
CALL STETER (9,OUTPUT)
156
FRAMEA(1:) = OUTPUT(1:)
157
CALL STKRDC('P4',1,1,80,IAV,COLROW,UNI,NULO,STAT) !get coords.
159
CALL STKRDC('OUT_A',1,1,80,IAV,FRAMEB,UNI,NULO,STAT)
161
C map input + result frame
162
CALL GENEQF(FRAMEA,FRAMEB,STAT)
163
IF (STAT.EQ.1) THEN !same name
164
CALL STIGET(FRAMEA,D_R4_FORMAT,F_IO_MODE,F_IMA_TYPE,
165
+ 2,NAXIS,NPIXA,STARTA,STEPA,IDENTA,
166
+ CUNITA,PNTRA,IMNOA,STAT)
168
CALL STETER(1,'input frame must be a 2-dim frame...')
169
ELSE IF (NAXIS.GT.2) THEN
171
+ ('only first plane of 3-dim input frame processed',STAT)
176
SIZE = NPIXA(1)*NPIXA(2)
178
CALL STIGET(FRAMEA,D_R4_FORMAT,F_I_MODE,F_IMA_TYPE,
179
+ 2,NAXIS,NPIXA,STARTA,STEPA,IDENTA,
180
+ CUNITA,PNTRA,IMNOA,STAT)
182
CALL STETER(1,'input frame must be a 2-dim frame...')
183
ELSE IF (NAXIS.GT.2) THEN
185
+ ('only first plane of 3-dim input frame processed',STAT)
188
CALL STIPUT(FRAMEB,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,
189
+ NAXIS,NPIXA,STARTA,STEPA,IDENTA,
190
+ CUNITA,PNTRB,IMNOB,STAT)
191
SIZE = NPIXA(1)*NPIXA(2)
192
CALL COPYF(MADRID(PNTRA),MADRID(PNTRB),SIZE) !copy data...
196
IF (ACTION(1:1).EQ.'C') THEN !allocate workspace
201
CALL STFXMP(SIZE,D_R4_FORMAT,PNTRX,STAT)
202
CALL STFXMP(SIZE,D_R4_FORMAT,PNTRY,STAT)
204
C save min,max + cuts of image
205
CALL STDRDR(IMNOA,'LHCUTS',1,4,IAV,CUTS,UNI,NULO,STAT)
209
C fork according to input mode
210
IF (TBLFLG.EQ.2) THEN
212
ISTAT = 2 !thus we start with KROW = 0
213
GOTO 3000 !and ISTAT != 1
216
C extract columns/rows from COLROW
222
CALL EXTRSS(COLROW,',',OFF,SUBPAR(N),SLEN)
224
IF (NCOUNT.LE.0) CALL STETER(2,ERRMS1)
225
GOTO 1000 !we reached the end...
231
C finally loop through columns or rows
233
1000 KINDEX = KINDEX + ISTAT
234
IF (KINDEX.GT.NCOUNT) GOTO 4000
237
IF (SUBPAR(N)(1:1).EQ.'@') THEN !input = @pixel
238
CALL GENCNV(SUBPAR(N)(2:),1,1,IBUF,RR,DD,SLEN)
239
IF (SLEN.LE.0) CALL STETER(3,ERRMS2)
240
ELSE !input = world coord
241
CALL GENCNV(SUBPAR(N),2,1,IAV,TEMP,DD,SLEN)
242
IF (SLEN.LE.0) CALL STETER(3,ERRMS2)
243
IBUF(1) = NINT((TEMP - STARTA(INDXFL))/STEPA(INDXFL)) + 1
245
IF (KINDEX.EQ.NCOUNT) THEN
249
IF (SUBPAR(N)(1:1).EQ.'@') THEN !input = @pixel
250
CALL GENCNV(SUBPAR(N)(2:),1,1,IBUF(2),TEMP,DD,SLEN)
251
IF (SLEN.LE.0) CALL STETER(3,ERRMS2)
252
ELSE !input = world coord
253
CALL GENCNV(SUBPAR(N),2,1,IAV,TEMP,DD,SLEN)
254
IF (SLEN.LE.0) CALL STETER(3,ERRMS2)
255
IBUF(2) = NINT((TEMP - STARTA(INDXFL))/STEPA(INDXFL)) + 1
261
CALL DOIT(ACTION,MADRID(PNTRB),MADRID(PNTRX),MADRID(PNTRY),
262
+ STARTA,STEPA,NPIXA,
263
+ IBUF,FMIN,FMAX,ISTAT)
266
CALL STTPUT(MESS(-ISTAT),STAT)
267
ISTAT = 1 !on return, ISTAT = 1 or 2
268
ELSE !depending on no. of columns/rows used
269
SLEN = INDEX(SUBPAR(KINDEX),' ') !cut off trailing blanks
270
IF (SLEN.LE.0) SLEN = LEN(SUBPAR(KINDEX))
273
OUTPUT(1:) = 'column/row at x/y = '
274
+ //SUBPAR(KINDEX)(1:SLEN)//
277
SLEN1 = INDEX(SUBPAR(KINDEX+1),' ') !cut off trailing blanks
278
IF (SLEN1.LE.0) SLEN1 = LEN(SUBPAR(KINDEX+1))
279
OUTPUT(1:) = 'columns/rows at x/y = '//
280
+ SUBPAR(KINDEX)(1:SLEN)//', '//
281
+ SUBPAR(KINDEX+1)(1:SLEN1)//'cleaned...'
283
CALL STTPUT(OUTPUT,STAT)
284
RMIN = MIN(RMIN,FMIN)
285
RMAX = MAX(RMAX,FMAX)
287
GOTO (1000,3000),TBLFLG !look for more...
289
C here we get our input data from a table
290
3000 KROW = KROW2 + ISTAT - 1 !KROW -> KROW2 or -> KROW2+1
291
IF (KROW.LE.NROW) THEN
293
IF (ISTAT.EQ.1) THEN !only one row used last time...
295
SUBPAR(1)(1:) = SUBPAR(2)(1:)
296
GOTO 3100 !so reuse last value
299
3030 CALL TBSGET(TIDI,KROW1,SELFLG,STAT) !only use selected rows
300
IF (.NOT.SELFLG) THEN
301
KROW1 = KROW1 + 1 !get next row
302
IF (KROW1.LE.NROW) THEN
305
GOTO 3300 !end of table reached
309
CALL TBRRDR(TIDI,KROW1,1,TABCLN,TEMP,TABNUL,STAT)
310
IBUF(1) = NINT((TEMP - STARTA(INDXFL))/STEPA(INDXFL)) + 1
311
WRITE(SUBPAR(1),10000) TEMP
313
IF (SUBPAR(1)(N:N).NE.' ') THEN
314
IF (N.GT.1) SUBPAR(1)(1:) = SUBPAR(1)(N:)//' '
319
3100 KROW2 = KROW1 + 1 !point to next possible row
320
IF (KROW1.EQ.NROW) THEN
323
3130 CALL TBSGET(TIDI,KROW2,SELFLG,STAT) !only use selected rows
324
IF (.NOT.SELFLG) THEN
325
KROW2 = KROW2 + 1 !get next row
326
IF (KROW2.LE.NROW) THEN
334
CALL TBRRDR(TIDI,KROW2,1,TABCLN,TEMP,TABNUL,STAT)
335
IBUF(2) = NINT((TEMP - STARTA(INDXFL))/STEPA(INDXFL)) + 1
336
WRITE(SUBPAR(2),10000) TEMP
338
IF (SUBPAR(2)(N:N).NE.' ') THEN
339
IF (N.GT.1) SUBPAR(2)(1:) = SUBPAR(2)(N:)//' '
345
3200 KINDEX = 1 !force index to 1
346
GOTO 1010 !now continue as above
350
3300 CALL TBTCLO(TIDI,STAT)
352
C get new dynamic range + write descriptor LHCUTS
353
4000 CUTS(3) = MIN(RMIN,CUTS(3))
354
CUTS(4) = MAX(RMAX,CUTS(4))
356
C copy descriptors + append HISTORY
357
CALL DSCUPT(IMNOA,IMNOB,' ',STAT)
358
CALL STDWRR(IMNOB,'LHCUTS',CUTS,1,4,UNI,STAT) !use old cuts...
367
SUBROUTINE DOIT(ACTION,A,TEMPA,TEMPB,
368
+ START,STEP,NPIX,COORD,FMIN,FMAX,ISTAT)
372
INTEGER COORD(2),ISTAT
373
INTEGER JOF,JOF1,N,M,NFLAG,KFLAG
374
INTEGER NEXT,NP,JNDX,NOLINS
375
INTEGER NPIX(2),INDX(4),IOF(4)
379
REAL A(*),TEMPA(*),TEMPB(*),FMIN,FMAX
380
REAL V,VV,W,WW,XX,XXX
383
DOUBLE PRECISION START(2),STEP(2)
384
DOUBLE PRECISION S(4),Z(4),X(4),F(4)
385
DOUBLE PRECISION RR1,RR2,RR3,P1,P2,P3,Q
386
DOUBLE PRECISION SUM1,SUM2
387
DOUBLE PRECISION A0,A1,A2
389
IF (ACTION(1:1).EQ.'C') THEN
390
NFLAG = 1 !columns...
395
INDX(1) = COORD(1) - 2 !take 2 pixels less
398
INDX(2) = INDX(1) + 1
399
JNDX = INDX(2) + 1 !keep index of bad line...
400
IF (NEXT .EQ. INDX(1)+1) THEN
401
NOLINS = 2 !double lines...
405
INDX(3) = INDX(2) + NOLINS + 1 !single line...
406
INDX(4) = INDX(3) + 1
409
IF ((INDX(1).LT.1).OR.(INDX(4).GT.NPIX(NFLAG))) THEN
416
C get "x" values + related sums for later calculations
417
DO 200, N=1,4 !get x values...
418
X(N) = START(NFLAG) + (INDX(N)-1)*STEP(NFLAG)
421
XX = START(NFLAG) + (JNDX-1)*STEP(NFLAG) !x of bad row/column...
422
XXX = XX + STEP(NFLAG)
425
DO 400, N=1,4 !get x**2,x**3,x**4 ...
428
S(M) = 0.D0 !compute sums
434
C branch according to columns + rows
435
IF (ACTION(1:1).EQ.'C') GOTO 5000
438
DO 1200, N=1,4 !get y values...
439
IOF(N) = (INDX(N)-1)*NPIX(1)
441
JOF = (JNDX-1)*NPIX(1)
445
DO 3300, NP=1,NPIX(1)
446
DO 1400, M=1,4 !get function values
451
DO 1600, M=1,4 !compute sums on right side
453
Z(2) = Z(2) + F(M)*X(M)
454
Z(3) = Z(3) + F(M)*X(M)*X(M)
457
C reduce + solve the linear system 4.*A0 + S1*A1 + S2*A2 = Z1
458
C S1*A0 + S2*A1 + S3*A2 = Z2
459
C S2*A0 + S3*A1 + S4*A2 = Z3
468
C we now have: RR1*A1 + RR2*A2 = RR3
471
IF (ABS(P2-RR2*Q).LE.10.D-30) THEN
472
IF (ABS(P1 - RR1*Q).LE.10.D-30) THEN !linearly dependant system
479
A1 = (P3 - RR3*Q) / (P1 - RR1*Q)
480
A2 = (RR3 - A1*RR1)/RR2
482
A2 = (P3 - RR3*Q) / (P2 - RR2*Q)
483
A1 = (RR3 - A2*RR2)/RR1
486
A0 = (Z(1) - S(2)*A2 - S(1)*A1) * .25D0
488
C finally calculate interpolated value...!
489
3000 TEMPA(NP) = A0 + A1*XX + A2*XX*XX
491
+ TEMPB(NP) = A0 + A1*XXX + A2*XXX*XXX
494
C check, if we work on single line or not
496
IF (NOLINS.EQ.2) GOTO 4000
498
C for constant offset, get average difference to orignal bad row
499
IF (ACTION(2:2).EQ.'C') THEN
501
DO 3500, NP=1,NPIX(1)
502
SUM1 = SUM1 + DBLE(A(JOF+NP) - TEMPA(NP)) !sum differences
504
V = SNGL(SUM1/NPIX(1)) !get average offset
506
C and correct pixels in bad row with that offset
507
DO 3600, NP=1,NPIX(1)
513
IF (W.GT.FMAX) FMAX = W
519
C store approximated pixels in bad row
520
DO 3800, NP=1,NPIX(1)
526
IF (W.GT.FMAX) FMAX = W
532
C here to handle two adjacent "bad" rows
534
4000 IF (ACTION(2:2).EQ.'C') THEN
535
SUM1 = 0.D0 !get average difference to adjacent lines
537
DO 4200, NP=1,NPIX(1)
538
SUM1 = SUM1 + DBLE(A(JOF+NP) - TEMPA(NP)) !sum differences
539
SUM2 = SUM2 + DBLE(A(JOF1+NP) - TEMPB(NP)) !sum differences
541
V = SNGL(SUM1/NPIX(1)) !get average offset
542
VV = SNGL(SUM2/NPIX(1))
544
C and correct pixels in bad rows with these offsets
545
DO 4400, NP=1,NPIX(1)
552
IF (RMIN.LT.FMIN) FMIN = RMIN
553
IF (RMAX.GT.FMAX) FMAX = RMAX
558
C store approximated pixels in bad rows
559
DO 4600, NP=1,NPIX(1)
566
IF (RMIN.LT.FMIN) FMIN = RMIN
567
IF (RMAX.GT.FMAX) FMAX = RMAX
574
C go through the column
576
DO 6600, NP=1,NPIX(2)
577
DO 5200, M=1,4 !get function values
578
F(M) = A(JOF+INDX(M))
582
DO 5400, M=1,4 !compute sums on right side
584
Z(2) = Z(2) + F(M)*X(M)
585
Z(3) = Z(3) + F(M)*X(M)*X(M)
588
C reduce + solve the linear system 4.*A0 + S1*A1 + S2*A2 = Z1
589
C S1*A0 + S2*A1 + S3*A2 = Z2
590
C S2*A0 + S3*A1 + S4*A2 = Z3
599
C we now have: RR1*A1 + RR2*A2 = RR3
602
IF (ABS(P2-RR2*Q).LE.10.D-30) THEN
603
IF (ABS(P1 - RR1*Q).LE.10.D-30) THEN !linearly dependant system
610
A1 = (P3 - RR3*Q) / (P1 - RR1*Q)
611
A2 = (RR3 - A1*RR1)/RR2
613
A2 = (P3 - RR3*Q) / (P2 - RR2*Q)
614
A1 = (RR3 - A2*RR2)/RR1
617
A0 = (Z(1) - S(2)*A2 - S(1)*A1)*.25D0
619
C finally calculate interpolated value...!
620
6000 TEMPA(NP) = A0 + A1*XX + A2*XX*XX
622
+ TEMPB(NP) = A0 + A1*XXX + A2*XXX*XXX
623
JOF = JOF + NPIX(1) !update offset to next row...
626
C check, if we work on single line or not
628
IF (NOLINS.EQ.2) GOTO 8000
630
C for constant offset, get average difference to original bad column
631
IF (ACTION(2:2).EQ.'C') THEN
634
DO 6800, NP=1,NPIX(2)
635
SUM1 = SUM1 + DBLE(A(JOF) - TEMPA(NP)) !sum differences
638
W = SNGL(SUM1/NPIX(2)) !get average offset
640
C and correct pixels in bad column with that offset
642
DO 7000, NP=1,NPIX(2)
648
IF (V.GT.FMAX) FMAX = V
655
C fill approximated pixels into frame
657
DO 7400, NP=1,NPIX(2)
663
IF (V.GT.FMAX) FMAX = V
670
C here to handle two adjacent "bad" columns
671
8000 IF (ACTION(2:2).EQ.'C') THEN
672
SUM1 = 0.D0 !get average difference to adjacent lines
676
DO 8200, NP=1,NPIX(2)
677
SUM1 = SUM1 + DBLE(A(JOF) - TEMPA(NP)) !sum differences
678
SUM2 = SUM2 + DBLE(A(JOF+1) - TEMPB(NP))
681
V = SNGL(SUM1/NPIX(2)) !get average offset
682
VV = SNGL(SUM2/NPIX(2))
684
C and correct pixels in bad columns with these offsets
686
DO 8400, NP=1,NPIX(2)
693
IF (RMIN.LT.FMIN) FMIN = RMIN
694
IF (RMAX.GT.FMAX) FMAX = RMAX
700
C fill approximated pixels into frame
702
DO 8600, NP=1,NPIX(2)
710
IF (RMIN.LT.FMIN) FMIN = RMIN
711
IF (RMAX.GT.FMAX) FMAX = RMAX