Skip to content

Commit 1488899

Browse files
Merge pull request #97 from rahil-makadia/dev
Minor updates
2 parents aa33b99 + 6803f3f commit 1488899

File tree

18 files changed

+378
-119
lines changed

18 files changed

+378
-119
lines changed

grss/debias/get_debiasing_data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
# if lowres_data.tgz or lowres_data/ already exist, do not download
99
if not os.path.exists(f'{cwd}/lowres_data.tgz') and not os.path.exists(f'{cwd}/lowres_data/'):
1010
FTP_FILE = 'debias_2018.tgz'
11-
cmd = f'curl --connect-timeout 30 --silent --show-error -o {cwd}/lowres_data.tgz {FTP_SITE}/{FTP_FILE}'
11+
cmd = f'curl --connect-timeout 30 --show-error -o {cwd}/lowres_data.tgz {FTP_SITE}/{FTP_FILE}'
1212
print('Downloading low-resolution debiasing data...')
1313
os.system(cmd)
1414
if not os.path.exists(f'{cwd}/hires_data.tgz') and not os.path.exists(f'{cwd}/hires_data/'):
1515
FTP_FILE = 'debias_hires2018.tgz'
16-
cmd = f'curl --connect-timeout 30 --silent --show-error -o {cwd}/hires_data.tgz {FTP_SITE}/{FTP_FILE}'
16+
cmd = f'curl --connect-timeout 30 --show-error -o {cwd}/hires_data.tgz {FTP_SITE}/{FTP_FILE}'
1717
print('Downloading high-resolution debiasing data...')
1818
os.system(cmd)
1919

grss/fit/fit_ades.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@
110110

111111
special_codes = {
112112
'gaia': {'258'},
113-
'occultation': {'275'},
114-
'spacecraft': {'S/C', 'S_C', '245', '249', '250', '274', 'C49', 'C50', 'C51',
115-
'C52', 'C53', 'C54', 'C55', 'C56', 'C57', 'C59', },
113+
'occultation': {'244', '275'},
114+
'spacecraft': {'S/C', 'S_C', '245', '249', '250', '273', '274',
115+
'C49', 'C50', 'C51', 'C52', 'C53', 'C54', 'C55', 'C56', 'C57', 'C58', 'C59', },
116116
'roving': {'247', '270'},
117117
}

grss/fit/fit_optical.py

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ def _ades_mode_check(df):
6767
if not df['mode'].isin(valid_modes).all():
6868
raise ValueError(f"Invalid mode in the data: {df['mode'].unique()}.\n"
6969
f"Acceptable modes are {valid_modes}.")
70-
if df['mode'].isin(['UNK']).any():
71-
print("\tWARNING: At least one unknown observation mode in the data.")
7270
return None
7371

