PyNOT-redux 2.3__tar.gz → 2.4__tar.gz

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 (117) hide show
  1. {pynot_redux-2.3 → pynot_redux-2.4}/.gitignore +1 -0
  2. {pynot_redux-2.3 → pynot_redux-2.4}/PKG-INFO +1 -1
  3. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/PKG-INFO +1 -1
  4. pynot_redux-2.4/pynot/VERSION +1 -0
  5. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/default_options.yml +2 -0
  6. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/io.py +1 -1
  7. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/organizer.py +15 -3
  8. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/extraction.py +13 -3
  9. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/phot.py +25 -20
  10. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/phot_redux.py +12 -12
  11. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/redux.py +6 -1
  12. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/containers.py +6 -3
  13. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/notes.py +11 -5
  14. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/viewer.py +25 -8
  15. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/wcs.py +16 -10
  16. pynot_redux-2.3/pynot/VERSION +0 -1
  17. {pynot_redux-2.3 → pynot_redux-2.4}/.gitattributes +0 -0
  18. {pynot_redux-2.3 → pynot_redux-2.4}/.github/dependabot.yml +0 -0
  19. {pynot_redux-2.3 → pynot_redux-2.4}/LICENSE +0 -0
  20. {pynot_redux-2.3 → pynot_redux-2.4}/MANIFEST.in +0 -0
  21. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/SOURCES.txt +0 -0
  22. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/dependency_links.txt +0 -0
  23. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/entry_points.txt +0 -0
  24. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/requires.txt +0 -0
  25. {pynot_redux-2.3 → pynot_redux-2.4}/PyNOT_redux.egg-info/top_level.txt +0 -0
  26. {pynot_redux-2.3 → pynot_redux-2.4}/README.md +0 -0
  27. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/.extract_msg +0 -0
  28. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/.identify_msg +0 -0
  29. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/.instrument.cfg +0 -0
  30. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/.response_msg +0 -0
  31. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/__init__.py +0 -0
  32. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/alfosc.py +0 -0
  33. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/HeAr_linelist.dat +0 -0
  34. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/HeNe_linelist.dat +0 -0
  35. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/ThAr_linelist.dat +0 -0
  36. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/al-gr18_pixeltable.dat +0 -0
  37. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/al-gr19_pixeltable.dat +0 -0
  38. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/al-gr4_pixeltable.dat +0 -0
  39. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/al-gr7_pixeltable.dat +0 -0
  40. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/alfosc_filters.dat +0 -0
  41. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/default_options_img.yml +0 -0
  42. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/ef-gr13_pixeltable.dat +0 -0
  43. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/ef-gr14_pixeltable.dat +0 -0
  44. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/ef-gr1_pixeltable.dat +0 -0
  45. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/ef-gr3_pixeltable.dat +0 -0
  46. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/efosc_filters.dat +0 -0
  47. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/lapalma.ext +0 -0
  48. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/lasilla.ext +0 -0
  49. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/paranal.ext +0 -0
  50. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/bd174708.dat +0 -0
  51. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/bd262606.dat +0 -0
  52. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/bd332642.dat +0 -0
  53. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/bd75325.dat +0 -0
  54. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/eg21.dat +0 -0
  55. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/feige110.dat +0 -0
  56. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/feige34.dat +0 -0
  57. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/gd153.dat +0 -0
  58. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/gd50.dat +0 -0
  59. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/gd71.dat +0 -0
  60. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/hd19445.dat +0 -0
  61. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/hd84937.dat +0 -0
  62. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/hd93521.dat +0 -0
  63. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/he3.dat +0 -0
  64. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/hiltner600.dat +0 -0
  65. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/ltt3864.dat +0 -0
  66. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/tcs_namelist.txt +0 -0
  67. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calib/std/wolf1346.dat +0 -0
  68. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/calibs.py +0 -0
  69. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/__init__.py +0 -0
  70. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/alfosc.rules +0 -0
  71. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/efosc.rules +0 -0
  72. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/help/welcome_msg_extract.html +0 -0
  73. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/help/welcome_msg_identify.html +0 -0
  74. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/help/welcome_msg_response.html +0 -0
  75. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/data/obs.py +0 -0
  76. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/efosc.py +0 -0
  77. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/extract_gui.py +0 -0
  78. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/fitsio.py +0 -0
  79. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/functions.py +0 -0
  80. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/identify_gui.py +0 -0
  81. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/images.py +0 -0
  82. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/insconfig.py +0 -0
  83. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/logging.py +0 -0
  84. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/main.py +0 -0
  85. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/operations.py +0 -0
  86. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/reports.py +0 -0
  87. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/response.py +0 -0
  88. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/response_gui.py +0 -0
  89. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/scired.py +0 -0
  90. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/scombine.py +0 -0
  91. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/skysub.py +0 -0
  92. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/tasks.py +0 -0
  93. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/transients.py +0 -0
  94. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/txtio.py +0 -0
  95. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/__init__.py +0 -0
  96. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/default_linelists.json +0 -0
  97. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/dust.py +0 -0
  98. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/linelists.py +0 -0
  99. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/messages.py +0 -0
  100. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/models.py +0 -0
  101. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/spectrum.py +0 -0
  102. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/tablemodels.py +0 -0
  103. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/targets.py +0 -0
  104. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/Assef_2010.dat +0 -0
  105. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/FeII.Vestergaard.dat +0 -0
  106. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/FeIII.Vestergaard.dat +0 -0
  107. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/Hernan_Caballero_quasar_NIR_template.txt +0 -0
  108. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/QSO_selsing.dat +0 -0
  109. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/QSO_template.Krawczyk_all.dat +0 -0
  110. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/QSO_template.Krawczyk_high.dat +0 -0
  111. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/viewer/templates/QSO_template.Krawczyk_low.dat +0 -0
  112. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/wavecal.py +0 -0
  113. {pynot_redux-2.3 → pynot_redux-2.4}/pynot/welcome.py +0 -0
  114. {pynot_redux-2.3 → pynot_redux-2.4}/pyproject.toml +0 -0
  115. {pynot_redux-2.3 → pynot_redux-2.4}/requirements.txt +0 -0
  116. {pynot_redux-2.3 → pynot_redux-2.4}/setup.cfg +0 -0
  117. {pynot_redux-2.3 → pynot_redux-2.4}/setup.py +0 -0
