pyreduce-astro 0.6.0b5__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 +675 -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 +221 -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.0b5.dist-info/METADATA +113 -0
  156. pyreduce_astro-0.6.0b5.dist-info/RECORD +158 -0
  157. pyreduce_astro-0.6.0b5.dist-info/WHEEL +4 -0
  158. pyreduce_astro-0.6.0b5.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,123 @@
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
+
11
+ from astropy.time import Time
12
+
13
+ from .common import InstrumentWithModes, getter
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class MCDONALD(InstrumentWithModes):
19
+ def __init__(self):
20
+ super().__init__()
21
+ # The date is a combination of the two values
22
+ kw = f"{{{self.info['date']}}}T{{{self.info['universal_time']}}}"
23
+ self.filters["night"].keyword = kw
24
+
25
+ def _convert_time_deg(self, v):
26
+ v = [float(s) for s in v.split(":")]
27
+ v = v[0] + v[1] / 60 + v[2] / 3600
28
+ return v
29
+
30
+ def add_header_info(self, header, mode, **kwargs):
31
+ """read data from header and add it as REDUCE keyword back to the header"""
32
+ # "Normal" stuff is handled by the general version, specific changes to values happen here
33
+ # alternatively you can implement all of it here, whatever works
34
+
35
+ header = super().add_header_info(header, mode, **kwargs)
36
+ info = self.load_info()
37
+ get = getter(header, info, mode)
38
+
39
+ header["e_orient"] = get("orientation", 0)
40
+ # As per IDL rotate if orient is 4 or larger and transpose is undefined
41
+ # the image is transposed
42
+ header["e_transpose"] = get("transpose", (header["e_orient"] % 8 >= 4))
43
+
44
+ trimsec = get("trimsec")
45
+
46
+ if trimsec is not None:
47
+ pattern = r"\[(\d*?):(\d*?),(\d*?):(\d*?)\]"
48
+ res = re.match(pattern, trimsec)
49
+ prescan_x = int(res[1]) + 1
50
+ overscan_x = int(res[2])
51
+ prescan_y = int(res[3])
52
+ overscan_y = int(res[4])
53
+ else:
54
+ prescan_x = 2
55
+ overscan_x = 2048
56
+ prescan_y = 2
57
+ overscan_y = 2047
58
+
59
+ header["e_xlo"] = prescan_x
60
+ header["e_xhi"] = overscan_x
61
+
62
+ header["e_ylo"] = prescan_y
63
+ header["e_yhi"] = overscan_y
64
+
65
+ amp = get("amplifier")
66
+ gain = info["gain"].format(amplifier=amp)
67
+ readnoise = info["readnoise"].format(amplifier=amp)
68
+
69
+ header["e_gain"] = get(gain, 1)
70
+ header["e_readn"] = get(readnoise, 0)
71
+ header["e_exptim"] = get("exposure_time", 0)
72
+
73
+ header["e_sky"] = get("sky", 0)
74
+ header["e_drk"] = get("dark", 0)
75
+ header["e_backg"] = header["e_gain"] * (header["e_drk"] + header["e_sky"])
76
+
77
+ header["e_imtype"] = get("observation_type")
78
+ header["e_ctg"] = get("observation_type")
79
+
80
+ obs_date = get("date")
81
+ ut = get("universal_time")
82
+ if obs_date is not None and ut is not None:
83
+ obs_date = f"{obs_date}T{ut}"
84
+
85
+ dark_time = get("dark_time")
86
+ ra = get("ra")
87
+ dec = get("dec")
88
+
89
+ if ra is not None:
90
+ ra = self._convert_time_deg(ra)
91
+ if dec is not None:
92
+ dec = self._convert_time_deg(dec)
93
+ if dark_time is not None:
94
+ tmid = dark_time / 2
95
+ else:
96
+ tmid = 0
97
+ if obs_date is not None:
98
+ jd = Time(obs_date).mjd + tmid + 0.5
99
+ else:
100
+ jd = 0
101
+
102
+ header["e_ra"] = ra
103
+ header["e_dec"] = dec
104
+ header["e_jd"] = jd
105
+
106
+ header["e_obslon"] = self._convert_time_deg(info["longitude"])
107
+ header["e_obslat"] = self._convert_time_deg(info["latitude"])
108
+ header["e_obsalt"] = info["altitude"]
109
+
110
+ return header
111
+
112
+ def get_wavecal_filename(self, header, mode, **kwargs):
113
+ """Get the filename of the wavelength calibration config file"""
114
+ cwd = os.path.dirname(__file__)
115
+ fname = "mcdonald.npz"
116
+ fname = os.path.join(cwd, "..", "wavecal", fname)
117
+ return fname
118
+
119
+ def get_mask_filename(self, mode, **kwargs):
120
+ fname = "mask_mcdonald.fits.gz"
121
+ cwd = os.path.dirname(__file__)
122
+ fname = os.path.join(cwd, "..", "masks", fname)
123
+ return fname
@@ -0,0 +1,63 @@
1
+ {
2
+ "__instrument__": "METIS_IFU",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "METIS_IFU",
5
+ "telescope": "ELT",
6
+ "date": "MJD-OBS",
7
+ "date_format": "mjd",
8
+ "modes": [
9
+ "IFU_NOMINAL",
10
+ "IFU_EXTENDED"
11
+ ],
12
+ "kw_modes": "INSTMODE",
13
+ "id_modes": [
14
+ "ifu_nom",
15
+ "ifu_ext"
16
+ ],
17
+ "extension": 0,
18
+ "orientation": [
19
+ 1,
20
+ 1,
21
+ 1
22
+ ],
23
+ "prescan_x": 0,
24
+ "overscan_x": 0,
25
+ "prescan_y": 0,
26
+ "overscan_y": 0,
27
+ "naxis_x": "NAXIS1",
28
+ "naxis_y": "NAXIS2",
29
+ "gain": 1,
30
+ "readnoise": 4,
31
+ "dark": 10,
32
+ "exposure_time": "HIERARCH OBS_EXPTIME",
33
+ "ra": "RA",
34
+ "dec": "DEC",
35
+ "jd": "MJD-OBS",
36
+ "longitude": -70,
37
+ "latitude": -24,
38
+ "altitude": 3060,
39
+ "instrument_mode": "HIERARCH ESO INS MODE",
40
+ "observation_type": "HIERARCH ESO DPR TYPE",
41
+ "observation_category": "HIERARCH ESO DPR CATG",
42
+ "target": "",
43
+ "object": "OBJECT",
44
+ "id_dark": "DARK",
45
+ "id_format": "LAMP,FMTCHK",
46
+ "id_tell": "STD,TELLURIC",
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
+ "id_bias": "DARK",
56
+ "id_flat": "LAMP,FLAT",
57
+ "id_orders": "FLAT,PINHOLE",
58
+ "id_curvature": "SKY,WAVE",
59
+ "id_scatter": "LAMP,FLAT",
60
+ "id_wave": "SKY,WAVE",
61
+ "id_comb": null,
62
+ "id_spec": "OBJECT"
63
+ }
@@ -0,0 +1,45 @@
1
+ """
2
+ Handles instrument specific info for the METIS_IFU IFU spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+
10
+ from .common import InstrumentWithModes
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class METIS_IFU(InstrumentWithModes):
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_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_extension(self, header, mode):
33
+ extension = 1
34
+
35
+ return extension
36
+
37
+ def get_wavecal_filename(self, header, mode, **kwargs):
38
+ """Get the filename of the wavelength calibration config file"""
39
+ # info = self.load_info()
40
+ cwd = os.path.dirname(__file__)
41
+ fname = f"metis_ifu_{mode.lower()}_2D.npz"
42
+ # fname = f"metis_ifu_IFU_L_2D.npz" ## f"micado_IJ_2D_det1.npz"
43
+ fname = os.path.join(cwd, "..", "wavecal", fname)
44
+
45
+ return fname
@@ -0,0 +1,65 @@
1
+ {
2
+ "__instrument__": "METIS_LSS",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "METIS_LSS",
5
+ "telescope": "ELT",
6
+ "date": "MJD-OBS",
7
+ "date_format": "mjd",
8
+ "modes": [
9
+ "LSS_L",
10
+ "LSS_M",
11
+ "LSS_N"
12
+ ],
13
+ "kw_modes": "INSTMODE",
14
+ "id_modes": [
15
+ "lss_l",
16
+ "lss_m",
17
+ "lss_n"
18
+ ],
19
+ "extension": 0,
20
+ "orientation": [
21
+ 1,
22
+ 1,
23
+ 1
24
+ ],
25
+ "prescan_x": 0,
26
+ "overscan_x": 0,
27
+ "prescan_y": 0,
28
+ "overscan_y": 0,
29
+ "naxis_x": "NAXIS1",
30
+ "naxis_y": "NAXIS2",
31
+ "gain": 1,
32
+ "readnoise": 4,
33
+ "dark": 10,
34
+ "exposure_time": "HIERARCH OBS_EXPTIME",
35
+ "ra": "RA",
36
+ "dec": "DEC",
37
+ "jd": "MJD-OBS",
38
+ "longitude": -70,
39
+ "latitude": -24,
40
+ "altitude": 3060,
41
+ "instrument_mode": "HIERARCH ESO INS MODE",
42
+ "observation_type": "HIERARCH ESO DPR TYPE",
43
+ "observation_category": "HIERARCH ESO DPR CATG",
44
+ "target": "",
45
+ "object": "OBJECT",
46
+ "id_dark": "DARK",
47
+ "id_format": "LAMP,FMTCHK",
48
+ "id_tell": "STD,TELLURIC",
49
+ "kw_bias": "HIERARCH ESO DPR TYPE",
50
+ "kw_flat": "HIERARCH ESO DPR TYPE",
51
+ "kw_curvature": "HIERARCH ESO DPR TYPE",
52
+ "kw_scatter": "HIERARCH ESO DPR TYPE",
53
+ "kw_orders": "HIERARCH ESO DPR TYPE",
54
+ "kw_wave": "HIERARCH ESO DPR TYPE",
55
+ "kw_comb": null,
56
+ "kw_spec": "HIERARCH ESO DPR TYPE",
57
+ "id_bias": "DARK",
58
+ "id_flat": "LAMP,FLAT",
59
+ "id_orders": "FLAT,PINHOLE",
60
+ "id_curvature": "SKY,WAVE",
61
+ "id_scatter": "LAMP,FLAT",
62
+ "id_wave": "SKY,WAVE",
63
+ "id_comb": null,
64
+ "id_spec": "OBJECT"
65
+ }
@@ -0,0 +1,45 @@
1
+ """
2
+ Handles instrument specific info for the METIS_LSS LSS spectrograph
3
+
4
+ Mostly reading data from the header
5
+ """
6
+
7
+ import logging
8
+ import os.path
9
+
10
+ from .common import InstrumentWithModes
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class METIS_LSS(InstrumentWithModes):
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_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_extension(self, header, mode):
33
+ extension = 1
34
+
35
+ return extension
36
+
37
+ def get_wavecal_filename(self, header, mode, **kwargs):
38
+ """Get the filename of the wavelength calibration config file"""
39
+ # info = self.load_info()
40
+ cwd = os.path.dirname(__file__)
41
+ fname = f"metis_lss_{mode.lower()}_2D.npz"
42
+ # fname = f"metis_lss_LSS_L_2D.npz" ## f"micado_IJ_2D_det1.npz"
43
+ fname = os.path.join(cwd, "..", "wavecal", fname)
44
+
45
+ return fname
@@ -0,0 +1,53 @@
1
+ {
2
+ "__instrument__": "MICADO",
3
+ "instrument": "INSTRUME",
4
+ "id_instrument": "MICADO",
5
+ "telescope": "ELT",
6
+ "date": "MJD-OBS",
7
+ "date_format": "mjd",
8
+ "modes": ["NIR"],
9
+ "kw_modes": "ESO DET CHIP*NAME",
10
+ "id_modes": ["Hawaii4RG"],
11
+ "extension": 0,
12
+ "orientation": [1],
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": 1,
20
+ "readnoise": 4,
21
+ "dark": 10,
22
+ "exposure_time": "HIERARCH OBS_EXPTIME",
23
+ "ra": "RA",
24
+ "dec": "DEC",
25
+ "jd": "MJD-OBS",
26
+ "longitude": -70,
27
+ "latitude": -24,
28
+ "altitude": 3060,
29
+ "instrument_mode": "HIERARCH ESO SEQ ARM",
30
+ "observation_type": "HIERARCH ESO DPR TYPE",
31
+ "observation_category": "HIERARCH ESO DPR CATG",
32
+ "target": "",
33
+ "object": "OBJECT",
34
+ "id_dark": "DARK",
35
+ "id_format": "WAVE_PINH",
36
+ "id_tell": "STD,TELLURIC",
37
+ "kw_bias": "HIERARCH ESO DPR TYPE",
38
+ "kw_flat": "HIERARCH ESO DPR TYPE",
39
+ "kw_curvature": "HIERARCH ESO DPR TYPE",
40
+ "kw_scatter": "HIERARCH ESO DPR TYPE",
41
+ "kw_orders": "HIERARCH ESO DPR TYPE",
42
+ "kw_wave": "HIERARCH ESO DPR TYPE",
43
+ "kw_comb": null,
44
+ "kw_spec": "HIERARCH ESO DPR TYPE",
45
+ "id_bias": "DARK",
46
+ "id_flat": "SFLATSLIT",
47
+ "id_orders": "SFLAT_PINH",
48
+ "id_curvature": "WAVE",
49
+ "id_scatter": "LAMP,FLAT",
50
+ "id_wave": "WAVE",
51
+ "id_comb": null,
52
+ "id_spec": "OBJECT"
53
+ }
@@ -0,0 +1,45 @@
1
+ """
2
+ Handles instrument specific info for the MICADO 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 MICADO(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_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_extension(self, header, mode):
33
+ extension = 5
34
+
35
+ return extension
36
+
37
+ def get_wavecal_filename(self, header, mode, **kwargs):
38
+ """Get the filename of the wavelength calibration config file"""
39
+ # info = self.load_info()
40
+ cwd = os.path.dirname(__file__)
41
+ # fname = f"xshooter_{mode.lower()}.npz"
42
+ fname = "MICADO_HK_3arcsec_chip5.npz" ## f"micado_IJ_2D_det1.npz"
43
+ fname = os.path.join(cwd, "..", "wavecal", fname)
44
+
45
+ return fname
@@ -0,0 +1,51 @@
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__": "NEID",
4
+ "id_instrument": "NEID",
5
+ "instrument": "INSTRUME",
6
+ "telescope": "TELESCOP",
7
+ "date": "DATE-OBS",
8
+ "date_format": "fits",
9
+ "modes": ["HR"],
10
+ "modes_id" : ["HR"],
11
+ "namps": "NAMPS",
12
+ "extension": "AMPLIFIER {amp}",
13
+ "orientation": 0,
14
+ "transpose": false,
15
+ "prescan_y": 0,
16
+ "overscan_y": 0,
17
+ "naxis_x": "NAXIS1",
18
+ "naxis_y": "NAXIS2",
19
+ "gain": "CCDGAIN",
20
+ "readnoise": "CCDRN",
21
+ "exposure_time": "EXPTIME",
22
+ "image_type": "HIERARCH TNG OBS TARG NAME",
23
+ "category": "HIERARCH TNG DPR CATG",
24
+ "ra": "RA",
25
+ "dec": "DEC",
26
+ "longitude": "GEOLON",
27
+ "latitude": "GEOLAT",
28
+ "altitude": "GEOELEV",
29
+ "target": "OBJECT",
30
+ "instrument_mode": "OBS-MODE",
31
+ "observation_type": "TNG DPR TYPE",
32
+ "id_fiber_sci": "LAMP,DARK,TUN",
33
+ "id_fiber_cal": "DARK,LAMP,TUN",
34
+ "id_fiber_sky": "DARK,LAMP,TUN",
35
+ "kw_bias": "OBJECT",
36
+ "kw_flat": "OBJECT",
37
+ "kw_curvature": "OBJECT",
38
+ "kw_scatter": "OBJECT",
39
+ "kw_orders": "OBJECT",
40
+ "kw_wave": "OBJECT",
41
+ "kw_comb": "OBJECT",
42
+ "kw_spec": "OBJECT",
43
+ "id_bias": "BIAS,BIAS",
44
+ "id_flat": "LAMP,LAMP,TUN",
45
+ "id_orders": "LAMP,LAMP,TUN",
46
+ "id_curvature": "WAVE,WAVE,THAR2",
47
+ "id_scatter": "LAMP,LAMP,TUN",
48
+ "id_wave": "WAVE,WAVE,THAR2",
49
+ "id_comb": "WAVE,WAVE,COMB",
50
+ "id_spec": "STAR,*"
51
+ }
@@ -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