dkist-processing-visp 5.7.15__tar.gz → 5.7.16__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 (119) hide show
  1. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/CHANGELOG.rst +9 -0
  2. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/PKG-INFO +8 -8
  3. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/mixin/corrections.py +78 -16
  4. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/science.py +4 -0
  5. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_science.py +3 -3
  6. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp.egg-info/PKG-INFO +8 -8
  7. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp.egg-info/requires.txt +7 -7
  8. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/pyproject.toml +9 -9
  9. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/.gitignore +0 -0
  10. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/.pre-commit-config.yaml +0 -0
  11. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/.readthedocs.yml +0 -0
  12. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/.rovodev/.review-agent.md +0 -0
  13. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/.snyk +0 -0
  14. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/README.rst +0 -0
  15. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/SCIENCE_CHANGELOG.rst +0 -0
  16. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/bitbucket-pipelines.yml +0 -0
  17. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/changelog/.gitempty +0 -0
  18. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/__init__.py +0 -0
  19. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/config.py +0 -0
  20. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/fonts/Lato-Regular.ttf +0 -0
  21. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/__init__.py +0 -0
  22. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/constants.py +0 -0
  23. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/dataset_extras.py +0 -0
  24. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/fits_access.py +0 -0
  25. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/metric_code.py +0 -0
  26. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/parameters.py +0 -0
  27. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/tags.py +0 -0
  28. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/models/task_name.py +0 -0
  29. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/__init__.py +0 -0
  30. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/map_repeats.py +0 -0
  31. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/modulator_states.py +0 -0
  32. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/polarimeter_mode.py +0 -0
  33. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/raster_step.py +0 -0
  34. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/spectrograph_configuration.py +0 -0
  35. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/time.py +0 -0
  36. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/visp_l0_fits_access.py +0 -0
  37. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/parsers/visp_l1_fits_access.py +0 -0
  38. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/__init__.py +0 -0
  39. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/assemble_movie.py +0 -0
  40. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/background_light.py +0 -0
  41. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/dark.py +0 -0
  42. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/geometric.py +0 -0
  43. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/instrument_polarization.py +0 -0
  44. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/l1_output_data.py +0 -0
  45. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/lamp.py +0 -0
  46. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/make_movie_frames.py +0 -0
  47. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/mixin/__init__.py +0 -0
  48. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/mixin/beam_access.py +0 -0
  49. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/mixin/downsample.py +0 -0
  50. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/parse.py +0 -0
  51. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/polcal_as_science.py +0 -0
  52. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/quality_metrics.py +0 -0
  53. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/solar.py +0 -0
  54. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/visp_base.py +0 -0
  55. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/wavelength_calibration.py +0 -0
  56. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/write_dataset_extras.py +0 -0
  57. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tasks/write_l1.py +0 -0
  58. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/README.rst +0 -0
  59. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/__init__.py +0 -0
  60. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/conftest.py +0 -0
  61. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/header_models.py +0 -0
  62. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/__init__.py +0 -0
  63. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/l0_cals_only.py +0 -0
  64. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/l0_polcals_as_science.py +0 -0
  65. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/l0_solar_gain_as_science.py +0 -0
  66. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/l0_to_l1.py +0 -0
  67. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/local_trial_workflows/local_trial_helpers.py +0 -0
  68. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_assemble_movie.py +0 -0
  69. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_assemble_quality.py +0 -0
  70. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_background_light.py +0 -0
  71. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_dark.py +0 -0
  72. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_downsample.py +0 -0
  73. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_fits_access.py +0 -0
  74. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_geometric.py +0 -0
  75. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_instrument_polarization.py +0 -0
  76. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_lamp.py +0 -0
  77. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_make_movie_frames.py +0 -0
  78. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_map_repeats.py +0 -0
  79. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_parameters.py +0 -0
  80. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_parse.py +0 -0
  81. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_polcal_as_science.py +0 -0
  82. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_quality.py +0 -0
  83. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_solar.py +0 -0
  84. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_trial_create_quality_report.py +0 -0
  85. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_visp_base.py +0 -0
  86. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_visp_constants.py +0 -0
  87. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_wavelength_calibration.py +0 -0
  88. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_workflows.py +0 -0
  89. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_write_dataset_extras.py +0 -0
  90. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/tests/test_write_l1.py +0 -0
  91. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/workflows/__init__.py +0 -0
  92. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/workflows/l0_processing.py +0 -0
  93. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/workflows/single_task_workflows.py +0 -0
  94. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp/workflows/trial_workflows.py +0 -0
  95. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp.egg-info/SOURCES.txt +0 -0
  96. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp.egg-info/dependency_links.txt +0 -0
  97. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/dkist_processing_visp.egg-info/top_level.txt +0 -0
  98. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/Makefile +0 -0
  99. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/background_light.rst +0 -0
  100. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/changelog.rst +0 -0
  101. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/conf.py +0 -0
  102. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/dataset_extras.rst +0 -0
  103. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/gain_correction.rst +0 -0
  104. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/geometric.rst +0 -0
  105. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/index.rst +0 -0
  106. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/l0_to_l1_visp.rst +0 -0
  107. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/l0_to_l1_visp_full-trial.rst +0 -0
  108. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/landing_page.rst +0 -0
  109. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/make.bat +0 -0
  110. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/polarization_calibration.rst +0 -0
  111. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/requirements.txt +0 -0
  112. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/requirements_table.rst +0 -0
  113. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/science_calibration.rst +0 -0
  114. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/scientific_changelog.rst +0 -0
  115. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/docs/wavelength_calibration.rst +0 -0
  116. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/licenses/LICENSE.rst +0 -0
  117. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/science_towncrier.sh +0 -0
  118. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/setup.cfg +0 -0
  119. {dkist_processing_visp-5.7.15 → dkist_processing_visp-5.7.16}/towncrier_science.toml +0 -0
