LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin Class Reference
Inheritance diagram for lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin:

Public Member Functions

def getExecutionOrder (cls)
 
def __init__ (self, config, name, schema, metadata)
 
def measure (self, measRecord, exposure, posExp=None, negExp=None)
 
def doClassify (self, measRecord, chi2val)
 
def fail (self, measRecord, error=None)
 

Public Attributes

 log
 
 centroidKey
 
 fluxKey
 
 orientationKey
 
 separationKey
 
 chi2dofKey
 
 signalToNoiseKey
 
 classificationFlagKey
 
 classificationAttemptedFlagKey
 
 flagKey
 
 edgeFlagKey
 

Static Public Attributes

 ConfigClass = DipoleFitPluginConfig
 
 DipoleFitAlgorithmClass = DipoleFitAlgorithm
 
int FAILURE_EDGE = 1
 
int FAILURE_FIT = 2
 
int FAILURE_NOT_DIPOLE = 4
 

Detailed Description

A single frame measurement plugin that fits dipoles to all merged (two-peak) ``diaSources``.

This measurement plugin accepts up to three input images in
its `measure` method. If these are provided, it includes data
from the pre-subtraction posImage (science image) and optionally
negImage (template image) to constrain the fit. The meat of the
fitting routines are in the class `~lsst.module.name.DipoleFitAlgorithm`.

