dkist-processing-visp 4.0.0__py3-none-any.whl → 5.0.0__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/models/constants.py +50 -9
- dkist_processing_visp/models/fits_access.py +5 -1
- dkist_processing_visp/models/metric_code.py +10 -0
- dkist_processing_visp/models/parameters.py +128 -19
- dkist_processing_visp/parsers/spectrograph_configuration.py +75 -0
- dkist_processing_visp/parsers/visp_l0_fits_access.py +6 -0
- dkist_processing_visp/tasks/geometric.py +115 -7
- dkist_processing_visp/tasks/l1_output_data.py +202 -0
- dkist_processing_visp/tasks/lamp.py +50 -91
- dkist_processing_visp/tasks/parse.py +19 -0
- dkist_processing_visp/tasks/science.py +14 -14
- dkist_processing_visp/tasks/solar.py +894 -451
- dkist_processing_visp/tasks/visp_base.py +1 -0
- dkist_processing_visp/tests/conftest.py +98 -35
- dkist_processing_visp/tests/header_models.py +71 -20
- dkist_processing_visp/tests/local_trial_workflows/local_trial_helpers.py +25 -1
- dkist_processing_visp/tests/test_assemble_quality.py +89 -4
- dkist_processing_visp/tests/test_geometric.py +40 -0
- dkist_processing_visp/tests/test_instrument_polarization.py +2 -1
- dkist_processing_visp/tests/test_lamp.py +17 -22
- dkist_processing_visp/tests/test_parameters.py +120 -18
- dkist_processing_visp/tests/test_parse.py +73 -1
- dkist_processing_visp/tests/test_science.py +5 -6
- dkist_processing_visp/tests/test_solar.py +319 -102
- dkist_processing_visp/tests/test_visp_constants.py +35 -6
- {dkist_processing_visp-4.0.0.dist-info → dkist_processing_visp-5.0.0.dist-info}/METADATA +40 -37
- {dkist_processing_visp-4.0.0.dist-info → dkist_processing_visp-5.0.0.dist-info}/RECORD +31 -30
- docs/conf.py +4 -1
- docs/gain_correction.rst +50 -42
- dkist_processing_visp/tasks/mixin/line_zones.py +0 -116
- {dkist_processing_visp-4.0.0.dist-info → dkist_processing_visp-5.0.0.dist-info}/WHEEL +0 -0
- {dkist_processing_visp-4.0.0.dist-info → dkist_processing_visp-5.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from dataclasses import asdict
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
+
from dataclasses import field
|
|
4
5
|
from dataclasses import is_dataclass
|
|
5
6
|
from random import randint
|
|
7
|
+
from typing import Any
|
|
6
8
|
from typing import Callable
|
|
7
9
|
from typing import Type
|
|
8
10
|
|
|
@@ -17,6 +19,8 @@ from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
|
17
19
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
18
20
|
from dkist_processing_common.models.input_dataset import InputDatasetPartDocumentList
|
|
19
21
|
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
22
|
+
|
|
23
|
+
# Don't remove this; tests will break
|
|
20
24
|
from dkist_processing_common.tests.mock_metadata_store import fake_gql_client
|
|
21
25
|
|
|
22
26
|
from dkist_processing_visp.models.constants import VispConstants
|
|
@@ -41,6 +45,7 @@ def init_visp_constants_db():
|
|
|
41
45
|
|
|
42
46
|
@dataclass
|
|
43
47
|
class VispConstantsDb:
|
|
48
|
+
ARM_ID: int = 1
|
|
44
49
|
POLARIMETER_MODE: str = "observe_polarimetric"
|
|
45
50
|
OBS_IP_START_TIME: str = "2022-11-28T13:54:00"
|
|
46
51
|
NUM_MODSTATES: int = 10
|
|
@@ -66,6 +71,10 @@ class VispConstantsDb:
|
|
|
66
71
|
OBSERVE_READOUT_EXP_TIMES: tuple[float] = (0.02,)
|
|
67
72
|
POLCAL_READOUT_EXP_TIMES: tuple[float] = (0.02,)
|
|
68
73
|
SPECTRAL_LINE: str = "VISP Ca II H"
|
|
74
|
+
INCIDENT_LIGHT_ANGLE_DEG: float = 73.22
|
|
75
|
+
REFLECTED_LIGHT_ANGLE_DEG: float = 64.92
|
|
76
|
+
GRATING_CONSTANT_INVERSE_MM: float = 316.0
|
|
77
|
+
SOLAR_GAIN_IP_START_TIME: str = "2025-09-24T20:00:00"
|
|
69
78
|
STOKES_PARAMS: tuple[str] = (
|
|
70
79
|
"I",
|
|
71
80
|
"Q",
|
|
@@ -128,19 +137,59 @@ class VispInputDatasetParameterValues:
|
|
|
128
137
|
visp_geo_upsample_factor: float = 10.0
|
|
129
138
|
visp_geo_max_shift: float = 40.0
|
|
130
139
|
visp_geo_poly_fit_order: int = 3
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
visp_geo_zone_prominence: WavelengthParameter = WavelengthParameter(values=(0.2, 0.2, 0.3, 0.2))
|
|
141
|
+
visp_geo_zone_width: WavelengthParameter = WavelengthParameter(values=(7, 2, 3, 2))
|
|
142
|
+
visp_geo_zone_bg_order: WavelengthParameter = WavelengthParameter(values=(21, 22, 11, 22))
|
|
143
|
+
visp_geo_zone_normalization_percentile: WavelengthParameter = WavelengthParameter(
|
|
144
|
+
values=(90, 99, 90, 90)
|
|
145
|
+
)
|
|
146
|
+
visp_geo_zone_rel_height: float = 0.97
|
|
147
|
+
visp_solar_spatial_median_filter_width_px: WavelengthParameter = WavelengthParameter(
|
|
148
|
+
values=(250, 250, 250, 250)
|
|
133
149
|
)
|
|
134
150
|
visp_solar_characteristic_spatial_normalization_percentile: float = 90.0
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
visp_solar_vignette_initial_continuum_poly_fit_order: int = 6
|
|
152
|
+
visp_solar_vignette_crval_bounds_px: float = 7
|
|
153
|
+
visp_solar_vignette_dispersion_bounds_fraction: float = 0.02
|
|
154
|
+
visp_solar_vignette_wavecal_fit_kwargs: dict[str, Any] = field(
|
|
155
|
+
default_factory=lambda: {
|
|
156
|
+
"method": "differential_evolution",
|
|
157
|
+
"init": "halton",
|
|
158
|
+
"popsize": 1,
|
|
159
|
+
"tol": 1e-10,
|
|
160
|
+
}
|
|
137
161
|
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
162
|
+
visp_solar_vignette_spectral_poly_fit_order: int = 12
|
|
163
|
+
visp_solar_vignette_min_samples: float = 0.9
|
|
164
|
+
visp_wavecal_camera_lens_parameters_1: tuple[float, float, float] = (
|
|
165
|
+
0.7613,
|
|
166
|
+
1.720e-4,
|
|
167
|
+
-8.139e-8,
|
|
168
|
+
)
|
|
169
|
+
visp_wavecal_camera_lens_parameters_2: tuple[float, float, float] = (
|
|
170
|
+
0.9512,
|
|
171
|
+
2.141e-4,
|
|
172
|
+
-1.014e-7,
|
|
142
173
|
)
|
|
143
|
-
|
|
174
|
+
visp_wavecal_camera_lens_parameters_3: tuple[float, float, float] = (
|
|
175
|
+
0.1153e1,
|
|
176
|
+
2.595e-4,
|
|
177
|
+
-1.230e-7,
|
|
178
|
+
)
|
|
179
|
+
visp_wavecal_pixel_pitch_micron_per_pix: float = 6.5
|
|
180
|
+
visp_wavecal_atlas_download_config: dict[str, str] = field(
|
|
181
|
+
default_factory=lambda: {
|
|
182
|
+
"base_url": "doi:10.5281/zenodo.14646787/",
|
|
183
|
+
"telluric_reference_atlas_file_name": "telluric_reference_atlas.npy",
|
|
184
|
+
"telluric_reference_atlas_hash_id": "md5:8db5e12508b293bca3495d81a0747447",
|
|
185
|
+
"solar_reference_atlas_file_name": "solar_reference_atlas.npy",
|
|
186
|
+
"solar_reference_atlas_hash_id": "md5:84ab4c50689ef235fe5ed4f7ee905ca0",
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
visp_wavecal_init_crval_guess_normalization_percentile: float = 95
|
|
190
|
+
visp_wavecal_init_resolving_power: int = 150000
|
|
191
|
+
visp_wavecal_init_straylight_fraction: float = 0.2
|
|
192
|
+
visp_wavecal_init_opacity_factor: float = 5.0
|
|
144
193
|
visp_polcal_spatial_median_filter_width_px: int = 10
|
|
145
194
|
visp_polcal_num_spatial_bins: int = 10
|
|
146
195
|
visp_polcal_demod_spatial_smooth_fit_order: int = 17
|
|
@@ -160,6 +209,32 @@ def testing_obs_ip_start_time() -> str:
|
|
|
160
209
|
return "1946-11-20T12:34:56"
|
|
161
210
|
|
|
162
211
|
|
|
212
|
+
@pytest.fixture(scope="session")
|
|
213
|
+
def testing_grating_constant() -> float:
|
|
214
|
+
# Just make it different than the defaults in header_models.py
|
|
215
|
+
return 317.2
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@pytest.fixture(scope="session")
|
|
219
|
+
def testing_grating_angle() -> float:
|
|
220
|
+
return -43.2
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@pytest.fixture(scope="session")
|
|
224
|
+
def testing_arm_position() -> float:
|
|
225
|
+
return -5.3
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@pytest.fixture(scope="session")
|
|
229
|
+
def testing_solar_ip_start_time() -> str:
|
|
230
|
+
return "1946-11-21T12:34:56"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@pytest.fixture(scope="session")
|
|
234
|
+
def testing_arm_id() -> int:
|
|
235
|
+
return 2
|
|
236
|
+
|
|
237
|
+
|
|
163
238
|
@pytest.fixture(scope="session")
|
|
164
239
|
def input_dataset_document_simple_parameters_part():
|
|
165
240
|
"""Convert a dataclass of parameterValues into an actual input dataset parameters part."""
|
|
@@ -186,13 +261,17 @@ def input_dataset_document_simple_parameters_part():
|
|
|
186
261
|
|
|
187
262
|
@pytest.fixture(scope="session")
|
|
188
263
|
def assign_input_dataset_doc_to_task(
|
|
189
|
-
input_dataset_document_simple_parameters_part,
|
|
264
|
+
input_dataset_document_simple_parameters_part,
|
|
265
|
+
testing_obs_ip_start_time,
|
|
266
|
+
testing_wavelength,
|
|
267
|
+
testing_arm_id,
|
|
190
268
|
):
|
|
191
269
|
def update_task(
|
|
192
270
|
task: WorkflowTaskBase,
|
|
193
271
|
parameter_values,
|
|
194
272
|
parameter_class=VispParameters,
|
|
195
273
|
obs_ip_start_time=testing_obs_ip_start_time,
|
|
274
|
+
arm_id=testing_arm_id,
|
|
196
275
|
):
|
|
197
276
|
task.write(
|
|
198
277
|
data=InputDatasetPartDocumentList(
|
|
@@ -205,6 +284,7 @@ def assign_input_dataset_doc_to_task(
|
|
|
205
284
|
scratch=task.scratch,
|
|
206
285
|
obs_ip_start_time=obs_ip_start_time,
|
|
207
286
|
wavelength=testing_wavelength,
|
|
287
|
+
arm_id=str(arm_id),
|
|
208
288
|
)
|
|
209
289
|
|
|
210
290
|
return update_task
|
|
@@ -343,28 +423,14 @@ def write_intermediate_background_to_task(
|
|
|
343
423
|
)
|
|
344
424
|
|
|
345
425
|
|
|
346
|
-
def write_intermediate_lamp_to_task(
|
|
347
|
-
task, *, lamp_signal: float, beam: int, modstate: int, data_shape: tuple[int, int]
|
|
348
|
-
):
|
|
349
|
-
lamp_array = np.ones(data_shape) * lamp_signal
|
|
350
|
-
task.write(
|
|
351
|
-
data=lamp_array,
|
|
352
|
-
tags=[
|
|
353
|
-
VispTag.intermediate_frame(beam=beam, modstate=modstate),
|
|
354
|
-
VispTag.task_lamp_gain(),
|
|
355
|
-
],
|
|
356
|
-
encoder=fits_array_encoder,
|
|
357
|
-
)
|
|
358
|
-
|
|
359
|
-
|
|
360
426
|
def write_intermediate_solar_to_task(
|
|
361
|
-
task, *, solar_signal: float, beam: int,
|
|
427
|
+
task, *, solar_signal: float, beam: int, data_shape: tuple[int, int]
|
|
362
428
|
):
|
|
363
429
|
solar_array = np.ones(data_shape) * solar_signal
|
|
364
430
|
task.write(
|
|
365
431
|
data=solar_array,
|
|
366
432
|
tags=[
|
|
367
|
-
VispTag.intermediate_frame(beam=beam
|
|
433
|
+
VispTag.intermediate_frame(beam=beam),
|
|
368
434
|
VispTag.task_solar_gain(),
|
|
369
435
|
],
|
|
370
436
|
encoder=fits_array_encoder,
|
|
@@ -414,19 +480,16 @@ def write_intermediate_geometric_to_task(
|
|
|
414
480
|
def write_dummy_intermediate_solar_cals_to_task(
|
|
415
481
|
task,
|
|
416
482
|
*,
|
|
417
|
-
num_modstates: int,
|
|
418
483
|
data_shape: tuple[int, int],
|
|
419
484
|
):
|
|
420
485
|
solar_signal = 1.0
|
|
421
486
|
for beam in [1, 2]:
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
data_shape=data_shape,
|
|
429
|
-
)
|
|
487
|
+
write_intermediate_solar_to_task(
|
|
488
|
+
task=task,
|
|
489
|
+
solar_signal=solar_signal,
|
|
490
|
+
beam=beam,
|
|
491
|
+
data_shape=data_shape,
|
|
492
|
+
)
|
|
430
493
|
|
|
431
494
|
|
|
432
495
|
def write_intermediate_polcal_darks_to_task(
|
|
@@ -31,6 +31,12 @@ class VispHeaders(Spec122Dataset):
|
|
|
31
31
|
num_modstates_header_value: int = 2,
|
|
32
32
|
instrument: str = "visp",
|
|
33
33
|
polarimeter_mode: str = "observe_polarimetric",
|
|
34
|
+
arm_id: int = 1,
|
|
35
|
+
ip_start_time: str = "2022-11-28T13:00:00",
|
|
36
|
+
ip_end_time: str = "2022-11-28T13:00:00",
|
|
37
|
+
grating_constant: float = 316.0,
|
|
38
|
+
grating_angle: float = -69.9,
|
|
39
|
+
arm_position: float = -4.0,
|
|
34
40
|
**kwargs,
|
|
35
41
|
):
|
|
36
42
|
super().__init__(
|
|
@@ -40,13 +46,21 @@ class VispHeaders(Spec122Dataset):
|
|
|
40
46
|
instrument=instrument,
|
|
41
47
|
**kwargs,
|
|
42
48
|
)
|
|
49
|
+
self.add_constant_key("VISP_001", arm_id)
|
|
43
50
|
self.add_constant_key("WAVELNTH", 656.30)
|
|
44
51
|
self.add_constant_key("VISP_010", num_modstates_header_value)
|
|
45
52
|
self.add_constant_key("ID___013", "TEST_PROPOSAL_ID")
|
|
46
53
|
self.add_constant_key("VISP_006", polarimeter_mode)
|
|
47
54
|
self.add_constant_key("PAC__005", "0")
|
|
48
55
|
self.add_constant_key("PAC__007", "10")
|
|
56
|
+
self.add_constant_key("DKIST011", ip_start_time)
|
|
57
|
+
self.add_constant_key("DKIST012", ip_end_time)
|
|
49
58
|
self.add_constant_key("FILE_ID", uuid.uuid4().hex)
|
|
59
|
+
|
|
60
|
+
self.add_constant_key("VISP_002", arm_position)
|
|
61
|
+
self.add_constant_key("VISP_013", grating_constant)
|
|
62
|
+
self.add_constant_key("VISP_015", grating_angle)
|
|
63
|
+
|
|
50
64
|
self.num_modstates_header_value = num_modstates_header_value
|
|
51
65
|
self.add_constant_key("CAM__001", "camera_id")
|
|
52
66
|
self.add_constant_key("CAM__002", "camera_name")
|
|
@@ -83,6 +97,8 @@ class VispHeadersInputDarkFrames(VispHeaders):
|
|
|
83
97
|
num_modstates: int,
|
|
84
98
|
exp_time: float = 1.0,
|
|
85
99
|
readout_exp_time: float = 2.0,
|
|
100
|
+
ip_start_time="2022-11-28T13:44:00",
|
|
101
|
+
ip_end_time="2022-11-28T13:45:00",
|
|
86
102
|
**kwargs,
|
|
87
103
|
):
|
|
88
104
|
################################################
|
|
@@ -95,13 +111,13 @@ class VispHeadersInputDarkFrames(VispHeaders):
|
|
|
95
111
|
array_shape,
|
|
96
112
|
time_delta,
|
|
97
113
|
num_modstates_header_value=num_modstates,
|
|
114
|
+
ip_start_time=ip_start_time,
|
|
115
|
+
ip_end_time=ip_end_time,
|
|
98
116
|
**kwargs,
|
|
99
117
|
)
|
|
100
118
|
self.add_constant_key("DKIST004", TaskName.dark.value.lower())
|
|
101
119
|
self.add_constant_key("DKIST008", 1)
|
|
102
120
|
self.add_constant_key("DKIST009", 1)
|
|
103
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:44:00")
|
|
104
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:45:00")
|
|
105
121
|
self.add_constant_key("VISP_019", 1) # Num raster steps
|
|
106
122
|
self.add_constant_key("VISP_020", 1) # Current raster step
|
|
107
123
|
self.add_constant_key("ID___004")
|
|
@@ -131,6 +147,8 @@ class VispHeadersInputLampGainFrames(VispHeaders):
|
|
|
131
147
|
num_modstates: int,
|
|
132
148
|
exp_time: float = 10.0,
|
|
133
149
|
readout_exp_time: float = 20.0,
|
|
150
|
+
ip_start_time="2022-11-28T13:46:00",
|
|
151
|
+
ip_end_time="2022-11-28T13:47:00",
|
|
134
152
|
**kwargs,
|
|
135
153
|
):
|
|
136
154
|
################################################
|
|
@@ -143,14 +161,14 @@ class VispHeadersInputLampGainFrames(VispHeaders):
|
|
|
143
161
|
array_shape,
|
|
144
162
|
time_delta,
|
|
145
163
|
num_modstates_header_value=num_modstates,
|
|
164
|
+
ip_start_time=ip_start_time,
|
|
165
|
+
ip_end_time=ip_end_time,
|
|
146
166
|
**kwargs,
|
|
147
167
|
)
|
|
148
168
|
self.add_constant_key("DKIST004", TaskName.gain.value.lower())
|
|
149
169
|
self.add_constant_key("PAC__002", "lamp")
|
|
150
170
|
self.add_constant_key("DKIST008", 1)
|
|
151
171
|
self.add_constant_key("DKIST009", 1)
|
|
152
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:46:00")
|
|
153
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:47:00")
|
|
154
172
|
self.add_constant_key("VISP_019", 1)
|
|
155
173
|
self.add_constant_key("VISP_020", 1)
|
|
156
174
|
self.add_constant_key("PAC__003", "on")
|
|
@@ -172,6 +190,8 @@ class VispHeadersInputSolarGainFrames(VispHeaders):
|
|
|
172
190
|
num_modstates: int,
|
|
173
191
|
exp_time: float = 20.0,
|
|
174
192
|
readout_exp_time: float = 40.0,
|
|
193
|
+
ip_start_time="2022-11-28T13:48:00",
|
|
194
|
+
ip_end_time="2022-11-28T13:49:00",
|
|
175
195
|
**kwargs,
|
|
176
196
|
):
|
|
177
197
|
################################################
|
|
@@ -184,13 +204,13 @@ class VispHeadersInputSolarGainFrames(VispHeaders):
|
|
|
184
204
|
array_shape,
|
|
185
205
|
time_delta,
|
|
186
206
|
num_modstates_header_value=num_modstates,
|
|
207
|
+
ip_start_time=ip_start_time,
|
|
208
|
+
ip_end_time=ip_end_time,
|
|
187
209
|
**kwargs,
|
|
188
210
|
)
|
|
189
211
|
self.add_constant_key("DKIST004", TaskName.gain.value.lower())
|
|
190
212
|
self.add_constant_key("DKIST008", 1)
|
|
191
213
|
self.add_constant_key("DKIST009", 1)
|
|
192
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:48:00")
|
|
193
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:49:00")
|
|
194
214
|
self.add_constant_key("VISP_019", 1)
|
|
195
215
|
self.add_constant_key("VISP_020", 1)
|
|
196
216
|
self.add_constant_key("PAC__002", "clear")
|
|
@@ -218,6 +238,8 @@ class VispHeadersInputPolcalFrames(VispHeaders):
|
|
|
218
238
|
num_cs_steps: int = 1,
|
|
219
239
|
exp_time: float = 0.01,
|
|
220
240
|
readout_exp_time: float = 0.02,
|
|
241
|
+
ip_start_time="2022-11-28T13:50:00",
|
|
242
|
+
ip_end_time="2022-11-28T13:51:00",
|
|
221
243
|
**kwargs,
|
|
222
244
|
):
|
|
223
245
|
################################################
|
|
@@ -230,6 +252,8 @@ class VispHeadersInputPolcalFrames(VispHeaders):
|
|
|
230
252
|
array_shape,
|
|
231
253
|
time_delta,
|
|
232
254
|
num_modstates_header_value=num_modstates,
|
|
255
|
+
ip_start_time=ip_start_time,
|
|
256
|
+
ip_end_time=ip_end_time,
|
|
233
257
|
**kwargs,
|
|
234
258
|
)
|
|
235
259
|
self.index_to_modstate = list(range(1, num_modstates + 1)) * num_cs_steps
|
|
@@ -240,8 +264,6 @@ class VispHeadersInputPolcalFrames(VispHeaders):
|
|
|
240
264
|
self.add_constant_key("DKIST004", TaskName.polcal.value.lower())
|
|
241
265
|
self.add_constant_key("DKIST008", 1)
|
|
242
266
|
self.add_constant_key("DKIST009", 1)
|
|
243
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:50:00")
|
|
244
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:51:00")
|
|
245
267
|
self.add_constant_key("VISP_019", 1)
|
|
246
268
|
self.add_constant_key("VISP_020", 1)
|
|
247
269
|
self.add_constant_key("TELSCAN", "Raster")
|
|
@@ -290,16 +312,23 @@ class VispHeadersInputPolcalDarkFrames(VispHeaders):
|
|
|
290
312
|
num_modstates: int,
|
|
291
313
|
exp_time: float = 0.01,
|
|
292
314
|
readout_exp_time: float = 0.02,
|
|
315
|
+
ip_start_time="2022-11-28T13:50:00",
|
|
316
|
+
ip_end_time="2022-11-28T13:51:00",
|
|
293
317
|
**kwargs,
|
|
294
318
|
):
|
|
295
319
|
num_frames = num_modstates
|
|
296
320
|
dataset_shape = (num_frames, *array_shape[-2:])
|
|
297
|
-
super().__init__(
|
|
321
|
+
super().__init__(
|
|
322
|
+
dataset_shape,
|
|
323
|
+
array_shape,
|
|
324
|
+
time_delta,
|
|
325
|
+
ip_start_time=ip_start_time,
|
|
326
|
+
ip_end_time=ip_end_time,
|
|
327
|
+
**kwargs,
|
|
328
|
+
)
|
|
298
329
|
self.add_constant_key("DKIST004", TaskName.polcal.value.lower())
|
|
299
330
|
self.add_constant_key("DKIST008", 1)
|
|
300
331
|
self.add_constant_key("DKIST009", 1)
|
|
301
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:50:00")
|
|
302
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:51:00")
|
|
303
332
|
self.add_constant_key("VISP_019", 1)
|
|
304
333
|
self.add_constant_key("VISP_020", 1)
|
|
305
334
|
self.add_constant_key("TELSCAN", "Raster")
|
|
@@ -322,16 +351,23 @@ class VispHeadersInputPolcalGainFrames(VispHeaders):
|
|
|
322
351
|
num_modstates: int,
|
|
323
352
|
exp_time: float = 0.01,
|
|
324
353
|
readout_exp_time: float = 0.02,
|
|
354
|
+
ip_start_time="2022-11-28T13:50:00",
|
|
355
|
+
ip_end_time="2022-11-28T13:51:00",
|
|
325
356
|
**kwargs,
|
|
326
357
|
):
|
|
327
358
|
num_frames = num_modstates
|
|
328
359
|
dataset_shape = (num_frames, *array_shape[-2:])
|
|
329
|
-
super().__init__(
|
|
360
|
+
super().__init__(
|
|
361
|
+
dataset_shape,
|
|
362
|
+
array_shape,
|
|
363
|
+
time_delta,
|
|
364
|
+
ip_start_time=ip_start_time,
|
|
365
|
+
ip_end_time=ip_end_time,
|
|
366
|
+
**kwargs,
|
|
367
|
+
)
|
|
330
368
|
self.add_constant_key("DKIST004", TaskName.polcal.value.lower())
|
|
331
369
|
self.add_constant_key("DKIST008", 1)
|
|
332
370
|
self.add_constant_key("DKIST009", 1)
|
|
333
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:50:00")
|
|
334
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:51:00")
|
|
335
371
|
self.add_constant_key("VISP_019", 1)
|
|
336
372
|
self.add_constant_key("VISP_020", 1)
|
|
337
373
|
self.add_constant_key("TELSCAN", "Raster")
|
|
@@ -357,6 +393,9 @@ class VispHeadersValidObserveFrames(VispHeaders):
|
|
|
357
393
|
exp_time: float = 15.0,
|
|
358
394
|
readout_exp_time: float = 30.0,
|
|
359
395
|
abort_last_step: bool = False,
|
|
396
|
+
ip_start_time="2022-11-28T13:55:00",
|
|
397
|
+
ip_end_time="2022-11-28T13:56:00",
|
|
398
|
+
grating_constant=316,
|
|
360
399
|
**kwargs,
|
|
361
400
|
):
|
|
362
401
|
################################################
|
|
@@ -370,7 +409,15 @@ class VispHeadersValidObserveFrames(VispHeaders):
|
|
|
370
409
|
num_frames -= num_dropped_frames
|
|
371
410
|
|
|
372
411
|
dataset_shape = (num_frames, *array_shape[-2:])
|
|
373
|
-
super().__init__(
|
|
412
|
+
super().__init__(
|
|
413
|
+
dataset_shape,
|
|
414
|
+
array_shape,
|
|
415
|
+
time_delta,
|
|
416
|
+
ip_start_time=ip_start_time,
|
|
417
|
+
ip_end_time=ip_end_time,
|
|
418
|
+
grating_constant=grating_constant,
|
|
419
|
+
**kwargs,
|
|
420
|
+
)
|
|
374
421
|
|
|
375
422
|
self.index_to_map = sum(
|
|
376
423
|
[[map_num + 1] * num_modstates * num_raster_steps for map_num in range(num_maps)], []
|
|
@@ -391,8 +438,6 @@ class VispHeadersValidObserveFrames(VispHeaders):
|
|
|
391
438
|
|
|
392
439
|
self.num_raster_steps = num_raster_steps
|
|
393
440
|
self.add_constant_key("DKIST004", TaskName.observe.value.lower())
|
|
394
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:55:00") # IP start time
|
|
395
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:56:00") # IP end time
|
|
396
441
|
self.add_constant_key("ID___004")
|
|
397
442
|
self.add_constant_key("WAVELNTH", 656.28)
|
|
398
443
|
self.add_constant_key("EXPER_ID", "EXPERIMENT ID")
|
|
@@ -439,6 +484,8 @@ class VispHeadersValidCalibratedFrames(VispHeaders):
|
|
|
439
484
|
exp_time: float = 15.0,
|
|
440
485
|
readout_exp_time: float = 30.0,
|
|
441
486
|
wcs_axis_names: tuple[str, str] | None = None,
|
|
487
|
+
ip_start_time="2022-11-28T13:55:00",
|
|
488
|
+
ip_end_time="2022-11-28T13:56:00",
|
|
442
489
|
**kwargs,
|
|
443
490
|
):
|
|
444
491
|
################################################
|
|
@@ -452,7 +499,13 @@ class VispHeadersValidCalibratedFrames(VispHeaders):
|
|
|
452
499
|
num_frames = num_maps * num_raster_steps * num_stokes
|
|
453
500
|
dataset_shape = (num_frames, *array_shape[-2:])
|
|
454
501
|
super().__init__(
|
|
455
|
-
dataset_shape,
|
|
502
|
+
dataset_shape,
|
|
503
|
+
array_shape,
|
|
504
|
+
time_delta,
|
|
505
|
+
polarimeter_mode=polarimeter_mode,
|
|
506
|
+
ip_start_time=ip_start_time,
|
|
507
|
+
ip_end_time=ip_end_time,
|
|
508
|
+
**kwargs,
|
|
456
509
|
)
|
|
457
510
|
|
|
458
511
|
stokes_list = ["I", "Q", "U", "V"][:num_stokes]
|
|
@@ -466,8 +519,6 @@ class VispHeadersValidCalibratedFrames(VispHeaders):
|
|
|
466
519
|
|
|
467
520
|
self.num_raster_steps = num_raster_steps
|
|
468
521
|
self.add_constant_key("DKIST004", TaskName.observe.value.lower())
|
|
469
|
-
self.add_constant_key("DKIST011", "2022-11-28T13:55:00") # IP start time
|
|
470
|
-
self.add_constant_key("DKIST012", "2022-11-28T13:56:00") # IP end time
|
|
471
522
|
self.add_constant_key("ID___004")
|
|
472
523
|
self.add_constant_key("WAVELNTH", 656.28)
|
|
473
524
|
self.add_constant_key("EXPER_ID", "EXPERIMENT ID")
|
|
@@ -10,6 +10,7 @@ from dkist_header_validator import spec214_validator
|
|
|
10
10
|
from dkist_processing_common.codecs.fits import fits_array_decoder
|
|
11
11
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
12
12
|
from dkist_processing_common.models.constants import BudName
|
|
13
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
13
14
|
from dkist_processing_common.models.task_name import TaskName
|
|
14
15
|
from dkist_processing_common.parsers.cs_step import CSStepFlower
|
|
15
16
|
from dkist_processing_common.parsers.cs_step import NumCSStepBud
|
|
@@ -21,6 +22,8 @@ from dkist_processing_common.parsers.time import ExposureTimeFlower
|
|
|
21
22
|
from dkist_processing_common.parsers.time import ReadoutExpTimeFlower
|
|
22
23
|
from dkist_processing_common.parsers.time import TaskExposureTimesBud
|
|
23
24
|
from dkist_processing_common.parsers.time import TaskReadoutExpTimesBud
|
|
25
|
+
from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
|
|
26
|
+
from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
24
27
|
from dkist_processing_common.tasks import ParseL0InputDataBase
|
|
25
28
|
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
26
29
|
from dkist_processing_common.tasks.mixin.globus import GlobusTransferItem
|
|
@@ -31,10 +34,13 @@ from loguru import logger
|
|
|
31
34
|
from dkist_processing_visp.models.constants import VispBudName
|
|
32
35
|
from dkist_processing_visp.models.constants import VispConstants
|
|
33
36
|
from dkist_processing_visp.models.fits_access import VispMetadataKey
|
|
37
|
+
from dkist_processing_visp.models.metric_code import VispMetricCode
|
|
34
38
|
from dkist_processing_visp.models.parameters import VispParsingParameters
|
|
35
39
|
from dkist_processing_visp.models.tags import VispTag
|
|
36
40
|
from dkist_processing_visp.models.task_name import VispTaskName
|
|
37
41
|
from dkist_processing_visp.parsers.modulator_states import ModulatorStateFlower
|
|
42
|
+
from dkist_processing_visp.parsers.spectrograph_configuration import IncidentLightAngleBud
|
|
43
|
+
from dkist_processing_visp.parsers.spectrograph_configuration import ReflectedLightAngleBud
|
|
38
44
|
from dkist_processing_visp.parsers.time import DarkReadoutExpTimePickyBud
|
|
39
45
|
from dkist_processing_visp.parsers.time import NonDarkNonPolcalTaskReadoutExpTimesBud
|
|
40
46
|
from dkist_processing_visp.parsers.visp_l0_fits_access import VispL0FitsAccess
|
|
@@ -264,7 +270,9 @@ class SaveSolarCal(SaveTaskTags):
|
|
|
264
270
|
@property
|
|
265
271
|
def tag_lists_to_save(self) -> list[list[str]]:
|
|
266
272
|
return super().tag_lists_to_save + [
|
|
267
|
-
[VispTag.quality("TASK_TYPES"), VispTag.workflow_task("SolarCalibration")]
|
|
273
|
+
[VispTag.quality("TASK_TYPES"), VispTag.workflow_task("SolarCalibration")],
|
|
274
|
+
[VispTag.quality(VispMetricCode.solar_first_vignette)],
|
|
275
|
+
[VispTag.quality(VispMetricCode.solar_final_vignette)],
|
|
268
276
|
]
|
|
269
277
|
|
|
270
278
|
@property
|
|
@@ -416,11 +424,27 @@ class ParseCalOnlyL0InputData(ParseL0InputDataBase):
|
|
|
416
424
|
@property
|
|
417
425
|
def constant_buds(self):
|
|
418
426
|
"""Add ViSP specific constants to common constants."""
|
|
427
|
+
# TODO: Subclass ViSP parse task and *remove* unneeded things from this list
|
|
419
428
|
return super().constant_buds + [
|
|
429
|
+
UniqueBud(constant_name=VispBudName.arm_id.value, metadata_key=VispMetadataKey.arm_id),
|
|
420
430
|
NumCSStepBud(self.parameters.max_cs_step_time_sec),
|
|
421
431
|
NonDarkNonPolcalTaskReadoutExpTimesBud(),
|
|
422
432
|
DarkReadoutExpTimePickyBud(),
|
|
423
433
|
RetarderNameBud(),
|
|
434
|
+
IncidentLightAngleBud(),
|
|
435
|
+
ReflectedLightAngleBud(),
|
|
436
|
+
TaskUniqueBud(
|
|
437
|
+
constant_name=VispBudName.grating_constant_inverse_mm.value,
|
|
438
|
+
metadata_key=VispMetadataKey.grating_constant_inverse_mm,
|
|
439
|
+
ip_task_types=[TaskName.observe.value, TaskName.solar_gain.value],
|
|
440
|
+
task_type_parsing_function=parse_header_ip_task_with_gains,
|
|
441
|
+
),
|
|
442
|
+
TaskUniqueBud(
|
|
443
|
+
constant_name=VispBudName.solar_gain_ip_start_time.value,
|
|
444
|
+
metadata_key=MetadataKey.ip_start_time,
|
|
445
|
+
ip_task_types=TaskName.solar_gain,
|
|
446
|
+
task_type_parsing_function=parse_header_ip_task_with_gains,
|
|
447
|
+
),
|
|
424
448
|
TaskExposureTimesBud(
|
|
425
449
|
stem_name=VispBudName.lamp_exposure_times.value,
|
|
426
450
|
ip_task_types=TaskName.lamp_gain.value,
|
|
@@ -1,27 +1,65 @@
|
|
|
1
|
+
from typing import Generator
|
|
1
2
|
from unittest.mock import MagicMock
|
|
2
3
|
|
|
4
|
+
import numpy as np
|
|
3
5
|
import pytest
|
|
6
|
+
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
7
|
+
from dkist_processing_common.codecs.asdf import asdf_encoder
|
|
8
|
+
from dkist_processing_common.codecs.quality import quality_data_decoder
|
|
4
9
|
|
|
10
|
+
from dkist_processing_visp.models.metric_code import VispMetricCode
|
|
11
|
+
from dkist_processing_visp.models.tags import VispTag
|
|
5
12
|
from dkist_processing_visp.tasks.l1_output_data import VispAssembleQualityData
|
|
6
13
|
|
|
7
14
|
|
|
8
15
|
@pytest.fixture
|
|
9
|
-
def visp_assemble_quality_data_task(
|
|
16
|
+
def visp_assemble_quality_data_task(
|
|
17
|
+
tmp_path, recipe_run_id
|
|
18
|
+
) -> Generator[VispAssembleQualityData, None, None]:
|
|
10
19
|
|
|
11
20
|
with VispAssembleQualityData(
|
|
12
21
|
recipe_run_id=recipe_run_id, workflow_name="visp_assemble_quality", workflow_version="VX.Y"
|
|
13
22
|
) as task:
|
|
23
|
+
task.scratch = WorkflowFileSystem(scratch_base_path=tmp_path, recipe_run_id=recipe_run_id)
|
|
14
24
|
yield task
|
|
15
25
|
task._purge()
|
|
16
26
|
|
|
17
27
|
|
|
28
|
+
def write_raw_vignette_metrics_to_task(task):
|
|
29
|
+
for beam in [1, 2]:
|
|
30
|
+
dummy_vec = np.arange(10)
|
|
31
|
+
first_vignette_quality_outputs = {
|
|
32
|
+
"output_wave_vec": dummy_vec,
|
|
33
|
+
"input_spectrum": dummy_vec,
|
|
34
|
+
"best_fit_atlas": dummy_vec,
|
|
35
|
+
"best_fit_continuum": dummy_vec,
|
|
36
|
+
"residuals": dummy_vec,
|
|
37
|
+
}
|
|
38
|
+
task.write(
|
|
39
|
+
data=first_vignette_quality_outputs,
|
|
40
|
+
tags=[VispTag.quality(VispMetricCode.solar_first_vignette), VispTag.beam(beam)],
|
|
41
|
+
encoder=asdf_encoder,
|
|
42
|
+
)
|
|
43
|
+
final_correction_quality_outputs = {
|
|
44
|
+
"output_wave_vec": dummy_vec,
|
|
45
|
+
"median_spec": dummy_vec,
|
|
46
|
+
"low_deviation": dummy_vec,
|
|
47
|
+
"high_deviation": dummy_vec,
|
|
48
|
+
}
|
|
49
|
+
task.write(
|
|
50
|
+
data=final_correction_quality_outputs,
|
|
51
|
+
tags=[VispTag.quality(VispMetricCode.solar_final_vignette), VispTag.beam(beam)],
|
|
52
|
+
encoder=asdf_encoder,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
18
56
|
@pytest.fixture
|
|
19
57
|
def dummy_quality_data() -> list[dict]:
|
|
20
58
|
return [{"dummy_key": "dummy_value"}]
|
|
21
59
|
|
|
22
60
|
|
|
23
61
|
@pytest.fixture
|
|
24
|
-
def
|
|
62
|
+
def common_quality_assemble_data_mock(mocker, dummy_quality_data) -> MagicMock:
|
|
25
63
|
yield mocker.patch(
|
|
26
64
|
"dkist_processing_common.tasks.mixin.quality.QualityMixin.quality_assemble_data",
|
|
27
65
|
return_value=dummy_quality_data,
|
|
@@ -29,13 +67,60 @@ def quality_assemble_data_mock(mocker, dummy_quality_data) -> MagicMock:
|
|
|
29
67
|
)
|
|
30
68
|
|
|
31
69
|
|
|
32
|
-
def
|
|
70
|
+
def test_vignette_metrics_built(visp_assemble_quality_data_task):
|
|
71
|
+
"""
|
|
72
|
+
Given: A `VispAssembleQualityData` task with raw vignette metrics in scratch
|
|
73
|
+
When: Building the quality report data
|
|
74
|
+
Then: The vignette metrics are included in the data
|
|
75
|
+
"""
|
|
76
|
+
task = visp_assemble_quality_data_task
|
|
77
|
+
write_raw_vignette_metrics_to_task(task)
|
|
78
|
+
|
|
79
|
+
task()
|
|
80
|
+
|
|
81
|
+
final_report_list = list(task.read(tags=VispTag.quality_data(), decoder=quality_data_decoder))
|
|
82
|
+
assert len(final_report_list) == 1
|
|
83
|
+
final_report = final_report_list[0]
|
|
84
|
+
|
|
85
|
+
initial_vignette_metrics = list(
|
|
86
|
+
filter(lambda i: i["name"].startswith("Initial Vignette Estimation"), final_report)
|
|
87
|
+
)
|
|
88
|
+
assert len(initial_vignette_metrics) == 2
|
|
89
|
+
facet_set = set()
|
|
90
|
+
for m in initial_vignette_metrics:
|
|
91
|
+
assert m["metric_code"] == VispMetricCode.solar_first_vignette.value
|
|
92
|
+
assert m["description"]
|
|
93
|
+
assert m["multi_plot_data"]
|
|
94
|
+
facet_set.add(m["facet"])
|
|
95
|
+
|
|
96
|
+
assert facet_set == {"BEAM_1", "BEAM_2"}
|
|
97
|
+
|
|
98
|
+
final_vignette_metrics = list(
|
|
99
|
+
filter(lambda i: i["name"].startswith("Final Vignette Estimation"), final_report)
|
|
100
|
+
)
|
|
101
|
+
assert len(final_vignette_metrics) == 2
|
|
102
|
+
facet_set = set()
|
|
103
|
+
for m in final_vignette_metrics:
|
|
104
|
+
assert m["metric_code"] == VispMetricCode.solar_final_vignette.value
|
|
105
|
+
assert m["description"]
|
|
106
|
+
assert m["multi_plot_data"]
|
|
107
|
+
facet_set.add(m["facet"])
|
|
108
|
+
|
|
109
|
+
assert facet_set == {"BEAM_1", "BEAM_2"}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_correct_polcal_label_list(
|
|
113
|
+
visp_assemble_quality_data_task, common_quality_assemble_data_mock
|
|
114
|
+
):
|
|
33
115
|
"""
|
|
34
116
|
Given: A VispAssembleQualityData task
|
|
35
117
|
When: Calling the task
|
|
36
118
|
Then: The correct polcal_label_list property is passed to .quality_assemble_data
|
|
37
119
|
"""
|
|
38
120
|
task = visp_assemble_quality_data_task
|
|
121
|
+
write_raw_vignette_metrics_to_task(task)
|
|
39
122
|
|
|
40
123
|
task()
|
|
41
|
-
|
|
124
|
+
common_quality_assemble_data_mock.assert_called_once_with(
|
|
125
|
+
task, polcal_label_list=["Beam 1", "Beam 2"]
|
|
126
|
+
)
|