grss 4.3.2__tar.gz → 4.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {grss-4.3.2/grss.egg-info → grss-4.3.4}/PKG-INFO +1 -1
  2. {grss-4.3.2 → grss-4.3.4}/grss/fit/fit_simulation.py +66 -61
  3. {grss-4.3.2 → grss-4.3.4}/grss/prop/prop_utils.py +25 -7
  4. {grss-4.3.2 → grss-4.3.4}/grss/utils.py +2 -2
  5. grss-4.3.4/grss/version.txt +1 -0
  6. {grss-4.3.2 → grss-4.3.4/grss.egg-info}/PKG-INFO +1 -1
  7. {grss-4.3.2 → grss-4.3.4}/include/approach.h +6 -0
  8. {grss-4.3.2 → grss-4.3.4}/include/grss.h +3 -1
  9. {grss-4.3.2 → grss-4.3.4}/include/simulation.h +25 -3
  10. {grss-4.3.2 → grss-4.3.4}/include/utilities.h +10 -0
  11. grss-4.3.4/src/approach.cpp +1097 -0
  12. {grss-4.3.2 → grss-4.3.4}/src/force.cpp +102 -0
  13. {grss-4.3.2 → grss-4.3.4}/src/grss.cpp +67 -5
  14. {grss-4.3.2 → grss-4.3.4}/src/interpolate.cpp +2 -2
  15. {grss-4.3.2 → grss-4.3.4}/src/pck.cpp +12 -1
  16. {grss-4.3.2 → grss-4.3.4}/src/simulation.cpp +37 -7
  17. grss-4.3.4/tests/python/fit/chesley.ipynb +275 -0
  18. {grss-4.3.2 → grss-4.3.4}/tests/python/fit/eggl.ipynb +17 -17
  19. grss-4.3.4/tests/python/fit/farnocchia.ipynb +275 -0
  20. grss-4.3.4/tests/python/fit/shantanunaidu.ipynb +277 -0
  21. grss-4.3.2/grss/version.txt +0 -1
  22. grss-4.3.2/src/approach.cpp +0 -984
  23. grss-4.3.2/tests/python/fit/chesley.ipynb +0 -275
  24. grss-4.3.2/tests/python/fit/farnocchia.ipynb +0 -281
  25. grss-4.3.2/tests/python/fit/shantanunaidu.ipynb +0 -277
  26. {grss-4.3.2 → grss-4.3.4}/CMakeLists.txt +0 -0
  27. {grss-4.3.2 → grss-4.3.4}/LICENSE +0 -0
  28. {grss-4.3.2 → grss-4.3.4}/MANIFEST.in +0 -0
  29. {grss-4.3.2 → grss-4.3.4}/README.md +0 -0
  30. {grss-4.3.2 → grss-4.3.4}/build_cpp.sh +0 -0
  31. {grss-4.3.2 → grss-4.3.4}/docs/source/conf.py +0 -0
  32. {grss-4.3.2 → grss-4.3.4}/extern/get_cspice.py +0 -0
  33. {grss-4.3.2 → grss-4.3.4}/grss/__init__.py +0 -0
  34. {grss-4.3.2 → grss-4.3.4}/grss/debias/get_debiasing_data.py +0 -0
  35. {grss-4.3.2 → grss-4.3.4}/grss/fit/__init__.py +0 -0
  36. {grss-4.3.2 → grss-4.3.4}/grss/fit/fit_ades.py +0 -0
  37. {grss-4.3.2 → grss-4.3.4}/grss/fit/fit_optical.py +0 -0
  38. {grss-4.3.2 → grss-4.3.4}/grss/fit/fit_radar.py +0 -0
  39. {grss-4.3.2 → grss-4.3.4}/grss/fit/fit_utils.py +0 -0
  40. {grss-4.3.2 → grss-4.3.4}/grss/kernels/get_kernels.py +0 -0
  41. {grss-4.3.2 → grss-4.3.4}/grss/prop/__init__.py +0 -0
  42. {grss-4.3.2 → grss-4.3.4}/grss/prop/prop_parallel.py +0 -0
  43. {grss-4.3.2 → grss-4.3.4}/grss/prop/prop_unscented.py +0 -0
  44. {grss-4.3.2 → grss-4.3.4}/grss.egg-info/SOURCES.txt +0 -0
  45. {grss-4.3.2 → grss-4.3.4}/grss.egg-info/dependency_links.txt +0 -0
  46. {grss-4.3.2 → grss-4.3.4}/grss.egg-info/requires.txt +0 -0
  47. {grss-4.3.2 → grss-4.3.4}/grss.egg-info/top_level.txt +0 -0
  48. {grss-4.3.2 → grss-4.3.4}/include/elements.h +0 -0
  49. {grss-4.3.2 → grss-4.3.4}/include/force.h +0 -0
  50. {grss-4.3.2 → grss-4.3.4}/include/gr15.h +0 -0
  51. {grss-4.3.2 → grss-4.3.4}/include/interpolate.h +0 -0
  52. {grss-4.3.2 → grss-4.3.4}/include/observe.h +0 -0
  53. {grss-4.3.2 → grss-4.3.4}/include/parallel.h +0 -0
  54. {grss-4.3.2 → grss-4.3.4}/include/pck.h +0 -0
  55. {grss-4.3.2 → grss-4.3.4}/include/spk.h +0 -0
  56. {grss-4.3.2 → grss-4.3.4}/include/stm.h +0 -0
  57. {grss-4.3.2 → grss-4.3.4}/include/timeconvert.h +0 -0
  58. {grss-4.3.2 → grss-4.3.4}/pyproject.toml +0 -0
  59. {grss-4.3.2 → grss-4.3.4}/requirements.txt +0 -0
  60. {grss-4.3.2 → grss-4.3.4}/setup.cfg +0 -0
  61. {grss-4.3.2 → grss-4.3.4}/setup.py +0 -0
  62. {grss-4.3.2 → grss-4.3.4}/src/CMakeLists.txt +0 -0
  63. {grss-4.3.2 → grss-4.3.4}/src/elements.cpp +0 -0
  64. {grss-4.3.2 → grss-4.3.4}/src/gr15.cpp +0 -0
  65. {grss-4.3.2 → grss-4.3.4}/src/observe.cpp +0 -0
  66. {grss-4.3.2 → grss-4.3.4}/src/parallel.cpp +0 -0
  67. {grss-4.3.2 → grss-4.3.4}/src/spk.cpp +0 -0
  68. {grss-4.3.2 → grss-4.3.4}/src/stm.cpp +0 -0
  69. {grss-4.3.2 → grss-4.3.4}/src/timeconvert.cpp +0 -0
  70. {grss-4.3.2 → grss-4.3.4}/src/utilities.cpp +0 -0
  71. {grss-4.3.2 → grss-4.3.4}/tests/cpp/prop/CMakeLists.txt +0 -0
  72. {grss-4.3.2 → grss-4.3.4}/tests/cpp/prop/apophis.cpp +0 -0
  73. {grss-4.3.2 → grss-4.3.4}/tests/cpp/prop/didymos.cpp +0 -0
  74. {grss-4.3.2 → grss-4.3.4}/tests/cpp/prop/pck_map.cpp +0 -0
  75. {grss-4.3.2 → grss-4.3.4}/tests/cpp/prop/spk_map.cpp +0 -0
  76. {grss-4.3.2 → grss-4.3.4}/tests/python/prop/apophis.ipynb +0 -0
  77. {grss-4.3.2 → grss-4.3.4}/tests/python/prop/didymos.ipynb +0 -0
  78. {grss-4.3.2 → grss-4.3.4}/tests/python/prop/icarus.ipynb +0 -0
  79. {grss-4.3.2 → grss-4.3.4}/tests/python/prop/moshup.ipynb +0 -0
  80. {grss-4.3.2 → grss-4.3.4}/tests/python/run_tests.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: grss
