-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathla_cosmic.pro
941 lines (855 loc) · 32.1 KB
/
la_cosmic.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
;------------------------------------------------------------------------------
;+
; NAME:
; reckon_statsec
;
; PURPOSE:
; parse the statsec string in la_cosmic and return the indices
; which bracket the section to be exaimed.
;
;
; CALLING SEQUENCE:
; reckon_statsec, statstring,arrsize
;
; INPUTS:
; statstring: The string such as "[23:34,*]"
; arrsize : Array with the x and y sizes of the image
;
; OUTPUTS:
; returns the indices of the statsec in the form [x1,x2,y1,y2]
;
;
; PROCEDURES CALLED:
;
; COMMENTS:
; A good deal of error checking is done to ensure that
; a statsection will be valid.
;
; NOTES:
; BUGS:
;
; REVISION HISTORY:
; 20-May-2001 Written by Joshua Bloom, Caltech ([email protected])
;-
;------------------------------------------------------------------------------
function reckon_statsec, statstring,arrsize
;; must be of the form
;; X1:X2,Y1:Y2
tmp = size(statstring)
if (tmp[1] ne 7) then begin
print, 'RECKON_STATSEC: Warning, statsec not valid, using full image'
return, [0,arrsize[0]-1,0,arrsize[1]-1]
endif
tmp = strsplit(statstring,'[',/extract)
tmp = strsplit(tmp[0],']',/extract)
;; break up the string by the comma and evaluate
str = strsplit(tmp[0],',',/extract)
nstr = n_elements(str)
if (nstr ne 2) then begin
print, 'RECKON_STATSEC: Warning, statsec not valid, using full image'
return, [0,arrsize[0]-1,0,arrsize[1]-1]
endif
retarr = lonarr(4)
for i=0,1 do begin
; now look at each string and parse
str1 = strsplit(str[i],':',/extract)
nstr1 = n_elements(str1)
if (nstr1 gt 2) then begin
;; malformed strsep
retarr[i*2] = 0
retarr[i*2 + 1] = arrsize[i] - 1
endif
if (nstr1 eq 1) then begin
if (stregex(str1[0],'[*]',/boolean)) then begin
;; the user wants the entire image
retarr[i*2] = 0
retarr[i*2 + 1] = arrsize[i] - 1
endif else begin
;; it's a number, so convert it
retarr[i*2] = long(str1[0])
retarr[i*2 + 1] = long(str1[0])
endelse
endif else begin
retarr[i*2] = long(str1[0])
retarr[i*2 + 1] = long(str1[1])
endelse
endfor
return, retarr
end
;------------------------------------------------------------------------------
;+
; NAME:
; lacos_replace, arr, repval, low, high
;
; PURPOSE:
; replace pixels whose value are between low and high with value = repval
; modelled after IRAF (!) IMREPLACE
;
; CALLING SEQUENCE:
; lacos_replace, arr, repval, low, high
;
; INPUTS:
; arr: number array of any size or dimension.
; repval valid replacment value
; low,high bracket values to replace (can be 'INDEF') to replace all
;
; OUTPUTS:
; returns the array = arr but with the replaced pixels
;
; PROCEDURES CALLED:
;
; COMMENTS:
; NOTES:
; BUGS:
;
; REVISION HISTORY:
; 20-May-2001 Written by Joshua Bloom, Caltech ([email protected])
;-
;------------------------------------------------------------------------------
function lacos_replace, arr, repval, low, high
extr = 1d40
slow = size(low)
shigh = size(high)
if (shigh[1] eq 7) then begin
if (high ne 'INDEF') then begin
print, 'LACOS_REPLACE: Sorry must call with INDEF not'
print, high
return, arr
endif
high = extr
endif
if (slow[1] eq 7) then begin
if (low ne 'INDEF') then begin
print, 'LACOS_REPLACE: Sorry must call with INDEF not'
print, slow
return, arr
endif
low = -1d0 * extr
endif
high = double(high)
low = double(low)
bads = where((arr le high) and (arr ge low), n)
if (n ge 1) then arr[bads] = repval
return, arr
end
;+
; NAME:
; djs_median
;
; PURPOSE:
; Return the median of an image either with a filtering box or by collapsing
; the image along one of its dimensions.
;
; CALLING SEQUENCE:
; result = djs_median( array, [ dimension, width=, boundary= ] )
;
; INPUTS:
; array - N-dimensional array
;
; OPTIONAL INPUTS:
; dimension - The dimension over which to compute the median, starting
; at one. If this argument is not set, the median of all array
; elements (or all elements within the median window described
; by WIDTH) are medianed.
; width - Width of median window; scalar value.
; It is invalid to specify both DIMENSION and WIDTH.
; boundary - Boundary condition:
; 'none': Do not median filter within WIDTH/2 pixels of
; the edge; this is the default for both this
; routine and MEDIAN().
; 'nearest': Use the value of the nearest boundary pixel.
; NOT IMPLEMENTED
; 'reflect': Reflect pixel values around the boundary.
; 'wrap': Wrap pixel values around the boundary.
; NOT IMPLEMENTED
; These boundary conditions only take effect if WIDTH is set,
; and if ARRAY is either 1-dimensional or 2-dimensional.
;
; OUTPUTS:
; result - The output array. If neither DIMENSION nor WIDTH are set,
; then RESULT is a scalar. If DIMENSION is not set and WIDTH
; is set, then RESULT has the same dimensions as ARRAY.
; If DIMENSION is set and WIDTH is not
;
; OPTIONAL OUTPUTS:
;
; COMMENTS:
; The DIMENSION input is analogous to that used by the IDL built-in
; function TOTAL.
;
; I should like to add the functionality of having WIDTH be an N-dimensional
; smoothing box. For example, one should be able to median a 2-D image
; with a 3x5 filtering box.
;
; EXAMPLES:
; Create a 2-D image and compute the median of the entire image:
; > array = findgen(100,200)
; > print, djs_median(array)
;
; Create a data cube of 3 random-valued 100x200 images. At each pixel in
; the image, compute the median of the 3:
; > array = randomu(123,100,200,3)
; > medarr = djs_median(array,3)
;
; Create a random-valued 2-D image and median-filter with a 9x9 filtering box:
; > array = randomu(123,100,200)
; > medarr = djs_median(array,9)
;
; BUGS:
; The C routine only supports type FLOAT.
;
; PROCEDURES CALLED:
; Dynamic link to arrmedian.c
;
; REVISION HISTORY:
; 06-Jul-1999 Written by David Schlegel, Princeton.
;-
;------------------------------------------------------------------------------
function djs_median, array, dim, width=width, boundary=boundary
; Need at least 1 parameter
if (N_params() LT 1) then begin
print, 'Syntax - result = djs_median( array, [ dimension, width= ] )'
return, -1
endif
if (NOT keyword_set(boundary)) then boundary = 'none'
dimvec = size(array, /dimensions)
ndim = N_elements(dimvec)
if (NOT keyword_set(dim) AND NOT keyword_set(width)) then begin
if (n_elements(array) EQ 1) then medarr = array[0] $
else medarr = median(array, /even)
endif else if (NOT keyword_set(dim)) then begin
if (boundary EQ 'none') then begin
if (n_elements(array) EQ 1) then medarr = array[0] $
else if (width EQ 1) then medarr = array $
else medarr = median(array, width, /even)
endif else begin
padsize = ceil(width/2.) ; This padding will be at least 1 pixel
zero = array[0] - array[0] ; Zero in the type of ARRAY
if (ndim EQ 1) then begin
bigarr = bytarr(dimvec[0]+2*padsize) + zero
bigarr[padsize:padsize+dimvec[0]-1] = array
endif else if (ndim EQ 2) then begin
bigarr = bytarr(dimvec[0]+2*padsize, dimvec[1]+2*padsize) + zero
bigarr[padsize:padsize+dimvec[0]-1, padsize:padsize+dimvec[1]-1] $
= array
endif else begin
message, 'Unsupported number of dimensions with this b.c.'
endelse
if (ndim EQ 1) then begin
bigarr[0:padsize-1] = reverse(array[0:padsize-1])
bigarr[padsize+dimvec[0]:padsize*2+dimvec[0]-1] = $
array[dimvec[0]-padsize:dimvec[0]-1]
if (width GT 1) then $
bigarr = temporary( median(bigarr, width, /even) )
medarr = bigarr[padsize:padsize+dimvec[0]-1]
endif else begin
case boundary of
'nearest': begin
message, 'This boundary condition not implemented.'
end
'reflect': begin
; Copy into left + right
bigarr[0:padsize-1,padsize:dimvec[1]+padsize-1] = $
reverse(array[0:padsize-1,*],1)
bigarr[padsize+dimvec[0]:padsize*2+dimvec[0]-1, $
padsize:dimvec[1]+padsize-1] = $
reverse(array[dimvec[0]-padsize:dimvec[0]-1,*],1)
; Copy into bottom + top
bigarr[padsize:dimvec[0]+padsize-1,0:padsize-1] = $
reverse(array[*,0:padsize-1],2)
bigarr[padsize:padsize+dimvec[0]-1, $
padsize+dimvec[1]:padsize*2+dimvec[1]-1] = $
reverse(array[*,dimvec[1]-padsize:dimvec[1]-1],2)
; Copy into lower left
bigarr[0:padsize-1,0:padsize-1] = $
reverse(reverse(array[0:padsize-1,0:padsize-1],1),2)
; Copy into lower right
bigarr[padsize+dimvec[0]:padsize*2+dimvec[0]-1,0:padsize-1] = $
reverse(array[dimvec[0]-padsize:dimvec[0]-1,0:padsize-1],2)
; Copy into upper left
bigarr[0:padsize-1,padsize+dimvec[1]:padsize*2+dimvec[1]-1] = $
reverse(reverse(array[0:padsize-1, $
dimvec[1]-padsize:dimvec[1]-1],1),2)
; Copy into upper right
bigarr[padsize+dimvec[0]:padsize*2+dimvec[0]-1, $
padsize+dimvec[1]:padsize*2+dimvec[1]-1] = $
reverse(reverse(array[dimvec[0]-padsize:dimvec[0]-1, $
dimvec[1]-padsize:dimvec[1]-1],1),2)
if (width GT 1) then $
bigarr = temporary( median(bigarr, width, /even) )
medarr = bigarr[padsize:padsize+dimvec[0]-1, $
padsize:padsize+dimvec[1]-1]
end
'wrap': begin
message, 'This boundary condition not implemented.'
end
endcase
endelse
endelse
endif else if (NOT keyword_set(width)) then begin
if (ndim LE 1) then begin
message, 'ARRAY must be multi-dimensional if DIM is specified'
endif
if (dim GT ndim OR dim LT 1) then begin
message, 'DIM must be between 1 and '+string(ndim)+' inclusive'
endif
; Allocate memory for the output array
newdimvec = dimvec[ where(lindgen(ndim)+1 NE dim) ]
newsize = N_elements(array) / dimvec[dim-1]
medarr = reform(fltarr(newsize), newdimvec)
soname = filepath('libmath.so', $
root_dir=getenv('IDLUTILS_DIR'), subdirectory='lib')
retval = call_external(soname, 'arrmedian', $
ndim, dimvec, float(array), long(dim), medarr)
endif else begin
message, 'Invalid to specify both DIMENSION and WIDTH'
endelse
return, medarr
end
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;+
; NAME:
; djs_iterstat
;
; PURPOSE:
; Compute the mean, median and/or sigma of data with iterative sigma clipping.
;
; CALLING SEQUENCE:
; djs_iterstat, image, [sigrej=, maxiter=, mean=, median=, sigma=, mask=]
;
; INPUTS:
; image: Input data
;
; OPTIONAL INPUTS:
; sigrej: Sigma for rejection; default to 3.0
; maxiter: Maximum number of sigma rejection iterations; default to 10
;
; OUTPUTS:
;
; OPTIONAL OUTPUTS:
; mean: Computed mean
; median: Computed median
; sigma: Computed sigma
; mask: Mask set to 1 for good points, and 0 for rejected points
;
; PROCEDURES CALLED:
;
; COMMENTS:
; This routine is based upon Mark Dickinson's IRAF (!) script ITERSTAT.
; It iteratively rejects outliers as determined by SIGREJ. It stops
; when one of the following conditions is met:
; (1) The maximum number of iterations, as set by MAXITER, is reached.
; (2) No new pixels are rejected, as compared to the previous iteration.
; (3) At least 2 pixels remain from which to compute statistics. If not,
; then the returned values are based upon the previous iteration.
;
; BUGS:
;
; REVISION HISTORY:
; 16-Jun-1999 Written by David Schlegel, Princeton
; 11-Sep-2000 Speeded up by Hogg and Eisenstein
; 18-Sep-2000 Note change in MASK values to =1 for good (unrejected) points.
;-
;------------------------------------------------------------------------------
pro djs_iterstat, image, sigrej=sigrej, maxiter=maxiter, $
mean=fmean, median=fmedian, sigma=fsig, mask=mask
; Need 1 parameter
if N_params() LT 1 then begin
print, 'Syntax - djs_iterstat, image, [sigrej=, maxiter=, mean=, median=, sigma=,'
print, ' mask= ]'
return
endif
if (NOT keyword_set(sigrej)) then sigrej = 3.0
if (NOT keyword_set(maxiter)) then maxiter = 10
;----------
; Special cases of 0 or 1 data points
ngood = N_elements(image)
if (ngood EQ 0) then begin
print, 'No data points'
fmean = 0.0
fmedian = 0.0
fsig = 0.0
mask = 0B
return
endif
if (ngood EQ 1) then begin
print, 'Only 1 data point'
fmean = image[0]
fmedian = fmean
fsig = 0.0
mask = 0B
return
endif
;----------
; Compute the mean + stdev of the entire image.
; These values will be returned if there are fewer than 2 good points.
mask = bytarr(ngood) + 1
fmean = total(image*mask) / ngood
fsig = sqrt(total((image-fmean)^2*mask) / (ngood-1))
iiter = 1
;----------
; Iteratively compute the mean + stdev, updating the sigma-rejection
; thresholds each iteration.
nlast = -1
while (iiter LT maxiter AND nlast NE ngood AND ngood GE 2) do begin
loval = fmean - sigrej * fsig
hival = fmean + sigrej * fsig
nlast = ngood
mask = image GT loval AND image LT hival
ngood = total(mask)
if (ngood GE 2) then begin
fmean = total(image*mask) / ngood
fsig = sqrt( total((image-fmean)^2*mask) / (ngood-1) )
savemask = mask ; Save for computing the median using the same points
endif
iiter = iiter + 1
endwhile
if (arg_present(fmedian)) then begin
if (keyword_set(savemask)) then $
fmedian = median(image[where(savemask EQ 1)], /even) $
else $
fmedian = fmean
endif
return
end
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;+
; NAME:
; la_cosmic
;
; PURPOSE:
; Remove cosmic rays from imaging data. Images must be debiased for
; gain estimation to work properly.
;
; CALLING SEQUENCE:
; la_cosmic, imlist, [outlist=, masklist=, sigclip=, gain=, readn=, $
; skyval=,objlim=, niter=,sigfrac=,verbose=,statsec=, $
; zeroindexed=,masksuffix=, outsuff=,isbig=,blocksize=]
;
; INPUTS:
; imlist: List (strarr) of images to be cleaned or string with
; regexp of files
;
; OPTIONAL INPUTS:
; outlist: List (string array) of output cleaned images
; masklist: List of mask files associated with the cleaned images
; sigclip Level of cr clipping
; gain Gain of the CCD (< 0 to estimate) (default=-1.0)
; readn Readnoise of CCD (default=0.0)
; skyval Avg. of sky level already subtracted off the images (array)
; objlim Detection threshold for objects (not crs)
; niter How many passes to take
; sigfrac Sigfrac: see PASP paper
; verbose Verbose printing of steps?
; statsec image region for statistics
; string which can be of the form "[23:45,100:300]" or
; [*,100:400], etc.
; zeroindexed Is the image region zeroindexed?
; masksuffix Suffix to automatically determine mask output name
; outsuff Suffix to automatically determine output image name
; blocksize Size of working blocks. Keep in integer multiples of 512
; isbig Tell the routine to chop up the images in to more
; manageable sections of size blocksize x blocksize
;
; OUTPUTS:
;
; OPTIONAL OUTPUTS:
;
; PROCEDURES CALLED:
; DJS_ITERSTAT
; DJS_MEDIAN
; reckon_statsec
; lacos_replace
; astro-library
;
; COMMENTS:
; This routine is based on Pieter Van Dokkum's "LACOSMIC" Cosmic
; ray rejection routine for IRAF.
;
; If you find that after ~4 iterations that the routine is still
; finding up cosmic rays chances are that you are digging into the
; noise and or objects. Try setting the sigclip number a bit higher
;
; DEFAULTS:
; outlist: This will be set to the input list with the suffix
; outsuffix + '.fits'
; masklist: This will be set to the input list with the suffix
; masksuffix + '.fits'
; sigclip 4.5
; gain -1.0 (e-/DN) (forces routine to estimate for gain)
; readn 0.0
; skyval 0.0
; objlim 4.0
; niter 4
; sigfrac 0.5
; verbose 1 (yes)
; statsec "[*,*]" (use the entire image to estimate the gain)
; zeroindexed 0 (no)
; masksuffix "-mask"
; outsuff "-out"
; isbig 0
; blocksize 1024
;
; NOTES:
; (1) This routine will only work on .fits images
; (2) Haven't checked how useful it is on spectroscopic images.
; (3) Speed is clearly an issue. It takes about 21 seconds per iteration
; on a fairly zippy (650 PIII Linux 2.4 kernel) laptop on a 1k x 1k image.
; Using the isbig=1 the speed should scale as the number of
; pixels. So the scaling for speed is,
;
; t = 21 s * (n/1024)^2 * (cpu/650 MHz)^(-1)
;
; So that a 2k x 2k image will take ~80s per interation.
; EXAMPLES:
; 1. Remove the cosmic rays from a debiased flat-fielded HST STIS/Clear image
; hst1.fits and created a replaced image called hst1-cleaned.fits
; with a mask file called mask.fits. Set the read noise to be 4.46 e-
; and the gain to be = 1.0 (e-/DN)
;
; IDL> la_cosmic, ['hst1.fits'], masklist=['mask.fits'], $
; outsuffix="-cleaned", readn=4.46, gain=1.0
;
; 2. Remove the cosmic rays from all images starting with the name
; hst and create masks "hst*-mask.fits" and output images
; "hst*-out.fits". Set sigclip = 4. Let la_cosmic determine the gain
; from a region of [50:100,*] (indexed exactly as in IRAF, ie. unity
; indexed).
;
; IDL> la_cosmic, 'hst*.fits', outsuffix="-out",
; masksuffix="-mask",statsec="[50:100,*]",zeroindexed=0,
; gain = -1, sigclip = 4.0
;
; BUGS:
;
; 1. If the image has not been debiased, then the gain estimation
; will go horribly wrong. Could add a "biassec" parameter to
; allow the bias to be estimated.
; 2. Speed scaling of the routine works well until the point that
; the images are too large to store entirely in memory. Could write
; a little section which chops up the image in to manageable
; chunks and pastes those chuncks together...
;
; REVISION HISTORY:
; 20-May-2001 Written by Joshua Bloom, Caltech ([email protected])
;-
;------------------------------------------------------------------------------
pro la_cosmic, imlist, outlist=outlist, masklist=masklist, sigclip=sigclip, $
gain=gain, $
readn=readn, $
skyval=skyval,objlim=objlim, niter=niter,sigfrac=sigfrac, $
verbose=verbose,statsec=statsec,zeroindexed=zeroindexed,$
masksuffix=masksuff, outsuff=outsuff, isbig=isbig,blocksize=blocksize
;; set some sensible defaults
if ( (not keyword_set(outlist)) and (not keyword_set(outsuff))) then begin
outsuff = "-out"
endif
if ( (not keyword_set(masklist)) and (not keyword_set(masksuff))) then begin
masksuff = "-mask"
endif
nfiles = n_elements(imlist)
if (nfiles eq 1) then begin
;; nice to allow user to find a whole bunch of files
;; which match a particular describtion
imlist = file_search(imlist[0])
endif
nfiles = n_elements(imlist)
if (not keyword_set(outlist)) then outlist = imlist
if (not keyword_set(masklist)) then masklist = imlist
if (not keyword_set(gain)) then gain = -1.0
if (not keyword_set(readn)) then readn = 0.0
if (not keyword_set(skyval)) then begin
skyval = fltarr(nfiles)
endif
if (not keyword_set(sigclip)) then sigclip = 4.5
if (not keyword_set(sigfrac)) then sigfrac = 0.5
if (not keyword_set(objlim)) then objlim = 3.0
if (not keyword_set(niter)) then niter = 4
if (not keyword_set(verbose)) then verbose = 0
if ((not keyword_set(isbig)) and (not keyword_set(blocksize))) then begin
isbig = 0
endif
if keyword_set(blocksize) then begin
isbig = 1
endif
if (not keyword_set(blocksize)) then begin
blocksize = 512l
endif
if (not keyword_set(statsec)) then statsec = "[*,*]"
if (not keyword_set(zeroindexed)) then zeroindexed = 1
gain = double(gain)
readn = double(readn) > 0d0
if (nfiles le 0) then begin
print, "LACOSMIC: Sorry there's not much to do here. Returning."
return
endif
if ((nfiles ne n_elements(outlist) or (nfiles ne n_elements(masklist)))) then $
begin
print, "LACOSMIC: Sorry the number of elements in outlist, masklist, &" + $
" imlist must"
print, " match up. Leave masklist and outlist blank to " + $
"derive the outputted"
print, " names from the input names"
return
endif
if (verbose) then begin
print, ""
print, "----------------------------------------------------"
print, ""
print, " L.A. Cosmic: Laplacian cosmic ray removal"
print, ""
print, " by Pieter van Dokkum"
print, " IDL version by Josh Bloom"
print, ""
print, " Imaging version 1.0 (April 2001) "
print, "----------------------------------------------------"
endif
;; make the kernel as an array of 3x3
lakernel = [[0.0, -1.0, 0.0],[-1.0,4.0,-1.0],[0.0,-1.0,0.0]]
gkernel = [[1,1,1],[1,1,1],[1,1,1]]
for i=0, nfiles -1 do begin
filename = imlist[i]
if (verbose) then begin
print, "LACOSMIC: Working on image " + filename
endif
fxread, filename, oldoutput, oldheader
xsize = long(n_elements(oldoutput[*,0]))
ysize = long(n_elements(oldoutput[0,*]))
outmask = bytarr(xsize,ysize)
usegain = gain
sstop = 0
iter = 1
;if (skyval[i] gt 0.0) then oldoutput = temporary(oldoutput) + skyval[i]
xblock = blocksize ; 512l
yblock = blocksize ; 512l
if (isbig) then begin
;; we may have to do some chopping here. Chop the array into
;; blocks
if ((yblock GT ysize) and (xsize GT xblock)) then begin
;;; there's really no need to chop up here.
isbig = 0
potx = 1
poty = 1
regx = intarr(1,2)
regy = intarr(1,2)
regx[0,0] = 0l
regx[0,1] = xsize-1l
regy[0,0] = 0l
regy[0,1] = ysize-1l
endif else begin
potx = long(xsize) / long(xblock)
poty = long(ysize) / long(yblock)
;; create an array of indices which mark off the regions
;; of smaller blocks
regx = intarr(potx,2)
regy = intarr(poty,2)
regx[0,0] = 0
regx[0,1] = xblock - 1
regy[0,0] = 0
regy[0,1] = yblock - 1
for k=1,potx-2 do begin
regx[k,0] = regx[k-1,1] + 1
regx[k,1] = regx[k,0] + xblock - 1
endfor
;; the last block may be bigger than the others
regx[potx-1,0] = regx[potx-2,1] + 1
regx[potx-1,1] = xsize - 1
for k=1,poty-2 do begin
regy[k,0] = regy[k-1,1] + 1
regy[k,1] = regy[k,0] + xblock - 1
endfor
regy[poty-1,0] = regy[poty-2,1] + 1
regy[poty-1,1] = ysize - 1
endelse
endif else begin
;;; there's really no need to chop up here.
isbig = 0
potx = 1
poty = 1
regx = intarr(1,2)
regy = intarr(1,2)
regx[0,0] = 0l
regx[0,1] = xsize-1l
regy[0,0] = 0l
regy[0,1] = ysize-1l
endelse
while(not sstop) do begin
if (verbose) then begin
print, "-------------------Iteration" + $
strtrim(string(iter),2) + "------------------------"
endif
;; add back in the background if the user so desires
;oldoutput = oldoutput + skyval[i]
if (skyval[i] gt 0.0) then oldoutput = temporary(oldoutput) + skyval[i]
if (gain le 0.0) then begin
if (verbose and (iter eq 1)) then print, $
"Trying to determine gain automatically: "
if (verbose and (iter gt 1)) then print, $
"Improving gain estimate: "
;; figure out what statsection to use from the statsec
;; string
arr=reckon_statsec(statsec,[xsize,ysize])
if (zeroindexed eq 0) then begin
;; user gave a statsec region like IRAF. Unity indexed..
arr = arr - 1
endif
arr[1] = (arr[0] > arr[1]) < (xsize - 1)
arr[3] = (arr[2] > arr[3]) < (ysize - 1)
djs_iterstat, oldoutput[arr[0]:arr[1],arr[2]:arr[3]], $
sigrej=5.0, maxiter=10.0,mean=estmean,$
median=estmedian, sigma=estsigma
skylev = estmedian
;sigima = abs(oldoutput[arr[0]:arr[1],arr[2]:arr[3]] - $
; median(oldoutput[arr[0]:arr[1],arr[2]:arr[3]],7,/even))
sigima = abs(oldoutput[arr[0]:arr[1],arr[2]:arr[3]] - $
djs_median(oldoutput[arr[0]:arr[1],arr[2]:arr[3]],$
width=7,boundary='reflect'))
djs_iterstat, sigima, $
sigrej=5.0, maxiter=10.0,mean=estmean,$
median=estmedian, sigma=estsigma
sig = estmedian * 1.48
usegain = skylev/sig^2
if (verbose) then begin
print, " Approximate sky level = " + $
strtrim(string(skylev),2) + ' ADU'
print, " Sigma of sky = " + strtrim(string(sig),2)
print, " Estimated gain = " + strtrim(string(usegain),2)
endif
if (usegain le 0) then begin
print, 'LACOSMIC: error. Gain was found to be less than zero'
print, ' is it possible you forgot to give a "skyval"?'
return
endif
endif
if (verbose) then begin
print, 'Convolving image with Laplacian kernel'
print, ' '
endif
;; we've got to chop this image up
nchop = 1
ncosmicray = 0
for xchop = 0, potx - 1 do begin
for ychop = 0, poty - 1 do begin
oldoutputwork = oldoutput[regx[xchop,0]:regx[xchop,1], $
regy[ychop,0]:regy[ychop,1]]
outmaskwork = outmask[regx[xchop,0]:regx[xchop,1], $
regy[ychop,0]:regy[ychop,1]]
if (verbose) then begin
print, 'Working on block #' + strtrim(string(nchop),2) + $
' out of ' + strtrim(string(potx*poty),2)
endif
;; rebin the image and convolve with the kernel then rebin
tmpxsize = regx[xchop,1] - regx[xchop,0] + 1
tmpysize = regy[ychop,1] - regy[ychop,0] + 1
im2 = rebin( (convol(rebin(oldoutputwork,2*tmpxsize, $
2*tmpysize,/sample), $
lakernel,1,/center,/edge_truncate) > 0.0), $
tmpxsize, tmpysize)
;; compute the 5x5 median to remove all the cosmic rays
med5 = djs_median(oldoutputwork,width=5,boundary='reflect')
;med5 = median(oldoutput,5,/even)
;; NOTE: the boundary is not handled the same as in IRAF
;; This affects the outer 2 pixel boundary...could change
;; with some kludges...
; SAME but slower: med5 = lacos_replace(med5,0.0001,'INDEF', 0.0)
bad = med5 LE 0.0
med5 = 0.0001 * bad + temporary(med5) * (1.0 - bad)
bad = [0]
;; create a noise model based on this median image knowing the
;; gain, and readnoise of the image
;; note that this step supposes that no sky background subtration
;; has been done
if (verbose) then begin
print, 'Creating noise model using:'
print, ' gain = ' + strtrim(string(usegain),2)
print, ' readnoise = ' + strtrim(string(readn),2)
endif
noise = sqrt(med5*usegain + readn^2)/usegain
med5 = [0]
sigmap = im2/noise/2.d
;; free up some memory
im2 = [0]
sigmap = -1.0 * (djs_median(sigmap,width=5,boundary='reflect') - $
temporary(sigmap))
;; do a replacement setting all the high values to 1
firstsel = sigmap
firstsel = firstsel * (firstsel GT sigclip)
firstsel = firstsel * (firstsel LT 0.1) + (firstsel GE 0.1)
;med3 = median(oldoutput,3,/even)
;med7 = median(med3,7,/even)
med3 = djs_median(oldoutputwork,width=3,boundary='reflect')
med7 = djs_median(med3,width=7,boundary='reflect')
med3 = (temporary(med3) - med7)/noise
noise = [0]
med7 = [0]
med3 = temporary(med3) > 0.01
starreject = firstsel*sigmap/med3
med3 = [0]
firstsel = temporary(firstsel) * (starreject GT objlim)
starreject = [0]
;; grow CRs by one pixel and check in original sigma map
gfirstsel = convol(firstsel,gkernel,/center,/edge_truncate)
firstsel = [0]
gfirstsel = sigmap * ((gfirstsel GT 0.5) + $
gfirstsel*(gfirstsel LE 0.5))
gfirstsel = (temporary(gfirstsel) GT sigclip)
sigcliplow = sigfrac * sigclip
finalsel = convol(gfirstsel,gkernel,/center,/edge_truncate)
finalsel = sigmap * ((finalsel GT 0.5) + $
finalsel*(finalsel LE 0.5))
sigmap = [0]
finalsel = (temporary(finalsel) GT sigcliplow)
;; how many cosmic rays were found here
gfirstsel = (1.0 - outmaskwork)*finalsel
ttt = where(gfirstsel ge 0.5,npix)
ttt = [0]
gfirstsel = [0]
outmaskwork = (temporary(outmaskwork) + finalsel) < 1
finalsel = [0]
ncosmicray = ncosmicray + npix
inputmask = (1.0 - 10000.0*outmaskwork)*oldoutputwork
inputmask = lacos_replace(inputmask, !VALUES.F_NAN,'INDEF',-9999)
;med5 = median(inputmask,5,/even)*outmask
med5 = djs_median(inputmask,width=5,boundary='reflect')*outmaskwork
inputmask = [0]
output = (1.0 - outmaskwork)*oldoutputwork + med5
med5 = [0]
oldoutput[regx[xchop,0]:regx[xchop,1],regy[ychop,0]:regy[ychop,1]] = $
output[0:(tmpxsize-1),0:(tmpysize-1)]
outmask[regx[xchop,0]:regx[xchop,1],regy[ychop,0]:regy[ychop,1]] = $
outmaskwork[0:(tmpxsize-1),0:(tmpysize-1)]
nchop = nchop + 1
endfor
endfor
print, 'Found ' + strtrim(string(ncosmicray)) + ' cosmic rays in iteration ' + strtrim(string(iter))
if (ncosmicray eq 0) then sstop = 1
iter = iter + 1
if (iter gt niter) then sstop = 1
if (skyval[i] > 0) then oldoutput = temporary(oldoutput) - skyval[i]
;; groovy ---------------------------------------
endwhile
;; save the output image and the outmask
troot = strsplit(imlist[i],".fits",/extract,/regex)
tmp = strsplit(outlist[i],".fits",/extract,/regex)
if (outlist[i] eq imlist[i]) then begin
outname = tmp[0] + outsuff + ".fits"
endif else begin
outname = tmp[0] + '.fits'
endelse
tmp = strsplit(masklist[i],".fits",/extract,/regex)
if (masklist[i] eq imlist[i]) then begin
maskname = tmp[0] + masksuff + ".fits"
endif else begin
maskname = tmp[0] + '.fits'
endelse
print, 'Writing mask image = ' + maskname
print, ' output image = ' + outname
fxhmake,h,outmask
fxwrite,maskname,h,outmask
fxhmake,h,oldoutput
fxwrite,outname,h,oldoutput
endfor
return
end