pyreduce-astro 0.7b1__tar.gz → 0.7b3__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 (208) hide show
  1. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/.gitignore +2 -0
  2. pyreduce_astro-0.7b3/ANDES_plan.md +377 -0
  3. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/CHANGELOG.md +31 -0
  4. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/CLAUDE.md +26 -15
  5. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/PKG-INFO +15 -1
  6. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/README.md +14 -0
  7. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/aj_example.py +1 -1
  8. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/crires_plus_example.py +1 -1
  9. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/custom_instrument_example.py +1 -1
  10. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/harpn_example.py +1 -1
  11. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/harps_example.py +1 -1
  12. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/harps_gridsearch.py +1 -1
  13. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/just_one_swath.py +1 -1
  14. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/jwst_miri_example.py +1 -1
  15. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/jwst_niriss_example.py +1 -1
  16. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/lick_apf_example.py +1 -1
  17. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/mcdonald_example.py +1 -1
  18. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/metis_ifu_example.py +1 -1
  19. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/metis_lss_example.py +1 -1
  20. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/micado_example.py +10 -12
  21. pyreduce_astro-0.7b3/examples/mosaic_example.py +171 -0
  22. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/neid_example.py +1 -1
  23. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/nirspec_example.py +1 -1
  24. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/toes_example.py +1 -1
  25. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/uves_callfunc.py +18 -9
  26. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/uves_example.py +1 -1
  27. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/examples/xshooter_example.py +5 -5
  28. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyproject.toml +8 -2
  29. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/__main__.py +19 -1
  30. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/combine_frames.py +3 -0
  31. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/configuration.py +66 -15
  32. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/continuum_normalization.py +2 -0
  33. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/cwrappers.py +4 -1
  34. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/estimate_background_scatter.py +1 -0
  35. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/extract.py +99 -36
  36. pyreduce_astro-0.7b1/pyreduce/instruments/aj.py → pyreduce_astro-0.7b3/pyreduce/instruments/AJ/__init__.py +1 -1
  37. pyreduce_astro-0.7b3/pyreduce/instruments/AJ/settings.json +23 -0
  38. pyreduce_astro-0.7b1/pyreduce/instruments/andes.py → pyreduce_astro-0.7b3/pyreduce/instruments/ANDES/__init__.py +6 -8
  39. pyreduce_astro-0.7b3/pyreduce/instruments/ANDES/settings.json +16 -0
  40. pyreduce_astro-0.7b1/pyreduce/instruments/crires_plus.py → pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/__init__.py +6 -8
  41. pyreduce_astro-0.7b1/pyreduce/settings/settings_CRIRES_PLUS.json → pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/settings.json +16 -9
  42. pyreduce_astro-0.7b1/pyreduce/instruments/harpn.py → pyreduce_astro-0.7b3/pyreduce/instruments/HARPN/__init__.py +4 -4
  43. pyreduce_astro-0.7b3/pyreduce/instruments/HARPN/settings.json +21 -0
  44. pyreduce_astro-0.7b1/pyreduce/instruments/harps.py → pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/__init__.py +5 -8
  45. pyreduce_astro-0.7b1/pyreduce/settings/settings_HARPS.json → pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/settings.json +9 -7
  46. pyreduce_astro-0.7b1/pyreduce/instruments/jwst_miri.py → pyreduce_astro-0.7b3/pyreduce/instruments/JWST_MIRI/__init__.py +3 -5
  47. pyreduce_astro-0.7b1/pyreduce/settings/settings_JWST_MIRI.json → pyreduce_astro-0.7b3/pyreduce/instruments/JWST_MIRI/settings.json +17 -9
  48. pyreduce_astro-0.7b1/pyreduce/instruments/jwst_niriss.py → pyreduce_astro-0.7b3/pyreduce/instruments/JWST_NIRISS/__init__.py +5 -7
  49. pyreduce_astro-0.7b1/pyreduce/settings/settings_JWST_NIRISS.json → pyreduce_astro-0.7b3/pyreduce/instruments/JWST_NIRISS/settings.json +16 -8
  50. pyreduce_astro-0.7b1/pyreduce/instruments/lick_apf.py → pyreduce_astro-0.7b3/pyreduce/instruments/LICK_APF/__init__.py +2 -3
  51. pyreduce_astro-0.7b1/pyreduce/settings/settings_LICK_APF.json → pyreduce_astro-0.7b3/pyreduce/instruments/LICK_APF/settings.json +23 -15
  52. pyreduce_astro-0.7b1/pyreduce/instruments/mcdonald.py → pyreduce_astro-0.7b3/pyreduce/instruments/MCDONALD/__init__.py +3 -5
  53. pyreduce_astro-0.7b1/pyreduce/settings/settings_MCDONALD.json → pyreduce_astro-0.7b3/pyreduce/instruments/MCDONALD/settings.json +21 -10
  54. pyreduce_astro-0.7b1/pyreduce/instruments/metis_ifu.py → pyreduce_astro-0.7b3/pyreduce/instruments/METIS_IFU/__init__.py +3 -6
  55. pyreduce_astro-0.7b1/pyreduce/settings/settings_METIS_LSS.json → pyreduce_astro-0.7b3/pyreduce/instruments/METIS_IFU/settings.json +13 -11
  56. pyreduce_astro-0.7b1/pyreduce/instruments/metis_lss.py → pyreduce_astro-0.7b3/pyreduce/instruments/METIS_LSS/__init__.py +3 -6
  57. pyreduce_astro-0.7b3/pyreduce/instruments/METIS_LSS/settings.json +4 -0
  58. pyreduce_astro-0.7b1/pyreduce/instruments/micado.py → pyreduce_astro-0.7b3/pyreduce/instruments/MICADO/__init__.py +3 -6
  59. pyreduce_astro-0.7b1/pyreduce/settings/settings_MICADO.json → pyreduce_astro-0.7b3/pyreduce/instruments/MICADO/settings.json +14 -12
  60. pyreduce_astro-0.7b3/pyreduce/instruments/MOSAIC/__init__.py +12 -0
  61. pyreduce_astro-0.7b3/pyreduce/instruments/MOSAIC/config.yaml +48 -0
  62. pyreduce_astro-0.7b3/pyreduce/instruments/MOSAIC/mosaic_fiber_positions.npz +0 -0
  63. pyreduce_astro-0.7b3/pyreduce/instruments/MOSAIC/settings.json +30 -0
  64. pyreduce_astro-0.7b1/pyreduce/instruments/neid.py → pyreduce_astro-0.7b3/pyreduce/instruments/NEID/__init__.py +4 -4
  65. pyreduce_astro-0.7b1/pyreduce/settings/settings_NEID.json → pyreduce_astro-0.7b3/pyreduce/instruments/NEID/settings.json +17 -9
  66. pyreduce_astro-0.7b1/pyreduce/instruments/nirspec.py → pyreduce_astro-0.7b3/pyreduce/instruments/NIRSPEC/__init__.py +3 -3
  67. pyreduce_astro-0.7b1/pyreduce/settings/settings_NIRSPEC.json → pyreduce_astro-0.7b3/pyreduce/instruments/NIRSPEC/settings.json +16 -8
  68. pyreduce_astro-0.7b1/pyreduce/instruments/nte.py → pyreduce_astro-0.7b3/pyreduce/instruments/NTE/__init__.py +3 -5
  69. pyreduce_astro-0.7b1/pyreduce/settings/settings_NTE.json → pyreduce_astro-0.7b3/pyreduce/instruments/NTE/settings.json +16 -14
  70. pyreduce_astro-0.7b1/pyreduce/instruments/uves.py → pyreduce_astro-0.7b3/pyreduce/instruments/UVES/__init__.py +5 -8
  71. pyreduce_astro-0.7b1/pyreduce/settings/settings_UVES.json → pyreduce_astro-0.7b3/pyreduce/instruments/UVES/settings.json +15 -11
  72. pyreduce_astro-0.7b1/pyreduce/instruments/xshooter.py → pyreduce_astro-0.7b3/pyreduce/instruments/XSHOOTER/__init__.py +3 -5
  73. pyreduce_astro-0.7b1/pyreduce/settings/settings_XSHOOTER.json → pyreduce_astro-0.7b3/pyreduce/instruments/XSHOOTER/settings.json +16 -15
  74. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/instruments/common.py +59 -30
  75. pyreduce_astro-0.7b1/pyreduce/settings/settings_schema.json → pyreduce_astro-0.7b3/pyreduce/instruments/defaults/schema.json +8 -12
  76. pyreduce_astro-0.7b1/pyreduce/settings/settings_pyreduce.json → pyreduce_astro-0.7b3/pyreduce/instruments/defaults/settings.json +16 -15
  77. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/instruments/instrument_info.py +5 -3
  78. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/pipeline.py +8 -1
  79. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/rectify.py +9 -9
  80. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/reduce.py +72 -34
  81. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/slit_curve.py +22 -20
  82. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/tools/combine.py +1 -0
  83. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/trace.py +49 -43
  84. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/util.py +43 -5
  85. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/wavelength_calibration.py +6 -2
  86. pyreduce_astro-0.7b3/tools/make_notebook.py +47 -0
  87. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/uv.lock +413 -38
  88. pyreduce_astro-0.7b1/pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  89. pyreduce_astro-0.7b1/pyreduce/masks/mask_elodie.fits.gz +0 -0
  90. pyreduce_astro-0.7b1/pyreduce/masks/mask_feros3.fits.gz +0 -0
  91. pyreduce_astro-0.7b1/pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  92. pyreduce_astro-0.7b1/pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  93. pyreduce_astro-0.7b1/pyreduce/masks/mask_hds_red.fits.gz +0 -0
  94. pyreduce_astro-0.7b1/pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  95. pyreduce_astro-0.7b1/pyreduce/masks/mask_nes.fits.gz +0 -0
  96. pyreduce_astro-0.7b1/pyreduce/masks/mask_sarg.fits.gz +0 -0
  97. pyreduce_astro-0.7b1/pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  98. pyreduce_astro-0.7b1/pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  99. pyreduce_astro-0.7b1/pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  100. pyreduce_astro-0.7b1/pyreduce/settings/settings_AJ.json +0 -19
  101. pyreduce_astro-0.7b1/pyreduce/settings/settings_ANDES.json +0 -89
  102. pyreduce_astro-0.7b1/pyreduce/settings/settings_HARPN.json +0 -73
  103. pyreduce_astro-0.7b1/pyreduce/settings/settings_METIS_IFU.json +0 -77
  104. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/.gitattributes +0 -0
  105. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/.pre-commit-config.yaml +0 -0
  106. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/.python-version +0 -0
  107. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/.readthedocs.yaml +0 -0
  108. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/AGENTS.md +0 -0
  109. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/LICENSE +0 -0
  110. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/hatch_build.py +0 -0
  111. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/__init__.py +0 -0
  112. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/cli.py +0 -0
  113. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/__init__.py +0 -0
  114. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/build_extract.py +0 -0
  115. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/slit_func_2d_xi_zeta_bd.c +0 -0
  116. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/slit_func_2d_xi_zeta_bd.h +0 -0
  117. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/slit_func_bd.c +0 -0
  118. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clib/slit_func_bd.h +0 -0
  119. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/clipnflip.py +0 -0
  120. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/datasets.py +0 -0
  121. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/echelle.py +0 -0
  122. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/extraction_height.py +0 -0
  123. /pyreduce_astro-0.7b1/pyreduce/instruments/aj.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/AJ/config.yaml +0 -0
  124. /pyreduce_astro-0.7b1/pyreduce/instruments/andes.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/ANDES/config.yaml +0 -0
  125. /pyreduce_astro-0.7b1/pyreduce/instruments/crires_plus.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/config.yaml +0 -0
  126. /pyreduce_astro-0.7b1/pyreduce/masks/mask_crires_plus_det1.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/mask_det1.fits.gz +0 -0
  127. /pyreduce_astro-0.7b1/pyreduce/masks/mask_crires_plus_det2.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/mask_det2.fits.gz +0 -0
  128. /pyreduce_astro-0.7b1/pyreduce/masks/mask_crires_plus_det3.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/mask_det3.fits.gz +0 -0
  129. /pyreduce_astro-0.7b1/pyreduce/wavecal/crires_plus_J1228_det1.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det1.npz +0 -0
  130. /pyreduce_astro-0.7b1/pyreduce/wavecal/crires_plus_J1228_det2.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det2.npz +0 -0
  131. /pyreduce_astro-0.7b1/pyreduce/wavecal/crires_plus_J1228_det3.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det3.npz +0 -0
  132. /pyreduce_astro-0.7b1/pyreduce/instruments/harpn.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPN/config.yaml +0 -0
  133. /pyreduce_astro-0.7b1/pyreduce/wavecal/harpn_harpn_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPN/wavecal_harpn_2D.npz +0 -0
  134. /pyreduce_astro-0.7b1/pyreduce/instruments/harps.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/config.yaml +0 -0
  135. /pyreduce_astro-0.7b1/pyreduce/masks/mask_harps_blue.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/mask_blue.fits.gz +0 -0
  136. /pyreduce_astro-0.7b1/pyreduce/masks/mask_harps_red.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/mask_red.fits.gz +0 -0
  137. /pyreduce_astro-0.7b1/pyreduce/wavecal/harps_blue_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/wavecal_blue_2D.npz +0 -0
  138. /pyreduce_astro-0.7b1/pyreduce/wavecal/harps_blue_pol_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/wavecal_blue_pol_2D.npz +0 -0
  139. /pyreduce_astro-0.7b1/pyreduce/wavecal/harps_red_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/wavecal_red_2D.npz +0 -0
  140. /pyreduce_astro-0.7b1/pyreduce/wavecal/harps_red_pol_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/HARPS/wavecal_red_pol_2D.npz +0 -0
  141. /pyreduce_astro-0.7b1/pyreduce/instruments/jwst_miri.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/JWST_MIRI/config.yaml +0 -0
  142. /pyreduce_astro-0.7b1/pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/JWST_MIRI/mask_lrs_slitless.fits.gz +0 -0
  143. /pyreduce_astro-0.7b1/pyreduce/instruments/jwst_niriss.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/JWST_NIRISS/config.yaml +0 -0
  144. /pyreduce_astro-0.7b1/pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/JWST_NIRISS/mask_gr700xd.fits.gz +0 -0
  145. /pyreduce_astro-0.7b1/pyreduce/instruments/lick_apf.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/LICK_APF/config.yaml +0 -0
  146. /pyreduce_astro-0.7b1/pyreduce/masks/mask_lick_apf_.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/LICK_APF/mask_.fits.gz +0 -0
  147. /pyreduce_astro-0.7b1/pyreduce/instruments/mcdonald.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/MCDONALD/config.yaml +0 -0
  148. /pyreduce_astro-0.7b1/pyreduce/masks/mask_mcdonald.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/MCDONALD/mask.fits.gz +0 -0
  149. /pyreduce_astro-0.7b1/pyreduce/wavecal/mcdonald.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/MCDONALD/wavecal.npz +0 -0
  150. /pyreduce_astro-0.7b1/pyreduce/instruments/metis_ifu.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/METIS_IFU/config.yaml +0 -0
  151. /pyreduce_astro-0.7b1/pyreduce/instruments/metis_lss.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/METIS_LSS/config.yaml +0 -0
  152. /pyreduce_astro-0.7b1/pyreduce/wavecal/metis_lss_l_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/METIS_LSS/wavecal_l_2D.npz +0 -0
  153. /pyreduce_astro-0.7b1/pyreduce/wavecal/metis_lss_m_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/METIS_LSS/wavecal_m_2D.npz +0 -0
  154. /pyreduce_astro-0.7b1/pyreduce/instruments/micado.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/MICADO/config.yaml +0 -0
  155. /pyreduce_astro-0.7b1/pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/MICADO/wavecal_HK_3arcsec_chip5.npz +0 -0
  156. /pyreduce_astro-0.7b1/pyreduce/instruments/neid.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/NEID/config.yaml +0 -0
  157. /pyreduce_astro-0.7b1/pyreduce/instruments/nirspec.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/NIRSPEC/config.yaml +0 -0
  158. /pyreduce_astro-0.7b1/pyreduce/masks/mask_nirspec_nirspec.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/NIRSPEC/mask_nirspec.fits.gz +0 -0
  159. /pyreduce_astro-0.7b1/pyreduce/wavecal/nirspec_K2.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/NIRSPEC/wavecal_K2.npz +0 -0
  160. /pyreduce_astro-0.7b1/pyreduce/instruments/nte.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/NTE/config.yaml +0 -0
  161. /pyreduce_astro-0.7b1/pyreduce/instruments/uves.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/config.yaml +0 -0
  162. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_blue.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_blue.fits.gz +0 -0
  163. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_blue_binned_2_2.fits.gz +0 -0
  164. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_middle.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_middle.fits.gz +0 -0
  165. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_middle_2x2_split.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_middle_2x2_split.fits.gz +0 -0
  166. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_middle_binned_2_2.fits.gz +0 -0
  167. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_red.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_red.fits.gz +0 -0
  168. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_red_2x2.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_red_2x2.fits.gz +0 -0
  169. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_red_2x2_split.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_red_2x2_split.fits.gz +0 -0
  170. /pyreduce_astro-0.7b1/pyreduce/masks/mask_uves_red_binned_2_2.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/mask_red_binned_2_2.fits.gz +0 -0
  171. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_blue_360nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_blue_360nm_2D.npz +0 -0
  172. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_blue_390nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_blue_390nm_2D.npz +0 -0
  173. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_blue_437nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_blue_437nm_2D.npz +0 -0
  174. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_2x2_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_2x2_2D.npz +0 -0
  175. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_565nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_565nm_2D.npz +0 -0
  176. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_580nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_580nm_2D.npz +0 -0
  177. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_600nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_600nm_2D.npz +0 -0
  178. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_665nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_665nm_2D.npz +0 -0
  179. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_middle_860nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_middle_860nm_2D.npz +0 -0
  180. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_red_580nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_red_580nm_2D.npz +0 -0
  181. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_red_600nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_red_600nm_2D.npz +0 -0
  182. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_red_665nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_red_665nm_2D.npz +0 -0
  183. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_red_760nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_red_760nm_2D.npz +0 -0
  184. /pyreduce_astro-0.7b1/pyreduce/wavecal/uves_red_860nm_2D.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/UVES/wavecal_red_860nm_2D.npz +0 -0
  185. /pyreduce_astro-0.7b1/pyreduce/instruments/xshooter.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/XSHOOTER/config.yaml +0 -0
  186. /pyreduce_astro-0.7b1/pyreduce/masks/mask_xshooter_nir.fits.gz → /pyreduce_astro-0.7b3/pyreduce/instruments/XSHOOTER/mask_nir.fits.gz +0 -0
  187. /pyreduce_astro-0.7b1/pyreduce/wavecal/xshooter_nir.npz → /pyreduce_astro-0.7b3/pyreduce/instruments/XSHOOTER/wavecal_nir.npz +0 -0
  188. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/instruments/__init__.py +0 -0
  189. {pyreduce_astro-0.7b1/pyreduce/wavecal → pyreduce_astro-0.7b3/pyreduce/instruments/defaults}/atlas/thar.fits +0 -0
  190. {pyreduce_astro-0.7b1/pyreduce/wavecal → pyreduce_astro-0.7b3/pyreduce/instruments/defaults}/atlas/thar_list.txt +0 -0
  191. {pyreduce_astro-0.7b1/pyreduce/wavecal → pyreduce_astro-0.7b3/pyreduce/instruments/defaults}/atlas/une.fits +0 -0
  192. /pyreduce_astro-0.7b1/pyreduce/instruments/common.yaml → /pyreduce_astro-0.7b3/pyreduce/instruments/defaults/config.yaml +0 -0
  193. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/instruments/filters.py +0 -0
  194. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/instruments/models.py +0 -0
  195. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/pyreduce/tools/__init__.py +0 -0
  196. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/argon.line +0 -0
  197. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/bpm_creator.py +0 -0
  198. /pyreduce_astro-0.7b1/pyreduce/wavecal/convert.py → /pyreduce_astro-0.7b3/tools/convert_wavecal.py +0 -0
  199. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/create_wavelength_guess.py +0 -0
  200. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/download_files.py +0 -0
  201. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/ipy_startup.py +0 -0
  202. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/neon.lin +0 -0
  203. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/neon.line +0 -0
  204. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/pymultispec.py +0 -0
  205. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/thar.npz +0 -0
  206. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/wavecal_creator.py +0 -0
  207. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/wavecal_creator_from_existing.py +0 -0
  208. {pyreduce_astro-0.7b1 → pyreduce_astro-0.7b3}/tools/xshooter_nir.json +0 -0
