dkist-processing-cryonirsp 1.3.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.

Potentially problematic release.


This version of dkist-processing-cryonirsp might be problematic. Click here for more details.

Files changed (111) hide show
  1. changelog/.gitempty +0 -0
  2. dkist_processing_cryonirsp/__init__.py +11 -0
  3. dkist_processing_cryonirsp/config.py +12 -0
  4. dkist_processing_cryonirsp/models/__init__.py +1 -0
  5. dkist_processing_cryonirsp/models/constants.py +248 -0
  6. dkist_processing_cryonirsp/models/exposure_conditions.py +26 -0
  7. dkist_processing_cryonirsp/models/parameters.py +296 -0
  8. dkist_processing_cryonirsp/models/tags.py +168 -0
  9. dkist_processing_cryonirsp/models/task_name.py +14 -0
  10. dkist_processing_cryonirsp/parsers/__init__.py +1 -0
  11. dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +111 -0
  12. dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +30 -0
  13. dkist_processing_cryonirsp/parsers/exposure_conditions.py +163 -0
  14. dkist_processing_cryonirsp/parsers/map_repeats.py +40 -0
  15. dkist_processing_cryonirsp/parsers/measurements.py +55 -0
  16. dkist_processing_cryonirsp/parsers/modstates.py +31 -0
  17. dkist_processing_cryonirsp/parsers/optical_density_filters.py +40 -0
  18. dkist_processing_cryonirsp/parsers/polarimetric_check.py +120 -0
  19. dkist_processing_cryonirsp/parsers/scan_step.py +412 -0
  20. dkist_processing_cryonirsp/parsers/time.py +80 -0
  21. dkist_processing_cryonirsp/parsers/wavelength.py +26 -0
  22. dkist_processing_cryonirsp/tasks/__init__.py +19 -0
  23. dkist_processing_cryonirsp/tasks/assemble_movie.py +202 -0
  24. dkist_processing_cryonirsp/tasks/bad_pixel_map.py +96 -0
  25. dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +279 -0
  26. dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +55 -0
  27. dkist_processing_cryonirsp/tasks/ci_science.py +169 -0
  28. dkist_processing_cryonirsp/tasks/cryonirsp_base.py +67 -0
  29. dkist_processing_cryonirsp/tasks/dark.py +98 -0
  30. dkist_processing_cryonirsp/tasks/gain.py +251 -0
  31. dkist_processing_cryonirsp/tasks/instrument_polarization.py +447 -0
  32. dkist_processing_cryonirsp/tasks/l1_output_data.py +44 -0
  33. dkist_processing_cryonirsp/tasks/linearity_correction.py +582 -0
  34. dkist_processing_cryonirsp/tasks/make_movie_frames.py +302 -0
  35. dkist_processing_cryonirsp/tasks/mixin/__init__.py +1 -0
  36. dkist_processing_cryonirsp/tasks/mixin/beam_access.py +52 -0
  37. dkist_processing_cryonirsp/tasks/mixin/corrections.py +177 -0
  38. dkist_processing_cryonirsp/tasks/mixin/intermediate_frame.py +193 -0
  39. dkist_processing_cryonirsp/tasks/mixin/linearized_frame.py +309 -0
  40. dkist_processing_cryonirsp/tasks/mixin/shift_measurements.py +297 -0
  41. dkist_processing_cryonirsp/tasks/parse.py +281 -0
  42. dkist_processing_cryonirsp/tasks/quality_metrics.py +271 -0
  43. dkist_processing_cryonirsp/tasks/science_base.py +511 -0
  44. dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +270 -0
  45. dkist_processing_cryonirsp/tasks/sp_dispersion_axis_correction.py +484 -0
  46. dkist_processing_cryonirsp/tasks/sp_geometric.py +585 -0
  47. dkist_processing_cryonirsp/tasks/sp_science.py +299 -0
  48. dkist_processing_cryonirsp/tasks/sp_solar_gain.py +475 -0
  49. dkist_processing_cryonirsp/tasks/trial_output_data.py +61 -0
  50. dkist_processing_cryonirsp/tasks/write_l1.py +1033 -0
  51. dkist_processing_cryonirsp/tests/__init__.py +1 -0
  52. dkist_processing_cryonirsp/tests/conftest.py +456 -0
  53. dkist_processing_cryonirsp/tests/header_models.py +592 -0
  54. dkist_processing_cryonirsp/tests/local_trial_workflows/__init__.py +0 -0
  55. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +541 -0
  56. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +615 -0
  57. dkist_processing_cryonirsp/tests/local_trial_workflows/linearize_only.py +96 -0
  58. dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +592 -0
  59. dkist_processing_cryonirsp/tests/test_assemble_movie.py +144 -0
  60. dkist_processing_cryonirsp/tests/test_assemble_qualilty.py +517 -0
  61. dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +115 -0
  62. dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +106 -0
  63. dkist_processing_cryonirsp/tests/test_ci_science.py +355 -0
  64. dkist_processing_cryonirsp/tests/test_corrections.py +126 -0
  65. dkist_processing_cryonirsp/tests/test_cryo_base.py +202 -0
  66. dkist_processing_cryonirsp/tests/test_cryo_constants.py +76 -0
  67. dkist_processing_cryonirsp/tests/test_dark.py +287 -0
  68. dkist_processing_cryonirsp/tests/test_gain.py +278 -0
  69. dkist_processing_cryonirsp/tests/test_instrument_polarization.py +531 -0
  70. dkist_processing_cryonirsp/tests/test_linearity_correction.py +245 -0
  71. dkist_processing_cryonirsp/tests/test_make_movie_frames.py +111 -0
  72. dkist_processing_cryonirsp/tests/test_parameters.py +266 -0
  73. dkist_processing_cryonirsp/tests/test_parse.py +1439 -0
  74. dkist_processing_cryonirsp/tests/test_quality.py +203 -0
  75. dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +112 -0
  76. dkist_processing_cryonirsp/tests/test_sp_dispersion_axis_correction.py +155 -0
  77. dkist_processing_cryonirsp/tests/test_sp_geometric.py +319 -0
  78. dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +121 -0
  79. dkist_processing_cryonirsp/tests/test_sp_science.py +483 -0
  80. dkist_processing_cryonirsp/tests/test_sp_solar.py +198 -0
  81. dkist_processing_cryonirsp/tests/test_trial_create_quality_report.py +79 -0
  82. dkist_processing_cryonirsp/tests/test_trial_output_data.py +251 -0
  83. dkist_processing_cryonirsp/tests/test_workflows.py +9 -0
  84. dkist_processing_cryonirsp/tests/test_write_l1.py +436 -0
  85. dkist_processing_cryonirsp/workflows/__init__.py +2 -0
  86. dkist_processing_cryonirsp/workflows/ci_l0_processing.py +77 -0
  87. dkist_processing_cryonirsp/workflows/sp_l0_processing.py +84 -0
  88. dkist_processing_cryonirsp/workflows/trial_workflows.py +190 -0
  89. dkist_processing_cryonirsp-1.3.4.dist-info/METADATA +194 -0
  90. dkist_processing_cryonirsp-1.3.4.dist-info/RECORD +111 -0
  91. dkist_processing_cryonirsp-1.3.4.dist-info/WHEEL +5 -0
  92. dkist_processing_cryonirsp-1.3.4.dist-info/top_level.txt +4 -0
  93. docs/Makefile +134 -0
  94. docs/bad_pixel_calibration.rst +47 -0
  95. docs/beam_angle_calculation.rst +53 -0
  96. docs/beam_boundary_computation.rst +88 -0
  97. docs/changelog.rst +7 -0
  98. docs/ci_science_calibration.rst +33 -0
  99. docs/conf.py +52 -0
  100. docs/index.rst +21 -0
  101. docs/l0_to_l1_cryonirsp_ci-full-trial.rst +10 -0
  102. docs/l0_to_l1_cryonirsp_ci.rst +10 -0
  103. docs/l0_to_l1_cryonirsp_sp-full-trial.rst +10 -0
  104. docs/l0_to_l1_cryonirsp_sp.rst +10 -0
  105. docs/linearization.rst +43 -0
  106. docs/make.bat +170 -0
  107. docs/requirements.txt +1 -0
  108. docs/requirements_table.rst +8 -0
  109. docs/scientific_changelog.rst +10 -0
  110. docs/sp_science_calibration.rst +59 -0
  111. licenses/LICENSE.rst +11 -0
