dkist-processing-cryonirsp 1.4.14__py3-none-any.whl → 1.4.16rc1__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.
Potentially problematic release.
This version of dkist-processing-cryonirsp might be problematic. Click here for more details.
- changelog/170.feature.rst +11 -0
- changelog/170.misc.1.rst +2 -0
- changelog/170.misc.rst +3 -0
- changelog/174.bugfix.rst +1 -0
- dkist_processing_cryonirsp/codecs/__init__.py +5 -0
- dkist_processing_cryonirsp/codecs/fits.py +52 -0
- dkist_processing_cryonirsp/models/beam_boundaries.py +39 -0
- dkist_processing_cryonirsp/models/parameters.py +0 -1
- dkist_processing_cryonirsp/models/tags.py +34 -0
- dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +38 -2
- dkist_processing_cryonirsp/parsers/exposure_conditions.py +5 -3
- dkist_processing_cryonirsp/tasks/assemble_movie.py +2 -2
- dkist_processing_cryonirsp/tasks/bad_pixel_map.py +14 -9
- dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +24 -43
- dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +1 -1
- dkist_processing_cryonirsp/tasks/ci_science.py +24 -6
- dkist_processing_cryonirsp/tasks/cryonirsp_base.py +0 -10
- dkist_processing_cryonirsp/tasks/dark.py +34 -14
- dkist_processing_cryonirsp/tasks/gain.py +69 -22
- dkist_processing_cryonirsp/tasks/instrument_polarization.py +131 -49
- dkist_processing_cryonirsp/tasks/l1_output_data.py +0 -1
- dkist_processing_cryonirsp/tasks/linearity_correction.py +4 -7
- dkist_processing_cryonirsp/tasks/make_movie_frames.py +5 -5
- dkist_processing_cryonirsp/tasks/quality_metrics.py +4 -4
- dkist_processing_cryonirsp/tasks/science_base.py +34 -10
- dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +1 -1
- dkist_processing_cryonirsp/tasks/sp_dispersion_axis_correction.py +14 -6
- dkist_processing_cryonirsp/tasks/sp_geometric.py +112 -39
- dkist_processing_cryonirsp/tasks/sp_science.py +53 -11
- dkist_processing_cryonirsp/tasks/sp_solar_gain.py +108 -29
- dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +2 -10
- dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +8 -11
- dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +1 -1
- dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +1 -2
- dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +6 -5
- dkist_processing_cryonirsp/tests/test_ci_science.py +25 -24
- dkist_processing_cryonirsp/tests/test_cryo_base.py +41 -43
- dkist_processing_cryonirsp/tests/test_dark.py +20 -28
- dkist_processing_cryonirsp/tests/test_gain.py +46 -35
- dkist_processing_cryonirsp/tests/test_instrument_polarization.py +22 -16
- dkist_processing_cryonirsp/tests/test_linearity_correction.py +1 -4
- dkist_processing_cryonirsp/tests/test_parse.py +41 -0
- dkist_processing_cryonirsp/tests/test_quality.py +1 -2
- dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +6 -5
- dkist_processing_cryonirsp/tests/test_sp_dispersion_axis_correction.py +10 -9
- dkist_processing_cryonirsp/tests/test_sp_geometric.py +108 -53
- dkist_processing_cryonirsp/tests/test_sp_science.py +49 -35
- dkist_processing_cryonirsp/tests/test_sp_solar.py +70 -38
- {dkist_processing_cryonirsp-1.4.14.dist-info → dkist_processing_cryonirsp-1.4.16rc1.dist-info}/METADATA +2 -2
- {dkist_processing_cryonirsp-1.4.14.dist-info → dkist_processing_cryonirsp-1.4.16rc1.dist-info}/RECORD +52 -48
- dkist_processing_cryonirsp/tasks/mixin/beam_access.py +0 -52
- dkist_processing_cryonirsp/tasks/mixin/intermediate_frame.py +0 -193
- dkist_processing_cryonirsp/tasks/mixin/linearized_frame.py +0 -309
- {dkist_processing_cryonirsp-1.4.14.dist-info → dkist_processing_cryonirsp-1.4.16rc1.dist-info}/WHEEL +0 -0
- {dkist_processing_cryonirsp-1.4.14.dist-info → dkist_processing_cryonirsp-1.4.16rc1.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,8 @@ import math
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from dkist_service_configuration.logging import logger
|
|
6
6
|
|
|
7
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundary
|
|
7
8
|
from dkist_processing_cryonirsp.tasks.beam_boundaries_base import BeamBoundariesCalibrationBase
|
|
8
|
-
from dkist_processing_cryonirsp.tasks.beam_boundaries_base import BeamBoundary
|
|
9
9
|
from dkist_processing_cryonirsp.tasks.mixin.shift_measurements import ShiftMeasurementsMixin
|
|
10
10
|
from dkist_processing_cryonirsp.tasks.mixin.shift_measurements import SPATIAL
|
|
11
11
|
from dkist_processing_cryonirsp.tasks.mixin.shift_measurements import SPECTRAL
|
|
@@ -17,7 +17,10 @@ from scipy.optimize import differential_evolution
|
|
|
17
17
|
from scipy.optimize import OptimizeResult
|
|
18
18
|
from sunpy.coordinates import HeliocentricInertial
|
|
19
19
|
|
|
20
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_access_decoder
|
|
21
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
20
22
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
23
|
+
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import CryonirspL0FitsAccess
|
|
21
24
|
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
22
25
|
|
|
23
26
|
__all__ = ["SPDispersionAxisCorrection"]
|
|
@@ -126,8 +129,9 @@ class SPDispersionAxisCorrection(CryonirspTaskBase, InputDatasetMixin):
|
|
|
126
129
|
"""Load intermediate 1d characteristic measured_spectra for beam 1."""
|
|
127
130
|
# Only fitting with the left beam.
|
|
128
131
|
beam = 1
|
|
129
|
-
array_generator = self.
|
|
130
|
-
tags=[CryonirspTag.
|
|
132
|
+
array_generator = self.read(
|
|
133
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task("SOLAR_CHAR_SPEC")],
|
|
134
|
+
decoder=cryo_fits_array_decoder,
|
|
131
135
|
)
|
|
132
136
|
|
|
133
137
|
return next(array_generator)
|
|
@@ -136,11 +140,15 @@ class SPDispersionAxisCorrection(CryonirspTaskBase, InputDatasetMixin):
|
|
|
136
140
|
"""Grab a header from a random solar gain frame to be used to find a rough initial wavelength estimate."""
|
|
137
141
|
# Only fitting with the left beam.
|
|
138
142
|
beam = 1
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
solar_tags = [CryonirspTag.linearized_frame(), CryonirspTag.task("SOLAR_GAIN")]
|
|
144
|
+
solar_obj = next(
|
|
145
|
+
self.read(
|
|
146
|
+
tags=solar_tags,
|
|
147
|
+
decoder=cryo_fits_access_decoder,
|
|
148
|
+
fits_access_class=CryonirspL0FitsAccess,
|
|
142
149
|
)
|
|
143
|
-
)
|
|
150
|
+
)
|
|
151
|
+
solar_header = solar_obj.header
|
|
144
152
|
return solar_header
|
|
145
153
|
|
|
146
154
|
def get_theoretical_dispersion(self) -> tuple[u.Quantity, int, float]:
|
|
@@ -4,6 +4,7 @@ import math
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import peakutils as pku
|
|
6
6
|
import scipy.ndimage as spnd
|
|
7
|
+
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
7
8
|
from dkist_processing_common.models.task_name import TaskName
|
|
8
9
|
from dkist_processing_math.arithmetic import divide_arrays_by_array
|
|
9
10
|
from dkist_processing_math.arithmetic import subtract_array_from_arrays
|
|
@@ -11,7 +12,12 @@ from dkist_processing_math.statistics import average_numpy_arrays
|
|
|
11
12
|
from dkist_service_configuration.logging import logger
|
|
12
13
|
from scipy.optimize import minimize
|
|
13
14
|
|
|
15
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
16
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundary
|
|
14
17
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
18
|
+
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import (
|
|
19
|
+
CryonirspLinearizedFitsAccess,
|
|
20
|
+
)
|
|
15
21
|
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
16
22
|
from dkist_processing_cryonirsp.tasks.mixin.shift_measurements import ShiftMeasurementsMixin
|
|
17
23
|
from dkist_processing_cryonirsp.tasks.mixin.shift_measurements import SPATIAL
|
|
@@ -99,8 +105,7 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
99
105
|
with self.apm_processing_step("Computing and logging quality metrics"):
|
|
100
106
|
no_of_raw_geo_frames: int = self.scratch.count_all(
|
|
101
107
|
tags=[
|
|
102
|
-
CryonirspTag.
|
|
103
|
-
CryonirspTag.frame(),
|
|
108
|
+
CryonirspTag.linearized_frame(),
|
|
104
109
|
CryonirspTag.task_solar_gain(),
|
|
105
110
|
],
|
|
106
111
|
)
|
|
@@ -123,8 +128,12 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
123
128
|
np.ndarray
|
|
124
129
|
Dark corrected data array
|
|
125
130
|
"""
|
|
126
|
-
array_generator = self.
|
|
127
|
-
tags=[
|
|
131
|
+
array_generator = self.read(
|
|
132
|
+
tags=[
|
|
133
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
134
|
+
CryonirspTag.task("GC_BASIC_GAIN_CORRECTED"),
|
|
135
|
+
],
|
|
136
|
+
decoder=cryo_fits_array_decoder,
|
|
128
137
|
)
|
|
129
138
|
return average_numpy_arrays(array_generator)
|
|
130
139
|
|
|
@@ -142,8 +151,12 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
142
151
|
np.ndarray
|
|
143
152
|
Dark and bad pixel corrected data array
|
|
144
153
|
"""
|
|
145
|
-
array_generator = self.
|
|
146
|
-
tags=[
|
|
154
|
+
array_generator = self.read(
|
|
155
|
+
tags=[
|
|
156
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
157
|
+
CryonirspTag.task("GC_BASIC_DARK_BP_CORRECTED"),
|
|
158
|
+
],
|
|
159
|
+
decoder=cryo_fits_array_decoder,
|
|
147
160
|
)
|
|
148
161
|
return average_numpy_arrays(array_generator)
|
|
149
162
|
|
|
@@ -161,8 +174,9 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
161
174
|
np.ndarray
|
|
162
175
|
Offset corrected data array
|
|
163
176
|
"""
|
|
164
|
-
array_generator = self.
|
|
165
|
-
tags=[CryonirspTag.
|
|
177
|
+
array_generator = self.read(
|
|
178
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task("GC_OFFSET")],
|
|
179
|
+
decoder=cryo_fits_array_decoder,
|
|
166
180
|
)
|
|
167
181
|
return average_numpy_arrays(array_generator)
|
|
168
182
|
|
|
@@ -171,24 +185,50 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
171
185
|
# There is likely only a single exposure conditions tuple in the list, but we iterate over the list
|
|
172
186
|
# in case there are multiple exposure conditions tuples. We also need a specific exposure conditions tag
|
|
173
187
|
# to ensure we get the proper dark arrays to use in the correction.
|
|
174
|
-
for
|
|
175
|
-
|
|
188
|
+
for beam in range(1, self.constants.num_beams + 1):
|
|
189
|
+
beam_array = next(
|
|
190
|
+
self.read(
|
|
191
|
+
tags=CryonirspTag.intermediate_beam_boundaries(beam=beam),
|
|
192
|
+
decoder=cryo_fits_array_decoder,
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
beam_boundary = BeamBoundary(*beam_array)
|
|
196
|
+
|
|
197
|
+
for exposure_conditions in self.constants.solar_gain_exposure_conditions_list:
|
|
176
198
|
logger.info(f"Starting basic reductions for {exposure_conditions = } and {beam = }")
|
|
177
199
|
try:
|
|
178
|
-
dark_array =
|
|
179
|
-
|
|
200
|
+
dark_array = next(
|
|
201
|
+
self.read(
|
|
202
|
+
tags=[
|
|
203
|
+
CryonirspTag.intermediate_frame(
|
|
204
|
+
beam=beam, exposure_conditions=exposure_conditions
|
|
205
|
+
),
|
|
206
|
+
CryonirspTag.task_dark(),
|
|
207
|
+
],
|
|
208
|
+
decoder=cryo_fits_array_decoder,
|
|
209
|
+
)
|
|
180
210
|
)
|
|
181
211
|
except StopIteration as e:
|
|
182
212
|
raise ValueError(f"No matching dark found for {exposure_conditions = }") from e
|
|
183
213
|
|
|
184
|
-
lamp_gain_array =
|
|
185
|
-
|
|
214
|
+
lamp_gain_array = next(
|
|
215
|
+
self.read(
|
|
216
|
+
tags=[
|
|
217
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
218
|
+
CryonirspTag.task_lamp_gain(),
|
|
219
|
+
],
|
|
220
|
+
decoder=cryo_fits_array_decoder,
|
|
221
|
+
)
|
|
186
222
|
)
|
|
187
223
|
|
|
188
|
-
input_solar_arrays = self.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
input_solar_arrays = self.read(
|
|
225
|
+
tags=[
|
|
226
|
+
CryonirspTag.linearized_frame(exposure_conditions=exposure_conditions),
|
|
227
|
+
CryonirspTag.task_solar_gain(),
|
|
228
|
+
],
|
|
229
|
+
decoder=cryo_fits_array_decoder,
|
|
230
|
+
fits_access_class=CryonirspLinearizedFitsAccess,
|
|
231
|
+
beam_boundary=beam_boundary,
|
|
192
232
|
)
|
|
193
233
|
|
|
194
234
|
avg_solar_array = average_numpy_arrays(input_solar_arrays)
|
|
@@ -197,24 +237,36 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
197
237
|
subtract_array_from_arrays(arrays=avg_solar_array, array_to_subtract=dark_array)
|
|
198
238
|
)
|
|
199
239
|
|
|
200
|
-
bad_pixel_map =
|
|
240
|
+
bad_pixel_map = next(
|
|
241
|
+
self.read(
|
|
242
|
+
tags=[CryonirspTag.intermediate_frame(), CryonirspTag.task_bad_pixel_map()],
|
|
243
|
+
decoder=cryo_fits_array_decoder,
|
|
244
|
+
beam_boundary=beam_boundary,
|
|
245
|
+
)
|
|
246
|
+
)
|
|
201
247
|
bad_pixel_corrected_array = self.corrections_correct_bad_pixels(
|
|
202
248
|
dark_corrected_solar_array, bad_pixel_map
|
|
203
249
|
)
|
|
204
250
|
logger.info(f"Writing bad pixel corrected data for {beam=}")
|
|
205
|
-
self.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
251
|
+
self.write(
|
|
252
|
+
data=bad_pixel_corrected_array,
|
|
253
|
+
tags=[
|
|
254
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
255
|
+
CryonirspTag.task("GC_BASIC_DARK_BP_CORRECTED"),
|
|
256
|
+
],
|
|
257
|
+
encoder=fits_array_encoder,
|
|
209
258
|
)
|
|
210
259
|
gain_corrected_solar_array = next(
|
|
211
260
|
divide_arrays_by_array(bad_pixel_corrected_array, lamp_gain_array)
|
|
212
261
|
)
|
|
213
262
|
logger.info(f"Writing gain corrected data for {beam=}")
|
|
214
|
-
self.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
263
|
+
self.write(
|
|
264
|
+
data=gain_corrected_solar_array,
|
|
265
|
+
tags=[
|
|
266
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
267
|
+
CryonirspTag.task("GC_BASIC_GAIN_CORRECTED"),
|
|
268
|
+
],
|
|
269
|
+
encoder=fits_array_encoder,
|
|
218
270
|
)
|
|
219
271
|
|
|
220
272
|
def compute_beam_angle(self, beam: int) -> float:
|
|
@@ -239,7 +291,12 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
239
291
|
# Step 1
|
|
240
292
|
# Do not use a gain corrected image here, as it will cancel out the slit structure
|
|
241
293
|
# that is used for the shift measurement computations
|
|
242
|
-
gain_array =
|
|
294
|
+
gain_array = next(
|
|
295
|
+
self.read(
|
|
296
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_lamp_gain()],
|
|
297
|
+
decoder=cryo_fits_array_decoder,
|
|
298
|
+
)
|
|
299
|
+
)
|
|
243
300
|
|
|
244
301
|
full_spatial_size, full_spectral_size = gain_array.shape
|
|
245
302
|
|
|
@@ -344,7 +401,11 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
344
401
|
|
|
345
402
|
"""
|
|
346
403
|
corrected_array = next(self.corrections_correct_geometry(array, shift=offset))
|
|
347
|
-
self.
|
|
404
|
+
self.write(
|
|
405
|
+
data=corrected_array,
|
|
406
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task("GC_OFFSET")],
|
|
407
|
+
encoder=fits_array_encoder,
|
|
408
|
+
)
|
|
348
409
|
|
|
349
410
|
def compute_spectral_shifts(self, beam: int) -> np.ndarray:
|
|
350
411
|
"""
|
|
@@ -404,10 +465,13 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
404
465
|
logger.info(f"Mean of spectral shifts = {self.mean_shifts}")
|
|
405
466
|
|
|
406
467
|
beam_shifts -= self.mean_shifts
|
|
407
|
-
self.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
468
|
+
self.write(
|
|
469
|
+
data=beam_shifts,
|
|
470
|
+
tags=[
|
|
471
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
472
|
+
CryonirspTag.task("GC_RAW_SPECTRAL_SHIFTS"),
|
|
473
|
+
],
|
|
474
|
+
encoder=fits_array_encoder,
|
|
411
475
|
)
|
|
412
476
|
|
|
413
477
|
# Finally, fit the shifts and return the resulting polynomial. Any "bad" fits were set to NaN and will be
|
|
@@ -538,8 +602,10 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
538
602
|
None
|
|
539
603
|
"""
|
|
540
604
|
array = np.array([angle])
|
|
541
|
-
self.
|
|
542
|
-
|
|
605
|
+
self.write(
|
|
606
|
+
data=array,
|
|
607
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_geometric_angle()],
|
|
608
|
+
encoder=fits_array_encoder,
|
|
543
609
|
)
|
|
544
610
|
|
|
545
611
|
def write_beam_offset(self, offset: np.ndarray, beam: int) -> None:
|
|
@@ -559,8 +625,10 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
559
625
|
None
|
|
560
626
|
|
|
561
627
|
"""
|
|
562
|
-
self.
|
|
563
|
-
|
|
628
|
+
self.write(
|
|
629
|
+
data=offset,
|
|
630
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_geometric_offset()],
|
|
631
|
+
encoder=fits_array_encoder,
|
|
564
632
|
)
|
|
565
633
|
|
|
566
634
|
def write_spectral_shifts(self, shifts: np.ndarray, beam: int) -> None:
|
|
@@ -580,6 +648,11 @@ class SPGeometricCalibration(CryonirspTaskBase, ShiftMeasurementsMixin):
|
|
|
580
648
|
None
|
|
581
649
|
|
|
582
650
|
"""
|
|
583
|
-
self.
|
|
584
|
-
|
|
651
|
+
self.write(
|
|
652
|
+
data=shifts,
|
|
653
|
+
tags=[
|
|
654
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
655
|
+
CryonirspTag.task_geometric_spectral_shifts(),
|
|
656
|
+
],
|
|
657
|
+
encoder=fits_array_encoder,
|
|
585
658
|
)
|
|
@@ -6,6 +6,7 @@ from astropy.io import fits
|
|
|
6
6
|
from dkist_processing_math.statistics import average_numpy_arrays
|
|
7
7
|
from dkist_service_configuration.logging import logger
|
|
8
8
|
|
|
9
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
9
10
|
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
10
11
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
11
12
|
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import CryonirspL0FitsAccess
|
|
@@ -258,35 +259,76 @@ class SPScienceCalibration(ScienceCalibrationBase):
|
|
|
258
259
|
for beam in range(1, self.constants.num_beams + 1):
|
|
259
260
|
# Load the dark arrays
|
|
260
261
|
for exposure_conditions in self.constants.observe_exposure_conditions_list:
|
|
261
|
-
dark_array =
|
|
262
|
-
|
|
262
|
+
dark_array = next(
|
|
263
|
+
self.read(
|
|
264
|
+
tags=[
|
|
265
|
+
CryonirspTag.intermediate_frame(
|
|
266
|
+
beam=beam, exposure_conditions=exposure_conditions
|
|
267
|
+
),
|
|
268
|
+
CryonirspTag.task_dark(),
|
|
269
|
+
],
|
|
270
|
+
decoder=cryo_fits_array_decoder,
|
|
271
|
+
)
|
|
263
272
|
)
|
|
264
273
|
dark_dict[CryonirspTag.beam(beam)][
|
|
265
274
|
CryonirspTag.exposure_conditions(exposure_conditions)
|
|
266
275
|
] = dark_array
|
|
267
276
|
|
|
268
277
|
# Load the gain arrays
|
|
269
|
-
solar_dict[CryonirspTag.beam(beam)] =
|
|
270
|
-
|
|
278
|
+
solar_dict[CryonirspTag.beam(beam)] = next(
|
|
279
|
+
self.read(
|
|
280
|
+
tags=[
|
|
281
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
282
|
+
CryonirspTag.task_solar_gain(),
|
|
283
|
+
],
|
|
284
|
+
decoder=cryo_fits_array_decoder,
|
|
285
|
+
)
|
|
271
286
|
)
|
|
272
287
|
|
|
273
288
|
# Load the angle arrays
|
|
274
|
-
|
|
289
|
+
angle_array = next(
|
|
290
|
+
self.read(
|
|
291
|
+
tags=[
|
|
292
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
293
|
+
CryonirspTag.task_geometric_angle(),
|
|
294
|
+
],
|
|
295
|
+
decoder=cryo_fits_array_decoder,
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
angle_dict[CryonirspTag.beam(beam)] = float(angle_array[0])
|
|
275
299
|
|
|
276
300
|
# Load the state offsets
|
|
277
|
-
state_offset_dict[CryonirspTag.beam(beam)] =
|
|
278
|
-
|
|
301
|
+
state_offset_dict[CryonirspTag.beam(beam)] = next(
|
|
302
|
+
self.read(
|
|
303
|
+
tags=[
|
|
304
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
305
|
+
CryonirspTag.task_geometric_offset(),
|
|
306
|
+
],
|
|
307
|
+
decoder=cryo_fits_array_decoder,
|
|
308
|
+
)
|
|
279
309
|
)
|
|
280
310
|
|
|
281
311
|
# Load the spectral shifts
|
|
282
|
-
spec_shift_dict[CryonirspTag.beam(beam)] =
|
|
283
|
-
|
|
312
|
+
spec_shift_dict[CryonirspTag.beam(beam)] = next(
|
|
313
|
+
self.read(
|
|
314
|
+
tags=[
|
|
315
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
316
|
+
CryonirspTag.task_geometric_spectral_shifts(),
|
|
317
|
+
],
|
|
318
|
+
decoder=cryo_fits_array_decoder,
|
|
319
|
+
)
|
|
284
320
|
)
|
|
285
321
|
|
|
286
322
|
# Load the demod matrices
|
|
287
323
|
if self.constants.correct_for_polarization:
|
|
288
|
-
demod_dict[CryonirspTag.beam(beam)] =
|
|
289
|
-
|
|
324
|
+
demod_dict[CryonirspTag.beam(beam)] = next(
|
|
325
|
+
self.read(
|
|
326
|
+
tags=[
|
|
327
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
328
|
+
CryonirspTag.task_demodulation_matrices(),
|
|
329
|
+
],
|
|
330
|
+
decoder=cryo_fits_array_decoder,
|
|
331
|
+
)
|
|
290
332
|
)
|
|
291
333
|
|
|
292
334
|
return CalibrationCollection(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Cryo SP solar gain task."""
|
|
2
2
|
import numpy as np
|
|
3
3
|
import scipy.ndimage as spnd
|
|
4
|
+
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
4
5
|
from dkist_processing_common.models.task_name import TaskName
|
|
5
6
|
from dkist_processing_math.arithmetic import divide_arrays_by_array
|
|
6
7
|
from dkist_processing_math.arithmetic import subtract_array_from_arrays
|
|
@@ -8,9 +9,14 @@ from dkist_processing_math.statistics import average_numpy_arrays
|
|
|
8
9
|
from dkist_service_configuration.logging import logger
|
|
9
10
|
from scipy import signal
|
|
10
11
|
|
|
12
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
13
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundary
|
|
11
14
|
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
12
15
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
13
16
|
from dkist_processing_cryonirsp.models.task_name import CryonirspTaskName
|
|
17
|
+
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import (
|
|
18
|
+
CryonirspLinearizedFitsAccess,
|
|
19
|
+
)
|
|
14
20
|
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
15
21
|
|
|
16
22
|
__all__ = ["SPSolarGainCalibration"]
|
|
@@ -105,8 +111,7 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
105
111
|
with self.apm_processing_step("Computing and logging quality metrics"):
|
|
106
112
|
no_of_raw_solar_frames: int = self.scratch.count_all(
|
|
107
113
|
tags=[
|
|
108
|
-
CryonirspTag.
|
|
109
|
-
CryonirspTag.frame(),
|
|
114
|
+
CryonirspTag.linearized_frame(),
|
|
110
115
|
CryonirspTag.task_solar_gain(),
|
|
111
116
|
],
|
|
112
117
|
)
|
|
@@ -137,13 +142,21 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
137
142
|
beam, exposure_conditions
|
|
138
143
|
)
|
|
139
144
|
# Save as intermediate result for final gain computation
|
|
140
|
-
self.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
self.write(
|
|
146
|
+
data=basic_corrected_solar_array,
|
|
147
|
+
tags=[
|
|
148
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
149
|
+
CryonirspTag.task("SC_DARK_BP_CORRECTED_ONLY"),
|
|
150
|
+
],
|
|
151
|
+
encoder=fits_array_encoder,
|
|
144
152
|
)
|
|
145
153
|
# Gain correct using the lamp gain. This removes internal optical effects.
|
|
146
|
-
lamp_array =
|
|
154
|
+
lamp_array = next(
|
|
155
|
+
self.read(
|
|
156
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_lamp_gain()],
|
|
157
|
+
decoder=cryo_fits_array_decoder,
|
|
158
|
+
)
|
|
159
|
+
)
|
|
147
160
|
lamp_corrected_solar_array = next(
|
|
148
161
|
divide_arrays_by_array(basic_corrected_solar_array, lamp_array)
|
|
149
162
|
)
|
|
@@ -152,10 +165,13 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
152
165
|
lamp_corrected_solar_array, beam
|
|
153
166
|
)
|
|
154
167
|
# Save as an intermediate result for science users
|
|
155
|
-
self.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
168
|
+
self.write(
|
|
169
|
+
data=spectral_corrected_solar_array,
|
|
170
|
+
tags=[
|
|
171
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
172
|
+
CryonirspTag.task(CryonirspTaskName.spectral_corrected_solar_array.value),
|
|
173
|
+
],
|
|
174
|
+
encoder=fits_array_encoder,
|
|
159
175
|
)
|
|
160
176
|
return spectral_corrected_solar_array
|
|
161
177
|
|
|
@@ -178,18 +194,45 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
178
194
|
A solar array with dark and bad pixel corrections
|
|
179
195
|
"""
|
|
180
196
|
# Load the necessary files
|
|
181
|
-
dark_array =
|
|
182
|
-
|
|
197
|
+
dark_array = next(
|
|
198
|
+
self.read(
|
|
199
|
+
tags=[
|
|
200
|
+
CryonirspTag.intermediate_frame(
|
|
201
|
+
beam=beam, exposure_conditions=exposure_conditions
|
|
202
|
+
),
|
|
203
|
+
CryonirspTag.task_dark(),
|
|
204
|
+
],
|
|
205
|
+
decoder=cryo_fits_array_decoder,
|
|
206
|
+
)
|
|
183
207
|
)
|
|
184
208
|
# Compute the avg solar array
|
|
185
|
-
|
|
186
|
-
|
|
209
|
+
beam_array = next(
|
|
210
|
+
self.read(
|
|
211
|
+
tags=CryonirspTag.intermediate_beam_boundaries(beam=beam),
|
|
212
|
+
decoder=cryo_fits_array_decoder,
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
beam_boundary = BeamBoundary(*beam_array)
|
|
216
|
+
linearized_solar_arrays = self.read(
|
|
217
|
+
tags=[
|
|
218
|
+
CryonirspTag.linearized_frame(exposure_conditions=exposure_conditions),
|
|
219
|
+
CryonirspTag.task_solar_gain(),
|
|
220
|
+
],
|
|
221
|
+
decoder=cryo_fits_array_decoder,
|
|
222
|
+
fits_access_class=CryonirspLinearizedFitsAccess,
|
|
223
|
+
beam_boundary=beam_boundary,
|
|
187
224
|
)
|
|
188
225
|
avg_solar_array = average_numpy_arrays(linearized_solar_arrays)
|
|
189
226
|
# Dark correct it
|
|
190
227
|
dark_corrected_solar_array = next(subtract_array_from_arrays(avg_solar_array, dark_array))
|
|
191
228
|
# Correct for bad pixels
|
|
192
|
-
bad_pixel_map =
|
|
229
|
+
bad_pixel_map = next(
|
|
230
|
+
self.read(
|
|
231
|
+
tags=[CryonirspTag.intermediate_frame(), CryonirspTag.task_bad_pixel_map()],
|
|
232
|
+
decoder=cryo_fits_array_decoder,
|
|
233
|
+
beam_boundary=beam_boundary,
|
|
234
|
+
)
|
|
235
|
+
)
|
|
193
236
|
bad_pixel_corrected_solar_array = self.corrections_correct_bad_pixels(
|
|
194
237
|
dark_corrected_solar_array, bad_pixel_map
|
|
195
238
|
)
|
|
@@ -212,9 +255,34 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
212
255
|
An array that has geometric and spectral corrections
|
|
213
256
|
"""
|
|
214
257
|
# Get the parameters and save them to self for use later on...
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
258
|
+
angle_array = next(
|
|
259
|
+
self.read(
|
|
260
|
+
tags=[
|
|
261
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
262
|
+
CryonirspTag.task_geometric_angle(),
|
|
263
|
+
],
|
|
264
|
+
decoder=cryo_fits_array_decoder,
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
self.angle = float(angle_array[0])
|
|
268
|
+
self.state_offset = next(
|
|
269
|
+
self.read(
|
|
270
|
+
tags=[
|
|
271
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
272
|
+
CryonirspTag.task_geometric_offset(),
|
|
273
|
+
],
|
|
274
|
+
decoder=cryo_fits_array_decoder,
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
self.spec_shift = next(
|
|
278
|
+
self.read(
|
|
279
|
+
tags=[
|
|
280
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
281
|
+
CryonirspTag.task_geometric_spectral_shifts(),
|
|
282
|
+
],
|
|
283
|
+
decoder=cryo_fits_array_decoder,
|
|
284
|
+
)
|
|
285
|
+
)
|
|
218
286
|
# Correct for rotation and state offset. This does not correct for spectral curvature!
|
|
219
287
|
geo_corrected_solar_array = next(
|
|
220
288
|
self.corrections_correct_geometry(lamp_corrected_array, self.state_offset, self.angle)
|
|
@@ -245,8 +313,13 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
245
313
|
char_spec_1d = np.nanmedian(array_row_norm, axis=0)
|
|
246
314
|
# Expand the 1D median along the columns (along the slit)
|
|
247
315
|
median_char_spec_2d = np.tile(char_spec_1d, (array_row_norm.shape[0], 1))
|
|
248
|
-
self.
|
|
249
|
-
|
|
316
|
+
self.write(
|
|
317
|
+
data=char_spec_1d,
|
|
318
|
+
tags=[
|
|
319
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
320
|
+
CryonirspTag.task_characteristic_spectra(),
|
|
321
|
+
],
|
|
322
|
+
encoder=fits_array_encoder,
|
|
250
323
|
)
|
|
251
324
|
return median_char_spec_2d
|
|
252
325
|
|
|
@@ -294,11 +367,12 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
294
367
|
-------
|
|
295
368
|
A dark and bad pixel corrected solar array
|
|
296
369
|
"""
|
|
297
|
-
array_generator = self.
|
|
370
|
+
array_generator = self.read(
|
|
298
371
|
tags=[
|
|
372
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
299
373
|
CryonirspTag.task("SC_DARK_BP_CORRECTED_ONLY"),
|
|
300
|
-
|
|
301
|
-
|
|
374
|
+
],
|
|
375
|
+
decoder=cryo_fits_array_decoder,
|
|
302
376
|
)
|
|
303
377
|
return next(array_generator)
|
|
304
378
|
|
|
@@ -350,10 +424,10 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
350
424
|
None
|
|
351
425
|
"""
|
|
352
426
|
logger.info(f"Writing final SolarGain for {beam=}")
|
|
353
|
-
self.
|
|
354
|
-
|
|
355
|
-
beam=beam,
|
|
356
|
-
|
|
427
|
+
self.write(
|
|
428
|
+
data=gain_array,
|
|
429
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_solar_gain()],
|
|
430
|
+
encoder=fits_array_encoder,
|
|
357
431
|
)
|
|
358
432
|
|
|
359
433
|
def compute_fringe_corrected_gain(self, beam: int, exposure_conditions: float) -> np.ndarray:
|
|
@@ -416,7 +490,12 @@ class SPSolarGainCalibration(CryonirspTaskBase):
|
|
|
416
490
|
-------
|
|
417
491
|
The scaled lamp array
|
|
418
492
|
"""
|
|
419
|
-
lamp_array =
|
|
493
|
+
lamp_array = next(
|
|
494
|
+
self.read(
|
|
495
|
+
tags=[CryonirspTag.intermediate_frame(beam=beam), CryonirspTag.task_lamp_gain()],
|
|
496
|
+
decoder=cryo_fits_array_decoder,
|
|
497
|
+
)
|
|
498
|
+
)
|
|
420
499
|
lamp_corrected_solar_array = next(divide_arrays_by_array(corrected_solar_array, lamp_array))
|
|
421
500
|
flux_ratio = np.nanmedian(lamp_corrected_solar_array, axis=1)
|
|
422
501
|
scaled_lamp_array = lamp_array * flux_ratio[:, None]
|