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`)
104 nSolarSystemObjects = len(solarSystemObjects)
105 if nSolarSystemObjects <= 0:
106 return self.
_return_empty(diaSourceCatalog, solarSystemObjects)
108 mjd_midpoint = visitInfo.date.toAstropy().tai.mjd
109 ref_time = mjd_midpoint - solarSystemObjects[
"tmin"].value[0]
111 solarSystemObjects[
'obs_position'] = [
112 np.array([chebval(ref_time, row[
'obs_x_poly']),
113 chebval(ref_time, row[
'obs_y_poly']),
114 chebval(ref_time, row[
'obs_z_poly'])])
115 for row
in solarSystemObjects]
116 solarSystemObjects[
'obs_velocity'] = [
117 np.array([chebval(ref_time, Chebyshev(row[
'obs_x_poly']).deriv().coef),
118 chebval(ref_time, Chebyshev(row[
'obs_y_poly']).deriv().coef),
119 chebval(ref_time, Chebyshev(row[
'obs_z_poly']).deriv().coef)])
120 for row
in solarSystemObjects]
121 solarSystemObjects[
'obj_position'] = [
122 np.array([chebval(ref_time, row[
'obj_x_poly']),
123 chebval(ref_time, row[
'obj_y_poly']),
124 chebval(ref_time, row[
'obj_z_poly'])])
125 for row
in solarSystemObjects]
126 solarSystemObjects[
'obj_velocity'] = [
127 np.array([chebval(ref_time, Chebyshev(row[
'obj_x_poly']).deriv().coef),
128 chebval(ref_time, Chebyshev(row[
'obj_y_poly']).deriv().coef),
129 chebval(ref_time, Chebyshev(row[
'obj_z_poly']).deriv().coef)])
130 for row
in solarSystemObjects]
131 vector = np.vstack(solarSystemObjects[
'obj_position'].value
132 - solarSystemObjects[
'obs_position'].value)
133 ras, decs = np.vstack(hp.vec2ang(vector, lonlat=
True))
134 solarSystemObjects[
'ra'] = ras
135 solarSystemObjects[
'dec'] = decs
136 solarSystemObjects[
'obs_position_x'], solarSystemObjects[
'obs_position_y'], \
137 solarSystemObjects[
'obs_position_z'] = solarSystemObjects[
'obs_position'].value.T
138 solarSystemObjects[
'heliocentricX'], solarSystemObjects[
'heliocentricY'], \
139 solarSystemObjects[
'heliocentricZ'] = solarSystemObjects[
'obj_position'].value.T
140 solarSystemObjects[
'obs_velocity_x'], solarSystemObjects[
'obs_velocity_y'], \
141 solarSystemObjects[
'obs_velocity_z'] = solarSystemObjects[
'obs_velocity'].value.T
142 solarSystemObjects[
'heliocentricVX'], solarSystemObjects[
'heliocentricVY'], \
143 solarSystemObjects[
'heliocentricVZ'] = solarSystemObjects[
'obj_velocity'].value.T
144 solarSystemObjects[
'topocentric_position'], solarSystemObjects[
'topocentric_velocity'] = (
145 solarSystemObjects[
'obj_position'] - solarSystemObjects[
'obs_position'],
146 solarSystemObjects[
'obj_velocity'] - solarSystemObjects[
'obs_velocity'],
148 solarSystemObjects[
'topocentricX'], solarSystemObjects[
'topocentricY'], \
149 solarSystemObjects[
'topocentricZ'] = (
150 np.array(list(solarSystemObjects[
'topocentric_position'].value)).T
152 solarSystemObjects[
'topocentricVX'], solarSystemObjects[
'topocentricVY'], \
153 solarSystemObjects[
'topocentricVZ'] = (
154 np.array(list(solarSystemObjects[
'topocentric_velocity'].value)).T
156 solarSystemObjects[
'heliocentricVX'], solarSystemObjects[
'heliocentricVY'], \
157 solarSystemObjects[
'heliocentricVZ'] = np.array(list(solarSystemObjects[
'obj_velocity'].value)).T
158 solarSystemObjects[
'heliocentricDist'] = np.linalg.norm(solarSystemObjects[
'obj_position'], axis=1)
159 solarSystemObjects[
'topocentricDist'] = np.linalg.norm(solarSystemObjects[
'topocentric_position'],
161 solarSystemObjects[
'phaseAngle'] = np.degrees(np.arccos(np.sum(
162 solarSystemObjects[
'obj_position'].T * solarSystemObjects[
'topocentric_position'].T
163 / solarSystemObjects[
'heliocentricDist'] / solarSystemObjects[
'topocentricDist'], axis=0
166 stateVectorColumns = [
'heliocentricX',
'heliocentricY',
'heliocentricZ',
'heliocentricVX',
167 'heliocentricVY',
'heliocentricVZ',
'topocentricX',
'topocentricY',
168 'topocentricZ',
'topocentricVX',
'topocentricVY',
'topocentricVZ']
170 mpcorbColumns = [col
for col
in solarSystemObjects.columns
if col[:7] ==
'MPCORB_']
176 solarSystemObjects[
"Err(arcsec)"].max()).copy()
177 nSolarSystemObjects = len(maskedObjects)
178 if nSolarSystemObjects <= 0:
181 maxRadius = np.deg2rad(self.config.maxDistArcSeconds / 3600)
185 diaSourceCatalog[
"dec"])
188 tree = cKDTree(vectors)
194 ssSourceData, ssObjectIds = [], []
195 ras, decs, residual_ras, residual_decs, dia_ids = [], [], [], [], []
196 diaSourceCatalog[
"ssObjectId"] = 0
198 maskedObjects[
'associated'] =
False
199 if 'diaSourceId' in diaSourceCatalog.columns:
200 source_column =
'diaSourceId'
201 for ssObject
in maskedObjects:
202 index = ssObject.index
203 ssoVect = self.
_radec_to_xyz(ssObject[
"ra"], ssObject[
"dec"])
205 dist, idx = tree.query(ssoVect, distance_upper_bound=maxRadius)
206 if len(idx) == 1
and np.isfinite(dist[0]):
208 diaSourceCatalog[idx[0]][
"ssObjectId"] = ssObject[
"ssObjectId"]
209 ssObjectIds.append(ssObject[
"ssObjectId"])
210 all_cols = [
"phaseAngle",
"heliocentricDist",
211 "topocentricDist"] + stateVectorColumns + mpcorbColumns
212 ssSourceData.append(list(ssObject[all_cols].values()))
213 dia_ra = diaSourceCatalog[idx[0]][
"ra"]
214 dia_dec = diaSourceCatalog[idx[0]][
"dec"]
215 dia_id = diaSourceCatalog[idx[0]][source_column]
218 dia_ids.append(dia_id)
219 residual_ras.append(dia_ra - ssObject[
"ra"])
220 residual_decs.append(dia_dec - ssObject[
"dec"])
221 maskedObjects[
'associated'][index] =
True
223 maskedObjects[
'associated'][index] =
False
225 self.log.info(
"Successfully associated %d / %d SolarSystemObjects.", nFound, nSolarSystemObjects)
226 self.metadata[
'nAssociatedSsObjects'] = nFound
227 self.metadata[
'nExpectedSsObjects'] = nSolarSystemObjects
228 assocSourceMask = diaSourceCatalog[
"ssObjectId"] != 0
229 unAssocObjectMask = np.logical_not(maskedObjects[
'associated'].value)
230 ssSourceData = np.array(ssSourceData)
231 ssSourceData = Table(ssSourceData,
233 "phaseAngle",
"heliocentricDist",
"topocentricDist"
234 ] + stateVectorColumns + mpcorbColumns)
235 ssSourceData[
'ssObjectId'] = Column(data=ssObjectIds, dtype=int)
236 ssSourceData[
"ra"] = ras
237 ssSourceData[
"dec"] = decs
238 ssSourceData[
"residualRa"] = residual_ras
239 ssSourceData[
"residualDec"] = residual_decs
240 ssSourceData[source_column] = dia_ids
241 coords = SkyCoord(ra=ssSourceData[
'ra'].value * u.deg, dec=ssSourceData[
'dec'].value * u.deg)
242 ssSourceData[
'galacticL'] = coords.galactic.l.deg
243 ssSourceData[
'galacticB'] = coords.galactic.b.deg
244 ssSourceData[
'eclipticLambda'] = coords.barycentrictrueecliptic.lon.deg
245 ssSourceData[
'eclipticBeta'] = coords.barycentrictrueecliptic.lat.deg
246 unassociatedObjects = maskedObjects[unAssocObjectMask]
248 "obs_position",
"obs_velocity",
"obj_position",
"obj_velocity",
"topocentric_position",
249 "topocentric_velocity",
"obs_x_poly",
"obs_y_poly",
"obs_z_poly",
"obj_x_poly",
"obj_y_poly",
250 "obj_z_poly",
"associated"
252 unassociatedObjects.remove_columns(columns_to_drop)
253 return pipeBase.Struct(
254 ssoAssocDiaSources=diaSourceCatalog[assocSourceMask],
255 unAssocDiaSources=diaSourceCatalog[~assocSourceMask],
256 nTotalSsObjects=nSolarSystemObjects,
257 nAssociatedSsObjects=nFound,
258 associatedSsSources=ssSourceData,
259 unassociatedSsObjects=unassociatedObjects)