2525
2626from astropy import units as u
2727from astropy .table import Table
28+ from astropy .coordinates import SkyCoord
2829import healpy as hp
2930import numpy as np
31+ from numpy .polynomial .chebyshev import Chebyshev , chebval
3032import pandas as pd
3133from scipy .spatial import cKDTree
3234
@@ -103,24 +105,63 @@ def run(self, diaSourceCatalog, solarSystemObjects, exposure):
103105 ref_time = mjd_midpoint - solarSystemObjects ["tmin" ].values [0 ]
104106
105107 solarSystemObjects ['obs_position' ] = solarSystemObjects .apply (lambda row : np .array ([
106- np .polynomial .chebyshev .chebval (ref_time , row ['obs_x_poly' ]),
107- np .polynomial .chebyshev .chebval (ref_time , row ['obs_y_poly' ]),
108- np .polynomial .chebyshev .chebval (ref_time , row ['obs_z_poly' ])
108+ chebval (ref_time , row ['obs_x_poly' ]),
109+ chebval (ref_time , row ['obs_y_poly' ]),
110+ chebval (ref_time , row ['obs_z_poly' ])
111+ ]), axis = 1 )
112+ solarSystemObjects ['obs_velocity' ] = solarSystemObjects .apply (lambda row : np .array ([
113+ chebval (ref_time , Chebyshev (row ['obs_x_poly' ]).deriv ().coef ),
114+ chebval (ref_time , Chebyshev (row ['obs_y_poly' ]).deriv ().coef ),
115+ chebval (ref_time , Chebyshev (row ['obs_z_poly' ]).deriv ().coef ),
109116 ]), axis = 1 )
110-
111117 solarSystemObjects ['obj_position' ] = solarSystemObjects .apply (lambda row : np .array ([
112- np .polynomial .chebyshev .chebval (ref_time , row ['obj_x_poly' ]),
113- np .polynomial .chebyshev .chebval (ref_time , row ['obj_y_poly' ]),
114- np .polynomial .chebyshev .chebval (ref_time , row ['obj_z_poly' ])
118+ chebval (ref_time , row ['obj_x_poly' ]),
119+ chebval (ref_time , row ['obj_y_poly' ]),
120+ chebval (ref_time , row ['obj_z_poly' ])
121+ ]), axis = 1 )
122+ solarSystemObjects ['obj_velocity' ] = solarSystemObjects .apply (lambda row : np .array ([
123+ chebval (ref_time , Chebyshev (row ['obj_x_poly' ]).deriv ().coef ),
124+ chebval (ref_time , Chebyshev (row ['obj_y_poly' ]).deriv ().coef ),
125+ chebval (ref_time , Chebyshev (row ['obj_z_poly' ]).deriv ().coef ),
115126 ]), axis = 1 )
116-
117127 vector = np .vstack (solarSystemObjects ['obj_position' ].values
118128 - solarSystemObjects ['obs_position' ].values )
119129 solarSystemObjects [['ra' , 'dec' ]] = np .vstack (hp .vec2ang (vector , lonlat = True )).T
120130 solarSystemObjects ['obs_position_x' ], solarSystemObjects ['obs_position_y' ], \
121131 solarSystemObjects ['obs_position_z' ] = np .array (list (solarSystemObjects ['obs_position' ].values )).T
122- solarSystemObjects ['obj_position_x' ], solarSystemObjects ['obj_position_y' ], \
123- solarSystemObjects ['obj_position_z' ] = np .array (list (solarSystemObjects ['obj_position' ].values )).T
132+ solarSystemObjects ['heliocentricX' ], solarSystemObjects ['heliocentricY' ], \
133+ solarSystemObjects ['heliocentricZ' ] = np .array (list (solarSystemObjects ['obj_position' ].values )).T
134+ solarSystemObjects ['obs_velocity_x' ], solarSystemObjects ['obs_velocity_y' ], \
135+ solarSystemObjects ['obs_velocity_z' ] = np .array (list (solarSystemObjects ['obs_velocity' ].values )).T
136+ solarSystemObjects ['heliocentricVX' ], solarSystemObjects ['heliocentricVY' ], \
137+ solarSystemObjects ['heliocentricVZ' ] = np .array (list (solarSystemObjects ['obj_velocity' ].values )).T
138+ solarSystemObjects ['topocentric_position' ], solarSystemObjects ['topocentric_velocity' ] = (
139+ solarSystemObjects ['obj_position' ] - solarSystemObjects ['obs_position' ],
140+ solarSystemObjects ['obj_velocity' ] - solarSystemObjects ['obs_velocity' ],
141+ )
142+ solarSystemObjects ['topocentricX' ], solarSystemObjects ['topocentricY' ], \
143+ solarSystemObjects ['topocentricZ' ] = (
144+ np .array (list (solarSystemObjects ['topocentric_position' ].values )).T
145+ )
146+ solarSystemObjects ['topocentricVX' ], solarSystemObjects ['topocentricVY' ], \
147+ solarSystemObjects ['topocentricVZ' ] = (
148+ np .array (list (solarSystemObjects ['topocentric_velocity' ].values )).T
149+ )
150+ solarSystemObjects ['heliocentricVX' ], solarSystemObjects ['heliocentricVY' ], \
151+ solarSystemObjects ['heliocentricVZ' ] = np .array (list (solarSystemObjects ['obj_velocity' ].values )).T
152+ solarSystemObjects ['heliocentricDist' ], solarSystemObjects ['topocentricDist' ] = (
153+ solarSystemObjects ['obj_position' ].apply (np .linalg .norm ),
154+ solarSystemObjects ['topocentric_position' ].apply (np .linalg .norm )
155+ )
156+ solarSystemObjects ['phaseAngle' ] = (
157+ (solarSystemObjects ['obj_position' ] * solarSystemObjects ['topocentric_position' ]
158+ / solarSystemObjects ['heliocentricDist' ] / solarSystemObjects ['topocentricDist' ])
159+ .apply (np .sum ).apply (np .arccos ).apply (np .degrees )
160+ )
161+
162+ stateVectorColumns = ['heliocentricX' , 'heliocentricY' , 'heliocentricZ' , 'heliocentricVX' ,
163+ 'heliocentricVY' , 'heliocentricVZ' , 'topocentricX' , 'topocentricY' ,
164+ 'topocentricZ' , 'topocentricVX' , 'topocentricVY' , 'topocentricVZ' ]
124165
125166 maskedObjects = self ._maskToCcdRegion (
126167 solarSystemObjects ,
@@ -144,24 +185,28 @@ def run(self, diaSourceCatalog, solarSystemObjects, exposure):
144185 # picks the DiaSource with the shortest distance. We can do something
145186 # fancier later.
146187 ssSourceData = []
147- ras , decs , expected_ras , expected_decs = [], [], [], []
188+ ras , decs , residual_ras , residual_decs , dia_ids = [], [], [], [], []
148189 diaSourceCatalog ["ssObjectId" ] = 0
190+ source_column = 'id'
191+ if 'diaSourceId' in diaSourceCatalog .columns :
192+ source_column = 'diaSourceId'
149193 for index , ssObject in maskedObjects .iterrows ():
150194 ssoVect = self ._radec_to_xyz (ssObject ["ra" ], ssObject ["dec" ])
151195 # Which DIA Sources fall within r?
152196 dist , idx = tree .query (ssoVect , distance_upper_bound = maxRadius )
153197 if len (idx ) == 1 and np .isfinite (dist [0 ]):
154198 nFound += 1
155199 diaSourceCatalog .loc [diaSourceCatalog .index [idx [0 ]], "ssObjectId" ] = ssObject ["ssObjectId" ]
156- ssSourceData .append (ssObject [["ssObjectId" , "obs_position_x" , "obs_position_y" ,
157- "obs_position_z" , "obj_position_x" , "obj_position_y" ,
158- "obj_position_z" ]].values )
200+ ssSourceData .append (ssObject [["ssObjectId" , "phaseAngle" , "heliocentricDist" ,
201+ "topocentricDist" ] + stateVectorColumns ].values )
159202 dia_ra = diaSourceCatalog .loc [diaSourceCatalog .index [idx [0 ]], "ra" ]
160203 dia_dec = diaSourceCatalog .loc [diaSourceCatalog .index [idx [0 ]], "dec" ]
204+ dia_id = diaSourceCatalog .loc [diaSourceCatalog .index [idx [0 ]], source_column ]
161205 ras .append (dia_ra )
162206 decs .append (dia_dec )
163- expected_ras .append (ssObject ["ra" ])
164- expected_decs .append (ssObject ["dec" ])
207+ dia_ids .append (dia_id )
208+ residual_ras .append (dia_ra - ssObject ["ra" ])
209+ residual_decs .append (dia_dec - ssObject ["dec" ])
165210 maskedObjects .loc [index , 'associated' ] = True
166211 else :
167212 maskedObjects .loc [index , 'associated' ] = False
@@ -171,18 +216,26 @@ def run(self, diaSourceCatalog, solarSystemObjects, exposure):
171216 self .metadata ['nExpectedSsObjects' ] = nSolarSystemObjects
172217 assocSourceMask = diaSourceCatalog ["ssObjectId" ] != 0
173218 unAssocObjectMask = np .logical_not (maskedObjects ['associated' ].values )
174- ssSourceData = pd .DataFrame (ssSourceData , columns = ["ssObjectId" , "obs_position_x" , "obs_position_y" ,
175- "obs_position_z" , "obj_position_x" ,
176- "obj_position_y" , "obj_position_z" ])
219+ ssSourceData = pd .DataFrame (ssSourceData ,
220+ columns = [
221+ "ssObjectId" , "phaseAngle" , "heliocentricDist" , "topocentricDist"
222+ ] + stateVectorColumns )
177223 ssSourceData ["ra" ] = ras
178224 ssSourceData ["dec" ] = decs
179- ssSourceData ["expected_ra" ] = expected_ras
180- ssSourceData ["expected_dec" ] = expected_decs
181- unassociatedObjects = maskedObjects [unAssocObjectMask ].drop (columns = ['obs_x_poly' , 'obs_y_poly' ,
182- 'obs_z_poly' , 'obj_x_poly' ,
183- 'obj_y_poly' , 'obj_z_poly' ,
184- 'obs_position' , 'obj_position' ,
185- 'associated' ])
225+ ssSourceData ["residualRa" ] = residual_ras
226+ ssSourceData ["residualDec" ] = residual_decs
227+ ssSourceData [source_column ] = dia_ids
228+ coords = SkyCoord (ra = ssSourceData ['ra' ].values * u .deg , dec = ssSourceData ['dec' ].values * u .deg )
229+ ssSourceData ['galacticL' ] = coords .galactic .l .deg
230+ ssSourceData ['galacticB' ] = coords .galactic .b .deg
231+ ssSourceData ['eclipticLambda' ] = coords .barycentrictrueecliptic .lon .deg
232+ ssSourceData ['eclipticBeta' ] = coords .barycentrictrueecliptic .lat .deg
233+ columns_to_drop = [
234+ "obs_position" , "obs_velocity" , "obj_position" , "obj_velocity" , "topocentric_position" ,
235+ "topocentric_velocity" , "obs_x_poly" , "obs_y_poly" , "obs_z_poly" , "obj_x_poly" , "obj_y_poly" ,
236+ "obj_z_poly" , "associated"
237+ ]
238+ unassociatedObjects = maskedObjects [unAssocObjectMask ].drop (columns = columns_to_drop )
186239 return pipeBase .Struct (
187240 ssoAssocDiaSources = diaSourceCatalog [assocSourceMask ].reset_index (drop = True ),
188241 unAssocDiaSources = diaSourceCatalog [~ assocSourceMask ].reset_index (drop = True ),
0 commit comments