Skip to content

Commit e99ff5a

Browse files
Merge pull request #83 from rahil-makadia/dev
update pip install pipeline; impact location comparison routines
2 parents d015b93 + e27f5db commit e99ff5a

File tree

13 files changed

+148
-94
lines changed

13 files changed

+148
-94
lines changed

.github/workflows/joss.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
uses: openjournals/openjournals-draft-action@master
1919
with:
2020
journal: joss
21-
paper-path: ./joss/joss_paper.md
21+
paper-path: ./joss/paper.md
2222
- name: Upload
2323
uses: actions/upload-artifact@master
2424
with:

.github/workflows/python_tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ jobs:
2323
python-version: 3.11
2424
- name: Install GRSS (including dependencies)
2525
run: |
26+
cd ./extern/
27+
python3 get_cspice.py
28+
cd ..
2629
python3 -m pip install --upgrade pip
2730
pip3 install "pybind11[global]>=2.10.0"
2831
pip3 install .

build_cpp.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#!/bin/bash
2+
# make error stop the script
3+
set -e
24

35
clean=0
46
docs=0

grss/prop/prop_utils.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'plot_ca_summary',
1313
'plot_bplane',
1414
'plot_earth_impact',
15+
'compare_earth_impact',
1516
]
1617

1718
earth_obliq = 84381.448/3600.0*np.pi/180.0
@@ -904,3 +905,95 @@ def plot_earth_impact(impact_list, print_ellipse_params=False, sigma_points=None
904905
y=0.93)
905906
plt.show()
906907
return None
908+
909+
def compare_earth_impact(coord1, coord2, sig1, sig2, labels, zoom_size=5.0e3, save_name=None):
910+
"""
911+
Show two impact circumstances and compare them.
912+
913+
Parameters
914+
----------
915+
coord1 : np.ndarray
916+
[time, lon, lat] of the first impact
917+
coord2 : np.ndarray
918+
[time, lon, lat] of the second impact
919+
sig1 : np.ndarray
920+
[time, lon, lat] uncertainty of the first impact
921+
sig2 : np.ndarray
922+
[time, lon, lat] uncertainty of the second impact
923+
labels : list
924+
List of labels for the two impacts
925+
zoom_size : float, optional
926+
Size of the zoomed in plot, in km, by default 5.0e3.
927+
save_name : str, optional
928+
Name to save the plots as, by default None.
929+
930+
Returns
931+
-------
932+
None : NoneType
933+
None
934+
"""
935+
_, lon1, lat1 = coord1
936+
_, lon2, lat2 = coord2
937+
fig, ax = plt.subplots(1, 3, figsize=(10, 4), dpi=150, gridspec_kw={'width_ratios': [4, 3, 1]})
938+
size = zoom_size*1e3
939+
m = Basemap(width=size,height=size,
940+
rsphere=(6378137.00,6356752.3142),
941+
resolution='i',area_thresh=size/100,projection='lcc',
942+
lat_0=lat1,lon_0=lon1,ax=ax[0])
943+
m.bluemarble()
944+
m.drawcountries()
945+
lat_step = lon_step = 3 if zoom_size <= 1e3 else 10
946+
if zoom_size <= 500:
947+
lat_step = lon_step = 1
948+
if zoom_size <= 100:
949+
lat_step = lon_step = 0.5
950+
if zoom_size > 5e3:
951+
lon_step = 20
952+
lat_step = 20
953+
# draw parallels and meridians.
954+
parallels = np.arange(-90, 91, lat_step)
955+
# labels = [left,right,top,bottom]
956+
m.drawparallels(parallels,labels=[True,False,False,False], color='gray')
957+
meridians = np.arange(0, 361, lon_step)
958+
m.drawmeridians(meridians,labels=[False,False,False,True], color='gray')
959+
x_lon1,y_lat1 = m(lon1,lat1)
960+
m.plot(x_lon1,y_lat1,'b.')
961+
x_lon2,y_lat2 = m(lon2,lat2)
962+
m.plot(x_lon2,y_lat2,'r.')
963+
# draw line between two points
964+
m.plot([x_lon1,x_lon2], [y_lat1,y_lat2], 'g--')
965+
966+
# plot error bars for grss solution, and plot GRSS solution
967+
n_sig = 1
968+
deg2m = np.pi/180*6378137.0
969+
sig1[1:] *= deg2m
970+
sig2[1:] *= deg2m
971+
diff = coord2 - coord1
972+
# diff[0] *= 86400*1e3
973+
diff[1:] *= deg2m
974+
diff[1] *= np.cos(lat1*np.pi/180)
975+
976+
# add two subplots
977+
ax[1].set_xlabel('Longitude Difference [m]')
978+
ax[1].set_ylabel('Latitude Difference [m]')
979+
ax[1].errorbar(0.0, 0.0, xerr=sig1[1]*n_sig, yerr=sig1[2]*n_sig,
980+
fmt='s', capsize=6, markeredgewidth=1.5, lw=1.5, label=labels[0])
981+
ax[1].errorbar(diff[1], diff[2], xerr=sig2[1]*n_sig, yerr=sig2[2]*n_sig,
982+
fmt='o', capsize=6, markeredgewidth=1.5, lw=1.5, label=labels[1])
983+
ax[1].legend(ncol=1)
984+
985+
ax[2].set_ylabel('Time Difference [ms]')
986+
ax[2].errorbar(0.0, 0.0, yerr=sig1[0]*n_sig,
987+
fmt='s', capsize=6, markeredgewidth=1.5, lw=1.5, label=labels[0])
988+
ax[2].errorbar(0.0, diff[0], yerr=sig2[0]*n_sig,
989+
fmt='o', capsize=6, markeredgewidth=1.5, lw=1.5, label=labels[1])
990+
ax[2].set_xticks([])
991+
ax[2].yaxis.tick_right()
992+
ax[2].yaxis.set_label_position('right')
993+
994+
fig.tight_layout()
995+
if save_name is not None:
996+
plt.savefig(save_name, bbox_inches='tight')
997+
plt.suptitle(f'Impact Circumstance Comparison ({n_sig}$\\sigma$)', y=1.05)
998+
plt.show()
999+
return None

