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,479 @@
1
+ # Apache License 2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ import pandas as pd
8
+
9
+ from ostk.mathematics.curve_fitting import Interpolator
10
+
11
+ from ostk.physics.environment.object import Celestial
12
+ from ostk.physics.environment.object.celestial import Earth
13
+ from ostk.physics.time import Instant
14
+ from ostk.physics.coordinate import Frame
15
+
16
+ from ostk.astrodynamics.converters import coerce_to_datetime
17
+ from ostk.astrodynamics.converters import coerce_to_instant
18
+ from ostk.astrodynamics.trajectory import State
19
+ from ostk.astrodynamics.trajectory import StateBuilder
20
+ from ostk.astrodynamics.trajectory import Orbit
21
+ from ostk.astrodynamics.trajectory.state import CoordinateSubset
22
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianPosition
23
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import CartesianVelocity
24
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import AttitudeQuaternion
25
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import AngularVelocity
26
+ from ostk.astrodynamics.trajectory.orbit.model import Tabulated as TabulatedOrbit
27
+ from ostk.astrodynamics.flight import Profile
28
+ from ostk.astrodynamics.flight.profile.model import Tabulated as TabulatedProfile
29
+
30
+
31
+ DEFAULT_REFERENCE_FRAME: Frame = Frame.GCRF()
32
+ DEFAULT_TIME_COLUMN: str = "Timestamp"
33
+ DEFAULT_POSITION_COLUMNS_FORMAT: list[str] = [
34
+ "r_{frame}_x",
35
+ "r_{frame}_y",
36
+ "r_{frame}_z",
37
+ ]
38
+ DEFAULT_VELOCITY_COLUMNS_FORMAT: list[str] = [
39
+ "v_{frame}_x",
40
+ "v_{frame}_y",
41
+ "v_{frame}_z",
42
+ ]
43
+ DEFAULT_ATTITUDE_COLUMNS_FORMAT: list[str] = [
44
+ "q_B_{frame}_x",
45
+ "q_B_{frame}_y",
46
+ "q_B_{frame}_z",
47
+ "q_B_{frame}_s",
48
+ ]
49
+ DEFAULT_ANGULAR_VELOCITY_COLUMNS_FORMAT: list[str] = [
50
+ "w_B_{frame}_in_B_x",
51
+ "w_B_{frame}_in_B_y",
52
+ "w_B_{frame}_in_B_z",
53
+ ]
54
+ CARTESIAN_POSITION_SUBSET: CartesianPosition = CartesianPosition.default()
55
+ CARTESIAN_VELOCITY_SUBSET: CartesianVelocity = CartesianVelocity.default()
56
+ ATTITUDE_QUATERNION_SUBSET: AttitudeQuaternion = AttitudeQuaternion.default()
57
+ ANGULAR_VELOCITY_SUBSET: AngularVelocity = AngularVelocity.default()
58
+
59
+ DEFAULT_INTERPOLATION_TYPE: Interpolator.Type = Interpolator.Type.BarycentricRational
60
+
61
+
62
+ def generate_column_names(
63
+ reference_frame: Frame,
64
+ time_column: str | None = None,
65
+ position_columns: list[str] | None = None,
66
+ velocity_columns: list[str] | None = None,
67
+ attitude_columns: list[str] | None = None,
68
+ angular_velocity_columns: list[str] | None = None,
69
+ ) -> tuple[str, list[str], list[str], list[str], list[str]]:
70
+ """
71
+ Generate column names for a DataFrame containing orbit data.
72
+
73
+ Args:
74
+ reference_frame (Frame): Reference frame.
75
+ time_column (str | None): Name of the column containing the time data in [UTC].
76
+ position_columns (list[str] | None): List of column names containing the position data in [m].
77
+ velocity_columns (list[str] | None): List of column names containing the velocity data in [m/s].
78
+ attitude_columns (list[str] | None): List of column names containing the attitude data in [x, y, z, s] form.
79
+ angular_velocity_columns (list[str] | None): List of column names containing the angular velocity data in [rad/s].
80
+
81
+ Returns:
82
+ tuple[str, list[str], list[str], list[str], list[str]: Tuple containing the column names.
83
+ """
84
+ reference_frame_name: str = reference_frame.get_name()
85
+
86
+ return (
87
+ time_column or DEFAULT_TIME_COLUMN,
88
+ position_columns
89
+ or [
90
+ column.format(frame=reference_frame_name)
91
+ for column in DEFAULT_POSITION_COLUMNS_FORMAT
92
+ ],
93
+ velocity_columns
94
+ or [
95
+ column.format(frame=reference_frame_name)
96
+ for column in DEFAULT_VELOCITY_COLUMNS_FORMAT
97
+ ],
98
+ attitude_columns
99
+ or [
100
+ column.format(frame=reference_frame_name)
101
+ for column in DEFAULT_ATTITUDE_COLUMNS_FORMAT
102
+ ],
103
+ angular_velocity_columns
104
+ or [
105
+ column.format(frame=reference_frame_name)
106
+ for column in DEFAULT_ANGULAR_VELOCITY_COLUMNS_FORMAT
107
+ ],
108
+ )
109
+
110
+
111
+ def generate_states_from_dataframe(
112
+ dataframe: pd.DataFrame,
113
+ reference_frame: Frame | None = None,
114
+ time_column: str | None = None,
115
+ position_columns: list[str] | None = None,
116
+ velocity_columns: list[str] | None = None,
117
+ attitude_columns: list[str] | None = None,
118
+ angular_velocity_columns: list[str] | None = None,
119
+ output_frame: Frame | None = None,
120
+ ) -> list[State]:
121
+ """
122
+ Generate a list of OSTk States from a Pandas DataFrame.
123
+
124
+ Args:
125
+ dataframe (pd.DataFrame): Pandas DataFrame containing the orbit data.
126
+ reference_frame (Frame | None, optional): Reference frame of the states in the dataframe.
127
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
128
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
129
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
130
+ attitude_columns (list[str] | None, optional): List of column names containing the attitude data in [x, y, z, s] form.
131
+ angular_velocity_columns (list[str] | None, optional): List of column names containing the angular velocity data in [rad/s].
132
+ output_frame (Frame | None, optional): Output frame for the states.
133
+
134
+ Returns:
135
+ list[State]: List of OSTk States.
136
+ """
137
+
138
+ reference_frame = reference_frame or DEFAULT_REFERENCE_FRAME
139
+
140
+ output_frame = output_frame or reference_frame
141
+
142
+ (
143
+ time_column,
144
+ position_columns,
145
+ velocity_columns,
146
+ attitude_columns,
147
+ angular_velocity_columns,
148
+ ) = generate_column_names(
149
+ reference_frame=reference_frame,
150
+ time_column=time_column,
151
+ position_columns=position_columns,
152
+ velocity_columns=velocity_columns,
153
+ attitude_columns=attitude_columns,
154
+ angular_velocity_columns=angular_velocity_columns,
155
+ )
156
+
157
+ if not set(position_columns).issubset(dataframe.columns):
158
+ raise ValueError("Position columns are not present in the DataFrame.")
159
+
160
+ if not set(velocity_columns).issubset(dataframe.columns):
161
+ raise ValueError("Velocity columns are not present in the DataFrame.")
162
+
163
+ # check if the dataframe contains a timestamp column
164
+ has_timestamp: bool = time_column in dataframe.columns
165
+
166
+ # check if the dataframe contains attitude
167
+ has_attitude: bool = set(attitude_columns).issubset(dataframe.columns)
168
+
169
+ # check if the dataframe contains angular velocity
170
+ has_angular_velocity: bool = set(angular_velocity_columns).issubset(dataframe.columns)
171
+
172
+ coordinate_subsets = [
173
+ CARTESIAN_POSITION_SUBSET,
174
+ CARTESIAN_VELOCITY_SUBSET,
175
+ ]
176
+
177
+ if has_attitude:
178
+ coordinate_subsets.extend([ATTITUDE_QUATERNION_SUBSET])
179
+
180
+ if has_angular_velocity:
181
+ coordinate_subsets.extend([ANGULAR_VELOCITY_SUBSET])
182
+
183
+ state_builder: StateBuilder = StateBuilder(
184
+ frame=reference_frame,
185
+ coordinate_subsets=coordinate_subsets,
186
+ )
187
+
188
+ states: list[State] = []
189
+ for index, row in dataframe.to_dict("index").items():
190
+
191
+ coordinates: list[float] = [
192
+ *[row[column] for column in position_columns],
193
+ *[row[column] for column in velocity_columns],
194
+ ]
195
+
196
+ if has_attitude:
197
+ coordinates.extend([row[column] for column in attitude_columns])
198
+
199
+ if has_angular_velocity:
200
+ coordinates.extend([row[column] for column in angular_velocity_columns])
201
+
202
+ states.append(
203
+ state_builder.build(
204
+ instant=coerce_to_instant(
205
+ row[time_column] if has_timestamp else index,
206
+ ),
207
+ coordinates=coordinates,
208
+ ).in_frame(output_frame)
209
+ )
210
+
211
+ return states
212
+
213
+
214
+ def generate_dataframe_from_states(
215
+ states: list[State],
216
+ reference_frame: Frame | None = None,
217
+ time_column: str | None = None,
218
+ position_columns: list[str] | None = None,
219
+ velocity_columns: list[str] | None = None,
220
+ attitude_columns: list[str] | None = None,
221
+ angular_velocity_columns: list[str] | None = None,
222
+ set_time_index: bool = True,
223
+ ) -> pd.DataFrame:
224
+ """
225
+ Generate a Pandas DataFrame from a list of OSTk States.
226
+
227
+ Args:
228
+ states (list[State]): List of OSTk States.
229
+ reference_frame (Frame | None, optional): The desired reference frame.
230
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
231
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
232
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
233
+ attitude_columns (list[str] | None, optional): List of column names containing the attitude data in [x, y, z, s] form.
234
+ angular_velocity_columns (list[str] | None, optional): List of column names containing the angular velocity data in [rad/s].
235
+ set_time_index (bool, optional): Whether to set the time column as the index. Defaults to True.
236
+
237
+ Returns:
238
+ pd.DataFrame: Pandas DataFrame containing the orbit data.
239
+ """
240
+ has_attitude: bool = states[0].has_subset(ATTITUDE_QUATERNION_SUBSET)
241
+ has_angular_velocity: bool = states[0].has_subset(ANGULAR_VELOCITY_SUBSET)
242
+
243
+ reference_frame = reference_frame or DEFAULT_REFERENCE_FRAME
244
+
245
+ (
246
+ time_column,
247
+ position_columns,
248
+ velocity_columns,
249
+ attitude_columns,
250
+ angular_velocity_columns,
251
+ ) = generate_column_names(
252
+ reference_frame=reference_frame,
253
+ time_column=time_column,
254
+ position_columns=position_columns,
255
+ velocity_columns=velocity_columns,
256
+ attitude_columns=attitude_columns,
257
+ angular_velocity_columns=angular_velocity_columns,
258
+ )
259
+
260
+ if len(position_columns) != 3:
261
+ raise ValueError("Position columns must be a list of length 3.")
262
+
263
+ if len(velocity_columns) != 3:
264
+ raise ValueError("Velocity columns must be a list of length 3.")
265
+
266
+ if len(attitude_columns) != 4:
267
+ raise ValueError("Attitude columns must be a list of length 4.")
268
+
269
+ if len(angular_velocity_columns) != 3:
270
+ raise ValueError("Angular velocity columns must be a list of length 3.")
271
+
272
+ data: list[dict] = []
273
+
274
+ for state in states:
275
+ state = state.in_frame(reference_frame)
276
+
277
+ datum: dict = {
278
+ time_column: coerce_to_datetime(state.get_instant()),
279
+ **_get_entry_from_state(state, position_columns, CARTESIAN_POSITION_SUBSET),
280
+ **_get_entry_from_state(state, velocity_columns, CARTESIAN_VELOCITY_SUBSET),
281
+ }
282
+
283
+ if has_attitude:
284
+ datum.update(
285
+ _get_entry_from_state(state, attitude_columns, ATTITUDE_QUATERNION_SUBSET)
286
+ )
287
+ if has_angular_velocity:
288
+ datum.update(
289
+ _get_entry_from_state(
290
+ state, angular_velocity_columns, ANGULAR_VELOCITY_SUBSET
291
+ )
292
+ )
293
+
294
+ data.append(datum)
295
+
296
+ dataframe: pd.DataFrame = pd.DataFrame(data)
297
+ if set_time_index:
298
+ dataframe.set_index(time_column, inplace=True)
299
+
300
+ return dataframe
301
+
302
+
303
+ def generate_orbit_from_dataframe(
304
+ dataframe: pd.DataFrame,
305
+ central_body: Celestial = Earth.default(),
306
+ reference_frame: Frame | None = None,
307
+ time_column: str | None = None,
308
+ position_columns: list[str] | None = None,
309
+ velocity_columns: list[str] | None = None,
310
+ initial_revolution_number: int = 1,
311
+ interpolation_type: Interpolator.Type | None = None,
312
+ output_frame: Frame | None = None,
313
+ ) -> Orbit:
314
+ """
315
+ Generate an OSTk Orbit from a Pandas DataFrame.
316
+
317
+ Args:
318
+ dataframe (pd.DataFrame): Pandas DataFrame containing the orbit data.
319
+ central_body (Celestial, optional): Celestial object around which the Orbit is defined. Defaults to Earth.
320
+ reference_frame (Frame | None, optional): Reference frame.
321
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
322
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
323
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
324
+ initial_revolution_number (int, optional): Initial revolution number. Defaults to 1.
325
+ interpolation_type (Interpolator.Type | None, optional): Interpolation type.
326
+ output_frame (Frame | None, optional): Output frame for the states.
327
+
328
+ Returns:
329
+ Orbit: OSTk Orbit.
330
+ """
331
+
332
+ return Orbit(
333
+ model=TabulatedOrbit(
334
+ states=generate_states_from_dataframe(
335
+ dataframe=dataframe,
336
+ time_column=time_column,
337
+ position_columns=position_columns,
338
+ velocity_columns=velocity_columns,
339
+ reference_frame=reference_frame,
340
+ output_frame=output_frame,
341
+ ),
342
+ initial_revolution_number=initial_revolution_number,
343
+ interpolation_type=interpolation_type or DEFAULT_INTERPOLATION_TYPE,
344
+ ),
345
+ celestial_object=central_body,
346
+ )
347
+
348
+
349
+ def generate_dataframe_from_orbit(
350
+ orbit: Orbit,
351
+ instants: list[Instant],
352
+ reference_frame: Frame | None = None,
353
+ time_column: str | None = None,
354
+ position_columns: list[str] | None = None,
355
+ velocity_columns: list[str] | None = None,
356
+ set_time_index: bool = True,
357
+ ) -> pd.DataFrame:
358
+ """
359
+ Generate a Pandas DataFrame from an OSTk Orbit.
360
+
361
+ Args:
362
+ orbit (Orbit): OSTk Orbit.
363
+ instants (list[Instant]): List of instants at which the Orbit is to be evaluated.
364
+ reference_frame (Frame | None, optional): Reference frame.
365
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
366
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
367
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
368
+ set_time_index (bool, optional): Whether to set the time column as the DataFrame index. Defaults to True.
369
+
370
+ Returns:
371
+ pd.DataFrame: Pandas DataFrame containing the Orbit data.
372
+ """
373
+
374
+ states: list[State] = orbit.get_states_at(instants)
375
+
376
+ return generate_dataframe_from_states(
377
+ states,
378
+ reference_frame=reference_frame,
379
+ time_column=time_column,
380
+ position_columns=position_columns,
381
+ velocity_columns=velocity_columns,
382
+ set_time_index=set_time_index,
383
+ )
384
+
385
+
386
+ def generate_profile_from_dataframe(
387
+ dataframe: pd.DataFrame,
388
+ reference_frame: Frame | None = None,
389
+ time_column: str | None = None,
390
+ position_columns: list[str] | None = None,
391
+ velocity_columns: list[str] | None = None,
392
+ attitude_columns: list[str] | None = None,
393
+ angular_velocity_columns: list[str] | None = None,
394
+ output_frame: Frame | None = None,
395
+ ) -> Profile:
396
+ """
397
+ Generate an OSTk Profile from a Pandas DataFrame.
398
+
399
+ Args:
400
+ dataframe (pd.DataFrame): Pandas DataFrame containing the Profile data.
401
+ reference_frame (Frame | None, optional): Reference frame.
402
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
403
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
404
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
405
+ attitude_columns (list[str] | None, optional): List of column names containing the attitude data in [x, y, z, s] form.
406
+ angular_velocity_columns (list[str] | None, optional): List of column names containing the angular velocity data in [rad/s].
407
+ output_frame (Frame | None, optional): Output frame for the states.
408
+
409
+ Returns:
410
+ Profile: OSTk Profile.
411
+ """
412
+
413
+ return Profile(
414
+ model=TabulatedProfile(
415
+ states=generate_states_from_dataframe(
416
+ dataframe=dataframe,
417
+ reference_frame=reference_frame,
418
+ time_column=time_column,
419
+ position_columns=position_columns,
420
+ velocity_columns=velocity_columns,
421
+ attitude_columns=attitude_columns,
422
+ angular_velocity_columns=angular_velocity_columns,
423
+ output_frame=output_frame,
424
+ ),
425
+ ),
426
+ )
427
+
428
+
429
+ def generate_dataframe_from_profile(
430
+ profile: Profile,
431
+ instants: list[Instant],
432
+ reference_frame: Frame | None = None,
433
+ time_column: str | None = None,
434
+ position_columns: list[str] | None = None,
435
+ velocity_columns: list[str] | None = None,
436
+ attitude_columns: list[str] | None = None,
437
+ angular_velocity_columns: list[str] | None = None,
438
+ set_time_index: bool = True,
439
+ ) -> pd.DataFrame:
440
+ """
441
+ Generate a Pandas DataFrame from an OSTk Profile.
442
+
443
+ Args:
444
+ profile (Profile): OSTk Profile.
445
+ instants (list[Instant]): List of instants at which the Profile is to be evaluated.
446
+ reference_frame (Frame | None, optional): Reference frame.
447
+ time_column (str | None, optional): Name of the column containing the time data in [UTC].
448
+ position_columns (list[str] | None, optional): List of column names containing the position data in [m].
449
+ velocity_columns (list[str] | None, optional): List of column names containing the velocity data in [m/s].
450
+ attitude_columns (list[str] | None, optional): List of column names containing the attitude data in [x, y, z, s] form.
451
+ angular_velocity_columns (list[str] | None, optional): List of column names containing the angular velocity data in [rad/s].
452
+ set_time_index (bool, optional): Whether to set the time column as the DataFrame index. Defaults to True.
453
+
454
+ Returns:
455
+ pd.DataFrame: Pandas DataFrame containing the Profile data.
456
+ """
457
+
458
+ states: list[State] = profile.get_states_at(instants)
459
+
460
+ return generate_dataframe_from_states(
461
+ states,
462
+ reference_frame=reference_frame,
463
+ time_column=time_column,
464
+ position_columns=position_columns,
465
+ velocity_columns=velocity_columns,
466
+ attitude_columns=attitude_columns,
467
+ angular_velocity_columns=angular_velocity_columns,
468
+ set_time_index=set_time_index,
469
+ )
470
+
471
+
472
+ def _get_entry_from_state(
473
+ state: State, columns: list[str], subset: CoordinateSubset
474
+ ) -> dict:
475
+ coordinates: np.ndarray = state.extract_coordinate(subset)
476
+ return {
477
+ column.format(frame=state.get_frame().get_name()): coordinates[idx]
478
+ for idx, column in enumerate(columns)
479
+ }
@@ -1,5 +1,7 @@
1
1
  # Apache License 2.0
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from typing import Any
4
6
 
5
7
  import pandas as pd