@@ -136,3 +136,4 @@ pynot/.instrument.cfg
136
136
  .DS_Store
137
137
  .DS_Store
138
138
  .DS_Store
139
+ *.vscode
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyNOT-redux
3
- Version: 2.3
3
+ Version: 2.4
4
4
  Summary: Data Reduction Pipeline for NOT/ALFOSC
5
5
  Home-page: https://github.com/jkrogager/PyNOT
6
6
  Author: Jens-Kristian Krogager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyNOT-redux
3
- Version: 2.3
3
+ Version: 2.4
4
4
  Summary: Data Reduction Pipeline for NOT/ALFOSC
5
5
  Home-page: https://github.com/jkrogager/PyNOT
6
6
  Author: Jens-Kristian Krogager
@@ -0,0 +1 @@
1
+ 2.4
@@ -92,3 +92,5 @@ response:
92
92
  kappa: 2 # Threshold for the median filtering to remove outlying response points
93
93
  interactive: False # Interactively filter and fit the response function
94
94
  force: False # Overwrite existing response function?
95
+ match_date: False # Use only response functions taken on the same day as the science exposure?
96
+ match_slit: False # Match both GRISM and SLIT of the science observations?
@@ -44,7 +44,7 @@ def save_database(database, output_fname):
44
44
  for filetype, files in sorted(database.items()):
45
45
  output.write("## %s:\n" % filetype)
46
46
  file_list = list()
47
- files += database.inactive.get(filetype, [])
47
+ files = files + database.inactive.get(filetype, [])
48
48
  sorted_files = sorted(files, key=lambda x: x[1:] if len(x) > 1 else x)
49
49
  for fname in sorted_files:
50
50
  try:
@@ -81,7 +81,7 @@ def match_date(files, date_mjd):
81
81
 
82
82
  return matches
83
83
 
84
- def match_response(sci_img, file_list, exact_date=False):
84
+ def match_response(sci_img, file_list, exact_date=False, match_slit=False):
85
85
  """
86
86
  Find response function that matches the grism of the input `sci_img`
87
87
  If `exact_date` is True, only return a match if the date matches exactly that of `sci_img`
@@ -89,17 +89,29 @@ def match_response(sci_img, file_list, exact_date=False):
89
89
  """
90
90
  target_grism = sci_img.grism
91
91
  target_mjd = sci_img.mjd
92
+ target_slit = sci_img.slit
92
93
  matches = list()
93
94
  date_diff = list()
94
95
  for fname in file_list:
95
96
  # These are PyNOT FITS files, so follows a slightly different Header Format
96
97
  hdr = fits.getheader(fname)
97
98
  this_grism = hdr['GRISM']
99
+ this_slit = hdr['SLIT']
98
100
  this_date = Time(hdr['DATE-OBS'])
99
- if this_grism == target_grism:
101
+ if not match_slit:
102
+ slit_filter = True
103
+ elif match_slit and this_slit == target_slit:
104
+ slit_filter = True
105
+ else:
106
+ slit_filter = False
107
+
108
+ if this_grism == target_grism and slit_filter:
100
109
  matches.append(fname)
101
110
  date_diff.append(this_date.mjd - target_mjd)
102
111
 
112
+ if len(matches) == 0:
113
+ return ""
114
+
103
115
  # Find target with smallest time difference
104
116
  idx = np.argmin(np.abs(date_diff))
105
117
  match_fname = matches[idx]
@@ -540,7 +552,7 @@ class UnknownObservingMode(Exception):
540
552
  pass
541
553
 
542
554
 
