203 def run(self, visitSummaries, mpcorb, de440s, sb441_n16, obsCodes, linux_p1550p2650, pck00010,
204 earth_latest_high_prec, earth_620120_250826, earth_2025_250826_2125_predict, naif0012):
205 """Parse the information on the current visit and retrieve the
206 observable solar system objects from Sorcha.
210 visitSummary : `lsst.afw.table.ExposureCatalog`
211 Has rows with .getVisitInfo, which give the center and time of exposure
213 mpcorb, de440s, sb441_n16, obsCodes, linux_p1550p2650, pck00010,
214 earth_latest_high_prec, earth_620120_250826, earth_2025_250826_2125_predict,
215 naif0012 : `lsst.pipe.tasks.sspAuxiliaryFile.SSPAuxiliaryFile`s
216 Minor Planet Center orbit table used for association
220 result : `lsst.pipe.base.Struct`
221 Results struct with components:
223 - ``ssObjects`` : `pandas.DataFrame`
224 DataFrame containing Solar System Objects near the detector
225 footprint as retrieved by Sorcha. The columns are as follows:
230 RA in decimal degrees (`float`)
232 DEC in decimal degrees (`float`)
235 if len(visitSummaries) == 0:
236 raise NoWorkFound(
"No visits input!")
237 visitInfos = [vs[0].getVisitInfo()
for vs
in visitSummaries]
238 fieldRA = np.array([vi.getBoresightRaDec().getRa().asDegrees()
for vi
in visitInfos])
239 fieldDec = np.array([vi.getBoresightRaDec().getDec().asDegrees()
for vi
in visitInfos])
240 epochMJD = np.array([vi.date.toAstropy().tai.mjd
for vi
in visitInfos])
241 visits = [vi.id
for vi
in visitInfos]
245 visitTime = np.ones(n) * 30.0
246 inputVisits = pd.DataFrame({
247 "observationMidpointMJD": epochMJD,
249 "fieldDec": fieldDec,
250 "observationId": visits,
251 "visitTime": np.ones(n) * visitTime,
252 "observationStartMJD": epochMJD - (visitTime / 2) / 86400.0,
253 "visitExposureTime": visitTime,
257 "seeingFwhmGeom": [-1] * n,
258 "seeingFwhmEff": [-1] * n,
259 "fiveSigmaDepth": [-1] * n,
260 "rotSkyPos": [-1] * n,
263 inputOrbits = mpcorb[
264 [
'packed_primary_provisional_designation',
'q',
'e',
'i',
265 'node',
'argperi',
'peri_time',
'epoch_mjd']
266 ].rename(columns={
'packed_primary_provisional_designation':
'ObjID',
'epoch_mjd':
'epochMJD_TDB',
267 'i':
'inc',
'argperi':
'argPeri',
'peri_time':
't_p_MJD_TDB'})
268 inputOrbits[
'FORMAT'] =
'COM'
270 inputColors = inputOrbits[[
"ObjID"]].copy()
271 inputColors[
"H_r"] = mpcorb[
'h']
272 inputColors[
"GS"] = 0.15
274 eph_str = resources.files(
lsst.pipe.tasks).parents[3].joinpath(
"data/eph.ini").read_text()
275 eph_str = eph_str.replace(
"{OBSCODE}", self.config.observatoryCode)
276 eph_str = eph_str.replace(
"{FOV}", str(self.config.observatoryFOVRadius))
278 with TemporaryDirectory()
as tmpdirname:
279 self.log.info(f
'temp dir: {tmpdirname}')
282 inputOrbits.to_csv(f
'{tmpdirname}/orbits.csv', index=
False)
284 conn = sqlite_connect(f
'{tmpdirname}/pointings.db')
285 inputVisits.to_sql(
'observations', conn, if_exists=
'replace', index=
False)
288 with open(f
'{tmpdirname}/eph.ini',
'w')
as ephFile:
289 ephFile.write(eph_str)
291 inputColors.to_csv(f
'{tmpdirname}/colors.csv', index=
False)
293 cache = f
'{tmpdirname}/sorcha_cache/'
294 self.log.info(
'making cache')
297 for filename, fileref
in [
298 (
'de440s.bsp', de440s),
299 (
'sb441-n16.bsp', sb441_n16),
300 (
'ObsCodes.json', obsCodes),
301 (
'linux_p1550p2650.440', linux_p1550p2650),
302 (
'pck00010.pck', pck00010),
303 (
'earth_latest_high_prec.bpc', earth_latest_high_prec),
304 (
'earth_620120_250826.bpc', earth_620120_250826),
305 (
'earth_2025_250826_2125_predict.bpc', earth_2025_250826_2125_predict),
306 (
'naif0012.tls', naif0012),
308 self.log.info(f
'writing {filename}')
309 with open(cache + filename,
'wb')
as file:
310 file.write(fileref.fileContents.read())
312 abspath = f
'{tmpdirname}/sorcha_cache/'
314 n_iter = int(len(str(abspath)) / split)
315 for n
in range(n_iter, 0, -1):
316 abspath = abspath[:split * n] +
"+' '" + abspath[split * n:]
318 meta_kernel_text = dedent(f
"""\
321 PATH_VALUES = ('{abspath}')
327 '$A/earth_620120_250826.bpc',
328 '$A/earth_2025_250826_2125_predict.bpc',
331 '$A/earth_latest_high_prec.bpc',
336 with open(f
'{tmpdirname}/sorcha_cache/meta_kernel.txt',
'w')
as meta_kernel_file:
337 meta_kernel_file.write(meta_kernel_text)
338 self.log.info(
'Sorcha process begun')
344 "-c", f
"{tmpdirname}/eph.ini",
345 "-o", f
"{tmpdirname}/",
346 "--ob", f
"{tmpdirname}/orbits.csv",
347 "-p", f
"{tmpdirname}/colors.csv",
348 "--pd", f
"{tmpdirname}/pointings.db",
349 "--ew", f
"{tmpdirname}/ephemeris",
350 "--ar", f
"{tmpdirname}/sorcha_cache/"
357 self.log.info(f
"Sorcha STDOUT:\n {result.stdout}")
358 self.log.info(f
"Sorcha STDERR:\n {result.stderr}")
360 eph_path = f
'{tmpdirname}/ephemeris.csv'
361 if not os.path.exists(eph_path):
362 raise FileNotFoundError(
363 " Sorcha did not create ephemeris. Check STDOUT/STDERR above. "
364 f
"Directory contents:\n{os.listdir(tmpdirname)}"
368 ephemeris = pd.read_csv(eph_path)
369 perVisitSsObjects = {FieldID: group
for FieldID, group
in ephemeris.groupby(
"FieldID")}
371 if v
not in perVisitSsObjects:
372 perVisitSsObjects[v] = ephemeris.iloc[:0]
373 return Struct(ssObjects=perVisitSsObjects)