pyreduce-astro 0.7a7__tar.gz → 0.7b2__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 (205) hide show
  1. pyreduce_astro-0.7b2/ANDES_plan.md +377 -0
  2. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/CHANGELOG.md +37 -0
  3. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/CLAUDE.md +26 -14
  4. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/PKG-INFO +1 -2
  5. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/aj_example.py +1 -1
  6. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/crires_plus_example.py +3 -4
  7. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/custom_instrument_example.py +1 -1
  8. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/harpn_example.py +1 -1
  9. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/harps_example.py +1 -1
  10. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/harps_gridsearch.py +1 -1
  11. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/just_one_swath.py +1 -1
  12. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/jwst_miri_example.py +1 -1
  13. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/jwst_niriss_example.py +1 -1
  14. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/lick_apf_example.py +5 -5
  15. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/mcdonald_example.py +1 -1
  16. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/metis_ifu_example.py +1 -1
  17. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/metis_lss_example.py +1 -1
  18. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/micado_example.py +1 -1
  19. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/neid_example.py +1 -1
  20. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/nirspec_example.py +1 -1
  21. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/toes_example.py +1 -1
  22. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/uves_callfunc.py +1 -1
  23. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/uves_example.py +1 -1
  24. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/examples/xshooter_example.py +2 -2
  25. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyproject.toml +5 -3
  26. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/__main__.py +102 -25
  27. pyreduce_astro-0.7b2/pyreduce/clib/build_extract.py +80 -0
  28. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/configuration.py +66 -15
  29. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/cwrappers.py +26 -40
  30. pyreduce_astro-0.7b2/pyreduce/datasets.py +190 -0
  31. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/extract.py +85 -71
  32. pyreduce_astro-0.7a7/pyreduce/instruments/aj.py → pyreduce_astro-0.7b2/pyreduce/instruments/AJ/__init__.py +1 -1
  33. pyreduce_astro-0.7b2/pyreduce/instruments/AJ/settings.json +23 -0
  34. pyreduce_astro-0.7a7/pyreduce/instruments/andes.py → pyreduce_astro-0.7b2/pyreduce/instruments/ANDES/__init__.py +6 -8
  35. pyreduce_astro-0.7b2/pyreduce/instruments/ANDES/settings.json +16 -0
  36. pyreduce_astro-0.7a7/pyreduce/instruments/crires_plus.py → pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/__init__.py +31 -8
  37. pyreduce_astro-0.7a7/pyreduce/settings/settings_CRIRES_PLUS.json → pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/settings.json +21 -16
  38. pyreduce_astro-0.7a7/pyreduce/instruments/harpn.py → pyreduce_astro-0.7b2/pyreduce/instruments/HARPN/__init__.py +4 -4
  39. pyreduce_astro-0.7b2/pyreduce/instruments/HARPN/settings.json +21 -0
  40. pyreduce_astro-0.7a7/pyreduce/instruments/harps.py → pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/__init__.py +5 -8
  41. pyreduce_astro-0.7a7/pyreduce/settings/settings_HARPS.json → pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/settings.json +12 -9
  42. pyreduce_astro-0.7a7/pyreduce/instruments/jwst_miri.py → pyreduce_astro-0.7b2/pyreduce/instruments/JWST_MIRI/__init__.py +3 -5
  43. pyreduce_astro-0.7a7/pyreduce/settings/settings_JWST_MIRI.json → pyreduce_astro-0.7b2/pyreduce/instruments/JWST_MIRI/settings.json +17 -9
  44. pyreduce_astro-0.7a7/pyreduce/instruments/jwst_niriss.py → pyreduce_astro-0.7b2/pyreduce/instruments/JWST_NIRISS/__init__.py +5 -15
  45. pyreduce_astro-0.7a7/pyreduce/settings/settings_JWST_NIRISS.json → pyreduce_astro-0.7b2/pyreduce/instruments/JWST_NIRISS/settings.json +16 -8
  46. pyreduce_astro-0.7a7/pyreduce/instruments/lick_apf.py → pyreduce_astro-0.7b2/pyreduce/instruments/LICK_APF/__init__.py +2 -3
  47. pyreduce_astro-0.7a7/pyreduce/settings/settings_LICK_APF.json → pyreduce_astro-0.7b2/pyreduce/instruments/LICK_APF/settings.json +28 -19
  48. pyreduce_astro-0.7a7/pyreduce/instruments/mcdonald.py → pyreduce_astro-0.7b2/pyreduce/instruments/MCDONALD/__init__.py +3 -5
  49. pyreduce_astro-0.7a7/pyreduce/settings/settings_MCDONALD.json → pyreduce_astro-0.7b2/pyreduce/instruments/MCDONALD/settings.json +21 -10
  50. pyreduce_astro-0.7a7/pyreduce/instruments/metis_ifu.py → pyreduce_astro-0.7b2/pyreduce/instruments/METIS_IFU/__init__.py +3 -6
  51. pyreduce_astro-0.7a7/pyreduce/settings/settings_METIS_LSS.json → pyreduce_astro-0.7b2/pyreduce/instruments/METIS_IFU/settings.json +16 -14
  52. pyreduce_astro-0.7a7/pyreduce/instruments/metis_lss.py → pyreduce_astro-0.7b2/pyreduce/instruments/METIS_LSS/__init__.py +3 -6
  53. pyreduce_astro-0.7b2/pyreduce/instruments/METIS_LSS/settings.json +4 -0
  54. pyreduce_astro-0.7a7/pyreduce/instruments/micado.py → pyreduce_astro-0.7b2/pyreduce/instruments/MICADO/__init__.py +3 -6
  55. pyreduce_astro-0.7a7/pyreduce/settings/settings_MICADO.json → pyreduce_astro-0.7b2/pyreduce/instruments/MICADO/settings.json +17 -15
  56. pyreduce_astro-0.7a7/pyreduce/instruments/neid.py → pyreduce_astro-0.7b2/pyreduce/instruments/NEID/__init__.py +4 -4
  57. pyreduce_astro-0.7a7/pyreduce/settings/settings_NEID.json → pyreduce_astro-0.7b2/pyreduce/instruments/NEID/settings.json +18 -10
  58. pyreduce_astro-0.7a7/pyreduce/instruments/nirspec.py → pyreduce_astro-0.7b2/pyreduce/instruments/NIRSPEC/__init__.py +3 -3
  59. pyreduce_astro-0.7a7/pyreduce/settings/settings_NIRSPEC.json → pyreduce_astro-0.7b2/pyreduce/instruments/NIRSPEC/settings.json +16 -8
  60. pyreduce_astro-0.7a7/pyreduce/instruments/nte.py → pyreduce_astro-0.7b2/pyreduce/instruments/NTE/__init__.py +3 -5
  61. pyreduce_astro-0.7a7/pyreduce/settings/settings_NTE.json → pyreduce_astro-0.7b2/pyreduce/instruments/NTE/settings.json +18 -16
  62. pyreduce_astro-0.7a7/pyreduce/instruments/uves.py → pyreduce_astro-0.7b2/pyreduce/instruments/UVES/__init__.py +5 -8
  63. pyreduce_astro-0.7a7/pyreduce/settings/settings_UVES.json → pyreduce_astro-0.7b2/pyreduce/instruments/UVES/settings.json +16 -12
  64. pyreduce_astro-0.7a7/pyreduce/instruments/xshooter.py → pyreduce_astro-0.7b2/pyreduce/instruments/XSHOOTER/__init__.py +3 -5
  65. pyreduce_astro-0.7a7/pyreduce/settings/settings_XSHOOTER.json → pyreduce_astro-0.7b2/pyreduce/instruments/XSHOOTER/settings.json +12 -10
  66. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/instruments/common.py +54 -30
  67. pyreduce_astro-0.7a7/pyreduce/settings/settings_schema.json → pyreduce_astro-0.7b2/pyreduce/instruments/defaults/schema.json +26 -16
  68. pyreduce_astro-0.7a7/pyreduce/settings/settings_pyreduce.json → pyreduce_astro-0.7b2/pyreduce/instruments/defaults/settings.json +16 -14
  69. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/instruments/instrument_info.py +5 -3
  70. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/pipeline.py +1 -5
  71. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/rectify.py +5 -5
  72. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/reduce.py +87 -60
  73. pyreduce_astro-0.7b2/pyreduce/slit_curve.py +739 -0
  74. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/wavelength_calibration.py +4 -2
  75. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/uv.lock +132 -129
  76. pyreduce_astro-0.7a7/pyreduce/clib/build_extract.py +0 -75
  77. pyreduce_astro-0.7a7/pyreduce/datasets.py +0 -238
  78. pyreduce_astro-0.7a7/pyreduce/make_shear.py +0 -607
  79. pyreduce_astro-0.7a7/pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  80. pyreduce_astro-0.7a7/pyreduce/masks/mask_elodie.fits.gz +0 -0
  81. pyreduce_astro-0.7a7/pyreduce/masks/mask_feros3.fits.gz +0 -0
  82. pyreduce_astro-0.7a7/pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  83. pyreduce_astro-0.7a7/pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  84. pyreduce_astro-0.7a7/pyreduce/masks/mask_hds_red.fits.gz +0 -0
  85. pyreduce_astro-0.7a7/pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  86. pyreduce_astro-0.7a7/pyreduce/masks/mask_nes.fits.gz +0 -0
  87. pyreduce_astro-0.7a7/pyreduce/masks/mask_sarg.fits.gz +0 -0
  88. pyreduce_astro-0.7a7/pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  89. pyreduce_astro-0.7a7/pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  90. pyreduce_astro-0.7a7/pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  91. pyreduce_astro-0.7a7/pyreduce/settings/settings_AJ.json +0 -19
  92. pyreduce_astro-0.7a7/pyreduce/settings/settings_ANDES.json +0 -89
  93. pyreduce_astro-0.7a7/pyreduce/settings/settings_HARPN.json +0 -73
  94. pyreduce_astro-0.7a7/pyreduce/settings/settings_METIS_IFU.json +0 -77
  95. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/.gitattributes +0 -0
  96. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/.gitignore +0 -0
  97. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/.pre-commit-config.yaml +0 -0
  98. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/.python-version +0 -0
  99. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/.readthedocs.yaml +0 -0
  100. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/AGENTS.md +0 -0
  101. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/LICENSE +0 -0
  102. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/README.md +0 -0
  103. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/hatch_build.py +0 -0
  104. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/__init__.py +0 -0
  105. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/cli.py +0 -0
  106. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clib/__init__.py +0 -0
  107. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clib/slit_func_2d_xi_zeta_bd.c +0 -0
  108. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clib/slit_func_2d_xi_zeta_bd.h +0 -0
  109. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clib/slit_func_bd.c +0 -0
  110. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clib/slit_func_bd.h +0 -0
  111. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/clipnflip.py +0 -0
  112. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/combine_frames.py +0 -0
  113. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/continuum_normalization.py +0 -0
  114. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/echelle.py +0 -0
  115. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/estimate_background_scatter.py +0 -0
  116. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/extraction_height.py +0 -0
  117. /pyreduce_astro-0.7a7/pyreduce/instruments/aj.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/AJ/config.yaml +0 -0
  118. /pyreduce_astro-0.7a7/pyreduce/instruments/andes.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/ANDES/config.yaml +0 -0
  119. /pyreduce_astro-0.7a7/pyreduce/instruments/crires_plus.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/config.yaml +0 -0
  120. /pyreduce_astro-0.7a7/pyreduce/masks/mask_crires_plus_det1.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/mask_det1.fits.gz +0 -0
  121. /pyreduce_astro-0.7a7/pyreduce/masks/mask_crires_plus_det2.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/mask_det2.fits.gz +0 -0
  122. /pyreduce_astro-0.7a7/pyreduce/masks/mask_crires_plus_det3.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/mask_det3.fits.gz +0 -0
  123. /pyreduce_astro-0.7a7/pyreduce/wavecal/crires_plus_J1228_det1.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det1.npz +0 -0
  124. /pyreduce_astro-0.7a7/pyreduce/wavecal/crires_plus_J1228_det2.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det2.npz +0 -0
  125. /pyreduce_astro-0.7a7/pyreduce/wavecal/crires_plus_J1228_det3.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/CRIRES_PLUS/wavecal_J1228_det3.npz +0 -0
  126. /pyreduce_astro-0.7a7/pyreduce/instruments/harpn.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPN/config.yaml +0 -0
  127. /pyreduce_astro-0.7a7/pyreduce/wavecal/harpn_harpn_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPN/wavecal_harpn_2D.npz +0 -0
  128. /pyreduce_astro-0.7a7/pyreduce/instruments/harps.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/config.yaml +0 -0
  129. /pyreduce_astro-0.7a7/pyreduce/masks/mask_harps_blue.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/mask_blue.fits.gz +0 -0
  130. /pyreduce_astro-0.7a7/pyreduce/masks/mask_harps_red.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/mask_red.fits.gz +0 -0
  131. /pyreduce_astro-0.7a7/pyreduce/wavecal/harps_blue_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/wavecal_blue_2D.npz +0 -0
  132. /pyreduce_astro-0.7a7/pyreduce/wavecal/harps_blue_pol_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/wavecal_blue_pol_2D.npz +0 -0
  133. /pyreduce_astro-0.7a7/pyreduce/wavecal/harps_red_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/wavecal_red_2D.npz +0 -0
  134. /pyreduce_astro-0.7a7/pyreduce/wavecal/harps_red_pol_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/HARPS/wavecal_red_pol_2D.npz +0 -0
  135. /pyreduce_astro-0.7a7/pyreduce/instruments/jwst_miri.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/JWST_MIRI/config.yaml +0 -0
  136. /pyreduce_astro-0.7a7/pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/JWST_MIRI/mask_lrs_slitless.fits.gz +0 -0
  137. /pyreduce_astro-0.7a7/pyreduce/instruments/jwst_niriss.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/JWST_NIRISS/config.yaml +0 -0
  138. /pyreduce_astro-0.7a7/pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/JWST_NIRISS/mask_gr700xd.fits.gz +0 -0
  139. /pyreduce_astro-0.7a7/pyreduce/instruments/lick_apf.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/LICK_APF/config.yaml +0 -0
  140. /pyreduce_astro-0.7a7/pyreduce/masks/mask_lick_apf_.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/LICK_APF/mask_.fits.gz +0 -0
  141. /pyreduce_astro-0.7a7/pyreduce/instruments/mcdonald.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/MCDONALD/config.yaml +0 -0
  142. /pyreduce_astro-0.7a7/pyreduce/masks/mask_mcdonald.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/MCDONALD/mask.fits.gz +0 -0
  143. /pyreduce_astro-0.7a7/pyreduce/wavecal/mcdonald.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/MCDONALD/wavecal.npz +0 -0
  144. /pyreduce_astro-0.7a7/pyreduce/instruments/metis_ifu.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/METIS_IFU/config.yaml +0 -0
  145. /pyreduce_astro-0.7a7/pyreduce/instruments/metis_lss.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/METIS_LSS/config.yaml +0 -0
  146. /pyreduce_astro-0.7a7/pyreduce/wavecal/metis_lss_l_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/METIS_LSS/wavecal_l_2D.npz +0 -0
  147. /pyreduce_astro-0.7a7/pyreduce/wavecal/metis_lss_m_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/METIS_LSS/wavecal_m_2D.npz +0 -0
  148. /pyreduce_astro-0.7a7/pyreduce/instruments/micado.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/MICADO/config.yaml +0 -0
  149. /pyreduce_astro-0.7a7/pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/MICADO/wavecal_HK_3arcsec_chip5.npz +0 -0
  150. /pyreduce_astro-0.7a7/pyreduce/instruments/neid.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/NEID/config.yaml +0 -0
  151. /pyreduce_astro-0.7a7/pyreduce/instruments/nirspec.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/NIRSPEC/config.yaml +0 -0
  152. /pyreduce_astro-0.7a7/pyreduce/masks/mask_nirspec_nirspec.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/NIRSPEC/mask_nirspec.fits.gz +0 -0
  153. /pyreduce_astro-0.7a7/pyreduce/wavecal/nirspec_K2.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/NIRSPEC/wavecal_K2.npz +0 -0
  154. /pyreduce_astro-0.7a7/pyreduce/instruments/nte.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/NTE/config.yaml +0 -0
  155. /pyreduce_astro-0.7a7/pyreduce/instruments/uves.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/config.yaml +0 -0
  156. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_blue.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_blue.fits.gz +0 -0
  157. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_blue_binned_2_2.fits.gz +0 -0
  158. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_middle.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_middle.fits.gz +0 -0
  159. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_middle_2x2_split.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_middle_2x2_split.fits.gz +0 -0
  160. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_middle_binned_2_2.fits.gz +0 -0
  161. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_red.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_red.fits.gz +0 -0
  162. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_red_2x2.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_red_2x2.fits.gz +0 -0
  163. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_red_2x2_split.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_red_2x2_split.fits.gz +0 -0
  164. /pyreduce_astro-0.7a7/pyreduce/masks/mask_uves_red_binned_2_2.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/mask_red_binned_2_2.fits.gz +0 -0
  165. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_blue_360nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_blue_360nm_2D.npz +0 -0
  166. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_blue_390nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_blue_390nm_2D.npz +0 -0
  167. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_blue_437nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_blue_437nm_2D.npz +0 -0
  168. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_2x2_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_2x2_2D.npz +0 -0
  169. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_565nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_565nm_2D.npz +0 -0
  170. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_580nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_580nm_2D.npz +0 -0
  171. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_600nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_600nm_2D.npz +0 -0
  172. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_665nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_665nm_2D.npz +0 -0
  173. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_middle_860nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_middle_860nm_2D.npz +0 -0
  174. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_red_580nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_red_580nm_2D.npz +0 -0
  175. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_red_600nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_red_600nm_2D.npz +0 -0
  176. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_red_665nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_red_665nm_2D.npz +0 -0
  177. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_red_760nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_red_760nm_2D.npz +0 -0
  178. /pyreduce_astro-0.7a7/pyreduce/wavecal/uves_red_860nm_2D.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/UVES/wavecal_red_860nm_2D.npz +0 -0
  179. /pyreduce_astro-0.7a7/pyreduce/instruments/xshooter.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/XSHOOTER/config.yaml +0 -0
  180. /pyreduce_astro-0.7a7/pyreduce/masks/mask_xshooter_nir.fits.gz → /pyreduce_astro-0.7b2/pyreduce/instruments/XSHOOTER/mask_nir.fits.gz +0 -0
  181. /pyreduce_astro-0.7a7/pyreduce/wavecal/xshooter_nir.npz → /pyreduce_astro-0.7b2/pyreduce/instruments/XSHOOTER/wavecal_nir.npz +0 -0
  182. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/instruments/__init__.py +0 -0
  183. {pyreduce_astro-0.7a7/pyreduce/wavecal → pyreduce_astro-0.7b2/pyreduce/instruments/defaults}/atlas/thar.fits +0 -0
  184. {pyreduce_astro-0.7a7/pyreduce/wavecal → pyreduce_astro-0.7b2/pyreduce/instruments/defaults}/atlas/thar_list.txt +0 -0
  185. {pyreduce_astro-0.7a7/pyreduce/wavecal → pyreduce_astro-0.7b2/pyreduce/instruments/defaults}/atlas/une.fits +0 -0
  186. /pyreduce_astro-0.7a7/pyreduce/instruments/common.yaml → /pyreduce_astro-0.7b2/pyreduce/instruments/defaults/config.yaml +0 -0
  187. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/instruments/filters.py +0 -0
  188. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/instruments/models.py +0 -0
  189. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/tools/__init__.py +0 -0
  190. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/tools/combine.py +0 -0
  191. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/trace.py +0 -0
  192. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/pyreduce/util.py +0 -0
  193. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/argon.line +0 -0
  194. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/bpm_creator.py +0 -0
  195. /pyreduce_astro-0.7a7/pyreduce/wavecal/convert.py → /pyreduce_astro-0.7b2/tools/convert_wavecal.py +0 -0
  196. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/create_wavelength_guess.py +0 -0
  197. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/download_files.py +0 -0
  198. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/ipy_startup.py +0 -0
  199. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/neon.lin +0 -0
  200. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/neon.line +0 -0
  201. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/pymultispec.py +0 -0
  202. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/thar.npz +0 -0
  203. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/wavecal_creator.py +0 -0
  204. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/wavecal_creator_from_existing.py +0 -0
  205. {pyreduce_astro-0.7a7 → pyreduce_astro-0.7b2}/tools/xshooter_nir.json +0 -0