@@ -1,3 +1,12 @@
1
+ v5.7.16 (2026-05-28)
2
+ ====================
3
+
4
+ Misc
5
+ ----
6
+
7
+ - Combine the translation and rotation steps of the geometric correction into a single interpolation. This preserves the existing science calibration behavior while simplifying the transform math and reducing repeated processing during geometry correction. (`#317 <https://bitbucket.org/dkistdc/dkist-processing-visp/pull-requests/317>`__)
8
+
9
+
1
10
  v5.7.15 (2026-05-27)
2
11
  ====================
3
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-visp
3
- Version: 5.7.15
3
+ Version: 5.7.16
4
4
  Summary: Science processing code for the ViSP instrument on DKIST
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -118,8 +118,8 @@ Requires-Dist: babel==2.18.0; extra == "frozen"
118
118
  Requires-Dist: beautifulsoup4==4.14.3; extra == "frozen"
119
119
  Requires-Dist: billiard==4.2.4; extra == "frozen"
120
120
  Requires-Dist: bleach==6.3.0; extra == "frozen"
121
- Requires-Dist: boto3==1.43.15; extra == "frozen"
122
- Requires-Dist: botocore==1.43.15; extra == "frozen"
121
+ Requires-Dist: boto3==1.43.16; extra == "frozen"
122
+ Requires-Dist: botocore==1.43.16; extra == "frozen"
123
123
  Requires-Dist: cadwyn==6.2.2; extra == "frozen"
124
124
  Requires-Dist: celery==5.6.3; extra == "frozen"
125
125
  Requires-Dist: certifi==2026.5.20; extra == "frozen"
@@ -145,7 +145,7 @@ Requires-Dist: dkist-processing-common==14.3.2; extra == "frozen"
145
145
  Requires-Dist: dkist-processing-core==7.3.0; extra == "frozen"
146
146
  Requires-Dist: dkist-processing-math==2.2.2; extra == "frozen"
147
147
  Requires-Dist: dkist-processing-pac==3.1.2; extra == "frozen"
148
- Requires-Dist: dkist-processing-visp==5.7.15; extra == "frozen"
148
+ Requires-Dist: dkist-processing-visp==5.7.16; extra == "frozen"
149
149
  Requires-Dist: dkist-service-configuration==4.3.0; extra == "frozen"
150
150
  Requires-Dist: dkist-spectral-lines==3.0.1; extra == "frozen"
151
151
  Requires-Dist: dkist_fits_specifications==4.26.0; extra == "frozen"
@@ -171,7 +171,7 @@ Requires-Dist: httpcore==1.0.9; extra == "frozen"
171
171
  Requires-Dist: httptools==0.8.0; extra == "frozen"
