70 def run(self, diaSourceCatalog, solarSystemObjects, visitInfo, bbox, wcs):
71 """Create a searchable tree of unassociated DiaSources and match
72 to the nearest ssoObject.
76 diaSourceCatalog : `astropy.table.Table`
77 Catalog of DiaSources. Modified in place to add ssObjectId to
78 successfully associated DiaSources.
79 solarSystemObjects : `astropy.table.Table`
80 Set of solar system objects that should be within the footprint
82 visitInfo : `lsst.afw.image.VisitInfo`
83 visitInfo of exposure used for exposure time
84 bbox : `lsst.geom.Box2I`
85 bbox of exposure used for masking
86 wcs : `lsst.afw.geom.SkyWcs`
87 wcs of exposure used for masking
91 resultsStruct : `lsst.pipe.base.Struct`
93 - ``ssoAssocDiaSources`` : DiaSources that were associated with
94 solar system objects in this visit. (`astropy.table.Table`)
95 - ``unAssocDiaSources`` : Set of DiaSources that were not
96 associated with any solar system object. (`astropy.table.Table`)
97 - ``nTotalSsObjects`` : Total number of SolarSystemObjects
98 contained in the CCD footprint. (`int`)
99 - ``nAssociatedSsObjects`` : Number of SolarSystemObjects
100 that were associated with DiaSources. (`int`)
101 - ``ssSourceData`` : ssSource table data. (`Astropy.table.Table`)
103 nSolarSystemObjects = len(solarSystemObjects)
104 if nSolarSystemObjects <= 0:
105 return self.
_return_empty(diaSourceCatalog, solarSystemObjects)
107 mjd_midpoint = visitInfo.date.toAstropy().tai.mjd
108 ref_time = mjd_midpoint - solarSystemObjects[
"tmin"].value[0]
110 solarSystemObjects[
'obs_position'] = [
111 np.array([chebval(ref_time, row[
'obs_x_poly']),
112 chebval(ref_time, row[
'obs_y_poly']),
113 chebval(ref_time, row[
'obs_z_poly'])])
114 for row
in solarSystemObjects]
115 solarSystemObjects[
'obs_velocity'] = [
116 np.array([chebval(ref_time, Chebyshev(row[
'obs_x_poly']).deriv().coef),
117 chebval(ref_time, Chebyshev(row[
'obs_y_poly']).deriv().coef),
118 chebval(ref_time, Chebyshev(row[
'obs_z_poly']).deriv().coef)])
119 for row
in solarSystemObjects]
120 solarSystemObjects[
'obj_position'] = [
121 np.array([chebval(ref_time, row[
'obj_x_poly']),
122 chebval(ref_time, row[
'obj_y_poly']),
123 chebval(ref_time, row[
'obj_z_poly'])])
124 for row
in solarSystemObjects]
125 solarSystemObjects[
'obj_velocity'] = [
126 np.array([chebval(ref_time, Chebyshev(row[
'obj_x_poly']).deriv().coef),
127 chebval(ref_time, Chebyshev(row[
'obj_y_poly']).deriv().coef),
128 chebval(ref_time, Chebyshev(row[
'obj_z_poly']).deriv().coef)])
129 for row
in solarSystemObjects]
130 vector = np.vstack(solarSystemObjects[
'obj_position'].value
131 - solarSystemObjects[
'obs_position'].value)
132 ras, decs = np.vstack(hp.vec2ang(vector, lonlat=
True))
133 solarSystemObjects[
'ra'] = ras
134 solarSystemObjects[
'dec'] = decs
135 solarSystemObjects[
'obs_position_x'], solarSystemObjects[
'obs_position_y'], \
136 solarSystemObjects[
'obs_position_z'] = solarSystemObjects[
'obs_position'].value.T
137 solarSystemObjects[
'heliocentricX'], solarSystemObjects[
'heliocentricY'], \
138 solarSystemObjects[
'heliocentricZ'] = solarSystemObjects[
'obj_position'].value.T
139 solarSystemObjects[
'obs_velocity_x'], solarSystemObjects[
'obs_velocity_y'], \
140 solarSystemObjects[
'obs_velocity_z'] = solarSystemObjects[
'obs_velocity'].value.T
141 solarSystemObjects[
'heliocentricVX'], solarSystemObjects[
'heliocentricVY'], \
142 solarSystemObjects[
'heliocentricVZ'] = solarSystemObjects[
'obj_velocity'].value.T
143 solarSystemObjects[
'topocentric_position'], solarSystemObjects[
'topocentric_velocity'] = (
144 solarSystemObjects[
'obj_position'] - solarSystemObjects[
'obs_position'],
145 solarSystemObjects[
'obj_velocity'] - solarSystemObjects[
'obs_velocity'],
147 solarSystemObjects[
'topocentricX'], solarSystemObjects[
'topocentricY'], \
148 solarSystemObjects[
'topocentricZ'] = (
149 np.array(list(solarSystemObjects[
'topocentric_position'].value)).T
151 solarSystemObjects[
'topocentricVX'], solarSystemObjects[
'topocentricVY'], \
152 solarSystemObjects[
'topocentricVZ'] = (
153 np.array(list(solarSystemObjects[
'topocentric_velocity'].value)).T
155 solarSystemObjects[
'heliocentricVX'], solarSystemObjects[
'heliocentricVY'], \
156 solarSystemObjects[
'heliocentricVZ'] = np.array(list(solarSystemObjects[
'obj_velocity'].value)).T
157 solarSystemObjects[
'heliocentricDist'] = np.linalg.norm(solarSystemObjects[
'obj_position'], axis=1)
158 solarSystemObjects[
'topocentricDist'] = np.linalg.norm(solarSystemObjects[
'topocentric_position'],
160 solarSystemObjects[
'phaseAngle'] = np.degrees(np.arccos(np.sum(
161 solarSystemObjects[
'obj_position'].T * solarSystemObjects[
'topocentric_position'].T
162 / solarSystemObjects[
'heliocentricDist'] / solarSystemObjects[
'topocentricDist'], axis=0
165 stateVectorColumns = [
'heliocentricX',
'heliocentricY',
'heliocentricZ',
'heliocentricVX',
166 'heliocentricVY',
'heliocentricVZ',
'topocentricX',
'topocentricY',
167 'topocentricZ',
'topocentricVX',
'topocentricVY',
'topocentricVZ']
173 solarSystemObjects[
"Err(arcsec)"].max()).copy()
174 nSolarSystemObjects = len(maskedObjects)
175 if nSolarSystemObjects <= 0:
178 maxRadius = np.deg2rad(self.config.maxDistArcSeconds / 3600)
182 diaSourceCatalog[
"dec"])
185 tree = cKDTree(vectors)
191 ssSourceData, ssObjectIds = [], []
192 ras, decs, residual_ras, residual_decs, dia_ids = [], [], [], [], []
193 diaSourceCatalog[
"ssObjectId"] = 0
195 maskedObjects[
'associated'] =
False
196 if 'diaSourceId' in diaSourceCatalog.columns:
197 source_column =
'diaSourceId'
198 for ssObject
in maskedObjects:
199 index = ssObject.index
200 ssoVect = self.
_radec_to_xyz(ssObject[
"ra"], ssObject[
"dec"])
202 dist, idx = tree.query(ssoVect, distance_upper_bound=maxRadius)
203 if len(idx) == 1
and np.isfinite(dist[0]):
205 diaSourceCatalog[idx[0]][
"ssObjectId"] = ssObject[
"ssObjectId"]
206 ssObjectIds.append(ssObject[
"ssObjectId"])
207 ssSourceData.append(list(ssObject[[
"phaseAngle",
"heliocentricDist",
208 "topocentricDist"] + stateVectorColumns].values()))
209 dia_ra = diaSourceCatalog[idx[0]][
"ra"]
210 dia_dec = diaSourceCatalog[idx[0]][
"dec"]
211 dia_id = diaSourceCatalog[idx[0]][source_column]
214 dia_ids.append(dia_id)
215 residual_ras.append(dia_ra - ssObject[
"ra"])
216 residual_decs.append(dia_dec - ssObject[
"dec"])
217 maskedObjects[
'associated'][index] =
True
219 maskedObjects[
'associated'][index] =
False
221 self.log.info(
"Successfully associated %d / %d SolarSystemObjects.", nFound, nSolarSystemObjects)
222 self.metadata[
'nAssociatedSsObjects'] = nFound
223 self.metadata[
'nExpectedSsObjects'] = nSolarSystemObjects
224 assocSourceMask = diaSourceCatalog[
"ssObjectId"] != 0
225 unAssocObjectMask = np.logical_not(maskedObjects[
'associated'].value)
226 ssSourceData = np.array(ssSourceData)
227 ssSourceData = Table(ssSourceData,
229 "phaseAngle",
"heliocentricDist",
"topocentricDist"
230 ] + stateVectorColumns)
231 ssSourceData[
'ssObjectId'] = Column(data=ssObjectIds, dtype=int)
232 ssSourceData[
"ra"] = ras
233 ssSourceData[
"dec"] = decs
234 ssSourceData[
"residualRa"] = residual_ras
235 ssSourceData[
"residualDec"] = residual_decs
236 ssSourceData[source_column] = dia_ids
237 coords = SkyCoord(ra=ssSourceData[
'ra'].value * u.deg, dec=ssSourceData[
'dec'].value * u.deg)
238 ssSourceData[
'galacticL'] = coords.galactic.l.deg
239 ssSourceData[
'galacticB'] = coords.galactic.b.deg
240 ssSourceData[
'eclipticLambda'] = coords.barycentrictrueecliptic.lon.deg
241 ssSourceData[
'eclipticBeta'] = coords.barycentrictrueecliptic.lat.deg
242 unassociatedObjects = maskedObjects[unAssocObjectMask]
244 "obs_position",
"obs_velocity",
"obj_position",
"obj_velocity",
"topocentric_position",
245 "topocentric_velocity",
"obs_x_poly",
"obs_y_poly",
"obs_z_poly",
"obj_x_poly",
"obj_y_poly",
246 "obj_z_poly",
"associated"
248 unassociatedObjects.remove_columns(columns_to_drop)
249 return pipeBase.Struct(
250 ssoAssocDiaSources=diaSourceCatalog[assocSourceMask],
251 unAssocDiaSources=diaSourceCatalog[~assocSourceMask],
252 nTotalSsObjects=nSolarSystemObjects,
253 nAssociatedSsObjects=nFound,
254 associatedSsSources=ssSourceData,
255 unassociatedSsObjects=unassociatedObjects)