LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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 940 of file dipoleFitTask.py.

Constructor & Destructor Documentation

◆ __init__()

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

Definition at line 975 of file dipoleFitTask.py.

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

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 1145 of file dipoleFitTask.py.

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

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

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

◆ 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 1050 of file dipoleFitTask.py.

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

Member Data Documentation

◆ centroidKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.centroidKey

Definition at line 984 of file dipoleFitTask.py.

◆ chi2dofKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.chi2dofKey

Definition at line 1026 of file dipoleFitTask.py.

◆ classificationAttemptedFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.classificationAttemptedFlagKey

Definition at line 1038 of file dipoleFitTask.py.

◆ classificationFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.classificationFlagKey

Definition at line 1034 of file dipoleFitTask.py.

◆ ConfigClass

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

Definition at line 959 of file dipoleFitTask.py.

◆ DipoleFitAlgorithmClass

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

Definition at line 960 of file dipoleFitTask.py.

◆ edgeFlagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.edgeFlagKey

Definition at line 1046 of file dipoleFitTask.py.

◆ FAILURE_EDGE

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

Definition at line 962 of file dipoleFitTask.py.

◆ FAILURE_FIT

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

Definition at line 963 of file dipoleFitTask.py.

◆ FAILURE_NOT_DIPOLE

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

Definition at line 964 of file dipoleFitTask.py.

◆ flagKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.flagKey

Definition at line 1042 of file dipoleFitTask.py.

◆ fluxKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.fluxKey

Definition at line 1014 of file dipoleFitTask.py.

◆ log

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.log

Definition at line 978 of file dipoleFitTask.py.

◆ orientationKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.orientationKey

Definition at line 1018 of file dipoleFitTask.py.

◆ separationKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.separationKey

Definition at line 1022 of file dipoleFitTask.py.

◆ signalToNoiseKey

lsst.ip.diffim.dipoleFitTask.DipoleFitPlugin.signalToNoiseKey

Definition at line 1030 of file dipoleFitTask.py.


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