@@ -21,3 +21,5 @@ docs/_build/
21
21
  debug/
22
22
  idl/
23
23
  logs/
24
+ *.ipynb
25
+ tmp/*
@@ -0,0 +1,377 @@
1
+ # ANDES Instrument Configuration Design
2
+
3
+ ## Background
4
+
5
+ ### ANDES Instrument Overview
6
+
7
+ ANDES is a future ELT high-resolution spectrograph with multiple spectrographs, each containing multiple arms:
8
+
9
+ | Spectrograph | Arms | Detector Type |
10
+ |--------------|------|---------------|
11
+ | 1 | U, B, V | Optical CCD |
12
+ | 2 | R, IZ | Red optical CCD |
13
+ | 3 | Y, J, H | Near-IR (H2RG or similar) |
14
+ | 4 | K | Thermal IR |
15
+
16
+ Key characteristics:
17
+ - All arms fed from the same fibers on sky
18
+ - Each arm has its own independent detector
19
+ - FITS files organized **per spectrograph** (one file with arms as extensions)
20
+ - Detectors are similar within each spectrograph
21
+
22
+ ### Current State
23
+
24
+ - `andes.yaml` - Multi-channel IR-focused config
25
+ - `settings_ANDES.json` - Inherits from CRIRES_PLUS (IR-tuned)
26
+ - `aj.yaml` / `settings_AJ.json` - Simulation instrument (draft for testing)
27
+
28
+ ---
29
+
30
+ ## PyReduce Architecture Context
31
+
32
+ ### How Channels Work
33
+
34
+ Channels in PyReduce handle multi-extension FITS files. The `getter` class in `instruments/common.py` automatically indexes list values by channel position:
35
+
36
+ ```yaml
37
+ # Example: UVES with 3 channels
38
+ channels: [BLUE, MIDDLE, RED]
39
+ extension: [0, 2, 1] # BLUE→ext0, MIDDLE→ext2, RED→ext1
40
+ orientation: [2, 1, 1] # BLUE rotated differently
41
+ ```
42
+
43
+ When processing channel "RED" (index 2), PyReduce automatically uses `extension[2]=1`, `orientation[2]=1`.
44
+
45
+ ### What MUST Be Shared Across Channels
46
+
47
+ 1. **File classification keywords** (`kw_bias`, `kw_flat`, `kw_wave`, `kw_spec`)
48
+ 2. **File classification patterns** (`id_bias`, `id_flat`, etc.)
49
+ 3. **Reduction settings** - `settings_INSTRUMENT.json` applies to ALL channels
50
+ 4. **Header keyword mappings** (date, target, exposure_time, etc.)
51
+
52
+ ### What CAN Vary Per Channel
53
+
54
+ 1. FITS extension index
55
+ 2. Image orientation
56
+ 3. Detector-specific header values (gain, readnoise) via `{id[n]}` templates
57
+ 4. Output filenames (mask, wavecal)
58
+
59
+ ### Critical Limitation: No Per-Channel Settings
60
+
61
+ **YAML instrument configs** support per-channel values via list indexing.
62
+
63
+ **JSON settings do NOT** - all channels share identical reduction parameters:
64
+ - Same `trace.degree`, `trace.noise`, `trace.min_cluster`
65
+ - Same `science.extraction_height`, `science.oversampling`
66
+ - Same `wavecal.degree`, `wavecal.threshold`
67
+
68
+ This means optical CCDs and IR arrays would share the same tuning if in one instrument.
69
+
70
+ ---
71
+
72
+ ## Design Options
73
+
74
+ ### Option A: Single ANDES Instrument (9 channels)
75
+
76
+ ```yaml
77
+ # andes.yaml
78
+ channels: [U, B, V, R, IZ, Y, J, H, K]
79
+ extension: [1, 2, 3, 1, 2, 1, 2, 3, 1]
80
+ ```
81
+
82
+ | Pros | Cons |
83
+ |------|------|
84
+ | Single abstraction level | Cannot tune settings per arm/spectrograph |
85
+ | Simple mental model | Must handle 4 FITS file types in one instrument |
86
+ | One config file | Optical/IR forced to share parameters |
87
+
88
+ **Implementation**: Would follow CRIRES+ pattern (see below).
89
+
90
+ ### Option A Implementation: CRIRES+ Pattern
91
+
92
+ CRIRES+ shows how to handle multiple file types with a single instrument:
93
+
94
+ ```python
95
+ class ANDES(Instrument):
96
+ def __init__(self):
97
+ super().__init__()
98
+ # Add spectrograph filter - files tagged by which spectrograph they're from
99
+ self.filters["spectrograph"] = Filter(self.info["kw_spectrograph"])
100
+ self.shared += ["spectrograph"]
101
+
102
+ def get_expected_values(self, target, night, channel):
103
+ expectations = super().get_expected_values(target, night)
104
+ # Map channel to spectrograph: J → YJH, U → UBV, etc.
105
+ spectrograph = self.channel_to_spectrograph(channel)
106
+ for key in expectations.keys():
107
+ expectations[key]["spectrograph"] = spectrograph
108
+ return expectations
109
+
110
+ def get_extension(self, header, channel):
111
+ # Map channel to extension: U→1, B→2, V→3, Y→1, J→2, H→3, etc.
112
+ return self.channel_extensions[channel]
113
+
114
+ def discover_channels(self, input_dir):
115
+ # Scan files, find which spectrographs present, return available channels
116
+ ...
117
+ ```
118
+
119
+ **How file filtering works:**
120
+ 1. Files have header keyword identifying spectrograph (UBV, RIZ, YJH, K)
121
+ 2. When `channel=J` requested, ANDES maps J → YJH spectrograph
122
+ 3. File filter selects only YJH spectrograph files
123
+ 4. Extension 2 read from those files
124
+
125
+ **Without specifying channel:**
126
+ - `discover_channels()` scans files to find which spectrographs exist
127
+ - Returns available channels (e.g., if only YJH files exist → `[Y, J, H]`)
128
+ - Pipeline loops over each discovered channel
129
+
130
+ This makes Option A fully viable following an existing pattern.
131
+
132
+ ### Option B: Separate Instruments (9 instruments, 1 channel each)
133
+
134
+ ```
135
+ ANDES_U channels=[U] extension=1 → inherits pyreduce
136
+ ANDES_B channels=[B] extension=2 → inherits ANDES_U
137
+ ANDES_V channels=[V] extension=3 → inherits ANDES_U
138
+ ANDES_R channels=[R] extension=1 → inherits pyreduce
139
+ ANDES_IZ channels=[IZ] extension=2 → inherits ANDES_R
140
+ ANDES_Y channels=[Y] extension=1 → inherits CRIRES_PLUS
141
+ ANDES_J channels=[J] extension=2 → inherits ANDES_Y
142
+ ANDES_H channels=[H] extension=3 → inherits ANDES_Y
143
+ ANDES_K channels=[K] extension=1 → inherits CRIRES_PLUS
144
+ ```
145
+
146
+ | Pros | Cons |
147
+ |------|------|
148
+ | Single abstraction (instruments only) | 9 YAML + 9 settings files |
149
+ | Maximum per-arm flexibility | File sorting overlap (U,B,V find same file) |
150
+ | Settings inheritance keeps configs DRY | Cannot reduce "all of UBV" in one command |
151
+ | Matches AJ pattern | More instruments to manage |
152
+
153
+ ### Option C: Per-Spectrograph Instruments (4 instruments)
154
+
155
+ ```
156
+ ANDES_UBV channels=[U,B,V] extension=[1,2,3] → inherits pyreduce
157
+ ANDES_RIZ channels=[R,IZ] extension=[1,2] → inherits ANDES_UBV
158
+ ANDES_YJH channels=[Y,J,H] extension=[1,2,3] → inherits CRIRES_PLUS
159
+ ANDES_K channels=[K] extension=1 → inherits ANDES_YJH
160
+ ```
161
+
162
+ | Pros | Cons |
163
+ |------|------|
164
+ | Matches FITS file structure (1:1) | Two abstraction levels |
165
+ | Cleaner file sorting | Per-spectrograph tuning only (not per-arm) |
166
+ | Per-spectrograph settings tuning | |
167
+ | Follows XSHOOTER/HARPS/UVES pattern | |
168
+ | Can reduce entire spectrograph at once | |
169
+
170
+ ---
171
+
172
+ ## Recommendation
173
+
174
+ **Option C** is recommended because:
175
+
176
+ 1. **Matches physical reality**: One instrument = one FITS file type
177
+ 2. **Sufficient tuning granularity**: Detectors are similar within spectrograph
178
+ 3. **Proven pattern**: XSHOOTER (UVB/VIS/NIR), HARPS (BLUE/RED), UVES work this way
179
+ 4. **Clean file handling**: No overlap in file discovery
180
+
181
+ If per-arm tuning becomes necessary, Option B remains viable with settings inheritance minimizing duplication.
182
+
183
+ ---
184
+
185
+ ## File Structure (Option C)
186
+
187
+ ```
188
+ pyreduce/instruments/
189
+ andes_ubv.yaml # channels=[U,B,V], extension=[1,2,3]
190
+ andes_riz.yaml # channels=[R,IZ], extension=[1,2]
191
+ andes_yjh.yaml # channels=[Y,J,H], extension=[1,2,3]
192
+ andes_k.yaml # channels=[K], extension=1
193
+
194
+ pyreduce/settings/
195
+ settings_ANDES_UBV.json # __inherits__: pyreduce (optical CCD tuning)
196
+ settings_ANDES_RIZ.json # __inherits__: ANDES_UBV
197
+ settings_ANDES_YJH.json # __inherits__: CRIRES_PLUS (near-IR tuning)
198
+ settings_ANDES_K.json # __inherits__: ANDES_YJH
199
+ ```
200
+
201
+ ### Migration
202
+
203
+ - Rename `andes.yaml` → `andes_yjh.yaml` (or delete and create fresh)
204
+ - Rename `settings_ANDES.json` → `settings_ANDES_YJH.json`
205
+ - Keep `AJ` as simulation/test instrument
206
+
207
+ ---
208
+
209
+ ## Future Enhancement: Per-Channel Settings
210
+
211
+ Adding per-channel settings would enable Option A (single instrument with full flexibility).
212
+
213
+ ### Current Flow
214
+
215
+ ```
216
+ configuration.py:load_config()
217
+ → loads settings_INSTRUMENT.json
218
+ → merges with defaults via _resolve_inheritance()
219
+ → returns config dict (same for all channels)
220
+
221
+ reduce.py:Step.__init__()
222
+ → receives config dict
223
+ → uses values directly: self.degree = config["degree"]
224
+ ```
225
+
226
+ ### Proposed Enhancement
227
+
228
+ Add channel-aware value selection in Step classes, similar to how `getter` works for YAML configs.
229
+
230
+ #### Option 1: Settings-level indexing
231
+
232
+ Modify `_resolve_inheritance()` or add post-processing to index list values:
233
+
234
+ ```python
235
+ def _apply_channel_index(config, channel, channels):
236
+ """Index list values in settings by channel position."""
237
+ if channel is None or channels is None:
238
+ return config
239
+ try:
240
+ idx = channels.index(channel.upper())
241
+ except (ValueError, AttributeError):
242
+ return config
243
+
244
+ result = {}
245
+ for key, value in config.items():
246
+ if isinstance(value, dict):
247
+ result[key] = _apply_channel_index(value, channel, channels)
248
+ elif isinstance(value, list) and len(value) == len(channels):
249
+ result[key] = value[idx]
250
+ else:
251
+ result[key] = value
252
+ return result
253
+ ```
254
+
255
+ Call this when creating Step instances in `pipeline.py`.
256
+
257
+ #### Option 2: Step-level helper
258
+
259
+ Add a method to Step base class:
260
+
261
+ ```python
262
+ class Step:
263
+ def get_config(self, key, default=None):
264
+ """Get config value, indexing by channel if value is a list."""
265
+ value = self.config.get(key, default)
266
+ if isinstance(value, list) and hasattr(self, 'channel_index'):
267
+ if len(value) > self.channel_index:
268
+ return value[self.channel_index]
269
+ return value
270
+ ```
271
+
272
+ #### Settings Format
273
+
274
+ ```json
275
+ {
276
+ "__instrument__": "ANDES",
277
+ "trace": {
278
+ "degree": 4,
279
+ "noise": [10, 10, 10, 20, 20, 50, 50, 50, 100],
280
+ "min_cluster": [500, 500, 500, 1000, 1000, 2000, 2000, 2000, 5000]
281
+ },
282
+ "science": {
283
+ "extraction_height": 10,
284
+ "oversampling": [10, 10, 10, 10, 10, 5, 5, 5, 3]
285
+ }
286
+ }
287
+ ```
288
+
289
+ Values that are scalars apply to all channels. Values that are lists with length matching `channels` are indexed.
290
+
291
+ #### Implementation Scope
292
+
293
+ 1. **Minimal**: ~20-30 lines in `configuration.py` or `reduce.py`
294
+ 2. **Changes needed**:
295
+ - Pass `channel` and `channels` list to config processing
296
+ - Add indexing logic (one of the options above)
297
+ - Update Step classes to use indexed values
298
+ 3. **Backward compatible**: Scalar values work as before; only lists trigger indexing
299
+ 4. **Risk**: Low - additive change, doesn't break existing instruments
300
+
301
+ #### Semantic List Parameters (Potential Conflict)
302
+
303
+ Current settings use lists for semantic pairs, not per-channel values:
304
+
305
+ | Parameter | Meaning | Where Used |
306
+ |-----------|---------|------------|
307
+ | `closing_shape` | [x, y] kernel | trace morphology |
308
+ | `opening_shape` | [x, y] kernel | trace morphology |
309
+ | `degree` | [order, column] | 2D fits (wavecal, curvature, freq_comb) |
310
+ | `extraction_height` | [below, above] | rarely as list, usually scalar |
311
+
312
+ **Option 1: Refactor semantic lists away**
313
+
314
+ ```json
315
+ // Before
316
+ "closing_shape": [5, 5]
317
+ "degree": [6, 6]
318
+
319
+ // After
320
+ "closing_shape_x": 5,
321
+ "closing_shape_y": 5,
322
+ "degree_order": 6,
323
+ "degree_column": 6
324
+ ```
325
+
326
+ Pros: Clean separation, no ambiguity
327
+ Cons: Breaking change, migration needed
328
+
329
+ **Option 2: Length-based disambiguation**
330
+
331
+ Per-channel lists must match `len(channels)`. Semantic lists are always 2 elements.
332
+ - ANDES has 9 channels, so `[10, 20, 30, 40, 50, 60, 70, 80, 90]` → per-channel
333
+ - `[6, 6]` → semantic (2 elements ≠ 9 channels)
334
+
335
+ Pros: Backward compatible
336
+ Cons: Fragile if instrument has exactly 2 channels
337
+
338
+ **Option 3: Explicit marker**
339
+
340
+ ```json
341
+ "noise": {"__per_channel__": [10, 20, 50, 100]}
342
+ // or
343
+ "noise": {"U": 10, "B": 10, "V": 10, "Y": 50, "J": 50, "H": 50, "K": 100}
344
+ ```
345
+
346
+ Pros: Explicit, no ambiguity
347
+ Cons: More verbose
348
+
349
+ **Recommendation**: Option 1 (refactor) for cleanest long-term solution. The semantic lists are:
350
+ - `closing_shape`, `opening_shape`: Rarely changed, easy to split
351
+ - `degree`: Common but well-understood, split to `degree_order`/`degree_column`
352
+ - `extraction_height`: Already scalar in most configs, deprecate list form
353
+
354
+ ---
355
+
356
+ ## Summary
357
+
358
+ | Approach | Effort | Flexibility | Complexity |
359
+ |----------|--------|-------------|------------|
360
+ | Option A + per-channel settings | Medium | Per-channel | Single instrument, single abstraction |
361
+ | Option B (9 instruments) | Low | Per-arm | 9 instruments, single abstraction |
362
+ | Option C (4 instruments) | Low | Per-spectrograph | 4 instruments, two abstractions |
363
+
364
+ **Revised Recommendation:**
365
+
366
+ **Option A** is now the most attractive if we implement per-channel settings:
367
+ 1. Single instrument, single abstraction level
368
+ 2. Maximum flexibility (per-channel tuning)
369
+ 3. Follows proven CRIRES+ pattern for file handling
370
+ 4. Clean long-term solution
371
+
372
+ **Implementation path:**
373
+ 1. Refactor semantic list parameters (`degree` → `degree_order`/`degree_column`, etc.)
374
+ 2. Add per-channel settings indexing (~30 lines)
375
+ 3. Create ANDES instrument with spectrograph filter (like CRIRES+ band filter)
376
+
377
+ If per-channel settings enhancement is deferred, use **Option C** as interim solution.
@@ -1,6 +1,37 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## [0.7b3] - 2026-01-11
5
+
6
+ ### Added
7
+ - MOSAIC instrument support with fiber group detection and curvature step
8
+ - Extraction animation controls: pause/step buttons and speed control (`PYREDUCE_PLOT_ANIMATION_SPEED`)
9
+ - `--plot-dir` and `--plot-show` CLI options for flexible plot output
10
+
11
+ ### Changed
12
+ - Rename `orders` to `traces` in rectify and slit_curve modules for consistency
13
+ - Downgrade extraction max-iterations message from ERROR to WARNING
14
+ - Only warn about missing files for steps that are actually requested
15
+
16
+ ### Fixed
17
+ - Handle channel mismatch gracefully in CLI
18
+ - Curvature plotting index error when peaks need int casting
19
+
20
+ ## [0.7b2] - 2026-01-09
21
+
22
+ ### Changed
23
+ - **Reorganize instrument files**: All instrument-related files now in per-instrument directories
24
+ - `instruments/{name}.py` → `instruments/{NAME}/__init__.py`
25
+ - `instruments/{name}.yaml` → `instruments/{NAME}/config.yaml`
26
+ - `settings/settings_{NAME}.json` → `instruments/{NAME}/settings.json`
27
+ - `wavecal/{name}_*.npz` → `instruments/{NAME}/wavecal_*.npz`
28
+ - `masks/mask_{name}_*.fits.gz` → `instruments/{NAME}/mask_*.fits.gz`
29
+ - Base settings and schema moved to `instruments/defaults/`
30
+ - Wavelength atlas files moved to `instruments/defaults/atlas/`
31
+
32
+ ### Removed
33
+ - Orphan mask files for undefined instruments (elodie, sarg, hds, etc.)
34
+
4
35
  ## [0.7b1] - 2026-01-06
5
36
 
6
37
  ### Changed
@@ -41,13 +41,19 @@ pyreduce/
41
41
  ├── instruments/ # Instrument definitions
42
42
  │ ├── common.py # Base Instrument class
43
43
  │ ├── models.py # Pydantic config models
44
+ │ ├── filters.py # File classification filters
44
45
  │ ├── instrument_info.py # Instrument loader
45
- │ ├── *.yaml # Instrument configs (one per instrument)
46
- └── *.py # Custom instrument logic (optional)
47
-
48
- ├── settings/ # Reduction parameters
49
- ├── settings_default.json
50
- │ └── settings_*.json # Per-instrument settings
46
+ │ ├── defaults/ # Base settings and line atlases
47
+ │ ├── settings.json # Default reduction parameters
48
+ │ ├── schema.json # Settings validation schema
49
+ │ │ ├── config.yaml # Base instrument config
50
+ │ └── atlas/ # Wavelength calibration line lists
51
+ │ └── {INSTRUMENT}/ # Per-instrument directory (e.g., UVES/, HARPS/)
52
+ │ ├── __init__.py # Instrument class
53
+ │ ├── config.yaml # Hardware/header config
54
+ │ ├── settings.json # Reduction parameters
55
+ │ ├── wavecal_*.npz # Pre-computed wavelength solutions
56
+ │ └── mask_*.fits.gz # Bad pixel masks
51
57
 
52
58
  └── clib/ # C source for extraction
53
59
  ├── slit_func_bd.c
@@ -97,7 +103,7 @@ Each step class has:
97
103
 
98
104
  ### Instrument Configs (YAML)
99
105
 
100
- Location: `pyreduce/instruments/*.yaml`
106
+ Location: `pyreduce/instruments/{INSTRUMENT}/config.yaml`
101
107
 
102
108
  Defines what the instrument IS - hardware properties and header mappings:
103
109
 
@@ -139,7 +145,7 @@ Validated by Pydantic model `InstrumentConfig` in `models.py`.
139
145
 
140
146
  ### Reduction Settings (JSON)
141
147
 
142
- Location: `pyreduce/settings/settings_*.json`
148
+ Location: `pyreduce/instruments/{INSTRUMENT}/settings.json`
143
149
 
144
150
  Defines HOW to reduce - algorithm parameters per step:
145
151
 
@@ -172,7 +178,7 @@ Defines HOW to reduce - algorithm parameters per step:
172
178
  }
173
179
  ```
174
180
 
175
- Settings cascade: `settings_default.json` < `settings_INSTRUMENT.json` < runtime overrides.
181
+ Settings cascade: `instruments/defaults/settings.json` < `instruments/{INSTRUMENT}/settings.json` < runtime overrides.
176
182
 
177
183
  ## Python API
178
184
 
@@ -251,8 +257,11 @@ uv run reduce list-steps
251
257
  ## Environment Variables
252
258
 
253
259
  - `REDUCE_DATA` - Base data directory (default: `~/REDUCE_DATA`)
254
- - `PYREDUCE_PLOT` - Override plot level (0, 1, 2)
255
- - `PYREDUCE_PLOT_DIR` - Save plots to directory instead of displaying
260
+ - `PYREDUCE_PLOT` - Override plot level (0=off, 1=basic, 2=detailed)
261
+ - `PYREDUCE_PLOT_DIR` - Save plots to directory as PNG files
262
+ - `PYREDUCE_PLOT_SHOW` - Display mode: `block` (default), `defer`, or `off`
263
+
264
+ Plot modes: `block` shows each plot interactively; `defer` accumulates all plots and shows at end (useful with webagg backend); `off` disables display. Save and display are independent.
256
265
 
257
266
  ## Development
258
267
 
@@ -272,10 +281,12 @@ After a fresh clone or `rm -rf .venv`, run `uv sync && uv run reduce-build` to s
272
281
 
273
282
  ### Adding Instruments
274
283
 
275
- 1. Create `pyreduce/instruments/name.yaml` with detector/header config
276
- 2. Create `pyreduce/instruments/name.py` if custom logic needed (optional)
277
- 3. Create `pyreduce/settings/settings_NAME.json` for reduction parameters
278
- 4. Add example script to `examples/name_example.py`
284
+ 1. Create `pyreduce/instruments/{NAME}/` directory
285
+ 2. Add `config.yaml` with detector/header config
286
+ 3. Add `settings.json` for reduction parameters (can use `"__inherits__": "defaults"`)
287
+ 4. Add `__init__.py` with instrument class if custom logic needed (optional)
288
+ 5. Add wavecal/mask files if available
289
+ 6. Add example script to `examples/name_example.py`
279
290
 
280
291
  ### Test Organization
281
292
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyreduce-astro
3
- Version: 0.7b1
3
+ Version: 0.7b3
4
4
  Summary: A data reduction package for echelle spectrographs
5
5
  Project-URL: Homepage, https://github.com/ivh/PyReduce
6
6
  Project-URL: Documentation, https://pyreduce-astro.readthedocs.io
@@ -94,6 +94,20 @@ Pipeline.from_instrument(
94
94
  ).run()
95
95
  ```
96
96
 
97
+ ## Plotting
98
+
99
+ Control plotting with environment variables:
100
+
101
+ ```bash
102
+ # Save plots to files (headless/CI)
103
+ PYREDUCE_PLOT=1 PYREDUCE_PLOT_DIR=/tmp/plots PYREDUCE_PLOT_SHOW=off uv run reduce run ...
104
+
105
+ # Show all plots at end (browser via webagg)
106
+ MPLBACKEND=webagg PYREDUCE_PLOT=1 PYREDUCE_PLOT_SHOW=defer uv run reduce run ...
107
+ ```
108
+
109
+ See [How To](https://pyreduce-astro.readthedocs.io/en/latest/howto.html#plot-modes) for details.
110
+
97
111
  ## Documentation
98
112
 
99
113
  Full documentation at [ReadTheDocs](https://pyreduce-astro.readthedocs.io/).
@@ -53,6 +53,20 @@ Pipeline.from_instrument(
53
53
  ).run()
54
54
  ```
55
55
 
56
+ ## Plotting
57
+
58
+ Control plotting with environment variables:
59
+
60
+ ```bash
61
+ # Save plots to files (headless/CI)
62
+ PYREDUCE_PLOT=1 PYREDUCE_PLOT_DIR=/tmp/plots PYREDUCE_PLOT_SHOW=off uv run reduce run ...
63
+
64
+ # Show all plots at end (browser via webagg)
65
+ MPLBACKEND=webagg PYREDUCE_PLOT=1 PYREDUCE_PLOT_SHOW=defer uv run reduce run ...
66
+ ```
67
+
68
+ See [How To](https://pyreduce-astro.readthedocs.io/en/latest/howto.html#plot-modes) for details.
69
+
56
70
  ## Documentation
57
71
 
58
72
  Full documentation at [ReadTheDocs](https://pyreduce-astro.readthedocs.io/).
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  AJ instrument example: Fiber bundle tracing with direct function calls.
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  import os.path
6
6
 
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  import matplotlib.pyplot as plt
6
6
  import numpy as np
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7b1"]
3
+ # dependencies = ["pyreduce-astro>=0.7b3"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce