dkist-processing-visp 3.3.0__py3-none-any.whl → 5.1.1__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_visp/__init__.py +1 -0
- dkist_processing_visp/config.py +1 -0
- dkist_processing_visp/models/constants.py +52 -21
- dkist_processing_visp/models/fits_access.py +20 -0
- dkist_processing_visp/models/metric_code.py +10 -0
- dkist_processing_visp/models/parameters.py +129 -19
- dkist_processing_visp/models/tags.py +1 -0
- dkist_processing_visp/models/task_name.py +1 -0
- dkist_processing_visp/parsers/map_repeats.py +1 -0
- dkist_processing_visp/parsers/modulator_states.py +1 -0
- dkist_processing_visp/parsers/polarimeter_mode.py +3 -1
- dkist_processing_visp/parsers/raster_step.py +4 -1
- dkist_processing_visp/parsers/spectrograph_configuration.py +75 -0
- dkist_processing_visp/parsers/time.py +15 -7
- dkist_processing_visp/parsers/visp_l0_fits_access.py +19 -8
- dkist_processing_visp/parsers/visp_l1_fits_access.py +1 -0
- dkist_processing_visp/tasks/__init__.py +1 -0
- dkist_processing_visp/tasks/assemble_movie.py +1 -0
- dkist_processing_visp/tasks/background_light.py +2 -1
- dkist_processing_visp/tasks/dark.py +5 -4
- dkist_processing_visp/tasks/geometric.py +132 -20
- dkist_processing_visp/tasks/instrument_polarization.py +13 -12
- dkist_processing_visp/tasks/l1_output_data.py +203 -0
- dkist_processing_visp/tasks/lamp.py +53 -93
- dkist_processing_visp/tasks/make_movie_frames.py +8 -6
- dkist_processing_visp/tasks/mixin/beam_access.py +1 -0
- dkist_processing_visp/tasks/mixin/corrections.py +54 -4
- dkist_processing_visp/tasks/mixin/downsample.py +1 -0
- dkist_processing_visp/tasks/parse.py +34 -4
- dkist_processing_visp/tasks/quality_metrics.py +5 -4
- dkist_processing_visp/tasks/science.py +126 -46
- dkist_processing_visp/tasks/solar.py +896 -456
- dkist_processing_visp/tasks/visp_base.py +2 -0
- dkist_processing_visp/tasks/write_l1.py +25 -5
- dkist_processing_visp/tests/conftest.py +99 -35
- dkist_processing_visp/tests/header_models.py +92 -20
- dkist_processing_visp/tests/local_trial_workflows/l0_cals_only.py +4 -23
- dkist_processing_visp/tests/local_trial_workflows/l0_polcals_as_science.py +421 -0
- dkist_processing_visp/tests/local_trial_workflows/l0_solar_gain_as_science.py +10 -29
- dkist_processing_visp/tests/local_trial_workflows/l0_to_l1.py +1 -21
- dkist_processing_visp/tests/local_trial_workflows/local_trial_helpers.py +98 -14
- dkist_processing_visp/tests/test_assemble_movie.py +2 -3
- dkist_processing_visp/tests/test_assemble_quality.py +89 -4
- dkist_processing_visp/tests/test_background_light.py +8 -5
- dkist_processing_visp/tests/test_dark.py +4 -3
- dkist_processing_visp/tests/test_fits_access.py +43 -0
- dkist_processing_visp/tests/test_geometric.py +45 -4
- dkist_processing_visp/tests/test_instrument_polarization.py +4 -3
- dkist_processing_visp/tests/test_lamp.py +22 -26
- dkist_processing_visp/tests/test_make_movie_frames.py +4 -4
- dkist_processing_visp/tests/test_map_repeats.py +3 -1
- dkist_processing_visp/tests/test_parameters.py +122 -21
- dkist_processing_visp/tests/test_parse.py +98 -14
- dkist_processing_visp/tests/test_quality.py +2 -3
- dkist_processing_visp/tests/test_science.py +113 -15
- dkist_processing_visp/tests/test_solar.py +318 -99
- dkist_processing_visp/tests/test_visp_constants.py +36 -8
- dkist_processing_visp/tests/test_workflows.py +1 -0
- dkist_processing_visp/tests/test_write_l1.py +17 -3
- dkist_processing_visp/workflows/__init__.py +1 -0
- dkist_processing_visp/workflows/l0_processing.py +8 -2
- dkist_processing_visp/workflows/trial_workflows.py +8 -2
- dkist_processing_visp-5.1.1.dist-info/METADATA +552 -0
- dkist_processing_visp-5.1.1.dist-info/RECORD +94 -0
- docs/conf.py +5 -1
- docs/gain_correction.rst +50 -42
- dkist_processing_visp/tasks/mixin/line_zones.py +0 -115
- dkist_processing_visp-3.3.0.dist-info/METADATA +0 -459
- dkist_processing_visp-3.3.0.dist-info/RECORD +0 -90
- {dkist_processing_visp-3.3.0.dist-info → dkist_processing_visp-5.1.1.dist-info}/WHEEL +0 -0
- {dkist_processing_visp-3.3.0.dist-info → dkist_processing_visp-5.1.1.dist-info}/top_level.txt +0 -0
|
@@ -2,7 +2,6 @@ import pytest
|
|
|
2
2
|
from dkist_data_simulator.dataset import key_function
|
|
3
3
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
4
4
|
from dkist_processing_common.models.tags import Tag
|
|
5
|
-
from dkist_processing_common.tests.conftest import FakeGQLClient
|
|
6
5
|
|
|
7
6
|
from dkist_processing_visp.models.parameters import VispParsingParameters
|
|
8
7
|
from dkist_processing_visp.models.tags import VispTag
|
|
@@ -87,6 +86,7 @@ def write_input_dark_frames_to_task(
|
|
|
87
86
|
time_delta: float = 10.0,
|
|
88
87
|
num_modstates: int = 2,
|
|
89
88
|
data_shape: tuple[int, int] = (2, 2),
|
|
89
|
+
**kwargs,
|
|
90
90
|
):
|
|
91
91
|
array_shape = (1, *data_shape)
|
|
92
92
|
dataset = VispHeadersInputDarkFrames(
|
|
@@ -95,6 +95,7 @@ def write_input_dark_frames_to_task(
|
|
|
95
95
|
exp_time=exp_time,
|
|
96
96
|
readout_exp_time=readout_exp_time,
|
|
97
97
|
num_modstates=num_modstates,
|
|
98
|
+
**kwargs,
|
|
98
99
|
)
|
|
99
100
|
|
|
100
101
|
num_written_frames = write_frames_to_task(
|
|
@@ -110,6 +111,7 @@ def write_input_lamp_frames_to_task(
|
|
|
110
111
|
time_delta: float = 10.0,
|
|
111
112
|
num_modstates: int = 2,
|
|
112
113
|
data_shape: tuple[int, int] = (2, 2),
|
|
114
|
+
**kwargs,
|
|
113
115
|
):
|
|
114
116
|
array_shape = (1, *data_shape)
|
|
115
117
|
dataset = VispHeadersInputLampGainFrames(
|
|
@@ -118,6 +120,7 @@ def write_input_lamp_frames_to_task(
|
|
|
118
120
|
exp_time=exp_time,
|
|
119
121
|
readout_exp_time=readout_exp_time,
|
|
120
122
|
num_modstates=num_modstates,
|
|
123
|
+
**kwargs,
|
|
121
124
|
)
|
|
122
125
|
|
|
123
126
|
num_written_frames = write_frames_to_task(
|
|
@@ -133,6 +136,7 @@ def write_input_solar_frames_to_task(
|
|
|
133
136
|
time_delta: float = 10.0,
|
|
134
137
|
num_modstates: int = 2,
|
|
135
138
|
data_shape: tuple[int, int] = (2, 2),
|
|
139
|
+
**kwargs,
|
|
136
140
|
):
|
|
137
141
|
array_shape = (1, *data_shape)
|
|
138
142
|
dataset = VispHeadersInputSolarGainFrames(
|
|
@@ -141,6 +145,7 @@ def write_input_solar_frames_to_task(
|
|
|
141
145
|
exp_time=exp_time,
|
|
142
146
|
readout_exp_time=readout_exp_time,
|
|
143
147
|
num_modstates=num_modstates,
|
|
148
|
+
**kwargs,
|
|
144
149
|
)
|
|
145
150
|
|
|
146
151
|
num_written_frames = write_frames_to_task(
|
|
@@ -156,6 +161,7 @@ def write_input_polcal_frames_to_task(
|
|
|
156
161
|
time_delta: float = 30.0,
|
|
157
162
|
num_modstates: int = 2,
|
|
158
163
|
data_shape: tuple[int, int] = (2, 2),
|
|
164
|
+
**kwargs,
|
|
159
165
|
):
|
|
160
166
|
array_shape = (1, *data_shape)
|
|
161
167
|
dataset = VispHeadersInputPolcalFrames(
|
|
@@ -164,6 +170,7 @@ def write_input_polcal_frames_to_task(
|
|
|
164
170
|
exp_time=exp_time,
|
|
165
171
|
readout_exp_time=readout_exp_time,
|
|
166
172
|
num_modstates=num_modstates,
|
|
173
|
+
**kwargs,
|
|
167
174
|
)
|
|
168
175
|
|
|
169
176
|
num_written_frames = write_frames_to_task(
|
|
@@ -179,6 +186,7 @@ def write_input_polcal_dark_frames_to_task(
|
|
|
179
186
|
time_delta: float = 30.0,
|
|
180
187
|
num_modstates: int = 2,
|
|
181
188
|
data_shape: tuple[int, int] = (2, 2),
|
|
189
|
+
**kwargs,
|
|
182
190
|
):
|
|
183
191
|
array_shape = (1, *data_shape)
|
|
184
192
|
dataset = VispHeadersInputPolcalDarkFrames(
|
|
@@ -187,6 +195,7 @@ def write_input_polcal_dark_frames_to_task(
|
|
|
187
195
|
exp_time=exp_time,
|
|
188
196
|
readout_exp_time=readout_exp_time,
|
|
189
197
|
num_modstates=num_modstates,
|
|
198
|
+
**kwargs,
|
|
190
199
|
)
|
|
191
200
|
|
|
192
201
|
num_written_frames = write_frames_to_task(
|
|
@@ -202,6 +211,7 @@ def write_input_polcal_gain_frames_to_task(
|
|
|
202
211
|
time_delta: float = 30.0,
|
|
203
212
|
num_modstates: int = 2,
|
|
204
213
|
data_shape: tuple[int, int] = (2, 2),
|
|
214
|
+
**kwargs,
|
|
205
215
|
):
|
|
206
216
|
array_shape = (1, *data_shape)
|
|
207
217
|
dataset = VispHeadersInputPolcalGainFrames(
|
|
@@ -210,6 +220,7 @@ def write_input_polcal_gain_frames_to_task(
|
|
|
210
220
|
exp_time=exp_time,
|
|
211
221
|
readout_exp_time=readout_exp_time,
|
|
212
222
|
num_modstates=num_modstates,
|
|
223
|
+
**kwargs,
|
|
213
224
|
)
|
|
214
225
|
|
|
215
226
|
num_written_frames = write_frames_to_task(
|
|
@@ -228,6 +239,7 @@ def write_input_observe_frames_to_task(
|
|
|
228
239
|
time_delta: float = 10.0,
|
|
229
240
|
data_shape: tuple[int, int] = (2, 2),
|
|
230
241
|
obs_dataset_class=VispHeadersValidObserveFrames,
|
|
242
|
+
**kwargs,
|
|
231
243
|
):
|
|
232
244
|
array_shape = (1, *data_shape)
|
|
233
245
|
dataset = obs_dataset_class(
|
|
@@ -238,6 +250,7 @@ def write_input_observe_frames_to_task(
|
|
|
238
250
|
num_modstates=num_modstates,
|
|
239
251
|
exp_time=exp_time,
|
|
240
252
|
readout_exp_time=readout_exp_time,
|
|
253
|
+
**kwargs,
|
|
241
254
|
)
|
|
242
255
|
num_written_frames = write_frames_to_task(
|
|
243
256
|
task=task, frame_generator=dataset, extra_tags=[VispTag.input()]
|
|
@@ -273,6 +286,11 @@ def write_input_cal_frames_to_task(
|
|
|
273
286
|
solar_exp_time,
|
|
274
287
|
polcal_exp_time,
|
|
275
288
|
num_modstates,
|
|
289
|
+
testing_arm_id,
|
|
290
|
+
testing_solar_ip_start_time,
|
|
291
|
+
testing_grating_constant,
|
|
292
|
+
testing_grating_angle,
|
|
293
|
+
testing_arm_position,
|
|
276
294
|
):
|
|
277
295
|
def write_frames_to_task(task):
|
|
278
296
|
for readout_exp_time in required_dark_readout_exp_times:
|
|
@@ -281,6 +299,7 @@ def write_input_cal_frames_to_task(
|
|
|
281
299
|
readout_exp_time=readout_exp_time,
|
|
282
300
|
exp_time=dark_exp_time,
|
|
283
301
|
num_modstates=num_modstates,
|
|
302
|
+
arm_id=testing_arm_id,
|
|
284
303
|
)
|
|
285
304
|
|
|
286
305
|
write_input_lamp_frames_to_task(
|
|
@@ -288,30 +307,39 @@ def write_input_cal_frames_to_task(
|
|
|
288
307
|
readout_exp_time=lamp_readout_exp_time,
|
|
289
308
|
exp_time=lamp_exp_time,
|
|
290
309
|
num_modstates=num_modstates,
|
|
310
|
+
arm_id=testing_arm_id,
|
|
291
311
|
)
|
|
292
312
|
write_input_solar_frames_to_task(
|
|
293
313
|
task=task,
|
|
294
314
|
readout_exp_time=solar_readout_exp_time,
|
|
295
315
|
exp_time=solar_exp_time,
|
|
296
316
|
num_modstates=num_modstates,
|
|
317
|
+
arm_id=testing_arm_id,
|
|
318
|
+
ip_start_time=testing_solar_ip_start_time,
|
|
319
|
+
grating_constant=testing_grating_constant,
|
|
320
|
+
grating_angle=testing_grating_angle,
|
|
321
|
+
arm_position=testing_arm_position,
|
|
297
322
|
)
|
|
298
323
|
write_input_polcal_frames_to_task(
|
|
299
324
|
task=task,
|
|
300
325
|
readout_exp_time=polcal_readout_exp_time,
|
|
301
326
|
exp_time=polcal_exp_time,
|
|
302
327
|
num_modstates=num_modstates,
|
|
328
|
+
arm_id=testing_arm_id,
|
|
303
329
|
)
|
|
304
330
|
write_input_polcal_dark_frames_to_task(
|
|
305
331
|
task=task,
|
|
306
332
|
readout_exp_time=polcal_readout_exp_time,
|
|
307
333
|
exp_time=polcal_exp_time,
|
|
308
334
|
num_modstates=num_modstates,
|
|
335
|
+
arm_id=testing_arm_id,
|
|
309
336
|
)
|
|
310
337
|
write_input_polcal_gain_frames_to_task(
|
|
311
338
|
task,
|
|
312
339
|
readout_exp_time=polcal_readout_exp_time,
|
|
313
340
|
exp_time=polcal_exp_time,
|
|
314
341
|
num_modstates=num_modstates,
|
|
342
|
+
arm_id=testing_arm_id,
|
|
315
343
|
)
|
|
316
344
|
|
|
317
345
|
return write_frames_to_task
|
|
@@ -350,6 +378,11 @@ def test_parse_visp_input_data(
|
|
|
350
378
|
observe_exp_times,
|
|
351
379
|
num_modstates,
|
|
352
380
|
mocker,
|
|
381
|
+
fake_gql_client,
|
|
382
|
+
testing_arm_id,
|
|
383
|
+
testing_grating_constant,
|
|
384
|
+
testing_grating_angle,
|
|
385
|
+
testing_arm_position,
|
|
353
386
|
):
|
|
354
387
|
"""
|
|
355
388
|
Given: A ParseVispInputData task
|
|
@@ -357,7 +390,7 @@ def test_parse_visp_input_data(
|
|
|
357
390
|
Then: All tagged files exist and individual task tags are applied
|
|
358
391
|
"""
|
|
359
392
|
mocker.patch(
|
|
360
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
393
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
361
394
|
)
|
|
362
395
|
task = parse_task_with_no_data
|
|
363
396
|
write_input_cal_frames_to_task(task)
|
|
@@ -369,6 +402,10 @@ def test_parse_visp_input_data(
|
|
|
369
402
|
num_steps=3,
|
|
370
403
|
readout_exp_time=obs_readout_exp_time,
|
|
371
404
|
exp_time=obs_exp_time,
|
|
405
|
+
arm_id=testing_arm_id,
|
|
406
|
+
grating_constant=testing_grating_constant,
|
|
407
|
+
grating_angle=testing_grating_angle,
|
|
408
|
+
arm_position=testing_arm_position,
|
|
372
409
|
)
|
|
373
410
|
|
|
374
411
|
# When
|
|
@@ -393,6 +430,7 @@ def test_parse_visp_input_data_constants(
|
|
|
393
430
|
parse_task_with_no_data,
|
|
394
431
|
write_input_cal_frames_to_task,
|
|
395
432
|
mocker,
|
|
433
|
+
fake_gql_client,
|
|
396
434
|
lamp_readout_exp_time,
|
|
397
435
|
solar_readout_exp_time,
|
|
398
436
|
polcal_readout_exp_time,
|
|
@@ -403,6 +441,12 @@ def test_parse_visp_input_data_constants(
|
|
|
403
441
|
polcal_exp_time,
|
|
404
442
|
observe_exp_times,
|
|
405
443
|
num_modstates,
|
|
444
|
+
testing_arm_id,
|
|
445
|
+
testing_obs_ip_start_time,
|
|
446
|
+
testing_solar_ip_start_time,
|
|
447
|
+
testing_grating_constant,
|
|
448
|
+
testing_grating_angle,
|
|
449
|
+
testing_arm_position,
|
|
406
450
|
):
|
|
407
451
|
"""
|
|
408
452
|
Given: A ParseVispInputData task
|
|
@@ -410,7 +454,7 @@ def test_parse_visp_input_data_constants(
|
|
|
410
454
|
Then: Constants are in the constants object as expected
|
|
411
455
|
"""
|
|
412
456
|
mocker.patch(
|
|
413
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
457
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
414
458
|
)
|
|
415
459
|
task = parse_task_with_no_data
|
|
416
460
|
write_input_cal_frames_to_task(task)
|
|
@@ -425,16 +469,29 @@ def test_parse_visp_input_data_constants(
|
|
|
425
469
|
num_steps=num_steps,
|
|
426
470
|
readout_exp_time=obs_readout_exp_time,
|
|
427
471
|
exp_time=obs_exp_time,
|
|
472
|
+
arm_id=testing_arm_id,
|
|
473
|
+
ip_start_time=testing_obs_ip_start_time,
|
|
474
|
+
grating_constant=testing_grating_constant,
|
|
475
|
+
grating_angle=testing_grating_angle,
|
|
476
|
+
arm_position=testing_arm_position,
|
|
428
477
|
)
|
|
429
478
|
|
|
430
479
|
# When
|
|
431
480
|
task()
|
|
432
481
|
# Then
|
|
482
|
+
assert task.constants._db_dict["ARM_ID"] == testing_arm_id
|
|
433
483
|
expected_dark_readout_exp_times = [
|
|
434
484
|
lamp_readout_exp_time,
|
|
435
485
|
solar_readout_exp_time,
|
|
436
486
|
] + observe_readout_exp_times
|
|
437
|
-
assert task.constants._db_dict["OBS_IP_START_TIME"] ==
|
|
487
|
+
assert task.constants._db_dict["OBS_IP_START_TIME"] == testing_obs_ip_start_time
|
|
488
|
+
assert task.constants._db_dict["INCIDENT_LIGHT_ANGLE_DEG"] == -1 * testing_grating_angle
|
|
489
|
+
assert (
|
|
490
|
+
task.constants._db_dict["REFLECTED_LIGHT_ANGLE_DEG"]
|
|
491
|
+
== -1 * testing_grating_angle + testing_arm_position
|
|
492
|
+
)
|
|
493
|
+
assert task.constants._db_dict["GRATING_CONSTANT_INVERSE_MM"] == testing_grating_constant
|
|
494
|
+
assert task.constants._db_dict["SOLAR_GAIN_IP_START_TIME"] == testing_solar_ip_start_time
|
|
438
495
|
assert task.constants._db_dict["NUM_MODSTATES"] == num_modstates
|
|
439
496
|
assert task.constants._db_dict["NUM_MAP_SCANS"] == num_maps_per_readout_exp_time * len(
|
|
440
497
|
observe_readout_exp_times
|
|
@@ -454,6 +511,10 @@ def test_parse_visp_input_data_constants(
|
|
|
454
511
|
observe_readout_exp_times
|
|
455
512
|
)
|
|
456
513
|
assert task.constants._db_dict["RETARDER_NAME"] == "SiO2 OC"
|
|
514
|
+
assert task.constants._db_dict["DARK_GOS_LEVEL3_STATUS"] == "lamp"
|
|
515
|
+
assert task.constants._db_dict["SOLAR_GAIN_GOS_LEVEL3_STATUS"] == "clear"
|
|
516
|
+
assert task.constants._db_dict["SOLAR_GAIN_NUM_RAW_FRAMES_PER_FPA"] == 10
|
|
517
|
+
assert task.constants._db_dict["POLCAL_NUM_RAW_FRAMES_PER_FPA"] == 10
|
|
457
518
|
|
|
458
519
|
|
|
459
520
|
def test_parse_visp_values(
|
|
@@ -462,6 +523,11 @@ def test_parse_visp_values(
|
|
|
462
523
|
observe_readout_exp_times,
|
|
463
524
|
num_modstates,
|
|
464
525
|
mocker,
|
|
526
|
+
fake_gql_client,
|
|
527
|
+
testing_arm_id,
|
|
528
|
+
testing_grating_constant,
|
|
529
|
+
testing_grating_angle,
|
|
530
|
+
testing_arm_position,
|
|
465
531
|
):
|
|
466
532
|
"""
|
|
467
533
|
:Given: A valid parse input task
|
|
@@ -469,7 +535,7 @@ def test_parse_visp_values(
|
|
|
469
535
|
:Then: Values are correctly loaded into the constants mutable mapping
|
|
470
536
|
"""
|
|
471
537
|
mocker.patch(
|
|
472
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
538
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
473
539
|
)
|
|
474
540
|
task = parse_task_with_no_data
|
|
475
541
|
write_input_cal_frames_to_task(task)
|
|
@@ -480,6 +546,10 @@ def test_parse_visp_values(
|
|
|
480
546
|
num_maps=1,
|
|
481
547
|
num_steps=1,
|
|
482
548
|
num_modstates=num_modstates,
|
|
549
|
+
arm_id=testing_arm_id,
|
|
550
|
+
grating_constant=testing_grating_constant,
|
|
551
|
+
grating_angle=testing_grating_angle,
|
|
552
|
+
arm_position=testing_arm_position,
|
|
483
553
|
)
|
|
484
554
|
|
|
485
555
|
task()
|
|
@@ -488,16 +558,19 @@ def test_parse_visp_values(
|
|
|
488
558
|
assert task.constants.maximum_cadence == 10
|
|
489
559
|
assert task.constants.minimum_cadence == 10
|
|
490
560
|
assert task.constants.variance_cadence == 0
|
|
561
|
+
assert task.constants.camera_name == "camera_name"
|
|
491
562
|
|
|
492
563
|
|
|
493
|
-
def test_multiple_num_raster_steps_raises_error(
|
|
564
|
+
def test_multiple_num_raster_steps_raises_error(
|
|
565
|
+
parse_task_with_no_data, num_modstates, mocker, fake_gql_client
|
|
566
|
+
):
|
|
494
567
|
"""
|
|
495
568
|
:Given: A prase task with data that have inconsistent VSPNSTP values
|
|
496
569
|
:When: Calling the parse task
|
|
497
570
|
:Then: The correct error is raised
|
|
498
571
|
"""
|
|
499
572
|
mocker.patch(
|
|
500
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
573
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
501
574
|
)
|
|
502
575
|
task = parse_task_with_no_data
|
|
503
576
|
write_input_dark_frames_to_task(task, readout_exp_time=0.1, exp_time=0.2)
|
|
@@ -515,14 +588,14 @@ def test_multiple_num_raster_steps_raises_error(parse_task_with_no_data, num_mod
|
|
|
515
588
|
task()
|
|
516
589
|
|
|
517
590
|
|
|
518
|
-
def test_incomplete_single_map(parse_task_with_no_data, num_modstates, mocker):
|
|
591
|
+
def test_incomplete_single_map(parse_task_with_no_data, num_modstates, mocker, fake_gql_client):
|
|
519
592
|
"""
|
|
520
593
|
:Given: A parse task with data that has an incomplete raster scan
|
|
521
594
|
:When: Calling the parse task
|
|
522
595
|
:Then: The correct number of raster steps are found
|
|
523
596
|
"""
|
|
524
597
|
mocker.patch(
|
|
525
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
598
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
526
599
|
)
|
|
527
600
|
task = parse_task_with_no_data
|
|
528
601
|
num_steps = 4
|
|
@@ -542,14 +615,14 @@ def test_incomplete_single_map(parse_task_with_no_data, num_modstates, mocker):
|
|
|
542
615
|
assert task.constants._db_dict["NUM_MAP_SCANS"] == num_map_scans
|
|
543
616
|
|
|
544
617
|
|
|
545
|
-
def test_incomplete_final_map(parse_task_with_no_data, num_modstates, mocker):
|
|
618
|
+
def test_incomplete_final_map(parse_task_with_no_data, num_modstates, mocker, fake_gql_client):
|
|
546
619
|
"""
|
|
547
620
|
:Given: A parse task with data that has complete raster scans along with an incomplete raster scan
|
|
548
621
|
:When: Calling the parse task
|
|
549
622
|
:Then: The correct number of raster steps and maps are found
|
|
550
623
|
"""
|
|
551
624
|
mocker.patch(
|
|
552
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
625
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
553
626
|
)
|
|
554
627
|
task = parse_task_with_no_data
|
|
555
628
|
num_steps = 4
|
|
@@ -575,6 +648,11 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
575
648
|
observe_readout_exp_times,
|
|
576
649
|
observe_exp_times,
|
|
577
650
|
mocker,
|
|
651
|
+
fake_gql_client,
|
|
652
|
+
testing_arm_id,
|
|
653
|
+
testing_grating_constant,
|
|
654
|
+
testing_grating_angle,
|
|
655
|
+
testing_arm_position,
|
|
578
656
|
):
|
|
579
657
|
"""
|
|
580
658
|
:Given: Data where the observe frames are in intensity mode and the calibration frames are in polarimetric mode
|
|
@@ -582,7 +660,7 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
582
660
|
:Then: All modulator state keys generated for all frames are in the first modulator state
|
|
583
661
|
"""
|
|
584
662
|
mocker.patch(
|
|
585
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
663
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
586
664
|
)
|
|
587
665
|
task = parse_task_with_no_data
|
|
588
666
|
write_input_cal_frames_to_task(task)
|
|
@@ -594,6 +672,10 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
594
672
|
readout_exp_time=observe_readout_exp_times[0],
|
|
595
673
|
exp_time=observe_exp_times[0],
|
|
596
674
|
obs_dataset_class=VispHeadersIntensityObserveFrames,
|
|
675
|
+
arm_id=testing_arm_id,
|
|
676
|
+
grating_constant=testing_grating_constant,
|
|
677
|
+
grating_angle=testing_grating_angle,
|
|
678
|
+
arm_position=testing_arm_position,
|
|
597
679
|
)
|
|
598
680
|
task()
|
|
599
681
|
assert task.constants._db_dict["NUM_MODSTATES"] == 1
|
|
@@ -603,14 +685,16 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
603
685
|
assert "MODSTATE_1" in task.scratch.tags(file)
|
|
604
686
|
|
|
605
687
|
|
|
606
|
-
def test_dark_readout_exp_time_picky_bud(
|
|
688
|
+
def test_dark_readout_exp_time_picky_bud(
|
|
689
|
+
parse_task_with_no_data, mocker, fake_gql_client, lamp_readout_exp_time
|
|
690
|
+
):
|
|
607
691
|
"""
|
|
608
692
|
:Given: Dataset where non-dark readout exp time values are missing from the set of dark IP frames.
|
|
609
693
|
:When: Parsing
|
|
610
694
|
:Then: The `DarkReadoutExpTimePickyBud` raises an error
|
|
611
695
|
"""
|
|
612
696
|
mocker.patch(
|
|
613
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
697
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
614
698
|
)
|
|
615
699
|
bad_readout_exp_time = lamp_readout_exp_time + 0.02
|
|
616
700
|
dummy_exp_time = 99.0
|
|
@@ -6,7 +6,6 @@ from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
|
6
6
|
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
7
7
|
from dkist_processing_common.models.tags import Tag
|
|
8
8
|
from dkist_processing_common.models.task_name import TaskName
|
|
9
|
-
from dkist_processing_common.tests.conftest import FakeGQLClient
|
|
10
9
|
|
|
11
10
|
from dkist_processing_visp.models.tags import VispTag
|
|
12
11
|
from dkist_processing_visp.tasks.quality_metrics import VispL0QualityMetrics
|
|
@@ -132,7 +131,7 @@ def test_l0_quality_task(
|
|
|
132
131
|
|
|
133
132
|
|
|
134
133
|
@pytest.mark.parametrize("pol_mode", ["observe_polarimetric", "observe_intensity"])
|
|
135
|
-
def test_l1_quality_task(visp_l1_quality_task, pol_mode, mocker):
|
|
134
|
+
def test_l1_quality_task(visp_l1_quality_task, pol_mode, mocker, fake_gql_client):
|
|
136
135
|
"""
|
|
137
136
|
Given: A VispL1QualityMetrics task
|
|
138
137
|
When: Calling the task instance
|
|
@@ -140,7 +139,7 @@ def test_l1_quality_task(visp_l1_quality_task, pol_mode, mocker):
|
|
|
140
139
|
and a single noise measurement and datetime is recorded for L1 file for each Stokes Q, U, and V
|
|
141
140
|
"""
|
|
142
141
|
mocker.patch(
|
|
143
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
142
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
144
143
|
)
|
|
145
144
|
# When
|
|
146
145
|
task, num_maps, num_steps, num_stokes = visp_l1_quality_task
|
|
@@ -12,8 +12,8 @@ from dkist_header_validator import spec122_validator
|
|
|
12
12
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
13
13
|
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
14
14
|
from dkist_processing_common.codecs.fits import fits_hdu_decoder
|
|
15
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
15
16
|
from dkist_processing_common.models.tags import Tag
|
|
16
|
-
from dkist_processing_common.tests.conftest import FakeGQLClient
|
|
17
17
|
|
|
18
18
|
from dkist_processing_visp.models.tags import VispStemName
|
|
19
19
|
from dkist_processing_visp.models.tags import VispTag
|
|
@@ -144,7 +144,7 @@ def dummy_calibration_collection():
|
|
|
144
144
|
|
|
145
145
|
dark_dict = {VispTag.beam(beam): {VispTag.readout_exp_time(0.04): np.zeros(intermediate_shape)}}
|
|
146
146
|
background_dict = {VispTag.beam(beam): np.zeros(intermediate_shape)}
|
|
147
|
-
solar_dict = {VispTag.beam(beam):
|
|
147
|
+
solar_dict = {VispTag.beam(beam): np.ones(intermediate_shape)}
|
|
148
148
|
angle_dict = {VispTag.beam(beam): 0.0}
|
|
149
149
|
spec_dict = {VispTag.beam(beam): np.zeros(intermediate_shape[1])}
|
|
150
150
|
offset_dict = {VispTag.beam(beam): {VispTag.modstate(modstate): np.zeros(2)}}
|
|
@@ -184,7 +184,7 @@ def headers_with_dates() -> tuple[list[fits.Header], str, int, int]:
|
|
|
184
184
|
]
|
|
185
185
|
random.shuffle(headers) # Shuffle to make sure they're not already in time order
|
|
186
186
|
for h in headers:
|
|
187
|
-
h[
|
|
187
|
+
h[MetadataKey.fpa_exposure_time_ms] = exp_time # Exposure time, in ms
|
|
188
188
|
|
|
189
189
|
return headers, start_time, exp_time, time_delta
|
|
190
190
|
|
|
@@ -252,10 +252,14 @@ def calibration_collection_with_full_overlap_slice() -> CalibrationCollection:
|
|
|
252
252
|
|
|
253
253
|
@pytest.mark.parametrize(
|
|
254
254
|
"background_on",
|
|
255
|
-
[pytest.param(True, id="
|
|
255
|
+
[pytest.param(True, id="background_on"), pytest.param(False, id="background_off")],
|
|
256
256
|
)
|
|
257
257
|
def test_science_calibration_task(
|
|
258
|
-
science_calibration_task,
|
|
258
|
+
science_calibration_task,
|
|
259
|
+
background_on,
|
|
260
|
+
assign_input_dataset_doc_to_task,
|
|
261
|
+
mocker,
|
|
262
|
+
fake_gql_client,
|
|
259
263
|
):
|
|
260
264
|
"""
|
|
261
265
|
Given: A ScienceCalibration task
|
|
@@ -264,7 +268,7 @@ def test_science_calibration_task(
|
|
|
264
268
|
"""
|
|
265
269
|
|
|
266
270
|
mocker.patch(
|
|
267
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
271
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
268
272
|
)
|
|
269
273
|
|
|
270
274
|
# When
|
|
@@ -304,7 +308,8 @@ def test_science_calibration_task(
|
|
|
304
308
|
task=task, num_modstates=num_modstates, data_shape=intermediate_shape, offsets=offsets
|
|
305
309
|
)
|
|
306
310
|
write_dummy_intermediate_solar_cals_to_task(
|
|
307
|
-
task=task,
|
|
311
|
+
task=task,
|
|
312
|
+
data_shape=intermediate_shape,
|
|
308
313
|
)
|
|
309
314
|
write_demod_matrices_to_task(task=task, num_modstates=num_modstates)
|
|
310
315
|
write_input_observe_frames_to_task(
|
|
@@ -360,10 +365,10 @@ def test_science_calibration_task(
|
|
|
360
365
|
assert header["VSPMAP"] == map_scan
|
|
361
366
|
|
|
362
367
|
# Check that WCS keys were updated
|
|
363
|
-
if offsets[1, 0, 0]
|
|
364
|
-
assert header["CRPIX2"] == input_header["CRPIX2"] - np.ceil(offsets[1, 0, 0])
|
|
365
|
-
if offsets[1, 0, 1]
|
|
366
|
-
assert header["CRPIX1"] == input_header["CRPIX1"] - np.ceil(offsets[1, 0, 1])
|
|
368
|
+
if offsets[1, 0, 0] < 0:
|
|
369
|
+
assert header["CRPIX2"] == input_header["CRPIX2"] - np.ceil(-offsets[1, 0, 0])
|
|
370
|
+
if offsets[1, 0, 1] < 0:
|
|
371
|
+
assert header["CRPIX1"] == input_header["CRPIX1"] - np.ceil(-offsets[1, 0, 1])
|
|
367
372
|
|
|
368
373
|
quality_files = task.read(tags=[Tag.quality("TASK_TYPES")])
|
|
369
374
|
for file in quality_files:
|
|
@@ -416,7 +421,7 @@ def test_readout_normalization_correct(
|
|
|
416
421
|
)
|
|
417
422
|
|
|
418
423
|
# When:
|
|
419
|
-
corrected_array, _ = task.correct_single_frame(
|
|
424
|
+
corrected_array, _, _ = task.correct_single_frame(
|
|
420
425
|
beam=1,
|
|
421
426
|
modstate=1,
|
|
422
427
|
raster_step=1,
|
|
@@ -509,7 +514,7 @@ def test_compute_date_keys_compressed_headers(
|
|
|
509
514
|
[[1.0, 2.0], [11.0, 10.0], [3.0, 2.0]], # Beam 2
|
|
510
515
|
]
|
|
511
516
|
),
|
|
512
|
-
[slice(
|
|
517
|
+
[slice(0, -11, None), slice(0, -10, None)],
|
|
513
518
|
),
|
|
514
519
|
(
|
|
515
520
|
np.array(
|
|
@@ -518,7 +523,7 @@ def test_compute_date_keys_compressed_headers(
|
|
|
518
523
|
[[-1.0, -2.0], [-11.0, -10.0], [-3.0, -2.0]], # Beam 2
|
|
519
524
|
]
|
|
520
525
|
),
|
|
521
|
-
[slice(
|
|
526
|
+
[slice(11, None, None), slice(10, None, None)],
|
|
522
527
|
),
|
|
523
528
|
(
|
|
524
529
|
np.array(
|
|
@@ -527,7 +532,7 @@ def test_compute_date_keys_compressed_headers(
|
|
|
527
532
|
[[1.0, 2.0], [-11.0, 10.0], [-3.0, -2.0]], # Beam 2
|
|
528
533
|
]
|
|
529
534
|
),
|
|
530
|
-
[slice(
|
|
535
|
+
[slice(11, -10, None), slice(2, -10, None)],
|
|
531
536
|
),
|
|
532
537
|
],
|
|
533
538
|
ids=["All positive", "All negative", "Positive and negative"],
|
|
@@ -577,3 +582,96 @@ def test_combine_beams(
|
|
|
577
582
|
expected = np.ones((10, 10, 4)) * 2.5
|
|
578
583
|
|
|
579
584
|
np.testing.assert_array_equal(data, expected)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@pytest.mark.parametrize(
|
|
588
|
+
"shifts",
|
|
589
|
+
# Shifts have shape (num_beams, num_modstates, 2)
|
|
590
|
+
# So the inner-most lists below (e.g., [5.0, 6.0]) correspond to [x_shift, y_shit]
|
|
591
|
+
[
|
|
592
|
+
np.array(
|
|
593
|
+
[
|
|
594
|
+
[[0.0, 0.0], [10.0, 2.0], [5.0, 6.0]], # Beam 1
|
|
595
|
+
[[1.0, 2.0], [-11.0, 10.0], [-3.0, -2.0]], # Beam 2
|
|
596
|
+
]
|
|
597
|
+
),
|
|
598
|
+
],
|
|
599
|
+
ids=["Positive and negative"],
|
|
600
|
+
)
|
|
601
|
+
def test_combine_and_cut_nan_masks(
|
|
602
|
+
science_calibration_task, calibration_collection_with_geo_shifts, shifts
|
|
603
|
+
):
|
|
604
|
+
"""
|
|
605
|
+
Given: A ScienceCalibration task and NaN masks, along with geometric shifts
|
|
606
|
+
When: Combining the two NaN masks
|
|
607
|
+
Then: The final mask has NaN values in the correct place and is correctly cropped
|
|
608
|
+
"""
|
|
609
|
+
nan_1_location = [0, 1]
|
|
610
|
+
nan_2_location = [50, 50]
|
|
611
|
+
nan_3_location = [4, 1]
|
|
612
|
+
nan_4_location = [55, 63]
|
|
613
|
+
nan_mask_shape = (100, 100)
|
|
614
|
+
nan_mask_1 = np.zeros(shape=nan_mask_shape)
|
|
615
|
+
nan_mask_1[nan_1_location[0], nan_1_location[1]] = np.nan
|
|
616
|
+
nan_mask_1[nan_2_location[0], nan_2_location[1]] = np.nan
|
|
617
|
+
nan_mask_2 = np.zeros(shape=nan_mask_shape)
|
|
618
|
+
nan_mask_2[nan_3_location[0], nan_3_location[1]] = np.nan
|
|
619
|
+
nan_mask_2[nan_4_location[0], nan_4_location[1]] = np.nan
|
|
620
|
+
task, _, _, _, _, _ = science_calibration_task
|
|
621
|
+
combined_nan_mask = task.combine_and_cut_nan_masks(
|
|
622
|
+
nan_masks=[nan_mask_1, nan_mask_2], calibrations=calibration_collection_with_geo_shifts
|
|
623
|
+
)
|
|
624
|
+
beam_1_shifts = shifts[0]
|
|
625
|
+
beam_2_shifts = shifts[1]
|
|
626
|
+
beam_1_x_shifts = [i[0] for i in beam_1_shifts]
|
|
627
|
+
beam_2_x_shifts = [i[0] for i in beam_2_shifts]
|
|
628
|
+
beam_1_y_shifts = [i[1] for i in beam_1_shifts]
|
|
629
|
+
beam_2_y_shifts = [i[1] for i in beam_2_shifts]
|
|
630
|
+
x_shifts = beam_1_x_shifts + beam_2_x_shifts
|
|
631
|
+
y_shifts = beam_1_y_shifts + beam_2_y_shifts
|
|
632
|
+
assert combined_nan_mask.shape == (
|
|
633
|
+
nan_mask_shape[0] - (max(x_shifts) - min(x_shifts)),
|
|
634
|
+
nan_mask_shape[1] - (max(y_shifts) - min(y_shifts)),
|
|
635
|
+
)
|
|
636
|
+
# Check that one NaN value from each original mask is present in the combined mask and in the correct place
|
|
637
|
+
assert (
|
|
638
|
+
combined_nan_mask[
|
|
639
|
+
nan_2_location[0] - int(abs(min(x_shifts))), nan_2_location[1] - int(abs(min(y_shifts)))
|
|
640
|
+
]
|
|
641
|
+
== True
|
|
642
|
+
)
|
|
643
|
+
assert (
|
|
644
|
+
combined_nan_mask[
|
|
645
|
+
nan_4_location[0] - int(abs(min(x_shifts))), nan_4_location[1] - int(abs(min(y_shifts)))
|
|
646
|
+
]
|
|
647
|
+
== True
|
|
648
|
+
)
|
|
649
|
+
assert np.sum(combined_nan_mask) == 2 # only two NaN values are in the final mask
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
def test_generate_nan_mask(science_calibration_task, dummy_calibration_collection):
|
|
653
|
+
"""
|
|
654
|
+
Given: a calibration collection
|
|
655
|
+
When: calculating the NaN mask to use
|
|
656
|
+
Then: the mask takes up some, but not all, of the frame size
|
|
657
|
+
"""
|
|
658
|
+
task, _, _, _, _, _ = science_calibration_task
|
|
659
|
+
calibration_collection, _, _ = dummy_calibration_collection
|
|
660
|
+
beam = 1
|
|
661
|
+
modstate = 1
|
|
662
|
+
solar_gain_array = calibration_collection.solar_gain[VispTag.beam(beam)]
|
|
663
|
+
angle = calibration_collection.angle[VispTag.beam(beam)]
|
|
664
|
+
spec_shift = calibration_collection.spec_shift[VispTag.beam(beam)]
|
|
665
|
+
state_offset = calibration_collection.state_offset[VispTag.beam(beam)][
|
|
666
|
+
VispTag.modstate(modstate)
|
|
667
|
+
]
|
|
668
|
+
nan_mask = task.generate_nan_mask(
|
|
669
|
+
solar_corrected_array=np.random.random(size=solar_gain_array.shape),
|
|
670
|
+
state_offset=state_offset,
|
|
671
|
+
angle=angle,
|
|
672
|
+
spec_shift=spec_shift,
|
|
673
|
+
)
|
|
674
|
+
# Some of the mask is marked as NaN but not all
|
|
675
|
+
assert np.sum(nan_mask) < np.size(nan_mask)
|
|
676
|
+
# Ensure that only zeroes and ones are in the mask
|
|
677
|
+
assert set(np.unique(nan_mask)) == {0, 1}
|