pyreduce-astro 0.6.0b5__cp312-cp312-win_amd64.whl

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 (164) hide show
  1. pyreduce/__init__.py +67 -0
  2. pyreduce/__main__.py +106 -0
  3. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.exp +0 -0
  4. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.lib +0 -0
  5. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.exp +0 -0
  6. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.lib +0 -0
  7. pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
  8. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
  9. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
  10. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.exp +0 -0
  11. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.lib +0 -0
  12. pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
  13. pyreduce/clib/__init__.py +0 -0
  14. pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
  15. pyreduce/clib/_slitfunc_2d.cp312-win_amd64.pyd +0 -0
  16. pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
  17. pyreduce/clib/_slitfunc_bd.cp312-win_amd64.pyd +0 -0
  18. pyreduce/clib/build_extract.py +75 -0
  19. pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
  20. pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
  21. pyreduce/clib/slit_func_bd.c +362 -0
  22. pyreduce/clib/slit_func_bd.h +17 -0
  23. pyreduce/clipnflip.py +147 -0
  24. pyreduce/combine_frames.py +855 -0
  25. pyreduce/configuration.py +186 -0
  26. pyreduce/continuum_normalization.py +329 -0
  27. pyreduce/cwrappers.py +404 -0
  28. pyreduce/datasets.py +231 -0
  29. pyreduce/echelle.py +413 -0
  30. pyreduce/estimate_background_scatter.py +129 -0
  31. pyreduce/extract.py +1361 -0
  32. pyreduce/extraction_width.py +77 -0
  33. pyreduce/instruments/__init__.py +0 -0
  34. pyreduce/instruments/andes.json +61 -0
  35. pyreduce/instruments/andes.py +102 -0
  36. pyreduce/instruments/common.json +46 -0
  37. pyreduce/instruments/common.py +675 -0
  38. pyreduce/instruments/crires_plus.json +63 -0
  39. pyreduce/instruments/crires_plus.py +103 -0
  40. pyreduce/instruments/filters.py +195 -0
  41. pyreduce/instruments/harpn.json +136 -0
  42. pyreduce/instruments/harpn.py +201 -0
  43. pyreduce/instruments/harps.json +155 -0
  44. pyreduce/instruments/harps.py +310 -0
  45. pyreduce/instruments/instrument_info.py +140 -0
  46. pyreduce/instruments/instrument_schema.json +221 -0
  47. pyreduce/instruments/jwst_miri.json +53 -0
  48. pyreduce/instruments/jwst_miri.py +29 -0
  49. pyreduce/instruments/jwst_niriss.json +52 -0
  50. pyreduce/instruments/jwst_niriss.py +98 -0
  51. pyreduce/instruments/lick_apf.json +53 -0
  52. pyreduce/instruments/lick_apf.py +35 -0
  53. pyreduce/instruments/mcdonald.json +59 -0
  54. pyreduce/instruments/mcdonald.py +123 -0
  55. pyreduce/instruments/metis_ifu.json +63 -0
  56. pyreduce/instruments/metis_ifu.py +45 -0
  57. pyreduce/instruments/metis_lss.json +65 -0
  58. pyreduce/instruments/metis_lss.py +45 -0
  59. pyreduce/instruments/micado.json +53 -0
  60. pyreduce/instruments/micado.py +45 -0
  61. pyreduce/instruments/neid.json +51 -0
  62. pyreduce/instruments/neid.py +154 -0
  63. pyreduce/instruments/nirspec.json +56 -0
  64. pyreduce/instruments/nirspec.py +215 -0
  65. pyreduce/instruments/nte.json +47 -0
  66. pyreduce/instruments/nte.py +42 -0
  67. pyreduce/instruments/uves.json +59 -0
  68. pyreduce/instruments/uves.py +46 -0
  69. pyreduce/instruments/xshooter.json +66 -0
  70. pyreduce/instruments/xshooter.py +39 -0
  71. pyreduce/make_shear.py +606 -0
  72. pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
  73. pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
  74. pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
  75. pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  76. pyreduce/masks/mask_elodie.fits.gz +0 -0
  77. pyreduce/masks/mask_feros3.fits.gz +0 -0
  78. pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  79. pyreduce/masks/mask_harps_blue.fits.gz +0 -0
  80. pyreduce/masks/mask_harps_red.fits.gz +0 -0
  81. pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  82. pyreduce/masks/mask_hds_red.fits.gz +0 -0
  83. pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  84. pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
  85. pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
  86. pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
  87. pyreduce/masks/mask_mcdonald.fits.gz +0 -0
  88. pyreduce/masks/mask_nes.fits.gz +0 -0
  89. pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
  90. pyreduce/masks/mask_sarg.fits.gz +0 -0
  91. pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  92. pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  93. pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  94. pyreduce/masks/mask_uves_blue.fits.gz +0 -0
  95. pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
  96. pyreduce/masks/mask_uves_middle.fits.gz +0 -0
  97. pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
  98. pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
  99. pyreduce/masks/mask_uves_red.fits.gz +0 -0
  100. pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
  101. pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
  102. pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
  103. pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
  104. pyreduce/rectify.py +138 -0
  105. pyreduce/reduce.py +2205 -0
  106. pyreduce/settings/settings_ANDES.json +89 -0
  107. pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
  108. pyreduce/settings/settings_HARPN.json +73 -0
  109. pyreduce/settings/settings_HARPS.json +69 -0
  110. pyreduce/settings/settings_JWST_MIRI.json +55 -0
  111. pyreduce/settings/settings_JWST_NIRISS.json +55 -0
  112. pyreduce/settings/settings_LICK_APF.json +62 -0
  113. pyreduce/settings/settings_MCDONALD.json +58 -0
  114. pyreduce/settings/settings_METIS_IFU.json +77 -0
  115. pyreduce/settings/settings_METIS_LSS.json +77 -0
  116. pyreduce/settings/settings_MICADO.json +78 -0
  117. pyreduce/settings/settings_NEID.json +73 -0
  118. pyreduce/settings/settings_NIRSPEC.json +58 -0
  119. pyreduce/settings/settings_NTE.json +60 -0
  120. pyreduce/settings/settings_UVES.json +54 -0
  121. pyreduce/settings/settings_XSHOOTER.json +78 -0
  122. pyreduce/settings/settings_pyreduce.json +178 -0
  123. pyreduce/settings/settings_schema.json +827 -0
  124. pyreduce/tools/__init__.py +0 -0
  125. pyreduce/tools/combine.py +117 -0
  126. pyreduce/trace_orders.py +645 -0
  127. pyreduce/util.py +1288 -0
  128. pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
  129. pyreduce/wavecal/atlas/thar.fits +4946 -13
  130. pyreduce/wavecal/atlas/thar_list.txt +4172 -0
  131. pyreduce/wavecal/atlas/une.fits +0 -0
  132. pyreduce/wavecal/convert.py +38 -0
  133. pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
  134. pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
  135. pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
  136. pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
  137. pyreduce/wavecal/harps_blue_2D.npz +0 -0
  138. pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
  139. pyreduce/wavecal/harps_red_2D.npz +0 -0
  140. pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
  141. pyreduce/wavecal/mcdonald.npz +0 -0
  142. pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
  143. pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
  144. pyreduce/wavecal/nirspec_K2.npz +0 -0
  145. pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
  146. pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
  147. pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
  148. pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
  149. pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
  150. pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
  151. pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
  152. pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
  153. pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
  154. pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
  155. pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
  156. pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
  157. pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
  158. pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
  159. pyreduce/wavecal/xshooter_nir.npz +0 -0
  160. pyreduce/wavelength_calibration.py +1873 -0
  161. pyreduce_astro-0.6.0b5.dist-info/METADATA +113 -0
  162. pyreduce_astro-0.6.0b5.dist-info/RECORD +164 -0
  163. pyreduce_astro-0.6.0b5.dist-info/WHEEL +4 -0
  164. pyreduce_astro-0.6.0b5.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,77 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from .util import make_index
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ def estimate_extraction_width(
11
+ img, orders, column_range, plot=False
12
+ ): # pragma: no cover
13
+ raise NotImplementedError
14
+ nrow, ncol = img.shape
15
+ nord, _ = orders.shape
16
+ extraction_width = np.zeros((nord, 2), dtype=int)
17
+
18
+ for i in range(nord):
19
+ # first guess, half way to the next order
20
+ # To order above
21
+ if i < nord - 1:
22
+ beg = max(column_range[[i, i + 1], 0])
23
+ end = min(column_range[[i, i + 1], 1])
24
+ x = np.arange(beg, end)
25
+ y = np.polyval(orders[i], x)
26
+ y_above = np.polyval(orders[i + 1], x)
27
+ width_above = int(np.mean(y_above - y) // 2)
28
+
29
+ # To order below
30
+ if i > 0:
31
+ beg = max(column_range[[i - 1, i], 0])
32
+ end = min(column_range[[i - 1, i], 1])
33
+ x = np.arange(beg, end)
34
+ y = np.polyval(orders[i], x)
35
+ y_below = np.polyval(orders[i - 1], x)
36
+ width_below = int(np.mean(y - y_below) // 2)
37
+ else:
38
+ width_below = width_above
39
+
40
+ if i == nord - 1:
41
+ width_above = width_below
42
+
43
+ beg, end = column_range[i]
44
+ x = np.arange(beg, end)
45
+ y = np.polyval(orders[i], x)
46
+
47
+ y_int = y.astype(int)
48
+ y_above = y_int + width_above
49
+ y_below = y_int - width_below
50
+
51
+ if np.ma.any(y_above >= nrow) or np.ma.any(y_below < 0):
52
+ beg, end = np.where((y_above < nrow) & (y_below >= 0))[0][[0, -1]]
53
+
54
+ index = make_index(y_int - width_below, y_int + width_above, beg, end, True)
55
+
56
+ np.ma.sum(img[index], axis=1)
57
+
58
+ # TODO fit rectangular profile
59
+
60
+ # width = int(4 * coef[2])
61
+
62
+ # plt.plot(p, slitf)
63
+ # plt.plot(p, gaussval(p, *coef))
64
+ # plt.vlines([coef[1] - width, coef[1] + width], slitf.min(), slitf.max())
65
+ # plt.show()
66
+
67
+ # width_below = min(width_below, width)
68
+ # width_above = min(width_above, width)
69
+
70
+ # index = make_index(y_int - width_below, y_int + width_above, beg, end, True)
71
+
72
+ # plt.imshow(np.log(img[index]), aspect="auto", origin="lower")
73
+ # plt.show()
74
+ width = 0.5
75
+ extraction_width[i] = [width, width]
76
+
77
+ return extraction_width
File without changes
@@ -0,0 +1,61 @@
1
+ {
2
+ "__comment__": "red and middle are in the same fits file, with different extensions, i.e. share the same mode identifier, but have different extensions",
3
+ "__instrument__": "ANDES",
4
+ "instrument": "INSTRUME",
5
+ "id_instrument": "ANDES",
6
+ "telescope": "VLT",
7
+ "date": "DATE-OBS",
8
+ "date_format": "fits",
9
+ "id_mode": "ESO INS MODE",
10
+ "id_band": "ESO INS WLEN ID",
11
+ "id_decker": "ESO INS OPTI8 ID",
12
+ "id_lamp": "ESO INS1 LAMP? ID",
13
+ "modes": ["SL", "IFU"],
14
+ "deckers": ["Open", "pos1", "pos2"],
15
+ "bands": ["UBV", "RIZ", "YJH", "K"],
16
+ "settings": ["B", "V", "R", "IZ", "Y", "J", "H", "K"],
17
+ "chips": ["det1"],
18
+ "extension": "CHIP1.INT1",
19
+ "orientation": 0,
20
+ "transpose": false,
21
+ "prescan_x": 5,
22
+ "overscan_x": 5,
23
+ "prescan_y": 5,
24
+ "overscan_y": 5,
25
+ "naxis_x": "NAXIS1",
26
+ "naxis_y": "NAXIS2",
27
+ "gain": "HIERARCH ESO DET CHIP GAIN",
28
+ "readnoise": "HIERARCH ESO DET CHIP RON",
29
+ "dark": "HIERARCH ESO DET DIT",
30
+ "sky": 0,
31
+ "exposure_time": "EXPTIME",
32
+ "image_type": "OBJECT",
33
+ "category": "HIERARCH ESO DPR CATG",
34
+ "ra": "RA",
35
+ "dec": "DEC",
36
+ "jd": "MJD-OBS",
37
+ "longitude": "HIERARCH ESO TEL GEOLON",
38
+ "latitude": "HIERARCH ESO TEL GEOLAT",
39
+ "altitude": "HIERARCH ESO TEL GEOELEV",
40
+ "target": "OBJECT",
41
+ "observation_type": "ESO DPR TYPE",
42
+
43
+ "kw_bias" : "ESO DPR TYPE",
44
+ "kw_flat" : "ESO DPR TYPE",
45
+ "kw_curvature": "ESO DPR TYPE",
46
+ "kw_scatter": "ESO DPR TYPE",
47
+ "kw_orders" : "ESO DPR TYPE",
48
+ "kw_wave": "ESO DPR TYPE",
49
+ "kw_comb": "ESO DPR TYPE",
50
+ "kw_spec": "ESO DPR TYPE",
51
+ "id_bias": "DARK",
52
+ "id_flat": "FLAT",
53
+ "id_orders": "FLAT",
54
+ "id_curvature": "WAVE,FPET",
55
+ "id_scatter": "FLAT",
56
+ "id_wave": "WAVE,UNE",
57
+ "id_comb": "WAVE,FPET",
58
+ "id_spec": "STAR,*,*",
59
+ "id_lamp_wavecal" : "UNe_HCL",
60
+ "id_lamp_etalon": "Etalon_Halogen"
61
+ }
@@ -0,0 +1,102 @@
1
+ """
2
+ Handles instrument specific info for the HARPS spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+ import re
10
+ from itertools import product
11
+
12
+ import numpy as np
13
+
14
+ from .common import Instrument
15
+ from .filters import Filter
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class ANDES(Instrument):
21
+ def __init__(self):
22
+ super().__init__()
23
+ self.filters["lamp"] = Filter(self.info["id_lamp"])
24
+ self.filters["band"] = Filter(self.info["id_band"])
25
+ self.filters["decker"] = Filter(self.info["id_decker"])
26
+ self.shared += ["band", "decker"]
27
+
28
+ def add_header_info(self, header, mode, **kwargs):
29
+ """read data from header and add it as REDUCE keyword back to the header"""
30
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
31
+ # alternatively you can implement all of it here, whatever works
32
+ band, decker, detector = self.parse_mode(mode)
33
+ header = super().add_header_info(header, band)
34
+ self.load_info()
35
+
36
+ return header
37
+
38
+ def get_supported_modes(self):
39
+ settings = self.info["settings"]
40
+ deckers = self.info["deckers"]
41
+ detectors = self.info["chips"]
42
+ modes = [
43
+ "_".join([s, d, c]) for s, d, c in product(settings, deckers, detectors)
44
+ ]
45
+ return modes
46
+
47
+ def parse_mode(self, mode):
48
+ pattern = r"([A-Z]+)(_(Open|pos1|pos2))?_det(\d)"
49
+ match = re.match(pattern, mode, flags=re.IGNORECASE)
50
+ if not match:
51
+ raise ValueError(f"Invalid mode format: {mode}")
52
+ band = match.group(1).upper()
53
+ if match.group(3) is not None:
54
+ decker = match.group(3).lower().capitalize()
55
+ else:
56
+ decker = "Open"
57
+ detector = match.group(4)
58
+ return band, decker, detector
59
+
60
+ def get_expected_values(self, target, night, mode):
61
+ expectations = super().get_expected_values(target, night)
62
+ band, decker, detector = self.parse_mode(mode)
63
+
64
+ for key in expectations.keys():
65
+ if key == "bias":
66
+ continue
67
+ expectations[key]["band"] = band
68
+ expectations[key]["decker"] = decker
69
+
70
+ return expectations
71
+
72
+ def get_extension(self, header, mode):
73
+ band, decker, detector = self.parse_mode(mode)
74
+ extension = int(detector)
75
+ return extension
76
+
77
+ def get_wavecal_filename(self, header, mode, **kwargs):
78
+ """Get the filename of the wavelength calibration config file"""
79
+ cwd = os.path.dirname(__file__)
80
+ fname = f"{self.name}_{mode}.npz"
81
+ fname = os.path.join(cwd, "..", "wavecal", fname)
82
+ return fname
83
+
84
+ def get_mask_filename(self, mode, **kwargs):
85
+ i = self.name.lower()
86
+ band, decker, detector = self.parse_mode(mode)
87
+
88
+ fname = f"mask_{i}_det{detector}.fits.gz"
89
+ cwd = os.path.dirname(__file__)
90
+ fname = os.path.join(cwd, "..", "masks", fname)
91
+ return fname
92
+
93
+ def get_wavelength_range(self, header, mode, **kwargs):
94
+ wmin = [header["ESO INS WLEN MIN%i" % i] for i in range(1, 11)]
95
+ wmax = [header["ESO INS WLEN MAX%i" % i] for i in range(1, 11)]
96
+
97
+ wavelength_range = np.array([wmin, wmax]).T
98
+ # Invert the order numbering
99
+ wavelength_range = wavelength_range[::-1]
100
+ # Convert from nm to Angstrom
101
+ wavelength_range *= 10
102
+ return wavelength_range
@@ -0,0 +1,46 @@
1
+ {
2
+ "__instrument__": "COMMON",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "COMMON",
5
+ "telescope": "TELESCOP",
6
+ "target": "OBJECT",
7
+ "date": "DATE-OBS",
8
+ "date_format": "fits",
9
+ "extension": 0,
10
+ "orientation": 0,
11
+ "transpose": false,
12
+ "prescan_x": 0,
13
+ "overscan_x": 0,
14
+ "prescan_y": 0,
15
+ "overscan_y": 0,
16
+ "naxis_x": "NAXIS1",
17
+ "naxis_y": "NAXIS2",
18
+ "gain": 1,
19
+ "readnoise": 0,
20
+ "dark": 0,
21
+ "sky": 0,
22
+ "exposure_time": "EXPTIME",
23
+ "ra": "RA",
24
+ "dec": "DEC",
25
+ "longitude": null,
26
+ "latitude": null,
27
+ "altitude": null,
28
+ "__comment__": "These define the keywords we look for, and the values they should have in the fits header, to be sorted into that category",
29
+ "kw_bias" : "",
30
+ "kw_flat" : "",
31
+ "kw_curvature": "",
32
+ "kw_scatter": "",
33
+ "kw_orders" : "",
34
+ "kw_wave": "",
35
+ "kw_comb": "",
36
+ "kw_spec": "",
37
+ "id_bias" : "BIAS",
38
+ "id_flat": "FLAT",
39
+ "id_orders": "ORDER",
40
+ "id_curvature": "CURV",
41
+ "id_scatter": "SCATTER",
42
+ "id_wave": "WAVE",
43
+ "id_comb": "COMB",
44
+ "id_spec": "SPEC",
45
+ "wavelength_range": null
46
+ }