pyreduce-astro 0.6.0__cp311-cp311-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 (158) 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.obj +0 -0
  6. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
  7. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
  8. pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
  9. pyreduce/clib/__init__.py +0 -0
  10. pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
  11. pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
  12. pyreduce/clib/build_extract.py +75 -0
  13. pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
  14. pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
  15. pyreduce/clib/slit_func_bd.c +362 -0
  16. pyreduce/clib/slit_func_bd.h +17 -0
  17. pyreduce/clipnflip.py +147 -0
  18. pyreduce/combine_frames.py +855 -0
  19. pyreduce/configuration.py +186 -0
  20. pyreduce/continuum_normalization.py +329 -0
  21. pyreduce/cwrappers.py +404 -0
  22. pyreduce/datasets.py +231 -0
  23. pyreduce/echelle.py +413 -0
  24. pyreduce/estimate_background_scatter.py +129 -0
  25. pyreduce/extract.py +1361 -0
  26. pyreduce/extraction_width.py +77 -0
  27. pyreduce/instruments/__init__.py +0 -0
  28. pyreduce/instruments/andes.json +61 -0
  29. pyreduce/instruments/andes.py +102 -0
  30. pyreduce/instruments/common.json +46 -0
  31. pyreduce/instruments/common.py +683 -0
  32. pyreduce/instruments/crires_plus.json +63 -0
  33. pyreduce/instruments/crires_plus.py +103 -0
  34. pyreduce/instruments/filters.py +195 -0
  35. pyreduce/instruments/harpn.json +136 -0
  36. pyreduce/instruments/harpn.py +201 -0
  37. pyreduce/instruments/harps.json +155 -0
  38. pyreduce/instruments/harps.py +310 -0
  39. pyreduce/instruments/instrument_info.py +140 -0
  40. pyreduce/instruments/instrument_schema.json +318 -0
  41. pyreduce/instruments/jwst_miri.json +53 -0
  42. pyreduce/instruments/jwst_miri.py +29 -0
  43. pyreduce/instruments/jwst_niriss.json +52 -0
  44. pyreduce/instruments/jwst_niriss.py +98 -0
  45. pyreduce/instruments/lick_apf.json +53 -0
  46. pyreduce/instruments/lick_apf.py +35 -0
  47. pyreduce/instruments/mcdonald.json +59 -0
  48. pyreduce/instruments/mcdonald.py +123 -0
  49. pyreduce/instruments/metis_ifu.json +63 -0
  50. pyreduce/instruments/metis_ifu.py +45 -0
  51. pyreduce/instruments/metis_lss.json +65 -0
  52. pyreduce/instruments/metis_lss.py +45 -0
  53. pyreduce/instruments/micado.json +53 -0
  54. pyreduce/instruments/micado.py +45 -0
  55. pyreduce/instruments/neid.json +51 -0
  56. pyreduce/instruments/neid.py +154 -0
  57. pyreduce/instruments/nirspec.json +56 -0
  58. pyreduce/instruments/nirspec.py +215 -0
  59. pyreduce/instruments/nte.json +47 -0
  60. pyreduce/instruments/nte.py +42 -0
  61. pyreduce/instruments/uves.json +59 -0
  62. pyreduce/instruments/uves.py +46 -0
  63. pyreduce/instruments/xshooter.json +66 -0
  64. pyreduce/instruments/xshooter.py +39 -0
  65. pyreduce/make_shear.py +606 -0
  66. pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
  67. pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
  68. pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
  69. pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  70. pyreduce/masks/mask_elodie.fits.gz +0 -0
  71. pyreduce/masks/mask_feros3.fits.gz +0 -0
  72. pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  73. pyreduce/masks/mask_harps_blue.fits.gz +0 -0
  74. pyreduce/masks/mask_harps_red.fits.gz +0 -0
  75. pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  76. pyreduce/masks/mask_hds_red.fits.gz +0 -0
  77. pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  78. pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
  79. pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
  80. pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
  81. pyreduce/masks/mask_mcdonald.fits.gz +0 -0
  82. pyreduce/masks/mask_nes.fits.gz +0 -0
  83. pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
  84. pyreduce/masks/mask_sarg.fits.gz +0 -0
  85. pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  86. pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  87. pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  88. pyreduce/masks/mask_uves_blue.fits.gz +0 -0
  89. pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
  90. pyreduce/masks/mask_uves_middle.fits.gz +0 -0
  91. pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
  92. pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
  93. pyreduce/masks/mask_uves_red.fits.gz +0 -0
  94. pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
  95. pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
  96. pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
  97. pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
  98. pyreduce/rectify.py +138 -0
  99. pyreduce/reduce.py +2205 -0
  100. pyreduce/settings/settings_ANDES.json +89 -0
  101. pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
  102. pyreduce/settings/settings_HARPN.json +73 -0
  103. pyreduce/settings/settings_HARPS.json +69 -0
  104. pyreduce/settings/settings_JWST_MIRI.json +55 -0
  105. pyreduce/settings/settings_JWST_NIRISS.json +55 -0
  106. pyreduce/settings/settings_LICK_APF.json +62 -0
  107. pyreduce/settings/settings_MCDONALD.json +58 -0
  108. pyreduce/settings/settings_METIS_IFU.json +77 -0
  109. pyreduce/settings/settings_METIS_LSS.json +77 -0
  110. pyreduce/settings/settings_MICADO.json +78 -0
  111. pyreduce/settings/settings_NEID.json +73 -0
  112. pyreduce/settings/settings_NIRSPEC.json +58 -0
  113. pyreduce/settings/settings_NTE.json +60 -0
  114. pyreduce/settings/settings_UVES.json +54 -0
  115. pyreduce/settings/settings_XSHOOTER.json +78 -0
  116. pyreduce/settings/settings_pyreduce.json +178 -0
  117. pyreduce/settings/settings_schema.json +827 -0
  118. pyreduce/tools/__init__.py +0 -0
  119. pyreduce/tools/combine.py +117 -0
  120. pyreduce/trace_orders.py +645 -0
  121. pyreduce/util.py +1288 -0
  122. pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
  123. pyreduce/wavecal/atlas/thar.fits +4946 -13
  124. pyreduce/wavecal/atlas/thar_list.txt +4172 -0
  125. pyreduce/wavecal/atlas/une.fits +0 -0
  126. pyreduce/wavecal/convert.py +38 -0
  127. pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
  128. pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
  129. pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
  130. pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
  131. pyreduce/wavecal/harps_blue_2D.npz +0 -0
  132. pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
  133. pyreduce/wavecal/harps_red_2D.npz +0 -0
  134. pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
  135. pyreduce/wavecal/mcdonald.npz +0 -0
  136. pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
  137. pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
  138. pyreduce/wavecal/nirspec_K2.npz +0 -0
  139. pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
  140. pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
  141. pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
  142. pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
  143. pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
  144. pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
  145. pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
  146. pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
  147. pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
  148. pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
  149. pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
  150. pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
  151. pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
  152. pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
  153. pyreduce/wavecal/xshooter_nir.npz +0 -0
  154. pyreduce/wavelength_calibration.py +1873 -0
  155. pyreduce_astro-0.6.0.dist-info/METADATA +114 -0
  156. pyreduce_astro-0.6.0.dist-info/RECORD +158 -0
  157. pyreduce_astro-0.6.0.dist-info/WHEEL +4 -0
  158. pyreduce_astro-0.6.0.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,154 @@
