dkist-processing-dlnirsp 0.32.9__py3-none-any.whl → 0.33.0rc1__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/120.feature.rst +2 -0
- changelog/121.misc.rst +2 -0
- changelog/124.feature.rst +2 -0
- changelog/124.science.rst +5 -0
- dkist_processing_dlnirsp/models/constants.py +6 -0
- dkist_processing_dlnirsp/models/parameters.py +33 -3
- dkist_processing_dlnirsp/parsers/task.py +2 -25
- dkist_processing_dlnirsp/parsers/time.py +2 -2
- dkist_processing_dlnirsp/tasks/__init__.py +1 -2
- dkist_processing_dlnirsp/tasks/movie.py +1121 -0
- dkist_processing_dlnirsp/tasks/parse.py +13 -8
- dkist_processing_dlnirsp/tasks/solar.py +129 -30
- dkist_processing_dlnirsp/tests/conftest.py +43 -6
- dkist_processing_dlnirsp/tests/local_trial_workflows/l0_polcals_as_science.py +21 -18
- dkist_processing_dlnirsp/tests/local_trial_workflows/l0_solar_gain_as_science.py +21 -18
- dkist_processing_dlnirsp/tests/local_trial_workflows/l0_to_l1.py +21 -18
- dkist_processing_dlnirsp/tests/local_trial_workflows/local_trial_dev_mockers.py +1 -1
- dkist_processing_dlnirsp/tests/test_dlnirsp_constants.py +2 -0
- dkist_processing_dlnirsp/tests/test_movie.py +141 -0
- dkist_processing_dlnirsp/tests/test_parameters.py +8 -0
- dkist_processing_dlnirsp/tests/test_parse.py +10 -0
- dkist_processing_dlnirsp/tests/test_science.py +0 -9
- dkist_processing_dlnirsp/tests/test_solar.py +114 -17
- dkist_processing_dlnirsp/workflows/l0_processing.py +6 -8
- dkist_processing_dlnirsp/workflows/trial_workflow.py +7 -7
- {dkist_processing_dlnirsp-0.32.9.dist-info → dkist_processing_dlnirsp-0.33.0rc1.dist-info}/METADATA +40 -23
- {dkist_processing_dlnirsp-0.32.9.dist-info → dkist_processing_dlnirsp-0.33.0rc1.dist-info}/RECORD +31 -29
- docs/gain.rst +7 -3
- dkist_processing_dlnirsp/tasks/assemble_movie.py +0 -150
- dkist_processing_dlnirsp/tasks/make_movie_frames.py +0 -156
- dkist_processing_dlnirsp/tests/test_assemble_movie.py +0 -169
- dkist_processing_dlnirsp/tests/test_make_movie_frames.py +0 -98
- {dkist_processing_dlnirsp-0.32.9.dist-info → dkist_processing_dlnirsp-0.33.0rc1.dist-info}/WHEEL +0 -0
- {dkist_processing_dlnirsp-0.32.9.dist-info → dkist_processing_dlnirsp-0.33.0rc1.dist-info}/entry_points.txt +0 -0
- {dkist_processing_dlnirsp-0.32.9.dist-info → dkist_processing_dlnirsp-0.33.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@ from dkist_processing_common.parsers.single_value_single_key_flower import (
|
|
|
13
13
|
SingleValueSingleKeyFlower,
|
|
14
14
|
)
|
|
15
15
|
from dkist_processing_common.parsers.task import PolcalTaskFlower
|
|
16
|
+
from dkist_processing_common.parsers.task import parse_header_ip_task_with_gains
|
|
16
17
|
from dkist_processing_common.parsers.time import ExposureTimeFlower
|
|
17
18
|
from dkist_processing_common.parsers.time import ObsIpStartTimeBud
|
|
18
19
|
from dkist_processing_common.parsers.time import TaskExposureTimesBud
|
|
@@ -36,7 +37,6 @@ from dkist_processing_dlnirsp.parsers.mosaic import NumMosaicRepeatsBud
|
|
|
36
37
|
from dkist_processing_dlnirsp.parsers.mosaic import NumMosaicXTilesBud
|
|
37
38
|
from dkist_processing_dlnirsp.parsers.mosaic import NumMosaicYTilesBud
|
|
38
39
|
from dkist_processing_dlnirsp.parsers.task import DlnirspTaskTypeFlower
|
|
39
|
-
from dkist_processing_dlnirsp.parsers.task import parse_header_ip_task
|
|
40
40
|
from dkist_processing_dlnirsp.parsers.time import DLnirspSolarGainIpStartTimeBud
|
|
41
41
|
from dkist_processing_dlnirsp.parsers.time import DlnirspTimeObsBud
|
|
42
42
|
from dkist_processing_dlnirsp.parsers.wavelength import ObserveWavelengthBud
|
|
@@ -145,6 +145,11 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
145
145
|
"""Add DLNIRSP specific constants to common constants."""
|
|
146
146
|
return default_constant_bud_factory() + [
|
|
147
147
|
ObserveWavelengthBud(),
|
|
148
|
+
TaskUniqueBud(
|
|
149
|
+
constant_name=DlnirspBudName.obs_ip_end_time.value,
|
|
150
|
+
metadata_key=MetadataKey.ip_end_time,
|
|
151
|
+
ip_task_types=TaskName.observe,
|
|
152
|
+
),
|
|
148
153
|
DLnirspSolarGainIpStartTimeBud(),
|
|
149
154
|
NumCSStepBud(max_cs_step_time_sec=self.parameters.max_cs_step_time_sec),
|
|
150
155
|
UniqueBud(
|
|
@@ -175,42 +180,42 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
175
180
|
TaskExposureTimesBud(
|
|
176
181
|
stem_name=DlnirspBudName.lamp_gain_exposure_times.value,
|
|
177
182
|
ip_task_types=TaskName.lamp_gain.value,
|
|
178
|
-
header_task_parsing_func=
|
|
183
|
+
header_task_parsing_func=parse_header_ip_task_with_gains,
|
|
179
184
|
),
|
|
180
185
|
TaskExposureTimesBud(
|
|
181
186
|
stem_name=DlnirspBudName.solar_gain_exposure_times.value,
|
|
182
187
|
ip_task_types=TaskName.solar_gain.value,
|
|
183
|
-
header_task_parsing_func=
|
|
188
|
+
header_task_parsing_func=parse_header_ip_task_with_gains,
|
|
184
189
|
),
|
|
185
190
|
TaskExposureTimesBud(
|
|
186
191
|
stem_name=DlnirspBudName.observe_exposure_times.value,
|
|
187
192
|
ip_task_types=TaskName.observe.value,
|
|
188
|
-
header_task_parsing_func=
|
|
193
|
+
header_task_parsing_func=parse_header_ip_task_with_gains,
|
|
189
194
|
),
|
|
190
195
|
TaskExposureTimesBud(
|
|
191
196
|
stem_name=DlnirspBudName.polcal_exposure_times.value,
|
|
192
197
|
ip_task_types=TaskName.polcal.value,
|
|
193
|
-
header_task_parsing_func=
|
|
198
|
+
header_task_parsing_func=parse_header_ip_task_with_gains,
|
|
194
199
|
),
|
|
195
200
|
TaskNearFloatBud(
|
|
196
201
|
constant_name=DlnirspBudName.arm_position_mm.value,
|
|
197
202
|
metadata_key=DlnirspMetadataKey.arm_position_mm,
|
|
198
203
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
199
204
|
tolerance=0.01,
|
|
200
|
-
task_type_parsing_function=
|
|
205
|
+
task_type_parsing_function=parse_header_ip_task_with_gains,
|
|
201
206
|
),
|
|
202
207
|
TaskUniqueBud(
|
|
203
208
|
constant_name=DlnirspBudName.grating_constant_inverse_mm.value,
|
|
204
209
|
metadata_key=DlnirspMetadataKey.grating_constant_inverse_mm,
|
|
205
210
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
206
|
-
task_type_parsing_function=
|
|
211
|
+
task_type_parsing_function=parse_header_ip_task_with_gains,
|
|
207
212
|
),
|
|
208
213
|
TaskNearFloatBud(
|
|
209
214
|
constant_name=DlnirspBudName.grating_position_deg.value,
|
|
210
215
|
metadata_key=DlnirspMetadataKey.grating_position_deg,
|
|
211
216
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
212
217
|
tolerance=0.01,
|
|
213
|
-
task_type_parsing_function=
|
|
218
|
+
task_type_parsing_function=parse_header_ip_task_with_gains,
|
|
214
219
|
),
|
|
215
220
|
]
|
|
216
221
|
|
|
@@ -8,6 +8,7 @@ from dkist_processing_common.models.task_name import TaskName
|
|
|
8
8
|
from dkist_processing_common.tasks.mixin.quality import QualityMixin
|
|
9
9
|
from dkist_processing_math.arithmetic import divide_arrays_by_array
|
|
10
10
|
from dkist_processing_math.arithmetic import subtract_array_from_arrays
|
|
11
|
+
from dkist_processing_math.linear_algebra import nd_left_matrix_multiply
|
|
11
12
|
from dkist_processing_math.statistics import average_numpy_arrays
|
|
12
13
|
from dkist_service_configuration.logging import logger
|
|
13
14
|
|
|
@@ -17,8 +18,10 @@ from dkist_processing_dlnirsp.tasks.mixin.corrections import CorrectionsMixin
|
|
|
17
18
|
|
|
18
19
|
__all__ = ["SolarCalibration"]
|
|
19
20
|
|
|
21
|
+
from dkist_processing_dlnirsp.tasks.mixin.group_id import GroupIdMixin
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin, GroupIdMixin):
|
|
22
25
|
"""
|
|
23
26
|
Task for computing an intermediate solar gain image.
|
|
24
27
|
|
|
@@ -33,21 +36,23 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
33
36
|
"""
|
|
34
37
|
Compute a solar gain image with the solar spectrum removed.
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
2. Compute a single characteristic spectrum across all slitbeams and place into the full array
|
|
39
|
-
|
|
40
|
-
3. Re-apply the geometric calibration (spectral shifts and scales) to the characteristic spectra
|
|
41
|
-
|
|
42
|
-
4. Remove the characteristic solar spectra from the dark-corrected solar gain image
|
|
39
|
+
#. Compute dark-only and fully (additional lamp and geometric) corrected solar gain data.
|
|
43
40
|
|
|
44
|
-
|
|
41
|
+
a. For polarimetric data, compute a separate average for each modstate and then demodulate and use the Stokes I data
|
|
42
|
+
#. For intensity data, use the average over all modstates (there should be only one).
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
#. Compute a single characteristic spectrum across all slitbeams and place into the full array
|
|
45
|
+
#. Re-apply the geometric calibration (spectral shifts and scales) to the characteristic spectra
|
|
46
|
+
#. Remove the characteristic solar spectra from the dark-corrected solar gain image
|
|
47
|
+
#. Rescale each slitbeam to have the same average value as the raw, dark corrected solar gain image
|
|
48
|
+
#. Write the final, solar-spectrum-removed solar gain image.
|
|
47
49
|
"""
|
|
48
50
|
with self.telemetry_span("Apply dark and lamp corrections"):
|
|
49
51
|
logger.info("Computing average dark/lamp corrected gains")
|
|
50
|
-
self.
|
|
52
|
+
if self.constants.correct_for_polarization:
|
|
53
|
+
self.compute_demodulated_I_gains()
|
|
54
|
+
else:
|
|
55
|
+
self.compute_intensity_only_avg_gains()
|
|
51
56
|
|
|
52
57
|
with self.telemetry_span("Compute characteristic spectra"):
|
|
53
58
|
logger.info("Computing characteristic spectra")
|
|
@@ -81,9 +86,12 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
81
86
|
|
|
82
87
|
with self.telemetry_span("Write solar flat calibration"):
|
|
83
88
|
logger.info("Writing solar flat calibration")
|
|
89
|
+
tags = [DlnirspTag.intermediate_frame(), DlnirspTag.task_solar_gain()]
|
|
90
|
+
if self.constants.correct_for_polarization:
|
|
91
|
+
tags.append(DlnirspTag.stokes("I"))
|
|
84
92
|
self.write(
|
|
85
93
|
data=cleaned_gain,
|
|
86
|
-
tags=
|
|
94
|
+
tags=tags,
|
|
87
95
|
encoder=fits_array_encoder,
|
|
88
96
|
)
|
|
89
97
|
|
|
@@ -96,13 +104,110 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
96
104
|
task_type=TaskName.solar_gain.value, total_frames=no_of_raw_solar_frames
|
|
97
105
|
)
|
|
98
106
|
|
|
99
|
-
def
|
|
107
|
+
def compute_intensity_only_avg_gains(self):
|
|
108
|
+
"""
|
|
109
|
+
Compute dark-only and fully-corrected average solar gains for intensity mode data.
|
|
110
|
+
|
|
111
|
+
The raw solar gain frames are averaged over all modstates (of which there should only be one anyway).
|
|
112
|
+
The lamp-corrected data also have geometric corrections applied prior to saving.
|
|
113
|
+
"""
|
|
114
|
+
dark_corr, lamp_corr = self.compute_average_corrected_gain_for_modstate(modstate=None)
|
|
115
|
+
|
|
116
|
+
# This is the array we remove the characteristic solar spectrum from to produce the final gain array
|
|
117
|
+
self.write(
|
|
118
|
+
data=dark_corr,
|
|
119
|
+
tags=[DlnirspTag.intermediate_frame(), DlnirspTag.task("SC_DARK_ONLY")],
|
|
120
|
+
encoder=fits_array_encoder,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
geo_corr_gain = self.apply_geometric_correction(lamp_corr)
|
|
124
|
+
|
|
125
|
+
self.write(
|
|
126
|
+
data=geo_corr_gain,
|
|
127
|
+
tags=[DlnirspTag.intermediate_frame(), DlnirspTag.task("SC_FULL_CORR")],
|
|
128
|
+
encoder=fits_array_encoder,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def compute_demodulated_I_gains(self):
|
|
132
|
+
"""
|
|
133
|
+
Compute demodulated dark-only and fully-corrected solar gain data.
|
|
134
|
+
|
|
135
|
+
The raw solar gains are averaged once for each modstate before having dark and lamp corrections applied.
|
|
136
|
+
These two sets of arrays (dark-only and dark + lamp) are then demodulated. The resulting Stokes I are then saved
|
|
137
|
+
to disk for later use. The lamp-corrected data have a geometric correction applied prior to saving.
|
|
138
|
+
"""
|
|
139
|
+
dark_corr_modstate_stack = np.empty(
|
|
140
|
+
self.unrectified_array_shape + (self.constants.num_modstates,)
|
|
141
|
+
)
|
|
142
|
+
lamp_corr_modstate_stack = np.empty_like(dark_corr_modstate_stack)
|
|
143
|
+
for modstate in range(1, self.constants.num_modstates + 1):
|
|
144
|
+
dark_corr, lamp_corr = self.compute_average_corrected_gain_for_modstate(modstate)
|
|
145
|
+
dark_corr_modstate_stack[:, :, modstate - 1] = dark_corr
|
|
146
|
+
lamp_corr_modstate_stack[:, :, modstate - 1] = lamp_corr
|
|
147
|
+
|
|
148
|
+
logger.info("Loading demodulation matrices")
|
|
149
|
+
demod_matrices = next(
|
|
150
|
+
self.read(
|
|
151
|
+
tags=[DlnirspTag.intermediate_frame(), DlnirspTag.task_demodulation_matrices()],
|
|
152
|
+
decoder=fits_array_decoder,
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
demodulated_dark_corr_gain = nd_left_matrix_multiply(
|
|
157
|
+
vector_stack=dark_corr_modstate_stack, matrix_stack=demod_matrices
|
|
158
|
+
)
|
|
159
|
+
demodulated_lamp_corr_gain = nd_left_matrix_multiply(
|
|
160
|
+
vector_stack=lamp_corr_modstate_stack, matrix_stack=demod_matrices
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
dark_corr_I = demodulated_dark_corr_gain[:, :, 0]
|
|
164
|
+
lamp_corr_I = demodulated_lamp_corr_gain[:, :, 0]
|
|
165
|
+
|
|
166
|
+
# This is the array we remove the characteristic solar spectrum from to produce the final gain array
|
|
167
|
+
self.write(
|
|
168
|
+
data=dark_corr_I,
|
|
169
|
+
tags=[
|
|
170
|
+
DlnirspTag.intermediate_frame(),
|
|
171
|
+
DlnirspTag.task("SC_DARK_ONLY"),
|
|
172
|
+
DlnirspTag.stokes("I"),
|
|
173
|
+
],
|
|
174
|
+
encoder=fits_array_encoder,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
geo_corr_gain = self.apply_geometric_correction(lamp_corr_I)
|
|
178
|
+
|
|
179
|
+
self.write(
|
|
180
|
+
data=geo_corr_gain,
|
|
181
|
+
tags=[
|
|
182
|
+
DlnirspTag.intermediate_frame(),
|
|
183
|
+
DlnirspTag.task("SC_FULL_CORR"),
|
|
184
|
+
DlnirspTag.stokes("I"),
|
|
185
|
+
],
|
|
186
|
+
encoder=fits_array_encoder,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def compute_average_corrected_gain_for_modstate(
|
|
190
|
+
self, modstate: int | None
|
|
191
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
100
192
|
"""
|
|
101
|
-
Compute a single, averaged frame from all linearized solar gain frames.
|
|
193
|
+
Compute a single, averaged frame from all linearized solar gain frames for a given modstate.
|
|
102
194
|
|
|
103
|
-
Also apply dark
|
|
195
|
+
Also apply dark and lamp corrections. If there are multiple exposure times present in the solar
|
|
104
196
|
gain images, all frames for a single exposure time are averged prior to dark correction. Then all averaged
|
|
105
197
|
exposure time frames are averaged again into a single frame.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
modstate
|
|
202
|
+
The modstate to average over. If `None` then the average is performed over all modstates.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
dark_corrected
|
|
207
|
+
The average solar gains with only a dark correction applied
|
|
208
|
+
|
|
209
|
+
lamp_corrected
|
|
210
|
+
The average solar gains with both dark and lamp corrections applied
|
|
106
211
|
"""
|
|
107
212
|
all_exp_times = []
|
|
108
213
|
for exp_time in self.constants.solar_gain_exposure_times:
|
|
@@ -114,12 +219,14 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
114
219
|
)
|
|
115
220
|
)
|
|
116
221
|
|
|
117
|
-
logger.info(f"Loading solar gain frames for {exp_time = }")
|
|
222
|
+
logger.info(f"Loading solar gain frames for {modstate = } and {exp_time = }")
|
|
118
223
|
tags = [
|
|
119
224
|
DlnirspTag.linearized_frame(),
|
|
120
225
|
DlnirspTag.task_solar_gain(),
|
|
121
226
|
DlnirspTag.exposure_time(exp_time),
|
|
122
227
|
]
|
|
228
|
+
if modstate is not None:
|
|
229
|
+
tags.append(DlnirspTag.modstate(modstate))
|
|
123
230
|
gain_arrays = self.read(tags=tags, decoder=fits_array_decoder)
|
|
124
231
|
|
|
125
232
|
logger.info("Averaging solar gain frames")
|
|
@@ -135,13 +242,6 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
135
242
|
logger.info(f"Computing final average gain array for {len(all_exp_times)} exposure times")
|
|
136
243
|
avg_gain_array = average_numpy_arrays(all_exp_times)
|
|
137
244
|
|
|
138
|
-
# This is the array we remove the characteristic solar spectrum from to produce the final gain array
|
|
139
|
-
self.write(
|
|
140
|
-
data=avg_gain_array,
|
|
141
|
-
tags=[DlnirspTag.intermediate_frame(), DlnirspTag.task("SC_DARK_ONLY")],
|
|
142
|
-
encoder=fits_array_encoder,
|
|
143
|
-
)
|
|
144
|
-
|
|
145
245
|
logger.info("Loading lamp calibration")
|
|
146
246
|
lamp_array = next(
|
|
147
247
|
self.read(
|
|
@@ -155,8 +255,11 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
155
255
|
divide_arrays_by_array(arrays=avg_gain_array, array_to_divide_by=lamp_array)
|
|
156
256
|
)
|
|
157
257
|
|
|
158
|
-
|
|
258
|
+
return avg_gain_array, lamp_corrected_array
|
|
159
259
|
|
|
260
|
+
def apply_geometric_correction(self, array: np.ndarray) -> np.ndarray:
|
|
261
|
+
"""Apply the geometric correction to an array."""
|
|
262
|
+
logger.info("Loading geometric calibration")
|
|
160
263
|
geometric_correction = next(
|
|
161
264
|
self.read(
|
|
162
265
|
tags=[DlnirspTag.intermediate(), DlnirspTag.task_geometric()], decoder=asdf_decoder
|
|
@@ -169,7 +272,7 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
169
272
|
logger.info("Applying geometric calibration")
|
|
170
273
|
final_gain_array = next(
|
|
171
274
|
self.corrections_remove_spec_geometry(
|
|
172
|
-
arrays=
|
|
275
|
+
arrays=array,
|
|
173
276
|
shift_dict=shifts,
|
|
174
277
|
scale_dict=scales,
|
|
175
278
|
reference_wavelength_axis=reference_wavelength_axis,
|
|
@@ -177,11 +280,7 @@ class SolarCalibration(DlnirspTaskBase, CorrectionsMixin, QualityMixin):
|
|
|
177
280
|
)
|
|
178
281
|
)
|
|
179
282
|
|
|
180
|
-
|
|
181
|
-
data=final_gain_array,
|
|
182
|
-
tags=[DlnirspTag.intermediate_frame(), DlnirspTag.task("SC_FULL_CORR")],
|
|
183
|
-
encoder=fits_array_encoder,
|
|
184
|
-
)
|
|
283
|
+
return final_gain_array
|
|
185
284
|
|
|
186
285
|
def compute_characteristic_spectra(self) -> np.ndarray:
|
|
187
286
|
"""
|
|
@@ -170,12 +170,23 @@ class DlnirspTestingParameters:
|
|
|
170
170
|
dlnirsp_bad_pixel_correction_interpolation_kernel_shape: tuple[int, int] = (10, 3)
|
|
171
171
|
dlnirsp_wcs_pc_correction_matrix: tuple[tuple[int]] = ((1, 0), (0, -1))
|
|
172
172
|
dlnirsp_wcs_crpix_correction_method: str = "swap_then_flip_crpix2"
|
|
173
|
+
dlnirsp_movie_core_wave_value_nm_vis: float = 853.98
|
|
174
|
+
dlnirsp_movie_core_wave_value_nm_jband: float = 1083.0
|
|
175
|
+
dlnirsp_movie_core_wave_value_nm_hband: float = 1564.8
|
|
176
|
+
dlnirsp_movie_cont_wave_value_nm_vis: float = 854.23
|
|
177
|
+
dlnirsp_movie_cont_wave_value_nm_jband: float = 1083.268
|
|
178
|
+
dlnirsp_movie_cont_wave_value_nm_hband: float = 1565.06
|
|
179
|
+
dlnirsp_movie_vertical_nan_slices: list[list[int | None]] = field(
|
|
180
|
+
default_factory=lambda: [[None, 1], [31, 34], [-2, None]]
|
|
181
|
+
)
|
|
182
|
+
dlnirsp_movie_nan_replacement_kernel_shape: tuple[int, int] = (5, 5)
|
|
173
183
|
|
|
174
184
|
|
|
175
185
|
@dataclass
|
|
176
186
|
class DlnirspTestingConstants:
|
|
177
187
|
INSTRUMENT: str = "DLNIRSP"
|
|
178
|
-
OBS_IP_START_TIME: str = "2024-06-
|
|
188
|
+
OBS_IP_START_TIME: str = "2024-06-06T00:00:00"
|
|
189
|
+
OBS_IP_END_TIME: str = "2024-06-06T00:10:00"
|
|
179
190
|
ARM_ID: str = "HBand"
|
|
180
191
|
NUM_MODSTATES: int = 8
|
|
181
192
|
NUM_MOSAIC_TILES_X: int = 2
|
|
@@ -204,6 +215,7 @@ class DlnirspTestingConstants:
|
|
|
204
215
|
"EXPERID2",
|
|
205
216
|
"EXPERID3",
|
|
206
217
|
)
|
|
218
|
+
EXPERIMENT_ID: str = "eid_6_28"
|
|
207
219
|
ARM_POSITION_MM: float = -4.2
|
|
208
220
|
GRATING_CONSTANT_INVERSE_MM: float = 20.0
|
|
209
221
|
GRATING_POSITION_DEG: float = 87.4
|
|
@@ -1229,6 +1241,8 @@ class CalibratedHeaders(ModulatedObserveHeaders):
|
|
|
1229
1241
|
is_polarimetric: bool,
|
|
1230
1242
|
dither_mode_on: bool = False,
|
|
1231
1243
|
array_shape: tuple[int, int, int] = (3, 4, 5),
|
|
1244
|
+
crpix1_step_delta: float = 40.0,
|
|
1245
|
+
crpix2_step_delta: float = 30.0,
|
|
1232
1246
|
):
|
|
1233
1247
|
|
|
1234
1248
|
# Use the data_cycles loop to represent Stokes parameters
|
|
@@ -1246,6 +1260,8 @@ class CalibratedHeaders(ModulatedObserveHeaders):
|
|
|
1246
1260
|
allow_3D_arrays=True,
|
|
1247
1261
|
)
|
|
1248
1262
|
|
|
1263
|
+
self.crpix1_step_delta = crpix1_step_delta
|
|
1264
|
+
self.crpix2_step_delta = crpix2_step_delta
|
|
1249
1265
|
self.stokes_name_list = ["I", "Q", "U", "V"]
|
|
1250
1266
|
self.add_constant_key("DLN__014", 8 if is_polarimetric else 1)
|
|
1251
1267
|
self.add_constant_key("DLN__008", "Full Stokes" if is_polarimetric else "Stokes I")
|
|
@@ -1263,12 +1279,21 @@ class CalibratedHeaders(ModulatedObserveHeaders):
|
|
|
1263
1279
|
) # -1 b/c data cycles are indexed from 1
|
|
1264
1280
|
return self.stokes_name_list[stokes_axis_id]
|
|
1265
1281
|
|
|
1282
|
+
@property
|
|
1283
|
+
def current_crpix1(self) -> float:
|
|
1284
|
+
return self.array_shape[2] / 2 - self.crpix1_step_delta * self.current_MINDEX1_value
|
|
1285
|
+
|
|
1286
|
+
@property
|
|
1287
|
+
def current_crpix2(self) -> float:
|
|
1288
|
+
return self.array_shape[1] / 2 - self.crpix2_step_delta * self.current_MINDEX2_value
|
|
1289
|
+
|
|
1266
1290
|
@property
|
|
1267
1291
|
def fits_wcs(self):
|
|
1292
|
+
# Taken from real data from eid_2_24
|
|
1268
1293
|
w = WCS(naxis=3)
|
|
1269
|
-
w.wcs.crpix = self.
|
|
1270
|
-
w.wcs.crval =
|
|
1271
|
-
w.wcs.cdelt =
|
|
1294
|
+
w.wcs.crpix = self.current_crpix1, self.current_crpix2, self.array_shape[0] / 2
|
|
1295
|
+
w.wcs.crval = 176.118, -289.575, 1565.0
|
|
1296
|
+
w.wcs.cdelt = 0.031, 0.031, 0.2
|
|
1272
1297
|
w.wcs.cunit = "arcsec", "arcsec", "nm"
|
|
1273
1298
|
w.wcs.ctype = "HPLN-TAN", "HPLT-TAN", "AWAV"
|
|
1274
1299
|
w.wcs.pc = np.identity(self.array_ndim)
|
|
@@ -1342,6 +1367,15 @@ def make_cs_data(
|
|
|
1342
1367
|
return data
|
|
1343
1368
|
|
|
1344
1369
|
|
|
1370
|
+
@pytest.fixture
|
|
1371
|
+
def make_full_demodulation_matrix(demodulation_matrix):
|
|
1372
|
+
def make_array(frame: Spec122Dataset):
|
|
1373
|
+
array_shape = frame.array_shape[1:]
|
|
1374
|
+
return np.ones(array_shape + demodulation_matrix.shape) * demodulation_matrix
|
|
1375
|
+
|
|
1376
|
+
return make_array
|
|
1377
|
+
|
|
1378
|
+
|
|
1345
1379
|
def tag_on_modstate(frame: Spec122Dataset) -> list[str]:
|
|
1346
1380
|
modstate = frame.header()["DLN__015"]
|
|
1347
1381
|
return [DlnirspTag.modstate(modstate)]
|
|
@@ -1631,11 +1665,12 @@ def write_observe_frames_to_task(
|
|
|
1631
1665
|
array_shape: tuple[int, int] = (10, 10),
|
|
1632
1666
|
crpix_delta: tuple[float, float] = (80.3, 20.7),
|
|
1633
1667
|
swap_crpix_values: bool = False,
|
|
1668
|
+
start_date: str = "2023-01-01T01:23:45",
|
|
1669
|
+
modstate_length_sec: float = 0.5,
|
|
1634
1670
|
data_func: callable = make_random_data,
|
|
1635
1671
|
tags: list[str] | None = None,
|
|
1636
1672
|
tag_func: callable = lambda x: [],
|
|
1637
1673
|
) -> int:
|
|
1638
|
-
|
|
1639
1674
|
frame_generator = ModulatedObserveHeaders(
|
|
1640
1675
|
num_modstates=num_modstates,
|
|
1641
1676
|
num_X_tiles=num_X_tiles,
|
|
@@ -1650,6 +1685,8 @@ def write_observe_frames_to_task(
|
|
|
1650
1685
|
grating_angle=grating_angle,
|
|
1651
1686
|
crpix_delta=crpix_delta,
|
|
1652
1687
|
swap_crpix_values=swap_crpix_values,
|
|
1688
|
+
start_date=start_date,
|
|
1689
|
+
modstate_length_sec=modstate_length_sec,
|
|
1653
1690
|
)
|
|
1654
1691
|
|
|
1655
1692
|
num_frames = write_frames_to_task(
|
|
@@ -1700,7 +1737,7 @@ def write_calibrated_frames_to_task(
|
|
|
1700
1737
|
is_polarimetric: bool,
|
|
1701
1738
|
array_shape: tuple[int, int, int],
|
|
1702
1739
|
dither_mode_on: bool = False,
|
|
1703
|
-
data_func:
|
|
1740
|
+
data_func: Callable = make_3D_random_data,
|
|
1704
1741
|
):
|
|
1705
1742
|
dataset = CalibratedHeaders(
|
|
1706
1743
|
num_mosaics=num_mosaics,
|
|
@@ -13,11 +13,10 @@ from dkist_processing_common.tasks import WorkflowTaskBase
|
|
|
13
13
|
from dkist_service_configuration.logging import logger
|
|
14
14
|
|
|
15
15
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
16
|
-
from dkist_processing_dlnirsp.tasks import AssembleDlnirspMovie
|
|
17
16
|
from dkist_processing_dlnirsp.tasks import DlnirspAssembleQualityData
|
|
18
17
|
from dkist_processing_dlnirsp.tasks import DlnirspL0QualityMetrics
|
|
19
18
|
from dkist_processing_dlnirsp.tasks import DlnirspL1QualityMetrics
|
|
20
|
-
from dkist_processing_dlnirsp.tasks import
|
|
19
|
+
from dkist_processing_dlnirsp.tasks import MakeDlnirspMovie
|
|
21
20
|
from dkist_processing_dlnirsp.tasks.bad_pixel_map import BadPixelCalibration
|
|
22
21
|
from dkist_processing_dlnirsp.tasks.dark import DarkCalibration
|
|
23
22
|
from dkist_processing_dlnirsp.tasks.geometric import GeometricCalibration
|
|
@@ -197,10 +196,11 @@ def main(
|
|
|
197
196
|
load_bad_pixel: bool = False,
|
|
198
197
|
load_geometric: bool = False,
|
|
199
198
|
load_wavelength_calibration: bool = False,
|
|
200
|
-
load_solar: bool = False,
|
|
201
199
|
load_inst_polcal: bool = False,
|
|
200
|
+
load_solar: bool = False,
|
|
202
201
|
load_polcals_as_science: bool = False,
|
|
203
202
|
load_calibrated_data: bool = False,
|
|
203
|
+
skip_movie: bool = False,
|
|
204
204
|
transfer_trial_data: str | None = None,
|
|
205
205
|
):
|
|
206
206
|
with ManualProcessing(
|
|
@@ -298,18 +298,18 @@ def main(
|
|
|
298
298
|
manual_processing_run.run_task(task=WavelengthCalibration)
|
|
299
299
|
manual_processing_run.run_task(task=SaveWavelengthCal)
|
|
300
300
|
|
|
301
|
-
if load_solar:
|
|
302
|
-
manual_processing_run.run_task(task=LoadSolarCal)
|
|
303
|
-
else:
|
|
304
|
-
manual_processing_run.run_task(task=SolarCalibration)
|
|
305
|
-
manual_processing_run.run_task(task=SaveSolarCal)
|
|
306
|
-
|
|
307
301
|
if load_inst_polcal:
|
|
308
302
|
manual_processing_run.run_task(task=LoadInstPolCal)
|
|
309
303
|
else:
|
|
310
304
|
manual_processing_run.run_task(task=InstrumentPolarizationCalibration)
|
|
311
305
|
manual_processing_run.run_task(task=SaveInstPolCal)
|
|
312
306
|
|
|
307
|
+
if load_solar:
|
|
308
|
+
manual_processing_run.run_task(task=LoadSolarCal)
|
|
309
|
+
else:
|
|
310
|
+
manual_processing_run.run_task(task=SolarCalibration)
|
|
311
|
+
manual_processing_run.run_task(task=SaveSolarCal)
|
|
312
|
+
|
|
313
313
|
if load_polcals_as_science:
|
|
314
314
|
manual_processing_run.run_task(task=LoadPolCalAsScience)
|
|
315
315
|
else:
|
|
@@ -324,8 +324,6 @@ def main(
|
|
|
324
324
|
|
|
325
325
|
manual_processing_run.run_task(task=permissive_write_l1_task(force_intensity_only=False))
|
|
326
326
|
manual_processing_run.run_task(task=ValidateL1Output)
|
|
327
|
-
manual_processing_run.run_task(task=MakeDlnirspMovieFrames)
|
|
328
|
-
manual_processing_run.run_task(task=AssembleDlnirspMovie)
|
|
329
327
|
|
|
330
328
|
manual_processing_run.run_task(task=DlnirspL0QualityMetrics)
|
|
331
329
|
manual_processing_run.run_task(task=DlnirspL1QualityMetrics)
|
|
@@ -334,6 +332,9 @@ def main(
|
|
|
334
332
|
|
|
335
333
|
manual_processing_run.run_task(task=CreateTrialQualityReport)
|
|
336
334
|
|
|
335
|
+
if not skip_movie:
|
|
336
|
+
manual_processing_run.run_task(task=MakeDlnirspMovie)
|
|
337
|
+
|
|
337
338
|
if transfer_trial_data:
|
|
338
339
|
transfer_trial_data_locally(
|
|
339
340
|
trial_output_location=transfer_trial_data, processing_run=manual_processing_run
|
|
@@ -425,18 +426,18 @@ if __name__ == "__main__":
|
|
|
425
426
|
help="Load wavelength calibration solution from previously saved run",
|
|
426
427
|
action="store_true",
|
|
427
428
|
)
|
|
428
|
-
parser.add_argument(
|
|
429
|
-
"-S",
|
|
430
|
-
"--load-solar",
|
|
431
|
-
help="Load solar calibration from previously saved run",
|
|
432
|
-
action="store_true",
|
|
433
|
-
)
|
|
434
429
|
parser.add_argument(
|
|
435
430
|
"-P",
|
|
436
431
|
"--load-inst-polcal",
|
|
437
432
|
help="Load instrument polarization calibration from previously saved run",
|
|
438
433
|
action="store_true",
|
|
439
434
|
)
|
|
435
|
+
parser.add_argument(
|
|
436
|
+
"-S",
|
|
437
|
+
"--load-solar",
|
|
438
|
+
help="Load solar calibration from previously saved run",
|
|
439
|
+
action="store_true",
|
|
440
|
+
)
|
|
440
441
|
parser.add_argument(
|
|
441
442
|
"-O",
|
|
442
443
|
"--load-polcals-as-science",
|
|
@@ -446,6 +447,7 @@ if __name__ == "__main__":
|
|
|
446
447
|
parser.add_argument(
|
|
447
448
|
"-C", "--load-calibrated-data", help="Load CALIBRATED 'science' frames", action="store_true"
|
|
448
449
|
)
|
|
450
|
+
parser.add_argument("-V", "--skip-movie", help="Don't make a browse movie", action="store_true")
|
|
449
451
|
parser.add_argument(
|
|
450
452
|
"-p",
|
|
451
453
|
"--param-dir",
|
|
@@ -472,10 +474,11 @@ if __name__ == "__main__":
|
|
|
472
474
|
load_bad_pixel=args.load_bad_pixel,
|
|
473
475
|
load_geometric=args.load_geometric,
|
|
474
476
|
load_wavelength_calibration=args.load_wavelength_calibration,
|
|
475
|
-
load_solar=args.load_solar,
|
|
476
477
|
load_inst_polcal=args.load_inst_polcal,
|
|
478
|
+
load_solar=args.load_solar,
|
|
477
479
|
load_polcals_as_science=args.load_polcals_as_science,
|
|
478
480
|
load_calibrated_data=args.load_calibrated_data,
|
|
481
|
+
skip_movie=args.skip_movie,
|
|
479
482
|
transfer_trial_data=args.transfer_trial_data,
|
|
480
483
|
)
|
|
481
484
|
)
|
|
@@ -13,11 +13,10 @@ from dkist_processing_common.tasks import WorkflowTaskBase
|
|
|
13
13
|
from dkist_service_configuration.logging import logger
|
|
14
14
|
|
|
15
15
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
16
|
-
from dkist_processing_dlnirsp.tasks import AssembleDlnirspMovie
|
|
17
16
|
from dkist_processing_dlnirsp.tasks import DlnirspAssembleQualityData
|
|
18
17
|
from dkist_processing_dlnirsp.tasks import DlnirspL0QualityMetrics
|
|
19
18
|
from dkist_processing_dlnirsp.tasks import DlnirspL1QualityMetrics
|
|
20
|
-
from dkist_processing_dlnirsp.tasks import
|
|
19
|
+
from dkist_processing_dlnirsp.tasks import MakeDlnirspMovie
|
|
21
20
|
from dkist_processing_dlnirsp.tasks.bad_pixel_map import BadPixelCalibration
|
|
22
21
|
from dkist_processing_dlnirsp.tasks.dark import DarkCalibration
|
|
23
22
|
from dkist_processing_dlnirsp.tasks.geometric import GeometricCalibration
|
|
@@ -203,10 +202,11 @@ def main(
|
|
|
203
202
|
load_bad_pixel: bool = False,
|
|
204
203
|
load_geometric: bool = False,
|
|
205
204
|
load_wavelength_calibration: bool = False,
|
|
206
|
-
load_solar: bool = False,
|
|
207
205
|
load_inst_polcal: bool = False,
|
|
206
|
+
load_solar: bool = False,
|
|
208
207
|
load_solar_gain_as_science: bool = False,
|
|
209
208
|
load_calibrated_data: bool = False,
|
|
209
|
+
skip_movie: bool = False,
|
|
210
210
|
force_intensity_only: bool = False,
|
|
211
211
|
transfer_trial_data: str | None = None,
|
|
212
212
|
):
|
|
@@ -305,18 +305,18 @@ def main(
|
|
|
305
305
|
manual_processing_run.run_task(task=WavelengthCalibration)
|
|
306
306
|
manual_processing_run.run_task(task=SaveWavelengthCal)
|
|
307
307
|
|
|
308
|
-
if load_solar:
|
|
309
|
-
manual_processing_run.run_task(task=LoadSolarCal)
|
|
310
|
-
else:
|
|
311
|
-
manual_processing_run.run_task(task=SolarCalibration)
|
|
312
|
-
manual_processing_run.run_task(task=SaveSolarCal)
|
|
313
|
-
|
|
314
308
|
if load_inst_polcal:
|
|
315
309
|
manual_processing_run.run_task(task=LoadInstPolCal)
|
|
316
310
|
else:
|
|
317
311
|
manual_processing_run.run_task(task=InstrumentPolarizationCalibration)
|
|
318
312
|
manual_processing_run.run_task(task=SaveInstPolCal)
|
|
319
313
|
|
|
314
|
+
if load_solar:
|
|
315
|
+
manual_processing_run.run_task(task=LoadSolarCal)
|
|
316
|
+
else:
|
|
317
|
+
manual_processing_run.run_task(task=SolarCalibration)
|
|
318
|
+
manual_processing_run.run_task(task=SaveSolarCal)
|
|
319
|
+
|
|
320
320
|
if load_solar_gain_as_science:
|
|
321
321
|
manual_processing_run.run_task(
|
|
322
322
|
task=load_solar_gain_as_science_task(force_intensity_only=force_intensity_only)
|
|
@@ -338,8 +338,6 @@ def main(
|
|
|
338
338
|
task=permissive_write_l1_task(force_intensity_only=force_intensity_only)
|
|
339
339
|
)
|
|
340
340
|
manual_processing_run.run_task(task=ValidateL1Output)
|
|
341
|
-
manual_processing_run.run_task(task=MakeDlnirspMovieFrames)
|
|
342
|
-
manual_processing_run.run_task(task=AssembleDlnirspMovie)
|
|
343
341
|
|
|
344
342
|
manual_processing_run.run_task(task=DlnirspL0QualityMetrics)
|
|
345
343
|
manual_processing_run.run_task(task=DlnirspL1QualityMetrics)
|
|
@@ -348,6 +346,9 @@ def main(
|
|
|
348
346
|
|
|
349
347
|
manual_processing_run.run_task(task=CreateTrialQualityReport)
|
|
350
348
|
|
|
349
|
+
if not skip_movie:
|
|
350
|
+
manual_processing_run.run_task(task=MakeDlnirspMovie)
|
|
351
|
+
|
|
351
352
|
if transfer_trial_data:
|
|
352
353
|
transfer_trial_data_locally(
|
|
353
354
|
trial_output_location=transfer_trial_data, processing_run=manual_processing_run
|
|
@@ -444,18 +445,18 @@ if __name__ == "__main__":
|
|
|
444
445
|
help="Load wavelength calibration solution from previously saved run",
|
|
445
446
|
action="store_true",
|
|
446
447
|
)
|
|
447
|
-
parser.add_argument(
|
|
448
|
-
"-S",
|
|
449
|
-
"--load-solar",
|
|
450
|
-
help="Load solar calibration from previously saved run",
|
|
451
|
-
action="store_true",
|
|
452
|
-
)
|
|
453
448
|
parser.add_argument(
|
|
454
449
|
"-P",
|
|
455
450
|
"--load-inst-polcal",
|
|
456
451
|
help="Load instrument polarization calibration from previously saved run",
|
|
457
452
|
action="store_true",
|
|
458
453
|
)
|
|
454
|
+
parser.add_argument(
|
|
455
|
+
"-S",
|
|
456
|
+
"--load-solar",
|
|
457
|
+
help="Load solar calibration from previously saved run",
|
|
458
|
+
action="store_true",
|
|
459
|
+
)
|
|
459
460
|
parser.add_argument(
|
|
460
461
|
"-O",
|
|
461
462
|
"--load-solar-gain-as-science",
|
|
@@ -465,6 +466,7 @@ if __name__ == "__main__":
|
|
|
465
466
|
parser.add_argument(
|
|
466
467
|
"-C", "--load-calibrated-data", help="Load CALIBRATED 'science' frames", action="store_true"
|
|
467
468
|
)
|
|
469
|
+
parser.add_argument("-V", "--skip-movie", help="Don't make a browse movie", action="store_true")
|
|
468
470
|
parser.add_argument(
|
|
469
471
|
"-p",
|
|
470
472
|
"--param-dir",
|
|
@@ -491,10 +493,11 @@ if __name__ == "__main__":
|
|
|
491
493
|
load_bad_pixel=args.load_bad_pixel,
|
|
492
494
|
load_geometric=args.load_geometric,
|
|
493
495
|
load_wavelength_calibration=args.load_wavelength_calibration,
|
|
494
|
-
load_solar=args.load_solar,
|
|
495
496
|
load_inst_polcal=args.load_inst_polcal,
|
|
497
|
+
load_solar=args.load_solar,
|
|
496
498
|
load_solar_gain_as_science=args.load_solar_gain_as_science,
|
|
497
499
|
load_calibrated_data=args.load_calibrated_data,
|
|
500
|
+
skip_movie=args.skip_movie,
|
|
498
501
|
force_intensity_only=args.force_I_only,
|
|
499
502
|
transfer_trial_data=args.transfer_trial_data,
|
|
500
503
|
)
|