pyreduce-astro 0.7a4__cp314-cp314-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 (182) hide show
  1. pyreduce/__init__.py +67 -0
  2. pyreduce/__main__.py +322 -0
  3. pyreduce/cli.py +342 -0
  4. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.exp +0 -0
  5. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.lib +0 -0
  6. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.exp +0 -0
  7. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.lib +0 -0
  8. pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.exp +0 -0
  9. pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.lib +0 -0
  10. pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.exp +0 -0
  11. pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.lib +0 -0
  12. pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
  13. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
  14. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
  15. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.exp +0 -0
  16. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.lib +0 -0
  17. pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.exp +0 -0
  18. pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.lib +0 -0
  19. pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.exp +0 -0
  20. pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.lib +0 -0
  21. pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
  22. pyreduce/clib/__init__.py +0 -0
  23. pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
  24. pyreduce/clib/_slitfunc_2d.cp312-win_amd64.pyd +0 -0
  25. pyreduce/clib/_slitfunc_2d.cp313-win_amd64.pyd +0 -0
  26. pyreduce/clib/_slitfunc_2d.cp314-win_amd64.pyd +0 -0
  27. pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
  28. pyreduce/clib/_slitfunc_bd.cp312-win_amd64.pyd +0 -0
  29. pyreduce/clib/_slitfunc_bd.cp313-win_amd64.pyd +0 -0
  30. pyreduce/clib/_slitfunc_bd.cp314-win_amd64.pyd +0 -0
  31. pyreduce/clib/build_extract.py +75 -0
  32. pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
  33. pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
  34. pyreduce/clib/slit_func_bd.c +362 -0
  35. pyreduce/clib/slit_func_bd.h +17 -0
  36. pyreduce/clipnflip.py +147 -0
  37. pyreduce/combine_frames.py +861 -0
  38. pyreduce/configuration.py +191 -0
  39. pyreduce/continuum_normalization.py +329 -0
  40. pyreduce/cwrappers.py +404 -0
  41. pyreduce/datasets.py +238 -0
  42. pyreduce/echelle.py +413 -0
  43. pyreduce/estimate_background_scatter.py +130 -0
  44. pyreduce/extract.py +1362 -0
  45. pyreduce/extraction_width.py +77 -0
  46. pyreduce/instruments/__init__.py +0 -0
  47. pyreduce/instruments/aj.py +9 -0
  48. pyreduce/instruments/aj.yaml +51 -0
  49. pyreduce/instruments/andes.py +102 -0
  50. pyreduce/instruments/andes.yaml +72 -0
  51. pyreduce/instruments/common.py +711 -0
  52. pyreduce/instruments/common.yaml +57 -0
  53. pyreduce/instruments/crires_plus.py +103 -0
  54. pyreduce/instruments/crires_plus.yaml +101 -0
  55. pyreduce/instruments/filters.py +195 -0
  56. pyreduce/instruments/harpn.py +203 -0
  57. pyreduce/instruments/harpn.yaml +140 -0
  58. pyreduce/instruments/harps.py +312 -0
  59. pyreduce/instruments/harps.yaml +144 -0
  60. pyreduce/instruments/instrument_info.py +140 -0
  61. pyreduce/instruments/jwst_miri.py +29 -0
  62. pyreduce/instruments/jwst_miri.yaml +53 -0
  63. pyreduce/instruments/jwst_niriss.py +98 -0
  64. pyreduce/instruments/jwst_niriss.yaml +60 -0
  65. pyreduce/instruments/lick_apf.py +35 -0
  66. pyreduce/instruments/lick_apf.yaml +60 -0
  67. pyreduce/instruments/mcdonald.py +123 -0
  68. pyreduce/instruments/mcdonald.yaml +56 -0
  69. pyreduce/instruments/metis_ifu.py +45 -0
  70. pyreduce/instruments/metis_ifu.yaml +62 -0
  71. pyreduce/instruments/metis_lss.py +45 -0
  72. pyreduce/instruments/metis_lss.yaml +62 -0
  73. pyreduce/instruments/micado.py +45 -0
  74. pyreduce/instruments/micado.yaml +62 -0
  75. pyreduce/instruments/models.py +257 -0
  76. pyreduce/instruments/neid.py +156 -0
  77. pyreduce/instruments/neid.yaml +61 -0
  78. pyreduce/instruments/nirspec.py +215 -0
  79. pyreduce/instruments/nirspec.yaml +63 -0
  80. pyreduce/instruments/nte.py +42 -0
  81. pyreduce/instruments/nte.yaml +55 -0
  82. pyreduce/instruments/uves.py +46 -0
  83. pyreduce/instruments/uves.yaml +65 -0
  84. pyreduce/instruments/xshooter.py +39 -0
  85. pyreduce/instruments/xshooter.yaml +63 -0
  86. pyreduce/make_shear.py +607 -0
  87. pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
  88. pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
  89. pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
  90. pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  91. pyreduce/masks/mask_elodie.fits.gz +0 -0
  92. pyreduce/masks/mask_feros3.fits.gz +0 -0
  93. pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  94. pyreduce/masks/mask_harps_blue.fits.gz +0 -0
  95. pyreduce/masks/mask_harps_red.fits.gz +0 -0
  96. pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  97. pyreduce/masks/mask_hds_red.fits.gz +0 -0
  98. pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  99. pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
  100. pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
  101. pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
  102. pyreduce/masks/mask_mcdonald.fits.gz +0 -0
  103. pyreduce/masks/mask_nes.fits.gz +0 -0
  104. pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
  105. pyreduce/masks/mask_sarg.fits.gz +0 -0
  106. pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  107. pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  108. pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  109. pyreduce/masks/mask_uves_blue.fits.gz +0 -0
  110. pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
  111. pyreduce/masks/mask_uves_middle.fits.gz +0 -0
  112. pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
  113. pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
  114. pyreduce/masks/mask_uves_red.fits.gz +0 -0
  115. pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
  116. pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
  117. pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
  118. pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
  119. pyreduce/pipeline.py +619 -0
  120. pyreduce/rectify.py +138 -0
  121. pyreduce/reduce.py +2065 -0
  122. pyreduce/settings/settings_AJ.json +19 -0
  123. pyreduce/settings/settings_ANDES.json +89 -0
  124. pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
  125. pyreduce/settings/settings_HARPN.json +73 -0
  126. pyreduce/settings/settings_HARPS.json +69 -0
  127. pyreduce/settings/settings_JWST_MIRI.json +55 -0
  128. pyreduce/settings/settings_JWST_NIRISS.json +55 -0
  129. pyreduce/settings/settings_LICK_APF.json +62 -0
  130. pyreduce/settings/settings_MCDONALD.json +58 -0
  131. pyreduce/settings/settings_METIS_IFU.json +77 -0
  132. pyreduce/settings/settings_METIS_LSS.json +77 -0
  133. pyreduce/settings/settings_MICADO.json +78 -0
  134. pyreduce/settings/settings_NEID.json +73 -0
  135. pyreduce/settings/settings_NIRSPEC.json +58 -0
  136. pyreduce/settings/settings_NTE.json +60 -0
  137. pyreduce/settings/settings_UVES.json +54 -0
  138. pyreduce/settings/settings_XSHOOTER.json +78 -0
  139. pyreduce/settings/settings_pyreduce.json +184 -0
  140. pyreduce/settings/settings_schema.json +850 -0
  141. pyreduce/tools/__init__.py +0 -0
  142. pyreduce/tools/combine.py +117 -0
  143. pyreduce/trace.py +979 -0
  144. pyreduce/util.py +1366 -0
  145. pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
  146. pyreduce/wavecal/atlas/thar.fits +4946 -13
  147. pyreduce/wavecal/atlas/thar_list.txt +4172 -0
  148. pyreduce/wavecal/atlas/une.fits +0 -0
  149. pyreduce/wavecal/convert.py +38 -0
  150. pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
  151. pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
  152. pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
  153. pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
  154. pyreduce/wavecal/harps_blue_2D.npz +0 -0
  155. pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
  156. pyreduce/wavecal/harps_red_2D.npz +0 -0
  157. pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
  158. pyreduce/wavecal/mcdonald.npz +0 -0
  159. pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
  160. pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
  161. pyreduce/wavecal/nirspec_K2.npz +0 -0
  162. pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
  163. pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
  164. pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
  165. pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
  166. pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
  167. pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
  168. pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
  169. pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
  170. pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
  171. pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
  172. pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
  173. pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
  174. pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
  175. pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
  176. pyreduce/wavecal/xshooter_nir.npz +0 -0
  177. pyreduce/wavelength_calibration.py +1871 -0
  178. pyreduce_astro-0.7a4.dist-info/METADATA +106 -0
  179. pyreduce_astro-0.7a4.dist-info/RECORD +182 -0
  180. pyreduce_astro-0.7a4.dist-info/WHEEL +4 -0
  181. pyreduce_astro-0.7a4.dist-info/entry_points.txt +2 -0
  182. pyreduce_astro-0.7a4.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,61 @@