Notes
-----
The motivation behind this plugin and the necessity for including more than
one exposure are documented in DMTN-007 (http://dmtn-007.lsst.io).

This class is named `ip_diffim_DipoleFit` so that it may be used alongside
the existing `ip_diffim_DipoleMeasurement` classes until such a time as those
are deemed to be replaceable by this.

Definition at line 941 of file dipoleFitTask.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.__init__ (   self,
  config,
  name,
  schema,
  metadata 
)

Definition at line 976 of file dipoleFitTask.py.

976  def __init__(self, config, name, schema, metadata):
977  measBase.SingleFramePlugin.__init__(self, config, name, schema, metadata)
978 
979  self.log = Log.getLogger(name)
980 
981  self._setupSchema(config, name, schema, metadata)
982 

Member Function Documentation

◆ doClassify()

def lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.doClassify (   self,
  measRecord,
  chi2val 
)
Classify a source as a dipole.

Parameters
----------
measRecord : TODO: DM-17458
    TODO: DM-17458
chi2val : TODO: DM-17458
    TODO: DM-17458

Notes
-----
Sources are classified as dipoles, or not, according to three criteria:

1. Does the total signal-to-noise surpass the ``minSn``?
2. Are the pos/neg fluxes greater than 1.0 and no more than 0.65 (``maxFluxRatio``)
   of the total flux? By default this will never happen since ``posFlux == negFlux``.
3. Is it a good fit (``chi2dof`` < 1)? (Currently not used.)

Definition at line 1146 of file dipoleFitTask.py.

1146  def doClassify(self, measRecord, chi2val):
1147  """Classify a source as a dipole.
1148 
1149  Parameters
1150  ----------
1151  measRecord : TODO: DM-17458
1152  TODO: DM-17458
1153  chi2val : TODO: DM-17458
1154  TODO: DM-17458
1155 
1156  Notes
1157  -----
1158  Sources are classified as dipoles, or not, according to three criteria:
1159 
1160  1. Does the total signal-to-noise surpass the ``minSn``?
1161  2. Are the pos/neg fluxes greater than 1.0 and no more than 0.65 (``maxFluxRatio``)
1162  of the total flux? By default this will never happen since ``posFlux == negFlux``.
1163  3. Is it a good fit (``chi2dof`` < 1)? (Currently not used.)
1164  """
1165 
1166  # First, does the total signal-to-noise surpass the minSn?
1167  passesSn = measRecord[self.signalToNoiseKey] > self.config.minSn
1168 
1169  # Second, are the pos/neg fluxes greater than 1.0 and no more than 0.65 (param maxFluxRatio)
1170  # of the total flux? By default this will never happen since posFlux = negFlux.
1171  passesFluxPos = (abs(measRecord[self.posFluxKey])
1172  / (measRecord[self.fluxKey]*2.)) < self.config.maxFluxRatio
1173  passesFluxPos &= (abs(measRecord[self.posFluxKey]) >= 1.0)
1174  passesFluxNeg = (abs(measRecord[self.negFluxKey])
1175  / (measRecord[self.fluxKey]*2.)) < self.config.maxFluxRatio
1176  passesFluxNeg &= (abs(measRecord[self.negFluxKey]) >= 1.0)
1177  allPass = (passesSn and passesFluxPos and passesFluxNeg) # and passesChi2)
1178 
1179  # Third, is it a good fit (chi2dof < 1)?
1180  # Use scipy's chi2 cumulative distrib to estimate significance
1181  # This doesn't really work since I don't trust the values in the variance plane (which
1182  # affects the least-sq weights, which affects the resulting chi2).
1183  # But I'm going to keep this here for future use.
1184  if False:
1185  from scipy.stats import chi2
1186  ndof = chi2val / measRecord[self.chi2dofKey]
1187  significance = chi2.cdf(chi2val, ndof)
1188  passesChi2 = significance < self.config.maxChi2DoF
1189  allPass = allPass and passesChi2
1190 
1191  measRecord.set(self.classificationAttemptedFlagKey, True)
1192 
1193  if allPass: # Note cannot pass `allPass` into the `measRecord.set()` call below...?
1194  measRecord.set(self.classificationFlagKey, True)
1195  else:
1196  measRecord.set(self.classificationFlagKey, False)
1197 
Angle abs(Angle const &a)
Definition: Angle.h:106

◆ fail()

def lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.fail (   self,
  measRecord,
  error = None 
)
Catch failures and set the correct flags.

Definition at line 1198 of file dipoleFitTask.py.

1198  def fail(self, measRecord, error=None):
1199  """Catch failures and set the correct flags.
1200  """
1201 
1202  measRecord.set(self.flagKey, True)
1203  if error is not None:
1204  if error.getFlagBit() == self.FAILURE_EDGE:
1205  self.log.warning('DipoleFitPlugin not run on record %d: %s', measRecord.getId(), str(error))
1206  measRecord.set(self.edgeFlagKey, True)
1207  if error.getFlagBit() == self.FAILURE_FIT:
1208  self.log.warning('DipoleFitPlugin failed on record %d: %s', measRecord.getId(), str(error))
1209  measRecord.set(self.flagKey, True)
1210  if error.getFlagBit() == self.FAILURE_NOT_DIPOLE:
1211  self.log.debug('DipoleFitPlugin not run on record %d: %s',
1212  measRecord.getId(), str(error))
1213  measRecord.set(self.classificationAttemptedFlagKey, False)
1214  measRecord.set(self.flagKey, True)
1215  else:
1216  self.log.warning('DipoleFitPlugin failed on record %d', measRecord.getId())

◆ getExecutionOrder()

def lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.getExecutionOrder (   cls)
Set execution order to `FLUX_ORDER`.

This includes algorithms that require both `getShape()` and `getCentroid()`,
in addition to a Footprint and its Peaks.

Definition at line 968 of file dipoleFitTask.py.

968  def getExecutionOrder(cls):
969  """Set execution order to `FLUX_ORDER`.
970 
971  This includes algorithms that require both `getShape()` and `getCentroid()`,
972  in addition to a Footprint and its Peaks.
973  """
974  return cls.FLUX_ORDER
975 

◆ measure()

def lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.measure (   self,
  measRecord,
  exposure,
  posExp = None,
  negExp = None 
)
Perform the non-linear least squares minimization on the putative dipole source.

Parameters
----------
measRecord : `lsst.afw.table.SourceRecord`
    diaSources that will be measured using dipole measurement
exposure : `lsst.afw.image.Exposure`
    Difference exposure on which the diaSources were detected; `exposure = posExp-negExp`
    If both `posExp` and `negExp` are `None`, will attempt to fit the
    dipole to just the `exposure` with no constraint.
posExp : `lsst.afw.image.Exposure`, optional
    "Positive" exposure, typically a science exposure, or None if unavailable
    When `posExp` is `None`, will compute `posImage = exposure + negExp`.
negExp : `lsst.afw.image.Exposure`, optional
    "Negative" exposure, typically a template exposure, or None if unavailable
    When `negExp` is `None`, will compute `negImage = posExp - exposure`.

Notes
-----
The main functionality of this routine was placed outside of
this plugin (into `DipoleFitAlgorithm.fitDipole()`) so that
`DipoleFitAlgorithm.fitDipole()` can be called separately for
testing (@see `tests/testDipoleFitter.py`)

Returns
-------
result : TODO: DM-17458
    TODO: DM-17458

Definition at line 1051 of file dipoleFitTask.py.

1051  def measure(self, measRecord, exposure, posExp=None, negExp=None):
1052  """Perform the non-linear least squares minimization on the putative dipole source.
1053 
1054  Parameters
1055  ----------
1056  measRecord : `lsst.afw.table.SourceRecord`
1057  diaSources that will be measured using dipole measurement
1058  exposure : `lsst.afw.image.Exposure`
1059  Difference exposure on which the diaSources were detected; `exposure = posExp-negExp`
1060  If both `posExp` and `negExp` are `None`, will attempt to fit the
1061  dipole to just the `exposure` with no constraint.
1062  posExp : `lsst.afw.image.Exposure`, optional
1063  "Positive" exposure, typically a science exposure, or None if unavailable
1064  When `posExp` is `None`, will compute `posImage = exposure + negExp`.
1065  negExp : `lsst.afw.image.Exposure`, optional
1066  "Negative" exposure, typically a template exposure, or None if unavailable
1067  When `negExp` is `None`, will compute `negImage = posExp - exposure`.
1068 
1069  Notes
1070  -----
1071  The main functionality of this routine was placed outside of
1072  this plugin (into `DipoleFitAlgorithm.fitDipole()`) so that
1073  `DipoleFitAlgorithm.fitDipole()` can be called separately for
1074  testing (@see `tests/testDipoleFitter.py`)
1075 
1076  Returns
1077  -------
1078  result : TODO: DM-17458
1079  TODO: DM-17458
1080  """
1081 
1082  result = None
1083  pks = measRecord.getFootprint().getPeaks()
1084 
1085  # Check if the footprint consists of a putative dipole - else don't fit it.
1086  if (
1087  (len(pks) <= 1) # one peak in the footprint - not a dipole
1088  or (len(pks) > 1 and (np.sign(pks[0].getPeakValue())
1089  == np.sign(pks[-1].getPeakValue()))) # peaks are same sign - not a dipole
1090  ):
1091  measRecord.set(self.classificationFlagKey, False)
1092  measRecord.set(self.classificationAttemptedFlagKey, False)
1093  self.fail(measRecord, measBase.MeasurementError('not a dipole', self.FAILURE_NOT_DIPOLE))
1094  if not self.config.fitAllDiaSources:
1095  return result
1096 
1097  try:
1098  alg = self.DipoleFitAlgorithmClass(exposure, posImage=posExp, negImage=negExp)
1099  result, _ = alg.fitDipole(
1100  measRecord, rel_weight=self.config.relWeight,
1101  tol=self.config.tolerance,
1102  maxSepInSigma=self.config.maxSeparation,
1103  fitBackground=self.config.fitBackground,
1104  separateNegParams=self.config.fitSeparateNegParams,
1105  verbose=False, display=False)
1106  except pexExcept.LengthError:
1107  self.fail(measRecord, measBase.MeasurementError('edge failure', self.FAILURE_EDGE))
1108  except Exception:
1109  self.fail(measRecord, measBase.MeasurementError('dipole fit failure', self.FAILURE_FIT))
1110 
1111  if result is None:
1112  measRecord.set(self.classificationFlagKey, False)
1113  measRecord.set(self.classificationAttemptedFlagKey, False)
1114  return result
1115 
1116  self.log.debug("Dipole fit result: %d %s", measRecord.getId(), str(result))
1117 
1118  if result.posFlux <= 1.: # usually around 0.1 -- the minimum flux allowed -- i.e. bad fit.
1119  self.fail(measRecord, measBase.MeasurementError('dipole fit failure', self.FAILURE_FIT))
1120 
1121  # add chi2, coord/flux uncertainties (TBD), dipole classification
1122  # Add the relevant values to the measRecord
1123  measRecord[self.posFluxKey] = result.posFlux
1124  measRecord[self.posFluxErrKey] = result.signalToNoise # to be changed to actual sigma!
1125  measRecord[self.posCentroidKeyX] = result.posCentroidX
1126  measRecord[self.posCentroidKeyY] = result.posCentroidY
1127 
1128  measRecord[self.negFluxKey] = result.negFlux
1129  measRecord[self.negFluxErrKey] = result.signalToNoise # to be changed to actual sigma!
1130  measRecord[self.negCentroidKeyX] = result.negCentroidX
1131  measRecord[self.negCentroidKeyY] = result.negCentroidY
1132 
1133  # Dia source flux: average of pos+neg
1134  measRecord[self.fluxKey] = (abs(result.posFlux) + abs(result.negFlux))/2.
1135  measRecord[self.orientationKey] = result.orientation
1136  measRecord[self.separationKey] = np.sqrt((result.posCentroidX - result.negCentroidX)**2.
1137  + (result.posCentroidY - result.negCentroidY)**2.)
1138  measRecord[self.centroidKeyX] = result.centroidX
1139  measRecord[self.centroidKeyY] = result.centroidY
1140 
1141  measRecord[self.signalToNoiseKey] = result.signalToNoise
1142  measRecord[self.chi2dofKey] = result.redChi2
1143 
1144  self.doClassify(measRecord, result.chi2)
1145 
Reports attempts to exceed implementation-defined length limits for some classes.
Definition: Runtime.h:76
def measure(mi, x, y, size, statistic, stats)
Definition: fringe.py:517

Member Data Documentation

◆ centroidKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.centroidKey

Definition at line 985 of file dipoleFitTask.py.

◆ chi2dofKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.chi2dofKey

Definition at line 1027 of file dipoleFitTask.py.

◆ classificationAttemptedFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.classificationAttemptedFlagKey

Definition at line 1039 of file dipoleFitTask.py.

◆ classificationFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.classificationFlagKey

Definition at line 1035 of file dipoleFitTask.py.

◆ ConfigClass

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.ConfigClass = DipoleFitPluginConfig
static

Definition at line 960 of file dipoleFitTask.py.

◆ DipoleFitAlgorithmClass

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.DipoleFitAlgorithmClass = DipoleFitAlgorithm
static

Definition at line 961 of file dipoleFitTask.py.

◆ edgeFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.edgeFlagKey

Definition at line 1047 of file dipoleFitTask.py.

◆ FAILURE_EDGE

int lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.FAILURE_EDGE = 1
static

Definition at line 963 of file dipoleFitTask.py.

◆ FAILURE_FIT

int lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.FAILURE_FIT = 2
static

Definition at line 964 of file dipoleFitTask.py.

◆ FAILURE_NOT_DIPOLE

int lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.FAILURE_NOT_DIPOLE = 4
static

Definition at line 965 of file dipoleFitTask.py.

◆ flagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.flagKey

Definition at line 1043 of file dipoleFitTask.py.

◆ fluxKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.fluxKey

Definition at line 1015 of file dipoleFitTask.py.

◆ log

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.log

Definition at line 979 of file dipoleFitTask.py.

◆ orientationKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.orientationKey

Definition at line 1019 of file dipoleFitTask.py.

◆ separationKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.separationKey

Definition at line 1023 of file dipoleFitTask.py.

◆ signalToNoiseKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.signalToNoiseKey

Definition at line 1031 of file dipoleFitTask.py.


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