|
1 | 1 | import unittest |
| 2 | +import importlib |
| 3 | +from types import SimpleNamespace |
| 4 | +from unittest.mock import patch |
2 | 5 |
|
3 | 6 | import dsgp4 |
| 7 | +import dsgp4.deep_space as deep_space |
4 | 8 | import numpy as np |
5 | 9 | import sgp4.earth_gravity |
6 | 10 | import sgp4.io |
7 | 11 | import sgp4.propagation |
8 | 12 | import torch |
9 | 13 |
|
10 | 14 |
|
| 15 | +dsgp4_sgp4_module = importlib.import_module("dsgp4.sgp4") |
| 16 | + |
| 17 | + |
11 | 18 | DEEP_SPACE_TLES = [ |
12 | 19 | ( |
13 | 20 | "1 14128U 83058A 06176.02844893 -.00000158 00000-0 10000-3 0 9627", |
@@ -68,5 +75,240 @@ def test_mixed_batch_matches_reference(self): |
68 | 75 | self.assertTrue(np.allclose(out, ref, atol=1e-8, rtol=0.0)) |
69 | 76 |
|
70 | 77 |
|
| 78 | +class DeepSpaceCoverageBranchesTestCase(unittest.TestCase): |
| 79 | + @staticmethod |
| 80 | + def _tensor(v): |
| 81 | + return torch.tensor(float(v)) |
| 82 | + |
| 83 | + def _make_dpper_satellite(self): |
| 84 | + z = self._tensor(0.0) |
| 85 | + return SimpleNamespace( |
| 86 | + _zmos=z, |
| 87 | + _zmol=z, |
| 88 | + _t=z, |
| 89 | + _se2=z, |
| 90 | + _se3=z, |
| 91 | + _si2=z, |
| 92 | + _si3=z, |
| 93 | + _sl2=z, |
| 94 | + _sl3=z, |
| 95 | + _sl4=z, |
| 96 | + _sgh2=z, |
| 97 | + _sgh3=z, |
| 98 | + _sgh4=z, |
| 99 | + _sh2=z, |
| 100 | + _sh3=z, |
| 101 | + _ee2=z, |
| 102 | + _e3=z, |
| 103 | + _xi2=z, |
| 104 | + _xi3=z, |
| 105 | + _xl2=z, |
| 106 | + _xl3=z, |
| 107 | + _xl4=z, |
| 108 | + _xgh2=z, |
| 109 | + _xgh3=z, |
| 110 | + _xgh4=z, |
| 111 | + _xh2=z, |
| 112 | + _xh3=z, |
| 113 | + _peo=z, |
| 114 | + _pinco=z, |
| 115 | + _plo=z, |
| 116 | + _pgho=z, |
| 117 | + _pho=self._tensor(0.1), |
| 118 | + ) |
| 119 | + |
| 120 | + def _make_dsinit_satellite(self): |
| 121 | + return SimpleNamespace( |
| 122 | + _t=self._tensor(60.0), |
| 123 | + _xke=self._tensor(0.0743669161), |
| 124 | + _gsto=self._tensor(0.2), |
| 125 | + _mo=self._tensor(0.3), |
| 126 | + _nodeo=self._tensor(0.4), |
| 127 | + _argpo=self._tensor(0.1), |
| 128 | + _mdot=self._tensor(0.001), |
| 129 | + _nodedot=self._tensor(0.002), |
| 130 | + _no_unkozai=self._tensor(0.0086), |
| 131 | + ) |
| 132 | + |
| 133 | + def test_private_helpers_and_dpper_low_inclination_wrap(self): |
| 134 | + x = torch.tensor(1.23) |
| 135 | + self.assertIs(deep_space._to_tensor(x, x), x) |
| 136 | + self.assertTrue(deep_space._to_bool(True)) |
| 137 | + |
| 138 | + sat = self._make_dpper_satellite() |
| 139 | + ep, inclp, nodep, argpp, mp = deep_space.dpper( |
| 140 | + satellite=sat, |
| 141 | + inclo=self._tensor(0.1), |
| 142 | + init="n", |
| 143 | + ep=self._tensor(0.1), |
| 144 | + inclp=self._tensor(0.1), |
| 145 | + nodep=self._tensor(0.1), |
| 146 | + argpp=self._tensor(0.0), |
| 147 | + mp=self._tensor(0.0), |
| 148 | + opsmode="a", |
| 149 | + ) |
| 150 | + |
| 151 | + self.assertLess(float(nodep), 0.0) |
| 152 | + self.assertTrue(torch.isfinite(ep)) |
| 153 | + self.assertTrue(torch.isfinite(inclp)) |
| 154 | + self.assertTrue(torch.isfinite(argpp)) |
| 155 | + self.assertTrue(torch.isfinite(mp)) |
| 156 | + |
| 157 | + def test_dpper_negative_node_wraps_for_afspc_mode(self): |
| 158 | + sat = self._make_dpper_satellite() |
| 159 | + _, _, nodep, _, _ = deep_space.dpper( |
| 160 | + satellite=sat, |
| 161 | + inclo=self._tensor(0.1), |
| 162 | + init="n", |
| 163 | + ep=self._tensor(0.1), |
| 164 | + inclp=self._tensor(0.1), |
| 165 | + nodep=self._tensor(-0.1), |
| 166 | + argpp=self._tensor(0.0), |
| 167 | + mp=self._tensor(0.0), |
| 168 | + opsmode="a", |
| 169 | + ) |
| 170 | + |
| 171 | + self.assertGreaterEqual(float(nodep), 0.0) |
| 172 | + |
| 173 | + def _call_dsinit(self, ecco): |
| 174 | + sat = self._make_dsinit_satellite() |
| 175 | + one = self._tensor(1.0) |
| 176 | + half = self._tensor(0.5) |
| 177 | + em = self._tensor(ecco) |
| 178 | + eccsq = self._tensor(ecco * ecco) |
| 179 | + inclm = self._tensor(0.35) |
| 180 | + sinim = torch.sin(inclm) |
| 181 | + cosim = torch.cos(inclm) |
| 182 | + |
| 183 | + return deep_space.dsinit( |
| 184 | + satellite=sat, |
| 185 | + cosim=cosim, |
| 186 | + emsq=eccsq, |
| 187 | + argpo=self._tensor(0.1), |
| 188 | + s1=one, |
| 189 | + s2=one, |
| 190 | + s3=one, |
| 191 | + s4=one, |
| 192 | + s5=one, |
| 193 | + sinim=sinim, |
| 194 | + ss1=one, |
| 195 | + ss2=one, |
| 196 | + ss3=one, |
| 197 | + ss4=one, |
| 198 | + ss5=one, |
| 199 | + sz1=half, |
| 200 | + sz3=half, |
| 201 | + sz11=half, |
| 202 | + sz13=half, |
| 203 | + sz21=half, |
| 204 | + sz23=half, |
| 205 | + sz31=half, |
| 206 | + sz33=half, |
| 207 | + z1=half, |
| 208 | + z3=half, |
| 209 | + z11=half, |
| 210 | + z13=half, |
| 211 | + z21=half, |
| 212 | + z23=half, |
| 213 | + z31=half, |
| 214 | + z33=half, |
| 215 | + ecco=em, |
| 216 | + eccsq=eccsq, |
| 217 | + em=em, |
| 218 | + argpm=self._tensor(0.2), |
| 219 | + inclm=inclm, |
| 220 | + mm=self._tensor(0.3), |
| 221 | + nm=self._tensor(0.0086), |
| 222 | + nodem=self._tensor(0.4), |
| 223 | + xpidot=self._tensor(0.001), |
| 224 | + ) |
| 225 | + |
| 226 | + def test_dsinit_irez2_low_eccentricity_branch(self): |
| 227 | + out = self._call_dsinit(ecco=0.6) |
| 228 | + self.assertEqual(out["irez"], 2) |
| 229 | + self.assertNotEqual(float(out["d2201"]), 0.0) |
| 230 | + self.assertNotEqual(float(out["d5232"]), 0.0) |
| 231 | + |
| 232 | + def test_dsinit_irez2_high_eccentricity_branch(self): |
| 233 | + out = self._call_dsinit(ecco=0.8) |
| 234 | + self.assertEqual(out["irez"], 2) |
| 235 | + self.assertNotEqual(float(out["d5421"]), 0.0) |
| 236 | + self.assertNotEqual(float(out["d5433"]), 0.0) |
| 237 | + |
| 238 | + def test_dsinit_irez2_mid_high_eccentricity_branch(self): |
| 239 | + out = self._call_dsinit(ecco=0.7) |
| 240 | + self.assertEqual(out["irez"], 2) |
| 241 | + self.assertNotEqual(float(out["d5220"]), 0.0) |
| 242 | + |
| 243 | + def test_dspace_irez2_integration_branch(self): |
| 244 | + sat = SimpleNamespace( |
| 245 | + _gsto=self._tensor(0.3), |
| 246 | + _t=self._tensor(1000.0), |
| 247 | + _dedt=self._tensor(0.0), |
| 248 | + _didt=self._tensor(0.0), |
| 249 | + _domdt=self._tensor(0.0), |
| 250 | + _dnodt=self._tensor(0.0), |
| 251 | + _dmdt=self._tensor(0.0), |
| 252 | + _irez=2, |
| 253 | + _atime=self._tensor(0.0), |
| 254 | + _xni=self._tensor(0.0086), |
| 255 | + _xli=self._tensor(0.2), |
| 256 | + _no_unkozai=self._tensor(0.0086), |
| 257 | + _xlamo=self._tensor(0.2), |
| 258 | + _xfact=self._tensor(1.0e-4), |
| 259 | + _argpo=self._tensor(0.1), |
| 260 | + _argpdot=self._tensor(2.0e-4), |
| 261 | + _d2201=self._tensor(1.0e-6), |
| 262 | + _d2211=self._tensor(1.0e-6), |
| 263 | + _d3210=self._tensor(1.0e-6), |
| 264 | + _d3222=self._tensor(1.0e-6), |
| 265 | + _d4410=self._tensor(1.0e-6), |
| 266 | + _d4422=self._tensor(1.0e-6), |
| 267 | + _d5220=self._tensor(1.0e-6), |
| 268 | + _d5232=self._tensor(1.0e-6), |
| 269 | + _d5421=self._tensor(1.0e-6), |
| 270 | + _d5433=self._tensor(1.0e-6), |
| 271 | + ) |
| 272 | + |
| 273 | + em, argpm, inclm, mm, nodem, nm = deep_space.dspace( |
| 274 | + satellite=sat, |
| 275 | + em=self._tensor(0.7), |
| 276 | + argpm=self._tensor(0.2), |
| 277 | + inclm=self._tensor(0.3), |
| 278 | + mm=self._tensor(0.4), |
| 279 | + nodem=self._tensor(0.5), |
| 280 | + nm=self._tensor(0.0086), |
| 281 | + ) |
| 282 | + |
| 283 | + self.assertNotEqual(float(sat._atime), 0.0) |
| 284 | + self.assertTrue(torch.isfinite(em)) |
| 285 | + self.assertTrue(torch.isfinite(argpm)) |
| 286 | + self.assertTrue(torch.isfinite(inclm)) |
| 287 | + self.assertTrue(torch.isfinite(mm)) |
| 288 | + self.assertTrue(torch.isfinite(nodem)) |
| 289 | + self.assertTrue(torch.isfinite(nm)) |
| 290 | + |
| 291 | + def test_sgp4_deep_space_edge_guards(self): |
| 292 | + tle = dsgp4.tle.TLE([DEEP_SPACE_TLES[0][0], DEEP_SPACE_TLES[0][1]]) |
| 293 | + dsgp4.initialize_tle(tle, gravity_constant_name="wgs-84") |
| 294 | + self.assertEqual(tle._method, "d") |
| 295 | + |
| 296 | + with patch.object( |
| 297 | + dsgp4_sgp4_module, |
| 298 | + "dpper", |
| 299 | + return_value=( |
| 300 | + torch.tensor([1.1]), |
| 301 | + torch.tensor([-np.pi]), |
| 302 | + torch.tensor([0.2]), |
| 303 | + torch.tensor([0.1]), |
| 304 | + torch.tensor([0.3]), |
| 305 | + ), |
| 306 | + ): |
| 307 | + dsgp4_sgp4_module.sgp4(tle, torch.tensor([10.0])) |
| 308 | + |
| 309 | + self.assertEqual(int(tle._error), 3) |
| 310 | + self.assertTrue(torch.isfinite(tle._xlcof).all()) |
| 311 | + |
| 312 | + |
71 | 313 | if __name__ == "__main__": |
72 | 314 | unittest.main() |
0 commit comments