1# -*- coding: utf-8 -*- 2 3# Copyright 2017-2018 PaGMO development team 4# 5# This file is part of the PaGMO library. 6# 7# The PaGMO library is free software; you can redistribute it and/or modify 8# it under the terms of either: 9# 10# * the GNU Lesser General Public License as published by the Free 11# Software Foundation; either version 3 of the License, or (at your 12# option) any later version. 13# 14# or 15# 16# * the GNU General Public License as published by the Free Software 17# Foundation; either version 3 of the License, or (at your option) any 18# later version. 19# 20# or both in parallel, as here. 21# 22# The PaGMO library is distributed in the hope that it will be useful, but 23# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 24# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25# for more details. 26# 27# You should have received copies of the GNU General Public License and the 28# GNU Lesser General Public License along with the PaGMO library. If not, 29# see https://www.gnu.org/licenses/. 30 31from __future__ import absolute_import as _ai 32 33import unittest as _ut 34import numpy as np 35import pathlib 36 37from pykep import __extensions__ 38 39 40class core_functions_test_case(_ut.TestCase): 41 """Test case for the core functions 42 43 """ 44 45 def runTest(self): 46 self.run_epoch_test() 47 48 def run_epoch_test(self): 49 from .core import epoch 50 epoch(julian_date=0, julian_date_type='mjd2000') 51 52 53class lambert_test_case(_ut.TestCase): 54 """Test case for the lambert problem class 55 56 """ 57 58 def runTest(self): 59 from .core import lambert_problem 60 lambert_problem(r1=[1, 1, 0], r2=[0, 1, 0], 61 mu=1., cw=False, max_revs=0, tof=0.3) 62 63 64class mga_1dsm_test_case(_ut.TestCase): 65 """Test case for the mga1_dsm class 66 67 """ 68 69 def runTest(self): 70 self.run_construction_test() 71 self.run_decode_times_and_vinf_test() 72 73 def run_construction_test(self): 74 from .trajopt import mga_1dsm 75 # Correct use (nothrow) 76 udp = mga_1dsm() 77 self.assertEqual(udp.get_nobj(), 1) 78 udp = mga_1dsm(tof_encoding='direct', tof=[[20, 400], [20, 400]]) 79 self.assertEqual(udp.get_nobj(), 1) 80 udp = mga_1dsm(tof_encoding='eta', tof=500) 81 self.assertEqual(udp.get_nobj(), 1) 82 udp = mga_1dsm(tof_encoding='alpha', tof=[20, 500]) 83 self.assertEqual(udp.get_nobj(), 1) 84 udp = mga_1dsm(tof_encoding='direct', tof=[ 85 [20, 400], [20, 400]], multi_objective=True) 86 self.assertEqual(udp.get_nobj(), 2) 87 88 # Incorrect use (raise) 89 with self.assertRaises(TypeError): 90 mga_1dsm(tof_encoding='direct', tof=34) 91 with self.assertRaises(TypeError): 92 mga_1dsm(tof_encoding='direct', tof=[[400], [20, 400]]) 93 with self.assertRaises(TypeError): 94 mga_1dsm(tof_encoding='direct', tof=[20, 400]) 95 with self.assertRaises(TypeError): 96 mga_1dsm(tof_encoding='eta', tof=[20, 400]) 97 with self.assertRaises(TypeError): 98 mga_1dsm(tof_encoding='eta', tof=[[20, 400], [20, 400]]) 99 with self.assertRaises(TypeError): 100 mga_1dsm(tof_encoding='alpha', tof=4) 101 with self.assertRaises(TypeError): 102 mga_1dsm(tof_encoding='alpha', tof=[[20, 400], [20, 400]]) 103 104 def run_decode_times_and_vinf_test(self): 105 from .trajopt import mga_1dsm 106 # Alpha 107 udp = mga_1dsm(tof_encoding='alpha', tof=[20, 500]) 108 x = [10] + [0., 0., 1., 1., 0.5] + [0.4, 1.3, 0.5, 0.5] + [50] 109 retval = udp._decode_times_and_vinf(x) 110 self.assertAlmostEqual(retval[0][0], 25.) 111 self.assertAlmostEqual(retval[0][1], 25.) 112 self.assertAlmostEqual(retval[1], 0.) 113 self.assertAlmostEqual(retval[2], 0.) 114 self.assertAlmostEqual(retval[3], 1.) 115 # Eta 116 udp = mga_1dsm(tof_encoding='eta', tof=50) 117 x = [10] + [0., 0., 1., 1., 0.5] + [0.4, 1.3, 0.5, 0.5] 118 retval = udp._decode_times_and_vinf(x) 119 self.assertAlmostEqual(retval[0][0], 25.) 120 self.assertAlmostEqual(retval[0][1], 12.5) 121 self.assertAlmostEqual(retval[1], 0.) 122 self.assertAlmostEqual(retval[2], 0.) 123 self.assertAlmostEqual(retval[3], 1.) 124 # Direct 125 udp = mga_1dsm(tof_encoding='direct', tof=[[10, 400], [10, 400]]) 126 x = [10] + [0., 0., 1., 1., 123] + [0.4, 1.3, 0.5, 321] 127 retval = udp._decode_times_and_vinf(x) 128 self.assertAlmostEqual(retval[0][0], 123) 129 self.assertAlmostEqual(retval[0][1], 321) 130 self.assertAlmostEqual(retval[1], 0.) 131 self.assertAlmostEqual(retval[2], 0.) 132 self.assertAlmostEqual(retval[3], 1.) 133 134 135class gym_test_case(_ut.TestCase): 136 """Test case for the gym 137 138 """ 139 140 def runTest(self): 141 self.run_rosetta_test() 142 self.run_cassini2_test() 143 self.run_tandem_test() 144 self.run_juice_test() 145 self.run_messenger_test() 146 147 def run_rosetta_test(self): 148 from .trajopt import gym 149 udp = gym.rosetta 150 x = [1.53488329e+03, 4.56388378e-01, 9.51717655e-01, 4.18212047e+03, 151 4.32159299e-01, 3.65256539e+02, 5.03363275e+00, 2.38949977e+00, 152 4.55746823e-01, 7.09999954e+02, 1.79894273e+00, 1.05000003e+00, 153 6.09083347e-01, 2.60816142e+02, 4.95158968e+00, 3.16049580e+00, 154 6.89049263e-01, 7.29775762e+02, 4.30823655e+00, 1.10842692e+00, 155 4.16075410e-01, 1.84999995e+03] 156 self.assertAlmostEqual(udp.fitness(x)[0], 1371.4992595125018) 157 158 def run_cassini2_test(self): 159 from .trajopt import gym 160 udp = gym.cassini2 161 x = [-7.75699976e+02, 9.15777367e-01, 4.06442043e-01, 3.21309562e+03, 162 6.81118341e-01, 1.62660490e+02, -1.58051063e+00, 1.28479507e+00, 163 4.72699902e-01, 4.24319550e+02, 4.30475919e+00, 1.15739933e+00, 164 2.55718252e-01, 5.44489098e+01, -1.54332794e+00, 1.27160729e+00, 165 9.00000000e-01, 5.88481599e+02, 4.76774269e+00, 7.00000000e+01, 166 1.00000000e-02, 2.20000000e+03] 167 self.assertAlmostEqual(udp.fitness(x)[0], 1511.731793212) 168 169 def run_tandem_test(self): 170 from .trajopt import gym 171 udp = gym.tandem(prob_id = 6, constrained=False) 172 x = [ 7.98593791e+03, 9.02569236e-01, 3.59510662e-01, 3.31011777e+03, 173 1.00000000e-02, 1.68854894e+02, -1.15321363e+00, 1.05006538e+00, 174 4.21911761e-01, 3.38579352e+02, -1.68143357e+00, 1.10121434e+00, 175 6.39679220e-01, 1.17925136e+03, -2.02838607e+00, 1.05000000e+00, 176 2.31554532e-01, 1.80000707e+03] 177 self.assertAlmostEqual(udp.fitness(x)[0], -7.302117213470749) 178 179 def run_juice_test(self): 180 from .trajopt import gym 181 udp = gym.juice 182 x = [ 8.16283083e+03, 6.41922787e-01, 6.51202691e-01, 2.51009414e+03, 183 2.97841478e-01, 3.81541370e+02, 9.58572190e-01, 1.53007674e+00, 184 3.06125365e-01, 1.49264351e+02, 4.10103546e+00, 2.39297670e+00, 185 4.34424957e-01, 3.16066418e+02, 4.33225338e+00, 1.30946367e+00, 186 4.52048883e-01, 1.63208108e+02, 5.93850330e-01, 1.34871269e+00, 187 2.03288502e-01, 6.52494606e+02, -1.37902374e+00, 1.55482534e+00, 188 1.96917559e-01, 1.08471126e+03] 189 self.assertAlmostEqual(udp.fitness(x)[0], -7.987614956531155) 190 191 def run_messenger_test(self): 192 from .trajopt import gym 193 udp = gym.messenger 194 x = [ 2.03241398e+03, 6.40762059e-01, 6.63357785e-01, 4.04989271e+03, 195 6.63732323e-01, 4.50068524e+02, -3.86553343e+00, 3.52631372e+00, 196 5.57888828e-01, 2.24619580e+02, -4.45910441e+00, 1.22736521e+00, 197 7.08063036e-01, 2.17965497e+02, -2.47894274e+00, 1.43586128e+00, 198 5.88391838e-01, 2.62423586e+02, -2.40594385e-02, 2.45470457e+00, 199 7.25370468e-01, 3.58067954e+02, 1.47192632e+00, 1.05000000e+00, 200 9.02984391e-01, 5.38436770e+02] 201 self.assertAlmostEqual(udp.fitness(x)[0], 5855.8143406005165) 202 203 204class spherical_harmonics_loader_test_case(_ut.TestCase): 205 """Test case for the spherical harmonic gravity file loader function. 206 207 """ 208 209 def runTest(self): 210 self.run_egm96_test() 211 self.run_ggm02c_test() 212 self.run_ggm02s_test() 213 self.run_jgmro120d_test() 214 self.run_glgm3150_test() 215 self.run_jgl150q1_test() 216 self.run_lpe200_test() 217 218 def run_egm96_test(self): 219 from .util import load_gravity_model 220 221 req_r = 6378137 222 req_mu = 3.986004418e+14 223 224 c20_20 = 4.01448327968e-09 225 c100_100 = 1.10930637955e-09 226 227 s100_50 = -1.06362863541e-09 228 s250_125 = -8.34356616626e-11 229 230 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Earth/egm96.txt") 231 232 self.assertEqual(r, req_r) 233 self.assertEqual(mu, req_mu) 234 235 self.assertEqual(c[20, 20], c20_20) 236 self.assertEqual(c[100, 100], c100_100) 237 238 self.assertEqual(s[100, 50], s100_50) 239 self.assertEqual(s[250, 125], s250_125) 240 241 def run_ggm02c_test(self): 242 from .util import load_gravity_model 243 244 req_r = 6378136.3 245 req_mu = 3.986004415e+14 246 247 c20_20 = 3.734698472368e-09 248 c100_100 = 8.8043569591782e-10 249 250 s100_50 = -8.2691933615552e-10 251 s200_100 = -1.3266576400742e-12 252 253 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Earth/ggm02c.txt") 254 255 self.assertEqual(r, req_r) 256 self.assertEqual(mu, req_mu) 257 258 self.assertEqual(c[20, 20], c20_20) 259 self.assertEqual(c[100, 100], c100_100) 260 261 self.assertEqual(s[100, 50], s100_50) 262 self.assertEqual(s[200, 100], s200_100) 263 264 def run_ggm02s_test(self): 265 from .util import load_gravity_model 266 267 req_r = 6378136.3 268 req_mu = 3.986004415e+14 269 270 c20_20 = 3.7323168217059e-09 271 c100_100 = 1.0356187365035e-09 272 273 s100_50 = -8.3581312522994e-10 274 s160_80 = -2.327147027496e-09 275 276 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Earth/ggm02s.txt") 277 278 self.assertEqual(r, req_r) 279 self.assertEqual(mu, req_mu) 280 281 self.assertEqual(c[20, 20], c20_20) 282 self.assertEqual(c[100, 100], c100_100) 283 284 self.assertEqual(s[100, 50], s100_50) 285 self.assertEqual(s[160, 80], s160_80) 286 287 def run_jgmro120d_test(self): 288 from .util import load_gravity_model 289 290 req_r = 3396000.0 291 req_mu = 4.28283758157561e+13 292 293 c20_20 = -4.767064931643e-07 294 c100_100 = -6.238892373683e-09 295 296 s100_50 = -1.191278972881e-08 297 s120_60 = 5.598027946471e-10 298 299 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Mars/jgmro_120d.txt") 300 301 self.assertEqual(r, req_r) 302 self.assertEqual(mu, req_mu) 303 304 self.assertEqual(c[20, 20], c20_20) 305 self.assertEqual(c[100, 100], c100_100) 306 307 self.assertEqual(s[100, 50], s100_50) 308 self.assertEqual(s[120, 60], s120_60) 309 310 def run_glgm3150_test(self): 311 from .util import load_gravity_model 312 313 req_r = 1738000.0 314 req_mu = 4.9002800238e+12 315 316 c20_20 = -1.4913227206107e-08 317 c100_100 = -3.0367607155944e-08 318 319 s100_50 = 1.7233711523911e-10 320 s120_60 = -5.3052488170131e-09 321 322 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Moon/glgm3_150.txt") 323 324 self.assertEqual(r, req_r) 325 self.assertEqual(mu, req_mu) 326 327 self.assertEqual(c[20, 20], c20_20) 328 self.assertEqual(c[100, 100], c100_100) 329 330 self.assertEqual(s[100, 50], s100_50) 331 self.assertEqual(s[120, 60], s120_60) 332 333 def run_jgl150q1_test(self): 334 from .util import load_gravity_model 335 336 req_r = 1738000.0 337 req_mu = 4.902801076e+12 338 339 c20_20 = 1.17705963027e-07 340 c100_100 = -1.5618538762e-08 341 342 s100_50 = 5.1145625569e-09 343 s120_60 = -1.05725130139e-09 344 345 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Moon/jgl_150q1.txt") 346 347 self.assertEqual(r, req_r) 348 self.assertEqual(mu, req_mu) 349 350 self.assertEqual(c[20, 20], c20_20) 351 self.assertEqual(c[100, 100], c100_100) 352 353 self.assertEqual(s[100, 50], s100_50) 354 self.assertEqual(s[120, 60], s120_60) 355 356 def run_lpe200_test(self): 357 from .util import load_gravity_model 358 359 req_r = 1738000.0 360 req_mu = 4.902800238e+12 361 362 c20_20 = -1.5489032082686e-08 363 c100_100 = -3.0841142975112e-08 364 365 s100_50 = -1.53194061215089e-09 366 s200_100 = 4.25825545837e-09 367 368 r, mu, c, s, n, m = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Moon/lpe_200.txt") 369 370 self.assertEqual(r, req_r) 371 self.assertEqual(mu, req_mu) 372 373 self.assertEqual(c[20, 20], c20_20) 374 self.assertEqual(c[100, 100], c100_100) 375 376 self.assertEqual(s[100, 50], s100_50) 377 self.assertEqual(s[200, 100], s200_100) 378 379class gravity_spherical_harmonic_test_case(_ut.TestCase): 380 """Test case for the spherical harmonic gravity calculator function. 381 382 """ 383 384 def runTest(self): 385 from .util import load_gravity_model, gravity_spherical_harmonic 386 387 r, mu, c, s, n_max, m_max = load_gravity_model(pathlib.Path(__file__).parent / "util/gravity_models/Earth/egm96.txt") 388 389 x = np.array([[6.07303362e+06, -1.63535914e-9, -3.22908926e+06], 390 [-5874145.34596, 1745831.60905, 3123338.4834], 391 [5290507.45841, -3377313.30177, -2813012.71391], 392 [-4360347.55688, 4787584.94679, 2318437.92131], 393 [3144590.02052, -5884275.41062, -1672008.17262]]) 394 395 acc = gravity_spherical_harmonic(x, r, mu, c, s, n_max, m_max) 396 397 req_acc = np.array([[-7.438268885207450, 4.174587578722027e-05, 3.966055730251360], 398 [7.195259383674340, -2.138389507954604, -3.836583575161607], 399 [-6.482132055071062, 4.138055191303929, 3.456233485081509], 400 [5.344543324379746, -5.868302782861193, -2.849822685569829], 401 [-3.855999728216701, 7.215225587047862, 2.055872629061049]]) 402 403 for a, req_a in zip(acc, req_acc): 404 for ax, req_ax in zip(a, req_a): 405 self.assertAlmostEqual(ax, req_ax, 13) 406 407 408def run_test_suite(level=0): 409 """Run the full test suite. 410 411 This function will raise an exception if at least one test fails. 412 413 Args: 414 level(``int``): the test level (higher values run longer tests) 415 416 """ 417 418 retval = 0 419 suite = _ut.TestLoader().loadTestsFromTestCase(core_functions_test_case) 420 suite.addTest(lambert_test_case()) 421 suite.addTest(mga_1dsm_test_case()) 422 suite.addTest(gym_test_case()) 423 424 if __extensions__['numba']: 425 suite.addTest(spherical_harmonics_loader_test_case()) 426 suite.addTest(gravity_spherical_harmonic_test_case()) 427 428 429 test_result = _ut.TextTestRunner(verbosity=2).run(suite) 430 431 if len(test_result.failures) > 0 or len(test_result.errors) > 0: 432 retval = 1 433 if retval != 0: 434 raise RuntimeError('One or more tests failed.') 435