543
- class RawImage(object):
555
+ class RawImage:
544
556
  """
545
557
  Create a raw image instance from a FITS image.
546
558
 
@@ -8,7 +8,7 @@ from scipy.signal import find_peaks
8
8
  from numpy.polynomial import Chebyshev
9
9
  import warnings
10
10
 
11
- from lmfit import Parameters, minimize
11
+ from lmfit import Parameters, minimize, MinimizerException
12
12
 
13
13
  from pynot.functions import mad, NN_moffat, NN_gaussian, fix_nans, get_version_number
14
14
  from pynot import instrument
@@ -158,8 +158,8 @@ def fit_trace(img2D, x, y, model_name='moffat', dx=50, kappa=10., ymin=5, ymax=-
158
158
 
159
159
  # Fit trace with N objects:
160
160
  msg.append(" - Fitting the spectral trace with a %s profile" % model_name.title())
161
- trace_parameters = list()
162
- x_binned = np.arange(0., img2D.shape[1], dx, dtype=np.float64)
161
+ trace_parameters = []
162
+ x_binned = []
163
163
  for num in range(0, img2D.shape[1], dx):
164
164
  pars = prep_parameters(peaks, prominences, size=img2D.shape[0], model_name=model_name)
165
165
  col = np.nanmean(img2D[:, num:num+dx], axis=1)
@@ -173,12 +173,19 @@ def fit_trace(img2D, x, y, model_name='moffat', dx=50, kappa=10., ymin=5, ymax=-
173
173
  if par_val.stderr is None:
174
174
  par_val.stderr = 100.
175
175
  trace_parameters.append(popt.params)
176
+ x_binned.append(num + dx/2)
177
+ except (OverflowError, RuntimeError, MinimizerException):
178
+ msg.append(f"[WARNING] - Fitting of the trace model using a {model_name} model failed!")
179
+ msg.append(" Consider using a 'tophat' model, increase `dx` and decrease `order_center`")
180
+ msg.append("[WARNING] - Skipping this location %i:%i" % (num, num+dx))
176
181
  except ValueError:
177
182
  for par_val in pars.values():
178
183
  par_val.stderr = 100.
179
184
  trace_parameters.append(pars)
185
+ x_binned.append(num + dx/2)
180
186
  msg.append(" - Fitted %i points along the spectral trace" % len(trace_parameters))
181
187
  output_msg = "\n".join(msg)
188
+ x_binned = np.array(x_binned)
182
189
  return (x_binned, N_obj, trace_parameters, fwhm, output_msg)
183
190
 
184
191
 
@@ -262,6 +269,9 @@ def create_2d_profile(img2D, model_name='moffat', dx=25, width_scale=2, kappa_de
262
269
  fit_values = fit_trace(img2D, x, y, model_name=model_name, dx=dx, ymin=ymin, ymax=ymax, xmin=xmin, xmax=xmax, kappa=kappa_det)
263
270
  x_binned, N_obj, trace_parameters, fwhm, fit_msg = fit_values
264
271
  msg.append(fit_msg)
272
+ if len(trace_parameters) == 0:
273
+ msg.append(" [ERROR] - Automated fitting of the trace failed!")
274
+ raise ValueError("Could not determine the trace position!")
265
275
 
266
276
  msg.append(" - Creating 2D spectral profile from fitted parameters")
267
277
  msg.append(" - Profile type: %s" % model_name)
@@ -8,7 +8,6 @@ from matplotlib.patches import Ellipse
8
8
  from astropy.io import fits
9
9
  from astropy.modeling import models, fitting
10
10
  from astropy.table import Table
11
- from scipy.optimize import curve_fit
12
11
  import os
13
12
 
14
13
  from astropy.coordinates import SkyCoord
@@ -92,11 +91,11 @@ def source_detection(fname, zeropoint=0., threshold=5.0, aperture=10.0, kwargs_b
92
91
  data_sub = data - bkg
93
92
  msg.append(" - Subtracted sky background")
94
93
  msg.append(" - Background RMS: %.2e" % bkg.globalrms)
95
- data_sub = data_sub.byteswap().newbyteorder()
96
- error_image = error_image.byteswap().newbyteorder()
94
+ data_sub = data_sub.byteswap().view(data_sub.dtype.newbyteorder())
95
+ error_image = error_image.byteswap().view(error_image.dtype.newbyteorder())
97
96
  if data_sub.dtype.byteorder != '<':
98
- data_sub = data_sub.byteswap().newbyteorder()
99
- error_image = error_image.byteswap().newbyteorder()
97
+ data_sub = data_sub.byteswap().view(data_sub.dtype.newbyteorder())
98
+ error_image = error_image.byteswap().view(error_image.dtype.newbyteorder())
100
99
  extract_output = sep.extract(data_sub, threshold, err=bkg.globalrms, **kwargs_ext)
101
100
  if len(extract_output) == 2:
102
101
  objects, segmap = extract_output
@@ -366,9 +365,9 @@ def image_combine(corrected_images, output='', log_name='', fringe_image='', met
366
365
  msg.append(" - Registering input images:")
367
366
  shifted_images = [target]
368
367
  shifted_vars = [target_err**2]
369
- target = target.byteswap().newbyteorder()
368
+ target = target.byteswap().view(target.dtype.newbyteorder())
370
369
  if target.dtype.byteorder != '<':
371
- target = target.byteswap().newbyteorder()
370
+ target = target.byteswap().view(target.dtype.newbyteorder())
372
371
  final_exptime = exptime
373
372
  image_log = list()
374
373
  if len(corrected_images) > 1:
@@ -385,20 +384,20 @@ def image_combine(corrected_images, output='', log_name='', fringe_image='', met
385
384
  max_control_points=max_control_points,
386
385
  detection_sigma=detection_sigma,
387
386
  min_area=min_area)
388
- except:
387
+ except (TypeError, ValueError, aa.MaxIterError):
389
388
  msg.append(" [ERROR] - Failed to find image transformation!")
390
389
  msg.append(" - Skipping image")
391
390
  continue
392
391
 
393
- source = source.byteswap().newbyteorder()
394
- source_err = source_err.byteswap().newbyteorder()
395
- source_mask = source_mask.byteswap().newbyteorder()
392
+ source = source.byteswap().view(source.dtype.newbyteorder())
393
+ source_err = source_err.byteswap().view(source_err.dtype.newbyteorder())
394
+ source_mask = source_mask.byteswap().view(source_mask.dtype.newbyteorder())
396
395
  if source.dtype.byteorder != '<':
397
- source = source.byteswap().newbyteorder()
396
+ source = source.byteswap().view(source.dtype.newbyteorder())
398
397
  if source_err.dtype.byteorder != '<':
399
- source_err = source_err.byteswap().newbyteorder()
398
+ source_err = source_err.byteswap().view(source_err.dtype.newbyteorder())
400
399
  if source_mask.dtype.byteorder != '<':
401
- source_mask = source_mask.byteswap().newbyteorder()
400
+ source_mask = source_mask.byteswap().view(source_mask.dtype.newbyteorder())
402
401
 
403
402
  registered_image, _ = aa.apply_transform(transf, source, target, fill_value=0)
404
403
  registered_error, _ = aa.apply_transform(transf, source_err, target, fill_value=0)
@@ -584,11 +583,13 @@ def match_phot_catalogs(sep, phot, match_radius=1.):
584
583
 
585
584
  def get_sdss_catalog(ra, dec, radius=4.):
586
585
  """Download the SDSS photometry using astroquery for a circular region of radius in deg."""
586
+ # astroquery enforces radius < 3 arcmin when photoobj_fields are requested
587
+ radius = min(radius, 2.9)
587
588
  catalog_fname = 'sdss_phot_%.2f%+.2f.csv' % (ra, dec)
588
589
  fields = ['ra', 'dec', 'psfMag_u', 'psfMag_g', 'psfMag_r', 'psfMag_i', 'psfMag_z',
589
590
  'psfMagErr_u', 'psfMagErr_g', 'psfMagErr_r', 'psfMagErr_i', 'psfMagErr_z']
590
591
  field_center = SkyCoord(ra, dec, frame='icrs', unit='deg')
591
- sdss_result = SDSS.query_region(field_center, radius*u.arcmin, photoobj_fields=fields)
592
+ sdss_result = SDSS.query_region(field_center, radius=radius*u.arcmin, photoobj_fields=fields)
592
593
  if sdss_result is not None:
593
594
  sdss_result.write(os.path.join(obs.output_base_phot, catalog_fname), format='ascii.csv', overwrite=True)
594
595
  return sdss_result
@@ -641,14 +642,12 @@ def flux_calibration_sdss(img_fname, sep_fname, fig_fname='', q_lim=0.8, kappa=3
641
642
  msg.append(" - Downloading SDSS photometric catalog...")
642
643
  try:
643
644
  sdss_cat = get_sdss_catalog(hdr['CRVAL1'], hdr['CRVAL2'], radius)
644
- except:
645
+ except Exception as e:
645
646
  msg.append(" [ERROR] - Could not connect to SDSS server. Check your internet connection.")
646
647
  msg.append("")
648
+ msg.append(str(e))
647
649
  return "\n".join(msg)
648
650
 
649
- def line(x, zp):
650
- return zp + x
651
-
652
651
  if sdss_cat is None:
653
652
  msg.append(" [ERROR] - No data found in SDSS. No zero point calculated")
654
653
  msg.append("")
@@ -708,8 +707,14 @@ def flux_calibration_sdss(img_fname, sep_fname, fig_fname='', q_lim=0.8, kappa=3
708
707
  m_inst = match_sep['mag_auto']
709
708
  k = ext_coeffs[band]
710
709
 
710
+ # Reject non-finite measurements (e.g. negative fluxes giving NaN magnitudes):
711
+ finite = np.isfinite(mag) & np.isfinite(mag_err) & np.isfinite(m_inst) & (mag_err > 0)
712
+ mag = mag[finite]
713
+ mag_err = mag_err[finite]
714
+ m_inst = m_inst[finite]
715
+
711
716
  # Get first estimate using the median:
712
- zp0, _ = curve_fit(line, m_inst+k*airmass, mag, p0=[27], sigma=mag_err)
717
+ zp0 = np.median(mag - m_inst - k*airmass)
713
718
 
714
719
  # Filter outliers:
715
720
  cut = np.abs(zp0 + m_inst + k*airmass - mag) < kappa*mad(zp0 + m_inst + k*airmass - mag)
@@ -123,7 +123,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
123
123
  overwrite=True)
124
124
  log.commit(bias_msg)
125
125
  log.add_linebreak()
126
- except:
126
+ except Exception:
127
127
  log.error("Median combination of bias frames failed!")
128
128
  log.fatal_error()
129
129
  print("Unexpected error:", sys.exc_info()[0])
@@ -143,7 +143,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
143
143
  overwrite=True, mode='img')
144
144
  log.commit(flat_msg)
145
145
  master_flat[filter_name] = comb_flat_fname
146
- except:
146
+ except Exception:
147
147
  log.error("Flat field combination failed for filter: %s" % filter_name)
148
148
  log.fatal_error()
149
149
  print("Unexpected error:", sys.exc_info()[0])
@@ -156,7 +156,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
156
156
  log.write("Detected edges on Y-axis: %i ; %i" % (y1, y2))
157
157
  log.add_linebreak()
158
158
  filter_edges[filter_name] = (x1, x2, y1, y2)
159
- except:
159
+ except Exception:
160
160
  log.error("Automatic edge detection failed!")
161
161
  log.fatal_error()
162
162
  print("Unexpected error:", sys.exc_info()[0])
@@ -217,7 +217,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
217
217
  output=corrected_fname, overwrite=True, mode='img')
218
218
  log.commit(" - bias+flat ")
219
219
  temp_images.append(corrected_fname)
220
- except:
220
+ except Exception:
221
221
  log.error("Bias and flat field correction failed!")
222
222
  log.fatal_error()
223
223
  print("Unexpected error:", sys.exc_info()[0])
@@ -228,7 +228,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
228
228
  try:
229
229
  _ = trim_filter_edge(corrected_fname, *image_region, output=trim_fname)
230
230
  log.commit(" trim ")
231
- except:
231
+ except Exception:
232
232
  log.error("Image trim failed!")
233
233
  log.fatal_error()
234
234
  print("Unexpected error:", sys.exc_info()[0])
@@ -242,7 +242,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
242
242
  log.commit(" [done]")
243
243
  corrected_images.append(crr_fname)
244
244
  temp_images.append(trim_fname)
245
- except:
245
+ except Exception:
246
246
  log.error("Cosmic ray correction failed!")
247
247
  log.fatal_error()
248
248
  print("Unexpected error:", sys.exc_info()[0])
@@ -265,7 +265,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
265
265
  threshold=3)
266
266
  log.commit(msg)
267
267
  log.add_linebreak()
268
- except:
268
+ except Exception:
269
269
  log.error("Image combination failed!")
270
270
  log.fatal_error()
271
271
  print("Unexpected error:", sys.exc_info()[0])
@@ -294,8 +294,8 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
294
294
  log.error(str(e))
295
295
  log.fatal_error()
296
296
  return
297
- except:
298
- log.datal_error()
297
+ except Exception:
298
+ log.fatal_error()
299
299
  print("Unexpected error:", sys.exc_info()[0])
300
300
  raise
301
301
 
@@ -308,7 +308,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
308
308
  kwargs_ext=options['sep-extract'])
309
309
  log.commit(output_msg)
310
310
  log.add_linebreak()
311
- except:
311
+ except Exception:
312
312
  log.error("Source extraction failed!")
313
313
  log.fatal_error()
314
314
  print("Unexpected error:", sys.exc_info()[0])
@@ -321,7 +321,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
321
321
  output_msg = correct_wcs(combined_fname, sep_fname, **options['wcs'])
322
322
  log.commit(output_msg)
323
323
  log.add_linebreak()
324
- except:
324
+ except Exception:
325
325
  log.error("WCS calibration failed!")
326
326
  log.fatal_error()
327
327
  print("Unexpected error:", sys.exc_info()[0])
@@ -335,7 +335,7 @@ def run_pipeline(options_fname, verbose=False, force_restart=False):
335
335
  output_msg = flux_calibration_sdss(combined_fname, sep_fname, **options['sdss_flux'])
336
336
  log.commit(output_msg)
337
337
  log.add_linebreak()
338
- except:
338
+ except Exception:
339
339
  log.error("Zero point calibration failed!")
340
340
  log.fatal_error()
341
341
  print("Unexpected error:", sys.exc_info()[0])
@@ -463,7 +463,10 @@ def run_pipeline(options_fname, object_id=None, verbose=True, interactive=False,
463
463
 
464
464
  # Flux Calibration:
465
465
  if database.has_tag('RESPONSE'):
466
- response_fname = do.match_response(sci_img, database['RESPONSE'], exact_date=False)
466
+ response_fname = do.match_response(sci_img, database['RESPONSE'],
467
+ exact_date=task_options['response']['match_date'],
468
+ match_slit=task_options['response']['match_slit'],
469
+ )
467
470
  else:
468
471
  response_fname = ''
469
472
 
@@ -483,6 +486,8 @@ def run_pipeline(options_fname, object_id=None, verbose=True, interactive=False,
483
486
  else:
484
487
  log.warn("Could not find a response function that matches the observations!")
485
488
  log.warn("The spectra will not be flux clibrated!")
489
+ log.warn("Response functions in the database:")
490
+ log.warn(", ".join(database['RESPONSE']))
486
491
  status['FLUX2D'] = crr_fname
487
492
 
488
493
 
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import numpy as np
3
3
  from astropy.io import fits
4
+ from astropy.table import Table
4
5
  import astropy.units as u
5
6
 
6
7
  from pynot.viewer.spectrum import Spectrum
@@ -47,6 +48,8 @@ class QMEC:
47
48
  with fits.open(self.filename) as hdu:
48
49
  data = hdu['SPECTAB'].data[index]
49
50
  hdr = hdu['SPECTAB'].header
51
+ fibinfo = dict(Table.read(hdu['FIBMETATAB'])[index])
52
+ prov = hdu['PROVTAB'].data[::3][index]['ESOFILENAME']
50
53
 
51
54
  flux = data['FLUX'].flatten()
52
55
  try:
@@ -62,9 +65,9 @@ class QMEC:
62
65
  spectrum = Spectrum(wavelength=wavelength,
63
66
  flux=flux*flux_unit,
64
67
  error=error*flux_unit,
65
- name=f"[{index}]",
66
- filename=self.filename+f"[{index}]",
67
- meta=dict(hdr))
68
+ name=fibinfo['OBJ_NME'],
69
+ filename=prov,
70
+ meta=fibinfo)
68
71
  target.add_spectrum(spectrum)
69
72
  return target
70
73
 
@@ -63,7 +63,7 @@ class TargetNote:
63
63
 
64
64
 
65
65
  REDSHIFT_NAMES = ['REDSHIFT', 'Z_SPEC', 'ZBEST', 'Z_PIPE', 'ZSPEC', 'Z', 'ZFIT', 'Z_VI']
66
- ID_NAMES = ['SPECUID', 'FILENAME', 'PROV', 'OBJ_NME', 'OBJ_UID', 'NAME', 'OBJECT', 'TARGET', 'TARGETID', 'ID', 'UID']
66
+ ID_NAMES = ['PROV', 'FILENAME', 'PROV', 'OBJ_NME', 'OBJ_UID', 'NAME', 'OBJECT', 'TARGET', 'TARGETID', 'ID', 'UID']
67
67
  CLASS_NAMES = ['TYPE', 'ZBESTTYPE', 'SPECTYPE', 'CLASS', 'CLASSIFICATION', 'OBJ_CLS']
68
68
 
69
69
 
@@ -152,6 +152,10 @@ def load_redshift_table(filename, z_col=None, name_col=None, cls_col=None):
152
152
  redshift_table['TYPE'] = spectype
153
153
  redshift_table.meta['NAME_COLUMN'] = name_column
154
154
  redshift_table.add_index('NAME')
155
+ if 'ZBESTPROB' in tab.colnames:
156
+ redshift_table['ZPROB'] = tab['ZBESTPROB']
157
+ else:
158
+ redshift_table['ZPROB'] = np.nan
155
159
  return redshift_table
156
160
 
157
161
 
@@ -169,29 +173,31 @@ def redshift_table_lookup(redshift_table, spectrum):
169
173
  else:
170
174
  if not spectrum.meta:
171
175
  logging.error("Could not find a redshift. Spectrum has no metadata")
172
- return np.nan, ""
176
+ return np.nan, "", np.nan
173
177
 
174
178
  try:
175
179
  name = spectrum.meta[name_column]
176
180
  except KeyError:
177
181
  logging.error(f"Could not find a redshift. Spectrum has no {name_column} meta data")
178
- return np.nan, ""
182
+ return np.nan, "", np.nan
179
183
 
180
184
  try:
181
185
  row = redshift_table.loc[name]
182
186
  if isinstance(row, Table):
183
187
  z = row['REDSHIFT'][0]
184
188
  spectype = row['TYPE'][0]
189
+ zprob = row['ZPROB'][0]
185
190
  logging.warning(f"Multiple matches for name: {name}. Redshifts: {row['REDSHIFT']}")
186
191
  logging.warning(f"Multiple redshifts: Choosing the first: z = {z}, spectral type: {spectype}")
187
192
  else:
188
193
  z = row['REDSHIFT']
189
194
  spectype = row['TYPE']
190
- return z, spectype
195
+ zprob = row['ZPROB']
196
+ return z, spectype, zprob
191
197
 
192
198
  except KeyError:
193
199
  logging.error(f"No matching redshift for name: {name}")
194
- return np.nan, ""
200
+ return np.nan, "", np.nan
195
201
 
196
202
 
197
203
  def to_json(target: TargetNote):
@@ -511,8 +511,9 @@ class MainWindow(QtWidgets.QMainWindow):
511
511
  self.plot_spectrum(target)
512
512
 
513
513
  if self.redshift_table and len(target.spectra) > 0:
514
- z, spectype = redshift_table_lookup(self.redshift_table, target.spectra[0])
514
+ z, spectype, zprob = redshift_table_lookup(self.redshift_table, target.spectra[0])
515
515
  self.update_redshift(z)
516
+ self.update_zprob(zprob)
516
517
  self.sync_target_notes()
517
518
  self.sync_target_flags()
518
519
  target_flag: DataFlag = self.target_flags.get(target.name, DataFlag(0))
@@ -711,24 +712,36 @@ class MainWindow(QtWidgets.QMainWindow):
711
712
  self.slider_scale = 100_000
712
713
  self.slider.setRange(int(-0.1*self.slider_scale), int(7*self.slider_scale))
713
714
 
715
+ self.z_plusplus_btn = QtWidgets.QPushButton("++")
716
+ self.z_minusminus_btn = QtWidgets.QPushButton("--")
717
+ self.z_plusplus_btn.clicked.connect(lambda x: self.z_increment(0.001))
718
+ self.z_minusminus_btn.clicked.connect(lambda x: self.z_increment(-0.001))
714
719
  self.z_plus_btn = QtWidgets.QPushButton("+")
715
720
  self.z_minus_btn = QtWidgets.QPushButton("-")
716
- self.z_plus_btn.clicked.connect(self.z_increment)
717
- self.z_minus_btn.clicked.connect(self.z_decrement)
721
+ self.z_plus_btn.clicked.connect(lambda x: self.z_increment(0.0005))
722
+ self.z_minus_btn.clicked.connect(lambda x: self.z_increment(-0.0005))
718
723
  self.z_reset_btn = QtWidgets.QPushButton("Reset z")
719
724
  self.z_reset_btn.clicked.connect(self.reset_table_redshift)
720
725
 
721
726
  self.z_input = QtWidgets.QLineEdit("0.0")
722
727
  self.z_input.setFixedWidth(60)
723
728
 
729
+ self.zprob_text = QtWidgets.QLineEdit("0.0")
730
+ self.zprob_text.setFixedWidth(45)
731
+ self.zprob_text.setReadOnly(True)
732
+
724
733
  lines_toolbar.addWidget(self.linelist_combo)
725
734
  lines_toolbar.addWidget(self.linelist_edit_btn)
726
735
  lines_toolbar.addWidget(QtWidgets.QLabel("Redshift: "))
727
736
  lines_toolbar.addWidget(self.slider)
728
- lines_toolbar.addWidget(self.z_plus_btn)
737
+ # lines_toolbar.addWidget(self.z_minusminus_btn)
729
738
  lines_toolbar.addWidget(self.z_minus_btn)
739
+ lines_toolbar.addWidget(self.z_plus_btn)
740
+ # lines_toolbar.addWidget(self.z_plusplus_btn)
730
741
  lines_toolbar.addWidget(self.z_input)
731
742
  lines_toolbar.addWidget(self.z_reset_btn)
743
+ lines_toolbar.addWidget(QtWidgets.QLabel("P(z):"))
744
+ lines_toolbar.addWidget(self.zprob_text)
732
745
  self.slider.valueChanged.connect(self.update_from_slider)
733
746
  self.z_input.editingFinished.connect(self.update_from_text)
734
747
  self.addToolBar(lines_toolbar)
@@ -802,13 +815,13 @@ class MainWindow(QtWidgets.QMainWindow):
802
815
  except (ValueError, TypeError):
803
816
  logging.error("Invalid redshift input: {z}. Must be a numeral")
804
817
 
805
- def z_increment(self):
818
+ def z_increment(self, dz):
806
819
  z = float(self.z_input.text())
807
- self.update_redshift(z + 0.0001)
820
+ self.update_redshift(z + dz)
808
821
 
809
822
  def z_decrement(self):
810
823
  z = float(self.z_input.text())
811
- self.update_redshift(z - 0.0001)
824
+ self.update_redshift(z - 0.0005)
812
825
 
813
826
  def reset_table_redshift(self):
814
827
  targets = self.get_real_active_targets()
@@ -817,8 +830,12 @@ class MainWindow(QtWidgets.QMainWindow):
817
830
 
818
831
  target = targets[0]
819
832
  if self.redshift_table and len(target.spectra) > 0:
820
- z, spectype = redshift_table_lookup(self.redshift_table, target.spectra[0])
833
+ z, spectype, zprob = redshift_table_lookup(self.redshift_table, target.spectra[0])
821
834
  self.update_redshift(z)
835
+ self.update_zprob(zprob)
836
+
837
+ def update_zprob(self, zprob):
838
+ self.zprob_text.setText(f"{zprob:.3f}")
822
839
 
823
840
  def toggle_gridlines(self):
824
841
  show_grid = self.grid_radio_button.isChecked()
@@ -87,10 +87,15 @@ def get_gaia_catalog(ra, dec, radius=4., limit=2000, catalog_fname='', database=
87
87
  limit: max number of targets to retrieve
88
88
  """