7472
def _ades_ast_cat_check(df):
@@ -102,8 +100,6 @@ def _ades_ast_cat_check(df):
102100
'ACRS', 'LickGas', 'Ida93', 'Perth70', 'COSMOS',
103101
'Yale', 'ZZCAT', 'IHW', 'GZ', 'UNK']
104102
df_cats = df['astCat']
105-
if df_cats.isin(deprecated_cats).any():
106-
print("\tWARNING: At least one deprecated star catalog in the data.")
107103
if not df_cats.isin(valid_cats).all():
108104
invalid_cats = np.setdiff1d(df_cats.unique(), valid_cats)
109105
print("\tWARNING: At least one unrecognized astCat in the data. "
@@ -218,11 +214,24 @@ def add_psv_obs(psv_obs_file, obs_df, t_min_tdb=None, t_max_tdb=None, verbose=Fa
218214
t_min_tdb = -np.inf
219215
if t_max_tdb is None:
220216
t_max_tdb = np.inf
221-
psv_df = pd.read_csv(psv_obs_file, sep='|', skipinitialspace=True)
217+
# read file and skip header rows starting with '#' or '!'
218+
skip_count = 0
219+
with open(psv_obs_file, 'r') as f:
220+
lines = f.readlines()
221+
for line in lines:
222+
if line.startswith('#') or line.startswith('!'):
223+
skip_count += 1
224+
else:
225+
break
226+
psv_df = pd.read_csv(psv_obs_file, sep='|', skipinitialspace=True, skiprows=skip_count)
222227
psv_df.columns = psv_df.columns.str.strip()
223228
psv_df = psv_df[[col for col in psv_df.columns if col in ades_column_types]]
224229
psv_column_types = {col: ades_column_types[col] for col in psv_df.columns}
225230
psv_df = psv_df.astype(psv_column_types)
231+
psv_df['permID'] = obs_df.iloc[-1]['permID']
232+
psv_df['provID'] = obs_df.iloc[-1]['provID']
233+
# strip every entry in a column of leading and trailing whitespace
234+
psv_df = psv_df.apply(lambda x: x.str.strip() if x.dtype == "object" else x)
226235
occ_idx = psv_df.query("mode == 'OCC'").index
227236
if len(occ_idx) > 0:
228237
psv_df.loc[occ_idx,'dec'] = psv_df.loc[occ_idx,'decStar']
@@ -238,7 +247,10 @@ def add_psv_obs(psv_obs_file, obs_df, t_min_tdb=None, t_max_tdb=None, verbose=Fa
238247
psv_df['cosDec'] = np.cos(psv_df['dec']*np.pi/180)
239248
psv_df['sigRA'] = psv_df['rmsRA']
240249
psv_df['sigDec'] = psv_df['rmsDec']
241-
psv_df['sigCorr'] = psv_df['rmsCorr']
250+
if 'rmsCorr' not in psv_df:
251+
psv_df['sigCorr'] = 0.0
252+
if 'rmsTime' not in psv_df:
253+
psv_df['sigTime'] = 1.0
242254
times = Time(psv_df['obsTime'].to_list(), format='isot', scale='utc')
243255
psv_df['obsTimeMJD'] = times.utc.mjd
244256
psv_df['obsTimeMJDTDB'] = times.tdb.mjd
@@ -287,7 +299,8 @@ def _get_gaia_query_results(body_id, release):
287299
+ "ra_error_systematic,dec_error_systematic,ra_dec_correlation_systematic,"
288300
+ "ra_error_random,dec_error_random,ra_dec_correlation_random,"
289301
+ "x_gaia_geocentric,y_gaia_geocentric,z_gaia_geocentric,"
290-
+ "vx_gaia_geocentric,vy_gaia_geocentric,vz_gaia_geocentric"
302+
+ "vx_gaia_geocentric,vy_gaia_geocentric,vz_gaia_geocentric,"
303+
+ "astrometric_outcome_ccd, astrometric_outcome_transit"
291304
+ f" FROM {release}.{table} {match_str} ORDER BY epoch_utc ASC"
292305
)
293306
job = Gaia.launch_job_async(query, dump_to_file=False,background=True)
@@ -298,9 +311,9 @@ def _get_gaia_query_results(body_id, release):
298311
res.sort('epoch_utc')
299312
return res
300313

301-
def add_gaia_obs(obs_df, t_min_tdb=None, t_max_tdb=None, gaia_dr='gaiadr3', verbose=False):
314+
def add_gaia_obs(obs_df, t_min_tdb=None, t_max_tdb=None, gaia_dr='gaiafpr', verbose=False):
302315
"""
303-
Assemble the optical observations for a given body from Gaia DR3.
316+
Assemble the optical observations for a given body from Gaia FPR.
304317
305318
Parameters
306319
----------
@@ -312,7 +325,7 @@ def add_gaia_obs(obs_df, t_min_tdb=None, t_max_tdb=None, gaia_dr='gaiadr3', verb
312325
t_max_tdb : float, optional
313326
Maximum time (MJD TDB) for observations to be included, by default None
314327
gaia_dr : str, optional
315-
Gaia data release version database name, by default 'gaiadr3'
328+
Gaia data release version database name, by default 'gaiafpr'
316329
verbose : bool, optional
317330
Flag to print out information about the observations, by default False
318331
@@ -339,6 +352,10 @@ def add_gaia_obs(obs_df, t_min_tdb=None, t_max_tdb=None, gaia_dr='gaiadr3', verb
339352
curr_transit = int(-1e6)
340353
gaia_add_counter = 0
341354
for i, data in enumerate(res):
355+
# # print(data["astrometric_outcome_ccd"], data["astrometric_outcome_transit"])
356+
# # print(type(data["astrometric_outcome_ccd"]), type(data["astrometric_outcome_transit"]))
357+
# if data['astrometric_outcome_ccd'] != 1 or data['astrometric_outcome_transit'] != 1:
358+
# continue
342359
if curr_transit != data['transit_id']:
343360
curr_transit = data['transit_id']
344361
transit_count = 1
@@ -377,16 +394,27 @@ def add_gaia_obs(obs_df, t_min_tdb=None, t_max_tdb=None, gaia_dr='gaiadr3', verb
377394
obs_df.loc[idx, 'sigRA'] = ra_sig
378395
obs_df.loc[idx, 'sigDec'] = dec_sig
379396
obs_df.loc[idx, 'sigCorr'] = corr
397+
# obs_df.loc[idx, 'sigTime'] = data['epoch_err']*86400.0
380398
obs_df.loc[idx, 'biasRA'] = 0.0
381399
obs_df.loc[idx, 'biasDec'] = 0.0
382400
obs_df.loc[idx, 'ctr'] = ctr
383401
obs_df.loc[idx, 'sys'] = sys
384-
obs_df.loc[idx, 'pos1'] = data['x_gaia_geocentric']
385-
obs_df.loc[idx, 'pos2'] = data['y_gaia_geocentric']
386-
obs_df.loc[idx, 'pos3'] = data['z_gaia_geocentric']
387-
obs_df.loc[idx, 'vel1'] = data['vx_gaia_geocentric']
388-
obs_df.loc[idx, 'vel2'] = data['vy_gaia_geocentric']
389-
obs_df.loc[idx, 'vel3'] = data['vz_gaia_geocentric']
402+
tcb_tdb_fac = 1 - 1.550519768e-8
403+
obs_df.loc[idx, 'pos1'] = data['x_gaia_geocentric']*tcb_tdb_fac
404+
obs_df.loc[idx, 'pos2'] = data['y_gaia_geocentric']*tcb_tdb_fac
405+
obs_df.loc[idx, 'pos3'] = data['z_gaia_geocentric']*tcb_tdb_fac
406+
# obs_df.loc[idx, 'vel1'] = data['vx_gaia_geocentric']*tcb_tdb_fac
407+
# obs_df.loc[idx, 'vel2'] = data['vy_gaia_geocentric']*tcb_tdb_fac
408+
# obs_df.loc[idx, 'vel3'] = data['vz_gaia_geocentric']*tcb_tdb_fac
409+
# # add some position uncertainty (testing)
410+
# au2km = 149597870.7
411+
# pos_sig = 1.0/au2km
412+
# obs_df.loc[idx, 'posCov11'] = pos_sig**2
413+
# obs_df.loc[idx, 'posCov12'] = 0.0
414+
# obs_df.loc[idx, 'posCov13'] = 0.0
415+
# obs_df.loc[idx, 'posCov22'] = pos_sig**2
416+
# obs_df.loc[idx, 'posCov23'] = 0.0
417+
# obs_df.loc[idx, 'posCov33'] = pos_sig**2
390418
if verbose:
391419
print(f"\tFiltered to {gaia_add_counter} observations that",
392420
"satisfy the time range constraints.")
@@ -889,10 +917,9 @@ def deweight_obs(obs_df, eff_obs_per_night, verbose):
889917
times = obs_df['obsTimeMJD'].values
890918
stations = obs_df['stn'].values
891919
weights = obs_df[['sigRA', 'sigDec']].values
920+
batch_first_time = times[0]
892921
for i in range(1, len(obs_df)):
893-
curr_jd_night = np.floor(times[i]+2400000.5)
894-
prev_jd_night = np.floor(times[i-1]+2400000.5)
895-
night_match = curr_jd_night == prev_jd_night
922+
night_match = times[i] - batch_first_time < 8/24
896923
curr_observatory = stations[i]
897924
prev_observatory = stations[i-1]
898925
observatory_match = curr_observatory == prev_observatory
@@ -904,6 +931,7 @@ def deweight_obs(obs_df, eff_obs_per_night, verbose):
904931
factor = night_count**0.5/eff_obs_per_night**0.5
905932
weights[i-night_count:i] *= factor
906933
night_count = 1
934+
batch_first_time = times[i]
907935
# edge case where last observation is part of a batch that needs deweighting
908936
if night_count > eff_obs_per_night:
909937
deweight_count += night_count
@@ -939,10 +967,9 @@ def eliminate_obs(obs_df, max_obs_per_night, verbose):
939967
print(f"Applying {max_obs_per_night}-observation per night elimination scheme.")
940968
times = obs_df['obsTimeMJD'].values
941969
stations = obs_df['stn'].values
970+
batch_first_time = times[0]
942971
for i in range(1, len(obs_df)):
943-
curr_jd_night = np.floor(times[i]+2400000.5)
944-
prev_jd_night = np.floor(times[i-1]+2400000.5)
945-
night_match = curr_jd_night == prev_jd_night
972+
night_match = times[i] - batch_first_time < 8/24
946973
curr_observatory = stations[i]
947974
prev_observatory = stations[i-1]
948975
observatory_match = curr_observatory == prev_observatory
@@ -953,6 +980,7 @@ def eliminate_obs(obs_df, max_obs_per_night, verbose):
953980
idx_to_drop.append(i)
954981
else:
955982
night_count = 1
983+
batch_first_time = times[i]
956984
obs_df.drop(idx_to_drop, inplace=True)
957985
obs_df.reset_index(drop=True, inplace=True)
958986
if verbose:
@@ -1004,16 +1032,17 @@ def get_optical_obs(body_id, optical_obs_file=None, t_min_tdb=None,
10041032
"""
10051033
if eliminate and deweight:
10061034
raise ValueError('Cannot deweight and eliminate observations at the same time.')
1007-
if not eliminate and not deweight:
1035+
if not eliminate and not deweight and verbose:
10081036
print("WARNING: No deweighting or elimination scheme applied",
10091037
"for observations during the same night.")
10101038
obs_df = create_optical_obs_df(body_id, optical_obs_file,
10111039
t_min_tdb, t_max_tdb, verbose)
10121040
if debias_lowres is not None:
10131041
obs_df = apply_debiasing_scheme(obs_df, debias_lowres, verbose)
10141042
else:
1015-
print("WARNING: No debiasing scheme applied to the observations.",
1016-
"Setting biases to zero.")
1043+
if verbose:
1044+
print("WARNING: No debiasing scheme applied to the observations.",
1045+
"Setting biases to zero.")
10171046
opt_idx = obs_df.query("mode != 'RAD'").index
10181047
obs_df.loc[opt_idx, ['biasRA', 'biasDec']] = 0.0
10191048
if not accept_weights:

grss/fit/fit_simulation.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,14 +1366,24 @@ def _inflate_uncertainties(self, prop_sim_past, prop_sim_future):
13661366
sig_ra_vals = self.obs.sigRA.values
13671367
sig_dec_vals = self.obs.sigDec.values
13681368
sig_corr_vals = self.obs.sigCorr.values
1369+
sys_vals = self.obs.sys.values
1370+
p11_vals = self.obs.posCov11.values
1371+
p12_vals = self.obs.posCov12.values
1372+
p13_vals = self.obs.posCov13.values
1373+
p22_vals = self.obs.posCov22.values
1374+
p23_vals = self.obs.posCov23.values
1375+
p33_vals = self.obs.posCov33.values
13691376
if self.past_obs_exist and self.future_obs_exist:
13701377
optical_obs_dot = prop_sim_past.opticalObsDot + prop_sim_future.opticalObsDot
1378+
optical_obs_partials = prop_sim_past.opticalPartials + prop_sim_future.opticalPartials
13711379
state_eval = prop_sim_past.xIntegEval + prop_sim_future.xIntegEval
13721380
elif self.past_obs_exist:
13731381
optical_obs_dot = prop_sim_past.opticalObsDot
1382+
optical_obs_partials = prop_sim_past.opticalPartials
13741383
state_eval = prop_sim_past.xIntegEval
13751384
elif self.future_obs_exist:
13761385
optical_obs_dot = prop_sim_future.opticalObsDot
1386+
optical_obs_partials = prop_sim_future.opticalPartials
13771387
state_eval = prop_sim_future.xIntegEval
13781388
computed_obs_dot = np.array(optical_obs_dot)[:,0:2]
13791389
computed_obs_dot[:, 0] *= self.obs.cosDec.values
@@ -1399,6 +1409,7 @@ def _inflate_uncertainties(self, prop_sim_past, prop_sim_future):
13991409
cov = np.array([[sig_ra**2, off_diag],
14001410
[off_diag, sig_dec**2]])
14011411
time_uncert = sig_times[i]
1412+
# apply time uncertainties to the optical observations
14021413
if time_uncert != 0.0 and stations[i] not in no_time_uncert:
14031414
ra_dot_cos_dec = computed_obs_dot[i, 0]
14041415
dec_dot = computed_obs_dot[i, 1]
@@ -1407,10 +1418,28 @@ def _inflate_uncertainties(self, prop_sim_past, prop_sim_future):
14071418
[off_diag_time, dec_dot**2]])*(time_uncert/86400)**2
14081419
cov += cov_time
14091420
sig_times[i] = time_uncert
1421+
# apply Gaia astrometric handling
14101422
if radius_nonzero and stations[i] == '258':
14111423
cov_fac = np.array([[fac[i], 0.0],
14121424
[0.0, fac[i]]])
14131425
cov += cov_fac
1426+
# apply station position uncertainties
1427+
if np.isfinite(p11_vals[i]):
1428+
cov_stn_pos = np.array([
1429+
[p11_vals[i], p12_vals[i], p13_vals[i]],
1430+
[p12_vals[i], p22_vals[i], p23_vals[i]],
1431+
[p13_vals[i], p23_vals[i], p33_vals[i]]])
1432+
# make sure all cov values are finite
1433+
if not np.isfinite(cov_stn_pos).all():
1434+
raise ValueError("Station position covariance matrix is not finite.")
1435+
if sys_vals[i] not in {'ICRF_AU', 'ICRF_KM'}:
1436+
raise ValueError("Station position covariance matrix system not defined/recognized.")
1437+
conv = 1 if sys_vals[i] == 'ICRF_AU' else 1/1.495978707e8
1438+
cov_stn_pos *= conv**2
1439+
partials = np.array(optical_obs_partials[i]).reshape(2, 6)[:, :3]
1440+
partials[0, :] *= self.obs.cosDec.values[i]
1441+
cov_stn_unc = partials @ cov_stn_pos @ partials.T
1442+
cov += cov_stn_unc
14141443
det = cov[0, 0]*cov[1, 1] - cov[0, 1]*cov[1, 0]
14151444
inv = np.array([[cov[1, 1], -cov[0, 1]],
14161445
[-cov[1, 0], cov[0, 0]]])/det

