/usr/share/gnudatalanguage/astrolib/mmm.pro is in gdl-astrolib 2018.02.16+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | pro mmm, sky_vector, skymod, sigma , skew, HIGHBAD = highbad, DEBUG = debug, $
ReadNoise = readnoise, Nsky = nsky, INTEGER = discrete, $
MAXITER = mxiter, SILENT = silent, MINSKY = minsky
;+
; NAME:
; MMM
; PURPOSE:
; Estimate the sky background in a stellar contaminated field.
; EXPLANATION:
; MMM assumes that contaminated sky pixel values overwhelmingly display
; POSITIVE departures from the true value. Adapted from DAOPHOT
; routine of the same name.
;
; CALLING SEQUENCE:
; MMM, sky, [ skymod, sigma, skew, HIGHBAD = , READNOISE=, /DEBUG,
; MINSKY=, NSKY=, /INTEGER,/SILENT]
;
; INPUTS:
; SKY - Array or Vector containing sky values. This version of
; MMM does not require SKY to be sorted beforehand. SKY
; is unaltered by this program.
;
; OPTIONAL OUTPUTS:
; skymod - Scalar giving estimated mode of the sky values (float)
; SIGMA - Scalar giving standard deviation of the peak in the sky
; histogram. If for some reason it is impossible to derive
; skymod, then SIGMA = -1.0
; SKEW - Scalar giving skewness of the peak in the sky histogram
;
; If no output variables are supplied or if /DEBUG is set
; then the values of skymod, SIGMA and SKEW will be printed.
;
; OPTIONAL KEYWORD INPUTS:
; HIGHBAD - scalar value of the (lowest) "bad" pixel level (e.g. cosmic
; rays or saturated pixels) If not supplied, then there is
; assumed to be no high bad pixels.
; MINSKY - Integer giving mininum number of sky values to be used. MMM
; will return an error if fewer sky elements are supplied.
; Default = 20.
; MAXITER - integer giving maximum number of iterations allowed,default=50
; READNOISE - Scalar giving the read noise (or minimum noise for any
; pixel). Normally, MMM determines the (robust) median by
; averaging the central 20% of the sky values. In some cases
; where the noise is low, and pixel values are quantized a
; larger fraction may be needed. By supplying the optional
; read noise parameter, MMM is better able to adjust the
; fraction of pixels used to determine the median.
; /INTEGER - Set this keyword if the input SKY vector only contains
; discrete integer values. This keyword is only needed if the
; SKY vector is of type float or double precision, but contains
; only discrete integer values. (Prior to July 2004, the
; equivalent of /INTEGER was set for all data types)
; /DEBUG - If this keyword is set and non-zero, then additional
; information is displayed at the terminal.
; /SILENT - If set, then error messages will be suppressed when MMM
; cannot compute a background. Sigma will still be set to -1
; OPTIONAL OUTPUT KEYWORD:
; NSKY - Integer scalar giving the number of pixels actually used for the
; sky computation (after outliers have been removed).
; NOTES:
; (1) Program assumes that low "bad" pixels (e.g. bad CCD columns) have
; already been deleted from the SKY vector.
; (2) MMM was updated in June 2004 to better match more recent versions
; of DAOPHOT.
; (3) Does not work well in the limit of low Poisson integer counts
; (4) MMM may fail for strongly skewed distributions.
; METHOD:
; The algorithm used by MMM consists of roughly two parts:
; (1) The average and sigma of the sky pixels is computed. These values
; are used to eliminate outliers, i.e. values with a low probability
; given a Gaussian with specified average and sigma. The average
; and sigma are then recomputed and the process repeated up to 20
; iterations:
; (2) The amount of contamination by stars is estimated by comparing the
; mean and median of the remaining sky pixels. If the mean is larger
; than the median then the true sky value is estimated by
; 3*median - 2*mean
;
; REVISION HISTORY:
; Adapted to IDL from 1986 version of DAOPHOT in STSDAS,
; W. Landsman, STX Feb 1987
; Added HIGHBAD keyword, W. Landsman January, 1991
; Fixed occasional problem with integer inputs W. Landsman Feb, 1994
; Avoid possible 16 bit integer overflow W. Landsman November 2001
; Added READNOISE, NSKY keywords, new median computation
; W. Landsman June 2004
; Added INTEGER keyword W. Landsman July 2004
; Improve numerical precision W. Landsman October 2004
; Fewer aborts on strange input sky histograms W. Landsman October 2005
; Added /SILENT keyword November 2005
; Fix too many /CON keywords to MESSAGE W.L. December 2005
; Fix bug introduced June 2004 removing outliers when READNOISE not set
; N. Cunningham/W. Landsman January 2006
; Make sure that MESSAGE never aborts W. Landsman January 2008
; Add mxiter keyword and change default to 50 W. Landsman August 2011
; Added MINSKY keyword W.L. December 2011
; Always return floating point sky mode W.L. December 2015
;-
compile_opt idl2
On_error,2 ;Return to caller
if N_params() EQ 0 then begin
print,'Syntax: MMM, sky, skymod, sigma, skew, [/INTEGER, /SILENT'
print,' [HIGHBAD = , READNOISE =, /DEBUG, MXITER=, NSKY=] '
return
endif
silent = keyword_set(SILENT)
;Maximum number of iterations allowed
if N_elements(mxiter) EQ 0 then mxiter = 50
if N_elements(minsky) Eq 0 then minsky = 20 ;Minimum number of legal sky elements
nsky = N_elements( sky_vector ) ;Get number of sky elements
if nsky LT minsky then begin
sigma=-1.0 & skew = 0.0
message,/CON, NoPrint= Silent, $
'ERROR -Input vector must contain at least '+strtrim(minsky,2)+' elements'
return
endif
nlast = nsky-1 ;Subscript of last pixel in SKY array
if keyword_set(DEBUG) then $
message,'Processing '+strtrim(nsky,2) + ' element array',/INF
sz_sky = size(sky_vector,/structure)
integer = keyword_set(discrete)
if ~integer then integer = (sz_sky.type LT 4) or (sz_sky.type GT 11)
sky = sky_vector[ sort( sky_vector ) ] ;Sort SKY in ascending values
skymid = 0.5*sky[(nsky-1)/2] + 0.5*sky[nsky/2] ;Median value of all sky values
cut1 = min( [skymid-sky[0],sky[nsky-1] - skymid] )
if N_elements(highbad) EQ 1 then cut1 = cut1 < (highbad - skymid)
cut2 = skymid + cut1
cut1 = skymid - cut1
; Select the pixels between Cut1 and Cut2
good = where( (sky LE cut2) and (sky GE cut1), Ngood )
if ( Ngood EQ 0 ) then begin
sigma=-1.0 & skew = 0.0
message,/CON, NoPrint=Silent, $
'ERROR - No sky values fall within ' + strtrim(cut1,2) + $
' and ' + strtrim(cut2,2)
return
endif
delta = sky[good] - skymid ;Subtract median to improve arithmetic accuracy
sum = total(delta,/double)
sumsq = total(delta^2,/double)
maximm = max( good,MIN=minimm ) ;Highest value accepted at upper end of vector
minimm = minimm -1 ;Highest value reject at lower end of vector
; Compute mean and sigma (from the first pass).
skymed = 0.5*sky[(minimm+maximm+1)/2] + 0.5*sky[(minimm+maximm)/2 + 1] ;median
skymn = float(sum/(maximm-minimm)) ;mean
sigma = sqrt(sumsq/(maximm-minimm)-skymn^2) ;sigma
skymn = skymn + skymid ;Add median which was subtracted off earlier
; If mean is less than the mode, then the contamination is slight, and the
; mean value is what we really want.
skymod = (skymed LT skymn) ? 3.*skymed - 2.*skymn : skymn
; Rejection and recomputation loop:
niter = 0
clamp = 1
old = 0
START_LOOP:
niter = niter + 1
if ( niter GT mxiter ) then begin
sigma=-1.0 & skew = 0.0
message,/CON, NoPrint=Silent, $
'ERROR - Too many ('+strtrim(mxiter,2) + ') iterations,' + $
' unable to compute sky'
return
endif
if ( maximm-minimm LT minsky ) then begin ;Error?
sigma = -1.0 & skew = 0.0
message,/CON,NoPrint=Silent, $
'ERROR - Too few ('+strtrim(maximm-minimm,2) + $
') valid sky elements, unable to compute sky'
return
endif
; Compute Chauvenet rejection criterion.
r = alog10( float( maximm-minimm ) )
r = max( [ 2., ( -0.1042*r + 1.1695)*r + 0.8895 ] )
; Compute rejection limits (symmetric about the current mode).
cut = r*sigma + 0.5*abs(skymn-skymod)
if integer then cut = cut > 1.5
cut1 = skymod - cut & cut2 = skymod + cut
;
; Recompute mean and sigma by adding and/or subtracting sky values
; at both ends of the interval of acceptable values.
redo = 0B
newmin = minimm
tst_min = sky[newmin+1] GE cut1 ;Is minimm+1 above current CUT?
done = (newmin EQ -1) and tst_min ;Are we at first pixel of SKY?
if ~done then $
done = (sky[newmin>0] LT cut1) and tst_min
if ~done then begin
istep = 1 - 2*fix(tst_min)
repeat begin
newmin = newmin + istep
done = (newmin EQ -1) || (newmin EQ nlast)
if ~done then $
done = (sky[newmin] LE cut1) and (sky[newmin+1] GE cut1)
endrep until done
if tst_min then delta = sky[newmin+1:minimm] - skymid $
else delta = sky[minimm+1:newmin] - skymid
sum = sum - istep*total(delta,/double)
sumsq = sumsq - istep*total(delta^2,/double)
redo = 1b
minimm = newmin
endif
;
newmax = maximm
tst_max = sky[maximm] LE cut2 ;Is current maximum below upper cut?
done = (maximm EQ nlast) and tst_max ;Are we at last pixel of SKY array?
if ~done then $
done = ( tst_max ) && (sky[(maximm+1)<nlast] GT cut2)
if ~done then begin ;Keep incrementing NEWMAX
istep = -1 + 2*fix(tst_max) ;Increment up or down?
Repeat begin
newmax = newmax + istep
done = (newmax EQ nlast) or (newmax EQ -1)
if ~done then $
done = ( sky[newmax] LE cut2 ) and ( sky[newmax+1] GE cut2 )
endrep until done
if tst_max then delta = sky[maximm+1:newmax] - skymid $
else delta = sky[newmax+1:maximm] - skymid
sum = sum + istep*total(delta,/double)
sumsq = sumsq + istep*total(delta^2,/double)
redo = 1b
maximm = newmax
endif
;
; Compute mean and sigma (from this pass).
;
nsky = maximm - minimm
if ( nsky LT minsky ) then begin ;Error?
sigma = -1.0 & skew = 0.0
message,NoPrint=Silent, /CON, $
'ERROR - Outlier rejection left too few sky elements'
return
endif
skymn = float(sum/nsky)
sigma = float( sqrt( (sumsq/nsky - skymn^2)>0 ))
skymn = skymn + skymid
; Determine a more robust median by averaging the central 20% of pixels.
; Estimate the median using the mean of the central 20 percent of sky
; values. Be careful to include a perfectly symmetric sample of pixels about
; the median, whether the total number is even or odd within the acceptance
; interval
center = (minimm + 1 + maximm)/2.
side = round(0.2*(maximm-minimm))/2. + 0.25
J = round(CENTER-SIDE)
K = round(CENTER+SIDE)
; In case the data has a large number of of the same (quantized)
; intensity, expand the range until both limiting values differ from the
; central value by at least 0.25 times the read noise.
if keyword_set(readnoise) then begin
L = round(CENTER-0.25)
M = round(CENTER+0.25)
R = 0.25*readnoise
while ((J GT 0) && (K LT Nsky-1) && $
( ((sky[L] - sky[J]) LT R) || ((sky[K] - sky[M]) LT R))) do begin
J--
K++
endwhile
endif
skymed = total(sky[j:k])/(k-j+1)
; If the mean is less than the median, then the problem of contamination
; is slight, and the mean is what we really want.
dmod = skymed LT skymn ? 3.*skymed-2.*skymn-skymod : skymn - skymod
; prevent oscillations by clamping down if sky adjustments are changing sign
if dmod*old LT 0 then clamp = 0.5*clamp
skymod = skymod + clamp*dmod
old = dmod
if redo then goto, START_LOOP
;
skew = float( (skymn-skymod)/max([1.,sigma]) )
nsky = maximm - minimm
if keyword_set(DEBUG) or ( N_params() EQ 1 ) then begin
print, '% MMM: Number of unrejected sky elements: ', strtrim(nsky,2), $
' Number of iterations: ', strtrim(niter,2)
print, '% MMM: Mode, Sigma, Skew of sky vector:', skymod, sigma, skew
endif
return
end
|