89
89
  from astroquery.gaia import Gaia
90
- query_args = {'limit': limit, 'ra': ra, 'dec': dec, 'radius': radius/60., 'dr': database}
91
- query = """SELECT TOP {limit} ra, dec, phot_g_mean_mag, bp_rp FROM gaia{dr}.gaia_source
92
- WHERE CONTAINS(POINT('ICRS', gaia{dr}.gaia_source.ra, gaia{dr}.gaia_source.dec),
93
- CIRCLE('ICRS', {ra}, {dec}, {radius}))=1;""".format(**query_args)
90
+ size = radius / 60.
91
+ query_args = {'limit': limit, 'ra_lower': ra-size, 'ra_upper': ra+size,
92
+ 'dec_lower': dec-size, 'dec_upper': dec+size, 'dr': database}
93
+ query = """
94
+ SELECT TOP {limit} ra, dec, phot_g_mean_mag, bp_rp
95
+ FROM gaia{dr}.gaia_source
96
+ WHERE ra BETWEEN {ra_lower} AND {ra_upper}
97
+ AND dec BETWEEN {dec_lower} AND {dec_upper}
98
+ """.format(**query_args)
94
99
  job = Gaia.launch_job_async(query, dump_to_file=True,
95
100
  output_format='csv', verbose=False,
96
101
  output_file=catalog_fname)
