Skip to content

Commit 62d7244

Browse files
committed
Add Ex metric for TEx computation in visit and ccd table.
1 parent 282ba76 commit 62d7244

File tree

3 files changed

+131
-5
lines changed

3 files changed

+131
-5
lines changed

python/lsst/pipe/tasks/computeExposureSummaryStats.py

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import lsst.afw.image as afwImage
3636
import lsst.geom as geom
3737
from lsst.meas.algorithms import ScienceSourceSelectorTask
38+
from lsst.meas.algorithms.computeExPsf import ComputeExPsfTask, ComputeExPsfConfig
3839
from lsst.utils.timer import timeMethod
3940
import lsst.ip.isr as ipIsr
4041

@@ -137,6 +138,22 @@ class ComputeExposureSummaryStatsConfig(pexConfig.Config):
137138
doc="Signal-to-noise ratio for computing the magnitude limit depth.",
138139
default=5.0
139140
)
141+
psfTE1TreecorrConfig = pexConfig.ConfigField(
142+
dtype=ComputeExPsfConfig,
143+
doc="Treecorr config for computing scalar value of TE1.",
144+
)
145+
psfTE2TreecorrConfig = pexConfig.ConfigField(
146+
dtype=ComputeExPsfConfig,
147+
doc="Treecorr config for computing scalar value of TE1.",
148+
)
149+
psfTE3TreecorrConfig = pexConfig.ConfigField(
150+
dtype=ComputeExPsfConfig,
151+
doc="Treecorr config for computing scalar value of TE1.",
152+
)
153+
psfTE4TreecorrConfig = pexConfig.ConfigField(
154+
dtype=ComputeExPsfConfig,
155+
doc="Treecorr config for computing scalar value of TE1.",
156+
)
140157

141158
def setDefaults(self):
142159
super().setDefaults()
@@ -159,6 +176,22 @@ def setDefaults(self):
159176
self.starSelector.signalToNoise.fluxField = "slot_PsfFlux_instFlux"
160177
self.starSelector.signalToNoise.errField = "slot_PsfFlux_instFluxErr"
161178

179+
min_theta = [1e-6, 5.0, 1e-6, 5.0]
180+
max_theta = [1.0, 100.0, 5.0, 20.0]
181+
TExTreecorrConfig = [
182+
self.psfTE1TreecorrConfig,
183+
self.psfTE2TreecorrConfig,
184+
self.psfTE3TreecorrConfig,
185+
self.psfTE4TreecorrConfig,
186+
]
187+
188+
for texc, mint, maxt in zip(TExTreecorrConfig, min_theta, max_theta):
189+
texc.treecorr.min_sep = mint / 60.0
190+
texc.treecorr.max_sep = maxt / 60.0
191+
texc.treecorr.nbins = 1
192+
texc.treecorr.bin_type = "Linear"
193+
texc.treecorr.sep_units = "degree"
194+
162195