grss/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.3.4
1+
4.3.5

include/simulation.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,6 @@ class ImpactParameters : public CloseApproachParameters {
388388
real lon;
389389
real lat;
390390
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());
393391
/**
394392
* @brief Get the impact parameters.
395393
*/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ @article{Makadia2024
2626
publisher = {The American Astronomical Society},
2727
}
2828

29+
@article{Makadia2024b,
30+
author = {Rahil Makadia and Davide Farnocchia and Steven R. Chesley and Siegfried Eggl},
31+
journal = {The Planetary Science Journal},
32+
title = {{Gauss-Radau Small-body Simulator (GRSS): An Open-Source Library for Planetary Defense}},
33+
year = {2024},
34+
volume = {Submitted},
35+
publisher = {The American Astronomical Society},
36+
}
37+
2938
@article{Rein2014,
3039
author = {Rein, Hanno and Spiegel, David S.},
3140
title = "{ias15: a fast, adaptive, high-order integrator for gravitational dynamics, accurate to machine precision over a billion orbits}",
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ authors:
1212
corresponding: true
1313
orcid: 0000-0001-9265-2230
1414
affiliation: 1
15-
- name: Steven R. Chesley
16-
orcid: 0000-0003-3240-6497
17-
affiliation: 2
1815
- name: Davide Farnocchia
1916
orcid: 0000-0003-0774-884X
2017
affiliation: 2
18+
- name: Steven R. Chesley
19+
orcid: 0000-0003-3240-6497
20+
affiliation: 2
2121
- name: Siegfried Eggl
2222
orcid: 0000-0002-1398-6302
2323
affiliation: 1
@@ -27,7 +27,7 @@ affiliations:
2727
- name: Jet Propulsion Laboratory, California Institute of Technology, Pasadena, CA 91109, USA
2828
index: 2
2929
date: XX August 2024
30-
bibliography: joss_paper.bib
30+
bibliography: paper.bib
3131
aas-doi: 10.3847/PSJ/xxxxx
3232
aas-journal: Planetary Science Journal
3333
---
@@ -40,7 +40,7 @@ Modeling the motion of small solar system bodies is of utmost importance when lo
4040

4141
In this paper, we present ``GRSS``, the Gauss-Radau Small-body Simulator, an open-source library for orbit determination and propagation of small bodies in the solar system. ``GRSS`` is an open-source software library with a C++11 foundation and a Python binding. The propagator is based on the ``IAS15`` algorithm, a 15<sup>th</sup> order integrator based on Gauss-Radau quadrature [@Rein2014]. Only the particles of interest are integrated within ``GRSS`` to reduce computational cost. The states for the planets and 16 largest main-belt asteroids are computed using memory-mapped JPL digital ephemeris kernels [@Park2021] as done in the ``ASSIST`` orbit propagator library [@Holman2023]. In addition to the propagator, the C++ portion of the library also has the ability to predict impacts and calculate close encounter circumstances using various formulations of the B-plane [@Kizner1961; @Opik1976; @Chodas1999; @Milani1999; @Farnocchia2019].
4242

43-
The C++ functionality is exposed to Python through a binding generated using ``pybind11``[^1]. The Python layer of ``GRSS`` uses the propagator as the foundation to compute the orbits of small bodies from a given set of optical and/or radar astrometry from the Minor Planet Center[^2], the JPL Small Body Radar Astrometry database[^3], and the Gaia Focused Product Release solar system observations database[^4]. Additionally, the orbit determination modules also have the ability to fit especially demanding measurements such as stellar occultations. These capabilities of the ``GRSS`` library have already been used to study the the heliocentric changes in the orbit of the (65803) Didymos binary asteroid system as a result of the DART impact [@Makadia2022; @Makadia2024].
43+
The C++ functionality is exposed to Python through a binding generated using ``pybind11``[^1]. The Python layer of ``GRSS`` uses the propagator as the foundation to compute the orbits of small bodies from a given set of optical and/or radar astrometry from the Minor Planet Center[^2], the JPL Small Body Radar Astrometry database[^3], and the Gaia Focused Product Release solar system observations database[^4]. Additionally, the orbit determination modules also have the ability to fit especially demanding measurements such as stellar occultations. These capabilities of the ``GRSS`` library have already been used to study the the heliocentric changes in the orbit of the (65803) Didymos binary asteroid system as a result of the DART impact [@Makadia2022; @Makadia2024] and for analyzing the impact locations of two asteroids, 2024 BX<sub>1</sub> and 2024 RW<sub>1</sub> [@Makadia2024b].
4444

4545
``GRSS`` will continue to be developed in the future, with anticipated contributions including the ability to perform mission studies for future asteroid deflections. ``GRSS`` is publicly available to the community through the Python Package Index and the source code is available on GitHub[^5]. Therefore, ``GRSS`` is a reliable and efficient tool that the community has access to for studying the dynamics of small bodies in the solar system.
4646

setup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,17 @@ class CMakeBuild(build_ext):
3131
"""
3232

3333
def build_extension(self, ext: CMakeExtension) -> None:
34-
subprocess.run(["./build_cpp.sh"], cwd=ext.sourcedir, check=True)
34+
result = subprocess.run(["./build_cpp.sh"], cwd=ext.sourcedir, check=True)
35+
# check return code of subprocess
36+
if result.returncode != 0:
37+
raise subprocess.CalledProcessError(returncode=result.returncode, cmd=result.args)
3538
binary_created = [f for f in os.listdir(f"{ext.sourcedir}/build/")
3639
if f.startswith("libgrss")]
3740
if not binary_created:
3841
raise FileNotFoundError("libgrss binary for C++ source code not found "
3942
"in cmake build directory")
4043
os.system(f"cp {ext.sourcedir}/build/libgrss.* {self.build_lib}/grss/")
41-
return
44+
return None
4245

4346
setup(
4447
ext_modules=[CMakeExtension("libgrss")],

src/approach.cpp

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -63,46 +63,6 @@ static void rec_to_geodetic(const real &x, const real &y, const real &z,
6363
}
6464
}
6565

66-
static void rec_to_geodetic_jac(const real &lon, const real &lat, const real &h,
67-
std::vector< std::vector<real> > &jac) {
68-
// calculate derivatives of geodetic coordinates with respect to the
69-
// rectangular coordinates by inversion of the derivatives of the
70-
// rectangular coordinates with respect to the geodetic coordinates
71-
const real a = EARTH_RAD_WGS84;
72-
const real slat = sin(lat);
73-
const real clat = cos(lat);
74-
const real slon = sin(lon);
75-
const real clon = cos(lon);
76-
const real flat = 1.0 - EARTH_FLAT_WGS84;
77-
const real flat2 = flat * flat;
78-
const real g = sqrt(clat*clat + flat2*slat*slat);
79-
const real g2 = g * g;
80-
const real dg_dlat = (-1.0 + flat2) * slat * clat / g;
81-
std::vector< std::vector<real> > jacInv = std::vector< std::vector<real> >(3, std::vector<real>(3, 0.0));
82-
// partials of rectangular coordinates w.r.t. geodetic longitude
83-
jacInv[0][0] = - (h + a/g) * slon * clat;
84-
jacInv[1][0] = (h + a/g) * clon * clat;
85-
jacInv[2][0] = 0.0;
86-
// partials of rectangular coordinates w.r.t. geodetic latitude
87-
jacInv[0][1] = (-a*dg_dlat/g2) * clon * clat - (h + a/g) * clon * slat;
88-
jacInv[1][1] = (-a*dg_dlat/g2) * slon * clat - (h + a/g) * slon * slat;
89-
jacInv[2][1] = (-flat2*a*dg_dlat/g2) * slat + (h + flat2*a/g) * clat;
90-
// partials of rectangular coordinates w.r.t. geodetic altitude
91-
jacInv[0][2] = clon * clat;
92-
jacInv[1][2] = slon * clat;
93-
jacInv[2][2] = slat;
94-
// invert the Jacobian
95-
std::vector< std::vector<real> > jacSmall = std::vector< std::vector<real> >(3, std::vector<real>(3, 0.0));
96-
mat3_inv(jacInv, jacSmall);
97-
// fill the full 2x6 Jacobian for just longitude and latitude
98-
jac.resize(2, std::vector<real>(6, 0.0));
99-
for (size_t i = 0; i < 2; i++) {
100-
for (size_t j = 0; j < 3; j++) {
101-
jac[i][j] = jacSmall[i][j];
102-
}
103-
}
104-
}
105-
10666
/**
10767
* @param[inout] propSim PropSimulation object for the integration.
10868
* @param[in] tOld Time at the previous integrator epoch.
@@ -1030,13 +990,11 @@ void ImpactParameters::get_impact_parameters(PropSimulation *propSim){
1030990
x = this->xRelBodyFixed[0];
1031991
y = this->xRelBodyFixed[1];
1032992
z = this->xRelBodyFixed[2];
1033-
std::vector<std::vector<real>> jac(2, std::vector<real>(6, 0.0));
1034993
if (this->centralBodySpiceId == 399){
1035994
rec_to_geodetic(x, y, z, lon, lat, alt);
1036-
rec_to_geodetic_jac(lon, lat, alt, jac);
1037995
} else {
1038996
const real dist = sqrt(x*x + y*y + z*z);
1039-
lat = atan2(z, sqrt(x*x + y*y));
997+
lat = asin(z/dist);
1040998
lon = atan2(y, x);
1041999
if (lon < 0.0) {
10421000
lon += 2 * PI;
@@ -1048,39 +1006,10 @@ void ImpactParameters::get_impact_parameters(PropSimulation *propSim){
10481006
centralBodyRadius = propSim->spiceBodies[this->centralBodyIdx - propSim->integParams.nInteg].radius;
10491007
}
10501008
alt = dist-centralBodyRadius;
1051-
// calculate derivatives of latitudinal coordinates with respect to the
1052-
// rectangular coordinates by inversion of the derivatives of the
1053-
// rectangular coordinates with respect to the latitudinal coordinates
1054-
std::vector<std::vector<real>> jacInv(3, std::vector<real>(3, 0.0));
1055-
// partials of rectangular coordinates with respect to longitude
1056-
jacInv[0][1] = -dist * sin(lon) * cos(lat);
1057-
jacInv[1][1] = dist * cos(lon) * cos(lat);
1058-
jacInv[2][1] = 0.0;
1059-
// partials of rectangular coordinates with respect to latitude
1060-
jacInv[0][2] = -dist * cos(lon) * sin(lat);
1061-
jacInv[1][2] = -dist * sin(lon) * sin(lat);
1062-
jacInv[2][2] = dist * cos(lat);
1063-
// partials of rectangular coordinates with respect to radius
1064-
jacInv[0][3] = cos(lon) * cos(lat);
1065-
jacInv[1][3] = sin(lon) * cos(lat);
1066-
jacInv[2][3] = sin(lat);
1067-
std::vector<std::vector<real>> jacSmall(3, std::vector<real>(3, 0.0));
1068-
mat3_inv(jacInv, jacSmall);
1069-
for (size_t k = 0; k < 2; k++) {
1070-
for (size_t k2 = 0; k2 < 3; k2++) {
1071-
jac[k][k2] = jacSmall[k][k2];
1072-
}
1073-
}
10741009
}
10751010
this->lon = lon;
10761011
this->lat = lat;
10771012
this->alt = alt;
1078-
std::vector<std::vector<real>> jac_inertial(2, std::vector<real>(6, 0.0));
1079-
mat_mat_mul(jac, rotMat, jac_inertial);
1080-
for (size_t k = 0; k < 6; k++) {
1081-
this->dlon[k] = jac_inertial[0][k];
1082-
this->dlat[k] = jac_inertial[1][k];
1083-
}
10841013
}
10851014

10861015
/**

0 commit comments

Comments
 (0)