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.
Files changed (140) hide show
  1. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/CHANGELOG.rst +23 -0
  2. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/PKG-INFO +4 -6
  3. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/SCIENCE_CHANGELOG.rst +10 -0
  4. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/codecs/fits.py +3 -3
  5. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/beam_boundaries.py +13 -13
  6. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/parameters.py +27 -15
  7. dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +252 -0
  8. dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +25 -0
  9. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/dark.py +2 -2
  10. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/gain.py +3 -3
  11. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/instrument_polarization.py +4 -4
  12. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/science_base.py +2 -2
  13. dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +52 -0
  14. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_geometric.py +2 -2
  15. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_solar_gain.py +2 -2
  16. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/write_dataset_extras.py +29 -0
  17. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/conftest.py +10 -3
  18. {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
  19. {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
  20. {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
  21. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +22 -24
  22. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_instrument_polarization.py +2 -2
  23. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_parameters.py +2 -0
  24. dkist_processing_cryonirsp-3.0.0/dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +208 -0
  25. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_write_dataset_extras.py +6 -0
  26. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/ci_l0_processing.py +3 -3
  27. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/sp_l0_processing.py +3 -3
  28. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/trial_workflows.py +6 -6
  29. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/PKG-INFO +4 -6
  30. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/requires.txt +3 -5
  31. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/scm_version.json +2 -2
  32. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/dataset_extras.rst +9 -0
  33. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/pyproject.toml +5 -7
  34. dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +0 -261
  35. dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +0 -56
  36. dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +0 -271
  37. dkist_processing_cryonirsp-2.1.5/dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +0 -121
  38. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.gitignore +0 -0
  39. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.pre-commit-config.yaml +0 -0
  40. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.readthedocs.yml +0 -0
  41. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.rovodev/.review-agent.md +0 -0
  42. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/.snyk +0 -0
  43. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/README.rst +0 -0
  44. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/bitbucket-pipelines.yml +0 -0
  45. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/changelog/.gitempty +0 -0
  46. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/__init__.py +0 -0
  47. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/codecs/__init__.py +0 -0
  48. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/config.py +0 -0
  49. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/__init__.py +0 -0
  50. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/constants.py +0 -0
  51. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/dataset_extras.py +0 -0
  52. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/exposure_conditions.py +0 -0
  53. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/fits_access.py +0 -0
  54. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/tags.py +0 -0
  55. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/models/task_name.py +0 -0
  56. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/__init__.py +0 -0
  57. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/check_for_gains.py +0 -0
  58. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +0 -0
  59. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +0 -0
  60. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/exposure_conditions.py +0 -0
  61. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/map_repeats.py +0 -0
  62. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/measurements.py +0 -0
  63. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/modstates.py +0 -0
  64. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/optical_density_filters.py +0 -0
  65. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/polarimetric_check.py +0 -0
  66. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/scan_step.py +0 -0
  67. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/parsers/time.py +0 -0
  68. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/__init__.py +0 -0
  69. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/assemble_movie.py +0 -0
  70. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/bad_pixel_map.py +0 -0
  71. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/ci_science.py +0 -0
  72. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/cryonirsp_base.py +0 -0
  73. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/l1_output_data.py +0 -0
  74. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/linearity_correction.py +0 -0
  75. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/make_movie_frames.py +0 -0
  76. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/__init__.py +0 -0
  77. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/corrections.py +0 -0
  78. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/mixin/shift_measurements.py +0 -0
  79. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/parse.py +0 -0
  80. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/polcal_as_science.py +0 -0
  81. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/quality_metrics.py +0 -0
  82. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_science.py +0 -0
  83. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/sp_wavelength_calibration.py +0 -0
  84. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tasks/write_l1.py +0 -0
  85. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/__init__.py +0 -0
  86. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/header_models.py +0 -0
  87. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/__init__.py +0 -0
  88. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/local_trial_workflows/linearize_only.py +0 -0
  89. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_assemble_movie.py +0 -0
  90. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_assemble_qualilty.py +0 -0
  91. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +0 -0
  92. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_ci_science.py +0 -0
  93. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_corrections.py +0 -0
  94. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_cryo_base.py +0 -0
  95. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_cryo_constants.py +0 -0
  96. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_dark.py +0 -0
  97. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_fits_access.py +0 -0
  98. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_gain.py +0 -0
  99. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_linearity_correction.py +0 -0
  100. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_make_movie_frames.py +0 -0
  101. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_parse.py +0 -0
  102. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_polcal_as_science.py +0 -0
  103. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_quality.py +0 -0
  104. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_geometric.py +0 -0
  105. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +0 -0
  106. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_science.py +0 -0
  107. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_solar.py +0 -0
  108. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_sp_wavelength_calibration.py +0 -0
  109. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_trial_create_quality_report.py +0 -0
  110. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_workflows.py +0 -0
  111. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/tests/test_write_l1.py +0 -0
  112. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp/workflows/__init__.py +0 -0
  113. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/SOURCES.txt +0 -0
  114. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/dependency_links.txt +0 -0
  115. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/scm_file_list.json +0 -0
  116. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/dkist_processing_cryonirsp.egg-info/top_level.txt +0 -0
  117. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/Makefile +0 -0
  118. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/bad_pixel_calibration.rst +0 -0
  119. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/beam_angle_calculation.rst +0 -0
  120. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/beam_boundary_computation.rst +0 -0
  121. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/changelog.rst +0 -0
  122. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/ci_science_calibration.rst +0 -0
  123. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/conf.py +0 -0
  124. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/index.rst +0 -0
  125. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_ci-full-trial.rst +0 -0
  126. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_ci.rst +0 -0
  127. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_sp-full-trial.rst +0 -0
  128. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/l0_to_l1_cryonirsp_sp.rst +0 -0
  129. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/landing_page.rst +0 -0
  130. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/linearization.rst +0 -0
  131. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/make.bat +0 -0
  132. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/requirements.txt +0 -0
  133. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/requirements_table.rst +0 -0
  134. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/scientific_changelog.rst +0 -0
  135. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/sp_science_calibration.rst +0 -0
  136. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/docs/wavelength_calibration.rst +0 -0
  137. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/licenses/LICENSE.rst +0 -0
  138. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/science_towncrier.sh +0 -0
  139. {dkist_processing_cryonirsp-2.1.5 → dkist_processing_cryonirsp-3.0.0}/setup.cfg +0 -0
  140. {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: 2.1.5
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.109; extra == "frozen"
118
- Requires-Dist: botocore==1.43.109; extra == "frozen"
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==2.1.5; extra == "frozen"
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 BeamBoundary
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: BeamBoundary | None = None,
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: BeamBoundary | None = None,
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 BeamBoundary:
9
+ class BeamBoundaries:
10
10
  """Simple dataclass to hold boundary information for the illuminated portion of the beam array."""
11
11
 
12
- y_min: int
13
- y_max: int
14
- x_min: int
15
- x_max: int
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 y_slice(self):
19
- """Return a slice object representing the illumination along the y-axis (numpy 0 axis)."""
20
- return slice(self.y_min, self.y_max)
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 x_slice(self):
24
- """Return a slice object representing the illumination along the x-axis (numpy 1 axis)."""
25
- return slice(self.x_min, self.x_max)
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.y_slice, self.x_slice
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.y_min, self.y_max, self.x_min, self.x_max
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 beam_boundaries_smoothing_disk_size(self) -> int:
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
- Fraction of full spectral size to use as the size of the transition region between the two SP beams.
115
+ Return a list of `slice` objects that extract beams in the spectral dimension.
126
116
 
127
- A region with size = (this parameter * full spectral size) and centered at the center of the spectral dimension
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
- "cryonirsp_beam_boundaries_sp_beam_transition_region_size_fraction"
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 BeamBoundary
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 = BeamBoundary(*beam_array)
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 BeamBoundary
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 = BeamBoundary(*beam_array)
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 = BeamBoundary(*beam_array)
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 BeamBoundary
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 = BeamBoundary(*beam_array)
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 = BeamBoundary(*beam_array)
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 = BeamBoundary(*beam_array)
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 BeamBoundary
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 = BeamBoundary(*beam_array)
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