dkist-processing-common 10.5.4__py3-none-any.whl → 12.1.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. changelog/280.misc.rst +1 -0
  2. changelog/282.feature.2.rst +2 -0
  3. changelog/282.feature.rst +2 -0
  4. changelog/284.feature.rst +1 -0
  5. changelog/285.feature.rst +2 -0
  6. changelog/285.misc.rst +2 -0
  7. changelog/286.feature.rst +2 -0
  8. changelog/287.misc.rst +1 -0
  9. dkist_processing_common/__init__.py +1 -0
  10. dkist_processing_common/_util/constants.py +1 -0
  11. dkist_processing_common/_util/graphql.py +1 -0
  12. dkist_processing_common/_util/scratch.py +9 -9
  13. dkist_processing_common/_util/tags.py +1 -0
  14. dkist_processing_common/codecs/array.py +20 -0
  15. dkist_processing_common/codecs/asdf.py +9 -3
  16. dkist_processing_common/codecs/basemodel.py +22 -0
  17. dkist_processing_common/codecs/bytes.py +1 -0
  18. dkist_processing_common/codecs/fits.py +37 -9
  19. dkist_processing_common/codecs/iobase.py +1 -0
  20. dkist_processing_common/codecs/json.py +1 -0
  21. dkist_processing_common/codecs/path.py +1 -0
  22. dkist_processing_common/codecs/quality.py +1 -1
  23. dkist_processing_common/codecs/str.py +1 -0
  24. dkist_processing_common/config.py +64 -25
  25. dkist_processing_common/manual.py +6 -8
  26. dkist_processing_common/models/constants.py +373 -37
  27. dkist_processing_common/models/dkist_location.py +27 -0
  28. dkist_processing_common/models/fits_access.py +48 -0
  29. dkist_processing_common/models/flower_pot.py +231 -9
  30. dkist_processing_common/models/fried_parameter.py +41 -0
  31. dkist_processing_common/models/graphql.py +66 -75
  32. dkist_processing_common/models/input_dataset.py +117 -0
  33. dkist_processing_common/models/message.py +1 -1
  34. dkist_processing_common/models/message_queue_binding.py +1 -1
  35. dkist_processing_common/models/metric_code.py +2 -0
  36. dkist_processing_common/models/parameters.py +65 -28
  37. dkist_processing_common/models/quality.py +50 -5
  38. dkist_processing_common/models/tags.py +23 -21
  39. dkist_processing_common/models/task_name.py +3 -2
  40. dkist_processing_common/models/telemetry.py +28 -0
  41. dkist_processing_common/models/wavelength.py +3 -1
  42. dkist_processing_common/parsers/average_bud.py +46 -0
  43. dkist_processing_common/parsers/cs_step.py +13 -12
  44. dkist_processing_common/parsers/dsps_repeat.py +6 -4
  45. dkist_processing_common/parsers/experiment_id_bud.py +12 -4
  46. dkist_processing_common/parsers/id_bud.py +42 -27
  47. dkist_processing_common/parsers/l0_fits_access.py +5 -3
  48. dkist_processing_common/parsers/l1_fits_access.py +51 -23
  49. dkist_processing_common/parsers/lookup_bud.py +125 -0
  50. dkist_processing_common/parsers/near_bud.py +21 -20
  51. dkist_processing_common/parsers/observing_program_id_bud.py +24 -0
  52. dkist_processing_common/parsers/proposal_id_bud.py +13 -5
  53. dkist_processing_common/parsers/quality.py +2 -0
  54. dkist_processing_common/parsers/retarder.py +32 -0
  55. dkist_processing_common/parsers/single_value_single_key_flower.py +6 -1
  56. dkist_processing_common/parsers/task.py +8 -6
  57. dkist_processing_common/parsers/time.py +178 -72
  58. dkist_processing_common/parsers/unique_bud.py +21 -22
  59. dkist_processing_common/parsers/wavelength.py +5 -3
  60. dkist_processing_common/tasks/__init__.py +3 -2
  61. dkist_processing_common/tasks/assemble_movie.py +4 -3
  62. dkist_processing_common/tasks/base.py +59 -60
  63. dkist_processing_common/tasks/l1_output_data.py +54 -53
  64. dkist_processing_common/tasks/mixin/globus.py +24 -27
  65. dkist_processing_common/tasks/mixin/interservice_bus.py +1 -0
  66. dkist_processing_common/tasks/mixin/metadata_store.py +108 -243
  67. dkist_processing_common/tasks/mixin/object_store.py +22 -0
  68. dkist_processing_common/tasks/mixin/quality/__init__.py +1 -0
  69. dkist_processing_common/tasks/mixin/quality/_base.py +8 -1
  70. dkist_processing_common/tasks/mixin/quality/_metrics.py +166 -14
  71. dkist_processing_common/tasks/output_data_base.py +4 -3
  72. dkist_processing_common/tasks/parse_l0_input_data.py +277 -15
  73. dkist_processing_common/tasks/quality_metrics.py +9 -9
  74. dkist_processing_common/tasks/teardown.py +7 -7
  75. dkist_processing_common/tasks/transfer_input_data.py +67 -69
  76. dkist_processing_common/tasks/trial_catalog.py +77 -17
  77. dkist_processing_common/tasks/trial_output_data.py +16 -17
  78. dkist_processing_common/tasks/write_l1.py +102 -72
  79. dkist_processing_common/tests/conftest.py +32 -173
  80. dkist_processing_common/tests/mock_metadata_store.py +271 -0
  81. dkist_processing_common/tests/test_assemble_movie.py +4 -4
  82. dkist_processing_common/tests/test_assemble_quality.py +32 -4
  83. dkist_processing_common/tests/test_base.py +5 -19
  84. dkist_processing_common/tests/test_codecs.py +103 -12
  85. dkist_processing_common/tests/test_constants.py +15 -0
  86. dkist_processing_common/tests/test_dkist_location.py +15 -0
  87. dkist_processing_common/tests/test_fits_access.py +56 -19
  88. dkist_processing_common/tests/test_flower_pot.py +147 -5
  89. dkist_processing_common/tests/test_fried_parameter.py +27 -0
  90. dkist_processing_common/tests/test_input_dataset.py +78 -361
  91. dkist_processing_common/tests/test_interservice_bus.py +1 -0
  92. dkist_processing_common/tests/test_interservice_bus_mixin.py +1 -1
  93. dkist_processing_common/tests/test_manual_processing.py +33 -0
  94. dkist_processing_common/tests/test_output_data_base.py +5 -7
  95. dkist_processing_common/tests/test_parameters.py +71 -22
  96. dkist_processing_common/tests/test_parse_l0_input_data.py +115 -32
  97. dkist_processing_common/tests/test_publish_catalog_messages.py +2 -24
  98. dkist_processing_common/tests/test_quality.py +1 -0
  99. dkist_processing_common/tests/test_quality_mixin.py +255 -23
  100. dkist_processing_common/tests/test_scratch.py +2 -1
  101. dkist_processing_common/tests/test_stems.py +511 -168
  102. dkist_processing_common/tests/test_submit_dataset_metadata.py +3 -7
  103. dkist_processing_common/tests/test_tags.py +1 -0
  104. dkist_processing_common/tests/test_task_name.py +1 -1
  105. dkist_processing_common/tests/test_task_parsing.py +17 -7
  106. dkist_processing_common/tests/test_teardown.py +28 -24
  107. dkist_processing_common/tests/test_transfer_input_data.py +270 -125
  108. dkist_processing_common/tests/test_transfer_l1_output_data.py +2 -3
  109. dkist_processing_common/tests/test_trial_catalog.py +83 -8
  110. dkist_processing_common/tests/test_trial_output_data.py +46 -73
  111. dkist_processing_common/tests/test_workflow_task_base.py +8 -10
  112. dkist_processing_common/tests/test_write_l1.py +298 -76
  113. dkist_processing_common-12.1.0rc1.dist-info/METADATA +265 -0
  114. dkist_processing_common-12.1.0rc1.dist-info/RECORD +134 -0
  115. {dkist_processing_common-10.5.4.dist-info → dkist_processing_common-12.1.0rc1.dist-info}/WHEEL +1 -1
  116. docs/conf.py +1 -0
  117. docs/index.rst +1 -1
  118. docs/landing_page.rst +13 -0
  119. dkist_processing_common/tasks/mixin/input_dataset.py +0 -166
  120. dkist_processing_common-10.5.4.dist-info/METADATA +0 -175
  121. dkist_processing_common-10.5.4.dist-info/RECORD +0 -112
  122. {dkist_processing_common-10.5.4.dist-info → dkist_processing_common-12.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -4,21 +4,24 @@ Components of the Constant model.
4
4
  Contains names of database entries and Base class for an object that simplifies
5
5
  accessing the database (tab completion, etc.)
6
6
  """
7
- from enum import Enum
7
+
8
+ from enum import StrEnum
9
+ from enum import unique
8
10
  from string import ascii_uppercase
9
11
 
10
- from hashids import Hashids
12
+ from sqids import Sqids
11
13
 
12
14
  from dkist_processing_common._util.constants import ConstantsDb
13
15
 
14
16
 
15
- class BudName(str, Enum):
17
+ @unique
18
+ class BudName(StrEnum):
16
19
  """Controlled list of names for constant stems (buds)."""
17
20
 
18
- recipe_run_id = "RECIPE_RUN_ID"
19
21
  instrument = "INSTRUMENT"
20
22
  num_cs_steps = "NUM_CS_STEPS"
21
23
  num_modstates = "NUM_MODSTATES"
24
+ retarder_name = "RETARDER_NAME"
22
25
  proposal_id = "PROPOSAL_ID"
23
26
  contributing_proposal_ids = "CONTRIBUTING_PROPOSAL_IDS"
24
27
  experiment_id = "EXPERIMENT_ID"
@@ -32,6 +35,59 @@ class BudName(str, Enum):
32
35
  dark_exposure_times = "DARK_EXPOSURE_TIMES"
33
36
  dark_readout_exp_times = "DARK_READOUT_EXP_TIMES"
34
37
  wavelength = "WAVELENGTH"
38
+ camera_id = "CAMERA_ID"
39
+ camera_name = "CAMERA_NAME"
40
+ camera_bit_depth = "CAMERA_BIT_DEPTH"
41
+ hardware_binning_x = "HARDWARE_BINNING_X"
42
+ hardware_binning_y = "HARDWARE_BINNING_Y"
43
+ software_binning_x = "SOFTWARE_BINNING_X"
44
+ software_binning_y = "SOFTWARE_BINNING_Y"
45
+ hls_version = "HLS_VERSION"
46
+ # Multi-task buds start here:
47
+ dark_observing_program_execution_ids = "DARK_OBSERVING_PROGRAM_EXECUTION_IDS"
48
+ solar_gain_observing_program_execution_ids = "SOLAR_GAIN_OBSERVING_PROGRAM_EXECUTION_IDS"
49
+ polcal_observing_program_execution_ids = "POLCAL_OBSERVING_PROGRAM_EXECUTION_IDS"
50
+ dark_date_begin = "DARK_DATE_BEGIN"
51
+ solar_gain_date_begin = "SOLAR_GAIN_DATE_BEGIN"
52
+ polcal_date_begin = "POLCAL_DATE_BEGIN"
53
+ dark_date_end = "DARK_DATE_END"
54
+ solar_gain_date_end = "SOLAR_GAIN_DATE_END"
55
+ polcal_date_end = "POLCAL_DATE_END"
56
+ dark_num_raw_frames_per_fpa = "DARK_NUM_RAW_FRAMES_PER_FPA"
57
+ solar_gain_num_raw_frames_per_fpa = "SOLAR_GAIN_NUM_RAW_FRAMES_PER_FPA"
58
+ polcal_num_raw_frames_per_fpa = "POLCAL_NUM_RAW_FRAMES_PER_FPA"
59
+ solar_gain_telescope_tracking_mode = "SOLAR_GAIN_TELESCOPE_TRACKING_MODE"
60
+ polcal_telescope_tracking_mode = "POLCAL_TELESCOPE_TRACKING_MODE"
61
+ solar_gain_coude_table_tracking_mode = "SOLAR_GAIN_COUDE_TABLE_TRACKING_MODE"
62
+ polcal_coude_table_tracking_mode = "POLCAL_COUDE_TABLE_TRACKING_MODE"
63
+ solar_gain_telescope_scanning_mode = "SOLAR_GAIN_TELESCOPE_SCANNING_MODE"
64
+ polcal_telescope_scanning_mode = "POLCAL_TELESCOPE_SCANNING_MODE"
65
+ dark_average_light_level = "DARK_AVERAGE_LIGHT_LEVEL"
66
+ solar_gain_average_light_level = "SOLAR_GAIN_AVERAGE_LIGHT_LEVEL"
67
+ polcal_average_light_level = "POLCAL_AVERAGE_LIGHT_LEVEL"
68
+ dark_average_telescope_elevation = "DARK_AVERAGE_TELESCOPE_ELEVATION"
69
+ solar_gain_average_telescope_elevation = "SOLAR_GAIN_AVERAGE_TELESCOPE_ELEVATION"
70
+ polcal_average_telescope_elevation = "POLCAL_AVERAGE_TELESCOPE_ELEVATION"
71
+ dark_average_coude_table_angle = "DARK_AVERAGE_COUDE_TABLE_ANGLE"
72
+ solar_gain_average_coude_table_angle = "SOLAR_GAIN_AVERAGE_COUDE_TABLE_ANGLE"
73
+ polcal_average_coude_table_angle = "POLCAL_AVERAGE_COUDE_TABLE_ANGLE"
74
+ dark_average_telescope_azimuth = "DARK_AVERAGE_TELESCOPE_AZIMUTH"
75
+ solar_gain_average_telescope_azimuth = "SOLAR_GAIN_AVERAGE_TELESCOPE_AZIMUTH"
76
+ polcal_average_telescope_azimuth = "POLCAL_AVERAGE_TELESCOPE_AZIMUTH"
77
+ dark_gos_level3_status = "DARK_GOS_LEVEL3_STATUS"
78
+ solar_gain_gos_level3_status = "SOLAR_GAIN_GOS_LEVEL3_STATUS"
79
+ dark_gos_level3_lamp_status = "DARK_GOS_LEVEL3_LAMP_STATUS"
80
+ solar_gain_gos_level3_lamp_status = "SOLAR_GAIN_GOS_LEVEL3_LAMP_STATUS"
81
+ dark_gos_polarizer_status = "DARK_GOS_POLARIZER_STATUS"
82
+ solar_gain_gos_polarizer_status = "SOLAR_GAIN_GOS_POLARIZER_STATUS"
83
+ dark_gos_polarizer_angle = "DARK_GOS_POLARIZER_ANGLE"
84
+ solar_gain_gos_polarizer_angle = "SOLAR_GAIN_GOS_POLARIZER_ANGLE"
85
+ dark_gos_retarder_status = "DARK_GOS_RETARDER_STATUS"
86
+ solar_gain_gos_retarder_status = "SOLAR_GAIN_GOS_RETARDER_STATUS"
87
+ dark_gos_retarder_angle = "DARK_GOS_RETARDER_ANGLE"
88
+ solar_gain_gos_retarder_angle = "SOLAR_GAIN_GOS_RETARDER_ANGLE"
89
+ dark_gos_level0_status = "DARK_GOS_LEVEL0_STATUS"
90
+ solar_gain_gos_level0_status = "SOLAR_GAIN_GOS_LEVEL0_STATUS"
35
91
 
36
92
 
37
93
  class ConstantsBase:
@@ -61,7 +117,7 @@ class ConstantsBase:
61
117
  Parameters
62
118
  ----------
63
119
  recipe_run_id
64
- Thew recipe_run_id
120
+ The recipe_run_id
65
121
  task_name
66
122
  The task_name
67
123
  """
@@ -86,35 +142,64 @@ class ConstantsBase:
86
142
 
87
143
  @property
88
144
  def dataset_id(self) -> str:
89
- """Define the dataset_id constant."""
90
- return Hashids(min_length=5, alphabet=ascii_uppercase).encode(self._recipe_run_id)
145
+ """Define the dataset id constant."""
146
+ return Sqids(min_length=6, alphabet=ascii_uppercase).encode([self._recipe_run_id])
147
+
148
+ @property
149
+ def stokes_params(self) -> list[str]:
150
+ """Return the list of stokes parameter names."""
151
+ return ["I", "Q", "U", "V"]
152
+
153
+ @property
154
+ def instrument(self) -> str:
155
+ """Get the instrument name."""
156
+ return self._db_dict[BudName.instrument]
157
+
158
+ @property
159
+ def num_cs_steps(self) -> int:
160
+ """Get the number of calibration sequence steps."""
161
+ return self._db_dict[BudName.num_cs_steps]
162
+
163
+ @property
164
+ def num_modstates(self) -> int:
165
+ """Get the number of modulation states."""
166
+ return self._db_dict[BudName.num_modstates]
167
+
168
+ @property
169
+ def retarder_name(self) -> str:
170
+ """Get the retarder name."""
171
+ return self._db_dict[BudName.retarder_name]
91
172
 
92
173
  @property
93
174
  def proposal_id(self) -> str:
94
- """Get the proposal_id constant."""
175
+ """Get the proposal ID constant."""
95
176
  return self._db_dict[BudName.proposal_id]
96
177
 
97
178
  @property
98
- def contributing_proposal_ids(self) -> [str]:
179
+ def contributing_proposal_ids(self) -> list[str]:
99
180
  """Return the list of contributing proposal IDs."""
100
181
  proposal_ids = self._db_dict[BudName.contributing_proposal_ids]
101
- if isinstance(proposal_ids, str):
102
- return [proposal_ids]
103
- return proposal_ids
182
+ return list(proposal_ids)
104
183
 
105
184
  @property
106
- def instrument(self) -> str:
107
- """Get the instrument name."""
108
- return self._db_dict[BudName.instrument]
185
+ def experiment_id(self) -> str:
186
+ """Get the experiment ID constant."""
187
+ return self._db_dict[BudName.experiment_id]
188
+
189
+ @property
190
+ def contributing_experiment_ids(self) -> list[str]:
191
+ """Return the list of contributing experiment IDs."""
192
+ experiment_ids = self._db_dict[BudName.contributing_experiment_ids]
193
+ return list(experiment_ids)
109
194
 
110
195
  @property
111
196
  def obs_ip_start_time(self) -> str:
112
197
  """Return the start time of the observe IP."""
113
- return self._db_dict[BudName.obs_ip_start_time.value]
198
+ return self._db_dict[BudName.obs_ip_start_time]
114
199
 
115
200
  @property
116
201
  def average_cadence(self) -> float:
117
- """Get the average_cadence constant."""
202
+ """Get the average cadence constant."""
118
203
  return self._db_dict[BudName.average_cadence]
119
204
 
120
205
  @property
@@ -138,34 +223,285 @@ class ConstantsBase:
138
223
  return self._db_dict[BudName.num_dsps_repeats]
139
224
 
140
225
  @property
141
- def dark_exposure_times(self) -> [float]:
226
+ def dark_exposure_times(self) -> list[float]:
142
227
  """Get a list of exposure times used in the dark calibration."""
143
- return self._db_dict[BudName.dark_exposure_times]
228
+ exposure_times = self._db_dict[BudName.dark_exposure_times]
229
+ return list(exposure_times)
144
230
 
145
231
  @property
146
- def dark_readout_exp_times(self) -> [float]:
147
- """Get a list of readout exp times for all DARK frames."""
148
- return self._db_dict[BudName.dark_readout_exp_times]
232
+ def dark_readout_exp_times(self) -> list[float]:
233
+ """Get a list of readout exp times for all dark frames."""
234
+ readout_times = self._db_dict[BudName.dark_readout_exp_times]
235
+ return list(readout_times)
149
236
 
150
237
  @property
151
- def stokes_params(self) -> [str]:
152
- """Return the list of stokes parameter names."""
153
- return ["I", "Q", "U", "V"]
238
+ def wavelength(self) -> float:
239
+ """Wavelength."""
240
+ return self._db_dict[BudName.wavelength]
154
241
 
155
242
  @property
156
- def experiment_id(self) -> str:
157
- """Get the experiment_id constant."""
158
- return self._db_dict[BudName.experiment_id]
243
+ def camera_id(self) -> str:
244
+ """Return the camera ID constant."""
245
+ return self._db_dict[BudName.camera_id]
159
246
 
160
247
  @property
161
- def contributing_experiment_ids(self) -> [str]:
162
- """Return the list of contributing experiment IDs."""
163
- experiment_ids = self._db_dict[BudName.contributing_experiment_ids]
164
- if isinstance(experiment_ids, str):
165
- return [experiment_ids]
166
- return experiment_ids
248
+ def camera_name(self) -> str:
249
+ """Return the camera name for humans constant."""
250
+ return self._db_dict[BudName.camera_name]
167
251
 
168
252
  @property
169
- def wavelength(self) -> float:
170
- """Wavelength."""
171
- return self._db_dict[BudName.wavelength.value]
253
+ def camera_bit_depth(self) -> int:
254
+ """Return the camera bit depth constant."""
255
+ return self._db_dict[BudName.camera_bit_depth]
256
+
257
+ @property
258
+ def hardware_binning_x(self) -> int:
259
+ """Return the x-direction hardware binning constant."""
260
+ return self._db_dict[BudName.hardware_binning_x]
261
+
262
+ @property
263
+ def hardware_binning_y(self) -> int:
264
+ """Return the y-direction hardware binning constant."""
265
+ return self._db_dict[BudName.hardware_binning_y]
266
+
267
+ @property
268
+ def software_binning_x(self) -> int:
269
+ """Return the x-direction software binning constant."""
270
+ return self._db_dict[BudName.software_binning_x]
271
+
272
+ @property
273
+ def software_binning_y(self) -> int:
274
+ """Return the y-direction software binning constant."""
275
+ return self._db_dict[BudName.software_binning_y]
276
+
277
+ @property
278
+ def hls_version(self) -> str:
279
+ """Return the High-Level Software version."""
280
+ return self._db_dict[BudName.hls_version]
281
+
282
+ # Multi-task constants start here:
283
+
284
+ @property
285
+ def dark_observing_program_execution_ids(self) -> list[str]:
286
+ """Return the observing program execution ids constant for the dark task."""
287
+ observing_programs = self._db_dict[BudName.dark_observing_program_execution_ids]
288
+ return list(observing_programs)
289
+
290
+ @property
291
+ def solar_gain_observing_program_execution_ids(self) -> list[str]:
292
+ """Return the observing program execution ids constant for the solar_gain task."""
293
+ observing_programs = self._db_dict[BudName.solar_gain_observing_program_execution_ids]
294
+ return list(observing_programs)
295
+
296
+ @property
297
+ def polcal_observing_program_execution_ids(self) -> list[str]:
298
+ """Return the observing program execution ids constant."""
299
+ observing_programs = self._db_dict[BudName.polcal_observing_program_execution_ids]
300
+ return list(observing_programs)
301
+
302
+ @property
303
+ def dark_date_begin(self) -> str:
304
+ """Return the date begin header constant for the dark task."""
305
+ return self._db_dict[BudName.dark_date_begin]
306
+
307
+ @property
308
+ def solar_gain_date_begin(self) -> str:
309
+ """Return the date begin header constant for the solar gain task."""
310
+ return self._db_dict[BudName.solar_gain_date_begin]
311
+
312
+ @property
313
+ def polcal_date_begin(self) -> str:
314
+ """Return the time obs header constant for the polcal task."""
315
+ return self._db_dict[BudName.polcal_date_begin]
316
+
317
+ @property
318
+ def dark_date_end(self) -> str:
319
+ """Return the date end constant for the dark task."""
320
+ return self._db_dict[BudName.dark_date_end]
321
+
322
+ @property
323
+ def solar_gain_date_end(self) -> str:
324
+ """Return the date end constant for the solar gain task."""
325
+ return self._db_dict[BudName.solar_gain_date_end]
326
+
327
+ @property
328
+ def polcal_date_end(self) -> str:
329
+ """Return the date end constant for the polcal task."""
330
+ return self._db_dict[BudName.polcal_date_end]
331
+
332
+ @property
333
+ def dark_num_raw_frames_per_fpa(self) -> dict[float, list]:
334
+ """Return the dictionary of exposure times to number of raw frames per fpa."""
335
+ raw_return = self._db_dict[BudName.dark_num_raw_frames_per_fpa]
336
+ # convert JSON string keys back to float
337
+ return {float(k): v for k, v in raw_return.items()}
338
+
339
+ @property
340
+ def solar_gain_num_raw_frames_per_fpa(self) -> int:
341
+ """Return the number of raw frames per fpa constant for the solar gain task."""
342
+ return self._db_dict[BudName.solar_gain_num_raw_frames_per_fpa]
343
+
344
+ @property
345
+ def polcal_num_raw_frames_per_fpa(self) -> int:
346
+ """Return the num raw frames per fpa constant for the polcal task."""
347
+ return self._db_dict[BudName.polcal_num_raw_frames_per_fpa]
348
+
349
+ @property
350
+ def solar_gain_telescope_tracking_mode(self) -> str:
351
+ """Return the telescope tracking mode constant for the solar gain task."""
352
+ return self._db_dict[BudName.solar_gain_telescope_tracking_mode]
353
+
354
+ @property
355
+ def polcal_telescope_tracking_mode(self) -> str:
356
+ """Return the telescope tracking mode constant for the polcal task."""
357
+ return self._db_dict[BudName.polcal_telescope_tracking_mode]
358
+
359
+ @property
360
+ def solar_gain_coude_table_tracking_mode(self) -> str:
361
+ """Return the coude table tracking mode constant for the solar gain task."""
362
+ return self._db_dict[BudName.solar_gain_coude_table_tracking_mode]
363
+
364
+ @property
365
+ def polcal_coude_table_tracking_mode(self) -> str:
366
+ """Return the coude table tracking mode constant for the polcal task."""
367
+ return self._db_dict[BudName.polcal_coude_table_tracking_mode]
368
+
369
+ @property
370
+ def solar_gain_telescope_scanning_mode(self) -> str:
371
+ """Return the telescope scanning mode constant for the solar gain task."""
372
+ return self._db_dict[BudName.solar_gain_telescope_scanning_mode]
373
+
374
+ @property
375
+ def polcal_telescope_scanning_mode(self) -> str:
376
+ """Return the telescope scanning mode constant for the polcal task."""
377
+ return self._db_dict[BudName.polcal_telescope_scanning_mode]
378
+
379
+ @property
380
+ def dark_average_light_level(self) -> float:
381
+ """Return the average light level constant for the dark task."""
382
+ return self._db_dict[BudName.dark_average_light_level]
383
+
384
+ @property
385
+ def solar_gain_average_light_level(self) -> float:
386
+ """Return the average light level constant for the solar gain task."""
387
+ return self._db_dict[BudName.solar_gain_average_light_level]
388
+
389
+ @property
390
+ def polcal_average_light_level(self) -> float:
391
+ """Return the average light level constant for the polcal task."""
392
+ return self._db_dict[BudName.polcal_average_light_level]
393
+
394
+ @property
395
+ def dark_average_telescope_elevation(self) -> float:
396
+ """Return the average telescope elevation constant for the dark task."""
397
+ return self._db_dict[BudName.dark_average_telescope_elevation]
398
+
399
+ @property
400
+ def solar_gain_average_telescope_elevation(self) -> float:
401
+ """Return the average telescope elevation constant for the solar gain task."""
402
+ return self._db_dict[BudName.solar_gain_average_telescope_elevation]
403
+
404
+ @property
405
+ def polcal_average_telescope_elevation(self) -> float:
406
+ """Return the average telescope elevation constant for the polcal task."""
407
+ return self._db_dict[BudName.polcal_average_telescope_elevation]
408
+
409
+ @property
410
+ def dark_average_coude_table_angle(self) -> float:
411
+ """Return the average coude table angle constant for the dark task."""
412
+ return self._db_dict[BudName.dark_average_coude_table_angle]
413
+
414
+ @property
415
+ def solar_gain_average_coude_table_angle(self) -> float:
416
+ """Return the average coude table angle constant for the solar gain task."""
417
+ return self._db_dict[BudName.solar_gain_average_coude_table_angle]
418
+
419
+ @property
420
+ def polcal_average_coude_table_angle(self) -> float:
421
+ """Return the average coude table angle constant for the polcal task."""
422
+ return self._db_dict[BudName.polcal_average_coude_table_angle]
423
+
424
+ @property
425
+ def dark_average_telescope_azimuth(self) -> float:
426
+ """Return the average telescope azimuth constant for the dark task."""
427
+ return self._db_dict[BudName.dark_average_telescope_azimuth]
428
+
429
+ @property
430
+ def solar_gain_average_telescope_azimuth(self) -> float:
431
+ """Return the average telescope azimuth constant for the solar gain task."""
432
+ return self._db_dict[BudName.solar_gain_average_telescope_azimuth]
433
+
434
+ @property
435
+ def polcal_average_telescope_azimuth(self) -> float:
436
+ """Return the average telescope azimuth constant for the polcal task."""
437
+ return self._db_dict[BudName.polcal_average_telescope_azimuth]
438
+
439
+ @property
440
+ def dark_gos_level3_status(self) -> str:
441
+ """Return the gos level3 status constant for the dark task."""
442
+ return self._db_dict[BudName.dark_gos_level3_status]
443
+
444
+ @property
445
+ def solar_gain_gos_level3_status(self) -> str:
446
+ """Return the gos level3 status constant for the solar gain task."""
447
+ return self._db_dict[BudName.solar_gain_gos_level3_status]
448
+
449
+ @property
450
+ def dark_gos_level3_lamp_status(self) -> str:
451
+ """Return the gos level3 lamp status constant for the dark task."""
452
+ return self._db_dict[BudName.dark_gos_level3_lamp_status]
453
+
454
+ @property
455
+ def solar_gain_gos_level3_lamp_status(self) -> str:
456
+ """Return the gos level3 lamp status constant for the solar gain task."""
457
+ return self._db_dict[BudName.solar_gain_gos_level3_lamp_status]
458
+
459
+ @property
460
+ def dark_gos_polarizer_status(self) -> str:
461
+ """Return the gos polarizer status constant for the dark task."""
462
+ return self._db_dict[BudName.dark_gos_polarizer_status]
463
+
464
+ @property
465
+ def solar_gain_gos_polarizer_status(self) -> str:
466
+ """Return the gos polarizer status constant for the solar gain task."""
467
+ return self._db_dict[BudName.solar_gain_gos_polarizer_status]
468
+
469
+ @property
470
+ def dark_gos_polarizer_angle(self) -> float:
471
+ """Return the gos polarizer angle constant for the dark task."""
472
+ return self._db_dict[BudName.dark_gos_polarizer_angle]
473
+
474
+ @property
475
+ def solar_gain_gos_polarizer_angle(self) -> float:
476
+ """Return the gos polarizer angle constant for the solar gain task."""
477
+ return self._db_dict[BudName.solar_gain_gos_polarizer_angle]
478
+
479
+ @property
480
+ def dark_gos_retarder_status(self) -> str:
481
+ """Return the gos retarder status constant for the dark task."""
482
+ return self._db_dict[BudName.dark_gos_retarder_status]
483
+
484
+ @property
485
+ def solar_gain_gos_retarder_status(self) -> str:
486
+ """Return the gos retarder status constant for the solar gain task."""
487
+ return self._db_dict[BudName.solar_gain_gos_retarder_status]
488
+
489
+ @property
490
+ def dark_gos_retarder_angle(self) -> float:
491
+ """Return the gos retarder angle constant for the dark task."""
492
+ return self._db_dict[BudName.dark_gos_retarder_angle]
493
+
494
+ @property
495
+ def solar_gain_gos_retarder_angle(self) -> float:
496
+ """Return the gos retarder angle constant for the solar gain task."""
497
+ return self._db_dict[BudName.solar_gain_gos_retarder_angle]
498
+
499
+ @property
500
+ def dark_gos_level0_status(self) -> str:
501
+ """Return the gos level0 status constant for the dark task."""
502
+ return self._db_dict[BudName.dark_gos_level0_status]
503
+
504
+ @property
505
+ def solar_gain_gos_level0_status(self) -> str:
506
+ """Return the gos level0 status constant for the solar gain task."""
507
+ return self._db_dict[BudName.solar_gain_gos_level0_status]
@@ -0,0 +1,27 @@
1
+ """Return hard-coded EarthLocation of the DKIST.
2
+
3
+ Cartesian geocentric coordinates of DKIST on Earth as retrieved from
4
+ https://github.com/astropy/astropy-data/blob/gh-pages/coordinates/sites.json#L838
5
+ """
6
+
7
+ import astropy.units as u
8
+ from astropy.coordinates import EarthLocation
9
+
10
+ _dkist_site_info = {
11
+ "aliases": ["DKIST", "ATST"],
12
+ "name": "Daniel K. Inouye Solar Telescope",
13
+ "elevation": 3067,
14
+ "elevation_unit": "meter",
15
+ "latitude": 20.7067,
16
+ "latitude_unit": "degree",
17
+ "longitude": 203.7436,
18
+ "longitude_unit": "degree",
19
+ "timezone": "US/Hawaii",
20
+ "source": "DKIST website: https://www.nso.edu/telescopes/dki-solar-telescope/",
21
+ }
22
+
23
+ location_of_dkist: EarthLocation = EarthLocation.from_geodetic(
24
+ _dkist_site_info["longitude"] * u.Unit(_dkist_site_info["longitude_unit"]),
25
+ _dkist_site_info["latitude"] * u.Unit(_dkist_site_info["latitude_unit"]),
26
+ _dkist_site_info["elevation"] * u.Unit(_dkist_site_info["elevation_unit"]),
27
+ )
@@ -1,11 +1,59 @@
1
1
  """Abstraction layer for accessing fits data via class attributes."""
2
+
2
3
  from __future__ import annotations
3
4
 
5
+ from enum import StrEnum
6
+ from enum import unique
4
7
  from pathlib import Path
5
8
 
6
9
  import numpy as np
7
10
  from astropy.io import fits
8
11
 
12
+ HEADER_KEY_NOT_FOUND = "HEADER_KEY_NOT_FOUND"
13
+
14
+
15
+ @unique
16
+ class MetadataKey(StrEnum):
17
+ """Controlled list of names for FITS metadata header keys."""
18
+
19
+ ip_task_type = "IPTASK" # in L0FitsAccess
20
+ ip_start_time = "DKIST011" # in L0FitsAccess
21
+ ip_end_time = "DKIST012" # in L0FitsAccess
22
+ elevation = "ELEV_ANG"
23
+ azimuth = "TAZIMUTH"
24
+ table_angle = "TTBLANGL"
25
+ gos_level3_status = "LVL3STAT"
26
+ gos_level3_lamp_status = "LAMPSTAT"
27
+ gos_polarizer_status = "LVL2STAT"
28
+ gos_polarizer_angle = "POLANGLE"
29
+ gos_retarder_status = "LVL1STAT"
30
+ gos_retarder_angle = "RETANGLE"
31
+ gos_level0_status = "LVL0STAT"
32
+ time_obs = "DATE-BEG"
33
+ ip_id = "IP_ID"
34
+ instrument = "INSTRUME"
35
+ wavelength = "LINEWAV"
36
+ proposal_id = "PROP_ID"
37
+ experiment_id = "EXPER_ID"
38
+ num_dsps_repeats = "DSPSREPS"
39
+ current_dsps_repeat = "DSPSNUM"
40
+ fpa_exposure_time_ms = "XPOSURE"
41
+ sensor_readout_exposure_time_ms = "TEXPOSUR"
42
+ num_raw_frames_per_fpa = "NSUMEXP"
43
+ camera_id = "CAM_ID"
44
+ camera_name = "CAMERA"
45
+ camera_bit_depth = "BITDEPTH"
46
+ hardware_binning_x = "HWBIN1"
47
+ hardware_binning_y = "HWBIN2"
48
+ software_binning_x = "SWBIN1"
49
+ software_binning_y = "SWBIN2"
50
+ observing_program_execution_id = "OBSPR_ID"
51
+ telescope_tracking_mode = "TELTRACK"
52
+ coude_table_tracking_mode = "TTBLTRCK"
53
+ telescope_scanning_mode = "TELSCAN"
54
+ light_level = "LIGHTLVL"
55
+ hls_version = "HLSVERS"
56
+
9
57
 
10
58
  class FitsAccessBase:
11
59
  """