@@ -0,0 +1,592 @@
1
+ """
2
+ Model header objects
3
+ """
4
+ import datetime
5
+ import random
6
+ import uuid
7
+ from random import choice
8
+
9
+ import numpy as np
10
+ import pytest
11
+ from astropy.io import fits
12
+ from astropy.wcs import WCS
13
+ from dkist_data_simulator.dataset import key_function
14
+ from dkist_data_simulator.spec122 import Spec122Dataset
15
+ from dkist_header_validator import spec122_validator
16
+
17
+ from dkist_processing_cryonirsp.models.exposure_conditions import AllowableOpticalDensityFilterNames
18
+ from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
19
+
20
+
21
+ class CryonirspHeaders(Spec122Dataset):
22
+ def __init__(
23
+ self,
24
+ dataset_shape: tuple[int, ...],
25
+ array_shape: tuple[int, ...],
26
+ time_delta: 10,
27
+ instrument: str = "cryo-nirsp",
28
+ **kwargs,
29
+ ):
30
+ super().__init__(
31
+ dataset_shape=dataset_shape,
32
+ array_shape=array_shape,
33
+ time_delta=time_delta,
34
+ instrument=instrument,
35
+ **kwargs,
36
+ )
37
+ self.add_constant_key("WAVELNTH", 1083.0)
38
+ self.add_constant_key("CUNIT1", "nm")
39
+ self.add_constant_key("CDELT1", 0.2)
40
+ self.add_constant_key("CRVAL1", 1083.0)
41
+ # num modstates
42
+ self.add_constant_key("CRSP_041", 2)
43
+ self.add_constant_key("ID___013", "TEST_PROPOSAL_ID")
44
+ # polarizer_status angle
45
+ self.add_constant_key("PAC__005", "0")
46
+ # retarder_status angle
47
+ self.add_constant_key("PAC__007", "10")
48
+ self.add_constant_key("ID___002", uuid.uuid4().hex)
49
+ self.add_constant_key("CRSP_095", "HeI")
50
+ self.add_constant_key("CRSP_053", 1083.0)
51
+ self.add_constant_key("CRSP_054", 1.0)
52
+
53
+ @key_function("CRSP_042")
54
+ # current modstate
55
+ def current_modstate(self, key: str):
56
+ return choice([1, 2])
57
+
58
+ @key_function("CRSP_035")
59
+ # CNM1POS
60
+ def current_m1_position(self, key: str):
61
+ return random.randrange(-150, 150)
62
+
63
+ @key_function("CRSP_036")
64
+ # CNM1BPOS
65
+ def current_m1b_position(self, key: str):
66
+ return random.randrange(-150, 150)
67
+
68
+ @key_function("CRSP_103")
69
+ # CNM1OFF
70
+ def current_m1_offset(self, key: str):
71
+ return random.randrange(-10, 10)
72
+
73
+ @key_function("CRSP_104")
74
+ # CNM1BOFF
75
+ def current_m1b_offset(self, key: str):
76
+ return random.randrange(-10, 10)
77
+
78
+ @property
79
+ def fits_wcs(self):
80
+ w = WCS(naxis=self.array_ndim)
81
+ w.wcs.crpix = self.array_shape[2] / 2, self.array_shape[1] / 2, 1
82
+ w.wcs.crval = 1083.0, 0, 0
83
+ w.wcs.cdelt = 0.2, 1, 1
84
+ w.wcs.cunit = "nm", "arcsec", "arcsec"
85
+ w.wcs.ctype = "AWAV", "HPLT-TAN", "HPLN-TAN"
86
+ w.wcs.pc = np.identity(self.array_ndim)
87
+ return w
88
+
89
+
90
+ class CryonirspCIHeaders(CryonirspHeaders):
91
+ @property
92
+ def fits_wcs(self):
93
+ w = WCS(naxis=self.array_ndim)
94
+ w.wcs.crpix = self.array_shape[2] / 2, self.array_shape[1] / 2, 1
95
+ w.wcs.crval = 0, 0, 1083.0
96
+ w.wcs.cdelt = 1, 1, 0.2
97
+ w.wcs.cunit = "arcsec", "arcsec", "nm"
98
+ w.wcs.ctype = "HPLN-TAN", "HPLT-TAN", "AWAV"
99
+ w.wcs.pc = np.identity(self.array_ndim)
100
+ return w
101
+
102
+
103
+ class CryonirspHeadersValidNonLinearizedFrames(CryonirspHeaders):
104
+ def __init__(
105
+ self,
106
+ dataset_shape: tuple[int, ...],
107
+ array_shape: tuple[int, ...],
108
+ camera_readout_mode: str,
109
+ time_delta: float,
110
+ roi_x_origin: int,
111
+ roi_x_size: int,
112
+ roi_y_origin: int,
113
+ roi_y_size: int,
114
+ date_obs: str,
115
+ exposure_time: float,
116
+ arm_id: str,
117
+ **kwargs,
118
+ ):
119
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
120
+ self.add_constant_key("DKIST004", "observe")
121
+ self.add_constant_key("ID___004")
122
+ self.add_constant_key("CRSP_001", arm_id)
123
+ self.add_constant_key("CRSP_060", camera_readout_mode)
124
+ self.add_constant_key("CAM__034", roi_x_origin)
125
+ self.add_constant_key("CAM__035", roi_y_origin)
126
+ self.add_constant_key("CAM__036", roi_x_size)
127
+ self.add_constant_key("CAM__037", roi_y_size)
128
+ self.add_constant_key("DATE-OBS", date_obs)
129
+ self.add_constant_key("TEXPOSUR", exposure_time)
130
+ self.add_constant_key("CNFILTNP", AllowableOpticalDensityFilterNames.G358.value)
131
+ self.add_constant_key("DKIST011", "1999-12-31T23:59:59")
132
+
133
+ @key_function("CRSP_063")
134
+ # current frame number in current ramp
135
+ def current_frame_number(self, key: str):
136
+ return self.index
137
+
138
+ @key_function("XPOSURE")
139
+ # set the exposure time for each frame in the ramp
140
+ def exposure_time(self, key: float):
141
+ return 100 * self.index * 0.01
142
+
143
+
144
+ class CryonirspHeadersValidDarkFrames(CryonirspHeaders):
145
+ def __init__(
146
+ self,
147
+ dataset_shape: tuple[int, ...],
148
+ array_shape: tuple[int, ...],
149
+ time_delta: float,
150
+ exposure_time: float,
151
+ **kwargs,
152
+ ):
153
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
154
+ # IP task
155
+ self.add_constant_key("DKIST004", "dark")
156
+ # num dsps repeats
157
+ self.add_constant_key("DKIST008", 1)
158
+ # dsps repeat num
159
+ self.add_constant_key("DKIST009", 1)
160
+ # num scan positions
161
+ self.add_constant_key("CRSP_006", 1)
162
+ # current scan pos
163
+ self.add_constant_key("CRSP_007", 1)
164
+ # inst prog id
165
+ self.add_constant_key("ID___004")
166
+ self.add_constant_key(
167
+ "WAVELNTH", 0.0
168
+ ) # Intentionally bad to make sure it doesn't get parsed
169
+ # cam exposure time
170
+ self.add_constant_key("CAM__004", exposure_time)
171
+ # num_modstates and modstate are always 1 for dark frames
172
+ self.add_constant_key("CRSP_041", 1)
173
+ self.add_constant_key("CRSP_042", 1)
174
+
175
+
176
+ class CryonirspHeadersValidLampGainFrames(CryonirspHeaders):
177
+ def __init__(
178
+ self,
179
+ dataset_shape: tuple[int, ...],
180
+ array_shape: tuple[int, ...],
181
+ time_delta: float,
182
+ **kwargs,
183
+ ):
184
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
185
+ # IP task
186
+ self.add_constant_key("DKIST004", "gain")
187
+ # lamp (clear, lamp, undefined)
188
+ self.add_constant_key("PAC__002", "lamp")
189
+ # num dsps repeats
190
+ self.add_constant_key("DKIST008", 1)
191
+ # dsps repeat num
192
+ self.add_constant_key("DKIST009", 1)
193
+ # num scan positions
194
+ self.add_constant_key("CRSP_006", 1)
195
+ # current scan pos
196
+ self.add_constant_key("CRSP_007", 1)
197
+ # lamp status
198
+ self.add_constant_key("PAC__003", "on")
199
+ # inst prog id
200
+ self.add_constant_key("ID___004")
201
+ # num_modstates and modstate are always 1 for gain frames
202
+ self.add_constant_key("CRSP_041", 1)
203
+ self.add_constant_key("CRSP_042", 1)
204
+ # cam exposure time
205
+ self.add_constant_key("CAM__004", 10.0)
206
+
207
+
208
+ class CryonirspHeadersValidCISolarGainFrames(CryonirspHeaders):
209
+ def __init__(
210
+ self,
211
+ dataset_shape: tuple[int, ...],
212
+ array_shape: tuple[int, ...],
213
+ time_delta: float,
214
+ **kwargs,
215
+ ):
216
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
217
+ # IP task
218
+ self.add_constant_key("DKIST004", "gain")
219
+ # num dsps repeats
220
+ self.add_constant_key("DKIST008", 1)
221
+ # dsps repeat num
222
+ self.add_constant_key("DKIST009", 1)
223
+ # num scan positions
224
+ self.add_constant_key("CRSP_006", 1)
225
+ # current scan pos
226
+ self.add_constant_key("CRSP_007", 1)
227
+ # lamp (clear, lamp, undefined)
228
+ self.add_constant_key("PAC__002", "clear")
229
+ self.add_constant_key("TELSCAN", "Raster")
230
+ # inst prog id
231
+ self.add_constant_key("ID___004")
232
+ # num_modstates and modstate are always 1 for gain frames
233
+ self.add_constant_key("CRSP_041", 1)
234
+ self.add_constant_key("CRSP_042", 1)
235
+ # cam exposure time
236
+ self.add_constant_key("CAM__004", 20.0)
237
+ # arm_id
238
+ self.add_constant_key("CRSP_001", "CI")
239
+
240
+
241
+ class CryonirspHeadersValidSPSolarGainFrames(CryonirspHeaders):
242
+ def __init__(
243
+ self,
244
+ dataset_shape: tuple[int, ...],
245
+ array_shape: tuple[int, ...],
246
+ time_delta: float,
247
+ **kwargs,
248
+ ):
249
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
250
+ # IP task
251
+ self.add_constant_key("DKIST004", "gain")
252
+ # num dsps repeats
253
+ self.add_constant_key("DKIST008", 1)
254
+ # dsps repeat num
255
+ self.add_constant_key("DKIST009", 1)
256
+ # num scan positions
257
+ self.add_constant_key("CRSP_006", 1)
258
+ # current scan pos
259
+ self.add_constant_key("CRSP_007", 1)
260
+ # lamp (clear, lamp, undefined)
261
+ self.add_constant_key("PAC__002", "clear")
262
+ self.add_constant_key("TELSCAN", "Raster")
263
+ # inst prog id
264
+ self.add_constant_key("ID___004")
265
+ # num_modstates and modstate are always 1 for gain frames
266
+ self.add_constant_key("CRSP_041", 1)
267
+ self.add_constant_key("CRSP_042", 1)
268
+ # cam exposure time
269
+ self.add_constant_key("CAM__004", 20.0)
270
+ # arm_id
271
+ self.add_constant_key("CRSP_001", "SP")
272
+
273
+
274
+ class CryonirspHeadersValidPolcalFrames(CryonirspHeaders):
275
+ def __init__(
276
+ self,
277
+ dataset_shape: tuple[int, ...],
278
+ array_shape: tuple[int, ...],
279
+ time_delta: float,
280
+ num_modstates: int,
281
+ modstate: int,
282
+ **kwargs,
283
+ ):
284
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
285
+ self.add_constant_key("DKIST004", "polcal")
286
+ self.add_constant_key("DKIST008", 1)
287
+ self.add_constant_key("DKIST009", 1)
288
+ self.add_constant_key("CRSP_006", 1)
289
+ self.add_constant_key("CRSP_007", 1)
290
+ self.add_constant_key("TELSCAN", "Raster")
291
+ self.add_constant_key("ID___004")
292
+ self.add_constant_key("PAC__004", "Sapphire Polarizer")
293
+ self.add_constant_key("PAC__005", "60.")
294
+ self.add_constant_key("PAC__006", "clear")
295
+ self.add_constant_key("PAC__007", "0.0")
296
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
297
+ self.add_constant_key("CRSP_041", num_modstates)
298
+ self.add_constant_key("CRSP_042", modstate)
299
+ self.add_constant_key("CRSP_044", "Continuous")
300
+ self.add_constant_key("CAM__004", 0.01)
301
+
302
+
303
+ class CryonirspHeadersValidObserveFrames(CryonirspHeaders):
304
+ def __init__(
305
+ self,
306
+ dataset_shape: tuple[int, ...],
307
+ array_shape: tuple[int, ...],
308
+ time_delta: float,
309
+ num_map_scans: int,
310
+ map_scan: int,
311
+ num_scan_steps: int,
312
+ scan_step: int,
313
+ num_modstates: int,
314
+ modstate: int,
315
+ num_meas: int,
316
+ meas_num: int,
317
+ arm_id: str,
318
+ num_sub_repeats=1,
319
+ sub_repeat_num=1,
320
+ **kwargs,
321
+ ):
322
+ super().__init__(dataset_shape, array_shape, time_delta, **kwargs)
323
+ self.num_map_scans = num_map_scans
324
+ self.num_scan_steps = num_scan_steps
325
+ self.meas_num = meas_num
326
+ self.add_constant_key("NAXIS1", 2048)
327
+ self.add_constant_key("CRSP_101", num_sub_repeats)
328
+ self.add_constant_key("CRSP_102", sub_repeat_num)
329
+ self.add_constant_key("DKIST004", "observe")
330
+ self.add_constant_key("CRSP_001", arm_id)
331
+ self.add_constant_key("CRSP_006", num_scan_steps)
332
+ self.add_constant_key("CRSP_007", scan_step)
333
+ self.add_constant_key("DKIST008", num_map_scans)
334
+ self.add_constant_key("DKIST009", map_scan)
335
+ self.add_constant_key("ID___004")
336
+ self.add_constant_key("CRSP_041", num_modstates)
337
+ self.add_constant_key("CRSP_042", modstate)
338
+ self.add_constant_key("CRSP_044", "Continuous")
339
+ self.add_constant_key("CRSP_057", num_meas)
340
+ self.add_constant_key("CRSP_058", meas_num)
341
+ self.add_constant_key("WAVELNTH", 1080.2)
342
+ self.add_constant_key("ID___012", "EXPERIMENT ID")
343
+
344
+ @key_function("CAM__004")
345
+ def exposure_time(self, key: str) -> float:
346
+ return 0.02 if self.index % 2 == 0 else 0.03
347
+
348
+
349
+ class Cryonirsp122ObserveFrames(CryonirspHeaders):
350
+ def __init__(
351
+ self,
352
+ array_shape: tuple[int, ...],
353
+ num_steps: int = 4,
354
+ num_exp_per_step: int = 1,
355
+ num_map_scans: int = 5,
356
+ ):
357
+ super().__init__(
358
+ array_shape=array_shape,
359
+ time_delta=10,
360
+ dataset_shape=(num_exp_per_step * num_steps * num_map_scans,) + array_shape[-2:],
361
+ )
362
+ self.add_constant_key("DKIST004", "observe")
363
+
364
+
365
+ class SimpleModulatedHeaders(CryonirspHeaders):
366
+ def __init__(
367
+ self,
368
+ num_modstates: int,
369
+ modstate: int,
370
+ array_shape: tuple[int, ...],
371
+ task: str,
372
+ exposure_condition: ExposureConditions = ExposureConditions(
373
+ 6.0, AllowableOpticalDensityFilterNames.OPEN.value
374
+ ),
375
+ start_date: str = "2023-01-01T01:23:45",
376
+ modstate_length_sec: float = 0.5,
377
+ ):
378
+ dataset_shape = (1, *array_shape)
379
+ super().__init__(
380
+ dataset_shape=dataset_shape,
381
+ array_shape=array_shape,
382
+ start_time=datetime.datetime.fromisoformat(start_date),
383
+ time_delta=modstate_length_sec,
384
+ )
385
+
386
+ grating_angle_deg = 264984.2432
387
+ grating_littrow_angle = 173832.95442475166
388
+ grating_constant = 770970.3576216539
389
+ CRVAL1 = 1.083e-06
390
+ CRPIX1 = 0.5
391
+ CDELT1 = 2e-10
392
+
393
+ self.add_constant_key("DKIST004", task)
394
+ self.add_constant_key("CRSP_041", num_modstates)
395
+ self.add_constant_key("CRSP_042", modstate)
396
+ self.add_constant_key("CAM__004", exposure_condition.exposure_time)
397
+ self.add_constant_key("CRSP_048", exposure_condition.filter_name)
398
+ self.add_constant_key("CRSP_074", grating_angle_deg)
399
+ self.add_constant_key("CRSP_079", grating_littrow_angle)
400
+ self.add_constant_key("CRSP_077", grating_constant)
401
+ self.add_constant_key("CRVAL1", CRVAL1)
402
+ self.add_constant_key("CRPIX1", CRPIX1)
403
+ self.add_constant_key("CDELT1", CDELT1)
404
+
405
+
406
+ class ModulatedLampGainHeaders(SimpleModulatedHeaders):
407
+ def __init__(
408
+ self,
409
+ array_shape: tuple[int, ...],
410
+ exposure_condition: ExposureConditions,
411
+ start_date: str = "2023-01-01T01:23:45",
412
+ modstate_length_sec: float = 0.5,
413
+ num_modstates: int = 1,
414
+ modstate: int = 1,
415
+ ):
416
+ super().__init__(
417
+ num_modstates=num_modstates,
418
+ modstate=modstate,
419
+ array_shape=array_shape,
420
+ task="gain",
421
+ exposure_condition=exposure_condition,
422
+ start_date=start_date,
423
+ modstate_length_sec=modstate_length_sec,
424
+ )
425
+
426
+ self.add_constant_key("PAC__002", "lamp")
427
+ self.add_constant_key("PAC__003", "on")
428
+ # num dsps repeats
429
+ self.add_constant_key("DKIST008", 1)
430
+ # dsps repeat num
431
+ self.add_constant_key("DKIST009", 1)
432
+ # num scan positions
433
+ self.add_constant_key("CRSP_006", 1)
434
+ # current scan pos
435
+ self.add_constant_key("CRSP_007", 1)
436
+ self.add_constant_key("ID___004")
437
+
438
+
439
+ class ModulatedSolarGainHeaders(SimpleModulatedHeaders):
440
+ def __init__(
441
+ self,
442
+ array_shape: tuple[int, ...],
443
+ exposure_condition: ExposureConditions,
444
+ start_date: str = "2023-01-01T01:23:45",
445
+ modstate_length_sec: float = 0.5,
446
+ num_modstates: int = 1,
447
+ modstate: int = 1,
448
+ ):
449
+ super().__init__(
450
+ num_modstates=num_modstates,
451
+ modstate=modstate,
452
+ array_shape=array_shape,
453
+ task="gain",
454
+ exposure_condition=exposure_condition,
455
+ start_date=start_date,
456
+ modstate_length_sec=modstate_length_sec,
457
+ )
458
+
459
+ self.add_constant_key("PAC__002", "clear")
460
+ self.add_constant_key("PAC__003", "undefined")
461
+ self.add_constant_key("TELSCAN", "Raster")
462
+ # num dsps repeats
463
+ self.add_constant_key("DKIST008", 1)
464
+ # dsps repeat num
465
+ self.add_constant_key("DKIST009", 1)
466
+ # num scan positions
467
+ self.add_constant_key("CRSP_006", 1)
468
+ # current scan pos
469
+ self.add_constant_key("CRSP_007", 1)
470
+ # inst prog id
471
+ self.add_constant_key("ID___004")
472
+
473
+
474
+ class ModulatedDarkHeaders(SimpleModulatedHeaders):
475
+ def __init__(
476
+ self,
477
+ array_shape: tuple[int, ...],
478
+ exposure_condition: ExposureConditions,
479
+ start_date: str = "2023-01-01T01:23:45",
480
+ modstate_length_sec: float = 0.5,
481
+ num_modstates: int = 1,
482
+ modstate: int = 1,
483
+ ):
484
+ super().__init__(
485
+ num_modstates=num_modstates,
486
+ modstate=modstate,
487
+ array_shape=array_shape,
488
+ task="dark",
489
+ exposure_condition=exposure_condition,
490
+ start_date=start_date,
491
+ modstate_length_sec=modstate_length_sec,
492
+ )
493
+
494
+ # num dsps repeats
495
+ self.add_constant_key("DKIST008", 1)
496
+ # dsps repeat num
497
+ self.add_constant_key("DKIST009", 1)
498
+ # num scan positions
499
+ self.add_constant_key("CRSP_006", 1)
500
+ # current scan pos
501
+ self.add_constant_key("CRSP_007", 1)
502
+ # inst prog id
503
+ self.add_constant_key("ID___004")
504
+ self.add_constant_key("WAVELNTH", 0.0)
505
+
506
+
507
+ class ModulatedPolcalHeaders(SimpleModulatedHeaders):
508
+ def __init__(
509
+ self,
510
+ num_modstates: int,
511
+ modstate: int,
512
+ array_shape: tuple[int, ...],
513
+ exposure_condition: ExposureConditions,
514
+ extra_headers: dict | None = None,
515
+ start_date: str = "2023-01-01T01:23:45",
516
+ modstate_length_sec: float = 0.5,
517
+ ):
518
+ super().__init__(
519
+ num_modstates=num_modstates,
520
+ modstate=modstate,
521
+ array_shape=array_shape,
522
+ task="polcal",
523
+ exposure_condition=exposure_condition,
524
+ start_date=start_date,
525
+ modstate_length_sec=modstate_length_sec,
526
+ )
527
+
528
+ self.add_constant_key("DKIST004", "polcal")
529
+ self.add_constant_key("DKIST008", 1)
530
+ self.add_constant_key("DKIST009", 1)
531
+ self.add_constant_key("CRSP_006", 1)
532
+ self.add_constant_key("CRSP_007", 1)
533
+ self.add_constant_key("TELSCAN", "Raster")
534
+ self.add_constant_key("ID___004")
535
+ self.add_constant_key("PAC__005", "60.")
536
+ self.add_constant_key("PAC__007", "0.0")
537
+ self.add_constant_key("CRSP_044", "Continuous")
538
+
539
+ if extra_headers != None:
540
+ for header, value in extra_headers.items():
541
+ self.add_constant_key(header, value)
542
+ else:
543
+ self.add_constant_key("PAC__004", "Sapphire Polarizer")
544
+ self.add_constant_key("PAC__006", "clear")
545
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
546
+
547
+
548
+ class ModulatedObserveHeaders(SimpleModulatedHeaders):
549
+ def __init__(
550
+ self,
551
+ num_modstates: int,
552
+ modstate: int,
553
+ array_shape: tuple[int, ...],
554
+ exposure_condition: ExposureConditions,
555
+ num_map_scans: int,
556
+ num_scan_steps: int,
557
+ scan_step: int,
558
+ map_scan: int,
559
+ num_meas: int,
560
+ num_sub_repeats: int,
561
+ sub_repeat_num: int,
562
+ arm_id: str,
563
+ start_date: str = "2023-01-01T01:23:45",
564
+ modstate_length_sec: float = 0.5,
565
+ meas_num: int = 1,
566
+ ):
567
+ super().__init__(
568
+ num_modstates=num_modstates,
569
+ modstate=modstate,
570
+ array_shape=array_shape,
571
+ task="observe",
572
+ exposure_condition=exposure_condition,
573
+ start_date=start_date,
574
+ modstate_length_sec=modstate_length_sec,
575
+ )
576
+
577
+ self.num_map_scans = num_map_scans
578
+ self.num_scan_steps = num_scan_steps
579
+ self.meas_num = meas_num
580
+ self.add_constant_key("CRSP_101", num_sub_repeats)
581
+ self.add_constant_key("CRSP_102", sub_repeat_num)
582
+ self.add_constant_key("CRSP_001", arm_id)
583
+ self.add_constant_key("CRSP_006", num_scan_steps)
584
+ self.add_constant_key("CRSP_007", scan_step)
585
+ self.add_constant_key("DKIST008", num_map_scans)
586
+ self.add_constant_key("DKIST009", map_scan)
587
+ self.add_constant_key("ID___004")
588
+ self.add_constant_key("CRSP_044", "Continuous")
589
+ self.add_constant_key("CRSP_057", num_meas)
590
+ self.add_constant_key("CRSP_058", meas_num)
591
+ self.add_constant_key("WAVELNTH", 1080.2)
592
+ self.add_constant_key("ID___012", "EXPERIMENT ID")