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
|
@@ -358,3 +358,43 @@ def test_basic_corrections(geometric_calibration_task, assign_input_dataset_doc_
|
|
|
358
358
|
lamp_array = task.basic_corrected_lamp_data(beam=beam, modstate=modstate)
|
|
359
359
|
np.testing.assert_equal(expected, solar_array)
|
|
360
360
|
np.testing.assert_equal(expected, lamp_array)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def test_line_zones(geometric_calibration_task):
|
|
364
|
+
"""
|
|
365
|
+
Given: A spectrum with some absorption lines
|
|
366
|
+
When: Computing zones around the lines
|
|
367
|
+
Then: Correct results are returned
|
|
368
|
+
"""
|
|
369
|
+
|
|
370
|
+
# NOTE that it does not test for removal of overlapping regions
|
|
371
|
+
def gaussian(x, amp, mu, sig):
|
|
372
|
+
return amp * np.exp(-np.power(x - mu, 2.0) / (2 * np.power(sig, 2.0)))
|
|
373
|
+
|
|
374
|
+
spec = np.ones(1000) * 100
|
|
375
|
+
x = np.arange(1000.0)
|
|
376
|
+
expected = []
|
|
377
|
+
for m, s in zip([100.0, 300.0, 700], [10.0, 20.0, 5.0]):
|
|
378
|
+
spec -= gaussian(x, 40, m, s)
|
|
379
|
+
hwhm = s * 2.355 / 2
|
|
380
|
+
expected.append((np.floor(m - hwhm).astype(int), np.ceil(m + hwhm).astype(int)))
|
|
381
|
+
|
|
382
|
+
task = geometric_calibration_task[0]
|
|
383
|
+
|
|
384
|
+
zones = task.compute_line_zones(spec[:, None], bg_order=0, rel_height=0.5)
|
|
385
|
+
assert zones == expected
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def test_identify_overlapping_zones(geometric_calibration_task):
|
|
389
|
+
"""
|
|
390
|
+
Given: A list of zone borders that contain overlapping zones
|
|
391
|
+
When: Identifying zones that overlap
|
|
392
|
+
Then: The smaller of the overlapping zones are identified for removal
|
|
393
|
+
"""
|
|
394
|
+
rips = np.array([100, 110, 220, 200])
|
|
395
|
+
lips = np.array([150, 120, 230, 250])
|
|
396
|
+
|
|
397
|
+
task = geometric_calibration_task[0]
|
|
398
|
+
|
|
399
|
+
idx_to_remove = task.identify_overlapping_zones(rips, lips)
|
|
400
|
+
assert idx_to_remove == [1, 2]
|
|
@@ -255,7 +255,8 @@ def test_instrument_polarization_calibration_task(
|
|
|
255
255
|
task=task, num_modstates=num_modstates, data_shape=intermediate_shape
|
|
256
256
|
)
|
|
257
257
|
write_dummy_intermediate_solar_cals_to_task(
|
|
258
|
-
task=task,
|
|
258
|
+
task=task,
|
|
259
|
+
data_shape=intermediate_shape,
|
|
259
260
|
)
|
|
260
261
|
write_input_polcals_to_task(
|
|
261
262
|
task=task,
|
|
@@ -23,9 +23,10 @@ def make_lamp_array_data(
|
|
|
23
23
|
frame: VispHeadersInputLampGainFrames, dark_signal: float, beam_border: int
|
|
24
24
|
):
|
|
25
25
|
num_raw_frames_per_fpa = frame.header()["CAM__014"]
|
|
26
|
+
modstate = frame.current_modstate("") # Weird signature due to @key_function
|
|
26
27
|
data = np.zeros(frame.array_shape)
|
|
27
|
-
data[0, :beam_border, :] = (1.1 + dark_signal) * num_raw_frames_per_fpa
|
|
28
|
-
data[0, beam_border:, :] = (
|
|
28
|
+
data[0, :beam_border, :] = (1.0 + 0.1 * modstate + dark_signal) * num_raw_frames_per_fpa
|
|
29
|
+
data[0, beam_border:, :] = (2.0 + 0.1 * modstate + dark_signal) * num_raw_frames_per_fpa
|
|
29
30
|
|
|
30
31
|
return data
|
|
31
32
|
|
|
@@ -132,27 +133,21 @@ def test_lamp_calibration_task(
|
|
|
132
133
|
VispTag.task_lamp_gain(),
|
|
133
134
|
VispTag.intermediate(),
|
|
134
135
|
]
|
|
135
|
-
assert len(list(task.read(tags=tags))) ==
|
|
136
|
-
|
|
137
|
-
for i in range(num_modstates):
|
|
138
|
-
for beam in [1, 2]:
|
|
139
|
-
tags = [
|
|
140
|
-
VispTag.task_lamp_gain(),
|
|
141
|
-
VispTag.intermediate(),
|
|
142
|
-
VispTag.modstate(i + 1),
|
|
143
|
-
VispTag.beam(beam),
|
|
144
|
-
]
|
|
145
|
-
files = list(task.read(tags=tags))
|
|
146
|
-
assert len(files) == 1
|
|
147
|
-
hdu = fits.open(files[0])[0]
|
|
148
|
-
np.testing.assert_allclose(hdu.data, np.ones((10, 10)) * (1 + (0.1 * beam)))
|
|
136
|
+
assert len(list(task.read(tags=tags))) == 2 # One per beam
|
|
149
137
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
138
|
+
for beam in [1, 2]:
|
|
139
|
+
tags = [
|
|
140
|
+
VispTag.task_lamp_gain(),
|
|
141
|
+
VispTag.intermediate(),
|
|
142
|
+
VispTag.beam(beam),
|
|
143
|
+
]
|
|
144
|
+
files = list(task.read(tags=tags))
|
|
145
|
+
assert len(files) == 1
|
|
146
|
+
|
|
147
|
+
expected_signal = beam + np.mean(np.arange(1, num_modstates + 1)) * 0.1
|
|
148
|
+
|
|
149
|
+
hdu = fits.open(files[0])[0]
|
|
150
|
+
np.testing.assert_allclose(hdu.data, np.ones(intermediate_shape) * expected_signal)
|
|
156
151
|
|
|
157
152
|
quality_files = task.read(tags=[Tag.quality("TASK_TYPES")])
|
|
158
153
|
for file in quality_files:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from dataclasses import asdict
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
|
+
import astropy.units as u
|
|
4
5
|
import numpy as np
|
|
5
6
|
import pytest
|
|
6
7
|
from hypothesis import HealthCheck
|
|
@@ -8,6 +9,7 @@ from hypothesis import example
|
|
|
8
9
|
from hypothesis import given
|
|
9
10
|
from hypothesis import settings
|
|
10
11
|
from hypothesis import strategies as st
|
|
12
|
+
from pydantic import BaseModel
|
|
11
13
|
|
|
12
14
|
from dkist_processing_visp.models.parameters import VispParameters
|
|
13
15
|
from dkist_processing_visp.models.parameters import VispParsingParameters
|
|
@@ -15,10 +17,27 @@ from dkist_processing_visp.tasks.visp_base import VispTaskBase
|
|
|
15
17
|
from dkist_processing_visp.tests.conftest import VispConstantsDb
|
|
16
18
|
from dkist_processing_visp.tests.conftest import VispInputDatasetParameterValues
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
@pytest.fixture(scope="session")
|
|
22
|
+
def parse_parameter_names() -> list[str]:
|
|
23
|
+
# The property names of all parameters on `VispParsingParameters`
|
|
24
|
+
return [k for k, v in vars(VispParsingParameters).items() if isinstance(v, property)]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture(scope="session")
|
|
28
|
+
def arm_parameter_names() -> list[str]:
|
|
29
|
+
return [
|
|
30
|
+
"wavecal_camera_lens_parameters",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture(scope="session")
|
|
35
|
+
def unit_parameter_names_and_units() -> dict[str, u.Unit | list[u.Unit]]:
|
|
36
|
+
return {
|
|
37
|
+
"solar_vignette_crval_bounds_px": u.pix,
|
|
38
|
+
"wavecal_camera_lens_parameters": [u.m, u.m / u.nm, u.m / u.nm**2],
|
|
39
|
+
"wavecal_pixel_pitch_micron_per_pix": u.um / u.pix,
|
|
40
|
+
}
|
|
22
41
|
|
|
23
42
|
|
|
24
43
|
@pytest.fixture(scope="function")
|
|
@@ -27,6 +46,7 @@ def basic_science_task_with_parameter_mixin(
|
|
|
27
46
|
assign_input_dataset_doc_to_task,
|
|
28
47
|
init_visp_constants_db,
|
|
29
48
|
testing_obs_ip_start_time,
|
|
49
|
+
arm_id,
|
|
30
50
|
):
|
|
31
51
|
def make_task(
|
|
32
52
|
parameters_part: dataclass,
|
|
@@ -48,8 +68,9 @@ def basic_science_task_with_parameter_mixin(
|
|
|
48
68
|
parameters_part,
|
|
49
69
|
parameter_class=parameter_class,
|
|
50
70
|
obs_ip_start_time=obs_ip_start_time,
|
|
71
|
+
arm_id=arm_id,
|
|
51
72
|
)
|
|
52
|
-
yield task, parameters_part
|
|
73
|
+
yield task, asdict(parameters_part)
|
|
53
74
|
except:
|
|
54
75
|
raise
|
|
55
76
|
finally:
|
|
@@ -58,7 +79,14 @@ def basic_science_task_with_parameter_mixin(
|
|
|
58
79
|
return make_task
|
|
59
80
|
|
|
60
81
|
|
|
61
|
-
|
|
82
|
+
@pytest.mark.parametrize("arm_id", [pytest.param("1"), pytest.param("2"), pytest.param("3")])
|
|
83
|
+
def test_non_wave_parameters(
|
|
84
|
+
basic_science_task_with_parameter_mixin,
|
|
85
|
+
parse_parameter_names,
|
|
86
|
+
arm_parameter_names,
|
|
87
|
+
unit_parameter_names_and_units,
|
|
88
|
+
arm_id,
|
|
89
|
+
):
|
|
62
90
|
"""
|
|
63
91
|
Given: A Science task with the parameter mixin
|
|
64
92
|
When: Accessing properties for parameters that do not depend on wavelength
|
|
@@ -68,15 +96,41 @@ def test_non_wave_parameters(basic_science_task_with_parameter_mixin):
|
|
|
68
96
|
basic_science_task_with_parameter_mixin(VispInputDatasetParameterValues())
|
|
69
97
|
)
|
|
70
98
|
task_param_attr = task.parameters
|
|
71
|
-
for
|
|
72
|
-
|
|
99
|
+
parameter_properties = [k for k, v in vars(VispParameters).items() if isinstance(v, property)]
|
|
100
|
+
for parameter_name in parameter_properties:
|
|
101
|
+
pn = f"visp_{parameter_name}"
|
|
102
|
+
if parameter_name in arm_parameter_names:
|
|
103
|
+
pn = f"{pn}_{arm_id}"
|
|
104
|
+
pv = expected[pn]
|
|
105
|
+
is_wavelength_param = isinstance(pv, dict) and "wavelength" in pv
|
|
73
106
|
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
parameter_name not in parse_parameter_names
|
|
108
|
+
and not is_wavelength_param
|
|
109
|
+
and parameter_name != "solar_vignette_wavecal_fit_kwargs"
|
|
110
|
+
):
|
|
111
|
+
param_obj_value = getattr(task_param_attr, parameter_name)
|
|
112
|
+
if isinstance(pv, tuple):
|
|
113
|
+
pv = list(pv)
|
|
114
|
+
|
|
115
|
+
if parameter_name in unit_parameter_names_and_units:
|
|
116
|
+
expected_units = unit_parameter_names_and_units[parameter_name]
|
|
117
|
+
if not isinstance(param_obj_value, list):
|
|
118
|
+
param_obj_value = [param_obj_value]
|
|
119
|
+
pv = [pv]
|
|
120
|
+
expected_units = [expected_units]
|
|
77
121
|
|
|
122
|
+
assert all([param_obj_value[i].value == pv[i] for i in range(len(pv))])
|
|
123
|
+
assert all(
|
|
124
|
+
[param_obj_value[i].unit == expected_units[i] for i in range(len(pv))]
|
|
125
|
+
), f"Units {[v.unit for v in param_obj_value]} does not match expected {expected_units}"
|
|
126
|
+
elif isinstance(param_obj_value, BaseModel):
|
|
127
|
+
assert param_obj_value.model_dump() == pv
|
|
128
|
+
else:
|
|
129
|
+
assert getattr(task_param_attr, parameter_name) == pv
|
|
78
130
|
|
|
79
|
-
|
|
131
|
+
|
|
132
|
+
@pytest.mark.parametrize("arm_id", ["1"])
|
|
133
|
+
def test_parse_parameters(basic_science_task_with_parameter_mixin, parse_parameter_names):
|
|
80
134
|
"""
|
|
81
135
|
Given: A Science task with Parsing parameters
|
|
82
136
|
When: Accessing properties for Parse parameters
|
|
@@ -90,16 +144,19 @@ def test_parse_parameters(basic_science_task_with_parameter_mixin):
|
|
|
90
144
|
)
|
|
91
145
|
)
|
|
92
146
|
task_param_attr = task.parameters
|
|
93
|
-
for pn, pv in
|
|
147
|
+
for pn, pv in expected.items():
|
|
94
148
|
property_name = pn.removeprefix("visp_")
|
|
95
|
-
if property_name in
|
|
149
|
+
if property_name in parse_parameter_names and type(pv) is not dict:
|
|
96
150
|
assert getattr(task_param_attr, property_name) == pv
|
|
97
151
|
|
|
98
152
|
|
|
99
153
|
@given(wave=st.floats(min_value=500.0, max_value=2000.0))
|
|
100
154
|
@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
|
|
101
155
|
@example(wave=492.5)
|
|
102
|
-
|
|
156
|
+
@pytest.mark.parametrize("arm_id", ["1"])
|
|
157
|
+
def test_wave_parameters(
|
|
158
|
+
basic_science_task_with_parameter_mixin, parse_parameter_names, arm_parameter_names, wave
|
|
159
|
+
):
|
|
103
160
|
"""
|
|
104
161
|
Given: A Science task with the paramter mixin
|
|
105
162
|
When: Accessing properties for parameters that depend on wavelength
|
|
@@ -110,10 +167,55 @@ def test_wave_parameters(basic_science_task_with_parameter_mixin, wave):
|
|
|
110
167
|
)
|
|
111
168
|
task_param_attr = task.parameters
|
|
112
169
|
task_param_attr._wavelength = wave
|
|
113
|
-
pwaves = np.array(expected
|
|
170
|
+
pwaves = np.array(expected["visp_geo_zone_normalization_percentile"]["wavelength"])
|
|
114
171
|
midpoints = 0.5 * (pwaves[1:] + pwaves[:-1])
|
|
115
172
|
idx = np.sum(midpoints < wave)
|
|
116
|
-
for pn, pv in
|
|
173
|
+
for pn, pv in expected.items():
|
|
117
174
|
property_name = pn.removeprefix("visp_")
|
|
118
|
-
|
|
175
|
+
is_wavelength_param = isinstance(pv, dict) and "wavelength" in pv
|
|
176
|
+
if is_wavelength_param and property_name not in parse_parameter_names + arm_parameter_names:
|
|
119
177
|
assert getattr(task_param_attr, property_name) == pv["values"][idx]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class AnyInt:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@pytest.mark.parametrize("arm_id", [pytest.param("1")])
|
|
185
|
+
@pytest.mark.parametrize(
|
|
186
|
+
"db_value, expected",
|
|
187
|
+
[
|
|
188
|
+
pytest.param({"method": "nelder"}, {"method": "nelder"}, id="non_rng_method"),
|
|
189
|
+
pytest.param(
|
|
190
|
+
{"method": "basinhopping"}, {"method": "basinhopping", "rng": AnyInt}, id="random_rng"
|
|
191
|
+
),
|
|
192
|
+
pytest.param(
|
|
193
|
+
{"method": "differential_evolution", "rng": 6.28},
|
|
194
|
+
{"method": "differential_evolution", "rng": 6.28},
|
|
195
|
+
id="override_rng",
|
|
196
|
+
),
|
|
197
|
+
pytest.param(dict(), dict(), id="no_kwargs"),
|
|
198
|
+
],
|
|
199
|
+
)
|
|
200
|
+
def test_fit_kwarg_parameters(
|
|
201
|
+
basic_science_task_with_parameter_mixin,
|
|
202
|
+
db_value,
|
|
203
|
+
expected,
|
|
204
|
+
):
|
|
205
|
+
"""
|
|
206
|
+
Given: A Science task with the parameter mixin
|
|
207
|
+
When: Accessing properties for parameters that do not depend on wavelength
|
|
208
|
+
Then: The correct value is returned
|
|
209
|
+
"""
|
|
210
|
+
task, _ = next(
|
|
211
|
+
basic_science_task_with_parameter_mixin(
|
|
212
|
+
VispInputDatasetParameterValues(visp_solar_vignette_wavecal_fit_kwargs=db_value)
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
kwarg_dict = task.parameters.solar_vignette_wavecal_fit_kwargs
|
|
216
|
+
assert kwarg_dict.keys() == expected.keys()
|
|
217
|
+
for k in expected.keys():
|
|
218
|
+
if expected[k] is AnyInt:
|
|
219
|
+
assert type(kwarg_dict[k]) is int
|
|
220
|
+
else:
|
|
221
|
+
assert expected[k] == kwarg_dict[k]
|
|
@@ -86,6 +86,7 @@ def write_input_dark_frames_to_task(
|
|
|
86
86
|
time_delta: float = 10.0,
|
|
87
87
|
num_modstates: int = 2,
|
|
88
88
|
data_shape: tuple[int, int] = (2, 2),
|
|
89
|
+
**kwargs,
|
|
89
90
|
):
|
|
90
91
|
array_shape = (1, *data_shape)
|
|
91
92
|
dataset = VispHeadersInputDarkFrames(
|
|
@@ -94,6 +95,7 @@ def write_input_dark_frames_to_task(
|
|
|
94
95
|
exp_time=exp_time,
|
|
95
96
|
readout_exp_time=readout_exp_time,
|
|
96
97
|
num_modstates=num_modstates,
|
|
98
|
+
**kwargs,
|
|
97
99
|
)
|
|
98
100
|
|
|
99
101
|
num_written_frames = write_frames_to_task(
|
|
@@ -109,6 +111,7 @@ def write_input_lamp_frames_to_task(
|
|
|
109
111
|
time_delta: float = 10.0,
|
|
110
112
|
num_modstates: int = 2,
|
|
111
113
|
data_shape: tuple[int, int] = (2, 2),
|
|
114
|
+
**kwargs,
|
|
112
115
|
):
|
|
113
116
|
array_shape = (1, *data_shape)
|
|
114
117
|
dataset = VispHeadersInputLampGainFrames(
|
|
@@ -117,6 +120,7 @@ def write_input_lamp_frames_to_task(
|
|
|
117
120
|
exp_time=exp_time,
|
|
118
121
|
readout_exp_time=readout_exp_time,
|
|
119
122
|
num_modstates=num_modstates,
|
|
123
|
+
**kwargs,
|
|
120
124
|
)
|
|
121
125
|
|
|
122
126
|
num_written_frames = write_frames_to_task(
|
|
@@ -132,6 +136,7 @@ def write_input_solar_frames_to_task(
|
|
|
132
136
|
time_delta: float = 10.0,
|
|
133
137
|
num_modstates: int = 2,
|
|
134
138
|
data_shape: tuple[int, int] = (2, 2),
|
|
139
|
+
**kwargs,
|
|
135
140
|
):
|
|
136
141
|
array_shape = (1, *data_shape)
|
|
137
142
|
dataset = VispHeadersInputSolarGainFrames(
|
|
@@ -140,6 +145,7 @@ def write_input_solar_frames_to_task(
|
|
|
140
145
|
exp_time=exp_time,
|
|
141
146
|
readout_exp_time=readout_exp_time,
|
|
142
147
|
num_modstates=num_modstates,
|
|
148
|
+
**kwargs,
|
|
143
149
|
)
|
|
144
150
|
|
|
145
151
|
num_written_frames = write_frames_to_task(
|
|
@@ -155,6 +161,7 @@ def write_input_polcal_frames_to_task(
|
|
|
155
161
|
time_delta: float = 30.0,
|
|
156
162
|
num_modstates: int = 2,
|
|
157
163
|
data_shape: tuple[int, int] = (2, 2),
|
|
164
|
+
**kwargs,
|
|
158
165
|
):
|
|
159
166
|
array_shape = (1, *data_shape)
|
|
160
167
|
dataset = VispHeadersInputPolcalFrames(
|
|
@@ -163,6 +170,7 @@ def write_input_polcal_frames_to_task(
|
|
|
163
170
|
exp_time=exp_time,
|
|
164
171
|
readout_exp_time=readout_exp_time,
|
|
165
172
|
num_modstates=num_modstates,
|
|
173
|
+
**kwargs,
|
|
166
174
|
)
|
|
167
175
|
|
|
168
176
|
num_written_frames = write_frames_to_task(
|
|
@@ -178,6 +186,7 @@ def write_input_polcal_dark_frames_to_task(
|
|
|
178
186
|
time_delta: float = 30.0,
|
|
179
187
|
num_modstates: int = 2,
|
|
180
188
|
data_shape: tuple[int, int] = (2, 2),
|
|
189
|
+
**kwargs,
|
|
181
190
|
):
|
|
182
191
|
array_shape = (1, *data_shape)
|
|
183
192
|
dataset = VispHeadersInputPolcalDarkFrames(
|
|
@@ -186,6 +195,7 @@ def write_input_polcal_dark_frames_to_task(
|
|
|
186
195
|
exp_time=exp_time,
|
|
187
196
|
readout_exp_time=readout_exp_time,
|
|
188
197
|
num_modstates=num_modstates,
|
|
198
|
+
**kwargs,
|
|
189
199
|
)
|
|
190
200
|
|
|
191
201
|
num_written_frames = write_frames_to_task(
|
|
@@ -201,6 +211,7 @@ def write_input_polcal_gain_frames_to_task(
|
|
|
201
211
|
time_delta: float = 30.0,
|
|
202
212
|
num_modstates: int = 2,
|
|
203
213
|
data_shape: tuple[int, int] = (2, 2),
|
|
214
|
+
**kwargs,
|
|
204
215
|
):
|
|
205
216
|
array_shape = (1, *data_shape)
|
|
206
217
|
dataset = VispHeadersInputPolcalGainFrames(
|
|
@@ -209,6 +220,7 @@ def write_input_polcal_gain_frames_to_task(
|
|
|
209
220
|
exp_time=exp_time,
|
|
210
221
|
readout_exp_time=readout_exp_time,
|
|
211
222
|
num_modstates=num_modstates,
|
|
223
|
+
**kwargs,
|
|
212
224
|
)
|
|
213
225
|
|
|
214
226
|
num_written_frames = write_frames_to_task(
|
|
@@ -227,6 +239,7 @@ def write_input_observe_frames_to_task(
|
|
|
227
239
|
time_delta: float = 10.0,
|
|
228
240
|
data_shape: tuple[int, int] = (2, 2),
|
|
229
241
|
obs_dataset_class=VispHeadersValidObserveFrames,
|
|
242
|
+
**kwargs,
|
|
230
243
|
):
|
|
231
244
|
array_shape = (1, *data_shape)
|
|
232
245
|
dataset = obs_dataset_class(
|
|
@@ -237,6 +250,7 @@ def write_input_observe_frames_to_task(
|
|
|
237
250
|
num_modstates=num_modstates,
|
|
238
251
|
exp_time=exp_time,
|
|
239
252
|
readout_exp_time=readout_exp_time,
|
|
253
|
+
**kwargs,
|
|
240
254
|
)
|
|
241
255
|
num_written_frames = write_frames_to_task(
|
|
242
256
|
task=task, frame_generator=dataset, extra_tags=[VispTag.input()]
|
|
@@ -272,6 +286,11 @@ def write_input_cal_frames_to_task(
|
|
|
272
286
|
solar_exp_time,
|
|
273
287
|
polcal_exp_time,
|
|
274
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,
|
|
275
294
|
):
|
|
276
295
|
def write_frames_to_task(task):
|
|
277
296
|
for readout_exp_time in required_dark_readout_exp_times:
|
|
@@ -280,6 +299,7 @@ def write_input_cal_frames_to_task(
|
|
|
280
299
|
readout_exp_time=readout_exp_time,
|
|
281
300
|
exp_time=dark_exp_time,
|
|
282
301
|
num_modstates=num_modstates,
|
|
302
|
+
arm_id=testing_arm_id,
|
|
283
303
|
)
|
|
284
304
|
|
|
285
305
|
write_input_lamp_frames_to_task(
|
|
@@ -287,30 +307,39 @@ def write_input_cal_frames_to_task(
|
|
|
287
307
|
readout_exp_time=lamp_readout_exp_time,
|
|
288
308
|
exp_time=lamp_exp_time,
|
|
289
309
|
num_modstates=num_modstates,
|
|
310
|
+
arm_id=testing_arm_id,
|
|
290
311
|
)
|
|
291
312
|
write_input_solar_frames_to_task(
|
|
292
313
|
task=task,
|
|
293
314
|
readout_exp_time=solar_readout_exp_time,
|
|
294
315
|
exp_time=solar_exp_time,
|
|
295
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,
|
|
296
322
|
)
|
|
297
323
|
write_input_polcal_frames_to_task(
|
|
298
324
|
task=task,
|
|
299
325
|
readout_exp_time=polcal_readout_exp_time,
|
|
300
326
|
exp_time=polcal_exp_time,
|
|
301
327
|
num_modstates=num_modstates,
|
|
328
|
+
arm_id=testing_arm_id,
|
|
302
329
|
)
|
|
303
330
|
write_input_polcal_dark_frames_to_task(
|
|
304
331
|
task=task,
|
|
305
332
|
readout_exp_time=polcal_readout_exp_time,
|
|
306
333
|
exp_time=polcal_exp_time,
|
|
307
334
|
num_modstates=num_modstates,
|
|
335
|
+
arm_id=testing_arm_id,
|
|
308
336
|
)
|
|
309
337
|
write_input_polcal_gain_frames_to_task(
|
|
310
338
|
task,
|
|
311
339
|
readout_exp_time=polcal_readout_exp_time,
|
|
312
340
|
exp_time=polcal_exp_time,
|
|
313
341
|
num_modstates=num_modstates,
|
|
342
|
+
arm_id=testing_arm_id,
|
|
314
343
|
)
|
|
315
344
|
|
|
316
345
|
return write_frames_to_task
|
|
@@ -350,6 +379,10 @@ def test_parse_visp_input_data(
|
|
|
350
379
|
num_modstates,
|
|
351
380
|
mocker,
|
|
352
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
|
|
@@ -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
|
|
@@ -404,6 +441,12 @@ def test_parse_visp_input_data_constants(
|
|
|
404
441
|
polcal_exp_time,
|
|
405
442
|
observe_exp_times,
|
|
406
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,
|
|
407
450
|
):
|
|
408
451
|
"""
|
|
409
452
|
Given: A ParseVispInputData task
|
|
@@ -426,16 +469,29 @@ def test_parse_visp_input_data_constants(
|
|
|
426
469
|
num_steps=num_steps,
|
|
427
470
|
readout_exp_time=obs_readout_exp_time,
|
|
428
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,
|
|
429
477
|
)
|
|
430
478
|
|
|
431
479
|
# When
|
|
432
480
|
task()
|
|
433
481
|
# Then
|
|
482
|
+
assert task.constants._db_dict["ARM_ID"] == testing_arm_id
|
|
434
483
|
expected_dark_readout_exp_times = [
|
|
435
484
|
lamp_readout_exp_time,
|
|
436
485
|
solar_readout_exp_time,
|
|
437
486
|
] + observe_readout_exp_times
|
|
438
|
-
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
|
|
439
495
|
assert task.constants._db_dict["NUM_MODSTATES"] == num_modstates
|
|
440
496
|
assert task.constants._db_dict["NUM_MAP_SCANS"] == num_maps_per_readout_exp_time * len(
|
|
441
497
|
observe_readout_exp_times
|
|
@@ -468,6 +524,10 @@ def test_parse_visp_values(
|
|
|
468
524
|
num_modstates,
|
|
469
525
|
mocker,
|
|
470
526
|
fake_gql_client,
|
|
527
|
+
testing_arm_id,
|
|
528
|
+
testing_grating_constant,
|
|
529
|
+
testing_grating_angle,
|
|
530
|
+
testing_arm_position,
|
|
471
531
|
):
|
|
472
532
|
"""
|
|
473
533
|
:Given: A valid parse input task
|
|
@@ -486,6 +546,10 @@ def test_parse_visp_values(
|
|
|
486
546
|
num_maps=1,
|
|
487
547
|
num_steps=1,
|
|
488
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,
|
|
489
553
|
)
|
|
490
554
|
|
|
491
555
|
task()
|
|
@@ -585,6 +649,10 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
585
649
|
observe_exp_times,
|
|
586
650
|
mocker,
|
|
587
651
|
fake_gql_client,
|
|
652
|
+
testing_arm_id,
|
|
653
|
+
testing_grating_constant,
|
|
654
|
+
testing_grating_angle,
|
|
655
|
+
testing_arm_position,
|
|
588
656
|
):
|
|
589
657
|
"""
|
|
590
658
|
:Given: Data where the observe frames are in intensity mode and the calibration frames are in polarimetric mode
|
|
@@ -604,6 +672,10 @@ def test_intensity_observes_and_polarimetric_cals(
|
|
|
604
672
|
readout_exp_time=observe_readout_exp_times[0],
|
|
605
673
|
exp_time=observe_exp_times[0],
|
|
606
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,
|
|
607
679
|
)
|
|
608
680
|
task()
|
|
609
681
|
assert task.constants._db_dict["NUM_MODSTATES"] == 1
|
|
@@ -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)}}
|
|
@@ -252,7 +252,7 @@ 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
258
|
science_calibration_task,
|
|
@@ -308,7 +308,8 @@ def test_science_calibration_task(
|
|
|
308
308
|
task=task, num_modstates=num_modstates, data_shape=intermediate_shape, offsets=offsets
|
|
309
309
|
)
|
|
310
310
|
write_dummy_intermediate_solar_cals_to_task(
|
|
311
|
-
task=task,
|
|
311
|
+
task=task,
|
|
312
|
+
data_shape=intermediate_shape,
|
|
312
313
|
)
|
|
313
314
|
write_demod_matrices_to_task(task=task, num_modstates=num_modstates)
|
|
314
315
|
write_input_observe_frames_to_task(
|
|
@@ -658,9 +659,7 @@ def test_generate_nan_mask(science_calibration_task, dummy_calibration_collectio
|
|
|
658
659
|
calibration_collection, _, _ = dummy_calibration_collection
|
|
659
660
|
beam = 1
|
|
660
661
|
modstate = 1
|
|
661
|
-
solar_gain_array = calibration_collection.solar_gain[VispTag.beam(beam)]
|
|
662
|
-
VispTag.modstate(modstate)
|
|
663
|
-
]
|
|
662
|
+
solar_gain_array = calibration_collection.solar_gain[VispTag.beam(beam)]
|
|
664
663
|
angle = calibration_collection.angle[VispTag.beam(beam)]
|
|
665
664
|
spec_shift = calibration_collection.spec_shift[VispTag.beam(beam)]
|
|
666
665
|
state_offset = calibration_collection.state_offset[VispTag.beam(beam)][
|