172
172
  Requires-Dist: httpx==0.28.1; extra == "frozen"
173
173
  Requires-Dist: humanize==4.15.0; extra == "frozen"
174
- Requires-Dist: idna==3.16; extra == "frozen"
174
+ Requires-Dist: idna==3.17; extra == "frozen"
175
175
  Requires-Dist: imageio-ffmpeg==0.6.0; extra == "frozen"
176
176
  Requires-Dist: importlib_metadata==9.0.0; extra == "frozen"
177
177
  Requires-Dist: ipykernel==7.2.0; extra == "frozen"
@@ -262,7 +262,7 @@ Requires-Dist: pexpect==4.9.0; extra == "frozen"
262
262
  Requires-Dist: pika==1.4.1; extra == "frozen"
263
263
  Requires-Dist: pillow==10.4.0; extra == "frozen"
264
264
  Requires-Dist: pip==26.1.1; extra == "frozen"
265
- Requires-Dist: platformdirs==4.9.6; extra == "frozen"
265
+ Requires-Dist: platformdirs==4.10.0; extra == "frozen"
266
266
  Requires-Dist: pluggy==1.6.0; extra == "frozen"
267
267
  Requires-Dist: pooch==1.9.0; extra == "frozen"
268
268
  Requires-Dist: proglog==0.1.12; extra == "frozen"
@@ -299,7 +299,7 @@ Requires-Dist: rfc3987-syntax==1.1.0; extra == "frozen"
299
299
  Requires-Dist: rich==15.0.0; extra == "frozen"
300
300
  Requires-Dist: rich-argparse==1.8.0; extra == "frozen"
301
301
  Requires-Dist: rich-toolkit==0.19.10; extra == "frozen"
302
- Requires-Dist: rpds-py==0.30.0; extra == "frozen"
302
+ Requires-Dist: rpds-py==2026.5.1; extra == "frozen"
303
303
  Requires-Dist: s3transfer==0.17.1; extra == "frozen"
304
304
  Requires-Dist: scikit-image==0.25.2; extra == "frozen"
305
305
  Requires-Dist: scikit-learn==1.6.1; extra == "frozen"
@@ -328,7 +328,7 @@ Requires-Dist: text-unidecode==1.3; extra == "frozen"
328
328
  Requires-Dist: threadpoolctl==3.6.0; extra == "frozen"
329
329
  Requires-Dist: tifffile==2026.5.15; extra == "frozen"
330
330
  Requires-Dist: tinycss2==1.4.0; extra == "frozen"
331
- Requires-Dist: tornado==6.5.5; extra == "frozen"
331
+ Requires-Dist: tornado==6.5.6; extra == "frozen"
332
332
  Requires-Dist: tqdm==4.67.3; extra == "frozen"
333
333
  Requires-Dist: traitlets==5.15.0; extra == "frozen"
334
334
  Requires-Dist: typer==0.26.2; extra == "frozen"
@@ -5,19 +5,42 @@ from typing import Iterable
5
5
 
6
6
  import numpy as np
7
7
  import scipy.ndimage as spnd
8
- from dkist_processing_math.transform import affine_transform_arrays
9
- from dkist_processing_math.transform import rotate_arrays_about_point
8
+ from scipy.ndimage import affine_transform
10
9
 
11
10
 
12
11
  class CorrectionsMixin:
13
12
  """Mixin to provide support for various array corrections used by the workflow tasks."""
14
13
 
14
+ @staticmethod
15
+ def _geometry_inverse_transform(
16
+ array_shape: tuple[int, ...], shift: np.ndarray, angle: float
17
+ ) -> tuple[np.ndarray, np.ndarray]:
18
+ """
19
+ Build the inverse transform used by `scipy.ndimage.affine_transform`.
20
+
21
+ The forward correction translates by `-shift` and then rotates by `-angle`
22
+ about the array center. `affine_transform` instead wants the mapping from
23
+ output coordinates back to input coordinates, so we supply the inverse
24
+ rotation matrix and the corresponding center-preserving offset here.
25
+ """
26
+ cosine_angle = np.cos(angle)
27
+ sine_angle = np.sin(angle)
28
+ inverse_rotation_matrix = np.array(
29
+ [[cosine_angle, -sine_angle], [sine_angle, cosine_angle]],
30
+ dtype=np.float64,
31
+ )
32
+
33
+ rotation_center = 0.5 * (np.asarray(array_shape, dtype=np.float64) - 1.0)
34
+ transform_offset = rotation_center + shift - inverse_rotation_matrix @ rotation_center
35
+
36
+ return inverse_rotation_matrix, transform_offset
37
+
15
38
  @staticmethod
