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.
- pyreduce/__init__.py +67 -0
- pyreduce/__main__.py +106 -0
- pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
- pyreduce/clib/__init__.py +0 -0
- pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
- pyreduce/clib/build_extract.py +75 -0
- pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
- pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
- pyreduce/clib/slit_func_bd.c +362 -0
- pyreduce/clib/slit_func_bd.h +17 -0
- pyreduce/clipnflip.py +147 -0
- pyreduce/combine_frames.py +855 -0
- pyreduce/configuration.py +186 -0
- pyreduce/continuum_normalization.py +329 -0
- pyreduce/cwrappers.py +404 -0
- pyreduce/datasets.py +231 -0
- pyreduce/echelle.py +413 -0
- pyreduce/estimate_background_scatter.py +129 -0
- pyreduce/extract.py +1361 -0
- pyreduce/extraction_width.py +77 -0
- pyreduce/instruments/__init__.py +0 -0
- pyreduce/instruments/andes.json +61 -0
- pyreduce/instruments/andes.py +102 -0
- pyreduce/instruments/common.json +46 -0
- pyreduce/instruments/common.py +675 -0
- pyreduce/instruments/crires_plus.json +63 -0
- pyreduce/instruments/crires_plus.py +103 -0
- pyreduce/instruments/filters.py +195 -0
- pyreduce/instruments/harpn.json +136 -0
- pyreduce/instruments/harpn.py +201 -0
- pyreduce/instruments/harps.json +155 -0
- pyreduce/instruments/harps.py +310 -0
- pyreduce/instruments/instrument_info.py +140 -0
- pyreduce/instruments/instrument_schema.json +221 -0
- pyreduce/instruments/jwst_miri.json +53 -0
- pyreduce/instruments/jwst_miri.py +29 -0
- pyreduce/instruments/jwst_niriss.json +52 -0
- pyreduce/instruments/jwst_niriss.py +98 -0
- pyreduce/instruments/lick_apf.json +53 -0
- pyreduce/instruments/lick_apf.py +35 -0
- pyreduce/instruments/mcdonald.json +59 -0
- pyreduce/instruments/mcdonald.py +123 -0
- pyreduce/instruments/metis_ifu.json +63 -0
- pyreduce/instruments/metis_ifu.py +45 -0
- pyreduce/instruments/metis_lss.json +65 -0
- pyreduce/instruments/metis_lss.py +45 -0
- pyreduce/instruments/micado.json +53 -0
- pyreduce/instruments/micado.py +45 -0
- pyreduce/instruments/neid.json +51 -0
- pyreduce/instruments/neid.py +154 -0
- pyreduce/instruments/nirspec.json +56 -0
- pyreduce/instruments/nirspec.py +215 -0
- pyreduce/instruments/nte.json +47 -0
- pyreduce/instruments/nte.py +42 -0
- pyreduce/instruments/uves.json +59 -0
- pyreduce/instruments/uves.py +46 -0
- pyreduce/instruments/xshooter.json +66 -0
- pyreduce/instruments/xshooter.py +39 -0
- pyreduce/make_shear.py +606 -0
- pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
- pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
- pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
- pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
- pyreduce/masks/mask_elodie.fits.gz +0 -0
- pyreduce/masks/mask_feros3.fits.gz +0 -0
- pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
- pyreduce/masks/mask_harps_blue.fits.gz +0 -0
- pyreduce/masks/mask_harps_red.fits.gz +0 -0
- pyreduce/masks/mask_hds_blue.fits.gz +0 -0
- pyreduce/masks/mask_hds_red.fits.gz +0 -0
- pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
- pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
- pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
- pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
- pyreduce/masks/mask_mcdonald.fits.gz +0 -0
- pyreduce/masks/mask_nes.fits.gz +0 -0
- pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
- pyreduce/masks/mask_sarg.fits.gz +0 -0
- pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
- pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
- pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
- pyreduce/masks/mask_uves_blue.fits.gz +0 -0
- pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_uves_red.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
- pyreduce/rectify.py +138 -0
- pyreduce/reduce.py +2205 -0
- pyreduce/settings/settings_ANDES.json +89 -0
- pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
- pyreduce/settings/settings_HARPN.json +73 -0
- pyreduce/settings/settings_HARPS.json +69 -0
- pyreduce/settings/settings_JWST_MIRI.json +55 -0
- pyreduce/settings/settings_JWST_NIRISS.json +55 -0
- pyreduce/settings/settings_LICK_APF.json +62 -0
- pyreduce/settings/settings_MCDONALD.json +58 -0
- pyreduce/settings/settings_METIS_IFU.json +77 -0
- pyreduce/settings/settings_METIS_LSS.json +77 -0
- pyreduce/settings/settings_MICADO.json +78 -0
- pyreduce/settings/settings_NEID.json +73 -0
- pyreduce/settings/settings_NIRSPEC.json +58 -0
- pyreduce/settings/settings_NTE.json +60 -0
- pyreduce/settings/settings_UVES.json +54 -0
- pyreduce/settings/settings_XSHOOTER.json +78 -0
- pyreduce/settings/settings_pyreduce.json +178 -0
- pyreduce/settings/settings_schema.json +827 -0
- pyreduce/tools/__init__.py +0 -0
- pyreduce/tools/combine.py +117 -0
- pyreduce/trace_orders.py +645 -0
- pyreduce/util.py +1288 -0
- pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
- pyreduce/wavecal/atlas/thar.fits +4946 -13
- pyreduce/wavecal/atlas/thar_list.txt +4172 -0
- pyreduce/wavecal/atlas/une.fits +0 -0
- pyreduce/wavecal/convert.py +38 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
- pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
- pyreduce/wavecal/harps_blue_2D.npz +0 -0
- pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
- pyreduce/wavecal/harps_red_2D.npz +0 -0
- pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
- pyreduce/wavecal/mcdonald.npz +0 -0
- pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
- pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
- pyreduce/wavecal/nirspec_K2.npz +0 -0
- pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
- pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
- pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
- pyreduce/wavecal/xshooter_nir.npz +0 -0
- pyreduce/wavelength_calibration.py +1873 -0
- pyreduce_astro-0.6.0b5.dist-info/METADATA +113 -0
- pyreduce_astro-0.6.0b5.dist-info/RECORD +158 -0
- pyreduce_astro-0.6.0b5.dist-info/WHEEL +4 -0
- pyreduce_astro-0.6.0b5.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,155 @@
|
|
|
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__": "HARPS",
|
|
4
|
+
"id_instrument": "HARPS(pol)?",
|
|
5
|
+
"instrument": "INSTRUME",
|
|
6
|
+
"telescope": "TELESCOP",
|
|
7
|
+
"date": "DATE-OBS",
|
|
8
|
+
"date_format": "fits",
|
|
9
|
+
"modes": [
|
|
10
|
+
"BLUE",
|
|
11
|
+
"RED"
|
|
12
|
+
],
|
|
13
|
+
"modes_id": [
|
|
14
|
+
"HARPS",
|
|
15
|
+
"HARPS"
|
|
16
|
+
],
|
|
17
|
+
"modes_id_polarimetry": [
|
|
18
|
+
"HARPSpol",
|
|
19
|
+
"HARPSpol"
|
|
20
|
+
],
|
|
21
|
+
"extension": [
|
|
22
|
+
1,
|
|
23
|
+
2
|
|
24
|
+
],
|
|
25
|
+
"id": [
|
|
26
|
+
[
|
|
27
|
+
1,
|
|
28
|
+
1
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
1,
|
|
32
|
+
2
|
|
33
|
+
]
|
|
34
|
+
],
|
|
35
|
+
"orientation": 1,
|
|
36
|
+
"transpose": false,
|
|
37
|
+
"prescan_x": "HIERARCH ESO DET OUT{id[0]} PRSCX",
|
|
38
|
+
"overscan_x": "HIERARCH ESO DET OUT{id[0]} OVSCX",
|
|
39
|
+
"prescan_y": 0,
|
|
40
|
+
"overscan_y": 0,
|
|
41
|
+
"naxis_x": "NAXIS1",
|
|
42
|
+
"naxis_y": "NAXIS2",
|
|
43
|
+
"polarization_linear": "eso ins ret50 pos",
|
|
44
|
+
"polarization_circular": "eso ins ret25 pos",
|
|
45
|
+
"gain": "HIERARCH ESO DET OUT{id[0]} CONAD",
|
|
46
|
+
"readnoise": "HIERARCH ESO DET OUT{id[0]} RON",
|
|
47
|
+
"dark": "HIERARCH ESO INS DET{id[1]} OFFDRK",
|
|
48
|
+
"sky": "HIERARCH ESO INS DET{id[1]} OFFSKY",
|
|
49
|
+
"exposure_time": "EXPTIME",
|
|
50
|
+
"image_type": "OBJECT",
|
|
51
|
+
"category": "HIERARCH ESO DPR CATG",
|
|
52
|
+
"ra": "RA",
|
|
53
|
+
"dec": "DEC",
|
|
54
|
+
"longitude": "HIERARCH ESO TEL GEOLON",
|
|
55
|
+
"latitude": "HIERARCH ESO TEL GEOLAT",
|
|
56
|
+
"altitude": "HIERARCH ESO TEL GEOELEV",
|
|
57
|
+
"target": "OBJECT",
|
|
58
|
+
"instrument_mode": "ESO INS MODE",
|
|
59
|
+
"instrument_mode_alternative": "ESO TPL NAME",
|
|
60
|
+
"observation_type": "ESO DPR TYPE",
|
|
61
|
+
"id_fiber_a": "LAMP,DARK,TUN",
|
|
62
|
+
"id_fiber_b": "DARK,LAMP,TUN",
|
|
63
|
+
"kw_bias": "ESO DPR TYPE",
|
|
64
|
+
"kw_flat": "ESO DPR TYPE",
|
|
65
|
+
"kw_curvature": "ESO DPR TYPE",
|
|
66
|
+
"kw_scatter": "ESO DPR TYPE",
|
|
67
|
+
"kw_orders": "ESO DPR TYPE",
|
|
68
|
+
"kw_wave": "ESO DPR TYPE",
|
|
69
|
+
"kw_comb": "ESO DPR TYPE",
|
|
70
|
+
"kw_spec": "ESO DPR TYPE",
|
|
71
|
+
"id_bias": "BIAS,BIAS",
|
|
72
|
+
"id_flat": "LAMP,LAMP,TUN",
|
|
73
|
+
"id_orders": "LAMP,LAMP,TUN",
|
|
74
|
+
"id_curvature": "WAVE,WAVE,THAR2",
|
|
75
|
+
"id_scatter": "LAMP,LAMP,TUN",
|
|
76
|
+
"id_wave": "WAVE,WAVE,THAR2",
|
|
77
|
+
"id_comb": "WAVE,WAVE,COMB",
|
|
78
|
+
"id_spec": "STAR,*,*",
|
|
79
|
+
"wavelength_range": [[
|
|
80
|
+
[5245.4, 5304.3],
|
|
81
|
+
[5200.5, 5259.0],
|
|
82
|
+
[5156.5, 5214.4],
|
|
83
|
+
[5113.2, 5170.6],
|
|
84
|
+
[5070.6, 5127.6],
|
|
85
|
+
[5028.7, 5085.2],
|
|
86
|
+
[4987.5, 5043.5],
|
|
87
|
+
[4946.9, 5002.5],
|
|
88
|
+
[4907.0, 4962.2],
|
|
89
|
+
[4867.8, 4922.5],
|
|
90
|
+
[4829.2, 4883.4],
|
|
91
|
+
[4791.1, 4845.0],
|
|
92
|
+
[4753.7, 4807.1],
|
|
93
|
+
[4716.9, 4769.9],
|
|
94
|
+
[4680.6, 4733.2],
|
|
95
|
+
[4644.9, 4697.1],
|
|
96
|
+
[4609.7, 4661.5],
|
|
97
|
+
[4575.1, 4626.5],
|
|
98
|
+
[4540.9, 4591.9],
|
|
99
|
+
[4507.3, 4557.9],
|
|
100
|
+
[4474.2, 4524.4],
|
|
101
|
+
[4441.5, 4491.4],
|
|
102
|
+
[4409.3, 4458.9],
|
|
103
|
+
[4377.6, 4426.8],
|
|
104
|
+
[4346.4, 4395.2],
|
|
105
|
+
[4315.5, 4364.0],
|
|
106
|
+
[4285.2, 4333.3],
|
|
107
|
+
[4255.2, 4303.0],
|
|
108
|
+
[4225.7, 4273.1],
|
|
109
|
+
[4196.5, 4243.6],
|
|
110
|
+
[4167.8, 4214.6],
|
|
111
|
+
[4139.4, 4185.9],
|
|
112
|
+
[4111.5, 4157.6],
|
|
113
|
+
[4083.9, 4129.7],
|
|
114
|
+
[4056.7, 4102.2],
|
|
115
|
+
[4029.8, 4075.0],
|
|
116
|
+
[4003.3, 4048.2],
|
|
117
|
+
[3977.1, 4021.8],
|
|
118
|
+
[3951.3, 3995.7],
|
|
119
|
+
[3925.8, 3969.9],
|
|
120
|
+
[3900.7, 3944.5],
|
|
121
|
+
[3875.8, 3919.3],
|
|
122
|
+
[3851.3, 3894.5],
|
|
123
|
+
[3827.1, 3870.0],
|
|
124
|
+
[3803.2, 3845.9],
|
|
125
|
+
[3779.6, 3822.0]
|
|
126
|
+
],[
|
|
127
|
+
[6835.9, 6913.0],
|
|
128
|
+
[6760.0, 6836.2],
|
|
129
|
+
[6685.7, 6761.1],
|
|
130
|
+
[6613.1, 6687.6],
|
|
131
|
+
[6542.0, 6615.7],
|
|
132
|
+
[6472.4, 6545.4],
|
|
133
|
+
[6404.3, 6476.5],
|
|
134
|
+
[6337.7, 6409.1],
|
|
135
|
+
[6272.3, 6343.0],
|
|
136
|
+
[6208.4, 6278.3],
|
|
137
|
+
[6145.7, 6214.9],
|
|
138
|
+
[6084.2, 6152.8],
|
|
139
|
+
[6024.0, 6091.9],
|
|
140
|
+
[5965.0, 6032.1],
|
|
141
|
+
[5907.1, 5973.6],
|
|
142
|
+
[5850.3, 5916.2],
|
|
143
|
+
[5794.6, 5859.8],
|
|
144
|
+
[5739.9, 5804.6],
|
|
145
|
+
[5686.3, 5750.3],
|
|
146
|
+
[5633.7, 5697.1],
|
|
147
|
+
[5582.0, 5644.8],
|
|
148
|
+
[5531.3, 5593.5],
|
|
149
|
+
[5481.5, 5543.2],
|
|
150
|
+
[5432.5, 5493.7],
|
|
151
|
+
[5384.5, 5445.1],
|
|
152
|
+
[5337.3, 5397.3]
|
|
153
|
+
]
|
|
154
|
+
]
|
|
155
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
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 re
|
|
9
|
+
from os.path import dirname, join
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from .common import Instrument
|
|
14
|
+
from .filters import Filter, InstrumentFilter, NightFilter, ObjectFilter
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TypeFilter(Filter):
|
|
20
|
+
def __init__(self, keyword="ESO DPR TYPE"):
|
|
21
|
+
super().__init__(keyword, regex=True)
|
|
22
|
+
|
|
23
|
+
def classify(self, value):
|
|
24
|
+
if value is not None:
|
|
25
|
+
match = self.match(value)
|
|
26
|
+
data = np.asarray(self.data)
|
|
27
|
+
data = np.unique(data[match])
|
|
28
|
+
try:
|
|
29
|
+
regex = re.compile(value)
|
|
30
|
+
keys = [regex.match(f) for f in data]
|
|
31
|
+
keys = [[g for g in d.groups() if g is not None][0] for d in keys]
|
|
32
|
+
unique = np.unique(keys)
|
|
33
|
+
assign = {
|
|
34
|
+
u: [d for k, d in zip(keys, data, strict=False) if k == u]
|
|
35
|
+
for u in unique
|
|
36
|
+
}
|
|
37
|
+
data = [(u, self.match("|".join(a))) for u, a in assign.items()]
|
|
38
|
+
except IndexError:
|
|
39
|
+
data = np.asarray(self.data)
|
|
40
|
+
data = np.unique(data[match])
|
|
41
|
+
data = [(d, self.match(d)) for d in data]
|
|
42
|
+
else:
|
|
43
|
+
data = np.unique(self.data)
|
|
44
|
+
data = [(d, self.match(d)) for d in data]
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FiberFilter(Filter):
|
|
49
|
+
def __init__(self, keyword="ESO DPR TYPE"):
|
|
50
|
+
super().__init__(keyword, regex=True)
|
|
51
|
+
self.lamp_values = ["LAMP", "STAR", "CIRPOL", "LINPOL"]
|
|
52
|
+
|
|
53
|
+
def collect(self, header):
|
|
54
|
+
value = header.get(self.keyword)
|
|
55
|
+
if value is None:
|
|
56
|
+
value = ""
|
|
57
|
+
else:
|
|
58
|
+
value = value.split(",")
|
|
59
|
+
if value[0] in self.lamp_values and value[1] in self.lamp_values:
|
|
60
|
+
value = "AB"
|
|
61
|
+
elif value[1] in self.lamp_values:
|
|
62
|
+
value = "B"
|
|
63
|
+
elif value[0] in self.lamp_values:
|
|
64
|
+
value = "A"
|
|
65
|
+
else:
|
|
66
|
+
value = ""
|
|
67
|
+
|
|
68
|
+
self.data.append(value)
|
|
69
|
+
return value
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PolarizationFilter(Filter):
|
|
73
|
+
def __init__(self, keyword="ESO INS RET?? POS"):
|
|
74
|
+
super().__init__(keyword, regex=True)
|
|
75
|
+
|
|
76
|
+
def collect(self, header):
|
|
77
|
+
dpr_type = header.get("ESO DPR TYPE", "")
|
|
78
|
+
match = re.match(r"^.*,(CIR|LIN)POL,.*$", dpr_type)
|
|
79
|
+
if match is None:
|
|
80
|
+
value = "none"
|
|
81
|
+
elif match.group(1) == "CIR":
|
|
82
|
+
value = "circular"
|
|
83
|
+
elif match.group(1) == "LIN":
|
|
84
|
+
value = "linear"
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("Polarization not recognised")
|
|
87
|
+
self.data.append(value)
|
|
88
|
+
return value
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class HARPS(Instrument):
|
|
92
|
+
def __init__(self):
|
|
93
|
+
super().__init__()
|
|
94
|
+
self.filters = {
|
|
95
|
+
"instrument": InstrumentFilter(self.info["instrument"]),
|
|
96
|
+
"night": NightFilter(self.info["date"]),
|
|
97
|
+
# "branch": Filter(, regex=True),
|
|
98
|
+
"mode": Filter(
|
|
99
|
+
self.info["instrument_mode"], regex=True, flags=re.IGNORECASE
|
|
100
|
+
),
|
|
101
|
+
"type": TypeFilter(self.info["observation_type"]),
|
|
102
|
+
"polarization": PolarizationFilter(),
|
|
103
|
+
"target": ObjectFilter(self.info["target"], regex=True),
|
|
104
|
+
"fiber": FiberFilter(),
|
|
105
|
+
}
|
|
106
|
+
self.night = "night"
|
|
107
|
+
self.science = "science"
|
|
108
|
+
self.shared = ["instrument", "night", "mode", "polarization", "fiber"]
|
|
109
|
+
self.find_closest = [
|
|
110
|
+
"bias",
|
|
111
|
+
"flat",
|
|
112
|
+
"wavecal_master",
|
|
113
|
+
"freq_comb_master",
|
|
114
|
+
"orders",
|
|
115
|
+
"scatter",
|
|
116
|
+
"curvature",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
def get_expected_values(self, target, night, mode, fiber, polarimetry):
|
|
120
|
+
"""Determine the default expected values in the headers for a given observation configuration
|
|
121
|
+
|
|
122
|
+
Any parameter may be None, to indicate that all values are allowed
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
target : str
|
|
127
|
+
Name of the star / observation target
|
|
128
|
+
night : str
|
|
129
|
+
Observation night/nights
|
|
130
|
+
fiber : "A", "B", "AB"
|
|
131
|
+
Which of the fibers should carry observation signal
|
|
132
|
+
polarimetry : "none", "linear", "circular", bool
|
|
133
|
+
Whether the instrument is used in HARPS or HARPSpol mode
|
|
134
|
+
and which polarization is observed. Set to true for both kinds
|
|
135
|
+
of polarisation.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
expectations: dict
|
|
140
|
+
Dictionary of expected header values, with one entry per step.
|
|
141
|
+
The entries for each step refer to the filters defined in self.filters
|
|
142
|
+
|
|
143
|
+
Raises
|
|
144
|
+
------
|
|
145
|
+
ValueError
|
|
146
|
+
Invalid combination of parameters
|
|
147
|
+
"""
|
|
148
|
+
if target is not None:
|
|
149
|
+
target = target.replace(" ", r"(?:\s*|-)")
|
|
150
|
+
else:
|
|
151
|
+
target = ".*"
|
|
152
|
+
|
|
153
|
+
if fiber == "AB":
|
|
154
|
+
template = r"({a},{a}),{c}"
|
|
155
|
+
elif fiber == "A":
|
|
156
|
+
template = r"({a},{b}),{c}"
|
|
157
|
+
elif fiber == "B":
|
|
158
|
+
template = r"({b},{a}),{c}"
|
|
159
|
+
elif fiber is None:
|
|
160
|
+
template = None
|
|
161
|
+
fiber = "(AB)|(A)|(B)"
|
|
162
|
+
else:
|
|
163
|
+
raise ValueError(
|
|
164
|
+
"fiber keyword not understood, possible values are 'AB', 'A', 'B'"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if polarimetry == "none" or not polarimetry:
|
|
168
|
+
mode = "HARPS"
|
|
169
|
+
if template is not None:
|
|
170
|
+
id_orddef = template.format(a="LAMP", b="DARK", c=".*?")
|
|
171
|
+
id_spec = template.format(a="STAR", b="(?!STAR).*?", c=".*?")
|
|
172
|
+
else:
|
|
173
|
+
id_spec = (
|
|
174
|
+
r"^(STAR,(?!STAR).*),.*$|^((?!STAR).*?,STAR),.*$|^(STAR,STAR),.*$"
|
|
175
|
+
)
|
|
176
|
+
id_orddef = r"^(LAMP,DARK),.*$|^(DARK,LAMP),.*$|^(LAMP,LAMP),.*$"
|
|
177
|
+
polarimetry = "none"
|
|
178
|
+
else:
|
|
179
|
+
mode = "HARPSpol"
|
|
180
|
+
id_orddef = r"(LAMP,LAMP),.*"
|
|
181
|
+
if polarimetry == r"linear":
|
|
182
|
+
id_spec = r"(STAR,LINPOL),.*"
|
|
183
|
+
elif polarimetry == "circular":
|
|
184
|
+
id_spec = r"(STAR,CIRPOL),.*"
|
|
185
|
+
elif polarimetry:
|
|
186
|
+
id_spec = r"(STAR,(?:LIN|CIR)POL),.*"
|
|
187
|
+
polarimetry = r"(circular|linear)"
|
|
188
|
+
else:
|
|
189
|
+
raise ValueError(
|
|
190
|
+
f"polarization parameter not recognized. Expected one of 'none', 'linear', 'circular', but got {polarimetry}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
expectations = {
|
|
194
|
+
"bias": {"instrument": "HARPS", "night": night, "type": r"BIAS,BIAS"},
|
|
195
|
+
"flat": {"instrument": "HARPS", "night": night, "type": r"(LAMP,LAMP),.*"},
|
|
196
|
+
"orders": {
|
|
197
|
+
"instrument": "HARPS",
|
|
198
|
+
"night": night,
|
|
199
|
+
"fiber": fiber,
|
|
200
|
+
"type": id_orddef,
|
|
201
|
+
},
|
|
202
|
+
"scatter": {
|
|
203
|
+
"instrument": "HARPS",
|
|
204
|
+
"night": night,
|
|
205
|
+
"type": id_orddef, # Same as orders or same as flat?
|
|
206
|
+
},
|
|
207
|
+
"curvature": {
|
|
208
|
+
"instrument": "HARPS",
|
|
209
|
+
"night": night,
|
|
210
|
+
"type": [r"(WAVE,WAVE,COMB)", r"(WAVE,WAVE,THAR)\d?"],
|
|
211
|
+
},
|
|
212
|
+
"wavecal_master": {
|
|
213
|
+
"instrument": "HARPS",
|
|
214
|
+
"night": night,
|
|
215
|
+
"type": r"(WAVE,WAVE,THAR)\d?",
|
|
216
|
+
},
|
|
217
|
+
"freq_comb_master": {
|
|
218
|
+
"instrument": "HARPS",
|
|
219
|
+
"night": night,
|
|
220
|
+
"type": r"(WAVE,WAVE,COMB)",
|
|
221
|
+
},
|
|
222
|
+
"science": {
|
|
223
|
+
"instrument": "HARPS",
|
|
224
|
+
"night": night,
|
|
225
|
+
"mode": mode,
|
|
226
|
+
"type": id_spec,
|
|
227
|
+
"fiber": fiber,
|
|
228
|
+
"polarization": polarimetry,
|
|
229
|
+
"target": target,
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
return expectations
|
|
233
|
+
|
|
234
|
+
def get_extension(self, header, mode):
|
|
235
|
+
extension = super().get_extension(header, mode)
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
if (
|
|
239
|
+
header["NAXIS"] == 2
|
|
240
|
+
and header["NAXIS1"] == 4296
|
|
241
|
+
and header["NAXIS2"] == 4096
|
|
242
|
+
):
|
|
243
|
+
extension = 0
|
|
244
|
+
except KeyError:
|
|
245
|
+
pass
|
|
246
|
+
|
|
247
|
+
return extension
|
|
248
|
+
|
|
249
|
+
def add_header_info(self, header, mode, **kwargs):
|
|
250
|
+
"""read data from header and add it as REDUCE keyword back to the header"""
|
|
251
|
+
# "Normal" stuff is handled by the general version, specific changes to values happen here
|
|
252
|
+
# alternatively you can implement all of it here, whatever works
|
|
253
|
+
header = super().add_header_info(header, mode)
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
header["e_ra"] /= 15
|
|
257
|
+
header["e_jd"] += header["e_exptim"] / (7200 * 24) + 0.5
|
|
258
|
+
|
|
259
|
+
pol_angle = header.get("eso ins ret25 pos")
|
|
260
|
+
if pol_angle is None:
|
|
261
|
+
pol_angle = header.get("eso ins ret50 pos")
|
|
262
|
+
if pol_angle is None:
|
|
263
|
+
pol_angle = "no polarimeter"
|
|
264
|
+
else:
|
|
265
|
+
pol_angle = "lin %i" % pol_angle
|
|
266
|
+
else:
|
|
267
|
+
pol_angle = "cir %i" % pol_angle
|
|
268
|
+
|
|
269
|
+
header["e_pol"] = (pol_angle, "polarization angle")
|
|
270
|
+
except:
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
if (
|
|
275
|
+
header["NAXIS"] == 2
|
|
276
|
+
and header["NAXIS1"] == 4296
|
|
277
|
+
and header["NAXIS2"] == 4096
|
|
278
|
+
):
|
|
279
|
+
# both modes are in the same image
|
|
280
|
+
prescan_x = 50
|
|
281
|
+
overscan_x = 50
|
|
282
|
+
naxis_x = 2148
|
|
283
|
+
if mode == "BLUE":
|
|
284
|
+
header["e_xlo"] = prescan_x
|
|
285
|
+
header["e_xhi"] = naxis_x - overscan_x
|
|
286
|
+
elif mode == "RED":
|
|
287
|
+
header["e_xlo"] = naxis_x + prescan_x
|
|
288
|
+
header["e_xhi"] = 2 * naxis_x - overscan_x
|
|
289
|
+
except KeyError:
|
|
290
|
+
pass
|
|
291
|
+
|
|
292
|
+
return header
|
|
293
|
+
|
|
294
|
+
def get_wavecal_filename(self, header, mode, polarimetry, **kwargs):
|
|
295
|
+
"""Get the filename of the wavelength calibration config file"""
|
|
296
|
+
cwd = dirname(__file__)
|
|
297
|
+
if polarimetry:
|
|
298
|
+
pol = "_pol"
|
|
299
|
+
else:
|
|
300
|
+
pol = ""
|
|
301
|
+
fname = f"harps_{mode.lower()}{pol}_2D.npz"
|
|
302
|
+
fname = join(cwd, "..", "wavecal", fname)
|
|
303
|
+
return fname
|
|
304
|
+
|
|
305
|
+
def get_wavelength_range(self, header, mode, **kwargs):
|
|
306
|
+
wave_range = super().get_wavelength_range(header, mode, **kwargs)
|
|
307
|
+
# The wavelength orders are in inverse order in the .json file
|
|
308
|
+
# because I was to lazy to invert them in the file
|
|
309
|
+
wave_range = wave_range[::-1]
|
|
310
|
+
return wave_range
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interface for all instrument specific information
|
|
3
|
+
The actual info is contained in the instruments/{name}.py modules/classes, which are all subclasses of "common"
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import importlib
|
|
7
|
+
|
|
8
|
+
from .common import Instrument
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_instrument(instrument) -> Instrument:
|
|
12
|
+
"""Load an python instrument module
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
instrument : str
|
|
17
|
+
name of the instrument
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
instrument : Instrument
|
|
22
|
+
Instance of the {instrument} class
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# TODO: Loading arbitrary modules is probably bad style
|
|
26
|
+
# from instruments import uves, harps
|
|
27
|
+
# instruments = {"uves": uves.UVES, "harps": harps.HARPS}
|
|
28
|
+
# instrument = instruments[instrument.lower()]
|
|
29
|
+
# instrument = instrument()
|
|
30
|
+
if instrument is None:
|
|
31
|
+
instrument = "common"
|
|
32
|
+
|
|
33
|
+
fname = f".instruments.{instrument.lower()}"
|
|
34
|
+
lib = importlib.import_module(fname, package="pyreduce")
|
|
35
|
+
instrument = getattr(lib, instrument.upper())
|
|
36
|
+
instrument = instrument()
|
|
37
|
+
|
|
38
|
+
return instrument
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_instrument_info(instrument):
|
|
42
|
+
"""Load instrument specific information
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
instrument : str
|
|
47
|
+
Name of the instrument
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
dict{str:obj}
|
|
52
|
+
Dictionary with information
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
instrument = load_instrument(instrument)
|
|
56
|
+
return instrument.info
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def sort_files(input_dir, target, night, instrument, mode, **kwargs):
|
|
60
|
+
"""Sort a list of files into different categories and discard files that are not used
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
input_dir : str
|
|
65
|
+
directory containing all files (with tags for target, night, and instrument)
|
|
66
|
+
target : str
|
|
67
|
+
observation target name, as found in the files
|
|
68
|
+
night : str
|
|
69
|
+
observation night of interest, as found in the files
|
|
70
|
+
instrument : str
|
|
71
|
+
instrument name
|
|
72
|
+
mode : str
|
|
73
|
+
instrument mode, if applicable (e.g. red/blue for HARPS)
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
biaslist : list(str)
|
|
78
|
+
list of bias files
|
|
79
|
+
flatlist : list(str)
|
|
80
|
+
list of flat field files
|
|
81
|
+
wavelist : list(str)
|
|
82
|
+
list of wavelength calibration files
|
|
83
|
+
orderlist : list(str)
|
|
84
|
+
list of order definition files (for order tracing)
|
|
85
|
+
speclist : list(str)
|
|
86
|
+
list of science files, i.e. observations
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
instrument = load_instrument(instrument)
|
|
90
|
+
return instrument.sort_files(input_dir, target, night, mode, **kwargs)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_supported_modes(instrument):
|
|
94
|
+
instrument = load_instrument(instrument)
|
|
95
|
+
return instrument.get_supported_modes()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def modeinfo(header, instrument, mode, **kwargs):
|
|
99
|
+
"""Add instrument specific information to a header/dict
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
header : fits.header, dict
|
|
104
|
+
header to add information to
|
|
105
|
+
instrument : str
|
|
106
|
+
instrument name
|
|
107
|
+
mode : str
|
|
108
|
+
instrument mode (e.g. red/blue for HARPS)
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
header
|
|
113
|
+
header with added information
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
instrument = load_instrument(instrument)
|
|
117
|
+
header = instrument.add_header_info(header, mode, **kwargs)
|
|
118
|
+
return header
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_wavecal_filename(header, instrument, mode, **kwargs):
|
|
122
|
+
"""Get the filename of the pre-existing wavelength solution for the current settings
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
header : fits.header, dict
|
|
127
|
+
header of the wavelength calibration file
|
|
128
|
+
instrument : str
|
|
129
|
+
instrument name
|
|
130
|
+
mode : str
|
|
131
|
+
instrument mode (e.g. red/blue for HARPS)
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
filename : str
|
|
136
|
+
wavelength solution file
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
instrument = load_instrument(instrument)
|
|
140
|
+
return instrument.get_wavecal_filename(header, mode, **kwargs)
|