3
- Version: 4.3.2
3
+ Version: 4.3.4
4
4
  Summary: GRSS: Gauss-Radau Small-body Simulator
5
5
  Author: Rahil Makadia
6
6
  Author-email: makadia2@illinois.edu
@@ -3,6 +3,7 @@
3
3
  import sys
4
4
  import datetime
5
5
  import numpy as np
6
+ import pandas as pd
6
7
  import matplotlib.pyplot as plt
7
8
  from astropy.time import Time
8
9
 
@@ -562,7 +563,7 @@ class FitSimulation:
562
563
  self.fixed_propsim_params[key] = nongrav_info[key]
563
564
  self.fixed_propsim_params['events'] = events if events is not None else []
564
565
  self.prior_est = None
565
- self.prior_sigs = None
566
+ self.prior_sig = None
566
567
  self._priors_given = False
567
568
  self._xbar0 = None
568
569
  self._info0 = None
@@ -574,6 +575,7 @@ class FitSimulation:
574
575
  num_auto_rejected = np.sum(sel_ast == 'D')
575
576
  num_force_rejected = np.sum(sel_ast == 'd')
576
577
  self.num_rejected = num_auto_rejected + num_force_rejected
578
+ self.info_mats = []
577
579
  self.converged = False
578
580
  return None