16
39
  def corrections_correct_geometry(
17
40
  arrays: Iterable[np.ndarray] | np.ndarray,
18
41
  shift: np.ndarray = np.zeros(2),
19
42
  angle: float = 0.0,
20
- mode: str = "edge",
43
+ mode: str = "nearest",
21
44
  order: int = 5,
22
45
  cval: float = np.nan,
23
46
  ) -> Generator[np.ndarray, None, None]:
@@ -38,7 +61,7 @@ class CorrectionsMixin:
38
61
  angle : float
39
62
  The angle (in radians) between slit hairlines and pixel axes.
40
63
 
41
- mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}
64
+ mode : {'constant', 'nearest', 'symmetric', 'reflect', 'wrap'}
42
65
  Points outside the boundaries of the input are filled according
43
66
  to the given mode. Modes match the behaviour of `numpy.pad`.
44
67
 
@@ -61,19 +84,58 @@ class CorrectionsMixin:
61
84
  Generator
62
85
  2D array(s) containing the data of the rotated and shifted beam
63
86
  """
64
- arrays = [arrays] if isinstance(arrays, np.ndarray) else arrays
65
- for array in arrays:
66
- array = array.astype(np.float64)
67
- array[np.where(array == np.inf)] = np.max(array[np.isfinite(array)])
68
- array[np.where(array == -np.inf)] = np.min(array[np.isfinite(array)])
69
- array[np.isnan(array)] = np.nanmedian(array)
70
- translated = affine_transform_arrays(
71
- array, translation=-shift, mode=mode, order=order, cval=cval
72
- )
73
- yield next(
74
- rotate_arrays_about_point(
75
- translated, angle=-angle, mode=mode, order=order, cval=cval
87
+ uncorrected_arrays = (arrays,) if isinstance(arrays, np.ndarray) else arrays
88
+ shift = np.asarray(shift, dtype=np.float64)
89
+
90
+ previous_array_shape = None
91
+ inverse_transform_matrix = None
92
+ transform_offset = None
93
+
94
+ for array in uncorrected_arrays:
95
+ input_array = np.asarray(array, dtype=np.float64)
96
+
97
+ # `affine_transform` does not handle NaN and inf values well, so normalize them
98
+ # before interpolation. We identify the finite pixels once and reuse those
99
+ # results instead of rescanning the full array for each replacement case.
100
+ finite_pixel_mask = np.isfinite(input_array)
101
+ if not finite_pixel_mask.all():
102
+ finite_pixel_values = input_array[finite_pixel_mask]
103
+
104
+ if finite_pixel_values.size == 0:
105
+ input_array.fill(cval if np.isfinite(cval) else np.nan)
106
+ else:
107
+ # Replace +inf, -inf, and NaN using the finite pixels we already
108
+ # collected, and only computing the replacement values if necessary.
109
+ positive_infinity_mask = np.isposinf(input_array)
110
+ if positive_infinity_mask.any():
111
+ input_array[positive_infinity_mask] = finite_pixel_values.max()
112
+
113
+ negative_infinity_mask = np.isneginf(input_array)
114
+ if negative_infinity_mask.any():
115
+ input_array[negative_infinity_mask] = finite_pixel_values.min()
116
+
117
+ nan_pixel_mask = np.isnan(input_array)
118
+ if nan_pixel_mask.any():
119
+ input_array[nan_pixel_mask] = np.nanmedian(input_array)
120
+
121
+ if input_array.shape != previous_array_shape:
122
+ inverse_transform_matrix, transform_offset = (
123
+ CorrectionsMixin._geometry_inverse_transform(
124
+ array_shape=input_array.shape,
125
+ shift=shift,
126
+ angle=angle,
127
+ )
76
128
  )
129
+ previous_array_shape = input_array.shape
130
+
131
+ yield affine_transform(
132
+ input_array,
133
+ matrix=inverse_transform_matrix,
134
+ offset=transform_offset,
135
+ order=order,
136
+ mode=mode,
137
+ cval=cval,
138
+ prefilter=(order > 1),
77
139
  )
78
140
 
79
141
  @staticmethod
@@ -1,5 +1,6 @@
1
1
  """ViSP science calibration task. See :doc:`this page </science_calibration>` for more information."""
2
2
 
3
+ import time
3
4
  from collections import defaultdict
4
5
  from dataclasses import dataclass
5
6
  from functools import cached_property
@@ -140,6 +141,7 @@ class ScienceCalibration(
140
141
  None
141
142
 
142
143
  """
