dkist-processing-cryonirsp 0.0.1rc2__tar.gz → 0.0.1rc4__tar.gz
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.
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/.readthedocs.yml +1 -1
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/PKG-INFO +3 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/bitbucket-pipelines.yml +2 -2
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/models/constants.py +26 -3
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/models/filter.py +46 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/models/parameters.py +47 -37
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +4 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/map_repeats.py +2 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/task.py +2 -7
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/time.py +4 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/assemble_movie.py +1 -1
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/bad_pixel_map.py +24 -24
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +199 -0
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +58 -0
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/ci_science.py +164 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/cryonirsp_base.py +4 -40
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/gain.py +12 -10
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/instrument_polarization.py +20 -36
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/linearity_correction.py +282 -0
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/make_movie_frames.py +314 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/beam_access.py +10 -7
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/corrections.py +6 -7
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/intermediate_frame.py +1 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/linearized_frame.py +0 -1
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/parse.py +35 -27
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/quality_metrics.py +254 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/science_base.py +135 -163
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +234 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/sp_geometric.py +233 -170
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/sp_science.py +280 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/sp_solar_gain.py +23 -30
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tasks/write_l1.py +310 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/ci_e2e_test.py +14 -14
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/conftest.py +119 -59
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/sp_e2e_test.py +14 -15
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_assemble_movie.py +0 -4
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +7 -8
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +103 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_ci_make_movie_frames.py +2 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_ci_science.py +7 -8
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_cryo_base.py +3 -7
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_dark.py +0 -4
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_gain.py +0 -6
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_instrument_polarization.py +0 -8
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_linearity_correction.py +11 -6
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tests/test_parameters.py +184 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_parse.py +0 -19
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_quality.py +8 -8
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tests/test_beam_boundaries.py → dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +14 -25
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_sp_geometric.py +0 -2
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +2 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_sp_science.py +9 -10
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_sp_solar.py +0 -2
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp/tests/test_write_l1.py +236 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/workflows/ci_l0_processing.py +4 -4
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/workflows/sp_l0_processing.py +4 -4
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp.egg-info/PKG-INFO +3 -3
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp.egg-info/SOURCES.txt +7 -6
- dkist_processing_cryonirsp-0.0.1rc4/dkist_processing_cryonirsp.egg-info/requires.txt +40 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/setup.cfg +18 -18
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/models/spectral_line.py +0 -24
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/parsers/spectral_line.py +0 -36
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/beam_boundaries.py +0 -350
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/ci_make_movie_frames.py +0 -152
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/ci_science.py +0 -77
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/linearity_correction.py +0 -230
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/quality_metrics.py +0 -203
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/sp_make_movie_frames.py +0 -160
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/sp_science.py +0 -156
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tasks/write_l1.py +0 -342
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tests/test_parameters.py +0 -88
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp/tests/test_write_l1.py +0 -305
- dkist_processing_cryonirsp-0.0.1rc2/dkist_processing_cryonirsp.egg-info/requires.txt +0 -40
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/.gitignore +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/.pre-commit-config.yaml +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/CHANGELOG.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/README.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/models/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/models/tags.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/models/task_name.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/measurements.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/modstates.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/polarimeter_mode.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/polcal_task.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/scan_step.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/parsers/wavelength.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/dark.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/l1_output_data.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tasks/mixin/input_frame.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/e2e_helpers.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/e2e_linearize.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_build_quality_report.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_cryo_constants.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_submit_qualilty.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/tests/test_workflows.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp/workflows/__init__.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp.egg-info/dependency_links.txt +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/dkist_processing_cryonirsp.egg-info/top_level.txt +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/Makefile +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/changelog.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/ci_l0_to_l1_cryonirsp.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/conf.py +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/index.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/make.bat +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/requirements.txt +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/requirements_table.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/docs/sp_l0_to_l1_cryonirsp.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/licenses/LICENSE.rst +0 -0
- {dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dkist_processing_cryonirsp
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1rc4
|
|
4
4
|
Summary: Science processing code for the Cryo-NIRSP instrument on DKIST
|
|
5
5
|
Home-page: https://bitbucket.org/dkistdc/dkist_processing_cryonirsp/src/main/
|
|
6
6
|
Author: NSO / AURA
|
|
@@ -8,8 +8,8 @@ Author-email: "dkistdc@nso.edu"
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: Programming Language :: Python
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.
|
|
12
|
-
Requires-Python: >=3.
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
13
|
Provides-Extra: test
|
|
14
14
|
Provides-Extra: grogu
|
|
15
15
|
Provides-Extra: docs
|
{dkist_processing_cryonirsp-0.0.1rc2 → dkist_processing_cryonirsp-0.0.1rc4}/bitbucket-pipelines.yml
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#Build Configuration for docker deployment to artifactory
|
|
2
|
-
image: python:3.
|
|
2
|
+
image: python:3.11
|
|
3
3
|
|
|
4
4
|
definitions:
|
|
5
5
|
services:
|
|
@@ -40,7 +40,7 @@ definitions:
|
|
|
40
40
|
script:
|
|
41
41
|
- pip install -U pip
|
|
42
42
|
- pip install .[test]
|
|
43
|
-
- pytest -v
|
|
43
|
+
- pytest -v -n auto -m "not development" --cov dkist_processing_cryonirsp
|
|
44
44
|
services:
|
|
45
45
|
- redis
|
|
46
46
|
- step: &push_workflow
|
|
@@ -26,6 +26,10 @@ class CryonirspBudName(Enum):
|
|
|
26
26
|
axis_1_type = "AXIS_1_TYPE"
|
|
27
27
|
axis_2_type = "AXIS_2_TYPE"
|
|
28
28
|
axis_3_type = "AXIS_3_TYPE"
|
|
29
|
+
roi_1_origin_x = "ROI_1_ORIGIN_X"
|
|
30
|
+
roi_1_origin_y = "ROI_1_ORIGIN_Y"
|
|
31
|
+
roi_1_size_x = "ROI_1_SIZE_X"
|
|
32
|
+
roi_1_size_y = "ROI_1_SIZE_Y"
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
class CryonirspConstants(ConstantsBase):
|
|
@@ -70,8 +74,8 @@ class CryonirspConstants(ConstantsBase):
|
|
|
70
74
|
return self._db_dict[CryonirspBudName.num_meas.value]
|
|
71
75
|
|
|
72
76
|
@property
|
|
73
|
-
def time_obs_list(self) ->
|
|
74
|
-
"""Construct a
|
|
77
|
+
def time_obs_list(self) -> tuple[str]:
|
|
78
|
+
"""Construct a sorted tuple of all the dateobs for this dataset."""
|
|
75
79
|
return self._db_dict[CryonirspBudName.time_obs_list.value]
|
|
76
80
|
|
|
77
81
|
@property
|
|
@@ -115,7 +119,6 @@ class CryonirspConstants(ConstantsBase):
|
|
|
115
119
|
@property
|
|
116
120
|
def num_cs_steps(self) -> int:
|
|
117
121
|
"""Find the number of calibration sequence steps."""
|
|
118
|
-
# NB: Uses regular BudName
|
|
119
122
|
return self._db_dict[BudName.num_cs_steps.value]
|
|
120
123
|
|
|
121
124
|
@property
|
|
@@ -144,3 +147,23 @@ class CryonirspConstants(ConstantsBase):
|
|
|
144
147
|
def axis_3_type(self) -> str:
|
|
145
148
|
"""Find the type of the third array axis."""
|
|
146
149
|
return self._db_dict[CryonirspBudName.axis_3_type.value]
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def roi_1_origin_x(self) -> int:
|
|
153
|
+
"""Get the ROI #1 x origin."""
|
|
154
|
+
return self._db_dict[CryonirspBudName.roi_1_origin_x.value]
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def roi_1_origin_y(self) -> int:
|
|
158
|
+
"""Get the ROI #1 y origin."""
|
|
159
|
+
return self._db_dict[CryonirspBudName.roi_1_origin_y.value]
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def roi_1_size_x(self) -> int:
|
|
163
|
+
"""Get the ROI #1 x size."""
|
|
164
|
+
return self._db_dict[CryonirspBudName.roi_1_size_x.value]
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def roi_1_size_y(self) -> int:
|
|
168
|
+
"""Get the ROI #1 y size."""
|
|
169
|
+
return self._db_dict[CryonirspBudName.roi_1_size_y.value]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Cryo filter list and tooling."""
|
|
2
|
+
import astropy.units as u
|
|
3
|
+
from dkist_processing_common.models.wavelength import WavelengthRange
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Filter(WavelengthRange):
|
|
7
|
+
"""
|
|
8
|
+
CRYONirsp filter data structure.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
filter_id
|
|
13
|
+
Unique ID of the filter in use
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
filter_id: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
CRYONIRSP_CI_FILTERS = [
|
|
20
|
+
Filter(filter_id="Continuum", min=1049.000 * u.nm, max=1050.000 * u.nm),
|
|
21
|
+
Filter(filter_id="FeXIII1075", min=1074.200 * u.nm, max=1075.200 * u.nm),
|
|
22
|
+
Filter(filter_id="FeXIII1080", min=1079.300 * u.nm, max=1080.300 * u.nm),
|
|
23
|
+
Filter(filter_id="HeI", min=1082.500 * u.nm, max=1083.500 * u.nm),
|
|
24
|
+
Filter(filter_id="HPaschen-beta", min=1281.300 * u.nm, max=1282.300 * u.nm),
|
|
25
|
+
Filter(filter_id="JBand", min=1170.000 * u.nm, max=1330.000 * u.nm),
|
|
26
|
+
Filter(filter_id="SiX", min=1427.500 * u.nm, max=1432.500 * u.nm),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def find_associated_ci_filter(filter_id: str) -> Filter:
|
|
31
|
+
"""
|
|
32
|
+
Given a wavelength, find the Filter that contains that wavelength between its wavemin/wavemax.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
filter_id
|
|
37
|
+
Unique ID of the filter in use
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
A Filter object that contains the wavelength
|
|
42
|
+
"""
|
|
43
|
+
matching_filters = [f for f in CRYONIRSP_CI_FILTERS if f.filter_id == filter_id]
|
|
44
|
+
if len(matching_filters) == 1:
|
|
45
|
+
return matching_filters[0]
|
|
46
|
+
raise ValueError(f"Found {len(matching_filters)} matching filters when 1 was expected.")
|
|
@@ -15,9 +15,11 @@ class CryonirspParameters(ParameterBase):
|
|
|
15
15
|
self,
|
|
16
16
|
input_dataset_parameters: dict[str, list[InputDatasetParameterValue]],
|
|
17
17
|
wavelength: float | None = None,
|
|
18
|
+
arm_id: str | None = None,
|
|
18
19
|
):
|
|
19
20
|
super().__init__(input_dataset_parameters)
|
|
20
21
|
self._wavelength = wavelength
|
|
22
|
+
self._arm_id = arm_id
|
|
21
23
|
|
|
22
24
|
@property
|
|
23
25
|
def geo_upsample_factor(self) -> float:
|
|
@@ -35,24 +37,26 @@ class CryonirspParameters(ParameterBase):
|
|
|
35
37
|
return self._find_most_recent_past_value("cryonirsp_geo_poly_fit_order")
|
|
36
38
|
|
|
37
39
|
@property
|
|
38
|
-
def
|
|
39
|
-
"""Number of pixels to shift by when computing gradient."""
|
|
40
|
-
return self._find_most_recent_past_value("
|
|
40
|
+
def geo_spatial_gradient_displacement(self) -> int:
|
|
41
|
+
"""Number of spatial pixels to shift by when computing gradient."""
|
|
42
|
+
return self._find_most_recent_past_value("cryonirsp_geo_spatial_gradient_displacement")
|
|
41
43
|
|
|
42
44
|
@property
|
|
43
|
-
def
|
|
44
|
-
"""
|
|
45
|
-
return self._find_most_recent_past_value("
|
|
45
|
+
def geo_strip_spatial_size_fraction(self) -> float:
|
|
46
|
+
"""Fraction of full spatial size to use for spatial size of strips used to find the beam angle."""
|
|
47
|
+
return self._find_most_recent_past_value("cryonirsp_geo_strip_spatial_size_fraction")
|
|
46
48
|
|
|
47
49
|
@property
|
|
48
|
-
def
|
|
49
|
-
"""
|
|
50
|
-
return self._find_most_recent_past_value("
|
|
50
|
+
def geo_strip_spectral_size_fraction(self) -> float:
|
|
51
|
+
"""Fraction of full spectral size to use for spectral size of strips used to find the beam angle."""
|
|
52
|
+
return self._find_most_recent_past_value("cryonirsp_geo_strip_spectral_size_fraction")
|
|
51
53
|
|
|
52
54
|
@property
|
|
53
|
-
def
|
|
54
|
-
"""
|
|
55
|
-
return self._find_most_recent_past_value(
|
|
55
|
+
def geo_strip_spectral_offset_size_fraction(self) -> float:
|
|
56
|
+
"""Fraction of full spectral size to set as the +/- offset from spectral center for the two strips used to find the beam angle."""
|
|
57
|
+
return self._find_most_recent_past_value(
|
|
58
|
+
"cryonirsp_geo_strip_spectral_offset_size_fraction"
|
|
59
|
+
)
|
|
56
60
|
|
|
57
61
|
@property
|
|
58
62
|
def solar_spectral_avg_window(self):
|
|
@@ -122,9 +126,22 @@ class CryonirspParameters(ParameterBase):
|
|
|
122
126
|
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_upsample_factor")
|
|
123
127
|
|
|
124
128
|
@property
|
|
125
|
-
def
|
|
129
|
+
def beam_boundaries_sp_beam_transition_region_size_fraction(self) -> float:
|
|
130
|
+
"""
|
|
131
|
+
Fraction of full spectral size to use as the size of the transition region between the two SP beams.
|
|
132
|
+
|
|
133
|
+
A region with size = (this parameter * full spectral size) and centered at the center of the spectral dimension
|
|
134
|
+
will be ignored when extracting the beams.
|
|
135
|
+
"""
|
|
136
|
+
return self._find_most_recent_past_value(
|
|
137
|
+
"cryonirsp_beam_boundaries_sp_beam_transition_region_size_fraction"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def bad_pixel_map_median_filter_size(self) -> list[int, int]:
|
|
126
142
|
"""Return the smoothing disk size to be used in the bad pixel map computation."""
|
|
127
|
-
|
|
143
|
+
filter_size = self._find_parameter_for_arm("cryonirsp_bad_pixel_map_median_filter_size")
|
|
144
|
+
return filter_size
|
|
128
145
|
|
|
129
146
|
@property
|
|
130
147
|
def bad_pixel_map_threshold_factor(self) -> float:
|
|
@@ -132,35 +149,23 @@ class CryonirspParameters(ParameterBase):
|
|
|
132
149
|
return self._find_most_recent_past_value("cryonirsp_bad_pixel_map_threshold_factor")
|
|
133
150
|
|
|
134
151
|
@property
|
|
135
|
-
def
|
|
152
|
+
def corrections_bad_pixel_median_filter_size(self) -> int:
|
|
136
153
|
"""Return the size of the median filter to be used for bad pixel correction."""
|
|
137
154
|
return self._find_most_recent_past_value(
|
|
138
|
-
"
|
|
155
|
+
"cryonirsp_corrections_bad_pixel_median_filter_size"
|
|
139
156
|
)
|
|
140
157
|
|
|
141
158
|
@cached_property
|
|
142
|
-
def
|
|
143
|
-
"""Name of parameter associated with the
|
|
144
|
-
param_dict = self.
|
|
145
|
-
return self.
|
|
146
|
-
|
|
147
|
-
@cached_property
|
|
148
|
-
def ci_polyfit(self) -> np.ndarray:
|
|
149
|
-
"""Name of parameter associated with the CI linearization polyfit coefficients."""
|
|
150
|
-
param_dict = self._find_most_recent_past_value("cryonirsp_ci_polyfit")
|
|
151
|
-
return self._get_param_data_from_npy_file(param_dict)
|
|
159
|
+
def linearization_thresholds(self) -> np.ndarray:
|
|
160
|
+
"""Name of parameter associated with the linearization thresholds."""
|
|
161
|
+
param_dict = self._find_parameter_for_arm("cryonirsp_linearization_thresholds")
|
|
162
|
+
return self._load_param_value_from_npy_file(param_dict)
|
|
152
163
|
|
|
153
164
|
@cached_property
|
|
154
|
-
def
|
|
155
|
-
"""Name of parameter associated with the
|
|
156
|
-
param_dict = self.
|
|
157
|
-
return self.
|
|
158
|
-
|
|
159
|
-
@cached_property
|
|
160
|
-
def sp_polyfit(self) -> np.ndarray:
|
|
161
|
-
"""Name of parameter associated with the SP linearization polyfit coefficients."""
|
|
162
|
-
param_dict = self._find_most_recent_past_value("cryonirsp_sp_polyfit")
|
|
163
|
-
return self._get_param_data_from_npy_file(param_dict)
|
|
165
|
+
def linearization_polyfit_coeffs(self) -> np.ndarray:
|
|
166
|
+
"""Name of parameter associated with the linearization polyfit coefficients."""
|
|
167
|
+
param_dict = self._find_parameter_for_arm("cryonirsp_linearization_polyfit_coeffs")
|
|
168
|
+
return self._load_param_value_from_npy_file(param_dict)
|
|
164
169
|
|
|
165
170
|
def _find_parameter_closest_wavelength(self, parameter_name: str) -> Any:
|
|
166
171
|
"""
|
|
@@ -186,8 +191,13 @@ class CryonirspParameters(ParameterBase):
|
|
|
186
191
|
return chosen_value
|
|
187
192
|
|
|
188
193
|
@staticmethod
|
|
189
|
-
def
|
|
194
|
+
def _load_param_value_from_npy_file(param_dict: dict) -> np.ndarray:
|
|
190
195
|
"""Return the data associated with a parameter file saved in numpy format."""
|
|
191
196
|
file_path = param_dict["param_path"]
|
|
192
197
|
result = np.load(file_path)
|
|
193
198
|
return result
|
|
199
|
+
|
|
200
|
+
def _find_parameter_for_arm(self, parameter_name: str) -> Any:
|
|
201
|
+
full_param_name = f"{parameter_name}_{self._arm_id.lower()}"
|
|
202
|
+
param = self._find_most_recent_past_value(full_param_name)
|
|
203
|
+
return param
|
|
@@ -32,6 +32,10 @@ class CryonirspRampFitsAccess(L0FitsAccess):
|
|
|
32
32
|
self.camera_readout_mode = self.header["CNCAMMD"]
|
|
33
33
|
self.curr_frame_in_ramp: int = self.header["CNCNDR"]
|
|
34
34
|
self.arm_id: str = self.header["CNARMID"]
|
|
35
|
+
self.roi_1_origin_x = self.header["HWROI1OX"]
|
|
36
|
+
self.roi_1_origin_y = self.header["HWROI1OY"]
|
|
37
|
+
self.roi_1_size_x = self.header["HWROI1SX"]
|
|
38
|
+
self.roi_1_size_y = self.header["HWROI1SY"]
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
class CryonirspL0FitsAccess(L0FitsAccess):
|
|
@@ -52,7 +52,7 @@ class SingleScanStep:
|
|
|
52
52
|
return self.date_obs < other.date_obs
|
|
53
53
|
|
|
54
54
|
def __hash__(self) -> int:
|
|
55
|
-
|
|
55
|
+
"""Not strictly necessary, but does allow for using set() on these objects."""
|
|
56
56
|
return hash(
|
|
57
57
|
(
|
|
58
58
|
self.scan_step,
|
|
@@ -104,7 +104,7 @@ class MapScanFlower(MapScanStemBase):
|
|
|
104
104
|
"""Compute the map scan number for a single frame.
|
|
105
105
|
|
|
106
106
|
The frame implies a SingleScanStep. That object is then compared to the sorted list of objects for a single
|
|
107
|
-
(raster_step, modstate) tuple. The location within that sorted list is the map scan number.
|
|
107
|
+
(raster_step, meas_num, modstate, sub_repeat) tuple. The location within that sorted list is the map scan number.
|
|
108
108
|
"""
|
|
109
109
|
scan_step_obj = self.key_to_petal_dict[key]
|
|
110
110
|
step_list = sorted(
|
|
@@ -136,7 +136,6 @@ class NumMapScansBud(MapScanStemBase):
|
|
|
136
136
|
it will not be included.
|
|
137
137
|
Assumes the incomplete map_scan is always the last one due to summit abort or cancellation.
|
|
138
138
|
"""
|
|
139
|
-
# grab header value (fits access attribute from parse file: num subrepeats) of subrepeats and loop through here
|
|
140
139
|
map_scans_per_scan_step = []
|
|
141
140
|
for meas_dict in self.scan_step_dict.values():
|
|
142
141
|
for mod_dict in meas_dict.values():
|
|
@@ -10,14 +10,10 @@ from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import Cryonirs
|
|
|
10
10
|
|
|
11
11
|
def parse_header_ip_task(fits_obj: CryonirspL0FitsAccess) -> str:
|
|
12
12
|
"""
|
|
13
|
-
Parse CryoNIRSP tasks.
|
|
13
|
+
Parse CryoNIRSP tasks that aren't fully captured by the single IPTASK keyword.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
----------
|
|
17
|
-
fits_obj:
|
|
18
|
-
A single FitsAccess object
|
|
15
|
+
Right now this just distinguishes between solar and lamp gain images.
|
|
19
16
|
"""
|
|
20
|
-
# Distinguish between lamp and solar gains
|
|
21
17
|
if (
|
|
22
18
|
fits_obj.ip_task_type.upper() == TaskName.gain.value
|
|
23
19
|
and fits_obj.gos_level3_status == "lamp"
|
|
@@ -30,7 +26,6 @@ def parse_header_ip_task(fits_obj: CryonirspL0FitsAccess) -> str:
|
|
|
30
26
|
):
|
|
31
27
|
return TaskName.solar_gain.value
|
|
32
28
|
|
|
33
|
-
# Everything else is unchanged
|
|
34
29
|
return fits_obj.ip_task_type
|
|
35
30
|
|
|
36
31
|
|
|
@@ -32,7 +32,8 @@ class CryonirspTaskExposureTimesBud(TaskExposureTimesBud):
|
|
|
32
32
|
fits_obj:
|
|
33
33
|
A single FitsAccess object
|
|
34
34
|
"""
|
|
35
|
-
|
|
35
|
+
# This is where it's different than the common `TaskExposureTimesBud`
|
|
36
|
+
ip_task_type = parse_header_ip_task(fits_obj)
|
|
36
37
|
if ip_task_type.lower() == self.ip_task_type.lower():
|
|
37
38
|
raw_exp_time = getattr(fits_obj, self.metadata_key)
|
|
38
39
|
return round(raw_exp_time, 6)
|
|
@@ -64,9 +65,9 @@ class CryonirspTimeObsBud(Stem):
|
|
|
64
65
|
"""
|
|
65
66
|
return fits_obj.time_obs
|
|
66
67
|
|
|
67
|
-
def getter(self, key: Hashable) ->
|
|
68
|
+
def getter(self, key: Hashable) -> tuple:
|
|
68
69
|
"""
|
|
69
|
-
Get the
|
|
70
|
+
Get the sorted tuple of time_obs values.
|
|
70
71
|
|
|
71
72
|
Parameters
|
|
72
73
|
----------
|
|
@@ -114,7 +114,7 @@ class CIAssembleCryonirspMovie(AssembleCryonirspMovieBase):
|
|
|
114
114
|
"""
|
|
115
115
|
map_scan_num = n // self.constants.num_scan_steps + 1
|
|
116
116
|
scan_step = n % self.constants.num_scan_steps + 1
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
tags = [
|
|
119
119
|
CryonirspTag.map_scan(map_scan_num),
|
|
120
120
|
CryonirspTag.scan_step(scan_step),
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
import scipy.ndimage as spnd
|
|
4
4
|
from dkist_processing_math.statistics import average_numpy_arrays
|
|
5
|
+
from logging42 import logger
|
|
5
6
|
|
|
6
7
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
7
8
|
from dkist_processing_cryonirsp.models.task_name import CryonirspTaskName
|
|
8
|
-
from dkist_processing_cryonirsp.models.task_name import TaskName
|
|
9
9
|
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
10
10
|
|
|
11
11
|
|
|
@@ -40,31 +40,32 @@ class BadPixelMapCalibration(CryonirspTaskBase):
|
|
|
40
40
|
None
|
|
41
41
|
|
|
42
42
|
"""
|
|
43
|
-
# Step 1:
|
|
44
43
|
with self.apm_task_step(f"Compute average uncorrected solar gain image"):
|
|
44
|
+
logger.info("Averaging uncorrected solar gain images")
|
|
45
45
|
average_solar_gain_array = self._compute_average_gain_array()
|
|
46
|
+
|
|
46
47
|
with self.apm_task_step(f"Compute the bad pixel map"):
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
48
|
+
with self.apm_processing_step("Smooth array with median filter"):
|
|
49
|
+
logger.info("Smoothing array with median filter")
|
|
50
|
+
filter_size = self.parameters.bad_pixel_map_median_filter_size
|
|
51
|
+
filtered_array = spnd.median_filter(
|
|
52
|
+
average_solar_gain_array,
|
|
53
|
+
size=filter_size,
|
|
54
|
+
mode="constant",
|
|
55
|
+
cval=np.nanmedian(average_solar_gain_array),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
with self.apm_processing_step("Identify bad pixels"):
|
|
59
|
+
logger.info("Identifying bad pixels")
|
|
60
|
+
thresh = self.parameters.bad_pixel_map_threshold_factor
|
|
61
|
+
|
|
62
|
+
diff = filtered_array - average_solar_gain_array
|
|
63
|
+
bad_pixel_map = np.array((np.abs(diff) > thresh * diff.std()), dtype=int)
|
|
64
|
+
|
|
65
|
+
# Find and fix any residual zeros that slipped through the bad pixel map.
|
|
66
|
+
zeros = np.where(average_solar_gain_array == 0.0)
|
|
67
|
+
bad_pixel_map[zeros] = 1
|
|
68
|
+
|
|
68
69
|
with self.apm_writing_step("Writing bad pixel map"):
|
|
69
70
|
self.intermediate_frame_write_arrays(
|
|
70
71
|
bad_pixel_map, task=CryonirspTaskName.bad_pixel_map.value
|
|
@@ -83,7 +84,6 @@ class BadPixelMapCalibration(CryonirspTaskBase):
|
|
|
83
84
|
-------
|
|
84
85
|
The average gain array
|
|
85
86
|
"""
|
|
86
|
-
# Get the linearized solar gain arrays
|
|
87
87
|
lin_corr_gain_arrays = self.linearized_frame_full_array_generator(
|
|
88
88
|
tags=[
|
|
89
89
|
CryonirspTag.task_solar_gain(),
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""CryoNIRSP compute beam boundary task."""
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from dkist_processing_math.statistics import average_numpy_arrays
|
|
6
|
+
from logging42 import logger
|
|
7
|
+
from skimage import filters
|
|
8
|
+
from skimage import img_as_ubyte
|
|
9
|
+
from skimage.exposure import rescale_intensity
|
|
10
|
+
from skimage.morphology import disk
|
|
11
|
+
|
|
12
|
+
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
13
|
+
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BeamBoundariesCalibrationBase(CryonirspTaskBase):
|
|
17
|
+
"""
|
|
18
|
+
Task class for calculation of the beam boundaries for later use during calibration.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
recipe_run_id : int
|
|
23
|
+
id of the recipe run used to identify the workflow run this task is part of
|
|
24
|
+
workflow_name : str
|
|
25
|
+
name of the workflow to which this instance of the task belongs
|
|
26
|
+
workflow_version : str
|
|
27
|
+
version of the workflow to which this instance of the task belongs
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def run(self):
|
|
32
|
+
"""
|
|
33
|
+
Compute the beam boundaries by analyzing a set of solar gain images.
|
|
34
|
+
|
|
35
|
+
Steps:
|
|
36
|
+
1. Compute the average gain image
|
|
37
|
+
2. Correct any bad pixels
|
|
38
|
+
3. Smooth the image using a median filter with radius 3
|
|
39
|
+
4. Use a bimodal threshold filter to segment the image into illuminated and non-illuminated regions
|
|
40
|
+
5. Compute the boundaries of the illuminated region
|
|
41
|
+
6. Extract the illuminated portion of the image
|
|
42
|
+
7. Split the beams using a 10% buffer region around the horizontal mid-point
|
|
43
|
+
8. Find the horizontal shift between the two images
|
|
44
|
+
9. Identify the boundaries of the overlap
|
|
45
|
+
10. Save the boundaries as a fits file (json?)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
None
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
# Step 1:
|
|
54
|
+
with self.apm_processing_step(f"Compute average solar gain image"):
|
|
55
|
+
logger.info("Averaging solar gain image")
|
|
56
|
+
average_solar_gain_array = self._compute_average_gain_array()
|
|
57
|
+
|
|
58
|
+
# Step 2:
|
|
59
|
+
with self.apm_task_step(f"Retrieve bad pixel map"):
|
|
60
|
+
logger.info("Retrieving bad pixel map")
|
|
61
|
+
bad_pixel_map = self.intermediate_frame_load_full_bad_pixel_map()
|
|
62
|
+
corrected_solar_gain_array = self.corrections_correct_bad_pixels(
|
|
63
|
+
average_solar_gain_array, bad_pixel_map
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Step 3
|
|
67
|
+
with self.apm_processing_step(f"Smooth the array to get good segmentation"):
|
|
68
|
+
logger.info("Smoothing corrected solar gain array")
|
|
69
|
+
smoothed_solar_gain_array = self._smooth_gain_array(corrected_solar_gain_array)
|
|
70
|
+
|
|
71
|
+
# Step 4:
|
|
72
|
+
with self.apm_processing_step(
|
|
73
|
+
f"Segment the array into illuminated and non-illuminated pixels"
|
|
74
|
+
):
|
|
75
|
+
logger.info(
|
|
76
|
+
"Segmenting smoothed solar gain array into illuminated and non-illuminated pixels "
|
|
77
|
+
)
|
|
78
|
+
segmented_array = self._segment_array(smoothed_solar_gain_array)
|
|
79
|
+
|
|
80
|
+
# Step 5:
|
|
81
|
+
with self.apm_processing_step(f"Define the boundaries of the illuminated region"):
|
|
82
|
+
logger.info("Defining boundaries of illuminated region")
|
|
83
|
+
illuminated_boundaries = self._compute_illuminated_boundaries(segmented_array)
|
|
84
|
+
|
|
85
|
+
# Steps 6 - 9:
|
|
86
|
+
with self.apm_processing_step(f"Compute the beam boundaries of the illuminated region"):
|
|
87
|
+
logger.info("Computing beam boundaries of illuminated region")
|
|
88
|
+
boundaries = self._compute_beam_boundaries(
|
|
89
|
+
smoothed_solar_gain_array, illuminated_boundaries
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Step 10:
|
|
93
|
+
with self.apm_writing_step("Writing beam boundaries"):
|
|
94
|
+
logger.info("Writing beam boundaries")
|
|
95
|
+
for beam, array in enumerate(boundaries, start=1):
|
|
96
|
+
self.intermediate_frame_write_arrays(
|
|
97
|
+
array, task_tag=CryonirspTag.task_beam_boundaries(), beam=beam
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def _compute_average_gain_array(self) -> np.ndarray:
|
|
101
|
+
"""
|
|
102
|
+
Compute an average of uncorrected solar gain arrays.
|
|
103
|
+
|
|
104
|
+
We are computing the overall illumination pattern for both beams simultaneously,
|
|
105
|
+
so no dark correction is required and no beam splitting is used at this point.
|
|
106
|
+
Solar gain images are used because they have larger flux than the lamp gain images
|
|
107
|
+
and the lamp gain images do not have the same illumination pattern as the solar
|
|
108
|
+
gain images.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
The average gain array
|
|
113
|
+
"""
|
|
114
|
+
lin_corr_gain_arrays = self.linearized_frame_full_array_generator(
|
|
115
|
+
tags=[
|
|
116
|
+
CryonirspTag.task_solar_gain(),
|
|
117
|
+
CryonirspTag.linearized(),
|
|
118
|
+
CryonirspTag.frame(),
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
averaged_gain_data = average_numpy_arrays(lin_corr_gain_arrays)
|
|
122
|
+
return averaged_gain_data
|
|
123
|
+
|
|
124
|
+
def _smooth_gain_array(self, array: np.ndarray) -> np.ndarray:
|
|
125
|
+
"""
|
|
126
|
+
Smooth the input array with morphological filtering using a disk shape.
|
|
127
|
+
|
|
128
|
+
The array is smoothed to help eliminate artifacts in the image segmentation step.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
array
|
|
133
|
+
The input array to be smoothed
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
The smoothed output array
|
|
138
|
+
"""
|
|
139
|
+
# skimage.filters requires ubyte arrays and float->ubyte conversion only works with float in range [-1, 1]
|
|
140
|
+
norm_gain = img_as_ubyte(rescale_intensity(array, out_range=(0, 1.0)))
|
|
141
|
+
|
|
142
|
+
disk_size = self.parameters.beam_boundaries_smoothing_disk_size
|
|
143
|
+
norm_gain = filters.rank.median(norm_gain, disk(disk_size))
|
|
144
|
+
return norm_gain
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _segment_array(array: np.ndarray) -> np.ndarray:
|
|
148
|
+
"""
|
|
149
|
+
Segment the array into illuminated (True) and non-illuminated (False) regions.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
array
|
|
154
|
+
The array to be segmented
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
The boolean segmented output array
|
|
159
|
+
"""
|
|
160
|
+
thresh = filters.threshold_minimum(array)
|
|
161
|
+
logger.info(f"Segmentation threshold = {thresh}")
|
|
162
|
+
segmented_array = (array > thresh).astype(bool)
|
|
163
|
+
return segmented_array
|
|
164
|
+
|
|
165
|
+
@abstractmethod
|
|
166
|
+
def _compute_illuminated_boundaries(self, array: np.ndarray) -> list[int]:
|
|
167
|
+
"""
|
|
168
|
+
Compute the inscribed rectangular extent of the illuminated portion of the array.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
array
|
|
173
|
+
The segmented boolean array over which the illuminated boundaries are to be computed
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
The illuminated region boundaries, [y_min, y_max, x_min, x_max]
|
|
178
|
+
"""
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
@abstractmethod
|
|
182
|
+
def _compute_beam_boundaries(
|
|
183
|
+
self, smoothed_solar_gain_array: np.ndarray, illuminated_boundaries: list[int]
|
|
184
|
+
):
|
|
185
|
+
"""
|
|
186
|
+
Compute the beam boundaries from the illuminated beam.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
smoothed_solar_gain_array
|
|
191
|
+
The smoothed solar gain array, ready for beam identification
|
|
192
|
+
illuminated_boundaries
|
|
193
|
+
The boundaries of the illuminated beam [y_min, y_max, x_min, x_max]
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
A list of beam boundary arrays, one for each beam
|
|
198
|
+
"""
|
|
199
|
+
pass
|