dkist-processing-common 11.7.0rc3__py3-none-any.whl → 11.7.1rc1__py3-none-any.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.
- changelog/271.misc.rst +1 -0
- dkist_processing_common/models/constants.py +21 -357
- dkist_processing_common/models/fits_access.py +25 -16
- dkist_processing_common/parsers/experiment_id_bud.py +4 -8
- dkist_processing_common/parsers/id_bud.py +19 -35
- dkist_processing_common/parsers/l0_fits_access.py +3 -3
- dkist_processing_common/parsers/l1_fits_access.py +21 -47
- dkist_processing_common/parsers/near_bud.py +4 -4
- dkist_processing_common/parsers/proposal_id_bud.py +5 -11
- dkist_processing_common/parsers/single_value_single_key_flower.py +1 -0
- dkist_processing_common/parsers/time.py +27 -147
- dkist_processing_common/tasks/mixin/quality/_metrics.py +4 -6
- dkist_processing_common/tasks/parse_l0_input_data.py +1 -267
- dkist_processing_common/tests/test_fits_access.py +44 -19
- dkist_processing_common/tests/test_parse_l0_input_data.py +5 -39
- dkist_processing_common/tests/test_quality_mixin.py +11 -3
- dkist_processing_common/tests/test_stems.py +10 -127
- dkist_processing_common/tests/test_task_parsing.py +6 -6
- {dkist_processing_common-11.7.0rc3.dist-info → dkist_processing_common-11.7.1rc1.dist-info}/METADATA +2 -2
- {dkist_processing_common-11.7.0rc3.dist-info → dkist_processing_common-11.7.1rc1.dist-info}/RECORD +22 -28
- changelog/267.feature.1.rst +0 -1
- changelog/267.feature.2.rst +0 -1
- changelog/267.feature.rst +0 -1
- changelog/267.misc.rst +0 -1
- changelog/267.removal.1.rst +0 -2
- changelog/267.removal.rst +0 -1
- dkist_processing_common/parsers/average_bud.py +0 -48
- {dkist_processing_common-11.7.0rc3.dist-info → dkist_processing_common-11.7.1rc1.dist-info}/WHEEL +0 -0
- {dkist_processing_common-11.7.0rc3.dist-info → dkist_processing_common-11.7.1rc1.dist-info}/top_level.txt +0 -0
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from astropy.io import fits
|
|
4
4
|
|
|
5
|
-
from dkist_processing_common.models.fits_access import HEADER_KEY_NOT_FOUND
|
|
6
5
|
from dkist_processing_common.models.fits_access import FitsAccessBase
|
|
7
6
|
from dkist_processing_common.models.fits_access import MetadataKey
|
|
8
7
|
|
|
9
|
-
NOT_A_FLOAT = -999
|
|
10
|
-
|
|
11
8
|
|
|
12
9
|
class L1FitsAccess(FitsAccessBase):
|
|
13
10
|
"""
|
|
@@ -31,48 +28,25 @@ class L1FitsAccess(FitsAccessBase):
|
|
|
31
28
|
):
|
|
32
29
|
super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
|
|
33
30
|
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
36
|
-
self.
|
|
37
|
-
self.
|
|
38
|
-
self.
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
self.sensor_readout_exposure_time_ms
|
|
52
|
-
|
|
53
|
-
]
|
|
54
|
-
self.num_raw_frames_per_fpa: int = self.header[MetadataKey.num_raw_frames_per_fpa]
|
|
55
|
-
self.camera_id: str = self.header[MetadataKey.camera_id]
|
|
56
|
-
self.camera_name: str = self.header[MetadataKey.camera_name]
|
|
57
|
-
self.camera_bit_depth: int = self.header[MetadataKey.camera_bit_depth]
|
|
58
|
-
self.hardware_binning_x: int = self.header[MetadataKey.hardware_binning_x]
|
|
59
|
-
self.hardware_binning_y: int = self.header[MetadataKey.hardware_binning_y]
|
|
60
|
-
self.software_binning_x: int = self.header[MetadataKey.software_binning_x]
|
|
61
|
-
self.software_binning_y: int = self.header[MetadataKey.software_binning_y]
|
|
62
|
-
self.observing_program_execution_id: str = self.header[
|
|
63
|
-
MetadataKey.observing_program_execution_id
|
|
64
|
-
]
|
|
65
|
-
self.telescope_tracking_mode: str = self.header.get(
|
|
66
|
-
MetadataKey.telescope_tracking_mode, HEADER_KEY_NOT_FOUND
|
|
67
|
-
)
|
|
68
|
-
self.coude_table_tracking_mode: str = self.header.get(
|
|
69
|
-
MetadataKey.coude_table_tracking_mode, HEADER_KEY_NOT_FOUND
|
|
70
|
-
)
|
|
71
|
-
self.telescope_scanning_mode: str = self.header.get(
|
|
72
|
-
MetadataKey.telescope_scanning_mode, HEADER_KEY_NOT_FOUND
|
|
73
|
-
)
|
|
74
|
-
self.light_level: float = self.header[MetadataKey.light_level]
|
|
75
|
-
self.hls_version: str = self.header[MetadataKey.hls_version]
|
|
31
|
+
self._set_metadata_key_value(MetadataKey.elevation)
|
|
32
|
+
self._set_metadata_key_value(MetadataKey.azimuth)
|
|
33
|
+
self._set_metadata_key_value(MetadataKey.table_angle)
|
|
34
|
+
self._set_metadata_key_value(MetadataKey.gos_level3_status)
|
|
35
|
+
self._set_metadata_key_value(MetadataKey.gos_level3_lamp_status)
|
|
36
|
+
self._set_metadata_key_value(MetadataKey.gos_polarizer_status)
|
|
37
|
+
self._set_metadata_key_value(MetadataKey.gos_retarder_status)
|
|
38
|
+
self._set_metadata_key_value(MetadataKey.gos_level0_status)
|
|
39
|
+
self._set_metadata_key_value(MetadataKey.time_obs)
|
|
40
|
+
self._set_metadata_key_value(MetadataKey.ip_id)
|
|
41
|
+
self._set_metadata_key_value(MetadataKey.instrument)
|
|
42
|
+
self._set_metadata_key_value(MetadataKey.wavelength)
|
|
43
|
+
self._set_metadata_key_value(MetadataKey.proposal_id)
|
|
44
|
+
self._set_metadata_key_value(MetadataKey.experiment_id)
|
|
45
|
+
self._set_metadata_key_value(MetadataKey.num_dsps_repeats)
|
|
46
|
+
self._set_metadata_key_value(MetadataKey.current_dsps_repeat)
|
|
47
|
+
self._set_metadata_key_value(MetadataKey.fpa_exposure_time_ms)
|
|
48
|
+
self._set_metadata_key_value(MetadataKey.sensor_readout_exposure_time_ms)
|
|
49
|
+
self._set_metadata_key_value(MetadataKey.num_raw_frames_per_fpa)
|
|
76
50
|
|
|
77
51
|
@property
|
|
78
52
|
def gos_polarizer_angle(self) -> float:
|
|
@@ -80,7 +54,7 @@ class L1FitsAccess(FitsAccessBase):
|
|
|
80
54
|
try:
|
|
81
55
|
return float(self.header[MetadataKey.gos_polarizer_angle])
|
|
82
56
|
except ValueError:
|
|
83
|
-
return
|
|
57
|
+
return -999 # The angle is only used if the polarizer is in the beam
|
|
84
58
|
|
|
85
59
|
@property
|
|
86
60
|
def gos_retarder_angle(self) -> float:
|
|
@@ -88,4 +62,4 @@ class L1FitsAccess(FitsAccessBase):
|
|
|
88
62
|
try:
|
|
89
63
|
return float(self.header[MetadataKey.gos_retarder_angle])
|
|
90
64
|
except ValueError:
|
|
91
|
-
return
|
|
65
|
+
return -999 # The angle is only used if the retarder is in the beam
|
|
@@ -66,14 +66,14 @@ class NearFloatBud(Stem):
|
|
|
66
66
|
-------
|
|
67
67
|
The mean value associated with this input key
|
|
68
68
|
"""
|
|
69
|
-
|
|
70
|
-
biggest_value = max(
|
|
71
|
-
smallest_value = min(
|
|
69
|
+
value_set = list(self.key_to_petal_dict.values())
|
|
70
|
+
biggest_value = max(value_set)
|
|
71
|
+
smallest_value = min(value_set)
|
|
72
72
|
if biggest_value - smallest_value > self.tolerance:
|
|
73
73
|
raise ValueError(
|
|
74
74
|
f"{self.stem_name} values are not close enough. Max: {biggest_value}, Min: {smallest_value}, Tolerance: {self.tolerance}"
|
|
75
75
|
)
|
|
76
|
-
return mean(
|
|
76
|
+
return mean(value_set)
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
class TaskNearFloatBud(NearFloatBud):
|
|
@@ -2,27 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
from dkist_processing_common.models.constants import BudName
|
|
4
4
|
from dkist_processing_common.models.fits_access import MetadataKey
|
|
5
|
-
from dkist_processing_common.models.task_name import TaskName
|
|
6
5
|
from dkist_processing_common.parsers.id_bud import ContributingIdsBud
|
|
7
|
-
from dkist_processing_common.parsers.
|
|
6
|
+
from dkist_processing_common.parsers.id_bud import IdBud
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
class ProposalIdBud(
|
|
9
|
+
class ProposalIdBud(IdBud):
|
|
11
10
|
"""Class to create a Bud for the proposal_id."""
|
|
12
11
|
|
|
13
12
|
def __init__(self):
|
|
14
|
-
super().__init__(
|
|
15
|
-
constant_name=BudName.proposal_id,
|
|
16
|
-
metadata_key=MetadataKey.proposal_id,
|
|
17
|
-
ip_task_types=TaskName.observe,
|
|
18
|
-
)
|
|
13
|
+
super().__init__(constant_name=BudName.proposal_id, metadata_key=MetadataKey.proposal_id)
|
|
19
14
|
|
|
20
15
|
|
|
21
16
|
class ContributingProposalIdsBud(ContributingIdsBud):
|
|
22
|
-
"""Class to create a Bud for the
|
|
17
|
+
"""Class to create a Bud for the proposal_ids."""
|
|
23
18
|
|
|
24
19
|
def __init__(self):
|
|
25
20
|
super().__init__(
|
|
26
|
-
|
|
27
|
-
metadata_key=MetadataKey.proposal_id,
|
|
21
|
+
stem_name=BudName.contributing_proposal_ids, metadata_key=MetadataKey.proposal_id
|
|
28
22
|
)
|
|
@@ -22,6 +22,7 @@ from dkist_processing_common.parsers.single_value_single_key_flower import (
|
|
|
22
22
|
)
|
|
23
23
|
from dkist_processing_common.parsers.task import passthrough_header_ip_task
|
|
24
24
|
from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
|
|
25
|
+
from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class ObsIpStartTimeBud(TaskUniqueBud):
|
|
@@ -35,52 +36,15 @@ class ObsIpStartTimeBud(TaskUniqueBud):
|
|
|
35
36
|
)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
class
|
|
39
|
-
"""
|
|
40
|
-
Base class for making datetime-related buds.
|
|
41
|
-
|
|
42
|
-
Returns a tuple of sorted values converted from datetimes to unix seconds.
|
|
43
|
-
|
|
44
|
-
Complicated parsing of the header into a task type can be achieved by passing in a different
|
|
45
|
-
header task parsing function.
|
|
46
|
-
|
|
47
|
-
Parameters
|
|
48
|
-
----------
|
|
49
|
-
stem_name
|
|
50
|
-
The name for the constant to be defined
|
|
51
|
-
|
|
52
|
-
metadata_key
|
|
53
|
-
The metadata key associated with the constant
|
|
54
|
-
|
|
55
|
-
ip_task_types
|
|
56
|
-
Only consider objects whose parsed header IP task type matches a string in this list
|
|
57
|
-
|
|
58
|
-
header_type_parsing_func
|
|
59
|
-
The function used to convert a header into an IP task type
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
key_to_petal_dict: dict[str, float]
|
|
63
|
-
|
|
64
|
-
def __init__(
|
|
65
|
-
self,
|
|
66
|
-
stem_name: str,
|
|
67
|
-
metadata_key: str | StrEnum,
|
|
68
|
-
ip_task_types: str | list[str],
|
|
69
|
-
task_type_parsing_function: Callable = passthrough_header_ip_task,
|
|
70
|
-
):
|
|
71
|
-
super().__init__(stem_name=stem_name)
|
|
39
|
+
class CadenceBudBase(UniqueBud):
|
|
40
|
+
"""Base class for all Cadence Buds."""
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
self.metadata_key = metadata_key
|
|
76
|
-
if isinstance(ip_task_types, str):
|
|
77
|
-
ip_task_types = [ip_task_types]
|
|
78
|
-
self.ip_task_types = [task.casefold() for task in ip_task_types]
|
|
79
|
-
self.header_parsing_function = task_type_parsing_function
|
|
42
|
+
def __init__(self, constant_name: str):
|
|
43
|
+
super().__init__(constant_name, metadata_key=MetadataKey.time_obs)
|
|
80
44
|
|
|
81
45
|
def setter(self, fits_obj: L0FitsAccess) -> float | Type[SpilledDirt]:
|
|
82
46
|
"""
|
|
83
|
-
|
|
47
|
+
If the file is an observe file, its DATE-OBS value is stored as unix seconds.
|
|
84
48
|
|
|
85
49
|
Parameters
|
|
86
50
|
----------
|
|
@@ -88,45 +52,16 @@ class TaskDatetimeBudBase(Stem):
|
|
|
88
52
|
The input fits object
|
|
89
53
|
Returns
|
|
90
54
|
-------
|
|
91
|
-
The
|
|
55
|
+
The observe time in seconds
|
|
92
56
|
"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if task.casefold() in self.ip_task_types:
|
|
57
|
+
if fits_obj.ip_task_type.casefold() == TaskName.observe.value.casefold():
|
|
96
58
|
return (
|
|
97
59
|
datetime.fromisoformat(getattr(fits_obj, self.metadata_key))
|
|
98
60
|
.replace(tzinfo=timezone.utc)
|
|
99
61
|
.timestamp()
|
|
100
62
|
)
|
|
101
|
-
|
|
102
63
|
return SpilledDirt
|
|
103
64
|
|
|
104
|
-
def getter(self, key: Hashable) -> tuple[float, ...]:
|
|
105
|
-
"""
|
|
106
|
-
Return a tuple of sorted times in unix seconds.
|
|
107
|
-
|
|
108
|
-
Parameters
|
|
109
|
-
----------
|
|
110
|
-
key
|
|
111
|
-
The input key
|
|
112
|
-
|
|
113
|
-
Returns
|
|
114
|
-
-------
|
|
115
|
-
A tuple that is sorted times in unix seconds
|
|
116
|
-
"""
|
|
117
|
-
return tuple(sorted(list(self.key_to_petal_dict.values())))
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class CadenceBudBase(TaskDatetimeBudBase):
|
|
121
|
-
"""Base class for all Cadence Buds."""
|
|
122
|
-
|
|
123
|
-
def __init__(self, constant_name: str):
|
|
124
|
-
super().__init__(
|
|
125
|
-
stem_name=constant_name,
|
|
126
|
-
metadata_key=MetadataKey.time_obs,
|
|
127
|
-
ip_task_types=TaskName.observe,
|
|
128
|
-
)
|
|
129
|
-
|
|
130
65
|
|
|
131
66
|
class AverageCadenceBud(CadenceBudBase):
|
|
132
67
|
"""Class for the average cadence Bud."""
|
|
@@ -147,7 +82,7 @@ class AverageCadenceBud(CadenceBudBase):
|
|
|
147
82
|
-------
|
|
148
83
|
The mean value of the cadences of the input frames
|
|
149
84
|
"""
|
|
150
|
-
return np.mean(np.diff(
|
|
85
|
+
return np.mean(np.diff(sorted(list(self.key_to_petal_dict.values()))))
|
|
151
86
|
|
|
152
87
|
|
|
153
88
|
class MaximumCadenceBud(CadenceBudBase):
|
|
@@ -169,7 +104,7 @@ class MaximumCadenceBud(CadenceBudBase):
|
|
|
169
104
|
-------
|
|
170
105
|
The maximum cadence between frames
|
|
171
106
|
"""
|
|
172
|
-
return np.max(np.diff(
|
|
107
|
+
return np.max(np.diff(sorted(list(self.key_to_petal_dict.values()))))
|
|
173
108
|
|
|
174
109
|
|
|
175
110
|
class MinimumCadenceBud(CadenceBudBase):
|
|
@@ -191,7 +126,7 @@ class MinimumCadenceBud(CadenceBudBase):
|
|
|
191
126
|
-------
|
|
192
127
|
The minimum cadence between frames
|
|
193
128
|
"""
|
|
194
|
-
return np.min(np.diff(
|
|
129
|
+
return np.min(np.diff(sorted(list(self.key_to_petal_dict.values()))))
|
|
195
130
|
|
|
196
131
|
|
|
197
132
|
class VarianceCadenceBud(CadenceBudBase):
|
|
@@ -212,44 +147,11 @@ class VarianceCadenceBud(CadenceBudBase):
|
|
|
212
147
|
-------
|
|
213
148
|
Return the variance of the cadences over the input frames
|
|
214
149
|
"""
|
|
215
|
-
return np.var(np.diff(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
class TaskDateBeginBud(TaskDatetimeBudBase):
|
|
219
|
-
"""Class for the date begin task Bud."""
|
|
220
|
-
|
|
221
|
-
def __init__(
|
|
222
|
-
self,
|
|
223
|
-
constant_name: str,
|
|
224
|
-
ip_task_types: str | list[str],
|
|
225
|
-
task_type_parsing_function: Callable = passthrough_header_ip_task,
|
|
226
|
-
):
|
|
227
|
-
super().__init__(
|
|
228
|
-
stem_name=constant_name,
|
|
229
|
-
metadata_key=MetadataKey.time_obs,
|
|
230
|
-
ip_task_types=ip_task_types,
|
|
231
|
-
task_type_parsing_function=task_type_parsing_function,
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
def getter(self, key) -> str:
|
|
235
|
-
"""
|
|
236
|
-
Return the earliest date begin for the ip task type converted from unix seconds to datetime string.
|
|
237
|
-
|
|
238
|
-
Parameters
|
|
239
|
-
----------
|
|
240
|
-
key
|
|
241
|
-
The input key
|
|
242
|
-
Returns
|
|
243
|
-
-------
|
|
244
|
-
Return the minimum date begin as a datetime string
|
|
245
|
-
"""
|
|
246
|
-
min_time = super().getter(key)[0]
|
|
247
|
-
min_time_dt = datetime.fromtimestamp(min_time, tz=timezone.utc)
|
|
248
|
-
return min_time_dt.strftime("%Y-%m-%dT%H:%M:%S.%f")
|
|
150
|
+
return np.var(np.diff(sorted(list(self.key_to_petal_dict.values()))))
|
|
249
151
|
|
|
250
152
|
|
|
251
|
-
class
|
|
252
|
-
"""Base
|
|
153
|
+
class TimeFlowerBase(SingleValueSingleKeyFlower):
|
|
154
|
+
"""Base task for SingleValueSingleKeyFlowers that need to round their values to avoid value jitter."""
|
|
253
155
|
|
|
254
156
|
def setter(self, fits_obj: L0FitsAccess):
|
|
255
157
|
"""
|
|
@@ -267,7 +169,7 @@ class RoundTimeFlowerBase(SingleValueSingleKeyFlower):
|
|
|
267
169
|
return round(raw_value, EXP_TIME_ROUND_DIGITS)
|
|
268
170
|
|
|
269
171
|
|
|
270
|
-
class ExposureTimeFlower(
|
|
172
|
+
class ExposureTimeFlower(TimeFlowerBase):
|
|
271
173
|
"""For tagging the frame FPA exposure time."""
|
|
272
174
|
|
|
273
175
|
def __init__(self):
|
|
@@ -276,7 +178,7 @@ class ExposureTimeFlower(RoundTimeFlowerBase):
|
|
|
276
178
|
)
|
|
277
179
|
|
|
278
180
|
|
|
279
|
-
class ReadoutExpTimeFlower(
|
|
181
|
+
class ReadoutExpTimeFlower(TimeFlowerBase):
|
|
280
182
|
"""For tagging the exposure time of each readout that contributes to an FPA."""
|
|
281
183
|
|
|
282
184
|
def __init__(self):
|
|
@@ -286,18 +188,18 @@ class ReadoutExpTimeFlower(RoundTimeFlowerBase):
|
|
|
286
188
|
)
|
|
287
189
|
|
|
288
190
|
|
|
289
|
-
class
|
|
191
|
+
class TaskTimeBudBase(Stem):
|
|
290
192
|
"""
|
|
291
|
-
Base class for making buds that
|
|
193
|
+
Base class for making time-related buds that are computed for specific task types.
|
|
292
194
|
|
|
293
|
-
|
|
195
|
+
By "time-related" we mean values that generally need rounding when ingested into the database.
|
|
294
196
|
|
|
295
197
|
Complicated parsing of the header into a task type can be achieved by passing in a different
|
|
296
198
|
header task parsing function.
|
|
297
199
|
|
|
298
200
|
Parameters
|
|
299
201
|
----------
|
|
300
|
-
|
|
202
|
+
constant_name
|
|
301
203
|
The name for the constant to be defined
|
|
302
204
|
|
|
303
205
|
metadata_key
|
|
@@ -310,8 +212,6 @@ class TaskRoundTimeBudBase(Stem):
|
|
|
310
212
|
The function used to convert a header into an IP task type
|
|
311
213
|
"""
|
|
312
214
|
|
|
313
|
-
key_to_petal_dict: dict[str, float]
|
|
314
|
-
|
|
315
215
|
def __init__(
|
|
316
216
|
self,
|
|
317
217
|
stem_name: str,
|
|
@@ -329,18 +229,8 @@ class TaskRoundTimeBudBase(Stem):
|
|
|
329
229
|
self.ip_task_types = [task.casefold() for task in ip_task_types]
|
|
330
230
|
self.header_parsing_function = header_task_parsing_func
|
|
331
231
|
|
|
332
|
-
def setter(self, fits_obj: L0FitsAccess)
|
|
333
|
-
"""
|
|
334
|
-
Store the metadata key value if the parsed task type is in the desired types.
|
|
335
|
-
|
|
336
|
-
Parameters
|
|
337
|
-
----------
|
|
338
|
-
fits_obj
|
|
339
|
-
The input fits object
|
|
340
|
-
Returns
|
|
341
|
-
-------
|
|
342
|
-
The rounded time
|
|
343
|
-
"""
|
|
232
|
+
def setter(self, fits_obj: L0FitsAccess):
|
|
233
|
+
"""Return the desired metadata key only if the parsed task type matches the Bud's task type."""
|
|
344
234
|
task = self.header_parsing_function(fits_obj)
|
|
345
235
|
|
|
346
236
|
if task.casefold() in self.ip_task_types:
|
|
@@ -350,22 +240,12 @@ class TaskRoundTimeBudBase(Stem):
|
|
|
350
240
|
return SpilledDirt
|
|
351
241
|
|
|
352
242
|
def getter(self, key: Hashable) -> tuple[float, ...]:
|
|
353
|
-
"""
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
Parameters
|
|
357
|
-
----------
|
|
358
|
-
key
|
|
359
|
-
The input key
|
|
360
|
-
|
|
361
|
-
Returns
|
|
362
|
-
-------
|
|
363
|
-
A tuple that is the sorted set of unique times
|
|
364
|
-
"""
|
|
365
|
-
return tuple(sorted(set(self.key_to_petal_dict.values())))
|
|
243
|
+
"""Return a tuple of all the unique values found."""
|
|
244
|
+
value_tuple = tuple(sorted(set(self.key_to_petal_dict.values())))
|
|
245
|
+
return value_tuple
|
|
366
246
|
|
|
367
247
|
|
|
368
|
-
class TaskExposureTimesBud(
|
|
248
|
+
class TaskExposureTimesBud(TaskTimeBudBase):
|
|
369
249
|
"""Produce a tuple of all FPA exposure times present in the dataset for a specific ip task type."""
|
|
370
250
|
|
|
371
251
|
def __init__(
|
|
@@ -382,7 +262,7 @@ class TaskExposureTimesBud(TaskRoundTimeBudBase):
|
|
|
382
262
|
)
|
|
383
263
|
|
|
384
264
|
|
|
385
|
-
class TaskReadoutExpTimesBud(
|
|
265
|
+
class TaskReadoutExpTimesBud(TaskTimeBudBase):
|
|
386
266
|
"""Produce a tuple of all sensor readout exposure times present in the dataset for a specific task type."""
|
|
387
267
|
|
|
388
268
|
def __init__(
|
|
@@ -1356,15 +1356,13 @@ class _WavecalQualityMixin:
|
|
|
1356
1356
|
Note that the residuals are the *unweighed* residuals.
|
|
1357
1357
|
"""
|
|
1358
1358
|
weight_data = np.ones(input_wavelength.size) if weights is None else weights
|
|
1359
|
-
prepared_weights =
|
|
1359
|
+
prepared_weights = fit_result.prepared_weights
|
|
1360
1360
|
residuals = fit_result.minimizer_result.residual / prepared_weights
|
|
1361
1361
|
residuals[~np.isfinite(residuals)] = 0.0
|
|
1362
|
-
best_fit_atlas = input_spectrum - residuals
|
|
1363
1362
|
normalized_residuals = residuals / input_spectrum
|
|
1364
1363
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
best_fit_wavelength = wcs.spectral.pixel_to_world(np.arange(input_spectrum.size))
|
|
1364
|
+
best_fit_atlas = fit_result.best_fit_atlas
|
|
1365
|
+
best_fit_wavelength = fit_result.best_fit_wavelength_vector
|
|
1368
1366
|
|
|
1369
1367
|
finite_idx = (
|
|
1370
1368
|
np.isfinite(input_wavelength)
|
|
@@ -1378,7 +1376,7 @@ class _WavecalQualityMixin:
|
|
|
1378
1376
|
data = {
|
|
1379
1377
|
"input_wavelength_nm": input_wavelength.to_value(u.nm)[finite_idx].tolist(),
|
|
1380
1378
|
"input_spectrum": input_spectrum[finite_idx].tolist(),
|
|
1381
|
-
"best_fit_wavelength_nm": best_fit_wavelength
|
|
1379
|
+
"best_fit_wavelength_nm": best_fit_wavelength[finite_idx].tolist(),
|
|
1382
1380
|
"best_fit_atlas": best_fit_atlas[finite_idx].tolist(),
|
|
1383
1381
|
"normalized_residuals": normalized_residuals[finite_idx].tolist(),
|
|
1384
1382
|
"weights": None if weights is None else weight_data[finite_idx].tolist(),
|