grss/fit/fit_utils.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,8 @@ def get_mpc_observatory_info():
9292
dictionary of observatory codes and their corresponding longitude,
9393
rho*cos(latitude), and rho*sin(latitude)
9494
"""
95-
fpath = f'{grss_path}/fit/codes.json'
96-
with open(fpath, 'r', encoding='utf-8') as f:
97-
codes = json.load(f)
98-
mpc_info_dict = {}
99-
for key, val in codes.items():
100-
if 'Longitude' in val and 'cos' in val and 'sin' in val:
101-
mpc_info_dict[key] = val['Longitude'], val['cos'], val['sin']
95+
with open(f'{grss_path}/fit/codes.json', 'r', encoding='utf-8') as f:
96+
mpc_info_dict = json.load(f)
10297
return mpc_info_dict
10398

10499
def get_radar_codes_dict():
@@ -287,7 +282,9 @@ def get_sbdb_elems(tdes, cov_elems=True):
287282
print("get_radar_obs_array: ERROR. ", response.status_code, response.content)
288283
raise ValueError("Failed to get JPL orbit data")
289284
raw_data = get_sbdb_raw_data(tdes)
290-
if cov_elems:
285+
# check that covariance exists
286+
cov_exists = raw_data['orbit']['covariance'] is not None
287+
if cov_elems and cov_exists:
291288
# epoch of orbital elements at reference time [JD -> MJD]
292289
epoch_mjd = float(raw_data['orbit']['covariance']['epoch']) - 2400000.5
293290
# cometary elements at epoch_mjd
@@ -345,11 +342,16 @@ def get_sbdb_info(tdes):
345342
# cometary elements corresponding to the covariance on JPL SBDB
346343
elements = get_sbdb_elems(tdes, cov_elems=True)
347344
# covariance matrix for cometary orbital elements
348-
cov_keys = raw_data['orbit']['covariance']['labels']
349-
cov_mat = (np.array(raw_data['orbit']['covariance']['data'])).astype(float)
350-
# convert covariance matrix angle blocks from degrees to radians
351-
cov_mat[3:6, :] *= np.pi/180
352-
cov_mat[:, 3:6] *= np.pi/180
345+
cov_exists = raw_data['orbit']['covariance'] is not None
346+
cov_keys = raw_data['orbit']['covariance']['labels'] if cov_exists else []
347+
if cov_exists:
348+
cov_mat = (np.array(raw_data['orbit']['covariance']['data'])).astype(float)
349+
# convert covariance matrix angle blocks from degrees to radians
350+
cov_mat[3:6, :] *= np.pi/180
351+
cov_mat[:, 3:6] *= np.pi/180
352+
else:
353+
print(f"WARNING: No covariance data available for {tdes}")
354+
cov_mat = np.zeros((6, 6))
353355
# nongravitatinoal constants for target body
354356
nongrav_data = raw_data['orbit']['model_pars']
355357
hdr = [param['name'] for param in nongrav_data]

0 commit comments

Comments
 (0)