dkist-processing-cryonirsp 1.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dkist-processing-cryonirsp might be problematic. Click here for more details.
- changelog/.gitempty +0 -0
- dkist_processing_cryonirsp/__init__.py +11 -0
- dkist_processing_cryonirsp/config.py +12 -0
- dkist_processing_cryonirsp/models/__init__.py +1 -0
- dkist_processing_cryonirsp/models/constants.py +248 -0
- dkist_processing_cryonirsp/models/exposure_conditions.py +26 -0
- dkist_processing_cryonirsp/models/parameters.py +296 -0
- dkist_processing_cryonirsp/models/tags.py +168 -0
- dkist_processing_cryonirsp/models/task_name.py +14 -0
- dkist_processing_cryonirsp/parsers/__init__.py +1 -0
- dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +111 -0
- dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +30 -0
- dkist_processing_cryonirsp/parsers/exposure_conditions.py +163 -0
- dkist_processing_cryonirsp/parsers/map_repeats.py +40 -0
- dkist_processing_cryonirsp/parsers/measurements.py +55 -0
- dkist_processing_cryonirsp/parsers/modstates.py +31 -0
- dkist_processing_cryonirsp/parsers/optical_density_filters.py +40 -0
- dkist_processing_cryonirsp/parsers/polarimetric_check.py +120 -0
- dkist_processing_cryonirsp/parsers/scan_step.py +412 -0
- dkist_processing_cryonirsp/parsers/time.py +80 -0
- dkist_processing_cryonirsp/parsers/wavelength.py +26 -0
- dkist_processing_cryonirsp/tasks/__init__.py +19 -0
- dkist_processing_cryonirsp/tasks/assemble_movie.py +202 -0
- dkist_processing_cryonirsp/tasks/bad_pixel_map.py +96 -0
- dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +279 -0
- dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +55 -0
- dkist_processing_cryonirsp/tasks/ci_science.py +169 -0
- dkist_processing_cryonirsp/tasks/cryonirsp_base.py +67 -0
- dkist_processing_cryonirsp/tasks/dark.py +98 -0
- dkist_processing_cryonirsp/tasks/gain.py +251 -0
- dkist_processing_cryonirsp/tasks/instrument_polarization.py +447 -0
- dkist_processing_cryonirsp/tasks/l1_output_data.py +44 -0
- dkist_processing_cryonirsp/tasks/linearity_correction.py +582 -0
- dkist_processing_cryonirsp/tasks/make_movie_frames.py +302 -0
- dkist_processing_cryonirsp/tasks/mixin/__init__.py +1 -0
- dkist_processing_cryonirsp/tasks/mixin/beam_access.py +52 -0
- dkist_processing_cryonirsp/tasks/mixin/corrections.py +177 -0
- dkist_processing_cryonirsp/tasks/mixin/intermediate_frame.py +193 -0
- dkist_processing_cryonirsp/tasks/mixin/linearized_frame.py +309 -0
- dkist_processing_cryonirsp/tasks/mixin/shift_measurements.py +297 -0
- dkist_processing_cryonirsp/tasks/parse.py +281 -0
- dkist_processing_cryonirsp/tasks/quality_metrics.py +271 -0
- dkist_processing_cryonirsp/tasks/science_base.py +511 -0
- dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +270 -0
- dkist_processing_cryonirsp/tasks/sp_dispersion_axis_correction.py +484 -0
- dkist_processing_cryonirsp/tasks/sp_geometric.py +585 -0
- dkist_processing_cryonirsp/tasks/sp_science.py +299 -0
- dkist_processing_cryonirsp/tasks/sp_solar_gain.py +475 -0
- dkist_processing_cryonirsp/tasks/trial_output_data.py +61 -0
- dkist_processing_cryonirsp/tasks/write_l1.py +1033 -0
- dkist_processing_cryonirsp/tests/__init__.py +1 -0
- dkist_processing_cryonirsp/tests/conftest.py +456 -0
- dkist_processing_cryonirsp/tests/header_models.py +592 -0
- dkist_processing_cryonirsp/tests/local_trial_workflows/__init__.py +0 -0
- dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +541 -0
- dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +615 -0
- dkist_processing_cryonirsp/tests/local_trial_workflows/linearize_only.py +96 -0
- dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +592 -0
- dkist_processing_cryonirsp/tests/test_assemble_movie.py +144 -0
- dkist_processing_cryonirsp/tests/test_assemble_qualilty.py +517 -0
- dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +115 -0
- dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +106 -0
- dkist_processing_cryonirsp/tests/test_ci_science.py +355 -0
- dkist_processing_cryonirsp/tests/test_corrections.py +126 -0
- dkist_processing_cryonirsp/tests/test_cryo_base.py +202 -0
- dkist_processing_cryonirsp/tests/test_cryo_constants.py +76 -0
- dkist_processing_cryonirsp/tests/test_dark.py +287 -0
- dkist_processing_cryonirsp/tests/test_gain.py +278 -0
- dkist_processing_cryonirsp/tests/test_instrument_polarization.py +531 -0
- dkist_processing_cryonirsp/tests/test_linearity_correction.py +245 -0
- dkist_processing_cryonirsp/tests/test_make_movie_frames.py +111 -0
- dkist_processing_cryonirsp/tests/test_parameters.py +266 -0
- dkist_processing_cryonirsp/tests/test_parse.py +1439 -0
- dkist_processing_cryonirsp/tests/test_quality.py +203 -0
- dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +112 -0
- dkist_processing_cryonirsp/tests/test_sp_dispersion_axis_correction.py +155 -0
- dkist_processing_cryonirsp/tests/test_sp_geometric.py +319 -0
- dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +121 -0
- dkist_processing_cryonirsp/tests/test_sp_science.py +483 -0
- dkist_processing_cryonirsp/tests/test_sp_solar.py +198 -0
- dkist_processing_cryonirsp/tests/test_trial_create_quality_report.py +79 -0
- dkist_processing_cryonirsp/tests/test_trial_output_data.py +251 -0
- dkist_processing_cryonirsp/tests/test_workflows.py +9 -0
- dkist_processing_cryonirsp/tests/test_write_l1.py +436 -0
- dkist_processing_cryonirsp/workflows/__init__.py +2 -0
- dkist_processing_cryonirsp/workflows/ci_l0_processing.py +77 -0
- dkist_processing_cryonirsp/workflows/sp_l0_processing.py +84 -0
- dkist_processing_cryonirsp/workflows/trial_workflows.py +190 -0
- dkist_processing_cryonirsp-1.3.4.dist-info/METADATA +194 -0
- dkist_processing_cryonirsp-1.3.4.dist-info/RECORD +111 -0
- dkist_processing_cryonirsp-1.3.4.dist-info/WHEEL +5 -0
- dkist_processing_cryonirsp-1.3.4.dist-info/top_level.txt +4 -0
- docs/Makefile +134 -0
- docs/bad_pixel_calibration.rst +47 -0
- docs/beam_angle_calculation.rst +53 -0
- docs/beam_boundary_computation.rst +88 -0
- docs/changelog.rst +7 -0
- docs/ci_science_calibration.rst +33 -0
- docs/conf.py +52 -0
- docs/index.rst +21 -0
- docs/l0_to_l1_cryonirsp_ci-full-trial.rst +10 -0
- docs/l0_to_l1_cryonirsp_ci.rst +10 -0
- docs/l0_to_l1_cryonirsp_sp-full-trial.rst +10 -0
- docs/l0_to_l1_cryonirsp_sp.rst +10 -0
- docs/linearization.rst +43 -0
- docs/make.bat +170 -0
- docs/requirements.txt +1 -0
- docs/requirements_table.rst +8 -0
- docs/scientific_changelog.rst +10 -0
- docs/sp_science_calibration.rst +59 -0
- licenses/LICENSE.rst +11 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""Cryo SP science calibration task."""
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from astropy.io import fits
|
|
6
|
+
from dkist_processing_math.statistics import average_numpy_arrays
|
|
7
|
+
from dkist_service_configuration.logging import logger
|
|
8
|
+
|
|
9
|
+
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
10
|
+
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
11
|
+
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import CryonirspL0FitsAccess
|
|
12
|
+
from dkist_processing_cryonirsp.tasks.science_base import CalibrationCollection
|
|
13
|
+
from dkist_processing_cryonirsp.tasks.science_base import ScienceCalibrationBase
|
|
14
|
+
|
|
15
|
+
__all__ = ["SPScienceCalibration"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SPScienceCalibration(ScienceCalibrationBase):
|
|
19
|
+
"""Task class for SP Cryo science calibration of polarized and non-polarized data."""
|
|
20
|
+
|
|
21
|
+
def calibrate_and_write_frames(self, calibrations: CalibrationCollection):
|
|
22
|
+
"""
|
|
23
|
+
Top-level method to collect frame groupings (map_scan, scan_step, etc.) and send them to be calibrated.
|
|
24
|
+
|
|
25
|
+
Then write the calibrated arrays.
|
|
26
|
+
|
|
27
|
+
This is also where the polarimetric/non-polarimetric split is made.
|
|
28
|
+
"""
|
|
29
|
+
for exposure_conditions in self.constants.observe_exposure_conditions_list:
|
|
30
|
+
for map_scan in range(1, self.constants.num_map_scans + 1):
|
|
31
|
+
for scan_step in range(1, self.constants.num_scan_steps + 1):
|
|
32
|
+
for meas_num in range(1, self.constants.num_meas + 1):
|
|
33
|
+
if self.constants.correct_for_polarization:
|
|
34
|
+
calibrated_object = self.calibrate_polarimetric_beams(
|
|
35
|
+
exposure_conditions=exposure_conditions,
|
|
36
|
+
map_scan=map_scan,
|
|
37
|
+
scan_step=scan_step,
|
|
38
|
+
meas_num=meas_num,
|
|
39
|
+
calibrations=calibrations,
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
calibrated_object = self.calibrate_intensity_only_beams(
|
|
43
|
+
exposure_conditions=exposure_conditions,
|
|
44
|
+
map_scan=map_scan,
|
|
45
|
+
scan_step=scan_step,
|
|
46
|
+
meas_num=meas_num,
|
|
47
|
+
calibrations=calibrations,
|
|
48
|
+
)
|
|
49
|
+
logging_str = f"{exposure_conditions = }, {map_scan = }, {scan_step = } and {meas_num = }"
|
|
50
|
+
logger.info(f"Writing calibrated array for {logging_str}")
|
|
51
|
+
self.write_calibrated_object(
|
|
52
|
+
calibrated_object,
|
|
53
|
+
map_scan=map_scan,
|
|
54
|
+
scan_step=scan_step,
|
|
55
|
+
meas_num=meas_num,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def calibrate_polarimetric_beams(
|
|
59
|
+
self,
|
|
60
|
+
*,
|
|
61
|
+
exposure_conditions: ExposureConditions,
|
|
62
|
+
map_scan: int,
|
|
63
|
+
scan_step: int,
|
|
64
|
+
meas_num: int,
|
|
65
|
+
calibrations: CalibrationCollection,
|
|
66
|
+
) -> CryonirspL0FitsAccess:
|
|
67
|
+
"""
|
|
68
|
+
Completely calibrate polarimetric science frames.
|
|
69
|
+
|
|
70
|
+
- Apply dark and gain corrections
|
|
71
|
+
- Demodulate
|
|
72
|
+
- Apply geometric correction
|
|
73
|
+
- Apply telescope correction
|
|
74
|
+
- Combine beams
|
|
75
|
+
"""
|
|
76
|
+
beam_storage = dict()
|
|
77
|
+
header_storage = dict()
|
|
78
|
+
logging_str = f"{exposure_conditions = }, {map_scan = }, {scan_step = }, {meas_num = }"
|
|
79
|
+
for beam in range(1, self.constants.num_beams + 1):
|
|
80
|
+
logger.info(f"Processing polarimetric observe frames from {logging_str} and {beam = }")
|
|
81
|
+
intermediate_array, intermediate_header = self.correct_and_demodulate(
|
|
82
|
+
beam=beam,
|
|
83
|
+
meas_num=meas_num,
|
|
84
|
+
scan_step=scan_step,
|
|
85
|
+
map_scan=map_scan,
|
|
86
|
+
exposure_conditions=exposure_conditions,
|
|
87
|
+
calibrations=calibrations,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
geo_corrected_array = self.apply_geometric_correction(
|
|
91
|
+
array=intermediate_array, beam=beam, calibrations=calibrations
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
beam_storage[CryonirspTag.beam(beam)] = geo_corrected_array
|
|
95
|
+
header_storage[CryonirspTag.beam(beam)] = intermediate_header
|
|
96
|
+
|
|
97
|
+
logger.info(f"Combining beams for {logging_str}")
|
|
98
|
+
combined = self.combine_beams_into_fits_access(beam_storage, header_storage)
|
|
99
|
+
|
|
100
|
+
logger.info(f"Correcting telescope polarization for {logging_str}")
|
|
101
|
+
calibrated = self.telescope_polarization_correction(combined)
|
|
102
|
+
|
|
103
|
+
return calibrated
|
|
104
|
+
|
|
105
|
+
def calibrate_intensity_only_beams(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
exposure_conditions: ExposureConditions,
|
|
109
|
+
map_scan: int,
|
|
110
|
+
scan_step: int,
|
|
111
|
+
meas_num: int,
|
|
112
|
+
calibrations: CalibrationCollection,
|
|
113
|
+
) -> CryonirspL0FitsAccess:
|
|
114
|
+
"""
|
|
115
|
+
Completely calibrate non-polarimetric science frames.
|
|
116
|
+
|
|
117
|
+
- Apply all dark and gain corrections
|
|
118
|
+
- Apply geometric correction
|
|
119
|
+
- Combine beams
|
|
120
|
+
"""
|
|
121
|
+
beam_storage = dict()
|
|
122
|
+
header_storage = dict()
|
|
123
|
+
for beam in range(1, self.constants.num_beams + 1):
|
|
124
|
+
logging_str = f"{exposure_conditions = }, {map_scan = }, {scan_step = }, {meas_num = }"
|
|
125
|
+
logger.info(f"Processing Stokes-I observe frames from {logging_str} and {beam = }")
|
|
126
|
+
intermediate_array, intermediate_header = self.apply_basic_corrections(
|
|
127
|
+
beam=beam,
|
|
128
|
+
modstate=1,
|
|
129
|
+
meas_num=meas_num,
|
|
130
|
+
scan_step=scan_step,
|
|
131
|
+
map_scan=map_scan,
|
|
132
|
+
exposure_conditions=exposure_conditions,
|
|
133
|
+
calibrations=calibrations,
|
|
134
|
+
)
|
|
135
|
+
intermediate_header = self.compute_date_keys(intermediate_header)
|
|
136
|
+
|
|
137
|
+
intermediate_array = self.add_stokes_dimension_to_intensity_only_array(
|
|
138
|
+
intermediate_array
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
geo_corrected_array = self.apply_geometric_correction(
|
|
142
|
+
array=intermediate_array, beam=beam, calibrations=calibrations
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
beam_storage[CryonirspTag.beam(beam)] = geo_corrected_array
|
|
146
|
+
header_storage[CryonirspTag.beam(beam)] = intermediate_header
|
|
147
|
+
|
|
148
|
+
logger.info(f"Combining beams for {logging_str}")
|
|
149
|
+
calibrated = self.combine_beams_into_fits_access(beam_storage, header_storage)
|
|
150
|
+
|
|
151
|
+
return calibrated
|
|
152
|
+
|
|
153
|
+
def apply_geometric_correction(
|
|
154
|
+
self, array: np.ndarray, beam: int, calibrations: CalibrationCollection
|
|
155
|
+
) -> np.ndarray:
|
|
156
|
+
"""
|
|
157
|
+
Apply rotation, x/y shift, and spectral shift corrections to an array.
|
|
158
|
+
|
|
159
|
+
The input array needs to have a final dimension that corresponds to Stokes parameters (even if it's only length
|
|
160
|
+
1 for I-only).
|
|
161
|
+
"""
|
|
162
|
+
corrected_array = np.zeros_like(array)
|
|
163
|
+
num_stokes = array.shape[-1]
|
|
164
|
+
|
|
165
|
+
for i in range(num_stokes):
|
|
166
|
+
geo_corrected_array = next(
|
|
167
|
+
self.corrections_correct_geometry(
|
|
168
|
+
array[:, :, i],
|
|
169
|
+
calibrations.state_offset[CryonirspTag.beam(beam)],
|
|
170
|
+
calibrations.angle[CryonirspTag.beam(beam)],
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
spectral_corrected_array = next(
|
|
175
|
+
self.corrections_remove_spec_shifts(
|
|
176
|
+
geo_corrected_array,
|
|
177
|
+
calibrations.spec_shift[CryonirspTag.beam(beam)],
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
# Insert the result into the fully corrected array stack
|
|
181
|
+
corrected_array[:, :, i] = spectral_corrected_array
|
|
182
|
+
|
|
183
|
+
return corrected_array
|
|
184
|
+
|
|
185
|
+
def combine_beams_into_fits_access(
|
|
186
|
+
self, array_dict: dict, header_dict: dict
|
|
187
|
+
) -> CryonirspL0FitsAccess:
|
|
188
|
+
"""
|
|
189
|
+
Average all beams together.
|
|
190
|
+
|
|
191
|
+
Also complain if the inputs are strange.
|
|
192
|
+
"""
|
|
193
|
+
headers = list(header_dict.values())
|
|
194
|
+
if len(headers) == 0:
|
|
195
|
+
raise ValueError("No headers provided")
|
|
196
|
+
for h in headers[1:]:
|
|
197
|
+
if fits.HeaderDiff(headers[0], h):
|
|
198
|
+
raise ValueError("Headers are different! This should NEVER happen!")
|
|
199
|
+
|
|
200
|
+
if self.constants.correct_for_polarization:
|
|
201
|
+
avg_array = self.combine_polarimetric_beams(array_dict)
|
|
202
|
+
else:
|
|
203
|
+
avg_array = self.combine_spectrographic_beams(array_dict)
|
|
204
|
+
|
|
205
|
+
hdu = fits.ImageHDU(data=avg_array, header=headers[0])
|
|
206
|
+
obj = CryonirspL0FitsAccess(hdu=hdu, auto_squeeze=False)
|
|
207
|
+
|
|
208
|
+
return obj
|
|
209
|
+
|
|
210
|
+
def combine_polarimetric_beams(self, array_dict: dict[str, np.ndarray]) -> np.ndarray:
|
|
211
|
+
"""
|
|
212
|
+
Combine polarimetric beams so that polarization states are normalized by the intensity state (Stokes I).
|
|
213
|
+
|
|
214
|
+
In other words:
|
|
215
|
+
|
|
216
|
+
avg_I = (beam1_I + beam2_I) / 2
|
|
217
|
+
avg_Q = (beam1_Q / beam1_I + beam2_Q / beam2_I) / 2. * avg_I
|
|
218
|
+
|
|
219
|
+
...and the same for U and V
|
|
220
|
+
"""
|
|
221
|
+
beam1_data = array_dict[CryonirspTag.beam(1)]
|
|
222
|
+
beam2_data = array_dict[CryonirspTag.beam(2)]
|
|
223
|
+
|
|
224
|
+
avg_data = np.zeros_like(beam1_data)
|
|
225
|
+
# Rely on the fact that the Stokes states are in order after demodulation
|
|
226
|
+
avg_I = (beam1_data[:, :, 0] + beam2_data[:, :, 0]) / 2.0
|
|
227
|
+
avg_data[:, :, 0] = avg_I
|
|
228
|
+
|
|
229
|
+
for stokes in range(1, 4):
|
|
230
|
+
beam1_norm = beam1_data[:, :, stokes] / beam1_data[:, :, 0]
|
|
231
|
+
beam2_norm = beam2_data[:, :, stokes] / beam2_data[:, :, 0]
|
|
232
|
+
avg_data[:, :, stokes] = avg_I * (beam1_norm + beam2_norm) / 2.0
|
|
233
|
+
|
|
234
|
+
return avg_data
|
|
235
|
+
|
|
236
|
+
def combine_spectrographic_beams(self, array_dict: dict[str, np.ndarray]) -> np.ndarray:
|
|
237
|
+
"""Simply average the two beams together."""
|
|
238
|
+
array_list = []
|
|
239
|
+
for beam in range(1, self.constants.num_beams + 1):
|
|
240
|
+
array_list.append(array_dict[CryonirspTag.beam(beam)])
|
|
241
|
+
|
|
242
|
+
avg_array = average_numpy_arrays(array_list)
|
|
243
|
+
return avg_array
|
|
244
|
+
|
|
245
|
+
def collect_calibration_objects(self) -> CalibrationCollection:
|
|
246
|
+
"""
|
|
247
|
+
Collect *all* calibration for all modstates, and exposure times.
|
|
248
|
+
|
|
249
|
+
Doing this once here prevents lots of reads as we reduce the science data.
|
|
250
|
+
"""
|
|
251
|
+
dark_dict = defaultdict(dict)
|
|
252
|
+
solar_dict = dict()
|
|
253
|
+
angle_dict = dict()
|
|
254
|
+
state_offset_dict = dict()
|
|
255
|
+
spec_shift_dict = dict()
|
|
256
|
+
demod_dict = dict() if self.constants.correct_for_polarization else None
|
|
257
|
+
|
|
258
|
+
for beam in range(1, self.constants.num_beams + 1):
|
|
259
|
+
# Load the dark arrays
|
|
260
|
+
for exposure_conditions in self.constants.observe_exposure_conditions_list:
|
|
261
|
+
dark_array = self.intermediate_frame_load_dark_array(
|
|
262
|
+
beam=beam, exposure_conditions=exposure_conditions
|
|
263
|
+
)
|
|
264
|
+
dark_dict[CryonirspTag.beam(beam)][
|
|
265
|
+
CryonirspTag.exposure_conditions(exposure_conditions)
|
|
266
|
+
] = dark_array
|
|
267
|
+
|
|
268
|
+
# Load the gain arrays
|
|
269
|
+
solar_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_solar_gain_array(
|
|
270
|
+
beam=beam,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# Load the angle arrays
|
|
274
|
+
angle_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_angle(beam=beam)
|
|
275
|
+
|
|
276
|
+
# Load the state offsets
|
|
277
|
+
state_offset_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_state_offset(
|
|
278
|
+
beam=beam
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# Load the spectral shifts
|
|
282
|
+
spec_shift_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_spec_shift(
|
|
283
|
+
beam=beam
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Load the demod matrices
|
|
287
|
+
if self.constants.correct_for_polarization:
|
|
288
|
+
demod_dict[CryonirspTag.beam(beam)] = self.intermediate_frame_load_demod_matrices(
|
|
289
|
+
beam=beam
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return CalibrationCollection(
|
|
293
|
+
dark=dark_dict,
|
|
294
|
+
solar_gain=solar_dict,
|
|
295
|
+
angle=angle_dict,
|
|
296
|
+
state_offset=state_offset_dict,
|
|
297
|
+
spec_shift=spec_shift_dict,
|
|
298
|
+
demod_matrices=demod_dict,
|
|
299
|
+
)
|