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,278 @@
1
+ import json
2
+ from datetime import datetime
3
+
4
+ import numpy as np
5
+ import pytest
6
+ from astropy.io import fits
7
+ from dkist_header_validator import spec122_validator
8
+ from dkist_processing_common._util.scratch import WorkflowFileSystem
9
+ from dkist_processing_common.codecs.fits import fits_hdulist_encoder
10
+ from dkist_processing_common.tests.conftest import FakeGQLClient
11
+
12
+ from dkist_processing_cryonirsp.models.exposure_conditions import AllowableOpticalDensityFilterNames
13
+ from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
14
+ from dkist_processing_cryonirsp.models.tags import CryonirspTag
15
+ from dkist_processing_cryonirsp.tasks.gain import CISolarGainCalibration
16
+ from dkist_processing_cryonirsp.tasks.gain import LampGainCalibration
17
+ from dkist_processing_cryonirsp.tests.conftest import cryonirsp_testing_parameters_factory
18
+ from dkist_processing_cryonirsp.tests.conftest import CryonirspConstantsDb
19
+ from dkist_processing_cryonirsp.tests.conftest import generate_fits_frame
20
+ from dkist_processing_cryonirsp.tests.header_models import CryonirspHeadersValidLampGainFrames
21
+
22
+
23
+ @pytest.fixture
24
+ def ci_solar_gain_calibration_task(
25
+ tmp_path,
26
+ recipe_run_id,
27
+ assign_input_dataset_doc_to_task,
28
+ init_cryonirsp_constants_db,
29
+ ):
30
+ dataset_shape = (1, 10, 10)
31
+ array_shape = (1, 10, 10)
32
+ intermediate_shape = (10, 10)
33
+ constants_db = CryonirspConstantsDb(NUM_MODSTATES=1, ARM_ID="CI")
34
+ exposure_conditions = constants_db.SOLAR_GAIN_EXPOSURE_CONDITIONS_LIST[0]
35
+ init_cryonirsp_constants_db(recipe_run_id, constants_db)
36
+ with CISolarGainCalibration(
37
+ recipe_run_id=recipe_run_id,
38
+ workflow_name="ci_solar_gain_calibration",
39
+ workflow_version="VX.Y",
40
+ ) as task:
41
+ try: # This try... block is here to make sure the dbs get cleaned up if there's a failure in the fixture
42
+ task.scratch = WorkflowFileSystem(
43
+ scratch_base_path=tmp_path, recipe_run_id=recipe_run_id
44
+ )
45
+ param_class = cryonirsp_testing_parameters_factory(param_path=tmp_path)
46
+ assign_input_dataset_doc_to_task(task, param_class())
47
+ # Need a beam boundary file
48
+ task.intermediate_frame_write_arrays(
49
+ arrays=np.array([0, intermediate_shape[0], 0, intermediate_shape[1]]),
50
+ task_tag=CryonirspTag.task_beam_boundaries(),
51
+ beam=1,
52
+ )
53
+ # Create fake bad pixel map
54
+ task.intermediate_frame_write_arrays(
55
+ arrays=np.zeros(array_shape[1:]), task_tag=CryonirspTag.task_bad_pixel_map()
56
+ )
57
+ dark_signal = 3.0
58
+ start_time = datetime.now()
59
+ # Make intermediate dark frame
60
+ dark_cal = np.ones(intermediate_shape) * dark_signal
61
+ task.intermediate_frame_write_arrays(
62
+ arrays=dark_cal,
63
+ beam=1,
64
+ task_tag=CryonirspTag.task_dark(),
65
+ exposure_conditions=exposure_conditions,
66
+ )
67
+
68
+ solar_signal = 6.28
69
+ ds = CryonirspHeadersValidLampGainFrames(
70
+ dataset_shape=dataset_shape,
71
+ array_shape=array_shape,
72
+ time_delta=10,
73
+ start_time=start_time,
74
+ )
75
+ header_generator = (
76
+ spec122_validator.validate_and_translate_to_214_l0(
77
+ d.header(), return_type=fits.HDUList
78
+ )[0].header
79
+ for d in ds
80
+ )
81
+ hdul = generate_fits_frame(header_generator=header_generator, shape=array_shape)
82
+
83
+ hdul[0].data.fill(solar_signal + dark_signal)
84
+ tags = [
85
+ CryonirspTag.linearized(),
86
+ CryonirspTag.task_solar_gain(),
87
+ CryonirspTag.frame(),
88
+ CryonirspTag.exposure_conditions(exposure_conditions),
89
+ ]
90
+ task.write(
91
+ data=hdul,
92
+ tags=tags,
93
+ encoder=fits_hdulist_encoder,
94
+ )
95
+ yield task, solar_signal
96
+ finally:
97
+ task._purge()
98
+
99
+
100
+ @pytest.fixture(scope="function")
101
+ def lamp_calibration_task(
102
+ tmp_path,
103
+ recipe_run_id,
104
+ assign_input_dataset_doc_to_task,
105
+ init_cryonirsp_constants_db,
106
+ number_of_beams,
107
+ ):
108
+ exposure_conditions = ExposureConditions(100.0, AllowableOpticalDensityFilterNames.OPEN.value)
109
+ dataset_shape = (1, 10, 20)
110
+ array_shape = (1, 10, 20)
111
+ intermediate_shape = (10, 10)
112
+ constants_db = CryonirspConstantsDb(
113
+ NUM_MODSTATES=1,
114
+ ARM_ID="SP" if number_of_beams > 1 else "CI",
115
+ )
116
+ init_cryonirsp_constants_db(recipe_run_id, constants_db)
117
+ with LampGainCalibration(
118
+ recipe_run_id=recipe_run_id, workflow_name="sp_gain_calibration", workflow_version="VX.Y"
119
+ ) as task:
120
+ try: # This try... block is here to make sure the dbs get cleaned up if there's a failure in the fixture
121
+ task.scratch = WorkflowFileSystem(
122
+ scratch_base_path=tmp_path, recipe_run_id=recipe_run_id
123
+ )
124
+ param_class = cryonirsp_testing_parameters_factory(param_path=tmp_path)
125
+ assign_input_dataset_doc_to_task(task, param_class())
126
+ # Need a beam boundary file
127
+ task.intermediate_frame_write_arrays(
128
+ arrays=np.array([0, intermediate_shape[0], 0, intermediate_shape[1]]),
129
+ task_tag=CryonirspTag.task_beam_boundaries(),
130
+ beam=1,
131
+ )
132
+ # Create fake bad pixel map
133
+ task.intermediate_frame_write_arrays(
134
+ arrays=np.zeros(array_shape[1:]), task_tag=CryonirspTag.task_bad_pixel_map()
135
+ )
136
+ dark_signal = 3.0
137
+ start_time = datetime.now()
138
+ # Make intermediate dark frame
139
+ dark_cal = np.ones(intermediate_shape) * dark_signal
140
+
141
+ # Need a dark for each beam
142
+ for b in range(number_of_beams):
143
+ task.intermediate_frame_write_arrays(
144
+ arrays=dark_cal,
145
+ beam=b + 1,
146
+ task_tag=CryonirspTag.task_dark(),
147
+ exposure_conditions=exposure_conditions,
148
+ )
149
+ # Create fake beam border intermediate arrays
150
+ task.intermediate_frame_write_arrays(
151
+ arrays=np.array([0, 10, (b * 10), 10 + (b * 10)]),
152
+ task_tag=CryonirspTag.task_beam_boundaries(),
153
+ beam=b + 1,
154
+ )
155
+
156
+ # does this need to be in the beam loop as well?
157
+ ds = CryonirspHeadersValidLampGainFrames(
158
+ dataset_shape=dataset_shape,
159
+ array_shape=array_shape,
160
+ time_delta=10,
161
+ start_time=start_time,
162
+ )
163
+ header_generator = (
164
+ spec122_validator.validate_and_translate_to_214_l0(
165
+ d.header(), return_type=fits.HDUList
166
+ )[0].header
167
+ for d in ds
168
+ )
169
+ hdul = generate_fits_frame(
170
+ header_generator=header_generator, shape=array_shape
171
+ ) # Tweak data so that beam sides are slightly different
172
+ # Use data != 1 to check normalization in test
173
+ hdul[0].data.fill(1.1)
174
+ tags = [
175
+ CryonirspTag.beam(b + 1),
176
+ CryonirspTag.linearized(),
177
+ CryonirspTag.task_lamp_gain(),
178
+ CryonirspTag.frame(),
179
+ CryonirspTag.exposure_conditions(exposure_conditions),
180
+ ]
181
+ task.write(
182
+ data=hdul,
183
+ tags=tags,
184
+ encoder=fits_hdulist_encoder,
185
+ )
186
+ yield task
187
+ finally:
188
+ task._purge()
189
+
190
+
191
+ def test_ci_solar_gain_calibration_task(ci_solar_gain_calibration_task, mocker):
192
+ """
193
+ Given: A CISolarGainCalibration task
194
+ When: Calling the task instance
195
+ Then: The correct number of output solar gain frames exists, are tagged correctly, and are not normalized
196
+ """
197
+ mocker.patch(
198
+ "dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=FakeGQLClient
199
+ )
200
+ # When
201
+ task, solar_signal = ci_solar_gain_calibration_task
202
+ task()
203
+ # Then
204
+ tags = [
205
+ CryonirspTag.task_solar_gain(),
206
+ CryonirspTag.intermediate(),
207
+ CryonirspTag.frame(),
208
+ CryonirspTag.beam(1),
209
+ ]
210
+ files = list(task.read(tags=tags))
211
+ num_files = len(files)
212
+ assert num_files == 1 # Because only 1 beam in CI
213
+
214
+ hdu = fits.open(files[0])[0]
215
+ expected_results = np.ones((10, 10)) * solar_signal
216
+ np.testing.assert_allclose(hdu.data, expected_results)
217
+
218
+ tags = [
219
+ CryonirspTag.task_lamp_gain(),
220
+ CryonirspTag.intermediate(),
221
+ ]
222
+ for filepath in task.read(tags=tags):
223
+ assert filepath.exists()
224
+
225
+ quality_files = task.read(tags=[CryonirspTag.quality("TASK_TYPES")])
226
+ for file in quality_files:
227
+ with file.open() as f:
228
+ data = json.load(f)
229
+ assert isinstance(data, dict)
230
+ assert data["total_frames"] == num_files
231
+
232
+
233
+ @pytest.mark.parametrize("number_of_beams", [pytest.param(1, id="CI"), pytest.param(2, id="SP")])
234
+ def test_lamp_calibration_task(lamp_calibration_task, number_of_beams, mocker):
235
+ """
236
+ Given: A LampGainCalibration task
237
+ When: Calling the task instance
238
+ Then: The correct number of output lamp gain frames exists, are tagged correctly, and are normalized
239
+ """
240
+ mocker.patch(
241
+ "dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=FakeGQLClient
242
+ )
243
+ # When
244
+ task = lamp_calibration_task
245
+ task()
246
+ # Then
247
+ tags = [
248
+ CryonirspTag.task_lamp_gain(),
249
+ CryonirspTag.intermediate(),
250
+ ]
251
+ num_files = task.scratch.count_all(tags)
252
+ assert num_files == number_of_beams
253
+
254
+ for j in range(number_of_beams):
255
+ tags = [
256
+ CryonirspTag.task_lamp_gain(),
257
+ CryonirspTag.intermediate(),
258
+ CryonirspTag.beam(j + 1),
259
+ ]
260
+ files = list(task.read(tags=tags))
261
+ assert len(files) == 1
262
+ hdu = fits.open(files[0])[0]
263
+ expected_results = np.ones((10, 10)) # Because lamps are normalized
264
+ np.testing.assert_allclose(hdu.data, expected_results)
265
+
266
+ tags = [
267
+ CryonirspTag.task_lamp_gain(),
268
+ CryonirspTag.intermediate(),
269
+ ]
270
+ for filepath in task.read(tags=tags):
271
+ assert filepath.exists()
272
+
273
+ quality_files = task.read(tags=[CryonirspTag.quality("TASK_TYPES")])
274
+ for file in quality_files:
275
+ with file.open() as f:
276
+ data = json.load(f)
277
+ assert isinstance(data, dict)
278
+ assert data["total_frames"] == num_files