1
+ """
2
+ Handles instrument specific info for the NEID spectrograph
3
+ """
4
+
5
+ import logging
6
+ import re
7
+ from os.path import dirname, join
8
+
9
+ from .common import Instrument
10
+ from .filters import Filter, InstrumentFilter, NightFilter, ObjectFilter
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class NEID(Instrument):
16
+ def __init__(self):
17
+ super().__init__()
18
+ self.filters = {
19
+ "instrument": InstrumentFilter(self.info["instrument"]),
20
+ "night": NightFilter(self.info["date"]),
21
+ # "branch": Filter(, regex=True),
22
+ "mode": Filter(
23
+ self.info["instrument_mode"], regex=True, flags=re.IGNORECASE
24
+ ),
25
+ "type": Filter(self.info["observation_type"]),
26
+ "target": ObjectFilter(self.info["target"], regex=True),
27
+ }
28
+ self.night = "night"
29
+ self.science = "science"
30
+ self.shared = [
31
+ "instrument",
32
+ "night",
33
+ "mode",
34
+ ]
35
+ self.find_closest = [
36
+ "bias",
37
+ "flat",
38
+ "wavecal_master",
39
+ "freq_comb_master",
40
+ "orders",
41
+ "scatter",
42
+ ]
43
+
44
+ def get_expected_values(self, target, night, mode, fiber):
45
+ """Determine the default expected values in the headers for a given observation configuration
46
+
47
+ Any parameter may be None, to indicate that all values are allowed
48
+
49
+ Parameters
50
+ ----------
51
+ target : str
52
+ Name of the star / observation target
53
+ night : str
54
+ Observation night/nights
55
+ Returns
56
+ -------
57
+ expectations: dict
58
+ Dictionary of expected header values, with one entry per step.
59
+ The entries for each step refer to the filters defined in self.filters
60
+
61
+ Raises
62
+ ------
63
+ ValueError
64
+ Invalid combination of parameters
65
+ """
66
+ if target is not None:
67
+ target = target.replace(" ", r"(?:\s*|-)")
68
+ else:
69
+ target = ".*"
70
+
71
+ id_orddef = "LAMP,DARK,TUN"
72
+ id_spec = "STAR,WAVE"
73
+
74
+ expectations = {
75
+ "flat": {"instrument": "NEID", "night": night, "type": r"LAMP,LAMP,TUN"},
76
+ "orders": {
77
+ "instrument": "NEID",
78
+ "night": night,
79
+ "type": id_orddef,
80
+ },
81
+ "scatter": {
82
+ "instrument": "NEID",
83
+ "night": night,
84
+ "type": id_orddef, # Same as orders or same as flat?
85
+ },
86
+ "wavecal_master": {
87
+ "instrument": "NEID",
88
+ "night": night,
89
+ "type": r"WAVE,WAVE,THAR2",
90
+ },
91
+ "freq_comb_master": {
92
+ "instrument": "NEID",
93
+ "night": night,
94
+ "type": r"WAVE,WAVE,COMB",
95
+ },
96
+ "science": {
97
+ "instrument": "NEID",
98
+ "night": night,
99
+ "mode": mode,
100
+ "type": id_spec,
101
+ "target": target,
102
+ },
103
+ }
104
+ return expectations
105
+
106
+ def get_extension(self, header, mode):
107
+ extension = super().get_extension(header, mode)
108
+
109
+ return extension
110
+
111
+ def add_header_info(self, header, mode, **kwargs):
112
+ """read data from header and add it as REDUCE keyword back to the header"""
113
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
114
+ # alternatively you can implement all of it here, whatever works
115
+ header = super().add_header_info(header, mode)
116
+
117
+ try:
118
+ header["e_ra"] /= 15
119
+ header["e_jd"] += header["e_exptim"] / (7200 * 24) + 0.5
120
+
121
+ except:
122
+ pass
123
+
124
+ try:
125
+ if (
126
+ header["NAXIS"] == 2
127
+ and header["NAXIS1"] == 4296
128
+ and header["NAXIS2"] == 4096
129
+ ):
130
+ # both modes are in the same image
131
+ prescan_x = 50
132
+ overscan_x = 50
133
+ naxis_x = 2148
134
+ if mode == "BLUE":
135
+ header["e_xlo"] = prescan_x
136
+ header["e_xhi"] = naxis_x - overscan_x
137
+ elif mode == "RED":
138
+ header["e_xlo"] = naxis_x + prescan_x
139
+ header["e_xhi"] = 2 * naxis_x - overscan_x
140
+ except KeyError:
141
+ pass
142
+
143
+ return header
144
+
145
+ def get_wavecal_filename(self, header, mode, **kwargs):
146
+ """Get the filename of the wavelength calibration config file"""
147
+ cwd = dirname(__file__)
148
+ fname = f"NEID_{mode.lower()}_2D.npz"
149
+ fname = join(cwd, "..", "wavecal", fname)
150
+ return fname
151
+
152
+ def get_wavelength_range(self, header, mode, **kwargs):
153
+ wave_range = super().get_wavelength_range(header, mode, **kwargs)
154
+ return wave_range
@@ -0,0 +1,56 @@
1
+ {
2
+ "__instrument__": "NIRSPEC",
3
+ "instrument": "CURRINST",
4
+ "id_instrument": "NIRSPEC",
5
+ "telescope": "Keck",
6
+ "date": "DATE-OBS",
7
+ "date_format": "fits",
8
+ "modes": ["NIRSPEC"],
9
+ "extension": 0,
10
+ "orientation": 0,
11
+ "transpose": false,
12
+ "prescan_x": 5,
13
+ "overscan_x": 5,
14
+ "prescan_y": 0,
15
+ "overscan_y": 0,
16
+ "naxis_x": "NAXIS1",
17
+ "naxis_y": "NAXIS2",
18
+ "gain": "DETGAIN",
19
+ "readnoise": "DETRN",
20
+ "bias": "DETBIAS",
21
+ "dark": 0,
22
+ "sky": 0,
23
+ "air": "AIRMASS",
24
+ "exposure_time": "ITIME",
25
+ "image_type": "OBJECT",
26
+ "ra": "HA",
27
+ "dec": "DEC",
28
+ "jd": "MJD-OBS",
29
+ "longitude": -155.4783333,
30
+ "latitude": 19.8283333,
31
+ "altitude": 4160,
32
+ "target": "OBJECT",
33
+
34
+ "id_neon": "NEON",
35
+ "id_argon": "ARGON",
36
+ "id_krypton": "KRYPTON",
37
+ "id_xenon": "XENON",
38
+ "id_etalon": "ETALON",
39
+
40
+ "kw_bias" : null,
41
+ "kw_flat" : null,
42
+ "kw_curvature": null,
43
+ "kw_scatter": null,
44
+ "kw_orders" : null,
45
+ "kw_wave": null,
46
+ "kw_comb": null,
47
+ "kw_spec": null,
48
+ "id_bias" : "BIAS",
49
+ "id_flat": "FLAT",
50
+ "id_orders": null,
51
+ "id_curvature": null,
52
+ "id_scatter": null,
53
+ "id_wave": null,
54
+ "id_comb": null,
55
+ "id_spec": null
56
+ }
@@ -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_mode(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, mode, **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, mode)
57
+ # header["e_setting"] = NIRSPEC.get_mode(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, mode, 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
+ mode : str
75
+ instrument mode
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.load_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, mode=mode, 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 mode
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, mode, **kwargs):
197
+ """Get the filename of the wavelength calibration config file"""
198
+ info = self.load_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,47 @@
1
+ {
2
+ "__instrument__": "NTE",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "NTE",
5
+ "telescope": "NOT",
6
+ "category": "IMAGECAT",
7
+ "target": "OBJECT",
8
+ "date": "DATE-OBS",
9
+ "date_format" : "fits",
10
+ "modes": ["VIS", "NIR"],
11
+ "extension": 0,
12
+ "orientation": 0,
13
+ "prescan_x": 0,
14
+ "overscan_x": 0,
15
+ "prescan_y": 0,
16
+ "overscan_y": 0,
17
+ "naxis_x": "NAXIS1",
18
+ "naxis_y": "NAXIS2",
19
+ "gain": "GAIN",
20
+ "readnoise": "RDNOISE",
21
+ "dark": "DARK",
22
+ "sky": 0,
23
+ "exposure_time": "EXPTIME",
24
+ "ra": "RA",
25
+ "dec": "DEC",
26
+ "longitude": "LONGITUD",
27
+ "latitude": "LATITUD",
28
+ "altitude": "ELEVAT",
29
+ "kw_bias": "IMAGETYP",
30
+ "kw_dark": "IMAGETYP",
31
+ "kw_flat": "IMAGETYP",
32
+ "kw_curvature": "IMAGETYP",
33
+ "kw_scatter": "IMAGETYP",
34
+ "kw_orders": "IMAGETYP",
35
+ "kw_wave": "IMAGETYP",
36
+ "kw_comb": "IMAGETYP",
37
+ "kw_spec": "IMAGETYP",
38
+ "id_bias": "BIAS",
39
+ "id_dark": "DARK",
40
+ "id_flat": "LAMP,FLAT",
41
+ "id_orders": "LAMP,ORDERDEF",
42
+ "id_curvature": "LAMP,FPE",
43
+ "id_scatter": "LAMP,FLAT",
44
+ "id_wave": "LAMP,WAVE",
45
+ "id_comb": "LAMP,FPE",
46
+ "id_spec": "OBJECT"
47
+ }
@@ -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, mode, **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, mode)
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, mode, **kwargs):
29
+ """Get the filename of the wavelength calibration config file"""
30
+ info = self.load_info()
31
+ specifier = int(header[info["wavecal_specifier"]])
32
+
33
+ cwd = os.path.dirname(__file__)
34
+ fname = "{instrument}_{mode}_{specifier}nm_2D.npz".format(
35
+ instrument="nte", mode=mode.lower(), specifier=specifier
36
+ )
37
+ fname = os.path.join(cwd, "..", "wavecal", fname)
38
+ return fname
39
+
40
+ def get_wavelength_range(self, header, mode):
41
+ wave = 7 * [7000, 20_000]
42
+ return wave
@@ -0,0 +1,59 @@
1
+ {
2
+ "__instrument__": "UVES",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "UVES",
5
+ "telescope": "VLT",
6
+ "date": "DATE-OBS",
7
+ "date_format": "fits",
8
+ "modes": ["BLUE", "MIDDLE", "RED"],
9
+ "modes_id": ["blue", "red", "red"],
10
+ "extension": [0, 2, 1],
11
+ "id": [[1, 5], [1, 4], [1, 4]],
12
+ "orientation": [2, 1, 1],
13
+ "transpose" : false,
14
+ "prescan_x": "HIERARCH ESO DET OUT{id[0]} PRSCX",
15
+ "overscan_x": "HIERARCH ESO DET OUT{id[0]} OVSCX",
16
+ "prescan_y": 0,
17
+ "overscan_y": 0,
18
+ "naxis_x": "NAXIS1",
19
+ "naxis_y": "NAXIS2",
20
+ "gain": "HIERARCH ESO DET OUT{id[0]} CONAD",
21
+ "readnoise": "HIERARCH ESO DET OUT{id[0]} RON",
22
+ "dark": "HIERARCH ESO INS DET{id[1]} OFFDRK",
23
+ "sky": "HIERARCH ESO INS DET{id[1]} OFFSKY",
24
+ "exposure_time": "EXPTIME",
25
+ "ra": "RA",
26
+ "dec": "DEC",
27
+ "longitude": "HIERARCH ESO TEL GEOLON",
28
+ "latitude": "HIERARCH ESO TEL GEOLAT",
29
+ "altitude": "HIERARCH ESO TEL GEOELEV",
30
+
31
+ "target": "OBJECT",
32
+ "wavecal_element": "thar",
33
+
34
+ "wavecal_specifier": "ESO INS GRAT2 WLEN",
35
+ "category": "HIERARCH ESO DPR CATG",
36
+ "image_type": "OBJECT",
37
+
38
+ "observation_type": "ESO DPR TYPE",
39
+ "instrument_mode": "ESO INS MODE",
40
+ "instrument_mode_alternative": "ESO TPL NAME",
41
+
42
+
43
+ "kw_bias" : "ESO DPR TYPE",
44
+ "kw_flat" : "ESO DPR TYPE",
45
+ "kw_curvature": "OBJECT",
46
+ "kw_scatter": "ESO DPR TYPE",
47
+ "kw_orders" : "ESO DPR TYPE",
48
+ "kw_wave": "OBJECT",
49
+ "kw_comb": null,
50
+ "kw_spec": "ESO DPR TYPE",
51
+ "id_bias" : "BIAS",
52
+ "id_flat": "LAMP,FLAT",
53
+ "id_orders": "LAMP,ORDERDEF",
54
+ "id_curvature": "LAMP,WAVE",
55
+ "id_scatter": "LAMP,ORDERDEF",
56
+ "id_wave": "LAMP,WAVE",
57
+ "id_comb": null,
58
+ "id_spec": "OBJECT,POINT"
59
+ }
@@ -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, mode, **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, mode)
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, mode, **kwargs):
29
+ """Get the filename of the wavelength calibration config file"""
30
+ info = self.load_info()
31
+ specifier = int(header[info["wavecal_specifier"]])
32
+
33
+ cwd = os.path.dirname(__file__)
34
+ fname = "{instrument}_{mode}_{specifier}nm_2D.npz".format(
35
+ instrument="uves", mode=mode.lower(), specifier=specifier
36
+ )
37
+ fname = os.path.join(cwd, "..", "wavecal", fname)
38
+ return fname
39
+
40
+ def get_mask_filename(self, mode, **kwargs):
41
+ i = self.name.lower()
42
+ m = mode.lower()
43
+ fname = f"mask_{i}_{m}.fits.gz"
44
+ cwd = os.path.dirname(__file__)
45
+ fname = os.path.join(cwd, "..", "masks", fname)
46
+ return fname
@@ -0,0 +1,66 @@
1
+ {
2
+ "__instrument__": "XSHOOTER",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "SHOOT|XSHOOTER",
5
+ "telescope": "VLT",
6
+ "date": "MJD-OBS",
7
+ "date_format": "mjd",
8
+ "modes": [
9
+ "UVB",
10
+ "VIS",
11
+ "NIR"
12
+ ],
13
+ "kw_modes": "ESO DET CHIP*NAME",
14
+ "id_modes": [
15
+ "E2V CC44-82",
16
+ "MIT/LL CCID-20",
17
+ "Hawaii2RG"
18
+ ],
19
+ "extension": 0,
20
+ "orientation": [
21
+ 1,
22
+ 0,
23
+ 0
24
+ ],
25
+ "transpose": false,
26
+ "prescan_x": 0,
27
+ "overscan_x": 0,
28
+ "prescan_y": 0,
29
+ "overscan_y": 0,
30
+ "naxis_x": "NAXIS1",
31
+ "naxis_y": "NAXIS2",
32
+ "gain": "HIERARCH ESO DET OUT1 GAIN",
33
+ "readnoise": "HIERARCH ESO DET OUT1 RON",
34
+ "dark": 10,
35
+ "exposure_time": "EXPTIME",
36
+ "ra": "RA",
37
+ "dec": "DEC",
38
+ "jd": "MJD-OBS",
39
+ "longitude": "HIERARCH ESO TEL GEOLON",
40
+ "latitude": "HIERARCH ESO TEL GEOLAT",
41
+ "altitude": "HIERARCH ESO TEL GEOELEV",
42
+ "instrument_mode": "HIERARCH ESO SEQ ARM",
43
+ "observation_type": "HIERARCH ESO DPR TYPE",
44
+ "observation_category": "HIERARCH ESO DPR CATG",
45
+ "target": "HIERARCH ESO OBS TARG NAME",
46
+ "object": "OBJECT",
47
+ "id_dark": "DARK",
48
+ "id_format": "LAMP,FMTCHK",
49
+ "id_tell": "STD,TELLURIC",
50
+ "kw_bias": "HIERARCH ESO DPR TYPE",
51
+ "kw_flat": "HIERARCH ESO DPR TYPE",
52
+ "kw_curvature": "HIERARCH ESO DPR TYPE",
53
+ "kw_scatter": "HIERARCH ESO DPR TYPE",
54
+ "kw_orders": "HIERARCH ESO DPR TYPE",
55
+ "kw_wave": "HIERARCH ESO DPR TYPE",
56
+ "kw_comb": null,
57
+ "kw_spec": "HIERARCH ESO DPR TYPE",
58
+ "id_bias": "DARK",
59
+ "id_flat": "LAMP,FLAT",
60
+ "id_orders": "LAMP,ORDERDEF",
61
+ "id_curvature": "LAMP,WAVE",
62
+ "id_scatter": "LAMP,FLAT",
63
+ "id_wave": "LAMP,WAVE",
64
+ "id_comb": null,
65
+ "id_spec": "OBJECT"
66
+ }