open-space-toolkit-astrodynamics 9.1.6__py39-none-manylinux2014_aarch64.whl → 13.0.2__py39-none-manylinux2014_aarch64.whl

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 (30) hide show
  1. {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/METADATA +5 -5
  2. {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/RECORD +29 -27
  3. {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/WHEEL +1 -1
  4. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-39-aarch64-linux-gnu.so +0 -0
  5. ostk/astrodynamics/converters.py +35 -90
  6. ostk/astrodynamics/dataframe.py +479 -0
  7. ostk/astrodynamics/display.py +2 -0
  8. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.13 +0 -0
  9. ostk/astrodynamics/pytrajectory/pystate.py +216 -1
  10. ostk/astrodynamics/test/conftest.py +2 -2
  11. ostk/astrodynamics/test/flight/test_profile.py +155 -55
  12. ostk/astrodynamics/test/test_converters.py +43 -140
  13. ostk/astrodynamics/test/test_dataframe.py +875 -0
  14. ostk/astrodynamics/test/test_display.py +2 -3
  15. ostk/astrodynamics/test/test_event_condition.py +27 -7
  16. ostk/astrodynamics/test/test_trajectory.py +116 -38
  17. ostk/astrodynamics/test/test_utilities.py +31 -46
  18. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +13 -0
  19. ostk/astrodynamics/test/trajectory/orbit/test_pass.py +9 -0
  20. ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +3 -0
  21. ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +2 -2
  22. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +34 -2
  23. ostk/astrodynamics/test/trajectory/test_orbit.py +26 -2
  24. ostk/astrodynamics/test/trajectory/test_segment.py +99 -1
  25. ostk/astrodynamics/test/trajectory/test_sequence.py +53 -0
  26. ostk/astrodynamics/test/trajectory/test_state.py +306 -0
  27. ostk/astrodynamics/utilities.py +125 -36
  28. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.9 +0 -0
  29. {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/top_level.txt +0 -0
  30. {open_space_toolkit_astrodynamics-9.1.6.dist-info → open_space_toolkit_astrodynamics-13.0.2.dist-info}/zip-safe +0 -0
@@ -0,0 +1,875 @@
1
+ # Copyright © Loft Orbital Solutions Inc.
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ import pandas as pd
8
+
9
+ from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
10
+
11
+ from ostk.physics import Environment
12
+ from ostk.physics.time import Instant
13
+ from ostk.physics.time import DateTime
14
+ from ostk.physics.time import Duration
15
+ from ostk.physics.time import Scale
16
+ from ostk.physics.coordinate import Frame
17
+ from ostk.physics.coordinate import Position
18
+ from ostk.physics.coordinate import Velocity
19
+ from ostk.physics.coordinate.frame.provider.iau import Theory
20
+
21
+ from ostk.astrodynamics.converters import coerce_to_datetime
22
+ from ostk.astrodynamics.trajectory import State
23
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
24
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianPosition
25
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianVelocity
26
+ from ostk.astrodynamics.flight import Profile
27
+
28
+ from ostk.astrodynamics.dataframe import generate_states_from_dataframe
29
+ from ostk.astrodynamics.dataframe import generate_dataframe_from_states
30
+ from ostk.astrodynamics.dataframe import generate_profile_from_dataframe
31
+ from ostk.astrodynamics.dataframe import generate_dataframe_from_profile
32
+
33
+
34
+ class TestOrbitDataframe:
35
+ @pytest.fixture
36
+ def instant(self) -> Instant:
37
+ return Instant.date_time(DateTime.parse("2024-01-29T00:00:00"), Scale.UTC)
38
+
39
+ @pytest.fixture
40
+ def frame(self) -> Frame:
41
+ return Frame.GCRF()
42
+
43
+ @pytest.fixture
44
+ def position(self, frame: Frame) -> Position:
45
+ return Position.meters(
46
+ [755972.142139276024, -3390511.949699319433, 5955672.751532567665],
47
+ frame,
48
+ )
49
+
50
+ @pytest.fixture
51
+ def velocity(self, frame: Frame) -> Velocity:
52
+ return Velocity.meters_per_second(
53
+ [-563.764594800880, -6619.592151780337, -3685.668514834143],
54
+ frame,
55
+ )
56
+
57
+ @pytest.fixture
58
+ def attitude(self) -> Quaternion:
59
+ return Quaternion.xyzs(
60
+ -0.638160707740, -0.163520830523, 0.726693549038, 0.194751982966
61
+ )
62
+
63
+ @pytest.fixture
64
+ def angular_velocity(self) -> np.ndarray:
65
+ return np.array([0.0, 0.0, 0.0])
66
+
67
+ @pytest.fixture
68
+ def orbit_state(
69
+ self,
70
+ instant: Instant,
71
+ position: Position,
72
+ velocity: Velocity,
73
+ ) -> State:
74
+ return State(
75
+ instant=instant,
76
+ position=position,
77
+ velocity=velocity,
78
+ )
79
+
80
+ @pytest.fixture
81
+ def orbit_states(self, orbit_state: State) -> list[State]:
82
+ return [orbit_state, orbit_state, orbit_state]
83
+
84
+ @pytest.fixture
85
+ def profile_state(
86
+ self,
87
+ instant: Instant,
88
+ position: Position,
89
+ velocity: Velocity,
90
+ attitude: Quaternion,
91
+ angular_velocity: np.ndarray,
92
+ frame: Frame,
93
+ ) -> State:
94
+ return State(instant, position, velocity, attitude, angular_velocity, frame)
95
+
96
+ @pytest.fixture
97
+ def profile_states(self, profile_state: State) -> list[State]:
98
+ return [profile_state, profile_state, profile_state]
99
+
100
+ @pytest.fixture
101
+ def profile_dataframe_position_columns(self) -> list[str]:
102
+ return ["r_J2000 (IAU 2006)_x", "r_J2000 (IAU 2006)_y", "r_J2000 (IAU 2006)_z"]
103
+
104
+ @pytest.fixture
105
+ def profile_dataframe_velocity_columns(self) -> list[str]:
106
+ return ["v_J2000 (IAU 2006)_x", "v_J2000 (IAU 2006)_y", "v_J2000 (IAU 2006)_z"]
107
+
108
+ @pytest.fixture
109
+ def profile_dataframe_attitude_columns(self) -> list[str]:
110
+ return [
111
+ "q_B_J2000 (IAU 2006)_x",
112
+ "q_B_J2000 (IAU 2006)_y",
113
+ "q_B_J2000 (IAU 2006)_z",
114
+ "q_B_J2000 (IAU 2006)_s",
115
+ ]
116
+
117
+ @pytest.fixture
118
+ def profile_dataframe_angular_velocity_columns(self) -> list[str]:
119
+ return [
120
+ "w_B_J2000 (IAU 2006)_in_B_x",
121
+ "w_B_J2000 (IAU 2006)_in_B_y",
122
+ "w_B_J2000 (IAU 2006)_in_B_z",
123
+ ]
124
+
125
+ @pytest.fixture
126
+ def profile_dataframe(
127
+ self,
128
+ instant: Instant,
129
+ profile_dataframe_position_columns: list[str],
130
+ profile_dataframe_velocity_columns: list[str],
131
+ profile_dataframe_attitude_columns: list[str],
132
+ profile_dataframe_angular_velocity_columns: list[str],
133
+ ) -> pd.DataFrame:
134
+ return pd.DataFrame(
135
+ [
136
+ {
137
+ "Timestamp": coerce_to_datetime(instant),
138
+ **dict(zip(profile_dataframe_position_columns, [1.0, 2.0, 3.0])),
139
+ **dict(zip(profile_dataframe_velocity_columns, [4.0, 5.0, 6.0])),
140
+ **dict(zip(profile_dataframe_attitude_columns, [0.0, 0.0, 0.0, 1.0])),
141
+ **dict(
142
+ zip(profile_dataframe_angular_velocity_columns, [0.0, 0.0, 0.0])
143
+ ),
144
+ },
145
+ {
146
+ "Timestamp": coerce_to_datetime(instant + Duration.minutes(1.0)),
147
+ **dict(zip(profile_dataframe_position_columns, [11.0, 12.0, 13.0])),
148
+ **dict(zip(profile_dataframe_velocity_columns, [14.0, 15.0, 16.0])),
149
+ **dict(zip(profile_dataframe_attitude_columns, [0.0, 0.0, 1.0, 0.0])),
150
+ **dict(
151
+ zip(profile_dataframe_angular_velocity_columns, [1.0, 1.0, 1.0])
152
+ ),
153
+ },
154
+ ]
155
+ )
156
+
157
+ @pytest.fixture
158
+ def profile_dataframe_indexed_timestamp(
159
+ self,
160
+ profile_dataframe: pd.DataFrame,
161
+ ) -> pd.DataFrame:
162
+ profile_dataframe.set_index("Timestamp", inplace=True)
163
+ return profile_dataframe
164
+
165
+ @pytest.fixture
166
+ def orbit_dataframe(self, instant: Instant) -> pd.DataFrame:
167
+ return pd.DataFrame(
168
+ [
169
+ {
170
+ "Timestamp": coerce_to_datetime(instant),
171
+ "r_GCRF_x": 1.0,
172
+ "r_GCRF_y": 2.0,
173
+ "r_GCRF_z": 3.0,
174
+ "v_GCRF_x": 4.0,
175
+ "v_GCRF_y": 5.0,
176
+ "v_GCRF_z": 6.0,
177
+ },
178
+ {
179
+ "Timestamp": coerce_to_datetime(instant + Duration.minutes(1.0)),
180
+ "r_GCRF_x": 11.0,
181
+ "r_GCRF_y": 12.0,
182
+ "r_GCRF_z": 13.0,
183
+ "v_GCRF_x": 14.0,
184
+ "v_GCRF_y": 15.0,
185
+ "v_GCRF_z": 16.0,
186
+ },
187
+ ]
188
+ )
189
+
190
+ @pytest.fixture
191
+ def orbit_dataframe_indexed_timestamp(
192
+ self, orbit_dataframe: pd.DataFrame
193
+ ) -> pd.DataFrame:
194
+ orbit_dataframe.set_index("Timestamp", inplace=True)
195
+ return orbit_dataframe
196
+
197
+ def test_generate_orbit_states_from_dataframe_defaults_success(
198
+ self,
199
+ orbit_dataframe: pd.DataFrame,
200
+ ):
201
+ states: list[State] = generate_states_from_dataframe(orbit_dataframe)
202
+
203
+ for state in states:
204
+ assert len(state.get_coordinates()) == len(orbit_dataframe.columns) - 1
205
+
206
+ def test_generate_profile_states_from_dataframe_defaults_success(
207
+ self,
208
+ profile_dataframe: pd.DataFrame,
209
+ ):
210
+ states: list[State] = generate_states_from_dataframe(
211
+ profile_dataframe,
212
+ reference_frame=Frame.J2000(Theory.IAU_2006),
213
+ )
214
+
215
+ for state in states:
216
+ assert len(state.get_coordinates()) == len(profile_dataframe.columns) - 1
217
+
218
+ def test_generate_states_from_profile_dataframe_success(
219
+ self,
220
+ profile_dataframe: pd.DataFrame,
221
+ profile_dataframe_position_columns: list[str],
222
+ profile_dataframe_velocity_columns: list[str],
223
+ profile_dataframe_attitude_columns: list[str],
224
+ profile_dataframe_angular_velocity_columns: list[str],
225
+ ):
226
+ states: list[State] = generate_states_from_dataframe(
227
+ dataframe=profile_dataframe,
228
+ reference_frame=Frame.J2000(Theory.IAU_2006),
229
+ time_column="Timestamp",
230
+ position_columns=profile_dataframe_position_columns,
231
+ velocity_columns=profile_dataframe_velocity_columns,
232
+ attitude_columns=profile_dataframe_attitude_columns,
233
+ angular_velocity_columns=profile_dataframe_angular_velocity_columns,
234
+ )
235
+
236
+ for state in states:
237
+ assert len(state.get_coordinates()) == len(profile_dataframe.columns) - 1
238
+
239
+ def test_generate_states_from_orbit_dataframe_success(
240
+ self,
241
+ orbit_dataframe: pd.DataFrame,
242
+ ):
243
+ states: list[State] = generate_states_from_dataframe(
244
+ dataframe=orbit_dataframe,
245
+ reference_frame=Frame.GCRF(),
246
+ time_column="Timestamp",
247
+ position_columns=["r_GCRF_x", "r_GCRF_y", "r_GCRF_z"],
248
+ velocity_columns=["v_GCRF_x", "v_GCRF_y", "v_GCRF_z"],
249
+ )
250
+
251
+ for state in states:
252
+ assert len(state.get_coordinates()) == len(orbit_dataframe.columns) - 1
253
+
254
+ def test_generate_states_from_profile_dataframe_success_defined_columns_without_time(
255
+ self,
256
+ profile_dataframe_indexed_timestamp: pd.DataFrame,
257
+ profile_dataframe_position_columns: list[str],
258
+ profile_dataframe_velocity_columns: list[str],
259
+ profile_dataframe_attitude_columns: list[str],
260
+ profile_dataframe_angular_velocity_columns: list[str],
261
+ ):
262
+ states: list[State] = generate_states_from_dataframe(
263
+ dataframe=profile_dataframe_indexed_timestamp,
264
+ reference_frame=Frame.J2000(Theory.IAU_2006),
265
+ position_columns=profile_dataframe_position_columns,
266
+ velocity_columns=profile_dataframe_velocity_columns,
267
+ attitude_columns=profile_dataframe_attitude_columns,
268
+ angular_velocity_columns=profile_dataframe_angular_velocity_columns,
269
+ )
270
+
271
+ for state in states:
272
+ assert len(state.get_coordinates()) == len(
273
+ profile_dataframe_indexed_timestamp.columns
274
+ )
275
+
276
+ def test_generate_states_from_orbit_dataframe_success_defined_columnsout_with_time(
277
+ self,
278
+ orbit_dataframe_indexed_timestamp: pd.DataFrame,
279
+ ):
280
+ states: list[State] = generate_states_from_dataframe(
281
+ dataframe=orbit_dataframe_indexed_timestamp,
282
+ reference_frame=Frame.GCRF(),
283
+ position_columns=["r_GCRF_x", "r_GCRF_y", "r_GCRF_z"],
284
+ velocity_columns=["v_GCRF_x", "v_GCRF_y", "v_GCRF_z"],
285
+ )
286
+
287
+ for state in states:
288
+ assert len(state.get_coordinates()) == len(
289
+ orbit_dataframe_indexed_timestamp.columns
290
+ )
291
+
292
+ def test_generate_dataframe_from_profile_states_success_custom_columns(
293
+ self,
294
+ profile_states: list[State],
295
+ ):
296
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_states(
297
+ states=profile_states,
298
+ time_column="t",
299
+ position_columns=["r_1", "r_2", "r_3"],
300
+ velocity_columns=["v_1", "v_2", "v_3"],
301
+ attitude_columns=["q_1", "q_2", "q_3", "q_4"],
302
+ angular_velocity_columns=["w_1", "w_2", "w_3"],
303
+ )
304
+
305
+ assert list(generated_dataframe.columns) == [
306
+ "r_1",
307
+ "r_2",
308
+ "r_3",
309
+ "v_1",
310
+ "v_2",
311
+ "v_3",
312
+ "q_1",
313
+ "q_2",
314
+ "q_3",
315
+ "q_4",
316
+ "w_1",
317
+ "w_2",
318
+ "w_3",
319
+ ]
320
+
321
+ def test_generate_dataframe_from_orbit_states_success_custom_columns(
322
+ self,
323
+ orbit_states: list[State],
324
+ ):
325
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_states(
326
+ states=orbit_states,
327
+ time_column="t",
328
+ position_columns=["r_1", "r_2", "r_3"],
329
+ velocity_columns=["v_1", "v_2", "v_3"],
330
+ )
331
+
332
+ assert list(generated_dataframe.columns) == [
333
+ "r_1",
334
+ "r_2",
335
+ "r_3",
336
+ "v_1",
337
+ "v_2",
338
+ "v_3",
339
+ ]
340
+
341
+ def test_generate_dataframe_from_profile_states_success_custom_reference_frame(
342
+ self,
343
+ profile_states: list[State],
344
+ ):
345
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_states(
346
+ states=profile_states,
347
+ reference_frame=Frame.ITRF(),
348
+ )
349
+
350
+ assert list(generated_dataframe.columns) == [
351
+ "r_ITRF_x",
352
+ "r_ITRF_y",
353
+ "r_ITRF_z",
354
+ "v_ITRF_x",
355
+ "v_ITRF_y",
356
+ "v_ITRF_z",
357
+ "q_B_ITRF_x",
358
+ "q_B_ITRF_y",
359
+ "q_B_ITRF_z",
360
+ "q_B_ITRF_s",
361
+ "w_B_ITRF_in_B_x",
362
+ "w_B_ITRF_in_B_y",
363
+ "w_B_ITRF_in_B_z",
364
+ ]
365
+
366
+ def test_generate_dataframe_from_orbit_states_success_set_time_index_disabled(
367
+ self,
368
+ orbit_states: list[State],
369
+ ):
370
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_states(
371
+ states=orbit_states,
372
+ time_column="t",
373
+ position_columns=["r_1", "r_2", "r_3"],
374
+ velocity_columns=["v_1", "v_2", "v_3"],
375
+ set_time_index=False,
376
+ )
377
+
378
+ assert list(generated_dataframe.columns) == [
379
+ "t",
380
+ "r_1",
381
+ "r_2",
382
+ "r_3",
383
+ "v_1",
384
+ "v_2",
385
+ "v_3",
386
+ ]
387
+
388
+ def test_generate_dataframe_from_profile_states_success_set_time_index_disabled(
389
+ self,
390
+ profile_states: list[State],
391
+ ):
392
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_states(
393
+ states=profile_states,
394
+ time_column="t",
395
+ position_columns=["r_1", "r_2", "r_3"],
396
+ velocity_columns=["v_1", "v_2", "v_3"],
397
+ attitude_columns=["q_1", "q_2", "q_3", "q_4"],
398
+ angular_velocity_columns=["w_1", "w_2", "w_3"],
399
+ set_time_index=False,
400
+ )
401
+
402
+ assert list(generated_dataframe.columns) == [
403
+ "t",
404
+ "r_1",
405
+ "r_2",
406
+ "r_3",
407
+ "v_1",
408
+ "v_2",
409
+ "v_3",
410
+ "q_1",
411
+ "q_2",
412
+ "q_3",
413
+ "q_4",
414
+ "w_1",
415
+ "w_2",
416
+ "w_3",
417
+ ]
418
+
419
+
420
+ class TestProfileDataframe:
421
+ @pytest.fixture
422
+ def environment(self) -> Environment:
423
+ return Environment.default()
424
+
425
+ @pytest.fixture
426
+ def epoch(self) -> Instant:
427
+ return Instant.date_time(DateTime(2020, 1, 1, 0, 0, 0), Scale.UTC)
428
+
429
+ @pytest.fixture
430
+ def dataframe(self, epoch: Instant) -> pd.DataFrame:
431
+ return pd.DataFrame(
432
+ [
433
+ {
434
+ "Timestamp": coerce_to_datetime(epoch),
435
+ "r_GCRF_x": 1.0,
436
+ "r_GCRF_y": 2.0,
437
+ "r_GCRF_z": 3.0,
438
+ "v_GCRF_x": 4.0,
439
+ "v_GCRF_y": 5.0,
440
+ "v_GCRF_z": 6.0,
441
+ "q_B_GCRF_x": 0.0,
442
+ "q_B_GCRF_y": 0.0,
443
+ "q_B_GCRF_z": 0.0,
444
+ "q_B_GCRF_s": 1.0,
445
+ "w_B_GCRF_in_B_x": 0.0,
446
+ "w_B_GCRF_in_B_y": 0.0,
447
+ "w_B_GCRF_in_B_z": 0.0,
448
+ },
449
+ {
450
+ "Timestamp": coerce_to_datetime(epoch + Duration.minutes(1.0)),
451
+ "r_GCRF_x": 11.0,
452
+ "r_GCRF_y": 12.0,
453
+ "r_GCRF_z": 13.0,
454
+ "v_GCRF_x": 14.0,
455
+ "v_GCRF_y": 15.0,
456
+ "v_GCRF_z": 16.0,
457
+ "q_B_GCRF_x": 0.0,
458
+ "q_B_GCRF_y": 0.0,
459
+ "q_B_GCRF_z": 1.0,
460
+ "q_B_GCRF_s": 0.0,
461
+ "w_B_GCRF_in_B_x": 1.0,
462
+ "w_B_GCRF_in_B_y": 1.0,
463
+ "w_B_GCRF_in_B_z": 1.0,
464
+ },
465
+ ]
466
+ )
467
+
468
+ @pytest.fixture
469
+ def profile(self, dataframe: pd.DataFrame) -> Profile:
470
+ return generate_profile_from_dataframe(
471
+ dataframe=dataframe,
472
+ )
473
+
474
+ @pytest.fixture
475
+ def dataframe_indexed_timestamp(self, dataframe: pd.DataFrame) -> pd.DataFrame:
476
+ dataframe.set_index("Timestamp", inplace=True)
477
+ return dataframe
478
+
479
+ def test_generate_profile_from_dataframe_success(
480
+ self,
481
+ epoch: Instant,
482
+ dataframe: pd.DataFrame,
483
+ ):
484
+ profile: Profile = generate_profile_from_dataframe(
485
+ dataframe=dataframe,
486
+ )
487
+
488
+ assert profile is not None
489
+
490
+ np.testing.assert_allclose(
491
+ profile.get_state_at(epoch).get_position().get_coordinates(),
492
+ np.array((1.0, 2.0, 3.0)),
493
+ atol=1e-8,
494
+ )
495
+
496
+ np.testing.assert_allclose(
497
+ profile.get_state_at(epoch).get_velocity().get_coordinates(),
498
+ np.array((4.0, 5.0, 6.0)),
499
+ atol=1e-8,
500
+ )
501
+
502
+ np.testing.assert_allclose(
503
+ profile.get_state_at(epoch).get_attitude().to_vector(Quaternion.Format.XYZS),
504
+ np.array((0.0, 0.0, 0.0, 1.0)),
505
+ atol=1e-8,
506
+ )
507
+
508
+ np.testing.assert_allclose(
509
+ profile.get_state_at(epoch).get_angular_velocity(),
510
+ np.array((0.0, 0.0, 0.0)),
511
+ atol=1e-8,
512
+ )
513
+
514
+ np.testing.assert_allclose(
515
+ profile.get_state_at(epoch + Duration.minutes(1.0))
516
+ .get_position()
517
+ .get_coordinates(),
518
+ np.array((11.0, 12.0, 13.0)),
519
+ atol=1e-8,
520
+ )
521
+
522
+ np.testing.assert_allclose(
523
+ profile.get_state_at(epoch + Duration.minutes(1.0))
524
+ .get_velocity()
525
+ .get_coordinates(),
526
+ np.array((14.0, 15.0, 16.0)),
527
+ atol=1e-8,
528
+ )
529
+
530
+ np.testing.assert_allclose(
531
+ profile.get_state_at(epoch + Duration.minutes(1.0))
532
+ .get_attitude()
533
+ .to_vector(Quaternion.Format.XYZS),
534
+ np.array((0.0, 0.0, 1.0, 0.0)),
535
+ atol=1e-8,
536
+ )
537
+
538
+ np.testing.assert_allclose(
539
+ profile.get_state_at(epoch + Duration.minutes(1.0)).get_angular_velocity(),
540
+ np.array((1.0, 1.0, 1.0)),
541
+ atol=1e-8,
542
+ )
543
+
544
+ assert profile.get_state_at(epoch).get_frame() == Frame.GCRF()
545
+
546
+ def test_generate_profile_from_dataframe_success_defined_columns_with_time(
547
+ self,
548
+ epoch: Instant,
549
+ dataframe: pd.DataFrame,
550
+ ):
551
+ profile: Profile = generate_profile_from_dataframe(
552
+ dataframe=dataframe,
553
+ time_column="Timestamp",
554
+ position_columns=["r_GCRF_x", "r_GCRF_y", "r_GCRF_z"],
555
+ velocity_columns=["v_GCRF_x", "v_GCRF_y", "v_GCRF_z"],
556
+ attitude_columns=["q_B_GCRF_x", "q_B_GCRF_y", "q_B_GCRF_z", "q_B_GCRF_s"],
557
+ angular_velocity_columns=[
558
+ "w_B_GCRF_in_B_x",
559
+ "w_B_GCRF_in_B_y",
560
+ "w_B_GCRF_in_B_z",
561
+ ],
562
+ )
563
+
564
+ assert profile is not None
565
+
566
+ np.testing.assert_allclose(
567
+ profile.get_state_at(epoch).get_position().get_coordinates(),
568
+ np.array((1.0, 2.0, 3.0)),
569
+ atol=1e-8,
570
+ )
571
+
572
+ np.testing.assert_allclose(
573
+ profile.get_state_at(epoch).get_velocity().get_coordinates(),
574
+ np.array((4.0, 5.0, 6.0)),
575
+ atol=1e-8,
576
+ )
577
+
578
+ np.testing.assert_allclose(
579
+ profile.get_state_at(epoch).get_attitude().to_vector(Quaternion.Format.XYZS),
580
+ np.array((0.0, 0.0, 0.0, 1.0)),
581
+ atol=1e-8,
582
+ )
583
+
584
+ np.testing.assert_allclose(
585
+ profile.get_state_at(epoch).get_angular_velocity(),
586
+ np.array((0.0, 0.0, 0.0)),
587
+ atol=1e-8,
588
+ )
589
+
590
+ np.testing.assert_allclose(
591
+ profile.get_state_at(epoch + Duration.minutes(1.0))
592
+ .get_position()
593
+ .get_coordinates(),
594
+ np.array((11.0, 12.0, 13.0)),
595
+ atol=1e-8,
596
+ )
597
+
598
+ np.testing.assert_allclose(
599
+ profile.get_state_at(epoch + Duration.minutes(1.0))
600
+ .get_velocity()
601
+ .get_coordinates(),
602
+ np.array((14.0, 15.0, 16.0)),
603
+ atol=1e-8,
604
+ )
605
+
606
+ np.testing.assert_allclose(
607
+ profile.get_state_at(epoch + Duration.minutes(1.0))
608
+ .get_attitude()
609
+ .to_vector(Quaternion.Format.XYZS),
610
+ np.array((0.0, 0.0, 1.0, 0.0)),
611
+ atol=1e-8,
612
+ )
613
+
614
+ np.testing.assert_allclose(
615
+ profile.get_state_at(epoch + Duration.minutes(1.0)).get_angular_velocity(),
616
+ np.array((1.0, 1.0, 1.0)),
617
+ atol=1e-8,
618
+ )
619
+
620
+ assert profile.get_state_at(epoch).get_frame() == Frame.GCRF()
621
+
622
+ def test_generate_profile_from_dataframe_success_defined_columns_without_time(
623
+ self,
624
+ epoch: Instant,
625
+ dataframe_indexed_timestamp: pd.DataFrame,
626
+ ):
627
+ profile: Profile = generate_profile_from_dataframe(
628
+ dataframe=dataframe_indexed_timestamp,
629
+ position_columns=["r_GCRF_x", "r_GCRF_y", "r_GCRF_z"],
630
+ velocity_columns=["v_GCRF_x", "v_GCRF_y", "v_GCRF_z"],
631
+ attitude_columns=["q_B_GCRF_x", "q_B_GCRF_y", "q_B_GCRF_z", "q_B_GCRF_s"],
632
+ angular_velocity_columns=[
633
+ "w_B_GCRF_in_B_x",
634
+ "w_B_GCRF_in_B_y",
635
+ "w_B_GCRF_in_B_z",
636
+ ],
637
+ )
638
+
639
+ assert profile is not None
640
+
641
+ np.testing.assert_allclose(
642
+ profile.get_state_at(epoch).get_position().get_coordinates(),
643
+ np.array((1.0, 2.0, 3.0)),
644
+ atol=1e-8,
645
+ )
646
+
647
+ np.testing.assert_allclose(
648
+ profile.get_state_at(epoch).get_velocity().get_coordinates(),
649
+ np.array((4.0, 5.0, 6.0)),
650
+ atol=1e-8,
651
+ )
652
+
653
+ np.testing.assert_allclose(
654
+ profile.get_state_at(epoch).get_attitude().to_vector(Quaternion.Format.XYZS),
655
+ np.array((0.0, 0.0, 0.0, 1.0)),
656
+ atol=1e-8,
657
+ )
658
+
659
+ np.testing.assert_allclose(
660
+ profile.get_state_at(epoch).get_angular_velocity(),
661
+ np.array((0.0, 0.0, 0.0)),
662
+ atol=1e-8,
663
+ )
664
+
665
+ np.testing.assert_allclose(
666
+ profile.get_state_at(epoch + Duration.minutes(1.0))
667
+ .get_position()
668
+ .get_coordinates(),
669
+ np.array((11.0, 12.0, 13.0)),
670
+ atol=1e-8,
671
+ )
672
+
673
+ np.testing.assert_allclose(
674
+ profile.get_state_at(epoch + Duration.minutes(1.0))
675
+ .get_velocity()
676
+ .get_coordinates(),
677
+ np.array((14.0, 15.0, 16.0)),
678
+ atol=1e-8,
679
+ )
680
+
681
+ np.testing.assert_allclose(
682
+ profile.get_state_at(epoch + Duration.minutes(1.0))
683
+ .get_attitude()
684
+ .to_vector(Quaternion.Format.XYZS),
685
+ np.array((0.0, 0.0, 1.0, 0.0)),
686
+ atol=1e-8,
687
+ )
688
+
689
+ np.testing.assert_allclose(
690
+ profile.get_state_at(epoch + Duration.minutes(1.0)).get_angular_velocity(),
691
+ np.array((1.0, 1.0, 1.0)),
692
+ atol=1e-8,
693
+ )
694
+
695
+ assert profile.get_state_at(epoch).get_frame() == Frame.GCRF()
696
+
697
+ def test_generate_profile_from_dataframe_success_no_angular_velocity_columns(
698
+ self,
699
+ epoch: Instant,
700
+ dataframe_indexed_timestamp: pd.DataFrame,
701
+ ):
702
+ dataframe_indexed_timestamp.drop(
703
+ ["w_B_GCRF_in_B_x", "w_B_GCRF_in_B_y", "w_B_GCRF_in_B_z"],
704
+ axis=1,
705
+ inplace=True,
706
+ )
707
+
708
+ profile: Profile = generate_profile_from_dataframe(
709
+ dataframe=dataframe_indexed_timestamp,
710
+ position_columns=["r_GCRF_x", "r_GCRF_y", "r_GCRF_z"],
711
+ velocity_columns=["v_GCRF_x", "v_GCRF_y", "v_GCRF_z"],
712
+ attitude_columns=["q_B_GCRF_x", "q_B_GCRF_y", "q_B_GCRF_z", "q_B_GCRF_s"],
713
+ )
714
+
715
+ assert profile is not None
716
+
717
+ np.testing.assert_allclose(
718
+ profile.get_state_at(epoch).get_position().get_coordinates(),
719
+ np.array((1.0, 2.0, 3.0)),
720
+ atol=1e-8,
721
+ )
722
+
723
+ np.testing.assert_allclose(
724
+ profile.get_state_at(epoch).get_velocity().get_coordinates(),
725
+ np.array((4.0, 5.0, 6.0)),
726
+ atol=1e-8,
727
+ )
728
+
729
+ np.testing.assert_allclose(
730
+ profile.get_state_at(epoch).get_attitude().to_vector(Quaternion.Format.XYZS),
731
+ np.array((0.0, 0.0, 0.0, 1.0)),
732
+ atol=1e-8,
733
+ )
734
+
735
+ np.testing.assert_allclose(
736
+ profile.get_state_at(epoch + Duration.minutes(1.0))
737
+ .get_position()
738
+ .get_coordinates(),
739
+ np.array((11.0, 12.0, 13.0)),
740
+ atol=1e-8,
741
+ )
742
+
743
+ np.testing.assert_allclose(
744
+ profile.get_state_at(epoch + Duration.minutes(1.0))
745
+ .get_velocity()
746
+ .get_coordinates(),
747
+ np.array((14.0, 15.0, 16.0)),
748
+ atol=1e-8,
749
+ )
750
+
751
+ np.testing.assert_allclose(
752
+ profile.get_state_at(epoch + Duration.minutes(1.0))
753
+ .get_attitude()
754
+ .to_vector(Quaternion.Format.XYZS),
755
+ np.array((0.0, 0.0, 1.0, 0.0)),
756
+ atol=1e-8,
757
+ )
758
+
759
+ assert profile.get_state_at(epoch).get_frame() == Frame.GCRF()
760
+
761
+ def test_generate_dataframe_from_profile_success(
762
+ self,
763
+ epoch: Instant,
764
+ profile: Profile,
765
+ dataframe_indexed_timestamp: pd.DataFrame,
766
+ ):
767
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_profile(
768
+ profile=profile,
769
+ instants=[
770
+ epoch,
771
+ epoch + Duration.minutes(1.0),
772
+ ],
773
+ )
774
+
775
+ pd.testing.assert_frame_equal(generated_dataframe, dataframe_indexed_timestamp)
776
+
777
+ def test_generate_dataframe_from_profile_success_custom_columns(
778
+ self,
779
+ epoch: Instant,
780
+ profile: Profile,
781
+ ):
782
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_profile(
783
+ profile=profile,
784
+ instants=[
785
+ epoch,
786
+ epoch + Duration.minutes(1.0),
787
+ ],
788
+ time_column="t",
789
+ position_columns=["r_1", "r_2", "r_3"],
790
+ velocity_columns=["v_1", "v_2", "v_3"],
791
+ attitude_columns=["q_1", "q_2", "q_3", "q_4"],
792
+ angular_velocity_columns=["w_1", "w_2", "w_3"],
793
+ )
794
+
795
+ assert list(generated_dataframe.columns) == [
796
+ "r_1",
797
+ "r_2",
798
+ "r_3",
799
+ "v_1",
800
+ "v_2",
801
+ "v_3",
802
+ "q_1",
803
+ "q_2",
804
+ "q_3",
805
+ "q_4",
806
+ "w_1",
807
+ "w_2",
808
+ "w_3",
809
+ ]
810
+
811
+ def test_generate_dataframe_from_profile_success_custom_reference_frame(
812
+ self,
813
+ epoch: Instant,
814
+ profile: Profile,
815
+ ):
816
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_profile(
817
+ profile=profile,
818
+ instants=[
819
+ epoch,
820
+ epoch + Duration.minutes(1.0),
821
+ ],
822
+ reference_frame=Frame.ITRF(),
823
+ )
824
+
825
+ assert list(generated_dataframe.columns) == [
826
+ "r_ITRF_x",
827
+ "r_ITRF_y",
828
+ "r_ITRF_z",
829
+ "v_ITRF_x",
830
+ "v_ITRF_y",
831
+ "v_ITRF_z",
832
+ "q_B_ITRF_x",
833
+ "q_B_ITRF_y",
834
+ "q_B_ITRF_z",
835
+ "q_B_ITRF_s",
836
+ "w_B_ITRF_in_B_x",
837
+ "w_B_ITRF_in_B_y",
838
+ "w_B_ITRF_in_B_z",
839
+ ]
840
+
841
+ def test_generate_dataframe_from_profile_success_set_time_index_disabled(
842
+ self,
843
+ epoch: Instant,
844
+ profile: Profile,
845
+ ):
846
+ generated_dataframe: pd.DataFrame = generate_dataframe_from_profile(
847
+ profile=profile,
848
+ instants=[
849
+ epoch,
850
+ epoch + Duration.minutes(1.0),
851
+ ],
852
+ time_column="t",
853
+ position_columns=["r_1", "r_2", "r_3"],
854
+ velocity_columns=["v_1", "v_2", "v_3"],
855
+ attitude_columns=["q_1", "q_2", "q_3", "q_4"],
856
+ angular_velocity_columns=["w_1", "w_2", "w_3"],
857
+ set_time_index=False,
858
+ )
859
+
860
+ assert list(generated_dataframe.columns) == [
861
+ "t",
862
+ "r_1",
863
+ "r_2",
864
+ "r_3",
865
+ "v_1",
866
+ "v_2",
867
+ "v_3",
868
+ "q_1",
869
+ "q_2",
870
+ "q_3",
871
+ "q_4",
872
+ "w_1",
873
+ "w_2",
874
+ "w_3",
875
+ ]