dkist-processing-cryonirsp 2.1.5__tar.gz → 3.0.0__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.
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/CHANGELOG.rst +23 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/PKG-INFO +4 -6
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/SCIENCE_CHANGELOG.rst +10 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/codecs/fits.py +3 -3
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/beam_boundaries.py +13 -13
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/parameters.py +27 -15
- dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +252 -0
- dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +25 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/dark.py +2 -2
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/gain.py +3 -3
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/instrument_polarization.py +4 -4
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/science_base.py +2 -2
- dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +52 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_geometric.py +2 -2
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_solar_gain.py +2 -2
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/write_dataset_extras.py +29 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/conftest.py +10 -3
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +14 -14
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +14 -14
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +4 -4
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +22 -24
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_instrument_polarization.py +2 -2
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_parameters.py +2 -0
- dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +208 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_write_dataset_extras.py +6 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/ci_l0_processing.py +3 -3
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/sp_l0_processing.py +3 -3
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/trial_workflows.py +6 -6
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/PKG-INFO +4 -6
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/requires.txt +3 -5
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/scm_version.json +2 -2
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/dataset_extras.rst +9 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/pyproject.toml +5 -7
- dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +0 -261
- dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +0 -56
- dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +0 -271
- dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +0 -121
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.gitignore +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.pre-commit-config.yaml +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.readthedocs.yml +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.rovodev/.review-agent.md +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.snyk +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/README.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/bitbucket-pipelines.yml +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/changelog/.gitempty +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/codecs/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/config.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/constants.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/dataset_extras.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/exposure_conditions.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/fits_access.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/tags.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/task_name.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/check_for_gains.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/exposure_conditions.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/map_repeats.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/measurements.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/modstates.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/optical_density_filters.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/polarimetric_check.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/scan_step.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/time.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/assemble_movie.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/bad_pixel_map.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/ci_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/cryonirsp_base.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/l1_output_data.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/linearity_correction.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/make_movie_frames.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/corrections.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/shift_measurements.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/parse.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/polcal_as_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/quality_metrics.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_wavelength_calibration.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/write_l1.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/header_models.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/linearize_only.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_assemble_movie.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_assemble_qualilty.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_ci_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_corrections.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_cryo_base.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_cryo_constants.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_dark.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_fits_access.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_gain.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_linearity_correction.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_make_movie_frames.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_parse.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_polcal_as_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_quality.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_geometric.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_science.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_solar.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_wavelength_calibration.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_trial_create_quality_report.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_workflows.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_write_l1.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/__init__.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/SOURCES.txt +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/dependency_links.txt +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/scm_file_list.json +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/top_level.txt +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/Makefile +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/bad_pixel_calibration.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/beam_angle_calculation.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/beam_boundary_computation.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/changelog.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/ci_science_calibration.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/conf.py +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/index.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_ci-full-trial.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_ci.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_sp-full-trial.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_sp.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/landing_page.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/linearization.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/make.bat +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/requirements.txt +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/requirements_table.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/scientific_changelog.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/sp_science_calibration.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/wavelength_calibration.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/licenses/LICENSE.rst +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/science_towncrier.sh +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/setup.cfg +0 -0
- {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/towncrier_science.toml +0 -0
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
v3.0.0 (2026-10-08)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
Features
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
- Replace `BeamBoundariesCalibration` task with `SpatialBeamBoundaries`, which only computes the boundaries of the illuminated region along the spatial axis.
|
|
8
|
+
The spectral axis (or second spatial axis, for CI) boundaries are hard-coded as a pipeline parameter. (`#306 <https://bitbucket.org/dkistdc/dkist-processing-cryonirsp/pull-requests/306>`__)
|
|
9
|
+
- Save the full set of beam boundaries used to extract illuminated regions from the raw data as a dataset extra (called "BEAM_BOUNDARIES"). (`#306 <https://bitbucket.org/dkistdc/dkist-processing-cryonirsp/pull-requests/306>`__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Misc
|
|
13
|
+
----
|
|
14
|
+
|
|
15
|
+
- Replace "y" and "x" language with "axis_0" and "axis_1", respectively, in the `BeamBoundaries` model. (`#306 <https://bitbucket.org/dkistdc/dkist-processing-cryonirsp/pull-requests/306>`__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Documentation
|
|
19
|
+
-------------
|
|
20
|
+
|
|
21
|
+
- Update online documentation "Dataset Extras" page to include information about the beam boundaries extra. (`#306 <https://bitbucket.org/dkistdc/dkist-processing-cryonirsp/pull-requests/306>`__)
|
|
22
|
+
|
|
23
|
+
|
|
1
24
|
v2.1.5 (2026-10-08)
|
|
2
25
|
===================
|
|
3
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dkist-processing-cryonirsp
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Science processing code for the Cryo-NIRSP instrument on DKIST
|
|
5
5
|
Author-email: NSO / AURA <dkistdc@nso.edu>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -22,7 +22,6 @@ Requires-Dist: dkist-processing-math==2.2.3
|
|
|
22
22
|
Requires-Dist: dkist-processing-pac==3.1.2
|
|
23
23
|
Requires-Dist: dkist-spectral-lines==3.0.1
|
|
24
24
|
Requires-Dist: solar-wavelength-calibration==2.0.4
|
|
25
|
-
Requires-Dist: largestinteriorrectangle==0.2.1
|
|
26
25
|
Requires-Dist: dkist-service-configuration==4.3.0
|
|
27
26
|
Requires-Dist: moviepy==2.1.2
|
|
28
27
|
Requires-Dist: numba==0.61.2
|
|
@@ -114,8 +113,8 @@ Requires-Dist: babel==2.18.0; extra == "frozen"
|
|
|
114
113
|
Requires-Dist: beautifulsoup4==4.15.0; extra == "frozen"
|
|
115
114
|
Requires-Dist: billiard==4.3.1; extra == "frozen"
|
|
116
115
|
Requires-Dist: bleach==6.4.0; extra == "frozen"
|
|
117
|
-
Requires-Dist: boto3==1.43.
|
|
118
|
-
Requires-Dist: botocore==1.43.
|
|
116
|
+
Requires-Dist: boto3==1.43.110; extra == "frozen"
|
|
117
|
+
Requires-Dist: botocore==1.43.110; extra == "frozen"
|
|
119
118
|
Requires-Dist: cachetools==7.2.1; extra == "frozen"
|
|
120
119
|
Requires-Dist: cadwyn==7.0.0; extra == "frozen"
|
|
121
120
|
Requires-Dist: celery==5.6.3; extra == "frozen"
|
|
@@ -141,7 +140,7 @@ Requires-Dist: dill==0.4.1; extra == "frozen"
|
|
|
141
140
|
Requires-Dist: dkist-header-validator==6.0.0; extra == "frozen"
|
|
142
141
|
Requires-Dist: dkist-processing-common==14.6.0; extra == "frozen"
|
|
143
142
|
Requires-Dist: dkist-processing-core==7.5.0; extra == "frozen"
|
|
144
|
-
Requires-Dist: dkist-processing-cryonirsp==
|
|
143
|
+
Requires-Dist: dkist-processing-cryonirsp==3.0.0; extra == "frozen"
|
|
145
144
|
Requires-Dist: dkist-processing-math==2.2.3; extra == "frozen"
|
|
146
145
|
Requires-Dist: dkist-processing-pac==3.1.2; extra == "frozen"
|
|
147
146
|
Requires-Dist: dkist-service-configuration==4.3.0; extra == "frozen"
|
|
@@ -196,7 +195,6 @@ Requires-Dist: jupyterlab_pygments==0.3.0; extra == "frozen"
|
|
|
196
195
|
Requires-Dist: jupyterlab_server==2.28.1; extra == "frozen"
|
|
197
196
|
Requires-Dist: kiwisolver==1.5.1; extra == "frozen"
|
|
198
197
|
Requires-Dist: kombu==5.6.2; extra == "frozen"
|
|
199
|
-
Requires-Dist: largestinteriorrectangle==0.2.1; extra == "frozen"
|
|
200
198
|
Requires-Dist: lark==1.3.1; extra == "frozen"
|
|
201
199
|
Requires-Dist: lazy-loader==0.6; extra == "frozen"
|
|
202
200
|
Requires-Dist: lazy-object-proxy==1.12.0; extra == "frozen"
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
v3.0.0 (2026-10-08)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
- The task that computes the boundaries of the useful, illuminated regions of the INPUT data has been simplified and made more robust to data with very high
|
|
8
|
+
dynamic range. This improvement will most affect data taken at 1430nm, but will slightly change the final array shape for all data. (`#306 <https://bitbucket.org/dkistdc/dkist-processing-cryonirsp/pull-requests/306>`__)
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
v2.0.0 (2026-07-17)
|
|
2
12
|
===================
|
|
3
13
|
|
|
@@ -6,13 +6,13 @@ import numpy as np
|
|
|
6
6
|
from dkist_processing_common.codecs.fits import fits_access_decoder as common_fits_access_decoder
|
|
7
7
|
from dkist_processing_common.models.fits_access import FitsAccessBase
|
|
8
8
|
|
|
9
|
-
from dkist_processing_cryonirsp.models.beam_boundaries import
|
|
9
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def cryo_fits_access_decoder(
|
|
13
13
|
path: Path,
|
|
14
14
|
fits_access_class: FitsAccessBase = FitsAccessBase,
|
|
15
|
-
beam_boundary:
|
|
15
|
+
beam_boundary: BeamBoundaries | None = None,
|
|
16
16
|
**fits_access_kwargs,
|
|
17
17
|
) -> FitsAccessBase:
|
|
18
18
|
"""
|
|
@@ -33,7 +33,7 @@ def cryo_fits_access_decoder(
|
|
|
33
33
|
def cryo_fits_array_decoder(
|
|
34
34
|
path: Path,
|
|
35
35
|
fits_access_class: FitsAccessBase = FitsAccessBase,
|
|
36
|
-
beam_boundary:
|
|
36
|
+
beam_boundary: BeamBoundaries | None = None,
|
|
37
37
|
auto_squeeze: bool = True,
|
|
38
38
|
**fits_access_kwargs,
|
|
39
39
|
) -> np.array:
|
|
@@ -6,33 +6,33 @@ import numpy as np
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@dataclass
|
|
9
|
-
class
|
|
9
|
+
class BeamBoundaries:
|
|
10
10
|
"""Simple dataclass to hold boundary information for the illuminated portion of the beam array."""
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
axis_0_min: int
|
|
13
|
+
axis_0_max: int
|
|
14
|
+
axis_1_min: int
|
|
15
|
+
axis_1_max: int
|
|
16
16
|
|
|
17
17
|
@property
|
|
18
|
-
def
|
|
19
|
-
"""Return a slice object representing the illumination along the
|
|
20
|
-
return slice(self.
|
|
18
|
+
def axis_0_slice(self):
|
|
19
|
+
"""Return a slice object representing the illumination along the 0th axis."""
|
|
20
|
+
return slice(self.axis_0_min, self.axis_0_max)
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
|
-
def
|
|
24
|
-
"""Return a slice object representing the illumination along the
|
|
25
|
-
return slice(self.
|
|
23
|
+
def axis_1_slice(self):
|
|
24
|
+
"""Return a slice object representing the illumination along the 1st axis."""
|
|
25
|
+
return slice(self.axis_1_min, self.axis_1_max)
|
|
26
26
|
|
|
27
27
|
@property
|
|
28
28
|
def slices(self):
|
|
29
29
|
"""Return a tuple of slices in numpy order representing the illuminated portion of the beam array."""
|
|
30
|
-
return self.
|
|
30
|
+
return self.axis_0_slice, self.axis_1_slice
|
|
31
31
|
|
|
32
32
|
@property
|
|
33
33
|
def beam_boundaries(self):
|
|
34
34
|
"""Return a tuple containing the beam boundaries."""
|
|
35
|
-
return self.
|
|
35
|
+
return self.axis_0_min, self.axis_0_max, self.axis_1_min, self.axis_1_max
|
|
36
36
|
|
|
37
37
|
@property
|
|
38
38
|
def beam_boundaries_array(self):
|
|
@@ -110,27 +110,39 @@ class CryonirspParameters(ParameterBase, ParameterWavelengthMixin, ParameterArmI
|
|
|
110
110
|
return self._find_most_recent_past_value("cryonirsp_polcal_pac_fit_mode")
|
|
111
111
|
|
|
112
112
|
@property
|
|
113
|
-
def
|
|
114
|
-
"""Return the size of the smoothing disk (in pixels) to be used in the beam boundaries computation."""
|
|
115
|
-
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_smoothing_disk_size")
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
def beam_boundaries_upsample_factor(self) -> int:
|
|
119
|
-
"""Return the upsample factor to be used in the beam boundaries cross correlation computation."""
|
|
120
|
-
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_upsample_factor")
|
|
121
|
-
|
|
122
|
-
@property
|
|
123
|
-
def beam_boundaries_sp_beam_transition_region_size_fraction(self) -> float:
|
|
113
|
+
def beam_boundaries_spectral_beam_slices(self) -> list[slice]:
|
|
124
114
|
"""
|
|
125
|
-
|
|
115
|
+
Return a list of `slice` objects that extract beams in the spectral dimension.
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
will be ignored when extracting the beams.
|
|
117
|
+
For CI the "spectral" dimension is just the same axis of the chip that is spectral in SP data.
|
|
129
118
|
"""
|
|
119
|
+
raw_boundaries = self._find_parameter_for_arm(
|
|
120
|
+
"cryonirsp_beam_boundaries_spectral_beam_slices"
|
|
121
|
+
)
|
|
122
|
+
return [slice(b[0], b[1]) for b in raw_boundaries]
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def beam_boundaries_normalization_percentile(self) -> float:
|
|
126
|
+
"""Return the percentile (0, 100) used when collapsing the wavelength dimension into a single spatial profile."""
|
|
130
127
|
return self._find_most_recent_past_value(
|
|
131
|
-
"
|
|
128
|
+
"cryonirsp_beam_boundaries_normalization_percentile"
|
|
132
129
|
)
|
|
133
130
|
|
|
131
|
+
@property
|
|
132
|
+
def beam_boundaries_edge_profile_window_px(self) -> int:
|
|
133
|
+
"""Return the size of the moving window used to compute an edge profile."""
|
|
134
|
+
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_edge_profile_window_px")
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def beam_boundaries_edge_threshold_sigma(self) -> float:
|
|
138
|
+
"""Return the threshold for determining if an illumination edge is strong enough to consider, in units of edge profile sigma."""
|
|
139
|
+
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_edge_threshold_sigma")
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def beam_boundaries_detector_margin_px(self) -> int:
|
|
143
|
+
"""Return the padding amount from the detector edge that sets a hard limit on the illumination regions."""
|
|
144
|
+
return self._find_most_recent_past_value("cryonirsp_beam_boundaries_detector_margin_px")
|
|
145
|
+
|
|
134
146
|
@property
|
|
135
147
|
def bad_pixel_map_median_filter_size(self) -> list[int, int]:
|
|
136
148
|
"""Return the smoothing disk size to be used in the bad pixel map computation."""
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Task for computing the spatial boundaries of CryoNIRSP data."""
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from dkist_processing_common.codecs.fits import fits_array_encoder
|
|
7
|
+
from dkist_processing_math.statistics import average_numpy_arrays
|
|
8
|
+
from dkist_service_configuration.logging import logger
|
|
9
|
+
from scipy import stats
|
|
10
|
+
|
|
11
|
+
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
12
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
13
|
+
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
14
|
+
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import (
|
|
15
|
+
CryonirspLinearizedFitsAccess,
|
|
16
|
+
)
|
|
17
|
+
from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
|
|
18
|
+
|
|
19
|
+
__all__ = ["SpatialBeamBoundariesBase"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SpatialBeamBoundariesBase(CryonirspTaskBase):
|
|
23
|
+
"""
|
|
24
|
+
Task class for calculating the illuminated beam boundaries in the spatial dimension for later use during calibration.
|
|
25
|
+
|
|
26
|
+
For CI data the term "spatial" here refers to the same chip dimension that corresponds to the spatial dimension in
|
|
27
|
+
SP data (numpy axis 0).
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
recipe_run_id : int
|
|
32
|
+
id of the recipe run used to identify the workflow run this task is part of
|
|
33
|
+
|
|
34
|
+
workflow_name : str
|
|
35
|
+
name of the workflow to which this instance of the task belongs
|
|
36
|
+
|
|
37
|
+
workflow_version : str
|
|
38
|
+
version of the workflow to which this instance of the task belongs
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
record_provenance = True
|
|
42
|
+
num_beams: int = -1
|
|
43
|
+
|
|
44
|
+
def run(self):
|
|
45
|
+
"""
|
|
46
|
+
Compute the beam boundaries by analyzing a set of solar gain images.
|
|
47
|
+
|
|
48
|
+
Steps:
|
|
49
|
+
|
|
50
|
+
#. Compute the average gain image
|
|
51
|
+
|
|
52
|
+
#. For each beam
|
|
53
|
+
|
|
54
|
+
i. Extract the beam's spectral extent
|
|
55
|
+
|
|
56
|
+
#. Collapse along the spectral dimension to form a 1D spatial signal
|
|
57
|
+
|
|
58
|
+
#. Use a moving window comparison to construct a profile showing sharp changes in intensity
|
|
59
|
+
|
|
60
|
+
#. Take the maximum and minimum peaks of this profile to be the edges of the illuminated region
|
|
61
|
+
|
|
62
|
+
#. Adjust the regions so all beams have the same shape
|
|
63
|
+
|
|
64
|
+
#. Write the computed spatial bounds and the spectral bounds from `parameters` to scratch
|
|
65
|
+
|
|
66
|
+
NOTE: When this method refers to the "spectral" dimension for CI data we really mean the spatial dimension that
|
|
67
|
+
corresponds to the chip axis that is the spectral dimension in SP data (numpy axis 1).
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
None
|
|
72
|
+
"""
|
|
73
|
+
with self.telemetry_span(f"Compute average solar gain image"):
|
|
74
|
+
average_solar_gain_array = self.compute_average_gain_array()
|
|
75
|
+
|
|
76
|
+
beam_boundaries = []
|
|
77
|
+
for beam in range(1, self.num_beams + 1):
|
|
78
|
+
with self.telemetry_span(f"Calculating spatial boundaries for beam {beam}"):
|
|
79
|
+
beam_array = self.extract_spectral_beam(average_solar_gain_array, beam)
|
|
80
|
+
|
|
81
|
+
spatial_signal = np.nanpercentile(
|
|
82
|
+
beam_array, self.parameters.beam_boundaries_normalization_percentile, axis=1
|
|
83
|
+
)
|
|
84
|
+
# Not really necessary, but helps us compare some debug numbers across datasets
|
|
85
|
+
spatial_signal /= np.nanmax(spatial_signal)
|
|
86
|
+
|
|
87
|
+
edge_profile = self.compute_edge_profile(
|
|
88
|
+
spatial_signal, window=self.parameters.beam_boundaries_edge_profile_window_px
|
|
89
|
+
)
|
|
90
|
+
min_edge, max_edge = self.find_edges(
|
|
91
|
+
edge_profile,
|
|
92
|
+
threshold_sigma=self.parameters.beam_boundaries_edge_threshold_sigma,
|
|
93
|
+
detector_margin=self.parameters.beam_boundaries_detector_margin_px,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
beam_boundaries.append((min_edge, max_edge))
|
|
97
|
+
|
|
98
|
+
with self.telemetry_span("Matching beam sizes"):
|
|
99
|
+
spatial_size = beam_array.shape[0]
|
|
100
|
+
matched_spatial_boundaries = self.match_beam_sizes(
|
|
101
|
+
beam_boundaries, full_spatial_size=spatial_size
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
with self.telemetry_span("Writing beam boundaries"):
|
|
105
|
+
final_beam_boundaries = self.construct_final_boundaries_objects(
|
|
106
|
+
matched_spatial_boundaries
|
|
107
|
+
)
|
|
108
|
+
for beam, bounds in enumerate(final_beam_boundaries, start=1):
|
|
109
|
+
self.write(
|
|
110
|
+
data=bounds.beam_boundaries_array,
|
|
111
|
+
tags=[
|
|
112
|
+
CryonirspTag.intermediate_frame(beam=beam),
|
|
113
|
+
CryonirspTag.task_beam_boundaries(),
|
|
114
|
+
],
|
|
115
|
+
encoder=fits_array_encoder,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def compute_average_gain_array(self) -> np.ndarray:
|
|
119
|
+
"""
|
|
120
|
+
Compute an average of uncorrected solar gain arrays.
|
|
121
|
+
|
|
122
|
+
We are computing the overall illumination pattern for both beams simultaneously,
|
|
123
|
+
so no dark correction is required and no beam splitting is used at this point.
|
|
124
|
+
Solar gain images are used because they have larger flux than the lamp gain images
|
|
125
|
+
and the lamp gain images do not have the same illumination pattern as the solar
|
|
126
|
+
gain images.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
The average gain array
|
|
131
|
+
"""
|
|
132
|
+
lin_corr_gain_arrays = self.read(
|
|
133
|
+
tags=[CryonirspTag.linearized_frame(), CryonirspTag.task_solar_gain()],
|
|
134
|
+
decoder=cryo_fits_array_decoder,
|
|
135
|
+
fits_access_class=CryonirspLinearizedFitsAccess,
|
|
136
|
+
)
|
|
137
|
+
averaged_gain_data = average_numpy_arrays(lin_corr_gain_arrays)
|
|
138
|
+
spatial_edge_mask = self.parameters.beam_boundaries_detector_margin_px
|
|
139
|
+
|
|
140
|
+
# Fill in the masked edge regions with a spatial constant copied from the first pixel past the masked region
|
|
141
|
+
start_edge_good_signal = averaged_gain_data[spatial_edge_mask + 1, :]
|
|
142
|
+
end_edge_good_signal = averaged_gain_data[-(spatial_edge_mask + 1), :]
|
|
143
|
+
|
|
144
|
+
averaged_gain_data[:spatial_edge_mask, :] = start_edge_good_signal[None, :]
|
|
145
|
+
averaged_gain_data[-spatial_edge_mask:, :] = end_edge_good_signal[None, :]
|
|
146
|
+
return averaged_gain_data
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def compute_edge_profile(spatial_signal: np.ndarray, window: int) -> np.ndarray:
|
|
150
|
+
"""
|
|
151
|
+
Compute a profile showing sharp changes in intensity.
|
|
152
|
+
|
|
153
|
+
Each point in the profile is calculated as the mean intensity ``window`` pixels beyond that point minus the mean
|
|
154
|
+
intensity ``window`` pixels before that point.
|
|
155
|
+
|
|
156
|
+
Values within ``window`` pixels of the start/end of the array are set to NaN.
|
|
157
|
+
"""
|
|
158
|
+
moving_mean = np.convolve(spatial_signal, np.ones(window), "valid") / window
|
|
159
|
+
|
|
160
|
+
profile = np.full_like(spatial_signal, np.nan)
|
|
161
|
+
profile[window : len(profile) - (window - 1)] = moving_mean[window:] - moving_mean[:-window]
|
|
162
|
+
return profile
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def find_edges(
|
|
166
|
+
edge_profile: np.ndarray, threshold_sigma: float, detector_margin: int
|
|
167
|
+
) -> tuple[int, int]:
|
|
168
|
+
"""
|
|
169
|
+
Identify peaks in an edge profile.
|
|
170
|
+
|
|
171
|
+
The location of the maximum change in the profile is taken to be the minimum edge of the illuminated beam while
|
|
172
|
+
the location of the most negative change in the profile is taken to be the maximum edge illuminated beam.
|
|
173
|
+
|
|
174
|
+
Both edges are checked to ensure they are significant enough by comparing their value to a threshold controlled
|
|
175
|
+
by ``threshold_sigma``. Edges that are below the threshold are interpreted as being essentially at the edge of
|
|
176
|
+
the array and set to simply be ``detector_margin`` pixels away from the edge.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
`[min_edge_idx, max_edge_idx]`
|
|
181
|
+
"""
|
|
182
|
+
threshold = threshold_sigma * stats.median_abs_deviation(
|
|
183
|
+
edge_profile, nan_policy="omit", scale="normal"
|
|
184
|
+
)
|
|
185
|
+
num_pix = len(edge_profile)
|
|
186
|
+
|
|
187
|
+
bottom_candidate = np.nanargmax(edge_profile)
|
|
188
|
+
top_candidate = np.nanargmin(edge_profile)
|
|
189
|
+
|
|
190
|
+
if bottom_candidate > top_candidate:
|
|
191
|
+
# If the edges appear flipped around
|
|
192
|
+
# This could potentially happen if there is some sharp signal right at the edge of the otherwise-unilluminated
|
|
193
|
+
# detector that gets interpreted as a spurious edge. In this case we make the assumption that the true beginning
|
|
194
|
+
# of illumination is in the first half of the detector and the true end of illumination is in the second half.
|
|
195
|
+
logger.info(
|
|
196
|
+
"Edge profile increasing/decreasing peaks appear to be swapped. This is likely due to spurious edges. Restricting search to half the chip for each."
|
|
197
|
+
)
|
|
198
|
+
half_idx = edge_profile.size // 2
|
|
199
|
+
bottom_candidate = np.nanargmax(edge_profile[:half_idx])
|
|
200
|
+
top_candidate = np.nanargmin(edge_profile[half_idx:]) + half_idx
|
|
201
|
+
|
|
202
|
+
min_edge = (
|
|
203
|
+
bottom_candidate if edge_profile[bottom_candidate] > threshold else detector_margin
|
|
204
|
+
)
|
|
205
|
+
max_edge = (
|
|
206
|
+
top_candidate if edge_profile[top_candidate] < -threshold else num_pix - detector_margin
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return min_edge, max_edge
|
|
210
|
+
|
|
211
|
+
def construct_final_boundaries_objects(
|
|
212
|
+
self, spatial_boundary_list: list[tuple[int, int]]
|
|
213
|
+
) -> list[BeamBoundaries]:
|
|
214
|
+
"""Package the computed spatial boundaries with the spectral boundaries from parameters into `~dkist_processing_cryonirsp.models.beam_boundaries.BeamBoundaries` objects."""
|
|
215
|
+
spectral_slices = self.parameters.beam_boundaries_spectral_beam_slices
|
|
216
|
+
|
|
217
|
+
output_list = []
|
|
218
|
+
for spatial_boundaries, spectral_slice in zip(spatial_boundary_list, spectral_slices):
|
|
219
|
+
spatial_min, spatial_max = spatial_boundaries
|
|
220
|
+
boundary_obj = BeamBoundaries(
|
|
221
|
+
axis_0_min=spatial_min,
|
|
222
|
+
axis_0_max=spatial_max,
|
|
223
|
+
axis_1_min=spectral_slice.start,
|
|
224
|
+
axis_1_max=spectral_slice.stop,
|
|
225
|
+
)
|
|
226
|
+
output_list.append(boundary_obj)
|
|
227
|
+
|
|
228
|
+
return output_list
|
|
229
|
+
|
|
230
|
+
def extract_spectral_beam(self, array: np.ndarray, beam: int) -> np.ndarray:
|
|
231
|
+
"""
|
|
232
|
+
Split the beams along the "spectral" axis (axis 1).
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
array
|
|
237
|
+
The array to be split
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
[array, ...]
|
|
242
|
+
A list of arrays after the split
|
|
243
|
+
"""
|
|
244
|
+
slices = self.parameters.beam_boundaries_spectral_beam_slices
|
|
245
|
+
return array[:, slices[beam - 1]]
|
|
246
|
+
|
|
247
|
+
@abstractmethod
|
|
248
|
+
def match_beam_sizes(
|
|
249
|
+
self, beam_boundary_list: list[tuple[int, int]], full_spatial_size: int
|
|
250
|
+
) -> list[tuple[int, int]]:
|
|
251
|
+
"""Ensure that all spatial beam boundaries produce arrays of the same shape."""
|
|
252
|
+
pass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Cryonirsp CI beam boundaries task."""
|
|
2
|
+
|
|
3
|
+
from dkist_service_configuration.logging import logger
|
|
4
|
+
|
|
5
|
+
from dkist_processing_cryonirsp.tasks.beam_boundaries_base import SpatialBeamBoundariesBase
|
|
6
|
+
|
|
7
|
+
__all__ = ["CISpatialBeamBoundaries"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CISpatialBeamBoundaries(SpatialBeamBoundariesBase):
|
|
11
|
+
"""Task class for calculation of the CI beam boundaries for later use during calibration."""
|
|
12
|
+
|
|
13
|
+
num_beams = 1
|
|
14
|
+
|
|
15
|
+
def match_beam_sizes(
|
|
16
|
+
self, beam_boundary_list: list[tuple[int, int]], full_spatial_size: int
|
|
17
|
+
) -> list[tuple[int, int]]:
|
|
18
|
+
"""
|
|
19
|
+
Ensure that all spatial beam boundaries produce arrays of the same shape.
|
|
20
|
+
|
|
21
|
+
For CI there is only one beam so we just return the input boundaries.
|
|
22
|
+
"""
|
|
23
|
+
logger.info(f"Full array spatial boundaries = {beam_boundary_list[0]}")
|
|
24
|
+
|
|
25
|
+
return beam_boundary_list
|
|
@@ -6,7 +6,7 @@ from dkist_processing_math.statistics import average_numpy_arrays
|
|
|
6
6
|
from dkist_service_configuration.logging import logger
|
|
7
7
|
|
|
8
8
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
9
|
-
from dkist_processing_cryonirsp.models.beam_boundaries import
|
|
9
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
10
10
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
11
11
|
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import (
|
|
12
12
|
CryonirspLinearizedFitsAccess,
|
|
@@ -70,7 +70,7 @@ class DarkCalibration(CryonirspTaskBase):
|
|
|
70
70
|
decoder=cryo_fits_array_decoder,
|
|
71
71
|
)
|
|
72
72
|
)
|
|
73
|
-
beam_boundary =
|
|
73
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
74
74
|
|
|
75
75
|
for exposure_conditions in target_exposure_conditions:
|
|
76
76
|
logger.info(
|
|
@@ -10,7 +10,7 @@ from dkist_processing_math.statistics import average_numpy_arrays
|
|
|
10
10
|
from dkist_service_configuration.logging import logger
|
|
11
11
|
|
|
12
12
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
13
|
-
from dkist_processing_cryonirsp.models.beam_boundaries import
|
|
13
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
14
14
|
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
15
15
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
16
16
|
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import (
|
|
@@ -92,7 +92,7 @@ class GainCalibrationBase(CryonirspTaskBase):
|
|
|
92
92
|
decoder=cryo_fits_array_decoder,
|
|
93
93
|
)
|
|
94
94
|
)
|
|
95
|
-
beam_boundary =
|
|
95
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
96
96
|
|
|
97
97
|
for exposure_conditions in target_exposure_conditions:
|
|
98
98
|
apm_str = f"{beam = } and {exposure_conditions = }"
|
|
@@ -190,7 +190,7 @@ class GainCalibrationBase(CryonirspTaskBase):
|
|
|
190
190
|
decoder=cryo_fits_array_decoder,
|
|
191
191
|
)
|
|
192
192
|
)
|
|
193
|
-
beam_boundary =
|
|
193
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
194
194
|
tags = CryonirspTag.linearized_frame(exposure_conditions=exposure_conditions) + [
|
|
195
195
|
self.gain_tag
|
|
196
196
|
]
|
|
@@ -20,7 +20,7 @@ from dkist_service_configuration.logging import logger
|
|
|
20
20
|
|
|
21
21
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_access_decoder
|
|
22
22
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
23
|
-
from dkist_processing_cryonirsp.models.beam_boundaries import
|
|
23
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
24
24
|
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
25
25
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
26
26
|
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import CryonirspL0FitsAccess
|
|
@@ -250,7 +250,7 @@ class InstrumentPolarizationCalibrationBase(CryonirspTaskBase, ABC):
|
|
|
250
250
|
decoder=cryo_fits_array_decoder,
|
|
251
251
|
)
|
|
252
252
|
)
|
|
253
|
-
beam_boundary =
|
|
253
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
254
254
|
polcal_tags = [
|
|
255
255
|
CryonirspTag.linearized_frame(exposure_conditions=exposure_conditions),
|
|
256
256
|
CryonirspTag.cs_step(cs_step),
|
|
@@ -374,7 +374,7 @@ class InstrumentPolarizationCalibrationBase(CryonirspTaskBase, ABC):
|
|
|
374
374
|
decoder=cryo_fits_array_decoder,
|
|
375
375
|
)
|
|
376
376
|
)
|
|
377
|
-
beam_boundary =
|
|
377
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
378
378
|
for exposure_conditions in target_exposure_conditions_list:
|
|
379
379
|
with self.telemetry_span(
|
|
380
380
|
f"Calculating polcal dark array(s) for {exposure_conditions = } and {beam = }"
|
|
@@ -417,7 +417,7 @@ class InstrumentPolarizationCalibrationBase(CryonirspTaskBase, ABC):
|
|
|
417
417
|
decoder=cryo_fits_array_decoder,
|
|
418
418
|
)
|
|
419
419
|
)
|
|
420
|
-
beam_boundary =
|
|
420
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
421
421
|
for exposure_conditions in exposure_conditions_list:
|
|
422
422
|
logger.info(
|
|
423
423
|
f"Load polcal dark array for {exposure_conditions = } and {beam = }"
|
|
@@ -20,7 +20,7 @@ from dkist_service_configuration.logging import logger
|
|
|
20
20
|
|
|
21
21
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_access_decoder
|
|
22
22
|
from dkist_processing_cryonirsp.codecs.fits import cryo_fits_array_decoder
|
|
23
|
-
from dkist_processing_cryonirsp.models.beam_boundaries import
|
|
23
|
+
from dkist_processing_cryonirsp.models.beam_boundaries import BeamBoundaries
|
|
24
24
|
from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
|
|
25
25
|
from dkist_processing_cryonirsp.models.tags import CryonirspTag
|
|
26
26
|
from dkist_processing_cryonirsp.parsers.cryonirsp_l0_fits_access import CryonirspL0FitsAccess
|
|
@@ -156,7 +156,7 @@ class ScienceCalibrationBase(CryonirspTaskBase, ABC):
|
|
|
156
156
|
decoder=cryo_fits_array_decoder,
|
|
157
157
|
)
|
|
158
158
|
)
|
|
159
|
-
beam_boundary =
|
|
159
|
+
beam_boundary = BeamBoundaries(*beam_array)
|
|
160
160
|
observe_object_tags = self.build_observe_file_tags(
|
|
161
161
|
map_scan=map_scan,
|
|
162
162
|
scan_step=scan_step,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Cryonirsp SP beam boundaries task."""
|
|
2
|
+
|
|
3
|
+
from dkist_service_configuration.logging import logger
|
|
4
|
+
|
|
5
|
+
from dkist_processing_cryonirsp.tasks.beam_boundaries_base import SpatialBeamBoundariesBase
|
|
6
|
+
|
|
7
|
+
__all__ = ["SPSpatialBeamBoundaries"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SPSpatialBeamBoundaries(SpatialBeamBoundariesBase):
|
|
11
|
+
"""Task class for calculation of the SP spatial beam boundaries for later use during calibration."""
|
|
12
|
+
|
|
13
|
+
num_beams = 2
|
|
14
|
+
|
|
15
|
+
def match_beam_sizes(
|
|
16
|
+
self, beam_boundary_list: list[tuple[int, int]], full_spatial_size: int
|
|
17
|
+
) -> list[tuple[int, int]]:
|
|
18
|
+
"""
|
|
19
|
+
Ensure that all spatial beam boundaries produce arrays of the same shape.
|
|
20
|
+
|
|
21
|
+
The final spatial size for both beams is simply the smalles size represented in the raw boundaries; the beam that
|
|
22
|
+
is larger will have its boundaries adjusted to match the smaller size. This adjustment is only made to one side
|
|
23
|
+
of the boundaries: the side that is closest to the detector edge. The logic here is that a boundary farther from
|
|
24
|
+
the detector edge is more likely to be the real edge of illumination (as opposed to simply the edge of the detector),
|
|
25
|
+
which we take to be a more valid location for the absolute position of that beam.
|
|
26
|
+
"""
|
|
27
|
+
beam1_boundaries, beam2_boundaries = beam_boundary_list
|
|
28
|
+
|
|
29
|
+
beam1_size = beam1_boundaries[1] - beam1_boundaries[0]
|
|
30
|
+
beam2_size = beam2_boundaries[1] - beam2_boundaries[0]
|
|
31
|
+
|
|
32
|
+
final_beam_size = min(beam1_size, beam2_size)
|
|
33
|
+
|
|
34
|
+
logger.info(f"{beam1_size = :d}, {beam2_size = :d} => {final_beam_size = :d}")
|
|
35
|
+
|
|
36
|
+
final_boundary_objects = []
|
|
37
|
+
for beam, (boundaries, size) in enumerate(
|
|
38
|
+
zip(beam_boundary_list, [beam1_size, beam2_size]), start=1
|
|
39
|
+
):
|
|
40
|
+
size_diff = size - final_beam_size
|
|
41
|
+
|
|
42
|
+
logger.info(f"Beam {beam} has {size_diff = :d}")
|
|
43
|
+
logger.info(f"Raw spatial boundaries = {boundaries}")
|
|
44
|
+
if boundaries[0] > full_spatial_size - boundaries[1]:
|
|
45
|
+
logger.info(f"Adjusting boundary by -{size_diff} at high end")
|
|
46
|
+
final_boundary_objects.append((boundaries[0], boundaries[1] - size_diff))
|
|
47
|
+
else:
|
|
48
|
+
logger.info(f"Adjusting boundary by {size_diff} at low end")
|
|
49
|
+
final_boundary_objects.append((boundaries[0] + size_diff, boundaries[1]))
|
|
50
|
+
logger.info(f"New spatial boundaries = {final_boundary_objects[-1]}")
|
|
51
|
+
|
|
52
|
+
return final_boundary_objects
|