@@ -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,43 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## [0.7b2] - 2026-01-09
5
+
6
+ ### Changed
7
+ - **Reorganize instrument files**: All instrument-related files now in per-instrument directories
8
+ - `instruments/{name}.py` → `instruments/{NAME}/__init__.py`
9
+ - `instruments/{name}.yaml` → `instruments/{NAME}/config.yaml`
10
+ - `settings/settings_{NAME}.json` → `instruments/{NAME}/settings.json`
11
+ - `wavecal/{name}_*.npz` → `instruments/{NAME}/wavecal_*.npz`
12
+ - `masks/mask_{name}_*.fits.gz` → `instruments/{NAME}/mask_*.fits.gz`
13
+ - Base settings and schema moved to `instruments/defaults/`
14
+ - Wavelength atlas files moved to `instruments/defaults/atlas/`
15
+
16
+ ### Removed
17
+ - Orphan mask files for undefined instruments (elodie, sarg, hds, etc.)
18
+
19
+ ## [0.7b1] - 2026-01-06
20
+
21
+ ### Changed
22
+ - **Curvature algorithm rewrite**: Replace 2D model fitting with row-tracking method for better robustness
23
+ - Rename `make_shear.py` to `slit_curve.py`
24
+ - Rename curvature coefficients: `tilt`/`shear` → `p1`/`p2` throughout codebase
25
+ - Rename `arc_extraction` to `simple_extraction`
26
+ - Split curvature `extraction_height` into separate `extraction_height` and `curve_height` parameters
27
+ - Save file renamed from `.shear.npz` to `.curve.npz`
28
+
29
+ ### Added
30
+ - `discover_channels()` for automatic channel detection from data files
31
+ - CLI: `--target` is now optional; loops over all targets if not specified
32
+ - CLI: Uses `$REDUCE_DATA` for base_dir, reads default input_dir from config
33
+ - Comprehensive CLI test coverage
34
+
35
+ ### Fixed
36
+ - Curvature step index error when traces are removed during processing
37
+ - Validate base_dir and input_dir exist with clear error messages
38
+ - File sorting to correctly loop over all nights when not specified
39
+ - CLI dynamic dependency loading for step commands
40
+
4
41
  ## [0.7a7] - 2026-01-04