@@ -187,9 +192,10 @@ def correct_wcs(img_fname, sep_fname, output='', fig_fname='', min_num=6, G_lim=
187
192
  ref_cat = get_gaia_catalog(hdr['CRVAL1'], hdr['CRVAL2'],
188
193
  radius=radius, catalog_fname=gaia_cat_name, database=gaia_dr)
189
194
  msg.append(" - Saving Gaia source catalog: %s" % gaia_cat_name)
190
- except:
195
+ except Exception as e:
191
196
  msg.append(" [ERROR] - Could not reach Gaia server! Check your internet connection.")
192
197
  msg.append("")
198
+ msg.append(str(e))
193
199
  return "\n".join(msg)
194
200
 
195
201
  # reject brightest sources:
@@ -234,7 +240,7 @@ def correct_wcs(img_fname, sep_fname, output='', fig_fname='', min_num=6, G_lim=
234
240
  # Reject outliers:
235
241
  msg.append(" - Performing initial cross identification")
236
242
  msg.append(" - Found %s source%s" % (len(matched_ref),
237
- '' if len(matched_ref)==1 else 's'))
243
+ '' if len(matched_ref) == 1 else 's'))
238
244
  dist = np.sqrt(np.sum((matched_ref - matched_sep)**2, axis=1))*3600
