dkist-processing-dlnirsp 0.32.2__py3-none-any.whl → 0.32.4__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.
- dkist_processing_dlnirsp/models/fits_access.py +32 -0
- dkist_processing_dlnirsp/parsers/dlnirsp_l0_fits_access.py +35 -23
- dkist_processing_dlnirsp/parsers/task.py +2 -6
- dkist_processing_dlnirsp/parsers/time.py +2 -1
- dkist_processing_dlnirsp/parsers/wavelength.py +5 -1
- dkist_processing_dlnirsp/tasks/linearity_correction.py +55 -24
- dkist_processing_dlnirsp/tasks/parse.py +21 -12
- dkist_processing_dlnirsp/tasks/science.py +7 -5
- dkist_processing_dlnirsp/tasks/write_l1.py +5 -4
- dkist_processing_dlnirsp/tests/conftest.py +13 -5
- dkist_processing_dlnirsp/tests/local_trial_workflows/local_trial_dev_mockers.py +18 -16
- dkist_processing_dlnirsp/tests/local_trial_workflows/local_trial_helpers.py +2 -1
- dkist_processing_dlnirsp/tests/test_dlnirsp_fits_access.py +56 -3
- dkist_processing_dlnirsp/tests/test_linearity_correction.py +120 -21
- dkist_processing_dlnirsp/tests/test_parse.py +3 -2
- dkist_processing_dlnirsp/tests/test_science.py +7 -6
- {dkist_processing_dlnirsp-0.32.2.dist-info → dkist_processing_dlnirsp-0.32.4.dist-info}/METADATA +42 -41
- {dkist_processing_dlnirsp-0.32.2.dist-info → dkist_processing_dlnirsp-0.32.4.dist-info}/RECORD +21 -20
- {dkist_processing_dlnirsp-0.32.2.dist-info → dkist_processing_dlnirsp-0.32.4.dist-info}/WHEEL +0 -0
- {dkist_processing_dlnirsp-0.32.2.dist-info → dkist_processing_dlnirsp-0.32.4.dist-info}/entry_points.txt +0 -0
- {dkist_processing_dlnirsp-0.32.2.dist-info → dkist_processing_dlnirsp-0.32.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""DLNIRSP control of FITS key names and values."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DlnirspMetadataKey(StrEnum):
|
|
9
|
+
"""Controlled list of names for FITS metadata header keys."""
|
|
10
|
+
|
|
11
|
+
crpix_1 = "CRPIX1"
|
|
12
|
+
crpix_2 = "CRPIX2"
|
|
13
|
+
modulator_spin_mode = "DLMOD"
|
|
14
|
+
camera_readout_mode = "DLCAMSMD"
|
|
15
|
+
num_frames_in_ramp = "DLCAMNS"
|
|
16
|
+
current_frame_in_ramp = "DLCAMCUR"
|
|
17
|
+
arm_id = "DLARMID"
|
|
18
|
+
camera_sample_sequence = "DLCAMSSQ"
|
|
19
|
+
polarimeter_mode = "DLPOLMD"
|
|
20
|
+
number_of_modulator_states = "DLNUMST"
|
|
21
|
+
modulator_state = "DLSTNUM"
|
|
22
|
+
num_mosaic_repeats = "DLMOSNRP"
|
|
23
|
+
mosaic_num = "DLCURMOS"
|
|
24
|
+
num_X_tiles = "DLNSSTPX"
|
|
25
|
+
X_tile_num = "DLCSTPX"
|
|
26
|
+
num_Y_tiles = "DLNSSTPY"
|
|
27
|
+
Y_tile_num = "DLCSTPY"
|
|
28
|
+
num_dither_steps = "DLDMODE"
|
|
29
|
+
dither_step = "DLCURSTP"
|
|
30
|
+
arm_position_mm = "DLARMPS"
|
|
31
|
+
grating_position_deg = "DLGRTAN"
|
|
32
|
+
grating_constant_inverse_mm = "DLGRTCN"
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
from astropy.io import fits
|
|
4
4
|
from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
|
|
5
5
|
|
|
6
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class DlnirspRampFitsAccess(L0FitsAccess):
|
|
8
10
|
"""
|
|
@@ -30,12 +32,18 @@ class DlnirspRampFitsAccess(L0FitsAccess):
|
|
|
30
32
|
):
|
|
31
33
|
super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
|
|
32
34
|
|
|
33
|
-
self.modulator_spin_mode: str = self.header[
|
|
34
|
-
self.camera_readout_mode: str = self.header.get(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
self.
|
|
38
|
-
self.
|
|
35
|
+
self.modulator_spin_mode: str = self.header[DlnirspMetadataKey.modulator_spin_mode]
|
|
36
|
+
self.camera_readout_mode: str = self.header.get(
|
|
37
|
+
DlnirspMetadataKey.camera_readout_mode, "DEFAULT_VISIBLE_CAMERA"
|
|
38
|
+
)
|
|
39
|
+
self.num_frames_in_ramp: int = self.header.get(DlnirspMetadataKey.num_frames_in_ramp, -99)
|
|
40
|
+
self.current_frame_in_ramp: int = self.header.get(
|
|
41
|
+
DlnirspMetadataKey.current_frame_in_ramp, -88
|
|
42
|
+
)
|
|
43
|
+
self.arm_id: str = self.header[DlnirspMetadataKey.arm_id]
|
|
44
|
+
self.camera_sample_sequence: str = self.header.get(
|
|
45
|
+
DlnirspMetadataKey.camera_sample_sequence, "VISIBLE_CAMERA_SEQUENCE"
|
|
46
|
+
)
|
|
39
47
|
|
|
40
48
|
|
|
41
49
|
class DlnirspL0FitsAccess(L0FitsAccess):
|
|
@@ -64,24 +72,28 @@ class DlnirspL0FitsAccess(L0FitsAccess):
|
|
|
64
72
|
):
|
|
65
73
|
super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
|
|
66
74
|
|
|
67
|
-
self.crpix_1: float = self.header[
|
|
68
|
-
self.crpix_2: float = self.header[
|
|
69
|
-
self.arm_id: str = self.header[
|
|
70
|
-
self.polarimeter_mode: str = self.header[
|
|
71
|
-
self.number_of_modulator_states: int = self.header[
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
self.
|
|
75
|
-
self.
|
|
76
|
-
self.
|
|
77
|
-
self.
|
|
78
|
-
self.
|
|
75
|
+
self.crpix_1: float = self.header[DlnirspMetadataKey.crpix_1]
|
|
76
|
+
self.crpix_2: float = self.header[DlnirspMetadataKey.crpix_2]
|
|
77
|
+
self.arm_id: str = self.header[DlnirspMetadataKey.arm_id]
|
|
78
|
+
self.polarimeter_mode: str = self.header[DlnirspMetadataKey.polarimeter_mode]
|
|
79
|
+
self.number_of_modulator_states: int = self.header[
|
|
80
|
+
DlnirspMetadataKey.number_of_modulator_states
|
|
81
|
+
]
|
|
82
|
+
self.modulator_state: int = self.header[DlnirspMetadataKey.modulator_state]
|
|
83
|
+
self.num_mosaic_repeats: int = self.header[DlnirspMetadataKey.num_mosaic_repeats]
|
|
84
|
+
self.mosaic_num: int = self.header[DlnirspMetadataKey.mosaic_num]
|
|
85
|
+
self.num_X_tiles: int = self.header[DlnirspMetadataKey.num_X_tiles]
|
|
86
|
+
self.X_tile_num: int = self.header[DlnirspMetadataKey.X_tile_num]
|
|
87
|
+
self.num_Y_tiles: int = self.header[DlnirspMetadataKey.num_Y_tiles]
|
|
88
|
+
self.Y_tile_num: int = self.header[DlnirspMetadataKey.Y_tile_num]
|
|
79
89
|
# DLDMODE is a bool in the header; the number of dither steps is either 1 or 2, corresponding to dither
|
|
80
90
|
# mode being True or False, respectively
|
|
81
|
-
self.num_dither_steps: int = int(self.header[
|
|
91
|
+
self.num_dither_steps: int = int(self.header[DlnirspMetadataKey.num_dither_steps]) + 1
|
|
82
92
|
# Same with DLCURSTP. We'll index the dither loop at 0 so `False` is the first step and `True` is the second
|
|
83
93
|
# Use `get` because this key only exists if DLDMODE is `True`
|
|
84
|
-
self.dither_step: int = int(self.header.get(
|
|
85
|
-
self.arm_position_mm: float = self.header[
|
|
86
|
-
self.grating_position_deg: float = self.header[
|
|
87
|
-
self.grating_constant_inverse_mm: float = self.header[
|
|
94
|
+
self.dither_step: int = int(self.header.get(DlnirspMetadataKey.dither_step, False))
|
|
95
|
+
self.arm_position_mm: float = self.header[DlnirspMetadataKey.arm_position_mm]
|
|
96
|
+
self.grating_position_deg: float = self.header[DlnirspMetadataKey.grating_position_deg]
|
|
97
|
+
self.grating_constant_inverse_mm: float = self.header[
|
|
98
|
+
DlnirspMetadataKey.grating_constant_inverse_mm
|
|
99
|
+
]
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
"""Custom parsers to identify task sub-groupings not captured by a single header key."""
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from dkist_processing_common.models.flower_pot import SpilledDirt
|
|
3
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
6
4
|
from dkist_processing_common.models.tags import StemName
|
|
7
5
|
from dkist_processing_common.models.task_name import TaskName
|
|
8
|
-
from dkist_processing_common.parsers.near_bud import NearFloatBud
|
|
9
6
|
from dkist_processing_common.parsers.single_value_single_key_flower import (
|
|
10
7
|
SingleValueSingleKeyFlower,
|
|
11
8
|
)
|
|
12
|
-
from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
13
9
|
|
|
14
10
|
from dkist_processing_dlnirsp.parsers.dlnirsp_l0_fits_access import DlnirspL0FitsAccess
|
|
15
11
|
|
|
@@ -41,7 +37,7 @@ class DlnirspTaskTypeFlower(SingleValueSingleKeyFlower):
|
|
|
41
37
|
"""Flower to find the DLNIRSP task type."""
|
|
42
38
|
|
|
43
39
|
def __init__(self):
|
|
44
|
-
super().__init__(tag_stem_name=StemName.task.value, metadata_key=
|
|
40
|
+
super().__init__(tag_stem_name=StemName.task.value, metadata_key=MetadataKey.ip_task_type)
|
|
45
41
|
|
|
46
42
|
def setter(self, fits_obj: DlnirspL0FitsAccess):
|
|
47
43
|
"""
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Hashable
|
|
4
4
|
|
|
5
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
5
6
|
from dkist_processing_common.models.flower_pot import Stem
|
|
6
7
|
from dkist_processing_common.models.task_name import TaskName
|
|
7
8
|
from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
|
|
@@ -17,7 +18,7 @@ class DLnirspSolarGainIpStartTimeBud(TaskUniqueBud):
|
|
|
17
18
|
def __init__(self):
|
|
18
19
|
super().__init__(
|
|
19
20
|
constant_name=DlnirspBudName.solar_gain_ip_start_time.value,
|
|
20
|
-
metadata_key=
|
|
21
|
+
metadata_key=MetadataKey.ip_start_time,
|
|
21
22
|
ip_task_types=TaskName.solar_gain.value,
|
|
22
23
|
task_type_parsing_function=parse_header_ip_task,
|
|
23
24
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Bud to get the wavelength."""
|
|
2
2
|
|
|
3
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
3
4
|
from dkist_processing_common.models.flower_pot import SpilledDirt
|
|
4
5
|
from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
5
6
|
|
|
@@ -11,7 +12,10 @@ class ObserveWavelengthBud(UniqueBud):
|
|
|
11
12
|
"""Bud to find the wavelength."""
|
|
12
13
|
|
|
13
14
|
def __init__(self):
|
|
14
|
-
super().__init__(
|
|
15
|
+
super().__init__(
|
|
16
|
+
constant_name=DlnirspBudName.wavelength.value,
|
|
17
|
+
metadata_key=MetadataKey.wavelength,
|
|
18
|
+
)
|
|
15
19
|
|
|
16
20
|
def setter(self, fits_obj: DlnirspL0FitsAccess):
|
|
17
21
|
"""
|
|
@@ -28,14 +28,32 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
28
28
|
|
|
29
29
|
record_provenance = True
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
valid_camera_sequence_regex: re.Pattern = re.compile(
|
|
32
|
+
r"^(\d*subframe)?(?(1)|(?:\d*line,\d*read,?)+)(?:,\d*line)?$"
|
|
33
|
+
)
|
|
32
34
|
"""
|
|
33
|
-
regex pattern
|
|
35
|
+
regex pattern that defines all valid camera-sample sequences.
|
|
36
|
+
|
|
37
|
+
It must start with either "Xline,Yread", which can repeat any number of times, or "Xsubframe" which must be by itself.
|
|
38
|
+
Either of these sequences may be padded with ",Zline" reset frames.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
uptheramp_coadd_regex: re.Pattern = re.compile(r"(\d*)line,(\d*)read")
|
|
42
|
+
"""
|
|
43
|
+
regex pattern used to parse line-read-line values for a single UpTheRamp coadd.
|
|
34
44
|
|
|
35
45
|
This is where we decide that camera sequences are one or more coadd sequences, where each coadd sequence is
|
|
36
46
|
"Xline,Yread". The total sequence may be padded with ",Zline" reset frames, which are not captured by this regex.
|
|
37
47
|
"""
|
|
38
48
|
|
|
49
|
+
subframe_sequence_regex: re.Pattern = re.compile(r"(\d*)subframe")
|
|
50
|
+
"""
|
|
51
|
+
regex pattern used to parse coadds in SubFrame mode
|
|
52
|
+
|
|
53
|
+
Simply looks for "Xsubframe" and captures the "X". The sequence may be padded with ",Zline" reset frames, which are
|
|
54
|
+
not captured by this regex.
|
|
55
|
+
"""
|
|
56
|
+
|
|
39
57
|
def run(self):
|
|
40
58
|
"""
|
|
41
59
|
Linearize IR camera frames or tag VIS camera frames as LINEARIZED.
|
|
@@ -110,17 +128,16 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
110
128
|
)
|
|
111
129
|
num_coadds = len(coadd_sequence_nums_list)
|
|
112
130
|
|
|
113
|
-
line_read_line_indices = coadd_sequence_nums_list[0]
|
|
114
|
-
num_bias, num_read = line_read_line_indices[:2]
|
|
115
|
-
|
|
116
|
-
ndr_per_coadd = num_bias + num_read
|
|
117
|
-
|
|
118
131
|
# In `is_ramp_valid` we already confirmed that all NDRs have the same values and that they are one of the
|
|
119
132
|
# expected values
|
|
120
133
|
camera_readout_mode = ramp_obj_list[0].camera_readout_mode
|
|
121
134
|
modulator_spin_mode = ramp_obj_list[0].modulator_spin_mode
|
|
122
135
|
match camera_readout_mode:
|
|
123
136
|
case "UpTheRamp":
|
|
137
|
+
line_read_line_indices = coadd_sequence_nums_list[0]
|
|
138
|
+
num_bias, num_read = line_read_line_indices[:2]
|
|
139
|
+
ndr_per_coadd = num_bias + num_read
|
|
140
|
+
|
|
124
141
|
match modulator_spin_mode:
|
|
125
142
|
case "Continuous":
|
|
126
143
|
linearization_func = partial(
|
|
@@ -136,6 +153,11 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
136
153
|
)
|
|
137
154
|
|
|
138
155
|
case "SubFrame":
|
|
156
|
+
# `self.valid_camera_sequence_regex`, along with `parse_camera_sample_sequence`, provides assurance that
|
|
157
|
+
# by the time we get here these assumptions are valid
|
|
158
|
+
num_bias = 0
|
|
159
|
+
num_read = 1
|
|
160
|
+
ndr_per_coadd = 1
|
|
139
161
|
linearization_func = self.linearize_subframe_coadd
|
|
140
162
|
|
|
141
163
|
coadd_stack = np.zeros((num_coadds, *ramp_obj_list[0].data.shape))
|
|
@@ -291,16 +313,25 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
291
313
|
"3line,45read,3line,45read,2line"
|
|
292
314
|
`[[3, 45], [3, 45]]`
|
|
293
315
|
|
|
316
|
+
"4subframe,89line"
|
|
317
|
+
`[[1], [1], [1], [1]]`
|
|
318
|
+
|
|
294
319
|
Returns
|
|
295
320
|
-------
|
|
296
|
-
A list of lists. Top-level list contains an item for each coadd.
|
|
297
|
-
length 2. The numbers in these inner lists correspond to the number of bias and read frames in that coadd,
|
|
298
|
-
respectively.
|
|
321
|
+
A list of lists. Top-level list contains an item for each coadd. In UpTheRamp mode these items are themselves
|
|
322
|
+
lists of length 2. The numbers in these inner lists correspond to the number of bias and read frames in that coadd,
|
|
323
|
+
respectively. In SubFrame mode the inner lists will always be length 1 and should be equal to `[1]`.
|
|
299
324
|
"""
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
325
|
+
if "subframe" in camera_sample_sequence:
|
|
326
|
+
coadd_matches = self.subframe_sequence_regex.findall(camera_sample_sequence)
|
|
327
|
+
# `is_ramp_valid` ensures we only have a single match here
|
|
328
|
+
num_coadd = int(coadd_matches[0])
|
|
329
|
+
coadd_sequence_numbers = [[1]] * num_coadd
|
|
330
|
+
else:
|
|
331
|
+
coadd_matches = self.uptheramp_coadd_regex.findall(camera_sample_sequence)
|
|
332
|
+
coadd_sequence_numbers = [
|
|
333
|
+
[int(num) for num in coadd_match] for coadd_match in coadd_matches
|
|
334
|
+
]
|
|
304
335
|
|
|
305
336
|
return coadd_sequence_numbers
|
|
306
337
|
|
|
@@ -310,15 +341,15 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
310
341
|
|
|
311
342
|
Current validity checks are:
|
|
312
343
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
344
|
+
#. All frames in the ramp have the same value for NUM_FRAMES_IN_RAMP
|
|
345
|
+
#. All frames in the ramp have the same value for CAMERA_READOUT_MODE
|
|
346
|
+
#. All frames in the ramp have the same value for MODULATOR_SPIN_MODE
|
|
347
|
+
#. The CAMERA_READOUT and MODULATOR_SPIN modes have expected values
|
|
348
|
+
#. The value of NUM_FRAMES_IN_RAMP equals the length of actual frames found
|
|
349
|
+
#. All frames in the ramp have the same value for CAMERA_SAMPLE_SEQUENCE
|
|
350
|
+
#. The camera sample sequence has the expected form (`valid_camera_sequence_regex`)
|
|
351
|
+
#. All coadds in the ramp have the same camera sample sequence
|
|
352
|
+
#. The ramp length is equal to the expected length from the camera sample sequence
|
|
322
353
|
|
|
323
354
|
If a ramp is not valid then the reason is logged and `False` is returned.
|
|
324
355
|
"""
|
|
@@ -382,7 +413,7 @@ class LinearityCorrection(DlnirspTaskBase):
|
|
|
382
413
|
return False
|
|
383
414
|
|
|
384
415
|
camera_sample_sequence = camera_sample_sequence_set.pop()
|
|
385
|
-
if
|
|
416
|
+
if not self.valid_camera_sequence_regex.search(camera_sample_sequence):
|
|
386
417
|
logger.info(
|
|
387
418
|
f"Malformed camera sample sequence: '{camera_sample_sequence}'. "
|
|
388
419
|
f"{common_status_str}"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import TypeVar
|
|
4
4
|
|
|
5
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
5
6
|
from dkist_processing_common.models.flower_pot import Stem
|
|
6
7
|
from dkist_processing_common.models.task_name import TaskName
|
|
7
8
|
from dkist_processing_common.parsers.cs_step import CSStepFlower
|
|
@@ -22,6 +23,7 @@ from dkist_processing_common.tasks import default_constant_bud_factory
|
|
|
22
23
|
from dkist_processing_common.tasks import default_tag_flower_factory
|
|
23
24
|
|
|
24
25
|
from dkist_processing_dlnirsp.models.constants import DlnirspBudName
|
|
26
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
25
27
|
from dkist_processing_dlnirsp.models.parameters import DlnirspParsingParameters
|
|
26
28
|
from dkist_processing_dlnirsp.models.tags import DlnirspStemName
|
|
27
29
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
@@ -72,7 +74,9 @@ class ParseL0DlnirspRampData(ParseDataBase):
|
|
|
72
74
|
# Time Obs is the unique identifier for each ramp in the data set
|
|
73
75
|
DlnirspTimeObsBud(),
|
|
74
76
|
# This is used to determine whether we need to do any linearity correction at all.
|
|
75
|
-
UniqueBud(
|
|
77
|
+
UniqueBud(
|
|
78
|
+
constant_name=DlnirspBudName.arm_id.value, metadata_key=DlnirspMetadataKey.arm_id
|
|
79
|
+
),
|
|
76
80
|
]
|
|
77
81
|
|
|
78
82
|
@property
|
|
@@ -81,12 +85,12 @@ class ParseL0DlnirspRampData(ParseDataBase):
|
|
|
81
85
|
return [
|
|
82
86
|
SingleValueSingleKeyFlower(
|
|
83
87
|
tag_stem_name=DlnirspStemName.current_frame_in_ramp.value,
|
|
84
|
-
metadata_key=
|
|
88
|
+
metadata_key=DlnirspMetadataKey.current_frame_in_ramp,
|
|
85
89
|
),
|
|
86
90
|
# time_obs is a unique identifier for all raw frames in a single ramp
|
|
87
91
|
SingleValueSingleKeyFlower(
|
|
88
92
|
tag_stem_name=DlnirspStemName.time_obs.value,
|
|
89
|
-
metadata_key=
|
|
93
|
+
metadata_key=MetadataKey.time_obs,
|
|
90
94
|
),
|
|
91
95
|
]
|
|
92
96
|
|
|
@@ -144,12 +148,13 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
144
148
|
DLnirspSolarGainIpStartTimeBud(),
|
|
145
149
|
NumCSStepBud(max_cs_step_time_sec=self.parameters.max_cs_step_time_sec),
|
|
146
150
|
UniqueBud(
|
|
147
|
-
constant_name=DlnirspBudName.polarimeter_mode.value,
|
|
151
|
+
constant_name=DlnirspBudName.polarimeter_mode.value,
|
|
152
|
+
metadata_key=DlnirspMetadataKey.polarimeter_mode,
|
|
148
153
|
),
|
|
149
154
|
RetarderNameBud(),
|
|
150
155
|
UniqueBud(
|
|
151
156
|
constant_name=DlnirspBudName.num_modstates.value,
|
|
152
|
-
metadata_key=
|
|
157
|
+
metadata_key=DlnirspMetadataKey.number_of_modulator_states,
|
|
153
158
|
),
|
|
154
159
|
NumMosaicRepeatsBud(
|
|
155
160
|
crpix_correction_method=self.parameters.wcs_crpix_correction_method,
|
|
@@ -189,20 +194,20 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
189
194
|
),
|
|
190
195
|
TaskNearFloatBud(
|
|
191
196
|
constant_name=DlnirspBudName.arm_position_mm.value,
|
|
192
|
-
metadata_key=
|
|
197
|
+
metadata_key=DlnirspMetadataKey.arm_position_mm,
|
|
193
198
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
194
199
|
tolerance=0.01,
|
|
195
200
|
task_type_parsing_function=parse_header_ip_task,
|
|
196
201
|
),
|
|
197
202
|
TaskUniqueBud(
|
|
198
203
|
constant_name=DlnirspBudName.grating_constant_inverse_mm.value,
|
|
199
|
-
metadata_key=
|
|
204
|
+
metadata_key=DlnirspMetadataKey.grating_constant_inverse_mm,
|
|
200
205
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
201
206
|
task_type_parsing_function=parse_header_ip_task,
|
|
202
207
|
),
|
|
203
208
|
TaskNearFloatBud(
|
|
204
209
|
constant_name=DlnirspBudName.grating_position_deg.value,
|
|
205
|
-
metadata_key=
|
|
210
|
+
metadata_key=DlnirspMetadataKey.grating_position_deg,
|
|
206
211
|
ip_task_types=[TaskName.solar_gain.value, TaskName.observe.value],
|
|
207
212
|
tolerance=0.01,
|
|
208
213
|
task_type_parsing_function=parse_header_ip_task,
|
|
@@ -216,14 +221,17 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
216
221
|
DlnirspTaskTypeFlower(),
|
|
217
222
|
PolcalTaskFlower(),
|
|
218
223
|
SingleValueSingleKeyFlower(
|
|
219
|
-
tag_stem_name=DlnirspStemName.arm_id.value,
|
|
224
|
+
tag_stem_name=DlnirspStemName.arm_id.value,
|
|
225
|
+
metadata_key=DlnirspMetadataKey.arm_id,
|
|
220
226
|
),
|
|
221
227
|
ExposureTimeFlower(),
|
|
222
228
|
SingleValueSingleKeyFlower(
|
|
223
|
-
tag_stem_name=DlnirspStemName.modstate.value,
|
|
229
|
+
tag_stem_name=DlnirspStemName.modstate.value,
|
|
230
|
+
metadata_key=DlnirspMetadataKey.modulator_state,
|
|
224
231
|
),
|
|
225
232
|
SingleValueSingleKeyFlower(
|
|
226
|
-
tag_stem_name=DlnirspStemName.mosaic_num.value,
|
|
233
|
+
tag_stem_name=DlnirspStemName.mosaic_num.value,
|
|
234
|
+
metadata_key=DlnirspMetadataKey.mosaic_num,
|
|
227
235
|
),
|
|
228
236
|
MosaicStepXFlower(
|
|
229
237
|
crpix_correction_method=self.parameters.wcs_crpix_correction_method,
|
|
@@ -234,7 +242,8 @@ class ParseL0DlnirspLinearizedData(ParseDataBase):
|
|
|
234
242
|
bin_crpix_to_multiple_of=self.parameters.parse_bin_crpix_to_multiple_of,
|
|
235
243
|
),
|
|
236
244
|
SingleValueSingleKeyFlower(
|
|
237
|
-
tag_stem_name=DlnirspStemName.dither_step.value,
|
|
245
|
+
tag_stem_name=DlnirspStemName.dither_step.value,
|
|
246
|
+
metadata_key=DlnirspMetadataKey.dither_step,
|
|
238
247
|
),
|
|
239
248
|
CSStepFlower(max_cs_step_time_sec=self.parameters.max_cs_step_time_sec),
|
|
240
249
|
]
|
|
@@ -18,6 +18,7 @@ from dkist_processing_common.codecs.fits import fits_access_decoder
|
|
|
18
18
|
from dkist_processing_common.codecs.fits import fits_array_decoder
|
|
19
19
|
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
20
20
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
21
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
21
22
|
from dkist_processing_common.models.tags import EXP_TIME_ROUND_DIGITS
|
|
22
23
|
from dkist_processing_common.models.task_name import TaskName
|
|
23
24
|
from dkist_processing_common.tasks.mixin.quality import QualityMixin
|
|
@@ -29,6 +30,7 @@ from dkist_processing_pac.optics.telescope import Telescope
|
|
|
29
30
|
from dkist_service_configuration.logging import logger
|
|
30
31
|
from scipy.spatial import Delaunay
|
|
31
32
|
|
|
33
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
32
34
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
33
35
|
from dkist_processing_dlnirsp.parsers.dlnirsp_l0_fits_access import DlnirspL0FitsAccess
|
|
34
36
|
from dkist_processing_dlnirsp.parsers.wcs_corrections import correct_crpix_values
|
|
@@ -738,7 +740,7 @@ class ScienceCalibration(
|
|
|
738
740
|
date_end = (Time(sorted_obj_list[-1].time_obs) + exp_time).isot
|
|
739
741
|
|
|
740
742
|
header = sorted_obj_list[0].header
|
|
741
|
-
header[
|
|
743
|
+
header[MetadataKey.time_obs] = date_beg
|
|
742
744
|
header["DATE-END"] = date_end
|
|
743
745
|
|
|
744
746
|
return header
|
|
@@ -773,13 +775,13 @@ class ScienceCalibration(
|
|
|
773
775
|
|
|
774
776
|
crpix_correction_method = self.parameters.wcs_crpix_correction_method
|
|
775
777
|
cached_info_logger(f"Applying CRPIX correction method '{crpix_correction_method}'")
|
|
776
|
-
OG_crpix1 = header[
|
|
777
|
-
OG_crpix2 = header[
|
|
778
|
+
OG_crpix1 = header[DlnirspMetadataKey.crpix_1]
|
|
779
|
+
OG_crpix2 = header[DlnirspMetadataKey.crpix_2]
|
|
778
780
|
|
|
779
781
|
new_crpix1, new_crpix2 = correct_crpix_values(OG_crpix1, OG_crpix2, crpix_correction_method)
|
|
780
782
|
|
|
781
|
-
header[
|
|
782
|
-
header[
|
|
783
|
+
header[DlnirspMetadataKey.crpix_1] = new_crpix1
|
|
784
|
+
header[DlnirspMetadataKey.crpix_2] = new_crpix2
|
|
783
785
|
|
|
784
786
|
return header
|
|
785
787
|
|
|
@@ -12,6 +12,7 @@ from dkist_processing_common.tasks import WriteL1Frame
|
|
|
12
12
|
from dkist_service_configuration.logging import logger
|
|
13
13
|
|
|
14
14
|
from dkist_processing_dlnirsp.models.constants import DlnirspConstants
|
|
15
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
15
16
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
16
17
|
|
|
17
18
|
cached_info_logger = cache(logger.info)
|
|
@@ -83,7 +84,7 @@ class DlnirspWriteL1Frame(WriteL1Frame):
|
|
|
83
84
|
header[f"DPNAME{axis_index}"] = "dither step"
|
|
84
85
|
header[f"DWNAME{axis_index}"] = "time"
|
|
85
86
|
header[f"DUNIT{axis_index}"] = "s"
|
|
86
|
-
header[f"DINDEX{axis_index}"] = int(header[
|
|
87
|
+
header[f"DINDEX{axis_index}"] = int(header[DlnirspMetadataKey.dither_step]) + 1
|
|
87
88
|
|
|
88
89
|
if self.constants.correct_for_polarization:
|
|
89
90
|
cached_info_logger("Polarimetric data detected")
|
|
@@ -211,7 +212,7 @@ class DlnirspWriteL1Frame(WriteL1Frame):
|
|
|
211
212
|
tile_as_temporal_axis = False
|
|
212
213
|
temporal_axis_size = num_mosaic_repeats
|
|
213
214
|
pname = "mosaic repeat number"
|
|
214
|
-
dindex = header[
|
|
215
|
+
dindex = header[DlnirspMetadataKey.mosaic_num]
|
|
215
216
|
|
|
216
217
|
elif num_mosaic_repeats == 1 and (
|
|
217
218
|
(num_X_tiles == 1 and num_Y_tiles == 1) or (num_X_tiles > 1 and num_Y_tiles > 1)
|
|
@@ -224,14 +225,14 @@ class DlnirspWriteL1Frame(WriteL1Frame):
|
|
|
224
225
|
tile_as_temporal_axis = True
|
|
225
226
|
temporal_axis_size = num_X_tiles
|
|
226
227
|
pname = "repeat number"
|
|
227
|
-
dindex = header[
|
|
228
|
+
dindex = header[DlnirspMetadataKey.X_tile_num]
|
|
228
229
|
|
|
229
230
|
elif num_mosaic_repeats == 1 and num_X_tiles == 1 and num_Y_tiles > 1:
|
|
230
231
|
has_temporal_axis = True
|
|
231
232
|
tile_as_temporal_axis = True
|
|
232
233
|
temporal_axis_size = num_Y_tiles
|
|
233
234
|
pname = "repeat number"
|
|
234
|
-
dindex = header[
|
|
235
|
+
dindex = header[DlnirspMetadataKey.Y_tile_num]
|
|
235
236
|
|
|
236
237
|
else:
|
|
237
238
|
raise ValueError(
|
|
@@ -436,7 +436,19 @@ class RawRampHeaders(DlnirspHeaders):
|
|
|
436
436
|
raise ValueError(f"{array_shape = } is weird")
|
|
437
437
|
array_shape = array_shape[1:]
|
|
438
438
|
|
|
439
|
-
|
|
439
|
+
match camera_readout_mode:
|
|
440
|
+
case "UpTheRamp":
|
|
441
|
+
self.num_frames_per_coadd = num_line + num_read
|
|
442
|
+
coadd_read_sequence = f"{num_line}line,{num_read}read"
|
|
443
|
+
cam_read_sequence = ",".join([coadd_read_sequence] * num_coadd)
|
|
444
|
+
case "SubFrame":
|
|
445
|
+
self.num_frames_per_coadd = 1
|
|
446
|
+
cam_read_sequence = f"{num_coadd}subframe"
|
|
447
|
+
num_line = 0
|
|
448
|
+
num_read = 1
|
|
449
|
+
case _:
|
|
450
|
+
raise ValueError(f"Don't know how to make data for {camera_readout_mode = }")
|
|
451
|
+
|
|
440
452
|
num_NDR_per_ramp = self.num_frames_per_coadd * num_coadd + num_reset
|
|
441
453
|
num_frames = num_ramps * num_NDR_per_ramp
|
|
442
454
|
dataset_shape = (num_frames, *array_shape)
|
|
@@ -446,12 +458,8 @@ class RawRampHeaders(DlnirspHeaders):
|
|
|
446
458
|
self.ramp_length_sec = TimeDelta(ramp_length_sec, format="sec")
|
|
447
459
|
self.num_coadd = num_coadd
|
|
448
460
|
self.num_line = num_line
|
|
449
|
-
self.num_read = num_read
|
|
450
461
|
self.num_reset = num_reset
|
|
451
462
|
|
|
452
|
-
coadd_read_sequence = f"{num_line}line,{num_read}read"
|
|
453
|
-
cam_read_sequence = ",".join([coadd_read_sequence] * num_coadd)
|
|
454
|
-
|
|
455
463
|
if num_reset > 0:
|
|
456
464
|
cam_read_sequence += f",{num_reset}line"
|
|
457
465
|
|
|
@@ -9,6 +9,7 @@ from dkist_processing_common.codecs.fits import fits_array_decoder
|
|
|
9
9
|
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
10
10
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
11
11
|
from dkist_processing_common.models.constants import BudName
|
|
12
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
12
13
|
from dkist_processing_common.models.task_name import TaskName
|
|
13
14
|
from dkist_processing_common.tasks import TransferTrialData
|
|
14
15
|
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
@@ -17,6 +18,7 @@ from dkist_processing_math.statistics import average_numpy_arrays
|
|
|
17
18
|
from dkist_service_configuration.logging import logger
|
|
18
19
|
|
|
19
20
|
from dkist_processing_dlnirsp.models.constants import DlnirspBudName
|
|
21
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
20
22
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
21
23
|
from dkist_processing_dlnirsp.tasks import DlnirspWriteL1Frame
|
|
22
24
|
from dkist_processing_dlnirsp.tasks.dlnirsp_base import DlnirspTaskBase
|
|
@@ -87,7 +89,7 @@ def permissive_write_l1_task(force_intensity_only: bool):
|
|
|
87
89
|
self, header: fits.Header, stokes: Literal["I", "Q", "U", "V"]
|
|
88
90
|
) -> fits.Header:
|
|
89
91
|
if force_intensity_only:
|
|
90
|
-
header[
|
|
92
|
+
header[MetadataKey.polarimeter_mode] = "Stokes I"
|
|
91
93
|
|
|
92
94
|
return super().add_dataset_headers(header=header, stokes=stokes)
|
|
93
95
|
|
|
@@ -138,11 +140,11 @@ class TagPolcasAsScience(DlnirspTaskBase):
|
|
|
138
140
|
avg_array = average_numpy_arrays(arrays=arrays)
|
|
139
141
|
|
|
140
142
|
hdul = fits.HDUList([fits.PrimaryHDU(data=avg_array, header=first_header)])
|
|
141
|
-
hdul[0].header[
|
|
142
|
-
hdul[0].header[
|
|
143
|
-
hdul[0].header[
|
|
144
|
-
hdul[0].header[
|
|
145
|
-
hdul[0].header[
|
|
143
|
+
hdul[0].header[DlnirspMetadataKey.X_tile_num] = 1
|
|
144
|
+
hdul[0].header[DlnirspMetadataKey.Y_tile_num] = 1
|
|
145
|
+
hdul[0].header[DlnirspMetadataKey.num_mosaic_repeats] = self.constants.num_cs_steps
|
|
146
|
+
hdul[0].header[DlnirspMetadataKey.mosaic_num] = cs_step
|
|
147
|
+
hdul[0].header[MetadataKey.fpa_exposure_time_ms] = obs_exp_time
|
|
146
148
|
|
|
147
149
|
new_tags = [
|
|
148
150
|
DlnirspTag.task_observe(),
|
|
@@ -186,11 +188,11 @@ class TagSingleSolarGainAsScience(DlnirspTaskBase):
|
|
|
186
188
|
avg_array = average_numpy_arrays(arrays=arrays)
|
|
187
189
|
|
|
188
190
|
hdul = fits.HDUList([fits.PrimaryHDU(data=avg_array, header=first_header)])
|
|
189
|
-
hdul[0].header[
|
|
190
|
-
hdul[0].header[
|
|
191
|
-
hdul[0].header[
|
|
192
|
-
hdul[0].header[
|
|
193
|
-
hdul[0].header[
|
|
191
|
+
hdul[0].header[DlnirspMetadataKey.X_tile_num] = 1
|
|
192
|
+
hdul[0].header[DlnirspMetadataKey.Y_tile_num] = 1
|
|
193
|
+
hdul[0].header[DlnirspMetadataKey.num_mosaic_repeats] = 1
|
|
194
|
+
hdul[0].header[DlnirspMetadataKey.mosaic_num] = 0
|
|
195
|
+
hdul[0].header[DlnirspMetadataKey.num_dither_steps] = False
|
|
194
196
|
|
|
195
197
|
new_tags = [
|
|
196
198
|
DlnirspTag.task_observe(),
|
|
@@ -237,11 +239,11 @@ class TagModulatedSolarGainsAsScience(DlnirspTaskBase):
|
|
|
237
239
|
avg_array = average_numpy_arrays(arrays=arrays)
|
|
238
240
|
|
|
239
241
|
hdul = fits.HDUList([fits.PrimaryHDU(data=avg_array, header=first_header)])
|
|
240
|
-
hdul[0].header[
|
|
241
|
-
hdul[0].header[
|
|
242
|
-
hdul[0].header[
|
|
243
|
-
hdul[0].header[
|
|
244
|
-
hdul[0].header[
|
|
242
|
+
hdul[0].header[DlnirspMetadataKey.X_tile_num] = 1
|
|
243
|
+
hdul[0].header[DlnirspMetadataKey.Y_tile_num] = 1
|
|
244
|
+
hdul[0].header[DlnirspMetadataKey.num_mosaic_repeats] = 1
|
|
245
|
+
hdul[0].header[DlnirspMetadataKey.mosaic_num] = 0
|
|
246
|
+
hdul[0].header[DlnirspMetadataKey.num_dither_steps] = False
|
|
245
247
|
|
|
246
248
|
new_tags = [
|
|
247
249
|
DlnirspTag.task_observe(),
|
|
@@ -20,6 +20,7 @@ from loguru import logger
|
|
|
20
20
|
|
|
21
21
|
from dkist_processing_dlnirsp.models.constants import DlnirspBudName
|
|
22
22
|
from dkist_processing_dlnirsp.models.constants import DlnirspConstants
|
|
23
|
+
from dkist_processing_dlnirsp.models.fits_access import DlnirspMetadataKey
|
|
23
24
|
from dkist_processing_dlnirsp.models.tags import DlnirspTag
|
|
24
25
|
from dkist_processing_dlnirsp.models.task_name import DlnirspTaskName
|
|
25
26
|
from dkist_processing_dlnirsp.tasks.dlnirsp_base import DlnirspTaskBase
|
|
@@ -38,7 +39,7 @@ def get_camera_number(scratch_dir: Path, suffix: str = "FITS", data_ext: int = 1
|
|
|
38
39
|
header_list = [fits.getheader(f, ext=data_ext) for f in file_list]
|
|
39
40
|
table = Table(header_list)
|
|
40
41
|
|
|
41
|
-
camera_IDs = np.unique(table[
|
|
42
|
+
camera_IDs = np.unique(table[DlnirspMetadataKey.arm_id])
|
|
42
43
|
if camera_IDs.size > 1:
|
|
43
44
|
raise ValueError(f"Found more than one arm in scratch dir. Found {camera_IDs}")
|
|
44
45
|
|