5
42
 
6
43
  ### Added
@@ -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
@@ -74,7 +80,7 @@ The reduction pipeline consists of these steps (in typical order):
74
80
  | `bias` | `Bias` | Combine bias frames into master bias |
75
81
  | `flat` | `Flat` | Combine flat frames, subtract bias |
76
82
  | `trace` | `OrderTracing` | Trace echelle order positions on flat |
77
- | `curvature` | `SlitCurvatureDetermination` | Measure slit tilt/shear from arc lamp |
83
+ | `curvature` | `SlitCurvatureDetermination` | Measure slit curvature from arc lamp |
78
84
  | `scatter` | `BackgroundScatter` | Model inter-order scattered light |
79
85
  | `norm_flat` | `NormalizeFlatField` | Normalize flat, extract blaze function |
80
86
  | `wavecal_master` | `WavelengthCalibrationMaster` | Extract wavelength calibration spectrum |
@@ -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
 
@@ -260,18 +266,24 @@ uv run reduce list-steps
260
266
 
261
267
  ```bash
262
268
  uv sync # Install dependencies
269
+ uv run reduce-build # Compile C extensions
270
+ uv run reduce-clean # Remove compiled extensions
263
271
  uv run pre-commit install # Setup hooks (once)
264
272
  uv run pytest -m unit # Fast unit tests
265
273
  uv run pytest --instrument=UVES # Test single instrument
266
274
  uv run ruff check --fix . # Lint and fix
267
275
  ```