163196
class ComputeExposureSummaryStatsTask(pipeBase.Task):
164197
"""Task to compute exposure summary statistics.
@@ -199,6 +232,18 @@ class ComputeExposureSummaryStatsTask(pipeBase.Task):
199232
- maxDistToNearestPsf
200233
- psfTraceRadiusDelta
201234
- psfApFluxDelta
235+
- psfTE1E1
236+
- psfTE1E2
237+
- psfTE1Ex
238+
- psfTE2E1
239+
- psfTE2E2
240+
- psfTE2Ex
241+
- psfTE3E1
242+
- psfTE3E2
243+
- psfTE3Ex
244+
- psfTE4E1
245+
- psfTE4E2
246+
- psfTE4Ex
202247
203248
This quantity is computed based on the aperture correction map, the
204249
psfSigma, and the image mask to assess the robustness of the aperture
@@ -325,6 +370,18 @@ def update_psf_stats(
325370
summary.psfTraceRadiusDelta = nan
326371
summary.psfApFluxDelta = nan
327372
summary.psfApCorrSigmaScaledDelta = nan
373+
summary.psfTE1E1 = nan
374+
summary.psfTE1E2 = nan
375+
summary.psfTE1Ex = nan
376+
summary.psfTE2E1 = nan
377+
summary.psfTE2E2 = nan
378+
summary.psfTE2Ex = nan
379+
summary.psfTE3E1 = nan
380+
summary.psfTE3E2 = nan
381+
summary.psfTE3Ex = nan
382+
summary.psfTE4E1 = nan
383+
summary.psfTE4E2 = nan
384+
summary.psfTE4Ex = nan
328385

329386
if psf is None:
330387
return
@@ -410,10 +467,13 @@ def update_psf_stats(
410467
psfE1 = (psfXX - psfYY)/(psfXX + psfYY)
411468
psfE2 = 2*psfXY/(psfXX + psfYY)
412469

413-
psfStarDeltaE1Median = np.median(starE1 - psfE1)
414-
psfStarDeltaE1Scatter = sigmaMad(starE1 - psfE1, scale='normal')
415-
psfStarDeltaE2Median = np.median(starE2 - psfE2)
416-
psfStarDeltaE2Scatter = sigmaMad(starE2 - psfE2, scale='normal')
470+
e1Residuals = starE1 - psfE1
471+
e2Residuals = starE2 - psfE2
472+
473+
psfStarDeltaE1Median = np.median(e1Residuals)
474+
psfStarDeltaE1Scatter = sigmaMad(e1Residuals, scale='normal')
475+
psfStarDeltaE2Median = np.median(e2Residuals)
476+
psfStarDeltaE2Scatter = sigmaMad(e2Residuals, scale='normal')
417477

418478
psfStarDeltaSizeMedian = np.median(starSize - psfSize)
419479
psfStarDeltaSizeScatter = sigmaMad(starSize - psfSize, scale='normal')
@@ -427,6 +487,46 @@ def update_psf_stats(
427487
summary.psfStarDeltaSizeScatter = float(psfStarDeltaSizeScatter)
428488
summary.psfStarScaledDeltaSizeScatter = float(psfStarScaledDeltaSizeScatter)
429489

490+
ra = psf_cat["coord_ra"]
491+
dec = psf_cat["coord_dec"]
492+
493+
# Comp TEx
494+
495+
TExTreecorrConfig = [
496+
self.config.psfTE1TreecorrConfig,
497+
self.config.psfTE2TreecorrConfig,
498+
self.config.psfTE3TreecorrConfig,
499+
self.config.psfTE4TreecorrConfig,
500+
]
501+
502+
TExOutput = [
503+
[summary.psfTE1E1, summary.psfTE1E2, summary.psfTE1Ex],
504+
[summary.psfTE2E1, summary.psfTE2E2, summary.psfTE2Ex],
505+
[summary.psfTE3E1, summary.psfTE3E2, summary.psfTE3Ex],
506+
[summary.psfTE4E1, summary.psfTE4E2, summary.psfTE4Ex],
507+
]
508+
509+
isNotNan = np.array([True] * len(ra))
510+
isNotNan &= np.isfinite(ra)
511+
isNotNan &= np.isfinite(dec)
512+
isNotNan &= np.isfinite(e1Residuals)
513+
isNotNan &= np.isfinite(e2Residuals)
514+
515+
if np.sum(isNotNan) > 1:
516+
517+
for config, texoutput in zip(TExTreecorrConfig, TExOutput):
518+
519+
task = ComputeExPsfTask(config)
520+
output = task.run(
521+
e1Residuals[isNotNan], e2Residuals[isNotNan],
522+
ra[isNotNan], dec[isNotNan],
523+
units="degree",
524+
)
525+
526+
texoutput[0] = output.metric_E1
527+
texoutput[1] = output.metric_E2
528+
texoutput[2] = output.metric_Ex
529+
430530
if image_mask is not None:
431531
maxDistToNearestPsf = maximum_nearest_psf_distance(
432532
image_mask,

python/lsst/pipe/tasks/postprocess.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,10 @@ def run(self, visitSummaryRefs):
12301230
"maxDistToNearestPsf",
12311231
"effTime", "effTimePsfSigmaScale",
12321232
"effTimeSkyBgScale", "effTimeZeroPointScale",
1233-
"magLim"]
1233+
"magLim", "psfTE1E1", "psfTE1E2", "psfTE1Ex",
1234+
"psfTE2E1", "psfTE2E2", "psfTE2Ex",
1235+
"psfTE3E1", "psfTE3E2", "psfTE3Ex",
1236+
"psfTE4E1", "psfTE4E2", "psfTE4Ex"]
12341237
ccdEntry = summaryTable[selectColumns].to_pandas().set_index("id")
12351238
# 'visit' is the human readable visit number.
12361239
# 'visitId' is the key to the visitId table. They are the same.
@@ -1364,6 +1367,13 @@ def run(self, visitSummaries):
13641367
visitEntry["obsStart"] = visitEntry["expMidpt"] - 0.5 * pd.Timedelta(seconds=expTime)
13651368
expTime_days = expTime / (60*60*24)
13661369
visitEntry["obsStartMJD"] = visitEntry["expMidptMJD"] - 0.5 * expTime_days
1370+
# TEx = [
1371+
# "psfTE1E1", "psfTE1E2", "psfTE1Ex",
1372+
# "psfTE2E1", "psfTE2E2", "psfTE2Ex",
1373+
# "psfTE3E1", "psfTE3E2", "psfTE3Ex",
1374+
# ]
1375+
# for tex in TEx:
1376+
# visitEntry[tex] = visitRow[tex]
13671377
visitEntries.append(visitEntry)
13681378

13691379
# TODO: DM-30623, Add programId, exposureType, cameraTemp,

tests/test_computeExposureSummaryStats.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,22 @@ def testComputeExposureSummary(self):
162162
self.assertFloatsAlmostEqual(summary.effTime, expTime, rtol=1e-3)
163163
self.assertFloatsAlmostEqual(summary.magLim, 26.584, rtol=1e-3)
164164

165+
# Check TExEx does exist, would need a more complex unit
166+
# test with ~O(100) stars to check.
167+
nan = float('nan')
168+
self.assertFloatsAlmostEqual(summary.psfTE1E1, nan, ignoreNaNs=True)
169+
self.assertFloatsAlmostEqual(summary.psfTE1E2, nan, ignoreNaNs=True)
170+
self.assertFloatsAlmostEqual(summary.psfTE1Ex, nan, ignoreNaNs=True)
171+
self.assertFloatsAlmostEqual(summary.psfTE2E1, nan, ignoreNaNs=True)
172+
self.assertFloatsAlmostEqual(summary.psfTE2E2, nan, ignoreNaNs=True)
173+
self.assertFloatsAlmostEqual(summary.psfTE2Ex, nan, ignoreNaNs=True)
174+
self.assertFloatsAlmostEqual(summary.psfTE3E1, nan, ignoreNaNs=True)
175+
self.assertFloatsAlmostEqual(summary.psfTE3E2, nan, ignoreNaNs=True)
176+
self.assertFloatsAlmostEqual(summary.psfTE3Ex, nan, ignoreNaNs=True)
177+
self.assertFloatsAlmostEqual(summary.psfTE4E1, nan, ignoreNaNs=True)
178+
self.assertFloatsAlmostEqual(summary.psfTE4E2, nan, ignoreNaNs=True)
179+
self.assertFloatsAlmostEqual(summary.psfTE4Ex, nan, ignoreNaNs=True)
180+
165181
def testComputeMagnitudeLimit(self):
166182
"""Test the magnitude limit calculation using fiducials from SMTN-002
167183
and syseng_throughputs."""

0 commit comments

Comments
 (0)