LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
Public Member Functions | Static Public Attributes | Private Member Functions | List of all members
lsst.ip.isr.fringe.FringeTask Class Reference
Inheritance diagram for lsst.ip.isr.fringe.FringeTask:

Public Member Functions

def readFringes
 
def run
 
def runDataRef
 
def checkFilter
 
def removePedestal
 
def generatePositions
 
def measureExposure
 
def solve
 
def subtract
 

Static Public Attributes

 ConfigClass = FringeConfig
 

Private Member Functions

def _solve
 

Detailed Description

Task to remove fringes from a science exposure

We measure fringe amplitudes at random positions on the science exposure
and at the same positions on the (potentially multiple) fringe frames
and solve for the scales simultaneously.

Definition at line 61 of file fringe.py.

Member Function Documentation

def lsst.ip.isr.fringe.FringeTask._solve (   self,
  science,
  fringes 
)
private
Solve for the scale factors

@param science     Array of science exposure fringe amplitudes
@param fringes     Array of arrays of fringe frame fringe amplitudes
@return Array of scale factors for the fringe frames

Definition at line 300 of file fringe.py.

301  def _solve(self, science, fringes):
302  """Solve for the scale factors
303 
304  @param science Array of science exposure fringe amplitudes
305  @param fringes Array of arrays of fringe frame fringe amplitudes
306  @return Array of scale factors for the fringe frames
307  """
308  return afwMath.LeastSquares.fromDesignMatrix(fringes, science,
309  afwMath.LeastSquares.DIRECT_SVD).getSolution()
def lsst.ip.isr.fringe.FringeTask.checkFilter (   self,
  exposure 
)
Check whether we should fringe-subtract the science exposure

Definition at line 159 of file fringe.py.

160  def checkFilter(self, exposure):
161  """Check whether we should fringe-subtract the science exposure"""
162  return exposure.getFilter().getName() in self.config.filters
def lsst.ip.isr.fringe.FringeTask.generatePositions (   self,
  exposure,
  rng 
)
Generate a random distribution of positions for measuring fringe amplitudes

Definition at line 173 of file fringe.py.

174  def generatePositions(self, exposure, rng):
175  """Generate a random distribution of positions for measuring fringe amplitudes"""
176  start = self.config.large
177  num = self.config.num
178  width = exposure.getWidth() - self.config.large
179  height = exposure.getHeight() - self.config.large
180  return numpy.array([rng.randint(start, width, size=num),
181  rng.randint(start, height, size=num)]).swapaxes(0, 1)
def lsst.ip.isr.fringe.FringeTask.measureExposure (   self,
  exposure,
  positions,
  title = "Fringe" 
)
Measure fringe amplitudes for an exposure

The fringe amplitudes are measured as the statistic within a square
aperture.  The statistic within a larger aperture are subtracted so
as to remove the background.

@param exposure    Exposure to measure
@param positions   Array of (x,y) for fringe measurement
@param title       Title for display
@return Array of fringe measurements

Definition at line 183 of file fringe.py.

184  def measureExposure(self, exposure, positions, title="Fringe"):
185  """Measure fringe amplitudes for an exposure
186 
187  The fringe amplitudes are measured as the statistic within a square
188  aperture. The statistic within a larger aperture are subtracted so
189  as to remove the background.
190 
191  @param exposure Exposure to measure
192  @param positions Array of (x,y) for fringe measurement
193  @param title Title for display
194  @return Array of fringe measurements
195  """
196  stats = afwMath.StatisticsControl()
197  stats.setNumSigmaClip(self.config.stats.clip)
198  stats.setNumIter(self.config.stats.iterations)
199  stats.setAndMask(exposure.getMaskedImage().getMask().getPlaneBitMask(self.config.stats.badMaskPlanes))
200 
201  num = self.config.num
202  fringes = numpy.ndarray(num)
203 
204  for i in range(num):
205  x, y = positions[i]
206  small = measure(exposure.getMaskedImage(), x, y, self.config.small, self.config.stats.stat, stats)
207  large = measure(exposure.getMaskedImage(), x, y, self.config.large, self.config.stats.stat, stats)
208  fringes[i] = small - large
209 
210  import lsstDebug
211  display = lsstDebug.Info(__name__).display
212  if display:
213  frame = getFrame()
214  ds9.mtv(exposure, frame=frame, title=title)
215  if False:
216  with ds9.Buffering():
217  for x,y in positions:
218  corners = numpy.array([[-1, -1], [ 1, -1], [ 1, 1], [-1, 1], [-1, -1]]) + [[x, y]]
219  ds9.line(corners * self.config.small, frame=frame, ctype="green")
220  ds9.line(corners * self.config.large, frame=frame, ctype="blue")
221 
222  return fringes
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Definition: Statistics.h:92
def lsst.ip.isr.fringe.FringeTask.readFringes (   self,
  dataRef,
  assembler = None 
)
Read the fringe frame(s)

The current implementation assumes only a single fringe frame and
will have to be updated to support multi-mode fringe subtraction.