268
276
 
277
+ After a fresh clone or `rm -rf .venv`, run `uv sync && uv run reduce-build` to set up.
278
+
269
279
  ### Adding Instruments
270
280
 
271
- 1. Create `pyreduce/instruments/name.yaml` with detector/header config
272
- 2. Create `pyreduce/instruments/name.py` if custom logic needed (optional)
273
- 3. Create `pyreduce/settings/settings_NAME.json` for reduction parameters
274
- 4. Add example script to `examples/name_example.py`
281
+ 1. Create `pyreduce/instruments/{NAME}/` directory
282
+ 2. Add `config.yaml` with detector/header config
283
+ 3. Add `settings.json` for reduction parameters (can use `"__inherits__": "defaults"`)
284
+ 4. Add `__init__.py` with instrument class if custom logic needed (optional)
285
+ 5. Add wavecal/mask files if available
286
+ 6. Add example script to `examples/name_example.py`
275
287
 
276
288
  ### Test Organization
277
289
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyreduce-astro
3
- Version: 0.7a7
3
+ Version: 0.7b2
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
@@ -37,7 +37,6 @@ Requires-Dist: scikit-image>=0.22.0
37
37
  Requires-Dist: scipy>=1.11.0
38
38
  Requires-Dist: spectres>=2.2.0