579
581
 
@@ -642,10 +644,10 @@ class FitSimulation:
642
644
  ValueError
643
645
  If the prior estimates and sigmas do not have the same length.
644
646
  """
645
- # check that the keys in self.x_init are the same as in self.prior_est and self.prior_sigs
646
- if self.prior_est is not None and self.prior_sigs is not None:
647
+ # check that the keys in self.x_init are the same as in self.prior_est and self.prior_sig
648
+ if self.prior_est is not None and self.prior_sig is not None:
647
649
  self._priors_given = True
648
- if len(self.prior_est) != len(self.prior_sigs):
650
+ if len(self.prior_est) != len(self.prior_sig):
649
651
  raise ValueError("Prior estimates and sigmas must have the same length.")
650
652
  for key in self.prior_est.keys():
651
653
  if key not in self.x_init:
@@ -654,7 +656,7 @@ class FitSimulation:
654
656
  self._xbar0 = np.zeros(self.n_fit)
655
657
  for key in self.prior_est.keys():
656
658
  idx = list(self.x_init.keys()).index(key)
657
- self._info0[idx, idx] = 1/self.prior_sigs[key]**2
659
+ self._info0[idx, idx] = 1/self.prior_sig[key]**2
658
660
  self._xbar0[idx] = self.prior_est[key] - self.x_init[key]
659
661
  self._prior_constant = list(self.x_nom.values())+self._xbar0
660
662
  return None
@@ -693,56 +695,60 @@ class FitSimulation:
693
695
  raise ValueError("Simulated observation data must have the same length.")
694
696
  perm_id = self.obs['permID'][0]
695
697
  prov_id = self.obs['provID'][0]
698
+ new_sim_obs = []
696
699
  for i, time in enumerate(times):
697
- idx = len(self.obs)
700
+ this_obs = {}
698
701
  mode = modes[i]
699
702
  if mode not in {'SIM_CCD', 'SIM_OCC', 'SIM_RAD_DEL', 'SIM_RAD_DOP'}:
700
703
  raise ValueError(f"Unknown simulated observation mode {mode}.")
701
704
  weight = weights[i]
702
705
  if isinstance(perm_id, str):
703
- self.obs.loc[idx, 'permID'] = f'SIM_{perm_id}'
706
+ this_obs['permID'] = f'SIM_{perm_id}'
704
707
  if isinstance(prov_id, str):
705
- self.obs.loc[idx, 'provID'] = f'SIM_{prov_id}'
706
- self.obs.loc[idx, 'obsTime'] = f'{time.utc.isot}Z'
707
- self.obs.loc[idx, 'obsTimeMJD'] = time.utc.mjd
708
- self.obs.loc[idx, 'obsTimeMJDTDB'] = time.tdb.mjd
709
- self.obs.loc[idx, 'mode'] = mode
708
+ this_obs['provID'] = f'SIM_{prov_id}'
709
+ this_obs['obsTime'] = f'{time.utc.isot}Z'
710
+ this_obs['obsTimeMJD'] = time.utc.mjd
711
+ this_obs['obsTimeMJDTDB'] = time.tdb.mjd
712
+ this_obs['mode'] = mode
710
713
  if mode in {'SIM_CCD', 'SIM_OCC'}:
711
- self.obs.loc[idx, 'stn'] = 'SIM'
712
- self.obs.loc[idx, 'ra'] = np.nan
713
- self.obs.loc[idx, 'rmsRA'] = weight[0]
714
- self.obs.loc[idx, 'sigRA'] = weight[0]
715
- self.obs.loc[idx, 'dec'] = np.nan
716
- self.obs.loc[idx, 'rmsDec'] = weight[1]
717
- self.obs.loc[idx, 'sigDec'] = weight[1]
718
- self.obs.loc[idx, 'rmsCorr'] = weight[2]
719
- self.obs.loc[idx, 'sigCorr'] = weight[2]
720
- self.obs.loc[idx, 'cosDec'] = 1.0
714
+ this_obs['stn'] = 'SIM'
715
+ this_obs['ra'] = np.nan
716
+ this_obs['rmsRA'] = weight[0]
717
+ this_obs['sigRA'] = weight[0]
718
+ this_obs['dec'] = np.nan
719
+ this_obs['rmsDec'] = weight[1]
720
+ this_obs['sigDec'] = weight[1]
721
+ this_obs['rmsCorr'] = weight[2]
722
+ this_obs['sigCorr'] = weight[2]
723
+ this_obs['cosDec'] = 1.0
721
724
  elif mode in {'SIM_RAD_DEL', 'SIM_RAD_DOP'}:
722
- self.obs.loc[idx, 'trx'] = 'SIM'
723
- self.obs.loc[idx, 'rcv'] = 'SIM'
724
- self.obs.loc[idx, 'com'] = 1
725
+ this_obs['trx'] = 'SIM'
726
+ this_obs['rcv'] = 'SIM'
727
+ this_obs['com'] = 1
725
728
  if mode == 'SIM_RAD_DEL':
726
- self.obs.loc[idx, 'delay'] = np.nan
727
- self.obs.loc[idx, 'rmsDelay'] = weight[0]
728
- self.obs.loc[idx, 'sigDelay'] = weight[0]
729
- self.obs.loc[idx, 'doppler'] = np.nan
730
- self.obs.loc[idx, 'rmsDoppler'] = np.nan
731
- self.obs.loc[idx, 'sigDoppler'] = np.nan
729
+ this_obs['delay'] = np.nan
730
+ this_obs['rmsDelay'] = weight[0]
731
+ this_obs['sigDelay'] = weight[0]
732
+ this_obs['doppler'] = np.nan
733
+ this_obs['rmsDoppler'] = np.nan
734
+ this_obs['sigDoppler'] = np.nan
732
735
  else:
733
- self.obs.loc[idx, 'delay'] = np.nan
734
- self.obs.loc[idx, 'rmsDelay'] = np.nan
735
- self.obs.loc[idx, 'sigDelay'] = np.nan
736
- self.obs.loc[idx, 'doppler'] = np.nan
737
- self.obs.loc[idx, 'rmsDoppler'] = weight[0]
738
- self.obs.loc[idx, 'sigDoppler'] = weight[0]
739
- self.obs.loc[idx, 'frq'] = 8560.0
740
- self.obs.loc[idx, 'ctr'] = 399
741
- self.obs.loc[idx, 'sys'] = 'ITRF'
742
- self.obs.loc[idx, 'pos1'] = 0.0
743
- self.obs.loc[idx, 'pos2'] = 0.0
744
- self.obs.loc[idx, 'pos3'] = 0.0
745
- self.obs.loc[idx, 'selAst'] = 'a'
736
+ this_obs['delay'] = np.nan
737
+ this_obs['rmsDelay'] = np.nan
738
+ this_obs['sigDelay'] = np.nan
739
+ this_obs['doppler'] = np.nan
740
+ this_obs['rmsDoppler'] = weight[0]
741
+ this_obs['sigDoppler'] = weight[0]
742
+ this_obs['frq'] = 8560.0
743
+ this_obs['ctr'] = 399
744
+ this_obs['sys'] = 'ITRF'
745
+ this_obs['pos1'] = 0.0
746
+ this_obs['pos2'] = 0.0
747
+ this_obs['pos3'] = 0.0
748
+ this_obs['selAst'] = 'a'
749
+ new_sim_obs.append(this_obs)
750
+ sim_obs_df = pd.DataFrame(new_sim_obs)
751
+ self.obs = pd.concat([self.obs, sim_obs_df], ignore_index=True)
746
752
  return None
747
753
 
748
754
  def _parse_observation_arrays(self, obs_df):
@@ -1635,33 +1641,29 @@ class FitSimulation:
1635
1641
  raise ValueError("Observer info length not recognized.")
1636
1642
  resid = residuals[i]
1637
1643
  # calculate chi-squared for each residual if after the first iteration
1638
- if self.n_iter > 1:
1644
+ if start_rejecting and size == 2:
1639
1645
  obs_cov = self.obs_cov[i]
1640
1646
  obs_partials = partials[j:j+size, :]
1641
1647
  if sel_ast[i] in {'D', 'd'}:
1642
1648
  resid_cov = obs_cov + obs_partials @ full_cov @ obs_partials.T
1643
1649
  else:
1644
1650
  resid_cov = obs_cov - obs_partials @ full_cov @ obs_partials.T
1645
- if size == 1:
1646
- resid_cov_inv = 1.0/resid_cov
1647
- else:
1648
- resid_cov_det = resid_cov[0,0]*resid_cov[1,1] - resid_cov[0,1]*resid_cov[1,0]
1649
- resid_cov_inv = np.array([[resid_cov[1,1], -resid_cov[0,1]],
1650
- [-resid_cov[1,0], resid_cov[0,0]]])/resid_cov_det
1651
- residual_chi_squared = resid @ resid_cov_inv @ resid.T
1652
- res_chisq_vals[i] = residual_chi_squared
1653
- # outlier rejection, only reject RA/Dec measurements
1654
- if start_rejecting and size == 2:
1655
- if abs(residual_chi_squared) > chi_reject**2 and sel_ast[i] not in {'a', 'd'}:
1651
+ resid_cov_det = resid_cov[0,0]*resid_cov[1,1] - resid_cov[0,1]*resid_cov[1,0]
1652
+ resid_cov_inv = np.array([[resid_cov[1,1], -resid_cov[0,1]],
1653
+ [-resid_cov[1,0], resid_cov[0,0]]])/resid_cov_det
1654
+ outlier_chisq = resid @ resid_cov_inv @ resid.T
1655
+ # outlier rejection, only reject RA/Dec measurements
1656
+ if abs(outlier_chisq) > chi_reject**2 and sel_ast[i] not in {'a', 'd'}:
1656
1657
  if sel_ast[i] == 'A':
1657
1658
  self.num_rejected += 1
1658
1659
  sel_ast[i] = 'D'
1659
- elif abs(residual_chi_squared) < chi_recover**2 and sel_ast[i] == 'D':
1660
+ elif abs(outlier_chisq) < chi_recover**2 and sel_ast[i] == 'D':
1660
1661
  sel_ast[i] = 'A'
1661
1662
  self.num_rejected -= 1
1663
+ res_chisq_vals[i] = resid @ self.obs_weight[i] @ resid.T
1662
1664
  if sel_ast[i] not in {'D', 'd'}:
1663
1665
  rms_u += resid @ resid.T
1664
- chi_sq += resid @ self.obs_weight[i] @ resid.T
1666
+ chi_sq += res_chisq_vals[i]
1665
1667
  j += size
1666
1668
  # # write res_chisq_vals to file if any values are negative
1667
1669
  # if np.any(res_chisq_vals < 0):
@@ -1759,6 +1761,7 @@ class FitSimulation:
1759
1761
  atwb = np.zeros(self.n_fit)
1760
1762
  j = 0
1761
1763
  sel_ast = self.obs['selAst'].values
1764
+ self.info_mats = []
1762
1765
  for i, obs_info_len in enumerate(self.observer_info_lengths):
1763
1766
  if obs_info_len in {4, 7}:
1764
1767
  size = 2
@@ -1768,10 +1771,12 @@ class FitSimulation:
1768
1771
  raise ValueError("Observer info length not recognized.")
1769
1772
  if sel_ast[i] in {'D', 'd'}:
1770
1773
  j += size
1774
+ self.info_mats.append(atwa.copy())
1771
1775
  continue
1772
1776
  atwa += partials[j:j+size, :].T @ self.obs_weight[i] @ partials[j:j+size, :]
1773
1777
  atwb += partials[j:j+size, :].T @ self.obs_weight[i] @ residuals[i]
1774
1778
  j += size
1779
+ self.info_mats.append(atwa.copy())
1775
1780
  # use pseudo-inverse if the data arc is less than 7 days
1776
1781
  if self.obs.obsTimeMJD.max() - self.obs.obsTimeMJD.min() < 7.0:
1777
1782
  self.covariance = np.linalg.pinv(atwa, rcond=1e-20, hermitian=True)
@@ -2074,7 +2079,7 @@ class FitSimulation:
2074
2079
  f.write(f" {units_dict[key[:2]]}")
2075
2080
  if self._priors_given and key in self.prior_est:
2076
2081
  p_val = self.prior_est[key]
2077
- p_sig = self.prior_sigs[key]
2082
+ p_sig = self.prior_sig[key]
2078
2083
  if key in ['om', 'w', 'i']:
2079
2084
  p_val *= 180/np.pi
2080
2085
  p_sig *= 180/np.pi
@@ -2114,7 +2119,7 @@ class FitSimulation:
2114
2119
  f.write(f" {units_dict[key[:2]]}")
2115
2120
  if self._priors_given and key in self.prior_est:
2116
2121
  p_val = self.prior_est[key]
2117
- p_sig = self.prior_sigs[key]
2122
+ p_sig = self.prior_sig[key]
2118
2123
  if key in ['om', 'w', 'i']:
2119
2124
  p_val *= 180/np.pi
2120
2125
  p_sig *= 180/np.pi
@@ -2211,7 +2216,7 @@ class FitSimulation:
2211
2216
  f.write(f'{final_val:18.11e}{half_tab}')
2212
2217
  f.write(f'{final_unc:18.11e}{half_tab}')
2213
2218
  f.write(f'{final_val-init_val:+18.11e}{half_tab}')
2214
- f.write(f'{(final_val-init_val)/init_unc:+10.3f}\n')
2219
+ f.write(f'{(final_val-init_val)/final_unc:+10.3f}\n')
2215
2220
  f.write("\n")
2216
2221
  if itrn.iter_number <= self.n_iter:
2217
2222
  f.write(subsection_full + '\n')
@@ -536,27 +536,48 @@ def plot_bplane(ca_list, plot_offset=False, scale_coords=False, n_std=3, units_k
536
536
  lon = None
537
537
  lat = None
538
538
  impact_any = lon is not None and lat is not None
539
+ if kizner_nan and opik_nan and scaled_nan and not mtp_nan:
540
+ print("WARNING: Close approaches have some invalid B-planes but do have MTP. "
541
+ "Object might be captured.")
539
542
  if len(ca_list) >= 100 or sigma_points is not None:
543
+ # remove nans before converting data to ellipse
540
544
  if not kizner_nan:
541
545
  kizner_data = data_to_ellipse(kizner_x, kizner_y, n_std, 'kizner',
542
546
  print_ellipse_params, units, sigma_points)
543
547
  else:
544
- kizner_data = None
548
+ print(f"Kizner B-plane nan count: {np.sum(np.isnan(kizner_x))}")
549
+ non_nan_idx = np.where(~np.isnan(kizner_x) & ~np.isnan(kizner_y))[0]
550
+ kizner_data = data_to_ellipse(kizner_x[non_nan_idx], kizner_y[non_nan_idx],
551
+ n_std, 'kizner',
552
+ print_ellipse_params, units, sigma_points)
545
553
  if not opik_nan:
546
554
  opik_data = data_to_ellipse(opik_x, opik_y, n_std, 'opik',
547
555
  print_ellipse_params, units, sigma_points)
548
556
  else:
549
- opik_data = None
557
+ print(f"Opik B-plane nan count: {np.sum(np.isnan(opik_x))}")
558
+ non_nan_idx = np.where(~np.isnan(opik_x) & ~np.isnan(opik_y))[0]
559
+ opik_data = data_to_ellipse(opik_x[non_nan_idx], opik_y[non_nan_idx],
560
+ n_std, 'opik',
561
+ print_ellipse_params, units, sigma_points)
550
562
  if not scaled_nan:
551
563
  scaled_data = data_to_ellipse(scaled_x, scaled_y, n_std, 'scaled',
552
564
  print_ellipse_params, units, sigma_points)
553
565
  else:
554
- scaled_data = None
566
+ print(f"Scaled B-plane nan count: {np.sum(np.isnan(scaled_x))}")
567
+ non_nan_idx = np.where(~np.isnan(scaled_x) & ~np.isnan(scaled_y))[0]
568
+ scaled_data = data_to_ellipse(scaled_x[non_nan_idx], scaled_y[non_nan_idx],
569
+ n_std, 'scaled',
570
+ print_ellipse_params, units, sigma_points)
555
571
  if not mtp_nan:
556
572
  mtp_data = data_to_ellipse(mtp_x, mtp_y, n_std, 'mtp',
557
573
  print_ellipse_params, units, sigma_points)
558
574
  else:
559
- mtp_data = None
575
+ print(f"MTP B-plane nan count: {np.sum(np.isnan(mtp_x))}")
576
+ non_nan_idx = np.where(~np.isnan(mtp_x) & ~np.isnan(mtp_y))[0]
577
+ mtp_data = data_to_ellipse(mtp_x[non_nan_idx], mtp_y[non_nan_idx],
578
+ n_std, 'mtp',
579
+ print_ellipse_params, units, sigma_points)
580
+
560
581
  elif len(ca_list[0].xRel) >= 42 and analytic_info is not None:
561
582
  all_data = partials_to_ellipse(ca_list[0], au2units, n_std,
562
583
  print_ellipse_params, units, analytic_info)
@@ -566,9 +587,6 @@ def plot_bplane(ca_list, plot_offset=False, scale_coords=False, n_std=3, units_k
566
587
  opik_data = None
567
588
  scaled_data = None
568
589
  mtp_data = None
569
- if kizner_nan and opik_nan and scaled_nan and not mtp_nan:
570
- print("WARNING: Close approaches have no valid B-planes but do have MTP. "
571
- "Object might be captured.")
572
590
  fig, axes = plt.subplots(2, 2, figsize=(9, 9), dpi=250)
573
591
  plot_single_bplane(axes[0,0], kizner_x, kizner_y, kizner_data, 'kizner',
574
592
  focus_factor, show_central_body, plot_offset, scale_coords,
@@ -12,11 +12,11 @@ __all__ = [ 'default_kernel_path',
12
12
  grss_path = os.path.dirname(os.path.abspath(__file__))
13
13
  default_kernel_path = f'{grss_path}/kernels/'
14
14
 
15
- def _connected_to_internet(url='http://www.google.com/', timeout=5):
15
+ def _connected_to_internet(url='http://www.google.com/', timeout=30):
16
16
  try:
17
17
  _ = requests.head(url, timeout=timeout)
18
18
  return True
19
- except requests.ConnectionError:
19
+ except (requests.ConnectionError, requests.Timeout):
20
20
  print("No internet connection available.")
21
21
  return False
22
22
 
@@ -0,0 +1 @@
1
+ 4.3.4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: grss
3
- Version: 4.3.2
3
+ Version: 4.3.4
4
4
  Summary: GRSS: Gauss-Radau Small-body Simulator
5
5
  Author: Rahil Makadia
6
6
  Author-email: makadia2@illinois.edu
@@ -28,6 +28,12 @@ void impact_r_calc(PropSimulation *propSim, const size_t &i, const size_t &j,
28
28
  std::vector<real> get_rel_state(PropSimulation *propSim, const size_t &i,
29
29
  const size_t &j, const real &t);
30
30
 
31
+ /**
32
+ * @brief Compute partials of B-plane parameters.
33
+ */
34
+ void get_bplane_partials(PropSimulation *propSim, CloseApproachParameters *ca,
35
+ const real &mu, const real &radius);
36
+
31
37
  /**
32
38
  * @brief Compute the time of close approach or impact using Brent's method
33
39
  * for root finding in a bracketed interval.
@@ -16,7 +16,9 @@ void PropSimulation::integrate() {
16
16
  this->map_ephemeris();
17
17
  this->preprocess();
18
18
  gr15(this);
19
- this->unmap_ephemeris();
19
+ if (!this->unsafePersistentMemoryMap) {
20
+ this->unmap_ephemeris();
21
+ }
20
22
 
21
23
  // flip vectors if integration is backwards in time
22
24
  if (this->integParams.t0 > this->integParams.tf) {
@@ -109,11 +109,17 @@ class Body {
109
109
  real J2 = 0.0L;
110
110
  real poleRA = 0.0L;
111
111
  real poleDec = 90.0L;
112
+ size_t nZon = 0;
113
+ size_t nTes = 0;
114
+ std::vector<real> J = {};
115
+ std::vector<std::vector<real>> C = {};
116
+ std::vector<std::vector<real>> S = {};
112
117
  std::string name;
113
118
  int spiceId;
114
119
  real pos[3], vel[3], acc[3];
115
120
  bool isPPN = false;
116
121
  bool isJ2 = false;
122
+ bool isHarmonic = false;
117
123
  bool isNongrav = false;
118
124
  bool isMajor = false;
119
125
  real caTol = 0.1;
@@ -121,6 +127,12 @@ class Body {
121
127
  * @brief Set the J2 for the body.
122
128
  */
123
129
  void set_J2(real J2, real poleRA, real poleDec);
130
+ /**
131
+ * @brief Set the harmonic coefficients for the body.
132
+ */
133
+ void set_harmonics(real poleRA, real poleDec, int nZon, int nTes,
134
+ std::vector<real> J, std::vector<std::vector<real>> C,
135
+ std::vector<std::vector<real>> S);
124
136
  };
125
137
 
126
138
  /**
@@ -376,6 +388,8 @@ class ImpactParameters : public CloseApproachParameters {
376
388
  real lon;
377
389
  real lat;
378
390
  real alt;
391
+ std::vector<real> dlon = std::vector<real>(6, std::numeric_limits<real>::quiet_NaN());
392
+ std::vector<real> dlat = std::vector<real>(6, std::numeric_limits<real>::quiet_NaN());
379
393
  /**
380
394
  * @brief Get the impact parameters.
381
395
  */
@@ -389,12 +403,19 @@ class ImpactParameters : public CloseApproachParameters {
389
403
  /**
390
404
  * @brief Structure to hold interpolation parameters for a PropSimulation.
391
405
  *
406
+ * @param interpIdx Index of the interpolation parameters.
407
+ * @param t0 Initial time of the interpolation window.
408
+ * @param dt0 Timespan of the interpolation window.
409
+ * @param b0 Interpolation coefficients for the interpolation window.
410
+ * @param xInteg0 States at the initial time of the interpolation window.
411
+ * @param accInteg0 Accelerations at the initial time of the interpolation window.
392
412
  * @param tStack Stack of integrator epochs.
393
413
  * @param xIntegStack Stack of states at integrator epochs.
394
414
  * @param bStack Stack of interpolation coefficients at integrator epochs.
395
415
  * @param accIntegStack Stack of accelerations at integrator epochs.
396
416
  */
397
417
  struct InterpolationParameters {
418
+ size_t interpIdx = 0;
398
419
  real t0;
399
420
  real dt0;
400
421
  std::vector<real> b0;
@@ -411,7 +432,9 @@ struct InterpolationParameters {
411
432
  *
412
433
  * @param name Name of the simulation.
413
434
  * @param DEkernelPath Path to DE kernels.
414
- * @param ephem Ephemeris object for the simulation.
435
+ * @param spkEphem SPK ephemeris object for the simulation.
436
+ * @param pckEphem PCK ephemeris object for the simulation.
437
+ * @param unsafePersistentMemoryMap Flag to indicate if ephemeris memory maps should not be unmapped (unsafe, default: false).
415
438
  * @param consts Constants object for the simulation.
416
439
  * @param integParams Integration parameters for the simulation.
417
440
  * @param spiceBodies Vector of SpiceBody objects in the simulation.
@@ -423,7 +446,6 @@ struct InterpolationParameters {
423
446
  * @param t Current time of the simulation.
424
447
  * @param xInteg Current state of the simulation.
425
448
  * @param interpParams Interpolation parameters for the simulation.
426
- * @param interpIdx Index of the interpolation parameters.
427
449
  * @param tEvalUTC Flag to indicate if the evaluation times are in UTC.
428
450
  * @param evalApparentState Flag to indicate if the apparent state is evaluated.
429
451
  * @param evalMeasurements Flag to indicate if measurements are evaluated.
@@ -459,6 +481,7 @@ class PropSimulation {
459
481
  std::string DEkernelPath;
460
482
  SpkEphemeris spkEphem;
461
483
  PckEphemeris pckEphem;
484
+ bool unsafePersistentMemoryMap = false;
462
485
  /**
463
486
  * @brief Construct a new PropSimulation object.
464
487
  */
@@ -490,7 +513,6 @@ class PropSimulation {
490
513
  real t;
491
514
  std::vector<real> xInteg;
492
515
  InterpolationParameters interpParams;
493
- size_t interpIdx = 0;
494
516
  bool tEvalUTC = false;
495
517
  bool evalApparentState = false;
496
518
  bool evalMeasurements = false;
@@ -63,6 +63,16 @@ using std::tanh;
63
63
  *
64
64
  */
65
65
  #define EARTH_OBLIQUITY 84381.448 / 3600.0 * DEG2RAD
66
+ /**
67
+ * @brief Value of Earth's WGS84 radius in AU.
68
+ *
69
+ */
70
+ #define EARTH_RAD_WGS84 6378.137 / 1.495978707e8
71
+ /**
72
+ * @brief Value of Earth's WGS84 flattening.
73
+ *
74
+ */
75
+ #define EARTH_FLAT_WGS84 1.0 / 298.257223563
66
76
 
67
77
  /**
68
78
  * @brief Wrap an angle to the range [0, 2*pi).