1
+ # NEID instrument configuration
2
+ # Note: red and middle are in the same fits file, with different extensions,
3
+ # i.e. share the same mode identifier, but have different extensions
4
+
5
+ __instrument__: NEID
6
+ id_instrument: NEID
7
+ instrument: INSTRUME
8
+ telescope: TELESCOP
9
+
10
+ date: DATE-OBS
11
+ date_format: fits
12
+
13
+ arms: [HR]
14
+ arms_id: [HR]
15
+ namps: NAMPS
16
+ extension: "AMPLIFIER {amp}"
17
+ orientation: 0
18
+ transpose: false
19
+
20
+ prescan_y: 0
21
+ overscan_y: 0
22
+ naxis_x: NAXIS1
23
+ naxis_y: NAXIS2
24
+
25
+ gain: CCDGAIN
26
+ readnoise: CCDRN
27
+ exposure_time: EXPTIME
28
+
29
+ image_type: "HIERARCH TNG OBS TARG NAME"
30
+ category: "HIERARCH TNG DPR CATG"
31
+ ra: RA
32
+ dec: DEC
33
+ longitude: GEOLON
34
+ latitude: GEOLAT
35
+ altitude: GEOELEV
36
+ target: OBJECT
37
+ instrument_mode: OBS-MODE
38
+ observation_type: "TNG DPR TYPE"
39
+
40
+ id_fiber_sci: "LAMP,DARK,TUN"
41
+ id_fiber_cal: "DARK,LAMP,TUN"
42
+ id_fiber_sky: "DARK,LAMP,TUN"
43
+
44
+ # File classification keywords and patterns
45
+ kw_bias: OBJECT
46
+ kw_flat: OBJECT
47
+ kw_curvature: OBJECT
48
+ kw_scatter: OBJECT
49
+ kw_orders: OBJECT
50
+ kw_wave: OBJECT
51
+ kw_comb: OBJECT
52
+ kw_spec: OBJECT
53
+
54
+ id_bias: "BIAS,BIAS"
55
+ id_flat: "LAMP,LAMP,TUN"
56
+ id_orders: "LAMP,LAMP,TUN"
57
+ id_curvature: "WAVE,WAVE,THAR2"
58
+ id_scatter: "LAMP,LAMP,TUN"
59
+ id_wave: "WAVE,WAVE,THAR2"
60
+ id_comb: "WAVE,WAVE,COMB"
61
+ id_spec: "STAR,*"
@@ -0,0 +1,215 @@
1
+ """
2
+ Handles instrument specific info for the UVES spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import glob
8
+ import logging
9
+ import os.path
10
+ from datetime import datetime
11
+
12
+ import numpy as np
13
+ from astropy.io import fits
14
+ from dateutil import parser
15
+ from tqdm import tqdm
16
+
17
+ from .common import Instrument, observation_date_to_night
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class NIRSPEC(Instrument):
23
+ @staticmethod
24
+ def get_arm(header):
25
+ # TODO figure out the parameters to use for this
26
+ try:
27
+ fil1pos = header["FIL1POS"]
28
+ fil2pos = header["FIL2POS"]
29
+ filter = header["FILNAME"]
30
+ except KeyError:
31
+ return ""
32
+
33
+ # TODO get other settings
34
+ if filter == "NIRSPEC-1":
35
+ raise ValueError
36
+ elif filter == "NIRSPEC-2":
37
+ raise ValueError
38
+ elif filter == "NIRSPEC-4":
39
+ raise ValueError
40
+ elif filter == "NIRSPEC-5":
41
+ raise ValueError
42
+ elif filter == "NIRSPEC-7":
43
+ if fil1pos == 11 and fil2pos == 18:
44
+ setting = "K2"
45
+ else:
46
+ raise ValueError
47
+ else:
48
+ raise ValueError
49
+
50
+ return setting
51
+
52
+ def add_header_info(self, header, arm, **kwargs):
53
+ """read data from header and add it as REDUCE keyword back to the header"""
54
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
55
+ # alternatively you can implement all of it here, whatever works
56
+ header = super().add_header_info(header, arm)
57
+ # header["e_setting"] = NIRSPEC.get_arm(header)
58
+ header["EXPTIME"] = header.get("ITIME", 0) * header.get("COADDS", 0)
59
+ return header
60
+
61
+ def sort_files(self, input_dir, target, night, arm, calibration_dir, **kwargs):
62
+ """
63
+ Sort a set of fits files into different categories
64
+ types are: bias, flat, wavecal, orderdef, spec
65
+
66
+ Parameters
67
+ ----------
68
+ input_dir : str
69
+ input directory containing the files to sort
70
+ target : str
71
+ name of the target as in the fits headers
72
+ night : str
73
+ observation night, possibly with wildcards
74
+ arm : str
75
+ instrument arm
76
+ Returns
77
+ -------
78
+ files_per_night : list[dict{str:dict{str:list[str]}}]
79
+ a list of file sets, one entry per night, where each night consists of a dictionary with one entry per setting,
80
+ each fileset has five lists of filenames: "bias", "flat", "order", "wave", "spec", organised in another dict
81
+ nights_out : list[datetime]
82
+ a list of observation times, same order as files_per_night
83
+ """
84
+
85
+ # TODO allow several names for the target?
86
+
87
+ info = self.info
88
+ target = target.casefold()
89
+ instrument = self.__class__.__name__
90
+
91
+ # Try matching with nights
92
+ try:
93
+ night = parser.parse(night).date()
94
+ individual_nights = [night]
95
+ except ValueError:
96
+ # if the input night can't be parsed, use all nights
97
+ # Usually the case if wildcards are involved
98
+ individual_nights = "all"
99
+
100
+ # find all fits files in the input dir(s)
101
+ input_dir = input_dir.format(
102
+ instrument=instrument.upper(), target=target, arm=arm, night=night
103
+ )
104
+ files = glob.glob(input_dir + "/*.fits")
105
+ files += glob.glob(input_dir + "/*.fits.gz")
106
+ files = np.array(files)
107
+
108
+ # Initialize arrays
109
+ # observed object
110
+ ob = np.zeros(len(files), dtype="U20")
111
+ # observed night, parsed into a datetime object
112
+ ni = np.zeros(len(files), dtype=datetime)
113
+ # instrument, used for observation
114
+ it = np.zeros(len(files), dtype="U20")
115
+
116
+ for i, f in enumerate(files):
117
+ with fits.open(f) as hdu:
118
+ h = hdu[0].header
119
+ ob[i] = h.get(info["target"], "")
120
+ ni_tmp = h.get(info["date"], "")
121
+ it[i] = h.get(info["instrument"], "")
122
+
123
+ # Sanitize input
124
+ ni[i] = observation_date_to_night(ni_tmp)
125
+ ob[i] = ob[i].replace("-", "").replace(" ", "").casefold()
126
+
127
+ if isinstance(individual_nights, str) and individual_nights == "all":
128
+ individual_nights = np.unique(ni)
129
+ logger.info(
130
+ "Can't parse night %s, use all %i individual nights instead",
131
+ night,
132
+ len(individual_nights),
133
+ )
134
+
135
+ files_per_observation = []
136
+ cache = {}
137
+
138
+ for ind_night in tqdm(individual_nights):
139
+ # Select files for this night, this instrument, this instrument arm
140
+ selection = (ni == ind_night) & (it == instrument) & (ob == target)
141
+
142
+ for file in files[selection]:
143
+ # Read caliblist
144
+ caliblist = file[:-8] + ".caliblist"
145
+ caliblist = np.genfromtxt(
146
+ caliblist, skip_header=8, dtype=str, delimiter=" ", usecols=(0)
147
+ )
148
+ caliblist = np.array(
149
+ [
150
+ os.path.join(input_dir, calibration_dir, c) + ".gz"
151
+ for c in caliblist
152
+ ]
153
+ )
154
+
155
+ tp = np.zeros(len(caliblist), dtype="U20")
156
+ for i, c in enumerate(caliblist):
157
+ try:
158
+ tp[i] = cache[c]
159
+ except KeyError:
160
+ h = fits.open(c)[0].header
161
+ if h[info["id_flat"]] == 1:
162
+ tp[i] = "flat"
163
+ elif (
164
+ h[info["id_neon"]] == 1
165
+ or h[info["id_argon"]] == 1
166
+ or h[info["id_krypton"]] == 1
167
+ or h[info["id_xenon"]] == 1
168
+ ):
169
+ tp[i] = "wavecal"
170
+ elif h[info["id_etalon"]] == 1:
171
+ tp[i] = "freq_comb"
172
+ else:
173
+ tp[i] = "bias"
174
+ cache[c] = tp[i]
175
+ files_this_observation = {
176
+ "bias": caliblist[tp == "bias"],
177
+ "flat": caliblist[tp == "flat"],
178
+ "orders": caliblist[tp == "flat"],
179
+ "wavecal_master": caliblist[tp == "wavecal"],
180
+ "freq_comb_master": caliblist[tp == "freq_comb"],
181
+ "science": [file],
182
+ }
183
+ files_this_observation["curvature"] = (
184
+ files_this_observation["freq_comb_master"]
185
+ if len(files_this_observation["freq_comb_master"]) != 0
186
+ else files_this_observation["wavecal_master"]
187
+ )
188
+ files_this_observation["scatter"] = files_this_observation["orders"]
189
+
190
+ files_per_observation.append(
191
+ ({"night": ind_night, "target": target}, files_this_observation)
192
+ )
193
+
194
+ return files_per_observation
195
+
196
+ def get_wavecal_filename(self, header, arm, **kwargs):
197
+ """Get the filename of the wavelength calibration config file"""
198
+ info = self.info
199
+ if header[info["id_neon"]] == 1:
200
+ pass
201
+ elif header[info["id_argon"]] == 1:
202
+ pass
203
+ elif header[info["id_krypton"]] == 1:
204
+ pass
205
+ elif header[info["id_xenon"]] == 1:
206
+ pass
207
+ else:
208
+ raise ValueError("Wavelength calibration element not recognised")
209
+
210
+ echelle_setting = "K2"
211
+
212
+ cwd = os.path.dirname(__file__)
213
+ fname = f"nirspec_{echelle_setting}.npz"
214
+ fname = os.path.join(cwd, "..", "wavecal", fname)
215
+ return fname
@@ -0,0 +1,63 @@
1
+ # NIRSPEC (Keck) instrument configuration
2
+
3
+ __instrument__: NIRSPEC
4
+ instrument: CURRINST
5
+ id_instrument: NIRSPEC
6
+ telescope: Keck
7
+
8
+ date: DATE-OBS
9
+ date_format: fits
10
+
11
+ arms: [NIRSPEC]
12
+ extension: 0
13
+ orientation: 0
14
+ transpose: false
15
+
16
+ prescan_x: 5
17
+ overscan_x: 5
18
+ prescan_y: 0
19
+ overscan_y: 0
20
+ naxis_x: NAXIS1
21
+ naxis_y: NAXIS2
22
+
23
+ gain: DETGAIN
24
+ readnoise: DETRN
25
+ bias: DETBIAS
26
+ dark: 0
27
+ sky: 0
28
+ air: AIRMASS
29
+ exposure_time: ITIME
30
+
31
+ image_type: OBJECT
32
+ ra: HA
33
+ dec: DEC
34
+ jd: MJD-OBS
35
+ longitude: -155.4783333
36
+ latitude: 19.8283333
37
+ altitude: 4160
38
+ target: OBJECT
39
+
40
+ id_neon: NEON
41
+ id_argon: ARGON
42
+ id_krypton: KRYPTON
43
+ id_xenon: XENON
44
+ id_etalon: ETALON
45
+
46
+ # File classification keywords and patterns
47
+ kw_bias: null
48
+ kw_flat: null
49
+ kw_curvature: null
50
+ kw_scatter: null
51
+ kw_orders: null
52
+ kw_wave: null
53
+ kw_comb: null
54
+ kw_spec: null
55
+
56
+ id_bias: BIAS
57
+ id_flat: FLAT
58
+ id_orders: null
59
+ id_curvature: null
60
+ id_scatter: null
61
+ id_wave: null
62
+ id_comb: null
63
+ id_spec: null
@@ -0,0 +1,42 @@
1
+ """
2
+ Handles instrument specific info for the NTE spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+
10
+ from .common import Instrument
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class NTE(Instrument):
16
+ def add_header_info(self, header, arm, **kwargs):
17
+ """read data from header and add it as REDUCE keyword back to the header"""
18
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
19
+ # alternatively you can implement all of it here, whatever works
20
+ header = super().add_header_info(header, arm)
21
+
22
+ header["e_ra"] /= 15
23
+ if header["e_jd"] is not None:
24
+ header["e_jd"] += header["e_exptime"] / (7200 * 24) + 0.5
25
+
26
+ return header
27
+
28
+ def get_wavecal_filename(self, header, arm, **kwargs):
29
+ """Get the filename of the wavelength calibration config file"""
30
+ info = self.info
31
+ specifier = int(header[info["wavecal_specifier"]])
32
+
33
+ cwd = os.path.dirname(__file__)
34
+ fname = "{instrument}_{arm}_{specifier}nm_2D.npz".format(
35
+ instrument="nte", arm=arm.lower(), specifier=specifier
36
+ )
37
+ fname = os.path.join(cwd, "..", "wavecal", fname)
38
+ return fname
39
+
40
+ def get_wavelength_range(self, header, arm):
41
+ wave = 7 * [7000, 20_000]
42
+ return wave
@@ -0,0 +1,55 @@
1
+ # NTE instrument configuration
2
+
3
+ __instrument__: NTE
4
+ instrument: INSTRUME
5
+ id_instrument: NTE
6
+ telescope: NOT
7
+
8
+ category: IMAGECAT
9
+ target: OBJECT
10
+ date: DATE-OBS
11
+ date_format: fits
12
+
13
+ arms: [VIS, NIR]
14
+ extension: 0
15
+ orientation: 0
16
+
17
+ prescan_x: 0
18
+ overscan_x: 0
19
+ prescan_y: 0
20
+ overscan_y: 0
21
+ naxis_x: NAXIS1
22
+ naxis_y: NAXIS2
23
+
24
+ gain: GAIN
25
+ readnoise: RDNOISE
26
+ dark: DARK
27
+ sky: 0
28
+ exposure_time: EXPTIME
29
+
30
+ ra: RA
31
+ dec: DEC
32
+ longitude: LONGITUD
33
+ latitude: LATITUD
34
+ altitude: ELEVAT
35
+
36
+ # File classification keywords and patterns
37
+ kw_bias: IMAGETYP
38
+ kw_dark: IMAGETYP
39
+ kw_flat: IMAGETYP
40
+ kw_curvature: IMAGETYP
41
+ kw_scatter: IMAGETYP
42
+ kw_orders: IMAGETYP
43
+ kw_wave: IMAGETYP
44
+ kw_comb: IMAGETYP
45
+ kw_spec: IMAGETYP
46
+
47
+ id_bias: BIAS
48
+ id_dark: DARK
49
+ id_flat: "LAMP,FLAT"
50
+ id_orders: "LAMP,ORDERDEF"
51
+ id_curvature: "LAMP,FPE"
52
+ id_scatter: "LAMP,FLAT"
53
+ id_wave: "LAMP,WAVE"
54
+ id_comb: "LAMP,FPE"
55
+ id_spec: OBJECT
@@ -0,0 +1,46 @@
1
+ """
2
+ Handles instrument specific info for the UVES spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+
10
+ from .common import Instrument
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class UVES(Instrument):
16
+ def add_header_info(self, header, arm, **kwargs):
17
+ """read data from header and add it as REDUCE keyword back to the header"""
18
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
19
+ # alternatively you can implement all of it here, whatever works
20
+ header = super().add_header_info(header, arm)
21
+
22
+ header["e_ra"] /= 15
23
+ if header["e_jd"] is not None:
24
+ header["e_jd"] += header["e_exptime"] / (7200 * 24) + 0.5
25
+
26
+ return header
27
+
28
+ def get_wavecal_filename(self, header, arm, **kwargs):
29
+ """Get the filename of the wavelength calibration config file"""
30
+ info = self.info
31
+ specifier = int(header[info["wavecal_specifier"]])
32
+
33
+ cwd = os.path.dirname(__file__)
34
+ fname = "{instrument}_{arm}_{specifier}nm_2D.npz".format(
35
+ instrument="uves", arm=arm.lower(), specifier=specifier
36
+ )
37
+ fname = os.path.join(cwd, "..", "wavecal", fname)
38
+ return fname
39
+
40
+ def get_mask_filename(self, arm, **kwargs):
41
+ i = self.name.lower()
42
+ a = arm.lower()
43
+ fname = f"mask_{i}_{a}.fits.gz"
44
+ cwd = os.path.dirname(__file__)
45
+ fname = os.path.join(cwd, "..", "masks", fname)
46
+ return fname
@@ -0,0 +1,65 @@
1
+ # UVES instrument configuration
2
+ # Same structure as JSON, just YAML format for readability
3
+
4
+ __instrument__: UVES
5
+ instrument: INSTRUME
6
+ id_instrument: UVES
7
+ telescope: VLT
8
+
9
+ date: DATE-OBS
10
+ date_format: fits
11
+
12
+ arms: [BLUE, MIDDLE, RED]
13
+ arms_id: [blue, red, red]
14
+ extension: [0, 2, 1]
15
+ id: [[1, 5], [1, 4], [1, 4]]
16
+ orientation: [2, 1, 1]
17
+ transpose: false
18
+
19
+ prescan_x: "HIERARCH ESO DET OUT{id[0]} PRSCX"
20
+ overscan_x: "HIERARCH ESO DET OUT{id[0]} OVSCX"
21
+ prescan_y: 0
22
+ overscan_y: 0
23
+ naxis_x: NAXIS1
24
+ naxis_y: NAXIS2
25
+
26
+ gain: "HIERARCH ESO DET OUT{id[0]} CONAD"
27
+ readnoise: "HIERARCH ESO DET OUT{id[0]} RON"
28
+ dark: "HIERARCH ESO INS DET{id[1]} OFFDRK"
29
+ sky: "HIERARCH ESO INS DET{id[1]} OFFSKY"
30
+ exposure_time: EXPTIME
31
+
32
+ ra: RA
33
+ dec: DEC
34
+ longitude: "HIERARCH ESO TEL GEOLON"
35
+ latitude: "HIERARCH ESO TEL GEOLAT"
36
+ altitude: "HIERARCH ESO TEL GEOELEV"
37
+
38
+ target: OBJECT
39
+ wavecal_element: thar
40
+ wavecal_specifier: "ESO INS GRAT2 WLEN"
41
+
42
+ category: "HIERARCH ESO DPR CATG"
43
+ image_type: OBJECT
44
+ observation_type: "ESO DPR TYPE"
45
+ instrument_mode: "ESO INS MODE"
46
+ instrument_mode_alternative: "ESO TPL NAME"
47
+
48
+ # File classification keywords and patterns
49
+ kw_bias: "ESO DPR TYPE"
50
+ kw_flat: "ESO DPR TYPE"
51
+ kw_curvature: OBJECT
52
+ kw_scatter: "ESO DPR TYPE"
53
+ kw_orders: "ESO DPR TYPE"
54
+ kw_wave: OBJECT
55
+ kw_comb: null
56
+ kw_spec: "ESO DPR TYPE"
57
+
58
+ id_bias: BIAS
59
+ id_flat: "LAMP,FLAT"
60
+ id_orders: "LAMP,ORDERDEF"
61
+ id_curvature: "LAMP,WAVE"
62
+ id_scatter: "LAMP,ORDERDEF"
63
+ id_wave: "LAMP,WAVE"
64
+ id_comb: null
65
+ id_spec: "OBJECT,POINT"
@@ -0,0 +1,39 @@
1
+ """
2
+ Handles instrument specific info for the UVES spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+
10
+ from .common import Instrument
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class XSHOOTER(Instrument):
16
+ def add_header_info(self, header, arm, **kwargs):
17
+ """read data from header and add it as REDUCE keyword back to the header"""
18
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
19
+ # alternatively you can implement all of it here, whatever works
20
+ header = super().add_header_info(header, arm)
21
+
22
+ header["e_backg"] = (
23
+ header["e_readn"] + header["e_exptime"] * header["e_drk"] / 3600
24
+ )
25
+
26
+ header["e_ra"] /= 15
27
+ if header["e_jd"] is not None:
28
+ header["e_jd"] += header["e_exptime"] / 2 / 3600 / 24 + 0.5
29
+
30
+ return header
31
+
32
+ def get_wavecal_filename(self, header, arm, **kwargs):
33
+ """Get the filename of the wavelength calibration config file"""
34
+ self.load_info()
35
+
36
+ cwd = os.path.dirname(__file__)
37
+ fname = f"xshooter_{arm.lower()}.npz"
38
+ fname = os.path.join(cwd, "..", "wavecal", fname)
39
+ return fname
@@ -0,0 +1,63 @@
1
+ # XSHOOTER instrument configuration
2
+
3
+ __instrument__: XSHOOTER
4
+ instrument: INSTRUME
5
+ id_instrument: "SHOOT|XSHOOTER"
6
+ telescope: VLT
7
+
8
+ date: MJD-OBS
9
+ date_format: mjd
10
+
11
+ arms: [UVB, VIS, NIR]
12
+ kw_arm: "ESO DET CHIP*NAME"
13
+ id_arm: ["E2V CC44-82", "MIT/LL CCID-20", "Hawaii2RG"]
14
+ extension: 0
15
+ orientation: [1, 0, 0]
16
+ transpose: false
17
+
18
+ prescan_x: 0
19
+ overscan_x: 0
20
+ prescan_y: 0
21
+ overscan_y: 0
22
+ naxis_x: NAXIS1
23
+ naxis_y: NAXIS2
24
+
25
+ gain: "HIERARCH ESO DET OUT1 GAIN"
26
+ readnoise: "HIERARCH ESO DET OUT1 RON"
27
+ dark: 10
28
+ exposure_time: EXPTIME
29
+
30
+ ra: RA
31
+ dec: DEC
32
+ jd: MJD-OBS
33
+ longitude: "HIERARCH ESO TEL GEOLON"
34
+ latitude: "HIERARCH ESO TEL GEOLAT"
35
+ altitude: "HIERARCH ESO TEL GEOELEV"
36
+ instrument_mode: "HIERARCH ESO SEQ ARM"
37
+ observation_type: "HIERARCH ESO DPR TYPE"
38
+ observation_category: "HIERARCH ESO DPR CATG"
39
+ target: "HIERARCH ESO OBS TARG NAME"
40
+ object: OBJECT
41
+
42
+ id_dark: DARK
43
+ id_format: "LAMP,FMTCHK"
44
+ id_tell: "STD,TELLURIC"
45
+
46
+ # File classification keywords and patterns
47
+ kw_bias: "HIERARCH ESO DPR TYPE"
48
+ kw_flat: "HIERARCH ESO DPR TYPE"
49
+ kw_curvature: "HIERARCH ESO DPR TYPE"
50
+ kw_scatter: "HIERARCH ESO DPR TYPE"
51
+ kw_orders: "HIERARCH ESO DPR TYPE"
52
+ kw_wave: "HIERARCH ESO DPR TYPE"
53
+ kw_comb: null
54
+ kw_spec: "HIERARCH ESO DPR TYPE"
55
+
56
+ id_bias: DARK
57
+ id_flat: "LAMP,FLAT"
58
+ id_orders: "LAMP,ORDERDEF"
59
+ id_curvature: "LAMP,WAVE"
60
+ id_scatter: "LAMP,FLAT"
61
+ id_wave: "LAMP,WAVE"
62
+ id_comb: null
63
+ id_spec: OBJECT