39
39
  Requires-Dist: tqdm>=4.66.0
40
- Requires-Dist: wget>=3.2
41
40
  Description-Content-Type: text/markdown
42
41
 
43
42
  [![CI](https://github.com/ivh/PyReduce/actions/workflows/python-publish.yml/badge.svg)](https://github.com/ivh/PyReduce/actions/workflows/python-publish.yml)
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -21,14 +21,14 @@ steps = (
21
21
  # "bias",
22
22
  # "flat",
23
23
  # "trace",
24
- # "curvature",
24
+ "curvature",
25
25
  # "scatter",
26
26
  # "norm_flat",
27
27
  # "wavecal_master",
28
28
  # "wavecal_init",
29
29
  # "wavecal",
30
30
  # "freq_comb_master",
31
- "freq_comb",
31
+ # "freq_comb",
32
32
  # "science",
33
33
  # "continuum",
34
34
  # "finalize",
@@ -48,6 +48,5 @@ Pipeline.from_instrument(
48
48
  base_dir=base_dir,
49
49
  input_dir=input_dir,
50
50
  output_dir=output_dir,
51
- allow_calibration_only=True,
52
51
  # order_range=(0, 4),
53
52
  ).run()
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce
@@ -17,9 +17,9 @@ night = None
17
17
  channel = ""
18
18
  steps = (
19
19
  "bias",
20
- # "flat",
21
- # "trace",
22
- # "norm_flat",
20
+ "flat",
21
+ "trace",
22
+ "norm_flat",
23
23
  # "wavecal",
24
24
  # "curvature",
25
25
  "science",
@@ -42,5 +42,5 @@ Pipeline.from_instrument(
42
42
  input_dir=input_dir,
43
43
  output_dir=output_dir,
44
44
  # order_range=(0, 25),
45
- plot=0,
45
+ plot=1,
46
46
  ).run()
@@ -1,6 +1,6 @@
1
1
  # /// script
2
2
  # requires-python = ">=3.13"
3
- # dependencies = ["pyreduce-astro>=0.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
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.7a7"]
3
+ # dependencies = ["pyreduce-astro>=0.7b2"]
4
4
  # ///
5
5
  """
6
6
  Simple usage example for PyReduce