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,96 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from dkist_processing_common.manual import ManualProcessing
|
|
6
|
+
|
|
7
|
+
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
8
|
+
from dkist_processing_cryonirsp.tasks.linearity_correction import LinearityCorrection
|
|
9
|
+
from dkist_processing_cryonirsp.tasks.parse import ParseL0CryonirspRampData
|
|
10
|
+
from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
|
|
11
|
+
create_input_dataset_parameter_document,
|
|
12
|
+
)
|
|
13
|
+
from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
|
|
14
|
+
save_parsing_task,
|
|
15
|
+
)
|
|
16
|
+
from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
|
|
17
|
+
SaveLinearizedFiles,
|
|
18
|
+
)
|
|
19
|
+
from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
|
|
20
|
+
tag_inputs_task,
|
|
21
|
+
)
|
|
22
|
+
from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
|
|
23
|
+
translate_122_to_214_task,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main(
|
|
28
|
+
scratch_path: str,
|
|
29
|
+
suffix: str = "dat",
|
|
30
|
+
recipe_run_id: int = 2,
|
|
31
|
+
skip_translation: bool = False,
|
|
32
|
+
param_path: Path = None,
|
|
33
|
+
):
|
|
34
|
+
with ManualProcessing(
|
|
35
|
+
workflow_path=Path(scratch_path),
|
|
36
|
+
recipe_run_id=recipe_run_id,
|
|
37
|
+
testing=True,
|
|
38
|
+
workflow_name="cryonirsp-l0-pipeline", # need sperate workflows for CI and SP?
|
|
39
|
+
workflow_version="GROGU",
|
|
40
|
+
) as manual_processing_run:
|
|
41
|
+
if not skip_translation:
|
|
42
|
+
manual_processing_run.run_task(task=translate_122_to_214_task(suffix))
|
|
43
|
+
|
|
44
|
+
manual_processing_run.run_task(
|
|
45
|
+
task=create_input_dataset_parameter_document(param_path=param_path)
|
|
46
|
+
)
|
|
47
|
+
manual_processing_run.run_task(task=tag_inputs_task(suffix))
|
|
48
|
+
manual_processing_run.run_task(task=ParseL0CryonirspRampData)
|
|
49
|
+
manual_processing_run.run_task(
|
|
50
|
+
task=save_parsing_task(
|
|
51
|
+
tag_list=[CryonirspTag.input(), CryonirspTag.frame()],
|
|
52
|
+
save_file="input_parsing.asdf",
|
|
53
|
+
save_file_tags=False,
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
manual_processing_run.run_task(task=LinearityCorrection)
|
|
57
|
+
manual_processing_run.run_task(task=SaveLinearizedFiles)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
parser = argparse.ArgumentParser(
|
|
62
|
+
description="Run an end-to-end test of the Cryonirsp DC Science pipeline"
|
|
63
|
+
)
|
|
64
|
+
parser.add_argument("scratch_path", help="Location to use as the DC 'scratch' disk")
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
"-i",
|
|
67
|
+
"--run-id",
|
|
68
|
+
help="Which subdir to use. This will become the recipe run id",
|
|
69
|
+
type=int,
|
|
70
|
+
default=4,
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument("--suffix", help="File suffix to treat as INPUT frames", default="FITS")
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"-T",
|
|
75
|
+
"--skip-translation",
|
|
76
|
+
help="Skip the translation of raw 122 l0 frames to 214 l0",
|
|
77
|
+
action="store_true",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"-p",
|
|
81
|
+
"--param-path",
|
|
82
|
+
help="Path to parameter directory",
|
|
83
|
+
type=str,
|
|
84
|
+
default=None,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
args = parser.parse_args()
|
|
88
|
+
sys.exit(
|
|
89
|
+
main(
|
|
90
|
+
scratch_path=args.scratch_path,
|
|
91
|
+
suffix=args.suffix,
|
|
92
|
+
recipe_run_id=args.run_id,
|
|
93
|
+
skip_translation=args.skip_translation,
|
|
94
|
+
param_path=Path(args.param_path),
|
|
95
|
+
)
|
|
96
|
+
)
|
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
from dataclasses import asdict
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from random import randint
|
|
7
|
+
|
|
8
|
+
import asdf
|
|
9
|
+
from astropy.io import fits
|
|
10
|
+
from dkist_header_validator import spec122_validator
|
|
11
|
+
from dkist_processing_common.models.task_name import TaskName
|
|
12
|
+
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
13
|
+
from dkist_processing_common.tasks.mixin.globus import GlobusTransferItem
|
|
14
|
+
from dkist_service_configuration.logging import logger
|
|
15
|
+
|
|
16
|
+
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
17
|
+
from dkist_processing_cryonirsp.models.task_name import CryonirspTaskName
|
|
18
|
+
from dkist_processing_cryonirsp.tasks import TransferCryoTrialData
|
|
19
|
+
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
20
|
+
from dkist_processing_cryonirsp.tests.conftest import cryonirsp_testing_parameters_factory
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# These are the workflow versions of the polyfit coefficient parameters
|
|
24
|
+
WORKFLOW_LINEARIZATION_POLYFIT_COEFFS_CI = [
|
|
25
|
+
1.1565851e00,
|
|
26
|
+
-1.1925439e-05,
|
|
27
|
+
2.6748548e-10,
|
|
28
|
+
-2.7366326e-15,
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
WORKFLOW_LINEARIZATION_POLYFIT_COEFFS_SP = [
|
|
32
|
+
1.1421334e00,
|
|
33
|
+
-1.0536260e-05,
|
|
34
|
+
2.2702712e-10,
|
|
35
|
+
-2.5632187e-15,
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def save_parsing_task(
|
|
40
|
+
tag_list: [str], save_file: str, save_file_tags: bool = True, save_constants: bool = True
|
|
41
|
+
):
|
|
42
|
+
class SaveParsing(WorkflowTaskBase):
|
|
43
|
+
"""Save the result of parsing (constants and tags) to an asdf file."""
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def relative_save_file(self) -> str:
|
|
47
|
+
return save_file
|
|
48
|
+
|
|
49
|
+
def run(self):
|
|
50
|
+
if save_file_tags:
|
|
51
|
+
file_tag_dict = self.get_input_tags()
|
|
52
|
+
else:
|
|
53
|
+
logger.info("Skipping saving of file tags")
|
|
54
|
+
file_tag_dict = dict()
|
|
55
|
+
if save_constants:
|
|
56
|
+
constant_dict = self.get_constants()
|
|
57
|
+
else:
|
|
58
|
+
logger.info("Skipping saving of constants")
|
|
59
|
+
constant_dict = dict()
|
|
60
|
+
|
|
61
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
62
|
+
tree = {"file_tag_dict": file_tag_dict, "constants_dict": constant_dict}
|
|
63
|
+
af = asdf.AsdfFile(tree)
|
|
64
|
+
af.write_to(full_save_file)
|
|
65
|
+
logger.info(f"Saved input tags to {full_save_file}")
|
|
66
|
+
|
|
67
|
+
def get_input_tags(self) -> dict[str, list[str]]:
|
|
68
|
+
file_tag_dict = dict()
|
|
69
|
+
path_list = self.read(tags=tag_list)
|
|
70
|
+
for p in path_list:
|
|
71
|
+
tags = self.tags(p)
|
|
72
|
+
file_tag_dict[str(p)] = tags
|
|
73
|
+
|
|
74
|
+
return file_tag_dict
|
|
75
|
+
|
|
76
|
+
def get_constants(self) -> dict[str, str | float | list]:
|
|
77
|
+
constants_dict = dict()
|
|
78
|
+
for c in self.constants._db_dict.keys():
|
|
79
|
+
constants_dict[c] = self.constants._db_dict[c]
|
|
80
|
+
|
|
81
|
+
return constants_dict
|
|
82
|
+
|
|
83
|
+
return SaveParsing
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def load_parsing_task(save_file: str):
|
|
87
|
+
class LoadParsing(WorkflowTaskBase):
|
|
88
|
+
"""Load tags and constants into the database."""
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def relative_save_file(self) -> str:
|
|
92
|
+
return save_file
|
|
93
|
+
|
|
94
|
+
def run(self):
|
|
95
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
96
|
+
with asdf.open(full_save_file) as af:
|
|
97
|
+
file_tag_dict = af.tree["file_tag_dict"]
|
|
98
|
+
self.tag_input_files(file_tag_dict)
|
|
99
|
+
|
|
100
|
+
constants_dict = af.tree["constants_dict"]
|
|
101
|
+
self.populate_constants(constants_dict)
|
|
102
|
+
|
|
103
|
+
logger.info(f"Loaded tags and constants from {full_save_file}")
|
|
104
|
+
|
|
105
|
+
def tag_input_files(self, file_tag_dict: dict[str, list[str]]):
|
|
106
|
+
for f, t in file_tag_dict.items():
|
|
107
|
+
if not os.path.exists(f):
|
|
108
|
+
raise FileNotFoundError(f"Expected to find {f}, but it doesn't exist.")
|
|
109
|
+
self.tag(path=f, tags=t)
|
|
110
|
+
|
|
111
|
+
def populate_constants(self, constants_dict: dict[str, str | int | float]) -> None:
|
|
112
|
+
# First we purge all constants because a previous load might have polluted the DB
|
|
113
|
+
self.constants._purge()
|
|
114
|
+
for c, v in constants_dict.items():
|
|
115
|
+
logger.info(f"Setting value of {c} to {v}")
|
|
116
|
+
self.constants._update({c: v})
|
|
117
|
+
|
|
118
|
+
return LoadParsing
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class SaveLinearizedFiles(WorkflowTaskBase):
|
|
122
|
+
"""Save linearized files and their tags to a directory and asdf file."""
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def relative_save_file(self) -> str:
|
|
126
|
+
return "linearized.asdf"
|
|
127
|
+
|
|
128
|
+
def run(self):
|
|
129
|
+
file_tag_dict = dict()
|
|
130
|
+
path_list = self.read(tags=[CryonirspTag.linearized()])
|
|
131
|
+
save_dir = self.scratch.workflow_base_path / Path(self.relative_save_file).stem
|
|
132
|
+
save_dir.mkdir(exist_ok=True)
|
|
133
|
+
for p in path_list:
|
|
134
|
+
copied_path = shutil.move(str(p), save_dir)
|
|
135
|
+
tags = self.tags(p)
|
|
136
|
+
file_tag_dict[copied_path] = tags
|
|
137
|
+
|
|
138
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
139
|
+
tree = {"file_tag_dict": file_tag_dict}
|
|
140
|
+
af = asdf.AsdfFile(tree)
|
|
141
|
+
af.write_to(full_save_file)
|
|
142
|
+
logger.info(f"Saved linearized tags to {full_save_file}")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class LoadLinearizedFiles(WorkflowTaskBase):
|
|
146
|
+
"""Load linearized tags that point to previously saved files."""
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def relative_save_file(self) -> str:
|
|
150
|
+
return "linearized.asdf"
|
|
151
|
+
|
|
152
|
+
def run(self):
|
|
153
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
154
|
+
with asdf.open(full_save_file) as af:
|
|
155
|
+
for f, t in af.tree["file_tag_dict"].items():
|
|
156
|
+
# This is so any of the old (un-moved) files still tagged in the db are removed from the db
|
|
157
|
+
current_files = self.read(tags=t)
|
|
158
|
+
for current_file in current_files:
|
|
159
|
+
self.remove_tags(current_file, t)
|
|
160
|
+
|
|
161
|
+
self.tag(path=f, tags=t)
|
|
162
|
+
logger.info(f"Loaded linearized files entries from {full_save_file}")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class SaveTaskTags(WorkflowTaskBase):
|
|
166
|
+
@property
|
|
167
|
+
def task_str(self) -> str:
|
|
168
|
+
return "TASK"
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def relative_save_file(self) -> str:
|
|
172
|
+
return "default_sav.asdf"
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def tag_lists_to_save(self) -> list[list[str]] | list[str]:
|
|
176
|
+
return [[CryonirspTag.task(self.task_str), CryonirspTag.intermediate()]]
|
|
177
|
+
|
|
178
|
+
def run(self):
|
|
179
|
+
file_tag_dict = dict()
|
|
180
|
+
tag_list_list = self.tag_lists_to_save
|
|
181
|
+
if isinstance(tag_list_list[0], str):
|
|
182
|
+
tag_list_list = [tag_list_list]
|
|
183
|
+
|
|
184
|
+
for tags_to_save in tag_list_list:
|
|
185
|
+
path_list = self.read(tags=tags_to_save)
|
|
186
|
+
save_dir = self.scratch.workflow_base_path / Path(self.relative_save_file).stem
|
|
187
|
+
save_dir.mkdir(exist_ok=True)
|
|
188
|
+
for p in path_list:
|
|
189
|
+
copied_path = shutil.copy(str(p), save_dir)
|
|
190
|
+
tags = self.tags(p)
|
|
191
|
+
file_tag_dict[copied_path] = tags
|
|
192
|
+
|
|
193
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
194
|
+
tree = {"file_tag_dict": file_tag_dict}
|
|
195
|
+
af = asdf.AsdfFile(tree)
|
|
196
|
+
af.write_to(full_save_file)
|
|
197
|
+
logger.info(f"Saved {self.task_str} to {full_save_file}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class LoadTaskTags(WorkflowTaskBase):
|
|
201
|
+
@property
|
|
202
|
+
def relative_save_file(self) -> str:
|
|
203
|
+
return "default_sav.asdf"
|
|
204
|
+
|
|
205
|
+
def run(self):
|
|
206
|
+
full_save_file = self.scratch.workflow_base_path / self.relative_save_file
|
|
207
|
+
with asdf.open(full_save_file) as af:
|
|
208
|
+
for f, t in af.tree["file_tag_dict"].items():
|
|
209
|
+
self.tag(path=f, tags=t)
|
|
210
|
+
logger.info(f"Loaded database entries from {full_save_file}")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class SaveGeometricCal(WorkflowTaskBase):
|
|
214
|
+
def run(self) -> None:
|
|
215
|
+
relative_save_file = "geometric_cal.asdf"
|
|
216
|
+
file_tag_dict = dict()
|
|
217
|
+
path_list = list(
|
|
218
|
+
self.read(tags=[CryonirspTag.task_geometric_angle(), CryonirspTag.intermediate()])
|
|
219
|
+
)
|
|
220
|
+
path_list += list(
|
|
221
|
+
self.read(tags=[CryonirspTag.task_geometric_offset(), CryonirspTag.intermediate()])
|
|
222
|
+
)
|
|
223
|
+
path_list += list(
|
|
224
|
+
self.read(
|
|
225
|
+
tags=[CryonirspTag.task_geometric_sepectral_shifts(), CryonirspTag.intermediate()]
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
path_list += list(
|
|
229
|
+
self.read(
|
|
230
|
+
tags=[
|
|
231
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
232
|
+
CryonirspTag.workflow_task("SPGeometricCalibration"),
|
|
233
|
+
]
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
save_dir = self.scratch.workflow_base_path / Path(relative_save_file).stem
|
|
237
|
+
save_dir.mkdir(exist_ok=True)
|
|
238
|
+
for p in path_list:
|
|
239
|
+
copied_path = shutil.copy(str(p), save_dir)
|
|
240
|
+
tags = self.tags(p)
|
|
241
|
+
file_tag_dict[copied_path] = tags
|
|
242
|
+
|
|
243
|
+
full_save_file = self.scratch.workflow_base_path / relative_save_file
|
|
244
|
+
tree = {"file_tag_dict": file_tag_dict}
|
|
245
|
+
af = asdf.AsdfFile(tree)
|
|
246
|
+
af.write_to(full_save_file)
|
|
247
|
+
logger.info(f"Saved Geometric Calibration to {full_save_file}")
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class LoadGeometricCal(LoadTaskTags):
|
|
251
|
+
@property
|
|
252
|
+
def relative_save_file(self) -> str:
|
|
253
|
+
return "geometric_cal.asdf"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class SaveBadPixelMap(SaveTaskTags):
|
|
257
|
+
@property
|
|
258
|
+
def task_str(self):
|
|
259
|
+
return CryonirspTaskName.bad_pixel_map.value
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def relative_save_file(self) -> str:
|
|
263
|
+
return "bad_pixel_map.asdf"
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class LoadBadPixelMap(LoadTaskTags):
|
|
267
|
+
@property
|
|
268
|
+
def relative_save_file(self) -> str:
|
|
269
|
+
return "bad_pixel_map.asdf"
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class SaveBeamBoundaryCal(SaveTaskTags):
|
|
273
|
+
@property
|
|
274
|
+
def task_str(self):
|
|
275
|
+
return CryonirspTaskName.beam_boundaries.value
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def relative_save_file(self) -> str:
|
|
279
|
+
return "beam_boundary_cal.asdf"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class LoadBeamBoundaryCal(LoadTaskTags):
|
|
283
|
+
@property
|
|
284
|
+
def relative_save_file(self) -> str:
|
|
285
|
+
return "beam_boundary_cal.asdf"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class SaveDarkCal(SaveTaskTags):
|
|
289
|
+
@property
|
|
290
|
+
def task_str(self) -> str:
|
|
291
|
+
return TaskName.dark.value
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def relative_save_file(self) -> str:
|
|
295
|
+
return "dark_cal.asdf"
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def tag_lists_to_save(self) -> list[list[str]]:
|
|
299
|
+
return super().tag_lists_to_save + [
|
|
300
|
+
[CryonirspTag.quality("TASK_TYPES"), CryonirspTag.workflow_task("DarkCalibration")]
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class LoadDarkCal(LoadTaskTags):
|
|
305
|
+
@property
|
|
306
|
+
def relative_save_file(self) -> str:
|
|
307
|
+
return "dark_cal.asdf"
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class SaveLampCal(SaveTaskTags):
|
|
311
|
+
@property
|
|
312
|
+
def task_str(self) -> str:
|
|
313
|
+
return TaskName.lamp_gain.value
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def relative_save_file(self) -> str:
|
|
317
|
+
return "lamp_cal.asdf"
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def tag_lists_to_save(self) -> list[list[str]]:
|
|
321
|
+
return super().tag_lists_to_save + [
|
|
322
|
+
[CryonirspTag.quality("TASK_TYPES"), CryonirspTag.workflow_task("LampGainCalibration")],
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class LoadLampCal(LoadTaskTags):
|
|
327
|
+
@property
|
|
328
|
+
def relative_save_file(self) -> str:
|
|
329
|
+
return "lamp_cal.asdf"
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class SaveSolarCal(SaveTaskTags):
|
|
333
|
+
@property
|
|
334
|
+
def task_str(self) -> str:
|
|
335
|
+
return TaskName.solar_gain.value
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def relative_save_file(self) -> str:
|
|
339
|
+
return "solar_cal.asdf"
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def tag_lists_to_save(self) -> list[list[str]]:
|
|
343
|
+
return super().tag_lists_to_save + [
|
|
344
|
+
[
|
|
345
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
346
|
+
CryonirspTag.workflow_task("CISolarGainCalibration"),
|
|
347
|
+
],
|
|
348
|
+
[
|
|
349
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
350
|
+
CryonirspTag.workflow_task("SPSolarGainCalibration"),
|
|
351
|
+
],
|
|
352
|
+
[
|
|
353
|
+
CryonirspTag.intermediate(),
|
|
354
|
+
CryonirspTag.task_characteristic_spectra(),
|
|
355
|
+
],
|
|
356
|
+
]
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
class SaveDispersionAxisCorrection(SaveTaskTags):
|
|
360
|
+
@property
|
|
361
|
+
def task_str(self) -> str:
|
|
362
|
+
return CryonirspTaskName.spectral_fit.value
|
|
363
|
+
|
|
364
|
+
@property
|
|
365
|
+
def relative_save_file(self) -> str:
|
|
366
|
+
return "sp_dispersion_axis_correction.asdf"
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def tag_lists_to_save(self) -> list[list[str]]:
|
|
370
|
+
return super().tag_lists_to_save + [
|
|
371
|
+
[
|
|
372
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
373
|
+
CryonirspTag.workflow_task("SPDispersionAxisCorrection"),
|
|
374
|
+
],
|
|
375
|
+
]
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class LoadSolarCal(LoadTaskTags):
|
|
379
|
+
@property
|
|
380
|
+
def relative_save_file(self) -> str:
|
|
381
|
+
return "solar_cal.asdf"
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class LoadDispersionAxisCorrection(LoadTaskTags):
|
|
385
|
+
@property
|
|
386
|
+
def relative_save_file(self) -> str:
|
|
387
|
+
return "sp_dispersion_axis_correction.asdf"
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class SaveInstPolCal(SaveTaskTags):
|
|
391
|
+
@property
|
|
392
|
+
def task_str(self) -> str:
|
|
393
|
+
return TaskName.demodulation_matrices.value
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def relative_save_file(self) -> str:
|
|
397
|
+
return "inst_pol_cal.asdf"
|
|
398
|
+
|
|
399
|
+
@property
|
|
400
|
+
def tag_lists_to_save(self) -> list[list[str]]:
|
|
401
|
+
return super().tag_lists_to_save + [
|
|
402
|
+
[
|
|
403
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
404
|
+
CryonirspTag.workflow_task("CIInstrumentPolarizationCalibration"),
|
|
405
|
+
],
|
|
406
|
+
[
|
|
407
|
+
CryonirspTag.quality("TASK_TYPES"),
|
|
408
|
+
CryonirspTag.workflow_task("SPInstrumentPolarizationCalibration"),
|
|
409
|
+
],
|
|
410
|
+
[CryonirspTag.quality("POLCAL_CONSTANT_PAR_VALS")],
|
|
411
|
+
[CryonirspTag.quality("POLCAL_GLOBAL_PAR_VALS")],
|
|
412
|
+
[CryonirspTag.quality("POLCAL_LOCAL_PAR_VALS")],
|
|
413
|
+
[CryonirspTag.quality("POLCAL_FIT_RESIDUALS")],
|
|
414
|
+
[CryonirspTag.quality("POLCAL_EFFICIENCY")],
|
|
415
|
+
]
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class LoadInstPolCal(LoadTaskTags):
|
|
419
|
+
@property
|
|
420
|
+
def relative_save_file(self) -> str:
|
|
421
|
+
return "inst_pol_cal.asdf"
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def translate_122_to_214_task(suffix: str):
|
|
425
|
+
class Translate122To214L0(WorkflowTaskBase):
|
|
426
|
+
def run(self) -> None:
|
|
427
|
+
raw_dir = Path(self.scratch.scratch_base_path) / f"CRYO-NIRSP{self.recipe_run_id:03n}"
|
|
428
|
+
if not os.path.exists(self.scratch.workflow_base_path):
|
|
429
|
+
os.makedirs(self.scratch.workflow_base_path)
|
|
430
|
+
|
|
431
|
+
if not raw_dir.exists():
|
|
432
|
+
raise FileNotFoundError(
|
|
433
|
+
f"Expected to find a raw CRYO-NIRSP{self.recipe_run_id:03n} folder in {self.scratch.scratch_base_path}"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
for file in raw_dir.glob(f"*.{suffix}"):
|
|
437
|
+
translated_file_name = Path(self.scratch.workflow_base_path) / os.path.basename(
|
|
438
|
+
file
|
|
439
|
+
)
|
|
440
|
+
logger.info(f"Translating {file} -> {translated_file_name}")
|
|
441
|
+
hdl = fits.open(file)
|
|
442
|
+
# Handle both compressed and uncompressed files...
|
|
443
|
+
if len(hdl) > 1:
|
|
444
|
+
hdl_header = hdl[1].header
|
|
445
|
+
hdl_data = hdl[1].data
|
|
446
|
+
else:
|
|
447
|
+
hdl_header = hdl[0].header
|
|
448
|
+
hdl_data = hdl[0].data
|
|
449
|
+
header = spec122_validator.validate_and_translate_to_214_l0(
|
|
450
|
+
hdl_header, return_type=fits.HDUList
|
|
451
|
+
)[0].header
|
|
452
|
+
|
|
453
|
+
comp_hdu = fits.CompImageHDU(header=header, data=hdl_data)
|
|
454
|
+
comp_hdl = fits.HDUList([fits.PrimaryHDU(), comp_hdu])
|
|
455
|
+
comp_hdl.writeto(translated_file_name, overwrite=True)
|
|
456
|
+
|
|
457
|
+
hdl.close()
|
|
458
|
+
del hdl
|
|
459
|
+
comp_hdl.close()
|
|
460
|
+
del comp_hdl
|
|
461
|
+
|
|
462
|
+
return Translate122To214L0
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def create_input_dataset_parameter_document(param_path: Path):
|
|
466
|
+
class CreateInputDatasetParameterDocument(WorkflowTaskBase):
|
|
467
|
+
def run(self) -> None:
|
|
468
|
+
doc_path = self.scratch.workflow_base_path / "input_dataset_parameters.json"
|
|
469
|
+
with open(doc_path, "w") as f:
|
|
470
|
+
f.write(json.dumps(self.input_dataset_document_simple_parameters_part))
|
|
471
|
+
self.tag(doc_path, CryonirspTag.input_dataset_parameters())
|
|
472
|
+
logger.info(f"Wrote input dataset doc to {doc_path}")
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def input_dataset_document_simple_parameters_part(self):
|
|
476
|
+
parameters_list = []
|
|
477
|
+
value_id = randint(1000, 2000)
|
|
478
|
+
param_class = cryonirsp_testing_parameters_factory(
|
|
479
|
+
param_path=param_path, create_files=False
|
|
480
|
+
)
|
|
481
|
+
params = asdict(
|
|
482
|
+
param_class(
|
|
483
|
+
cryonirsp_linearization_polyfit_coeffs_ci=WORKFLOW_LINEARIZATION_POLYFIT_COEFFS_CI,
|
|
484
|
+
cryonirsp_linearization_polyfit_coeffs_sp=WORKFLOW_LINEARIZATION_POLYFIT_COEFFS_SP,
|
|
485
|
+
)
|
|
486
|
+
)
|
|
487
|
+
for pn, pv in params.items():
|
|
488
|
+
values = [
|
|
489
|
+
{
|
|
490
|
+
"parameterValueId": value_id,
|
|
491
|
+
"parameterValue": json.dumps(pv),
|
|
492
|
+
"parameterValueStartDate": "1946-11-20",
|
|
493
|
+
}
|
|
494
|
+
]
|
|
495
|
+
parameter = {"parameterName": pn, "parameterValues": values}
|
|
496
|
+
parameters_list.append(parameter)
|
|
497
|
+
|
|
498
|
+
return parameters_list
|
|
499
|
+
|
|
500
|
+
return CreateInputDatasetParameterDocument
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def tag_inputs_task(suffix: str):
|
|
504
|
+
class TagInputs(WorkflowTaskBase):
|
|
505
|
+
def run(self) -> None:
|
|
506
|
+
logger.info(f"Looking in {os.path.abspath(self.scratch.workflow_base_path)}")
|
|
507
|
+
input_file_list = list(self.scratch.workflow_base_path.glob(f"*.{suffix}"))
|
|
508
|
+
if len(input_file_list) == 0:
|
|
509
|
+
raise FileNotFoundError(
|
|
510
|
+
f"Did not find any files matching '*.{suffix}' in {self.scratch.workflow_base_path}"
|
|
511
|
+
)
|
|
512
|
+
for file in input_file_list:
|
|
513
|
+
logger.info(f"Found {file}")
|
|
514
|
+
self.tag(path=file, tags=[CryonirspTag.input(), CryonirspTag.frame()])
|
|
515
|
+
|
|
516
|
+
return TagInputs
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
class DBAccess(CryonirspTaskBase):
|
|
520
|
+
"""
|
|
521
|
+
No-Op task that allows use to access the redis database.
|
|
522
|
+
|
|
523
|
+
I.e.:
|
|
524
|
+
|
|
525
|
+
task = DBAccess(recipe_run_id)
|
|
526
|
+
value = task.constants.whatever
|
|
527
|
+
"""
|
|
528
|
+
|
|
529
|
+
def __init__(self, recipe_run_id: int):
|
|
530
|
+
workflow_name = "redis_db_access_task"
|
|
531
|
+
workflow_version = "vfoo.bar"
|
|
532
|
+
|
|
533
|
+
super().__init__(
|
|
534
|
+
recipe_run_id=recipe_run_id,
|
|
535
|
+
workflow_name=workflow_name,
|
|
536
|
+
workflow_version=workflow_version,
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
def run(self) -> None:
|
|
540
|
+
pass
|
|
541
|
+
|
|
542
|
+
def __call__(self, *args, **kwargs):
|
|
543
|
+
raise RuntimeError(f"{self.__class__.__name__} not intended to be called.")
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def transfer_trial_data_locally_task(
|
|
547
|
+
trial_dir: str | Path,
|
|
548
|
+
debug_switch: bool = True,
|
|
549
|
+
intermediate_switch: bool = True,
|
|
550
|
+
output_swtich: bool = True,
|
|
551
|
+
tag_lists: list | None = None,
|
|
552
|
+
):
|
|
553
|
+
class LocalTrialData(TransferCryoTrialData):
|
|
554
|
+
@property
|
|
555
|
+
def destination_folder(self) -> Path:
|
|
556
|
+
return Path(trial_dir)
|
|
557
|
+
|
|
558
|
+
@property
|
|
559
|
+
def debug_frame_switch(self) -> bool:
|
|
560
|
+
return debug_switch
|
|
561
|
+
|
|
562
|
+
@property
|
|
563
|
+
def intermediate_frame_switch(self) -> bool:
|
|
564
|
+
return intermediate_switch
|
|
565
|
+
|
|
566
|
+
@property
|
|
567
|
+
def output_frame_switch(self) -> bool:
|
|
568
|
+
return output_swtich
|
|
569
|
+
|
|
570
|
+
@property
|
|
571
|
+
def specific_frame_tag_lists(self) -> list:
|
|
572
|
+
return tag_lists or []
|
|
573
|
+
|
|
574
|
+
def remove_folder_objects(self):
|
|
575
|
+
logger.info("Would have removed folder objects here")
|
|
576
|
+
|
|
577
|
+
def globus_transfer_scratch_to_object_store(
|
|
578
|
+
self,
|
|
579
|
+
transfer_items: list[GlobusTransferItem],
|
|
580
|
+
label: str = None,
|
|
581
|
+
sync_level: str = None,
|
|
582
|
+
verify_checksum: bool = True,
|
|
583
|
+
) -> None:
|
|
584
|
+
if label:
|
|
585
|
+
logger.info(f"Transferring files with {label = }")
|
|
586
|
+
|
|
587
|
+
for frame in transfer_items:
|
|
588
|
+
if not frame.destination_path.parent.exists():
|
|
589
|
+
frame.destination_path.parent.mkdir(parents=True)
|
|
590
|
+
os.system(f"cp {frame.source_path} {frame.destination_path}")
|
|
591
|
+
|
|
592
|
+
return LocalTrialData
|