dkist-processing-cryonirsp 1.4.15__py3-none-any.whl → 1.4.16__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.

Files changed (49) hide show
  1. dkist_processing_cryonirsp/codecs/__init__.py +5 -0
  2. dkist_processing_cryonirsp/codecs/fits.py +52 -0
  3. dkist_processing_cryonirsp/models/beam_boundaries.py +39 -0
  4. dkist_processing_cryonirsp/models/parameters.py +0 -1
  5. dkist_processing_cryonirsp/models/tags.py +34 -0
  6. dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +38 -2
  7. dkist_processing_cryonirsp/tasks/assemble_movie.py +2 -2
  8. dkist_processing_cryonirsp/tasks/bad_pixel_map.py +14 -9
  9. dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +24 -43
  10. dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +1 -1
  11. dkist_processing_cryonirsp/tasks/ci_science.py +24 -6
  12. dkist_processing_cryonirsp/tasks/cryonirsp_base.py +0 -10
  13. dkist_processing_cryonirsp/tasks/dark.py +34 -14
  14. dkist_processing_cryonirsp/tasks/gain.py +69 -22
  15. dkist_processing_cryonirsp/tasks/instrument_polarization.py +131 -49
  16. dkist_processing_cryonirsp/tasks/l1_output_data.py +0 -1
  17. dkist_processing_cryonirsp/tasks/linearity_correction.py +4 -7
  18. dkist_processing_cryonirsp/tasks/make_movie_frames.py +5 -5
  19. dkist_processing_cryonirsp/tasks/quality_metrics.py +4 -4
  20. dkist_processing_cryonirsp/tasks/science_base.py +34 -10
  21. dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +1 -1
  22. dkist_processing_cryonirsp/tasks/sp_dispersion_axis_correction.py +14 -6
  23. dkist_processing_cryonirsp/tasks/sp_geometric.py +112 -39
  24. dkist_processing_cryonirsp/tasks/sp_science.py +53 -11
  25. dkist_processing_cryonirsp/tasks/sp_solar_gain.py +108 -29
  26. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +2 -10
  27. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +8 -11
  28. dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +1 -1
  29. dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +1 -2
  30. dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +6 -5
  31. dkist_processing_cryonirsp/tests/test_ci_science.py +25 -24
  32. dkist_processing_cryonirsp/tests/test_cryo_base.py +41 -43
  33. dkist_processing_cryonirsp/tests/test_dark.py +20 -28
  34. dkist_processing_cryonirsp/tests/test_gain.py +46 -35
  35. dkist_processing_cryonirsp/tests/test_instrument_polarization.py +22 -16
  36. dkist_processing_cryonirsp/tests/test_linearity_correction.py +1 -4
  37. dkist_processing_cryonirsp/tests/test_quality.py +1 -2
  38. dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +6 -5
  39. dkist_processing_cryonirsp/tests/test_sp_dispersion_axis_correction.py +10 -9
  40. dkist_processing_cryonirsp/tests/test_sp_geometric.py +108 -53
  41. dkist_processing_cryonirsp/tests/test_sp_science.py +49 -35
  42. dkist_processing_cryonirsp/tests/test_sp_solar.py +70 -38
  43. {dkist_processing_cryonirsp-1.4.15.dist-info → dkist_processing_cryonirsp-1.4.16.dist-info}/METADATA +2 -2
  44. {dkist_processing_cryonirsp-1.4.15.dist-info → dkist_processing_cryonirsp-1.4.16.dist-info}/RECORD +46 -46
  45. dkist_processing_cryonirsp/tasks/mixin/beam_access.py +0 -52
  46. dkist_processing_cryonirsp/tasks/mixin/intermediate_frame.py +0 -193
  47. dkist_processing_cryonirsp/tasks/mixin/linearized_frame.py +0 -309
  48. {dkist_processing_cryonirsp-1.4.15.dist-info → dkist_processing_cryonirsp-1.4.16.dist-info}/WHEEL +0 -0
  49. {dkist_processing_cryonirsp-1.4.15.dist-info → dkist_processing_cryonirsp-1.4.16.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.intermediate_frame_load_intermediate_arrays(
130
- tags=[CryonirspTag.task("SOLAR_CHAR_SPEC"), CryonirspTag.beam(beam)]
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
- solar_header = next(
140
- self.linearized_frame_fits_access_generator(
141
- tags=[CryonirspTag.task("SOLAR_GAIN")], beam=beam
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
- ).header
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.linearized(),
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.intermediate_frame_load_intermediate_arrays(
127
- tags=[CryonirspTag.task("GC_BASIC_GAIN_CORRECTED"), CryonirspTag.beam(beam)]
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.intermediate_frame_load_intermediate_arrays(
146
- tags=[CryonirspTag.task("GC_BASIC_DARK_BP_CORRECTED"), CryonirspTag.beam(beam)]
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.intermediate_frame_load_intermediate_arrays(
165
- tags=[CryonirspTag.task("GC_OFFSET"), CryonirspTag.beam(beam)]
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 exposure_conditions in self.constants.solar_gain_exposure_conditions_list:
175
- for beam in range(1, self.constants.num_beams + 1):
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 = self.intermediate_frame_load_dark_array(
179
- beam=beam, exposure_conditions=exposure_conditions
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 = self.intermediate_frame_load_lamp_gain_array(
185
- beam=beam,
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.linearized_frame_gain_array_generator(
189
- gain_type=TaskName.solar_gain.value,
190
- beam=beam,
191
- exposure_conditions=exposure_conditions,
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 = self.intermediate_frame_load_bad_pixel_map(beam=beam)
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.intermediate_frame_write_arrays(
206
- arrays=bad_pixel_corrected_array,
207
- beam=beam,
208
- task="GC_BASIC_DARK_BP_CORRECTED",
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.intermediate_frame_write_arrays(
215
- arrays=gain_corrected_solar_array,
216
- beam=beam,
217
- task="GC_BASIC_GAIN_CORRECTED",
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 = self.intermediate_frame_load_lamp_gain_array(beam=beam)
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.intermediate_frame_write_arrays(arrays=corrected_array, beam=beam, task="GC_OFFSET")
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.intermediate_frame_write_arrays(
408
- arrays=beam_shifts,
409
- beam=beam,
410
- task="GC_RAW_SPECTRAL_SHIFTS",
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.intermediate_frame_write_arrays(
542
- arrays=array, beam=beam, task_tag=CryonirspTag.task_geometric_angle()
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.intermediate_frame_write_arrays(
563
- arrays=offset, beam=beam, task_tag=CryonirspTag.task_geometric_offset()
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.intermediate_frame_write_arrays(
584
- arrays=shifts, beam=beam, task_tag=CryonirspTag.task_geometric_sepectral_shifts()
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 = self.intermediate_frame_load_dark_array(
262
- beam=beam, exposure_conditions=exposure_conditions
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)] = self.intermediate_frame_load_solar_gain_array(
270
- beam=beam,
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
- angle_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_angle(beam=beam)
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)] = self.intermediate_frame_load_state_offset(
278
- beam=beam
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)] = self.intermediate_frame_load_spec_shift(
283
- beam=beam
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)] = self.intermediate_frame_load_demod_matrices(
289
- beam=beam
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.linearized(),
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.intermediate_frame_write_arrays(
141
- arrays=basic_corrected_solar_array,
142
- beam=beam,
143
- task="SC_DARK_BP_CORRECTED_ONLY",
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 = self.intermediate_frame_load_lamp_gain_array(beam=beam)
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.intermediate_frame_write_arrays(
156
- arrays=spectral_corrected_solar_array,
157
- beam=beam,
158
- task=CryonirspTaskName.spectral_corrected_solar_array.value,
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 = self.intermediate_frame_load_dark_array(
182
- beam=beam, exposure_conditions=exposure_conditions
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
- linearized_solar_arrays = self.linearized_frame_gain_array_generator(
186
- beam=beam, exposure_conditions=exposure_conditions, gain_type=TaskName.solar_gain.value
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 = self.intermediate_frame_load_bad_pixel_map(beam=beam)
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
- self.angle = self.intermediate_frame_load_angle(beam=beam)
216
- self.state_offset = self.intermediate_frame_load_state_offset(beam=beam)
217
- self.spec_shift = self.intermediate_frame_load_spec_shift(beam=beam)
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.intermediate_frame_write_arrays(
249
- arrays=char_spec_1d, task_tag=CryonirspTag.task_characteristic_spectra(), beam=beam
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.intermediate_frame_load_intermediate_arrays(
370
+ array_generator = self.read(
298
371
  tags=[
372
+ CryonirspTag.intermediate_frame(beam=beam),
299
373
  CryonirspTag.task("SC_DARK_BP_CORRECTED_ONLY"),
300
- CryonirspTag.beam(beam),
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.intermediate_frame_write_arrays(
354
- arrays=gain_array,
355
- beam=beam,
356
- task_tag=CryonirspTag.task_solar_gain(),
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 = self.intermediate_frame_load_lamp_gain_array(beam=beam)
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]