This implementation could be optimised by persisting the fringe
positions and fluxes.

@param dataRef     Data reference for the science exposure
@param assembler   An instance of AssembleCcdTask (for assembling fringe frames)
@return Struct(fringes: fringe exposure or list of fringe exposures;
       seed: 32-bit uint derived from ccdExposureId for random number generator

Definition at line 70 of file fringe.py.

70 
71  def readFringes(self, dataRef, assembler=None):
72  """Read the fringe frame(s)
73 
74  The current implementation assumes only a single fringe frame and
75  will have to be updated to support multi-mode fringe subtraction.
76 
77  This implementation could be optimised by persisting the fringe
78  positions and fluxes.
79 
80  @param dataRef Data reference for the science exposure
81  @param assembler An instance of AssembleCcdTask (for assembling fringe frames)
82  @return Struct(fringes: fringe exposure or list of fringe exposures;
83  seed: 32-bit uint derived from ccdExposureId for random number generator
84  """
85  try:
86  fringe = dataRef.get("fringe", immediate=True)
87  except Exception as e:
88  raise RuntimeError("Unable to retrieve fringe for %s: %s" % (dataRef.dataId, e))
89  if assembler is not None:
90  fringe = assembler.assembleCcd(fringe)
91 
92  seed = self.config.stats.rngSeedOffset + dataRef.get("ccdExposureId", immediate=True)
93  #Seed for numpy.random.RandomState must be convertable to a 32 bit unsigned integer
94  seed %= 2**32
95 
96  return Struct(fringes = fringe,
97  seed = seed)
def lsst.ip.isr.fringe.FringeTask.removePedestal (   self,
  fringe 
)
Remove pedestal from fringe exposure

Definition at line 163 of file fringe.py.

164  def removePedestal(self, fringe):
165  """Remove pedestal from fringe exposure"""
166  stats = afwMath.StatisticsControl()
167  stats.setNumSigmaClip(self.config.stats.clip)
168  stats.setNumIter(self.config.stats.iterations)
169  mi = fringe.getMaskedImage()
170  pedestal = afwMath.makeStatistics(mi, afwMath.MEDIAN, stats).getValue()
171  self.log.info("Removing fringe pedestal: %f" % pedestal)
172  mi -= pedestal
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Definition: Statistics.h:92
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1082
def lsst.ip.isr.fringe.FringeTask.run (   self,
  exposure,
  fringes,
  seed = None 
)
Remove fringes from the provided science exposure.

Primary method of FringeTask.  Fringes are only subtracted if the
science exposure has a filter listed in the configuration.

@param exposure    Science exposure from which to remove fringes
@param fringes     Exposure or list of Exposures
@param seed        32-bit unsigned integer for random number generator

Definition at line 99 of file fringe.py.

99 
100  def run(self, exposure, fringes, seed=None):
101  """Remove fringes from the provided science exposure.
102 
103  Primary method of FringeTask. Fringes are only subtracted if the
104  science exposure has a filter listed in the configuration.
105 
106  @param exposure Science exposure from which to remove fringes
107  @param fringes Exposure or list of Exposures
108  @param seed 32-bit unsigned integer for random number generator
109  """
110  import lsstDebug
111  display = lsstDebug.Info(__name__).display
112 
113  if not self.checkFilter(exposure):
114  return
115 
116  if self.config.pedestal:
117  self.removePedestal(fringes)
118 
119  if seed is None:
120  seed = self.config.stats.rngSeedOffset
121  rng = numpy.random.RandomState(seed=seed)
122 
123  if hasattr(fringes, '__iter__'):
124  #multiple fringe frames (placeholder implementation)
125  positions = self.generatePositions(fringes[0], rng)
126  fluxes = numpy.ndarray([len(positions), len(fringes)])
127  for i, f in enumerate(fringes):
128  fluxes[:,i] = self.measureExposure(f, positions, title="Fringe frame")
129  else:
130  #single fringe frame
131  positions = self.generatePositions(fringes, rng)
132  fluxes = self.measureExposure(fringes, positions, title="Fringe frame")
133  fluxes = fluxes.reshape([len(positions), 1])
134  fringes = [fringes]
135 
136  expFringes = self.measureExposure(exposure, positions, title="Science")
137  solution = self.solve(expFringes, fluxes)
138  self.subtract(exposure, fringes, solution)
139  if display:
140  ds9.mtv(exposure, title="Fringe subtracted", frame=getFrame())
def lsst.ip.isr.fringe.FringeTask.runDataRef (   self,
  exposure,
  dataRef,
  assembler = None 
)
Remove fringes from the provided science exposure.

Retrieve fringes from butler dataRef provided and remove from
provided science exposure.
Fringes are only subtracted if the science exposure has a filter
listed in the configuration.

@param exposure    Science exposure from which to remove fringes
@param dataRef     Data reference for the science exposure
@param assembler   An instance of AssembleCcdTask (for assembling fringe frames)

Definition at line 142 of file fringe.py.

143  def runDataRef(self, exposure, dataRef, assembler=None):
144  """Remove fringes from the provided science exposure.
145 
146  Retrieve fringes from butler dataRef provided and remove from
147  provided science exposure.
148  Fringes are only subtracted if the science exposure has a filter
149  listed in the configuration.
150 
151  @param exposure Science exposure from which to remove fringes
152  @param dataRef Data reference for the science exposure
153  @param assembler An instance of AssembleCcdTask (for assembling fringe frames)
154  """
155  if not self.checkFilter(exposure):
156  return
157  fringeStruct = self.readFringes(dataRef, assembler=assembler)
158  self.run(exposure, **fringeStruct.getDict())
def lsst.ip.isr.fringe.FringeTask.solve (   self,
  science,
  fringes 
)
Solve (with iterative clipping) for the scale factors

@param science     Array of science exposure fringe amplitudes
@param fringes     Array of arrays of fringe frame fringe amplitudes
@return Array of scale factors for the fringe frames

Definition at line 224 of file fringe.py.

225  def solve(self, science, fringes):
226  """Solve (with iterative clipping) for the scale factors
227 
228  @param science Array of science exposure fringe amplitudes
229  @param fringes Array of arrays of fringe frame fringe amplitudes
230  @return Array of scale factors for the fringe frames
231  """
232  import lsstDebug
233  doPlot = lsstDebug.Info(__name__).plot
234 
235  origNum = len(science)
236 
237  good = numpy.where(numpy.logical_and(numpy.isfinite(science), numpy.any(numpy.isfinite(fringes), 1)))
238  science = science[good]
239  fringes = fringes[good]
240  oldNum = len(science)
241 
242  for i in range(self.config.iterations):
243  solution = self._solve(science, fringes)
244  resid = science - numpy.sum(solution * fringes, 1)
245  rms = stdev(resid)
246  good = numpy.logical_not(abs(resid) > self.config.clip * rms)
247  self.log.logdebug("Iteration %d: RMS=%f numGood=%d" % (i, rms, good.sum()))
248  self.log.logdebug("Solution %d: %s" % (i, solution))
249  newNum = good.sum()
250 
251  if doPlot:
252  import matplotlib.pyplot as plot
253  for j in range(fringes.shape[1]):
254  fig = plot.figure(j)
255  fig.clf()
256  try:
257  fig.canvas._tkcanvas._root().lift() # == Tk's raise
258  except:
259  pass
260  ax = fig.add_axes((0.1, 0.1, 0.8, 0.8))
261  adjust = science.copy()
262  others = set(range(fringes.shape[1]))
263  others.discard(j)
264  for k in others:
265  adjust -= solution[k] * fringes[:,k]
266  ax.plot(fringes[:,j], adjust, 'r.')
267  xmin = fringes[:,j].min()
268  xmax = fringes[:,j].max()
269  ymin = solution[j] * xmin
270  ymax = solution[j] * xmax
271  ax.plot([xmin, xmax], [ymin, ymax], 'b-')
272  ax.set_title("Fringe %d: %f" % (j, solution[j]))
273  ax.set_xlabel("Fringe amplitude")
274  ax.set_ylabel("Science amplitude")
275  ax.set_autoscale_on(False)
276  ax.set_xbound(lower=xmin, upper=xmax)
277  ax.set_ybound(lower=ymin, upper=ymax)
278  fig.show()
279  while True:
280  ans = raw_input("Enter or c to continue [chp]").lower()
281  if ans in ("", "c",):
282  break
283  if ans in ("p",):
284  import pdb; pdb.set_trace()
285  elif ans in ("h", ):
286  print "h[elp] c[ontinue] p[db]"
287 
288  if newNum == oldNum:
289  # Not gaining
290  break
291  oldNum = newNum
292  good = numpy.where(good)
293  science = science[good]
294  fringes = fringes[good]
295 
296  # Final solution without rejection
297  solution = self._solve(science, fringes)
298  self.log.info("Fringe solution: %s RMS: %f Good: %d/%d" % (solution, rms, len(science), origNum))
299  return solution
def lsst.ip.isr.fringe.FringeTask.subtract (   self,
  science,
  fringes,
  solution 
)
Subtract the fringes

@param science     Science exposure
@param fringes     List of fringe frames
@param solution    Array of scale factors for the fringe frames

Definition at line 310 of file fringe.py.

311  def subtract(self, science, fringes, solution):
312  """Subtract the fringes
313 
314  @param science Science exposure
315  @param fringes List of fringe frames
316  @param solution Array of scale factors for the fringe frames
317  """
318  if len(solution) != len(fringes):
319  raise RuntimeError("Number of fringe frames (%s) != number of scale factors (%s)"% \
320  (len(fringes), len(solution)))
321 
322  for s, f in zip(solution, fringes):
323  science.getMaskedImage().scaledMinus(s, f.getMaskedImage())
324 

Member Data Documentation

lsst.ip.isr.fringe.FringeTask.ConfigClass = FringeConfig
static

Definition at line 68 of file fringe.py.


The documentation for this class was generated from the following file: