Skip to content

Commit d26a68b

Browse files
authored
Update pointing table to include subsecond fields (IMAP-Science-Operations-Center#1500)
* Update pointing table to include subsecond fields * remove floating point met columns from fake pointing df creator * Improve docstrings
1 parent 75a7ab5 commit d26a68b

4 files changed

Lines changed: 61 additions & 28 deletions

File tree

imap_processing/spice/repoint.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ def get_repoint_data() -> pd.DataFrame:
1616
"""
1717
Read repointing file using environment variable and return as dataframe.
1818
19+
Pointing and repointing nomenclature can be confusing. In this case,
20+
repoint is taken to mean a repoint maneuver. Thus, repoint_start and repoint_end
21+
are the times that bound when the spacecraft is performing a repointing maneuver.
22+
This is different from a pointing which is the time between repointing maneuvers.
23+
1924
REPOINT_DATA_FILEPATH environment variable should point to a local
2025
file where the repointing csv file is located.
2126
@@ -24,8 +29,14 @@ def get_repoint_data() -> pd.DataFrame:
2429
repoint_df : pd.DataFrame
2530
The repointing csv loaded into a pandas dataframe. The dataframe will
2631
contain the following columns:
27-
- `repoint_start_time`: Starting MET time of each repoint maneuver.
28-
- `repoint_end_time`: Ending MET time of each repoint maneuver.
32+
- `repoint_start_sec`: Starting MET seconds of repoint maneuver.
33+
- `repoint_start_subsec`: Starting MET milliseconds of repoint maneuver.
34+
- `repoint_start_met`: Floating point MET of repoint maneuver start time.
35+
Derived by combining `repoint_start_sec` and `repoint_start_subsec`.
36+
- `repoint_end_sec`: Ending MET seconds of repoint maneuver.
37+
- `repoint_end_subsec`: Ending MET milliseconds of repoint maneuver.
38+
- `repoint_end_met`: Floating point MET of repoint maneuver end time.
39+
Derived by combining `repoint_end_sec` and `repoint_end_subsec`.
2940
- `repoint_id`: Unique ID number of each repoint maneuver.
3041
"""
3142
repoint_data_filepath = os.getenv("REPOINT_DATA_FILEPATH")
@@ -38,6 +49,14 @@ def get_repoint_data() -> pd.DataFrame:
3849
logger.info(f"Reading repointing data from {path_to_spin_file}")
3950
repoint_df = pd.read_csv(path_to_spin_file, comment="#")
4051

52+
# Compute times by combining seconds and subseconds fields
53+
repoint_df["repoint_start_met"] = (
54+
repoint_df["repoint_start_sec"] + repoint_df["repoint_start_subsec"] / 1e3
55+
)
56+
repoint_df["repoint_end_met"] = (
57+
repoint_df["repoint_end_sec"] + repoint_df["repoint_end_subsec"] / 1e3
58+
)
59+
4160
return repoint_df
4261

4362

@@ -68,8 +87,12 @@ def interpolate_repoint_data(
6887
repoint_df : pandas.DataFrame
6988
Repoint table data interpolated such that there is one row
7089
for each of the queried MET times. Output columns are:
71-
- `repoint_start_time`
72-
- `repoint_end_time`
90+
- `repoint_start_sec`
91+
- `repoint_start_subsec`
92+
- `repoint_start_met`
93+
- `repoint_end_sec`
94+
- `repoint_end_subsec`
95+
- `repoint_end_met`
7396
- `repoint_id`
7497
- `repoint_in_progress`
7598
@@ -84,29 +107,29 @@ def interpolate_repoint_data(
84107
query_met_times = np.atleast_1d(query_met_times)
85108

86109
# Make sure no query times are before the first repoint in the dataframe.
87-
repoint_df_start_time = repoint_df["repoint_start_time"].values[0]
88-
if np.any(query_met_times < repoint_df_start_time):
89-
bad_times = query_met_times[query_met_times < repoint_df_start_time]
110+
repoint_df_start_met = repoint_df["repoint_start_met"].values[0]
111+
if np.any(query_met_times < repoint_df_start_met):
112+
bad_times = query_met_times[query_met_times < repoint_df_start_met]
90113
raise ValueError(
91114
f"{bad_times.size} query times are before the first repoint start "
92-
f" time in the repoint table. {bad_times=}, {repoint_df_start_time=}"
115+
f" time in the repoint table. {bad_times=}, {repoint_df_start_met=}"
93116
)
94117
# Make sure that no query times are after the valid range of the dataframe.
95118
# We approximate the end time of the table by adding 24 hours to the last
96119
# known repoint start time.
97-
repoint_df_end_time = repoint_df["repoint_start_time"].values[-1] + 24 * 60 * 60
98-
if np.any(query_met_times >= repoint_df_end_time):
99-
bad_times = query_met_times[query_met_times >= repoint_df_end_time]
120+
repoint_df_end_met = repoint_df["repoint_start_met"].values[-1] + 24 * 60 * 60
121+
if np.any(query_met_times >= repoint_df_end_met):
122+
bad_times = query_met_times[query_met_times >= repoint_df_end_met]
100123
raise ValueError(
101124
f"{bad_times.size} query times are after the valid time of the "
102125
f"pointing table. The valid end time is 24-hours after the last "
103-
f"repoint_start_time. {bad_times=}, {repoint_df_end_time=}"
126+
f"repoint_start_time. {bad_times=}, {repoint_df_end_met=}"
104127
)
105128

106129
# Find the row index for each queried MET time such that:
107130
# repoint_start_time[i] <= MET < repoint_start_time[i+1]
108131
row_indices = (
109-
np.searchsorted(repoint_df["repoint_start_time"], query_met_times, side="right")
132+
np.searchsorted(repoint_df["repoint_start_met"], query_met_times, side="right")
110133
- 1
111134
)
112135
out_df = repoint_df.iloc[row_indices]
@@ -115,6 +138,6 @@ def interpolate_repoint_data(
115138
# The table already has the correct row for each query time, so we
116139
# only need to check if the query time is less than the repoint end time to
117140
# get the same result as `repoint_start_time <= query_met_times < repoint_end_time`.
118-
out_df["repoint_in_progress"] = query_met_times < out_df["repoint_end_time"].values
141+
out_df["repoint_in_progress"] = query_met_times < out_df["repoint_end_met"].values
119142

120143
return out_df

imap_processing/tests/conftest.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,10 @@ def generate_repoint_data(
590590
repoint_end_met = repoint_start_times + 15 * 60
591591
repoint_df = pd.DataFrame.from_dict(
592592
{
593-
"repoint_start_time": repoint_start_times,
594-
"repoint_end_time": np.array(repoint_end_met),
593+
"repoint_start_sec": repoint_start_times.astype(int),
594+
"repoint_start_subsec": ((repoint_start_times % 1.0) * 1e3).astype(int),
595+
"repoint_end_sec": repoint_end_met.astype(int),
596+
"repoint_end_subsec": ((repoint_end_met % 1.0) * 1e3).astype(int),
595597
"repoint_id": np.arange(repoint_start_times.size, dtype=int)
596598
+ repoint_id_start,
597599
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This is a fake csv file for the sole purpose of testing repoint module functions
2-
repoint_start_time,repoint_end_time,repoint_id
3-
0,5,0
4-
15,20,1
5-
25,30,2
2+
repoint_start_sec,repoint_start_subsec,repoint_end_sec,repoint_end_subsec,repoint_id
3+
0,100,5,100,0
4+
15,200,20,200,1
5+
25,300,30,300,2

imap_processing/tests/spice/test_repoint.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ def test_get_repoint_data(fake_repoint_data):
2020
repoint_df = get_repoint_data()
2121
assert isinstance(repoint_df, pd.DataFrame)
2222
assert set(repoint_df.columns) == {
23-
"repoint_start_time",
24-
"repoint_end_time",
23+
"repoint_start_sec",
24+
"repoint_start_subsec",
25+
"repoint_start_met",
26+
"repoint_end_sec",
27+
"repoint_end_subsec",
28+
"repoint_end_met",
2529
"repoint_id",
2630
}
2731

@@ -36,10 +40,14 @@ def test_spin_data_no_table():
3640

3741
def test_interpolate_repoint_data(fake_repoint_data):
3842
"""Test coverage for get_repoint_data function."""
39-
query_times = np.array([0, 6, 32])
43+
query_times = np.array([0.1, 6, 32])
4044
expected_vals = {
41-
"repoint_start_time": np.array([0, 0, 25]),
42-
"repoint_end_time": np.array([5, 5, 30]),
45+
"repoint_start_sec": np.array([0, 0, 25]),
46+
"repoint_start_subsec": np.array([100, 100, 300]),
47+
"repoint_start_met": np.array([0.1, 0.1, 25.3]),
48+
"repoint_end_sec": np.array([5, 5, 30]),
49+
"repoint_end_subsec": np.array([100, 100, 300]),
50+
"repoint_end_met": np.array([5.1, 5.1, 30.3]),
4351
"repoint_id": np.array([0, 0, 2]),
4452
"repoint_in_progress": np.array([True, False, False]),
4553
}
@@ -57,7 +65,7 @@ def test_interpolate_repoint_data(fake_repoint_data):
5765
"1 query times are before",
5866
), # Query times before start of table
5967
(
60-
np.array([0, 24 * 60 * 60 + 26]),
68+
np.array([1, 24 * 60 * 60 + 26]),
6169
"1 query times are after",
6270
), # Query times after end of valid range
6371
],
@@ -81,12 +89,12 @@ def test_interpolate_repoint_data_with_use_fake_fixture(use_fake_repoint_data_fo
8189

8290
# Expected repoint_start_times are the seeded start times array repeated twice
8391
np.testing.assert_array_equal(
84-
repoint_df["repoint_start_time"].values,
92+
repoint_df["repoint_start_met"].values,
8593
np.concat([repoint_start_times, repoint_start_times]),
8694
)
8795
# Expected repoint_end_times are the seeded start times + 15 minutes
8896
np.testing.assert_array_equal(
89-
repoint_df["repoint_end_time"].values,
97+
repoint_df["repoint_end_met"].values,
9098
np.concat([repoint_start_times + 15 * 60, repoint_start_times + 15 * 60]),
9199
)
92100
# Expected repoint_id

0 commit comments

Comments
 (0)