1from astropy.coordinates
import (
2 get_body_barycentric_posvel,
3 solar_system_ephemeris,
5 HeliocentricEclipticIAU76,
7from astropy.time
import Time
8import astropy.units
as u
9from functools
import partial
13from .
import util, schema
14from .photfit
import hg_V_mag, phase_angle_deg
15from .ephem
import _aux_compute_ephemerides
23 dia = dia.iloc[assoc[
"dia_index"]]
26 assert np.all(dia[
"ssObjectId"] == dia[
"ssObjectId"].iloc[0])
27 assert np.all(sss[
"ssObjectId"] == sss[
"ssObjectId"][0])
28 assert len(dia) == len(sss)
30 provID = sss[
"designation"][0]
31 ephTimes = Time(dia[
"midpointMjdTai"].values, format=
"mjd", scale=
"tai")
32 eph, (H, G), xx, vv, obs, mu_lon, mu_lat, mu = _aux_compute_ephemerides(provID, ephTimes, mpcorb)
34 sss[
"ephRateRa"] = mu_lon.value
35 sss[
"ephRateDec"] = mu_lat.value
36 sss[
"ephRate"] = mu.value
39 with solar_system_ephemeris.set(
"de440"):
40 pos, vel = get_body_barycentric_posvel(
"sun", ephTimes)
41 hx, hy, hz = pos.x.to(u.au).value, pos.z.to(u.au).value, pos.z.to(u.au).value
42 hvx, hvy, hvz = vel.x.to(kms).value, vel.y.to(kms).value, vel.z.to(kms).value
45 robs, vobs = util.observatory_barycentric_posvel(
"X05", ephTimes)
46 robs = robs.to(u.au).value
47 vobs = vobs.to(u.km / u.s).value
50 sss[
"ephRa"] = eph.ra.deg
51 sss[
"ephDec"] = eph.dec.deg
52 obsv = SkyCoord(ra=dia[
"ra"], dec=dia[
"dec"], unit=
"deg", frame=
"icrs")
54 sss[
"ephOffsetDec"] = (dia[
"dec"].to_numpy() - sss[
"ephDec"]) * 3600
55 sss[
"ephOffsetRa"] = (dia[
"ra"].to_numpy() - sss[
"ephRa"]) * np.cos(np.deg2rad(sss[
"ephDec"])) * 3600
56 sss[
"ephOffset"] = eph.separation(obsv).arcsec
59 sss[
"helio_x"] = xx[0] - hx
60 sss[
"helio_y"] = xx[1] - hy
61 sss[
"helio_z"] = xx[2] - hz
62 sss[
"helioRange"] = np.sqrt(sss[
"helio_x"] ** 2 + sss[
"helio_y"] ** 2 + sss[
"helio_z"] ** 2)
65 sss[
"helio_vx"] = vv[0] - hvx
66 sss[
"helio_vy"] = vv[1] - hvy
67 sss[
"helio_vz"] = vv[2] - hvz
68 sss[
"helio_vtot"] = np.sqrt(sss[
"helio_vx"] ** 2 + sss[
"helio_vy"] ** 2 + sss[
"helio_vz"] ** 2)
72 sss[
"helioRangeRate"] = (
73 sss[
"helio_vx"] * sss[
"helio_x"] + sss[
"helio_vy"] * sss[
"helio_y"] + sss[
"helio_vz"] * sss[
"helio_z"]
77 sss[
"topo_x"] = xx[0] - obs[0]
78 sss[
"topo_y"] = xx[1] - obs[1]
79 sss[
"topo_z"] = xx[2] - obs[2]
80 sss[
"topoRange"] = np.sqrt(sss[
"topo_x"] ** 2 + sss[
"topo_y"] ** 2 + sss[
"topo_z"] ** 2)
83 sss[
"topo_vx"] = vv[0] - vobs[0]
84 sss[
"topo_vy"] = vv[1] - vobs[1]
85 sss[
"topo_vz"] = vv[2] - vobs[2]
86 sss[
"topo_vtot"] = np.sqrt(sss[
"topo_vx"] ** 2 + sss[
"topo_vy"] ** 2 + sss[
"topo_vz"] ** 2)
90 sss[
"topoRangeRate"] = (
91 sss[
"topo_vx"] * sss[
"topo_x"] + sss[
"topo_vy"] * sss[
"topo_y"] + sss[
"topo_vz"] * sss[
"topo_z"]
94 sss[
"phaseAngle"] = phase_deg = phase_angle_deg(xx, obs)
96 sss[
"ephVmag"] = hg_V_mag(H, G, sss[
"helioRange"], sss[
"topoRange"], phase_deg)
98 max_sep = np.max(sss[
"ephOffset"])
99 med_sep = np.median(sss[
"ephOffset"])
100 print(f
"{provID}: max/median separation: {max_sep:.4f}, {med_sep:.4f} arcsec")
103if __name__ ==
"__main__":
104 input_dir =
"./analysis/inputs"
105 output_dir =
"./analysis/outputs"
107 dia = pd.read_parquet(
108 f
"{input_dir}/dia_sources.parquet", engine=
"pyarrow", dtype_backend=
"pyarrow"
109 ).reset_index(drop=
True)
111 dia = dia.sample(frac=0.9, random_state=42).reset_index(drop=
True)
113 det = pd.read_parquet(
114 f
"{input_dir}/obs_sbn.parquet", engine=
"pyarrow", dtype_backend=
"pyarrow"
118 sampled_provids = det[
"provid"].drop_duplicates().sample(10, random_state=42)
119 det = det[det[
"provid"].isin(sampled_provids)].reset_index()
124 det[
"obssubid"] = det[
"obssubid"].astype(int)
135 "designation_asterisk",
141 expect_dtypes = dict(
142 trksub=
"string[pyarrow]",
144 provid=
"string[pyarrow]",
145 permid=
"string[pyarrow]",
146 submission_id=
"string[pyarrow]",
147 ra=
"double[pyarrow]",
148 dec=
"double[pyarrow]",
149 obstime=
"timestamp[us][pyarrow]",
150 designation_asterisk=
"bool[pyarrow]",
153 for col
in det.columns:
154 assert det[col].dtype == expect_dtypes[col]
160 .merge(det.add_prefix(
"mpc_"), left_on=
"diaSourceId", right_on=
"mpc_obssubid", how=
"inner")
162 assoc.rename(columns={
"index":
"dia_index"}, inplace=
True)
165 assert np.all(dia[
"diaSourceId"].iloc[assoc[
"dia_index"]].to_numpy() == assoc[
"diaSourceId"].to_numpy())
168 util.assoc_validate(dia, assoc)
170 totalNumObs = len(assoc)
172 numid = pd.read_parquet(
173 f
"{input_dir}/numbered_identifications.parquet",
175 columns=[
"permid",
"unpacked_primary_provisional_designation"],
176 dtype_backend=
"pyarrow",
177 ).reset_index(drop=
True)
178 curid = pd.read_parquet(
179 f
"{input_dir}/current_identifications.parquet",
181 dtype_backend=
"pyarrow",
183 "unpacked_primary_provisional_designation",
184 "unpacked_secondary_provisional_designation",
185 "packed_primary_provisional_designation",
187 ).reset_index(drop=
True)
191 df = assoc[[
"mpc_provid",
"mpc_permid"]].merge(numid, left_on=
"mpc_permid", right_on=
"permid", how=
"left")
192 assert len(df) == len(assoc)
194 assoc[
"mpc_provid"] = assoc[
"mpc_provid"].where(
195 assoc[
"mpc_provid"].notna(), df[
"unpacked_primary_provisional_designation"]
198 assert not assoc[
"mpc_provid"].isna().any()
199 assert len(assoc) == totalNumObs
203 df = assoc[[
"mpc_provid"]].merge(
204 curid, left_on=
"mpc_provid", right_on=
"unpacked_secondary_provisional_designation", how=
"inner"
206 assoc[
"mpc_provid"] = df[
"unpacked_primary_provisional_designation"]
207 assoc[
"mpc_packed"] = df[
"packed_primary_provisional_designation"]
209 assert len(assoc) == totalNumObs
212 assoc.sort_values([
"mpc_provid"], inplace=
True)
215 sss = np.zeros(totalNumObs, dtype=schema.SSSourceDtype)
216 sss.dtype.itemsize, len(sss), f
"{sss.nbytes:,}"
221 sss[
"diaSourceId"] = assoc[
"diaSourceId"].values
222 sss[
"ssObjectId"] = util.packed_ascii_to_uint64_le(assoc[
"mpc_packed"])
223 sss[
"designation"] = assoc[
"mpc_provid"]
225 df = dia[[
"ra",
"dec",
"midpointMjdTai"]].iloc[assoc[
"dia_index"]]
228 df[
"dec"].to_numpy(),
229 Time(df[
"midpointMjdTai"].to_numpy(), format=
"mjd", scale=
"tai"),
232 sss[
"elongation"] = util.solar_elongation_ndarray(ra, dec, t)
235 p = SkyCoord(ra=ra * u.deg, dec=dec * u.deg, distance=1 * u.au, frame=
"hcrs")
236 ecl = p.transform_to(HeliocentricEclipticIAU76)
237 p = SkyCoord(ra=ra * u.deg, dec=dec * u.deg, distance=1 * u.au, frame=
"icrs")
238 gal = p.transform_to(
"galactic")
240 sss[
"eclLambda"] = ecl.lon
241 sss[
"eclBeta"] = ecl.lat
242 sss[
"galLon"] = gal.l
243 sss[
"galLat"] = gal.b
245 mpcorb = pd.read_parquet(
246 f
"{input_dir}/mpc_orbits.parquet",
248 dtype_backend=
"pyarrow",
250 "unpacked_primary_provisional_designation",
251 "packed_primary_provisional_designation",
264 ).reset_index(drop=
True)
266 util.group_by([sss, assoc],
"ssObjectId", partial(compute_sssource_entry, mpcorb=mpcorb, dia=dia))
268 totalNumObjects = np.unique(sss[
"ssObjectId"]).size
269 print(f
"{totalNumObjects:,} unique objects with {len(sss):,} total observations.")
271 util.struct_to_parquet(sss, f
"{output_dir}/sssource.parquet")
compute_sssource_entry(sss, assoc, mpcorb, dia)