239
245
  dxdy = np.abs(matched_sep - matched_ref)
240
246
  theta = np.arctan2(dxdy[:, 1], dxdy[:, 0])
@@ -280,7 +286,7 @@ def correct_wcs(img_fname, sep_fname, output='', fig_fname='', min_num=6, G_lim=
280
286
  msg.append("")
281
287
  return "\n".join(msg)
282
288
 
283
- # Fit the WCS transformation:
289
+ # Fit the WCS transformation:
284
290
  _, crval, CD, _ = get_WCS(hdr)
285
291
  msg.append(" - Fitting WCS transformation using %i sources" % len(matched_ref))
286
292
  wcs_keys = update_WCS(matched_sep, matched_ref, crval, CD)
@@ -299,12 +305,12 @@ def correct_wcs(img_fname, sep_fname, output='', fig_fname='', min_num=6, G_lim=
299
305
  ax = fig.add_subplot(111, projection=wcs_new)
300
306
  med_val = np.median(img)
301
307
  ax.imshow(img, vmin=med_val-1*mad(img), vmax=med_val+10*mad(img),
302
- origin='lower', cmap=plt.cm.gray_r)
308
+ origin='lower', cmap=plt.cm.gray_r)
303
309
  ax.scatter(matched_ref[:, 0], matched_ref[:, 1],
304
- transform=ax.get_transform('fk5'), edgecolor='r', facecolor='none', s=50)
310
+ transform=ax.get_transform('fk5'), edgecolor='r', facecolor='none', s=50)
305
311
  if debug:
306
312
  ax.scatter(matched_sep[:, 0], matched_sep[:, 1],
307
- transform=ax.get_transform('fk5'), edgecolor='green', facecolor='none', s=10, alpha=0.7)
313
+ transform=ax.get_transform('fk5'), edgecolor='green', facecolor='none', s=10, alpha=0.7)
308
314
  for i, r in zip(matched_sep, matched_ref):
309
315
  ax.plot([i[0], r[0]], [i[1], r[1]], 'k', alpha=0.5, transform=ax.get_transform('fk5'))
310
316
  ax.set_xlabel("Right Ascension")
@@ -1 +0,0 @@
1
- 2.3
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes