Skip to content

Commit

Permalink
Merge pull request #64 from rahil-makadia/dev
Browse files Browse the repository at this point in the history
updated ca/impact searches; addressed pandas FutureWarnings
  • Loading branch information
rahil-makadia authored Apr 27, 2024
2 parents ccb2333 + 8a04d31 commit e63ab24
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 78 deletions.
24 changes: 17 additions & 7 deletions grss/fit/fit_optical.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Optical observation handling for the GRSS orbit determination code"""
import os
from io import StringIO
from astropy.time import Time
import requests
from astroquery.gaia import Gaia
Expand Down Expand Up @@ -36,7 +37,7 @@ def get_mpc_raw_data(tdes):
obs_data = response.json()[0]["XML"]
else:
print("Error getting MPC XML data: ", response.status_code, response.content)
return obs_data
return StringIO(obs_data)

def _ades_mode_check(df):
"""
Expand Down Expand Up @@ -137,20 +138,23 @@ def create_optical_obs_df(body_id, optical_obs_file=None, t_min_tdb=None,
# read in the data and add extra columns if not present
obs_df = (
pd.read_xml(obs_data, dtype=ades_column_types)
# add columns if they are not present
.reindex(columns=ades_column_types.keys(), fill_value=np.nan)
# compute the obsTimeMJD time from obsTime
.assign(obsTimeMJD=lambda x:Time(x['obsTime'].to_list(),format='isot',scale='utc').utc.mjd)
)
# add columns if they are not present
str_cols = ['trx', 'rcv', 'sys', 'selAst']
for col in str_cols:
if col not in obs_df:
obs_df[col] = str(np.nan)
for col in ades_column_types:
if col not in obs_df:
obs_df[col] = np.nan
if verbose:
print(f"Read in {len(obs_df)} observations from the MPC.")
_ades_mode_check(obs_df)
_ades_ast_cat_check(obs_df)
# filter the data based on the time range
obs_df.query(f"{t_min_utc} <= obsTimeMJD <= {t_max_utc}", inplace=True)
# # filter the data based on the observation station
# stn_to_remove = ('247', '270') # roving observatories
# obs_df.query(f"stn not in {stn_to_remove}", inplace=True)
# reindex the data frame
obs_df.reset_index(drop=True, inplace=True)
# for all indices with OCC mode compute ra and dec as raStar+deltaRA and decStar+deltaDec
Expand Down Expand Up @@ -958,7 +962,13 @@ def get_optical_obs(body_id, optical_obs_file=None, t_min_tdb=None,
"for observations during the same night.")
obs_df = create_optical_obs_df(body_id, optical_obs_file,
t_min_tdb, t_max_tdb, verbose)
obs_df = apply_debiasing_scheme(obs_df, debias_lowres, verbose)
if debias_lowres is not None:
obs_df = apply_debiasing_scheme(obs_df, debias_lowres, verbose)
else:
print("WARNING: No debiasing scheme applied to the observations.",
"Setting biases to zero.")
opt_idx = obs_df.query("mode != 'RAD'").index
obs_df.loc[opt_idx, ['biasRA', 'biasDec']] = 0.0
obs_df = apply_weighting_scheme(obs_df, verbose)
if deweight:
obs_df = deweight_obs(obs_df, num_obs_per_night, verbose)
Expand Down
30 changes: 22 additions & 8 deletions grss/fit/fit_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from .. import libgrss
from ..utils import default_kernel_path, grss_path
from .fit_utils import get_observer_info
from .fit_utils import get_observer_info, get_similarity_stats

__all__ = [ 'FitSimulation',
]
Expand Down Expand Up @@ -712,7 +712,8 @@ def _parse_observation_arrays(self, obs_df):
None
"""
self.obs = obs_df
self.obs['selAst'].fillna('A', inplace=True)
sel_ast_map = {'': 'A', ' ': 'A', np.nan: 'A', 'nan': 'A'}
self.obs['selAst'] = self.obs['selAst'].replace(sel_ast_map)
if self.simulated_obs is not None:
self._add_simulated_obs()
self.obs.sort_values(by='obsTimeMJD', inplace=True, ignore_index=True)
Expand Down Expand Up @@ -1893,18 +1894,16 @@ def save(self, filename):
f.write(f'{obs["selAst"]+obs["obsTime"]:<{widths["obsTime"]}}')
if obs['mode'] in {'RAD', 'SIM_RAD_DEL', 'SIM_RAD_DOP'}:
f.write(f'{obs["trx"]+"/"+obs["rcv"]:^{widths["stn"]}}')
f.write(f'{obs["delay"]:^{widths["ra"]}.9f}')
sign = "+" if obs["doppler"] >= 0 else ""
f.write(f'{sign+str(obs["doppler"]):^{widths["dec"]}}')
f.write(f'{obs["delay"]:^{widths["ra"]}.13g}')
f.write(f'{obs["doppler"]:^+{widths["dec"]}.12g}')
f.write(f'{obs["sigDelay"]:^{widths["sigRA"]}.4f}')
f.write(f'{obs["sigDoppler"]:^{widths["sigDec"]}.4f}')
f.write(f'{obs["resDelay"]:^+{widths["resRA"]}.7f}')
f.write(f'{obs["resDoppler"]:^+{widths["resDec"]}.7f}')
else:
f.write(f'{obs["stn"]:^{widths["stn"]}}')
f.write(f'{obs["ra"]:^{widths["ra"]}}')
sign = "+" if obs["dec"] >= 0 else ""
f.write(f'{sign+str(obs["dec"]):^{widths["dec"]}}')
f.write(f'{obs["ra"]:^{widths["ra"]}.13g}')
f.write(f'{obs["dec"]:^+{widths["dec"]}.12g}')
f.write(f'{obs["sigRA"]:^{widths["sigRA"]}.4f}')
f.write(f'{obs["sigDec"]:^{widths["sigDec"]}.4f}')
f.write(f'{obs["resRA"]:^+{widths["resRA"]}.7f}')
Expand Down Expand Up @@ -1951,6 +1950,21 @@ def save(self, filename):
if itrn.iter_number != self.n_iter:
f.write(subsection_full + '\n')

mean_0 = np.array(list(self.x_init.values()))
cov_0 = self.covariance_init
mean_f = np.array(list(self.x_nom.values()))
cov_f = self.covariance
md_f, md_0, b_dist, b_coeff = get_similarity_stats(mean_0, cov_0, mean_f, cov_f)
f.write(f'Mahalonobis distance between initial and final solution: {md_f:0.2f}')
f.write("\n")
f.write(f'Mahalonobis distance between final and initial solution: {md_0:0.2f}')
f.write("\n")
f.write(f'Bhattacharya distance between initial and final solution: {b_dist:0.4f}')
f.write("\n")
f.write(f'Bhattacharya coefficient between initial and final solution: {b_coeff:0.4f}')
f.write("\n")
f.write(subsection_full + '\n')

f.write(section_full + '\n')
f.write(f"{header_section_half} END OF FILE {header_section_half}" + '\n')
f.write(section_full + '\n')
Expand Down
6 changes: 6 additions & 0 deletions grss/prop/prop_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ def cluster_ca_or_impacts(full_list, max_duration=45, central_body=399):
A tuple of close approach clusters (each cluster is a list of
close approaches).
"""
start_time = time.time()
all_clusters = []
full_list = [ca_or_impact for ca_or_impact in full_list
if ca_or_impact.centralBodySpiceId == central_body]
Expand All @@ -387,4 +388,9 @@ def cluster_ca_or_impacts(full_list, max_duration=45, central_body=399):
cluster.append(full_list[idx])
cluster_bodies.append(bodies[idx])
all_clusters.append(cluster)
end_time = time.time()
duration = end_time - start_time
mm = int(duration / 60)
ss = duration % 60
print(f'Clustering took {mm:02d} minute(s) and {ss:.6f} seconds')
return tuple(all_clusters)
9 changes: 7 additions & 2 deletions grss/prop/prop_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,13 @@ def plot_bplane(ca_list, plot_offset=False, scale_coords=False, n_std=3, units_k
mtp_y = np.array([approach.mtp.y*au2units for approach in ca_list])
mtp_nan = np.any(np.isnan(mtp_x)) or np.any(np.isnan(mtp_y))
focus_factor = np.nanmean([approach.gravFocusFactor for approach in ca_list])
impact_bool = np.array([approach.impact for approach in ca_list])
impact_any = np.any(impact_bool)
try:
lon = np.array([approach.lon for approach in ca_list])
lat = np.array([approach.lat for approach in ca_list])
except AttributeError:
lon = None
lat = None
impact_any = lon is not None and lat is not None
if len(ca_list) >= 100 or sigma_points is not None:
if not kizner_nan:
kizner_data = data_to_ellipse(kizner_x, kizner_y, n_std, 'kizner',
Expand Down
2 changes: 1 addition & 1 deletion grss/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0.1
4.0.2
12 changes: 9 additions & 3 deletions include/simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ struct NongravParameters {
* @brief Class for integrated bodies in a PropSimulation.
*
* @param spiceId SPICE ID of the body.
* @param logCA Flag to indicate if close approaches are logged (default: true).
* @param isCometary Flag to indicate if the body is initialized with a cometary state (as opposed to Cartesian state).
* @param initState Initial state of the body.
* @param isInteg Flag to indicate if the body is integrated.
Expand All @@ -188,6 +189,7 @@ class IntegBody : public Body {
private:
public:
int spiceId = -99999;
bool logCA = true;
bool isCometary = false;
std::vector<real> initState;
std::vector<real> initCart;
Expand Down Expand Up @@ -272,8 +274,10 @@ struct BPlaneParameters {
/**
* @brief Class for close approach parameters in a PropSimulation.
*
* @param t Time of the close approach.
* @param xRel Relative state at the close approach.
* @param t Time of the close approach or impact (from child class).
* @param xRel Relative state at the close approach or impact (from child class).
* @param tCA Time of the close approach.
* @param xRelCA Relative state at the close approach.
* @param tMap Time of the B-plane map.
* @param xRelMap Relative state at the B-plane map time.
* @param dist Distance at the close approach.
Expand Down Expand Up @@ -302,6 +306,8 @@ class CloseApproachParameters {
public:
real t;
std::vector<real> xRel;
real tCA;
std::vector<real> xRelCA;
real tMap;
std::vector<real> xRelMap;
real dist;
Expand Down Expand Up @@ -513,7 +519,7 @@ class PropSimulation {
std::vector<std::vector<real>> observerInfo =
std::vector<std::vector<real>>(),
bool adaptiveTimestep = true, real dt0 = 0.0L, real dtMax = 21.0L,
real dtMin = 5.0e-3L, real dtChangeFactor = 0.25L,
real dtMin = 1.0e-4L, real dtChangeFactor = 0.25L,
real tolInteg = 1.0e-11L, real tolPC = 1.0e-16L);
/**
* @brief Get the constants used in the simulation.
Expand Down
Loading

0 comments on commit e63ab24

Please sign in to comment.