144
+ start = time.perf_counter()
143
145
  with self.telemetry_span("Loading calibration objects"):
144
146
  calibrations = self.collect_calibration_objects()
145
147
 
@@ -162,6 +164,8 @@ class ScienceCalibration(
162
164
  self.quality_write_intermediate_task_type_counts(
163
165
  task_type=TaskName.observe.value, total_frames=no_of_raw_science_frames
164
166
  )
167
+ elapsed = time.perf_counter() - start
168
+ logger.info(f"Science task completed in {elapsed:.2f} s")
165
169
 
166
170
  def collect_calibration_objects(self) -> CalibrationCollection:
167
171
  """
@@ -683,9 +683,9 @@ def test_generate_nan_mask(science_calibration_task, dummy_calibration_collectio
683
683
  solar_gain_array = calibration_collection.solar_gain[VispTag.beam(beam)]
684
684
  angle = calibration_collection.angle[VispTag.beam(beam)]
685
685
  spec_shift = calibration_collection.spec_shift[VispTag.beam(beam)]
686
- state_offset = calibration_collection.state_offset[VispTag.beam(beam)][
687
- VispTag.modstate(modstate)
688
- ]
686
+ # Use a non-zero shift so the geometric correction creates edge pixels that
687
+ # should be masked in the final binary NaN mask.
688
+ state_offset = np.array([1.0, 0.0])
689
689
  nan_mask = task.generate_nan_mask(
690
690
  solar_corrected_array=np.random.random(size=solar_gain_array.shape),
691
691
  state_offset=state_offset,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-visp
3
- Version: 5.7.15
3
+ Version: 5.7.16
4
4
  Summary: Science processing code for the ViSP instrument on DKIST
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -118,8 +118,8 @@ Requires-Dist: babel==2.18.0; extra == "frozen"
118
118
  Requires-Dist: beautifulsoup4==4.14.3; extra == "frozen"
119
119
  Requires-Dist: billiard==4.2.4; extra == "frozen"
120
120
  Requires-Dist: bleach==6.3.0; extra == "frozen"
121
- Requires-Dist: boto3==1.43.15; extra == "frozen"
122
- Requires-Dist: botocore==1.43.15; extra == "frozen"
121
+ Requires-Dist: boto3==1.43.16; extra == "frozen"
122
+ Requires-Dist: botocore==1.43.16; extra == "frozen"
123
123
  Requires-Dist: cadwyn==6.2.2; extra == "frozen"
124
124
  Requires-Dist: celery==5.6.3; extra == "frozen"
125
125
  Requires-Dist: certifi==2026.5.20; extra == "frozen"
@@ -145,7 +145,7 @@ Requires-Dist: dkist-processing-common==14.3.2; extra == "frozen"
145
145
  Requires-Dist: dkist-processing-core==7.3.0; extra == "frozen"
146
146
  Requires-Dist: dkist-processing-math==2.2.2; extra == "frozen"
147
147
  Requires-Dist: dkist-processing-pac==3.1.2; extra == "frozen"
148
- Requires-Dist: dkist-processing-visp==5.7.15; extra == "frozen"
148
+ Requires-Dist: dkist-processing-visp==5.7.16; extra == "frozen"
149
149
  Requires-Dist: dkist-service-configuration==4.3.0; extra == "frozen"
150
150
  Requires-Dist: dkist-spectral-lines==3.0.1; extra == "frozen"
151
151
  Requires-Dist: dkist_fits_specifications==4.26.0; extra == "frozen"
@@ -171,7 +171,7 @@ Requires-Dist: httpcore==1.0.9; extra == "frozen"
171
171
  Requires-Dist: httptools==0.8.0; extra == "frozen"
172
172
  Requires-Dist: httpx==0.28.1; extra == "frozen"
173
173
  Requires-Dist: humanize==4.15.0; extra == "frozen"
174
- Requires-Dist: idna==3.16; extra == "frozen"
174
+ Requires-Dist: idna==3.17; extra == "frozen"
175
175
  Requires-Dist: imageio-ffmpeg==0.6.0; extra == "frozen"
176
176
  Requires-Dist: importlib_metadata==9.0.0; extra == "frozen"
177
177
  Requires-Dist: ipykernel==7.2.0; extra == "frozen"
@@ -262,7 +262,7 @@ Requires-Dist: pexpect==4.9.0; extra == "frozen"
262
262
  Requires-Dist: pika==1.4.1; extra == "frozen"
263
263
  Requires-Dist: pillow==10.4.0; extra == "frozen"
264
264
  Requires-Dist: pip==26.1.1; extra == "frozen"
265
- Requires-Dist: platformdirs==4.9.6; extra == "frozen"
265
+ Requires-Dist: platformdirs==4.10.0; extra == "frozen"
266
266
  Requires-Dist: pluggy==1.6.0; extra == "frozen"
267
267
  Requires-Dist: pooch==1.9.0; extra == "frozen"
268
268
  Requires-Dist: proglog==0.1.12; extra == "frozen"
@@ -299,7 +299,7 @@ Requires-Dist: rfc3987-syntax==1.1.0; extra == "frozen"
299
299
  Requires-Dist: rich==15.0.0; extra == "frozen"
300
300
  Requires-Dist: rich-argparse==1.8.0; extra == "frozen"
301
301
  Requires-Dist: rich-toolkit==0.19.10; extra == "frozen"
302
- Requires-Dist: rpds-py==0.30.0; extra == "frozen"
302
+ Requires-Dist: rpds-py==2026.5.1; extra == "frozen"
303
303
  Requires-Dist: s3transfer==0.17.1; extra == "frozen"
304
304
  Requires-Dist: scikit-image==0.25.2; extra == "frozen"
305
305
  Requires-Dist: scikit-learn==1.6.1; extra == "frozen"
@@ -328,7 +328,7 @@ Requires-Dist: text-unidecode==1.3; extra == "frozen"
328
328
  Requires-Dist: threadpoolctl==3.6.0; extra == "frozen"
329
329
  Requires-Dist: tifffile==2026.5.15; extra == "frozen"
330
330
  Requires-Dist: tinycss2==1.4.0; extra == "frozen"
331
- Requires-Dist: tornado==6.5.5; extra == "frozen"
331
+ Requires-Dist: tornado==6.5.6; extra == "frozen"
332
332
  Requires-Dist: tqdm==4.67.3; extra == "frozen"
333
333
  Requires-Dist: traitlets==5.15.0; extra == "frozen"
334
334
  Requires-Dist: typer==0.26.2; extra == "frozen"
@@ -84,8 +84,8 @@ babel==2.18.0
84
84
  beautifulsoup4==4.14.3
85
85
  billiard==4.2.4
86
86
  bleach==6.3.0
87
- boto3==1.43.15
88
- botocore==1.43.15
87
+ boto3==1.43.16
88
+ botocore==1.43.16
89
89
  cadwyn==6.2.2
90
90
  celery==5.6.3
91
91
  certifi==2026.5.20
@@ -111,7 +111,7 @@ dkist-processing-common==14.3.2
111
111
  dkist-processing-core==7.3.0
112
112
  dkist-processing-math==2.2.2
113
113
  dkist-processing-pac==3.1.2
114
- dkist-processing-visp==5.7.15
114
+ dkist-processing-visp==5.7.16
115
115
  dkist-service-configuration==4.3.0
116
116
  dkist-spectral-lines==3.0.1
117
117
  dkist_fits_specifications==4.26.0
@@ -137,7 +137,7 @@ httpcore==1.0.9
137
137
  httptools==0.8.0
138
138
  httpx==0.28.1
139
139
  humanize==4.15.0
140
- idna==3.16
140
+ idna==3.17
141
141
  imageio-ffmpeg==0.6.0
142
142
  importlib_metadata==9.0.0
143
143
  ipykernel==7.2.0
@@ -228,7 +228,7 @@ pexpect==4.9.0
228
228
  pika==1.4.1
229
229
  pillow==10.4.0
230
230
  pip==26.1.1
231
- platformdirs==4.9.6
231
+ platformdirs==4.10.0
232
232
  pluggy==1.6.0
233
233
  pooch==1.9.0
234
234
  proglog==0.1.12
@@ -265,7 +265,7 @@ rfc3987-syntax==1.1.0
265
265
  rich==15.0.0
266
266
  rich-argparse==1.8.0
267
267
  rich-toolkit==0.19.10
268
- rpds-py==0.30.0
268
+ rpds-py==2026.5.1
269
269
  s3transfer==0.17.1
270
270
  scikit-image==0.25.2
271
271
  scikit-learn==1.6.1
@@ -294,7 +294,7 @@ text-unidecode==1.3
294
294
  threadpoolctl==3.6.0
295
295
  tifffile==2026.5.15
296
296
  tinycss2==1.4.0
297
- tornado==6.5.5
297
+ tornado==6.5.6
298
298
  tqdm==4.67.3
299
299
  traitlets==5.15.0
300
300
  typer==0.26.2
@@ -9,8 +9,8 @@ exclude = ["build*"]
9
9
 
10
10
  [tool.dkist-dev-tools]
11
11
  # Most recently frozen version by dkist-dev-tools
12
- version = "5.7.15"
13
- date = 2026-05-27T06:45:45.578458
12
+ version = "5.7.16"
13
+ date = 2026-05-28T12:17:45.447074
14
14
 
15
15
  [project]
16
16
  dynamic = ["version"]
@@ -146,8 +146,8 @@ frozen = [
146
146
  "beautifulsoup4 == 4.14.3",
147
147
  "billiard == 4.2.4",
148
148
  "bleach == 6.3.0",
149
- "boto3 == 1.43.15",
150
- "botocore == 1.43.15",
149
+ "boto3 == 1.43.16",
150
+ "botocore == 1.43.16",
151
151
  "cadwyn == 6.2.2",
152
152
  "celery == 5.6.3",
153
153
  "certifi == 2026.5.20",
@@ -173,7 +173,7 @@ frozen = [
173
173
  "dkist-processing-core == 7.3.0",
174
174
  "dkist-processing-math == 2.2.2",
175
175
  "dkist-processing-pac == 3.1.2",
176
- "dkist-processing-visp == 5.7.15",
176
+ "dkist-processing-visp == 5.7.16",
177
177
  "dkist-service-configuration == 4.3.0",
178
178
  "dkist-spectral-lines == 3.0.1",
179
179
  "dkist_fits_specifications == 4.26.0",
@@ -199,7 +199,7 @@ frozen = [
199
199
  "httptools == 0.8.0",
200
200
  "httpx == 0.28.1",
201
201
  "humanize == 4.15.0",
202
- "idna == 3.16",
202
+ "idna == 3.17",
203
203
  "imageio-ffmpeg == 0.6.0",
204
204
  "importlib_metadata == 9.0.0",
205
205
  "ipykernel == 7.2.0",
@@ -290,7 +290,7 @@ frozen = [
290
290
  "pika == 1.4.1",
291
291
  "pillow == 10.4.0",
292
292
  "pip == 26.1.1",
293
- "platformdirs == 4.9.6",
293
+ "platformdirs == 4.10.0",
294
294
  "pluggy == 1.6.0",
295
295
  "pooch == 1.9.0",
296
296
  "proglog == 0.1.12",
@@ -327,7 +327,7 @@ frozen = [
327
327
  "rich == 15.0.0",
328
328
  "rich-argparse == 1.8.0",
329
329
  "rich-toolkit == 0.19.10",
330
- "rpds-py == 0.30.0",
330
+ "rpds-py == 2026.5.1",
331
331
  "s3transfer == 0.17.1",
332
332
  "scikit-image == 0.25.2",
333
333
  "scikit-learn == 1.6.1",
@@ -356,7 +356,7 @@ frozen = [
356
356
  "threadpoolctl == 3.6.0",
357
357
  "tifffile == 2026.5.15",
358
358
  "tinycss2 == 1.4.0",
359
- "tornado == 6.5.5",
359
+ "tornado == 6.5.6",
360
360
  "tqdm == 4.67.3",
361
361
  "traitlets == 5.15.0",
362
362
  "typer == 0.26.2",