From b00f1d6f89da3a26424581b8b0438739f749668f Mon Sep 17 00:00:00 2001 From: rcooke Date: Mon, 19 Feb 2024 09:14:29 +0000 Subject: [PATCH 1/8] correct DAR option added --- pypeit/coadd3d.py | 11 +++++++--- pypeit/core/datacube.py | 46 +++++++++++++++++++++++++++++------------ pypeit/par/pypeitpar.py | 9 ++++++-- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/pypeit/coadd3d.py b/pypeit/coadd3d.py index 5174fc0207..86de393d5e 100644 --- a/pypeit/coadd3d.py +++ b/pypeit/coadd3d.py @@ -414,6 +414,7 @@ def __init__(self, spec2dfiles, par, skysub_frame=None, scale_corr=None, ra_offs self.method = self.cubepar['method'] self.combine = self.cubepar['combine'] self.align = self.cubepar['align'] + self.correct_dar = self.cubepar['correct_dar'] # Do some quick checks on the input options if skysub_frame is not None and len(skysub_frame) != self.numfiles: msgs.error("The skysub_frame list should be identical length to the spec2dfiles list") @@ -1178,7 +1179,8 @@ def load(self): overwrite=self.overwrite, whitelight_range=wl_wvrng, outfile=outfile, spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, - slice_subpixel=self.slice_subpixel) + slice_subpixel=self.slice_subpixel, + correct_dar=self.correct_dar) # Prepare the header hdr = self.all_wcs[ff].to_header() if self.fluxcal: @@ -1297,6 +1299,7 @@ def compute_weights(self): weight_method=self.cubepar['weight_method'], whitelight_range=self.cubepar['whitelight_range'], reference_image=self.cubepar['reference_image'], + correct_dar=self.correct_dar, specname=self.specname) def run(self): @@ -1384,7 +1387,8 @@ def run(self): outfile=outfile, overwrite=self.overwrite, whitelight_range=wl_wvrng, spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, - slice_subpixel=self.slice_subpixel) + slice_subpixel=self.slice_subpixel, + correct_dar=self.correct_dar) # Prepare the header hdr = cube_wcs.to_header() if self.fluxcal: @@ -1409,7 +1413,8 @@ def run(self): overwrite=self.overwrite, whitelight_range=wl_wvrng, outfile=outfile, spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, - slice_subpixel=self.slice_subpixel) + slice_subpixel=self.slice_subpixel, + correct_dar=self.correct_dar) # Prepare the header hdr = cube_wcs.to_header() if self.fluxcal: diff --git a/pypeit/core/datacube.py b/pypeit/core/datacube.py index 2105e2d0a1..e6f6a6bc3f 100644 --- a/pypeit/core/datacube.py +++ b/pypeit/core/datacube.py @@ -983,7 +983,7 @@ def compute_weights_frompix(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, all_wcs, all_tilts, all_slits, all_align, all_dar, ra_offsets, dec_offsets, ra_min=None, ra_max=None, dec_min=None, dec_max=None, wave_min=None, wave_max=None, sn_smooth_npix=None, weight_method='auto', reference_image=None, whitelight_range=None, - specname="PYPSPEC"): + correct_dar=True, specname="PYPSPEC"): r""" Calculate wavelength dependent optimal weights. The weighting is currently based on a relative :math:`(S/N)^2` at each wavelength. Note, this function @@ -1082,6 +1082,8 @@ def compute_weights_frompix(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, reference_image : `numpy.ndarray`_ Reference image to use for the determination of the highest S/N spaxel in the image. + correct_dar : bool, optional + Correct for the differential atmospheric refraction. Default is False. specname : str Name of the spectrograph @@ -1109,21 +1111,22 @@ def compute_weights_frompix(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, # NOTE: hard-coding subpixel=1 in both directions for speed, and combining into a single image wl_full = generate_image_subpixel(image_wcs, voxedge, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtsImg, all_wcs, all_tilts, all_slits, all_align, all_dar, ra_offsets, dec_offsets, - spec_subpixel=1, spat_subpixel=1, slice_subpixel=1, combine=True) + spec_subpixel=1, spat_subpixel=1, slice_subpixel=1, combine=True, + correct_dar=correct_dar) # Compute the weights return compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, all_wcs, all_tilts, all_slits, all_align, all_dar, ra_offsets, dec_offsets, wl_full[:, :, 0], dspat, dwv, ra_min=ra_min, ra_max=ra_max, dec_min=dec_min, dec_max=dec_max, wave_min=wave_min, - sn_smooth_npix=sn_smooth_npix, weight_method=weight_method) + sn_smooth_npix=sn_smooth_npix, weight_method=weight_method, correct_dar=correct_dar) def compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, all_wcs, all_tilts, all_slits, all_align, all_dar, ra_offsets, dec_offsets, whitelight_img, dspat, dwv, ra_min=None, ra_max=None, dec_min=None, dec_max=None, wave_min=None, wave_max=None, - sn_smooth_npix=None, weight_method='auto'): + sn_smooth_npix=None, weight_method='auto', correct_dar=True): r""" Calculate wavelength dependent optimal weights. The weighting is currently based on a relative :math:`(S/N)^2` at each wavelength @@ -1171,6 +1174,8 @@ def compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, Number of pixels used for determining smoothly varying S/N ratio weights. This is currently not required, since a relative weighting scheme with a polynomial fit is used to calculate the S/N weights. + correct_dar : bool, optional + Apply the DAR correction to the input data. The default is True. weight_method : `str`, optional Weight method to be used in :func:`~pypeit.coadd.sn_weights`. Options are ``'auto'``, ``'constant'``, ``'uniform'``, ``'wave_dependent'``, ``'relative'``, or @@ -1260,7 +1265,8 @@ def compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, _slitidImg[ff], np.ones(_sciImg[ff].shape), _all_wcs[ff], _all_tilts[ff], _all_slits[ff], _all_align[ff], _all_dar[ff], _ra_offsets[ff], _dec_offsets[ff], - spec_subpixel=1, spat_subpixel=1, slice_subpixel=1) + spec_subpixel=1, spat_subpixel=1, slice_subpixel=1, + correct_dar=correct_dar) # Store the flux and ivar spectra of the highest S/N object. # TODO :: This is the flux per spectral pixel, and not per detector pixel. Is this correct? flux_stack[:, ff] = flxcube[:, 0, 0] @@ -1290,7 +1296,7 @@ def compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, def generate_image_subpixel(image_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, - spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, combine=False): + spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, combine=False, correct_dar=True): """ Generate a white light image from the input pixels @@ -1355,6 +1361,10 @@ def generate_image_subpixel(image_wcs, bins, sciImg, ivarImg, waveImg, slitid_im combine (:obj:`bool`, optional): If True, all of the input frames will be combined into a single output. Otherwise, individual images will be generated. + correct_dar (:obj:`bool`, optional): + If True, the DAR correction will be applied to the input images + before generating the white light images. If False, the DAR + correction will not be applied. Returns: `numpy.ndarray`_: The white light images for all frames @@ -1376,12 +1386,14 @@ def generate_image_subpixel(image_wcs, bins, sciImg, ivarImg, waveImg, slitid_im # Subpixellate img, _, _ = subpixellate(image_wcs, bins, _sciImg, _ivarImg, _waveImg, _slitid_img_gpm, _wghtImg, _all_wcs, _tilts, _slits, _astrom_trans, _all_dar, _ra_offset, _dec_offset, - spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel) + spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, + correct_dar=correct_dar) else: # Subpixellate img, _, _ = subpixellate(image_wcs, bins, _sciImg[fr], _ivarImg[fr], _waveImg[fr], _slitid_img_gpm[fr], _wghtImg[fr], _all_wcs[fr], _tilts[fr], _slits[fr], _astrom_trans[fr], _all_dar[fr], _ra_offset[fr], _dec_offset[fr], - spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel) + spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, + correct_dar=correct_dar) all_wl_imgs[:, :, fr] = img[:, :, 0] # Return the constructed white light images return all_wl_imgs @@ -1391,7 +1403,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, - overwrite=False, outfile=None, whitelight_range=None, debug=False): + overwrite=False, outfile=None, whitelight_range=None, correct_dar=True, debug=False): """ Save a datacube using the subpixel algorithm. Refer to the subpixellate() docstring for further details about this algorithm @@ -1468,6 +1480,9 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im either element of the list is None, then the minimum/maximum wavelength range of that element will be set by the minimum/maximum wavelength of all_wave. + correct_dar (bool, optional): + If True, the DAR correction will be applied to the datacube. If the + DAR correction is not available, the datacube will not be corrected. debug (bool, optional): If True, a residuals cube will be output. If the datacube generation is correct, the distribution of pixels in the residual cube with no @@ -1496,7 +1511,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im subpix = subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, - debug=debug) + correct_dar=correct_dar, debug=debug) # Extract the variables that we need if debug: flxcube, varcube, bpmcube, residcube = subpix @@ -1537,7 +1552,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, - spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, debug=False): + spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, correct_dar=True, debug=False): r""" Subpixellate the input data into a datacube. This algorithm splits each detector pixel into multiple subpixels and each IFU slice into multiple subslices. @@ -1614,6 +1629,9 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh values give more reliable results, but note that the time required goes as (``slice_subpixel``). The default value is 5, which divides each IFU slice into 5 subslices in the slice direction. + correct_dar (bool, optional): + If True, the DAR correction will be applied to the datacube. The + default is True. debug (bool, optional): If True, a residuals cube will be output. If the datacube generation is correct, the distribution of pixels in the residual cube with no @@ -1655,7 +1673,7 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh this_slits = _slits[fr] this_wcs = _all_wcs[fr] this_astrom_trans = _astrom_trans[fr] - this_wght_subpix = _wghtImg[fr][this_onslit_gpm] * area + this_wght_subpix = _wghtImg[fr][this_onslit_gpm] this_sci = _sciImg[fr][this_onslit_gpm] this_var = utils.inverse(_ivarImg[fr][this_onslit_gpm]) this_wav = _waveImg[fr][this_onslit_gpm] @@ -1685,7 +1703,9 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh # Calculate the wavelength at each subpixel this_wave_subpix = wave_spl(tiltpos) # Calculate the DAR correction at each sub pixel - ra_corr, dec_corr = _all_dar[fr].correction(this_wave_subpix) # This routine needs the wavelengths to be expressed in Angstroms + ra_corr, dec_corr = 0.0, 0.0 + if correct_dar: + ra_corr, dec_corr = _all_dar[fr].correction(this_wave_subpix) # This routine needs the wavelengths to be expressed in Angstroms # Calculate spatial and spectral positions of the subpixels spat_xx = np.add.outer(wpix[1], spat_x.flatten()).flatten() spec_yy = np.add.outer(wpix[0], spec_y.flatten()).flatten() diff --git a/pypeit/par/pypeitpar.py b/pypeit/par/pypeitpar.py index 19f918f3a8..633459f3de 100644 --- a/pypeit/par/pypeitpar.py +++ b/pypeit/par/pypeitpar.py @@ -1562,7 +1562,8 @@ def __init__(self, slit_spec=None, weight_method=None, align=None, combine=None, standard_cube=None, reference_image=None, save_whitelight=None, whitelight_range=None, method=None, ra_min=None, ra_max=None, dec_min=None, dec_max=None, wave_min=None, wave_max=None, spatial_delta=None, wave_delta=None, astrometric=None, grating_corr=None, scale_corr=None, - skysub_frame=None, spec_subpixel=None, spat_subpixel=None, slice_subpixel=None): + skysub_frame=None, spec_subpixel=None, spat_subpixel=None, slice_subpixel=None, + correct_dar=None): # Grab the parameter names and values from the function # arguments @@ -1761,6 +1762,10 @@ def __init__(self, slit_spec=None, weight_method=None, align=None, combine=None, 'this correction, it is best to use the spec2d file with the highest S/N sky spectrum. ' \ 'You should choose the same frame for both the standards and science frames.' + defaults['correct_dar'] = True + dtypes['correct_dar'] = bool + descr['correct_dar'] = 'If True, the data will be corrected for differential atmospheric refraction (DAR).' + defaults['skysub_frame'] = 'image' dtypes['skysub_frame'] = str descr['skysub_frame'] = 'Set the sky subtraction to be implemented. The default behaviour is to subtract ' \ @@ -1790,7 +1795,7 @@ def from_dict(cls, cfg): parkeys = ['slit_spec', 'output_filename', 'standard_cube', 'reference_image', 'save_whitelight', 'method', 'spec_subpixel', 'spat_subpixel', 'slice_subpixel', 'ra_min', 'ra_max', 'dec_min', 'dec_max', 'wave_min', 'wave_max', 'spatial_delta', 'wave_delta', 'weight_method', 'align', 'combine', - 'astrometric', 'grating_corr', 'scale_corr', 'skysub_frame', 'whitelight_range'] + 'astrometric', 'grating_corr', 'scale_corr', 'skysub_frame', 'whitelight_range', 'correct_dar'] badkeys = np.array([pk not in parkeys for pk in k]) if np.any(badkeys): From 874fff8c56ef2347f097b38bd43cd78f3dcf1928 Mon Sep 17 00:00:00 2001 From: rcooke Date: Mon, 19 Feb 2024 17:02:19 +0000 Subject: [PATCH 2/8] occurrences utility function --- pypeit/tests/test_utils.py | 6 ++++++ pypeit/utils.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/pypeit/tests/test_utils.py b/pypeit/tests/test_utils.py index bbeafb9ade..4d12bf63e0 100644 --- a/pypeit/tests/test_utils.py +++ b/pypeit/tests/test_utils.py @@ -138,3 +138,9 @@ def test_recursive_update(): d = utils.recursive_update(d, u) assert sorted(list(d['rdx'].keys())) == ['detnum', 'spectrograph'], 'Missing merged keys' + +def test_occurrences(): + inparr = np.array([1, 1, 4, 10, 5, 3, 5, 5, 8, 9]) + tstarr = np.array([2, 2, 1, 1, 3, 1, 3, 3, 1, 1]) + outarr = utils.occurrences(inparr) + assert np.array_equal(outarr, tstarr), 'Occurrences has failed' diff --git a/pypeit/utils.py b/pypeit/utils.py index 8e7c759c56..fbc6550c15 100644 --- a/pypeit/utils.py +++ b/pypeit/utils.py @@ -957,6 +957,26 @@ def rebinND(img, shape): return img_out +def occurrences(inarr): + """ Calculate the sub-pixellation weights. + + This function calculates the number of occurrences of each unique value in the input array. + For example, if the input array is [1, 1, 2, 2, 2, 3], the output array would be [2, 2, 3, 3, 3, 1]. + + Parameters + ---------- + inarr : ndarray + Input array. Must be 1D. + + Returns + ------- + ndarray + Array of sub-pixellation weights, same shape as input array. + """ + _, idx, cnt = np.unique(inarr, return_inverse=True, return_counts=True) + return cnt[idx] + + def pyplot_rcparams(): """ params for pretty matplotlib plots From f154b2645ab52a8b97c446c1fbc1c65c8ea7688e Mon Sep 17 00:00:00 2001 From: rcooke Date: Mon, 19 Feb 2024 17:02:53 +0000 Subject: [PATCH 3/8] calculate RA/Dec Image (one slit only) --- pypeit/slittrace.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pypeit/slittrace.py b/pypeit/slittrace.py index 4cec5b5916..2e7d08d1ce 100644 --- a/pypeit/slittrace.py +++ b/pypeit/slittrace.py @@ -479,7 +479,7 @@ def get_slitlengths(self, initial=False, median=False): slitlen = right - left return np.median(slitlen, axis=1) if median else slitlen - def get_radec_image(self, wcs, alignSplines, tilts, slice_offset=None, initial=True, flexure=None): + def get_radec_image(self, wcs, alignSplines, tilts, slit_compute=None, slice_offset=None, initial=True, flexure=None): """Generate an RA and DEC image for every pixel in the frame NOTE: This function is currently only used for SlicerIFU reductions. @@ -515,6 +515,15 @@ def get_radec_image(self, wcs, alignSplines, tilts, slice_offset=None, initial=T reference (usually the centre of the slit) and the edges of the slits. Shape is (nslits, 2). """ + # Check the input + if slit_compute is None: + # Compute all of the slits + slit_compute = np.arange(self.nslits) + elif isinstance(slit_compute, int): + slit_compute = np.atleast_1d(slit_compute) + elif isinstance(slit_compute, list): + slit_compute = np.array(slit_compute) + # Prepare the print out substring = '' if slice_offset is None else f' with slice_offset={slice_offset:.3f}' msgs.info("Generating an RA/DEC image"+substring) # Check the input @@ -529,6 +538,8 @@ def get_radec_image(self, wcs, alignSplines, tilts, slice_offset=None, initial=T # Get the slit information slitid_img_init = self.slit_img(pad=0, initial=initial, flexure=flexure) for slit_idx, spatid in enumerate(self.spat_id): + if slit_idx not in slit_compute: + continue onslit = (slitid_img_init == spatid) onslit_init = np.where(onslit) if self.mask[slit_idx] != 0: From acdcef6ebce664b7ff9074573ef6f5a1f1e02f54 Mon Sep 17 00:00:00 2001 From: rcooke Date: Mon, 19 Feb 2024 17:03:24 +0000 Subject: [PATCH 4/8] Fixed variance cubes --- pypeit/core/datacube.py | 125 +++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 46 deletions(-) diff --git a/pypeit/core/datacube.py b/pypeit/core/datacube.py index e6f6a6bc3f..139e9fb508 100644 --- a/pypeit/core/datacube.py +++ b/pypeit/core/datacube.py @@ -1552,7 +1552,8 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, - spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, correct_dar=True, debug=False): + spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, skip_subpix_weights=False, + correct_dar=True, debug=False): r""" Subpixellate the input data into a datacube. This algorithm splits each detector pixel into multiple subpixels and each IFU slice into multiple subslices. @@ -1629,6 +1630,14 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh values give more reliable results, but note that the time required goes as (``slice_subpixel``). The default value is 5, which divides each IFU slice into 5 subslices in the slice direction. + skip_subpix_weights (bool, optional): + If True, the computationally expensive step to calculate the + subpixellation weights will be skipped. If set the True, note that + the variance cubes returned will not be accurate. However, if you + are not interested in the variance cubes, this can save a lot of + time, and this is an example where you might consider setting this + variable to True. The flux datacube is unaffected by this variable. + The default is False. correct_dar (bool, optional): If True, the DAR correction will be applied to the datacube. The default is True. @@ -1651,6 +1660,7 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh # Prepare the output arrays outshape = (bins[0].size-1, bins[1].size-1, bins[2].size-1) binrng = [[bins[0][0], bins[0][-1]], [bins[1][0], bins[1][-1]], [bins[2][0], bins[2][-1]]] + binrng_arr = np.array(binrng) flxcube, varcube, normcube = np.zeros(outshape), np.zeros(outshape), np.zeros(outshape) if debug: residcube = np.zeros(outshape) @@ -1659,8 +1669,8 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh spat_offs = np.arange(0.5/spat_subpixel, 1, 1/spat_subpixel) - 0.5 # -0.5 is to offset from the centre of each pixel. slice_offs = np.arange(0.5/slice_subpixel, 1, 1/slice_subpixel) - 0.5 # -0.5 is to offset from the centre of each slice. spat_x, spec_y = np.meshgrid(spat_offs, spec_offs) - num_subpixels = spec_subpixel * spat_subpixel # Number of subpixels per detector pixel - area = 1 / (num_subpixels * slice_subpixel) # Area of each subpixel + num_subpixels = spec_subpixel * spat_subpixel # Number of subpixels (spat & spec) per detector pixel + num_all_subpixels = num_subpixels * slice_subpixel # Number of subpixels, including slice subpixels # Loop through all exposures for fr in range(numframes): onslit_gpm = _gpmImg[fr] @@ -1677,43 +1687,50 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh this_sci = _sciImg[fr][this_onslit_gpm] this_var = utils.inverse(_ivarImg[fr][this_onslit_gpm]) this_wav = _waveImg[fr][this_onslit_gpm] - # Loop over the subslices - for ss in range(slice_subpixel): - if slice_subpixel > 1: - # Only print this if there are multiple subslices - msgs.info(f"Resampling subslice {ss+1}/{slice_subpixel}") - # Generate an RA/Dec image for this subslice - raimg, decimg, minmax = this_slits.get_radec_image(this_wcs, this_astrom_trans, this_tilts, slice_offset=slice_offs[ss]) - this_ra = raimg[this_onslit_gpm] - this_dec = decimg[this_onslit_gpm] - # Loop through all slits - for sl, spatid in enumerate(this_slits.spat_id): - if numframes == 1: - msgs.info(f"Resampling slit {sl+1}/{this_slits.nslits}") - else: - msgs.info(f"Resampling slit {sl+1}/{this_slits.nslits} of frame {fr+1}/{numframes}") - this_sl = np.where(this_spatid == spatid) - wpix = (this_specpos[this_sl], this_spatpos[this_sl]) - # Generate a spline between spectral pixel position and wavelength - yspl = this_tilts[wpix]*(this_slits.nspec - 1) - tiltpos = np.add.outer(yspl, spec_y).flatten() - wspl = this_wav[this_sl] - asrt = np.argsort(yspl) - wave_spl = interp1d(yspl[asrt], wspl[asrt], kind='linear', bounds_error=False, fill_value='extrapolate') - # Calculate the wavelength at each subpixel - this_wave_subpix = wave_spl(tiltpos) - # Calculate the DAR correction at each sub pixel - ra_corr, dec_corr = 0.0, 0.0 - if correct_dar: - ra_corr, dec_corr = _all_dar[fr].correction(this_wave_subpix) # This routine needs the wavelengths to be expressed in Angstroms - # Calculate spatial and spectral positions of the subpixels - spat_xx = np.add.outer(wpix[1], spat_x.flatten()).flatten() - spec_yy = np.add.outer(wpix[0], spec_y.flatten()).flatten() - # Transform this to spatial location - spatpos_subpix = _astrom_trans[fr].transform(sl, spat_xx, spec_yy) - spatpos = _astrom_trans[fr].transform(sl, wpix[1], wpix[0]) + # Loop through all slits + for sl, spatid in enumerate(this_slits.spat_id): + if numframes == 1: + msgs.info(f"Resampling slit {sl + 1}/{this_slits.nslits}") + else: + msgs.info(f"Resampling slit {sl + 1}/{this_slits.nslits} of frame {fr + 1}/{numframes}") + # Find the pixels on this slit + this_sl = np.where(this_spatid == spatid) + wpix = (this_specpos[this_sl], this_spatpos[this_sl]) + # Create an array to index each subpixel + numpix = wpix[0].size + # Generate a spline between spectral pixel position and wavelength + yspl = this_tilts[wpix] * (this_slits.nspec - 1) + tiltpos = np.add.outer(yspl, spec_y).flatten() + wspl = this_wav[this_sl] + asrt = np.argsort(yspl) + wave_spl = interp1d(yspl[asrt], wspl[asrt], kind='linear', bounds_error=False, fill_value='extrapolate') + # Calculate the wavelength at each subpixel + this_wave_subpix = wave_spl(tiltpos) + # Calculate the DAR correction at each sub pixel + ra_corr, dec_corr = 0.0, 0.0 + if correct_dar: + # NOTE :: This routine needs the wavelengths to be expressed in Angstroms + ra_corr, dec_corr = _all_dar[fr].correction( this_wave_subpix) + # Calculate spatial and spectral positions of the subpixels + spat_xx = np.add.outer(wpix[1], spat_x.flatten()).flatten() + spec_yy = np.add.outer(wpix[0], spec_y.flatten()).flatten() + # Transform this to spatial location + spatpos_subpix = _astrom_trans[fr].transform(sl, spat_xx, spec_yy) + spatpos = _astrom_trans[fr].transform(sl, wpix[1], wpix[0]) + ssrt = np.argsort(spatpos) + # Initialize the voxel coordinates for each spec2D pixel + vox_coord = -1*np.ones((numpix, num_all_subpixels, 3)) + # Loop over the subslices + for ss in range(slice_subpixel): + if slice_subpixel > 1: + # Only print this if there are multiple subslices + msgs.info(f"Resampling subslice {ss+1}/{slice_subpixel}") + # Generate an RA/Dec image for this subslice + raimg, decimg, minmax = this_slits.get_radec_image(this_wcs, this_astrom_trans, this_tilts, + slit_compute=sl, slice_offset=slice_offs[ss]) + this_ra = raimg[this_onslit_gpm] + this_dec = decimg[this_onslit_gpm] # Interpolate the RA/Dec over the subpixel spatial positions - ssrt = np.argsort(spatpos) tmp_ra = this_ra[this_sl] tmp_dec = this_dec[this_sl] ra_spl = interp1d(spatpos[ssrt], tmp_ra[ssrt], kind='linear', bounds_error=False, fill_value='extrapolate') @@ -1725,13 +1742,29 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh this_ra_int += ra_corr + _ra_offset[fr] this_dec_int += dec_corr + _dec_offset[fr] # Convert world coordinates to voxel coordinates, then histogram - vox_coord = output_wcs.wcs_world2pix(np.vstack((this_ra_int, this_dec_int, this_wave_subpix * 1.0E-10)).T, 0) - # Use the "fast histogram" algorithm, that assumes regular bin spacing - flxcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * this_wght_subpix[this_sl], num_subpixels)) - varcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_var[this_sl] * this_wght_subpix[this_sl]**2, num_subpixels)) - normcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_wght_subpix[this_sl], num_subpixels)) - if debug: - residcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * np.sqrt(utils.inverse(this_var[this_sl])), num_subpixels)) + sslo = ss * num_subpixels + sshi = (ss + 1) * num_subpixels + vox_coord[:,sslo:sshi,:] = output_wcs.wcs_world2pix(np.vstack((this_ra_int, this_dec_int, this_wave_subpix * 1.0E-10)).T, 0).reshape(numpix, num_subpixels, 3) + # Convert the voxel coordinates to a bin index + if num_all_subpixels == 1 or skip_subpix_weights: + subpix_wght = 1.0 + else: + msgs.info("Preparing subpixel weights") + vox_index = np.floor(outshape * (vox_coord - binrng_arr[:,0].reshape((1, 1, 3))) / + (binrng_arr[:,1] - binrng_arr[:,0]).reshape((1, 1, 3))).astype(int) + # Convert to a unique index + vox_index = np.dot(vox_index, np.array([1, outshape[0], outshape[0]*outshape[1]])) + # Calculate the number of repeated indices for each subpixel - this is the subpixel weights + subpix_wght = np.apply_along_axis(utils.occurrences, 1, vox_index).flatten() + # Reshape the voxel coordinates + vox_coord = vox_coord.reshape(numpix * num_all_subpixels, 3) + # Use the "fast histogram" algorithm, that assumes regular bin spacing + flxcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * this_wght_subpix[this_sl], num_all_subpixels) * subpix_wght) + varcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_var[this_sl] * this_wght_subpix[this_sl]**2, num_all_subpixels) * subpix_wght**3) + normcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_wght_subpix[this_sl], num_all_subpixels) * subpix_wght) + if debug: + # NOTE :: The residual cube does not include the subpixel weights - so, the following line is probably incorrect + residcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * np.sqrt(utils.inverse(this_var[this_sl])), num_all_subpixels)) # Normalise the datacube and variance cube nc_inverse = utils.inverse(normcube) flxcube *= nc_inverse From 8d6be48f9f14b75a69207ae6b1afe364495f012f Mon Sep 17 00:00:00 2001 From: rcooke Date: Mon, 19 Feb 2024 21:02:09 +0000 Subject: [PATCH 5/8] skip subpix weights --- pypeit/coadd3d.py | 6 ++++++ pypeit/core/datacube.py | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/pypeit/coadd3d.py b/pypeit/coadd3d.py index 86de393d5e..e6cc7d356c 100644 --- a/pypeit/coadd3d.py +++ b/pypeit/coadd3d.py @@ -483,14 +483,17 @@ def __init__(self, spec2dfiles, par, skysub_frame=None, scale_corr=None, ra_offs # Determine what method is requested self.spec_subpixel, self.spat_subpixel, self.slice_subpixel = 1, 1, 1 + self.skip_subpix_weights = True if self.method == "subpixel": self.spec_subpixel, self.spat_subpixel, self.slice_subpixel = self.cubepar['spec_subpixel'], self.cubepar['spat_subpixel'], self.cubepar['slice_subpixel'] + self.skip_subpix_weights = False msgs.info("Adopting the subpixel algorithm to generate the datacube, with subpixellation scales:" + msgs.newline() + f" Spectral: {self.spec_subpixel}" + msgs.newline() + f" Spatial: {self.spat_subpixel}" + msgs.newline() + f" Slices: {self.slice_subpixel}") elif self.method == "ngp": msgs.info("Adopting the nearest grid point (NGP) algorithm to generate the datacube.") + self.skip_subpix_weights = True else: msgs.error(f"The following datacube method is not allowed: {self.method}") @@ -1180,6 +1183,7 @@ def load(self): spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, slice_subpixel=self.slice_subpixel, + skip_subpix_weights=self.skip_subpix_weights, correct_dar=self.correct_dar) # Prepare the header hdr = self.all_wcs[ff].to_header() @@ -1388,6 +1392,7 @@ def run(self): spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, slice_subpixel=self.slice_subpixel, + skip_subpix_weights=self.skip_subpix_weights, correct_dar=self.correct_dar) # Prepare the header hdr = cube_wcs.to_header() @@ -1414,6 +1419,7 @@ def run(self): outfile=outfile, spec_subpixel=self.spec_subpixel, spat_subpixel=self.spat_subpixel, slice_subpixel=self.slice_subpixel, + skip_subpix_weights=self.skip_subpix_weights, correct_dar=self.correct_dar) # Prepare the header hdr = cube_wcs.to_header() diff --git a/pypeit/core/datacube.py b/pypeit/core/datacube.py index 139e9fb508..2652cdbcc8 100644 --- a/pypeit/core/datacube.py +++ b/pypeit/core/datacube.py @@ -1266,7 +1266,7 @@ def compute_weights(raImg, decImg, waveImg, sciImg, ivarImg, slitidImg, _all_tilts[ff], _all_slits[ff], _all_align[ff], _all_dar[ff], _ra_offsets[ff], _dec_offsets[ff], spec_subpixel=1, spat_subpixel=1, slice_subpixel=1, - correct_dar=correct_dar) + skip_subpix_weights=True, correct_dar=correct_dar) # Store the flux and ivar spectra of the highest S/N object. # TODO :: This is the flux per spectral pixel, and not per detector pixel. Is this correct? flux_stack[:, ff] = flxcube[:, 0, 0] @@ -1387,13 +1387,13 @@ def generate_image_subpixel(image_wcs, bins, sciImg, ivarImg, waveImg, slitid_im img, _, _ = subpixellate(image_wcs, bins, _sciImg, _ivarImg, _waveImg, _slitid_img_gpm, _wghtImg, _all_wcs, _tilts, _slits, _astrom_trans, _all_dar, _ra_offset, _dec_offset, spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, - correct_dar=correct_dar) + skip_subpix_weights=True, correct_dar=correct_dar) else: # Subpixellate img, _, _ = subpixellate(image_wcs, bins, _sciImg[fr], _ivarImg[fr], _waveImg[fr], _slitid_img_gpm[fr], _wghtImg[fr], _all_wcs[fr], _tilts[fr], _slits[fr], _astrom_trans[fr], _all_dar[fr], _ra_offset[fr], _dec_offset[fr], spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, - correct_dar=correct_dar) + skip_subpix_weights=True, correct_dar=correct_dar) all_wl_imgs[:, :, fr] = img[:, :, 0] # Return the constructed white light images return all_wl_imgs @@ -1402,7 +1402,7 @@ def generate_image_subpixel(image_wcs, bins, sciImg, ivarImg, waveImg, slitid_im def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, - spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, + spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, skip_subpix_weights=False, overwrite=False, outfile=None, whitelight_range=None, correct_dar=True, debug=False): """ Save a datacube using the subpixel algorithm. Refer to the subpixellate() @@ -1468,6 +1468,14 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im values give more reliable results, but note that the time required goes as (``slice_subpixel``). The default value is 5, which divides each IFU slice into 5 subslices in the slice direction. + skip_subpix_weights (bool, optional): + If True, the computationally expensive step to calculate the + subpixellation weights will be skipped. If set the True, note that + the variance cubes returned will not be accurate. However, if you + are not interested in the variance cubes, this can save a lot of + time, and this is an example where you might consider setting this + variable to True. The flux datacube is unaffected by this variable. + The default is False. overwrite (bool, optional): If True, the output cube will be overwritten. outfile (str, optional): @@ -1511,7 +1519,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im subpix = subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, - correct_dar=correct_dar, debug=debug) + skip_subpix_weights=skip_subpix_weights, correct_dar=correct_dar, debug=debug) # Extract the variables that we need if debug: flxcube, varcube, bpmcube, residcube = subpix From 274f6a1e18aaa9ce1eedb9bca8416d9467a12811 Mon Sep 17 00:00:00 2001 From: rcooke Date: Fri, 23 Feb 2024 18:11:22 +0000 Subject: [PATCH 6/8] cleanup --- pypeit/core/datacube.py | 59 +++++++++++------------------------------ pypeit/slittrace.py | 12 ++++++--- 2 files changed, 25 insertions(+), 46 deletions(-) diff --git a/pypeit/core/datacube.py b/pypeit/core/datacube.py index 2652cdbcc8..57596b6bed 100644 --- a/pypeit/core/datacube.py +++ b/pypeit/core/datacube.py @@ -1403,7 +1403,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, skip_subpix_weights=False, - overwrite=False, outfile=None, whitelight_range=None, correct_dar=True, debug=False): + overwrite=False, outfile=None, whitelight_range=None, correct_dar=True): """ Save a datacube using the subpixel algorithm. Refer to the subpixellate() docstring for further details about this algorithm @@ -1491,10 +1491,6 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im correct_dar (bool, optional): If True, the DAR correction will be applied to the datacube. If the DAR correction is not available, the datacube will not be corrected. - debug (bool, optional): - If True, a residuals cube will be output. If the datacube generation - is correct, the distribution of pixels in the residual cube with no - flux should have mean=0 and std=1. Returns: :obj:`tuple`: Four `numpy.ndarray`_ objects containing @@ -1508,28 +1504,15 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im shape of the wavelength array is (nwave,). """ # Check the inputs - if whitelight_range is not None or debug: - if outfile is None: - msgs.error("Must provide an outfile name if either whitelight_range or debug are set") - - # Prepare the header, and add the unit of flux to the header - hdr = output_wcs.to_header() + if whitelight_range is not None and outfile is None: + msgs.error("Must provide an outfile name if whitelight_range is set") # Subpixellate - subpix = subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, - all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, - spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, slice_subpixel=slice_subpixel, - skip_subpix_weights=skip_subpix_weights, correct_dar=correct_dar, debug=debug) - # Extract the variables that we need - if debug: - flxcube, varcube, bpmcube, residcube = subpix - # Save a residuals cube - outfile_resid = outfile.replace(".fits", "_resid.fits") - msgs.info("Saving residuals datacube as: {0:s}".format(outfile_resid)) - hdu = fits.PrimaryHDU(residcube.T, header=hdr) - hdu.writeto(outfile_resid, overwrite=overwrite) - else: - flxcube, varcube, bpmcube = subpix + flxcube, varcube, bpmcube = subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, + all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, + spec_subpixel=spec_subpixel, spat_subpixel=spat_subpixel, + slice_subpixel=slice_subpixel, skip_subpix_weights=skip_subpix_weights, + correct_dar=correct_dar) # Get wavelength of each pixel nspec = flxcube.shape[2] @@ -1561,7 +1544,7 @@ def generate_cube_subpixel(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_im def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wghtImg, all_wcs, tilts, slits, astrom_trans, all_dar, ra_offset, dec_offset, spec_subpixel=5, spat_subpixel=5, slice_subpixel=5, skip_subpix_weights=False, - correct_dar=True, debug=False): + correct_dar=True): r""" Subpixellate the input data into a datacube. This algorithm splits each detector pixel into multiple subpixels and each IFU slice into multiple subslices. @@ -1649,10 +1632,6 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh correct_dar (bool, optional): If True, the DAR correction will be applied to the datacube. The default is True. - debug (bool, optional): - If True, a residuals cube will be output. If the datacube generation - is correct, the distribution of pixels in the residual cube with no - flux should have mean=0 and std=1. Returns: :obj:`tuple`: Three or four `numpy.ndarray`_ objects containing (1) the @@ -1667,11 +1646,8 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh # Prepare the output arrays outshape = (bins[0].size-1, bins[1].size-1, bins[2].size-1) - binrng = [[bins[0][0], bins[0][-1]], [bins[1][0], bins[1][-1]], [bins[2][0], bins[2][-1]]] - binrng_arr = np.array(binrng) + binrng = np.array([[bins[0][0], bins[0][-1]], [bins[1][0], bins[1][-1]], [bins[2][0], bins[2][-1]]]) flxcube, varcube, normcube = np.zeros(outshape), np.zeros(outshape), np.zeros(outshape) - if debug: - residcube = np.zeros(outshape) # Divide each pixel into subpixels spec_offs = np.arange(0.5/spec_subpixel, 1, 1/spec_subpixel) - 0.5 # -0.5 is to offset from the centre of each pixel. spat_offs = np.arange(0.5/spat_subpixel, 1, 1/spat_subpixel) - 0.5 # -0.5 is to offset from the centre of each pixel. @@ -1727,7 +1703,7 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh spatpos = _astrom_trans[fr].transform(sl, wpix[1], wpix[0]) ssrt = np.argsort(spatpos) # Initialize the voxel coordinates for each spec2D pixel - vox_coord = -1*np.ones((numpix, num_all_subpixels, 3)) + vox_coord = np.full((numpix, num_all_subpixels, 3), -1, dtype=float) # Loop over the subslices for ss in range(slice_subpixel): if slice_subpixel > 1: @@ -1758,8 +1734,8 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh subpix_wght = 1.0 else: msgs.info("Preparing subpixel weights") - vox_index = np.floor(outshape * (vox_coord - binrng_arr[:,0].reshape((1, 1, 3))) / - (binrng_arr[:,1] - binrng_arr[:,0]).reshape((1, 1, 3))).astype(int) + vox_index = np.floor(outshape * (vox_coord - binrng[:,0].reshape((1, 1, 3))) / + (binrng[:,1] - binrng[:,0]).reshape((1, 1, 3))).astype(int) # Convert to a unique index vox_index = np.dot(vox_index, np.array([1, outshape[0], outshape[0]*outshape[1]])) # Calculate the number of repeated indices for each subpixel - this is the subpixel weights @@ -1770,15 +1746,12 @@ def subpixellate(output_wcs, bins, sciImg, ivarImg, waveImg, slitid_img_gpm, wgh flxcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * this_wght_subpix[this_sl], num_all_subpixels) * subpix_wght) varcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_var[this_sl] * this_wght_subpix[this_sl]**2, num_all_subpixels) * subpix_wght**3) normcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_wght_subpix[this_sl], num_all_subpixels) * subpix_wght) - if debug: - # NOTE :: The residual cube does not include the subpixel weights - so, the following line is probably incorrect - residcube += histogramdd(vox_coord, bins=outshape, range=binrng, weights=np.repeat(this_sci[this_sl] * np.sqrt(utils.inverse(this_var[this_sl])), num_all_subpixels)) + # Normalise the datacube and variance cube nc_inverse = utils.inverse(normcube) flxcube *= nc_inverse varcube *= nc_inverse**2 bpmcube = (normcube == 0).astype(np.uint8) - if debug: - residcube *= nc_inverse - return flxcube, varcube, bpmcube, residcube + + # Return the datacube, variance cube and bad pixel cube return flxcube, varcube, bpmcube diff --git a/pypeit/slittrace.py b/pypeit/slittrace.py index 2e7d08d1ce..93b4b7df32 100644 --- a/pypeit/slittrace.py +++ b/pypeit/slittrace.py @@ -492,6 +492,11 @@ def get_radec_image(self, wcs, alignSplines, tilts, slit_compute=None, slice_off transform between detector pixel coordinates and WCS pixel coordinates. tilts : `numpy.ndarray`_ Spectral tilts. + slit_compute : int, list, `numpy.ndarray`_, optional + The slit indices to compute the RA and DEC image for. If None, all slits + are computed. If an integer, the RA and DEC image for the slit with this + index is computed. If a list or `numpy.ndarray`_, the RA and DEC image + for the slits with these indices are computed. slice_offset : float, optional Offset to apply to the slice positions. A value of 0.0 means that the slice positions are the centre of the slits. A value of +/-0.5 means that @@ -519,10 +524,11 @@ def get_radec_image(self, wcs, alignSplines, tilts, slit_compute=None, slice_off if slit_compute is None: # Compute all of the slits slit_compute = np.arange(self.nslits) - elif isinstance(slit_compute, int): + elif isinstance(slit_compute, (int, list)): slit_compute = np.atleast_1d(slit_compute) - elif isinstance(slit_compute, list): - slit_compute = np.array(slit_compute) + else: + msgs.error('Unrecognized type for slit_compute') + # Prepare the print out substring = '' if slice_offset is None else f' with slice_offset={slice_offset:.3f}' msgs.info("Generating an RA/DEC image"+substring) From 1b052433360f99ab57df8074d75d368ce09395a9 Mon Sep 17 00:00:00 2001 From: rcooke Date: Fri, 23 Feb 2024 20:12:06 +0000 Subject: [PATCH 7/8] build docs --- doc/api/pypeit.astrometry.rst | 8 +++ doc/api/pypeit.rst | 1 + doc/help/run_pypeit.rst | 2 +- doc/include/dev_suite_readme.rst | 15 +++++ doc/include/gemini_gnirs_echelle_A.pypeit.rst | 2 +- doc/include/keck_deimos.sorted.rst | 6 +- doc/include/keck_deimos_A.pypeit.rst | 2 +- doc/include/keck_nires_A.pypeit.rst | 2 +- doc/include/shane_kast_blue_A.pypeit.rst | 2 +- doc/pypeit_par.rst | 63 ++++++++++--------- 10 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 doc/api/pypeit.astrometry.rst diff --git a/doc/api/pypeit.astrometry.rst b/doc/api/pypeit.astrometry.rst new file mode 100644 index 0000000000..6a7ca8012f --- /dev/null +++ b/doc/api/pypeit.astrometry.rst @@ -0,0 +1,8 @@ +pypeit.astrometry module +======================== + +.. automodule:: pypeit.astrometry + :members: + :private-members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/pypeit.rst b/doc/api/pypeit.rst index fdc128b60e..1acdde8c40 100644 --- a/doc/api/pypeit.rst +++ b/doc/api/pypeit.rst @@ -27,6 +27,7 @@ Submodules pypeit.alignframe pypeit.archive + pypeit.astrometry pypeit.bitmask pypeit.calibframe pypeit.calibrations diff --git a/doc/help/run_pypeit.rst b/doc/help/run_pypeit.rst index 43055026a6..be6166e46d 100644 --- a/doc/help/run_pypeit.rst +++ b/doc/help/run_pypeit.rst @@ -4,7 +4,7 @@ usage: run_pypeit [-h] [-v VERBOSITY] [-r REDUX_PATH] [-m] [-s] [-o] [-c] pypeit_file - ## PypeIt : The Python Spectroscopic Data Reduction Pipeline v1.14.1.dev729+g948bfc229.d20240202 + ## PypeIt : The Python Spectroscopic Data Reduction Pipeline v1.15.1.dev38+g075fdecaa.d20240212 ## ## Available spectrographs include: ## bok_bc, gemini_flamingos1, gemini_flamingos2, gemini_gmos_north_e2v, diff --git a/doc/include/dev_suite_readme.rst b/doc/include/dev_suite_readme.rst index f996477749..676dc66976 100644 --- a/doc/include/dev_suite_readme.rst +++ b/doc/include/dev_suite_readme.rst @@ -419,6 +419,21 @@ To monitor a test in Nautilus as it is running, the logs can be tailed: Additionally they can be monitored with the `Nautilus Grafana page `__. +By default ``gen_kube_devsuite`` creates a job using a default container with PypeIt +pre-installed. It also supports running with different python versions by +selecting a different container. For example: + +.. code-block:: console + + $ ./gen_kube_devsuite devsuite-python3.11-job devsuite-python3.11-job.yml --container python3.11 + +Any of the standard python images in docker hub can be used. To use a different container the full +download path must be given. For example: + +.. code-block:: console + + $ ./gen_kube_devsuite devsuite-ubuntu-job devsuite-ubuntu-job.yml --container docker.io/library/ubuntu:22.04 + Additional Options ------------------ diff --git a/doc/include/gemini_gnirs_echelle_A.pypeit.rst b/doc/include/gemini_gnirs_echelle_A.pypeit.rst index 71e0008845..f5c7e91de8 100644 --- a/doc/include/gemini_gnirs_echelle_A.pypeit.rst +++ b/doc/include/gemini_gnirs_echelle_A.pypeit.rst @@ -17,7 +17,7 @@ # Data block data read - path /Users/westfall/Work/packages/PypeIt-development-suite/RAW_DATA/gemini_gnirs_echelle/32_SB_SXD + path /Users/rcooke/Software/PypeIt-development-suite/RAW_DATA/gemini_gnirs_echelle/32_SB_SXD filename | frametype | ra | dec | target | dispname | decker | binning | mjd | airmass | exptime | dispangle | dithoff | calib | comb_id | bkg_id cN20170331S0216.fits | arc,science,tilt | 205.53380833 | 9.47733611 | pisco | 32/mmSB_G5533 | 0.68arcsec_G5530 | 1,1 | 57843.3709743134 | 1.077 | 300.0 | 6.1887 | -0.34225501721318 | 0 | 5 | -1 cN20170331S0217.fits | arc,science,tilt | 205.53380833 | 9.47733611 | pisco | 32/mmSB_G5533 | 0.68arcsec_G5530 | 1,1 | 57843.3746886267 | 1.068 | 300.0 | 6.1887 | 2.65774498278682 | 0 | 6 | -1 diff --git a/doc/include/keck_deimos.sorted.rst b/doc/include/keck_deimos.sorted.rst index 82f3eaa4b4..655eedb3a6 100644 --- a/doc/include/keck_deimos.sorted.rst +++ b/doc/include/keck_deimos.sorted.rst @@ -10,14 +10,14 @@ filter1: OG550 #--------------------------------------------------------- filename | frametype | ra | dec | target | dispname | decker | binning | mjd | airmass | exptime | dispangle | amp | filter1 | lampstat01 | dateobs | utc | frameno | calib - d0527_0030.fits.gz | arc,tilt | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.077631 | 1.41291034 | 1.0 | 8099.98291016 | SINGLE:B | OG550 | Kr Xe Ar Ne | 2017-05-27 | 01:51:53.87 | 30 | 0 DE.20170527.06713.fits | arc,tilt | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.077631 | 1.41291034 | 1.0 | 8099.98291016 | SINGLE:B | OG550 | Kr Xe Ar Ne | 2017-05-27 | 01:51:53.87 | 30 | 0 - DE.20170527.06790.fits | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.07851 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:53:10.93 | 31 | 0 + d0527_0030.fits.gz | arc,tilt | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.077631 | 1.41291034 | 1.0 | 8099.98291016 | SINGLE:B | OG550 | Kr Xe Ar Ne | 2017-05-27 | 01:51:53.87 | 30 | 0 d0527_0031.fits.gz | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.07851 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:53:10.93 | 31 | 0 + DE.20170527.06790.fits | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.07851 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:53:10.93 | 31 | 0 d0527_0032.fits.gz | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.079356 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:54:24.03 | 32 | 0 DE.20170527.06864.fits | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.079356 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:54:24.03 | 32 | 0 - d0527_0033.fits.gz | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.080211 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:55:36.93 | 33 | 0 DE.20170527.06936.fits | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.080211 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:55:36.93 | 33 | 0 + d0527_0033.fits.gz | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | DOME PHLAT | 830G | LongMirr | 1,1 | 57900.080211 | 1.41291034 | 4.0 | 8099.98291016 | SINGLE:B | OG550 | Qz | 2017-05-27 | 01:55:36.93 | 33 | 0 DE.20170527.37601.fits | science | 261.0363749999999 | 19.028166666666667 | P261_OFF | 830G | LongMirr | 1,1 | 57900.435131 | 1.03078874 | 1200.0 | 8099.98291016 | SINGLE:B | OG550 | Off | 2017-05-27 | 10:26:41.61 | 80 | 0 DE.20170527.38872.fits | science | 261.0363749999999 | 19.028166666666667 | P261_OFF | 830G | LongMirr | 1,1 | 57900.449842 | 1.01267696 | 1200.0 | 8099.98291016 | SINGLE:B | OG550 | Off | 2017-05-27 | 10:47:52.92 | 81 | 0 d0527_0081.fits.gz | science | 261.0363749999999 | 19.028166666666667 | P261_OFF | 830G | LongMirr | 1,1 | 57900.449842 | 1.01267696 | 1200.0 | 8099.98291016 | SINGLE:B | OG550 | Off | 2017-05-27 | 10:47:52.92 | 81 | 0 diff --git a/doc/include/keck_deimos_A.pypeit.rst b/doc/include/keck_deimos_A.pypeit.rst index d5331442ad..857ca58813 100644 --- a/doc/include/keck_deimos_A.pypeit.rst +++ b/doc/include/keck_deimos_A.pypeit.rst @@ -20,7 +20,7 @@ # Data block data read - path /Users/westfall/Work/packages/PypeIt-development-suite/RAW_DATA/keck_deimos/1200G_M_7750 + path /Users/rcooke/Software/PypeIt-development-suite/RAW_DATA/keck_deimos/1200G_M_7750 filename | frametype | ra | dec | target | dispname | decker | binning | mjd | airmass | exptime | dispangle | amp | filter1 | lampstat01 | dateobs | utc | frameno | calib DE.20170425.09554.fits.gz | arc,tilt | 57.99999999999999 | 45.0 | unknown | 1200G | dra11 | 1,1 | 57868.110529 | 1.41291034 | 1.0 | 7699.95654297 | SINGLE:B | OG550 | Kr Xe Ar Ne | 2017-04-25 | 02:39:14.41 | 49 | 0 DE.20170425.09632.fits.gz | pixelflat,illumflat,trace | 57.99999999999999 | 45.0 | unknown | 1200G | dra11 | 1,1 | 57868.111418 | 1.41291034 | 12.0 | 7699.95654297 | SINGLE:B | OG550 | Qz | 2017-04-25 | 02:40:32.06 | 50 | 0 diff --git a/doc/include/keck_nires_A.pypeit.rst b/doc/include/keck_nires_A.pypeit.rst index e01401f356..ce37ea88ee 100644 --- a/doc/include/keck_nires_A.pypeit.rst +++ b/doc/include/keck_nires_A.pypeit.rst @@ -15,7 +15,7 @@ # Data block data read - path /Users/westfall/Work/packages/PypeIt-development-suite/RAW_DATA/keck_nires/ABBA_wstandard + path /Users/rcooke/Software/PypeIt-development-suite/RAW_DATA/keck_nires/ABBA_wstandard filename | frametype | ra | dec | target | dispname | decker | binning | mjd | airmass | exptime | dithpat | dithpos | dithoff | frameno | calib | comb_id | bkg_id s190519_0059.fits | arc,science,tilt | 194.259151362434 | 22.0313494322493 | GD153 | spec | 0.55 slit | 1,1 | 58622.3598610573 | 1.03675819208546 | 200.0 | ABBA | A | 2.0 | 59 | 0 | 1 | 2 s190519_0060.fits | arc,science,tilt | 194.260349844733 | 22.0313316699865 | GD153 | spec | 0.55 slit | 1,1 | 58622.362605849 | 1.04142552296712 | 200.0 | ABBA | B | -2.0 | 60 | 0 | 2 | 1 diff --git a/doc/include/shane_kast_blue_A.pypeit.rst b/doc/include/shane_kast_blue_A.pypeit.rst index b206d00094..32369ffd39 100644 --- a/doc/include/shane_kast_blue_A.pypeit.rst +++ b/doc/include/shane_kast_blue_A.pypeit.rst @@ -16,7 +16,7 @@ # Data block data read - path /Users/westfall/Work/packages/PypeIt-development-suite/RAW_DATA/shane_kast_blue/600_4310_d55 + path /Users/rcooke/Software/PypeIt-development-suite/RAW_DATA/shane_kast_blue/600_4310_d55 filename | frametype | ra | dec | target | dispname | decker | binning | mjd | airmass | exptime | dichroic | calib b1.fits.gz | arc,tilt | 140.44166666666663 | 37.43222222222222 | Arcs | 600/4310 | 0.5 arcsec | 1,1 | 57162.06664467593 | 1.0 | 30.0 | d55 | 0 b14.fits.gz | bias | 172.34291666666664 | 36.86833333333333 | Bias | 600/4310 | 2.0 arcsec | 1,1 | 57162.15420034722 | 1.0 | 0.0 | d55 | 0 diff --git a/doc/pypeit_par.rst b/doc/pypeit_par.rst index ce1532dd1d..1d091bb265 100644 --- a/doc/pypeit_par.rst +++ b/doc/pypeit_par.rst @@ -576,21 +576,21 @@ Collate1DPar Keywords Class Instantiation: :class:`~pypeit.par.pypeitpar.Collate1DPar` -========================= ========== ======= ============================================ ================================================================================================================================================================================================================================================================================================================================================================================================================== -Key Type Options Default Description -========================= ========== ======= ============================================ ================================================================================================================================================================================================================================================================================================================================================================================================================== -``dry_run`` bool .. False If set, the script will display the matching File and Object Ids but will not flux, coadd or archive. -``exclude_serendip`` bool .. False Whether to exclude SERENDIP objects from collating. -``exclude_slit_trace_bm`` list, str .. [] A list of slit trace bitmask bits that should be excluded. -``flux`` bool .. False If set, the script will flux calibrate using archived sensfuncs before coadding. -``ignore_flux`` bool .. False If set, the script will only coadd non-fluxed spectra even if flux data is present. Otherwise fluxed spectra are coadded if all spec1ds have been fluxed calibrated. -``match_using`` str .. ``ra/dec`` Determines how 1D spectra are matched as being the same object. Must be either 'pixel' or 'ra/dec'. -``outdir`` str .. ``/Users/westfall/Work/packages/pypeit/doc`` The path where all coadded output files and report files will be placed. -``refframe`` str .. .. Perform reference frame correction prior to coadding. Options are: observed, heliocentric, barycentric -``spec1d_outdir`` str .. .. The path where all modified spec1d files are placed. These are only created if flux calibration or refframe correction are asked for. -``tolerance`` str, float .. ``1.0`` The tolerance used when comparing the coordinates of objects. If two objects are within this distance from each other, they are considered the same object. If match_using is 'ra/dec' (the default) this is an angular distance. The defaults units are arcseconds but other units supported by astropy.coordinates.Angle can be used (`e.g.`, '0.003d' or '0h1m30s'). If match_using is 'pixel' this is a float. -``wv_rms_thresh`` float .. .. If set, any objects with a wavelength RMS > this value are skipped, else all wavelength RMS values are accepted. -========================= ========== ======= ============================================ ================================================================================================================================================================================================================================================================================================================================================================================================================== +========================= ========== ======= ===================================== ================================================================================================================================================================================================================================================================================================================================================================================================================== +Key Type Options Default Description +========================= ========== ======= ===================================== ================================================================================================================================================================================================================================================================================================================================================================================================================== +``dry_run`` bool .. False If set, the script will display the matching File and Object Ids but will not flux, coadd or archive. +``exclude_serendip`` bool .. False Whether to exclude SERENDIP objects from collating. +``exclude_slit_trace_bm`` list, str .. [] A list of slit trace bitmask bits that should be excluded. +``flux`` bool .. False If set, the script will flux calibrate using archived sensfuncs before coadding. +``ignore_flux`` bool .. False If set, the script will only coadd non-fluxed spectra even if flux data is present. Otherwise fluxed spectra are coadded if all spec1ds have been fluxed calibrated. +``match_using`` str .. ``ra/dec`` Determines how 1D spectra are matched as being the same object. Must be either 'pixel' or 'ra/dec'. +``outdir`` str .. ``/Users/rcooke/Software/PypeIt/doc`` The path where all coadded output files and report files will be placed. +``refframe`` str .. .. Perform reference frame correction prior to coadding. Options are: observed, heliocentric, barycentric +``spec1d_outdir`` str .. .. The path where all modified spec1d files are placed. These are only created if flux calibration or refframe correction are asked for. +``tolerance`` str, float .. ``1.0`` The tolerance used when comparing the coordinates of objects. If two objects are within this distance from each other, they are considered the same object. If match_using is 'ra/dec' (the default) this is an angular distance. The defaults units are arcseconds but other units supported by astropy.coordinates.Angle can be used (`e.g.`, '0.003d' or '0h1m30s'). If match_using is 'pixel' this is a float. +``wv_rms_thresh`` float .. .. If set, any objects with a wavelength RMS > this value are skipped, else all wavelength RMS values are accepted. +========================= ========== ======= ===================================== ================================================================================================================================================================================================================================================================================================================================================================================================================== ---- @@ -643,22 +643,22 @@ ReduxPar Keywords Class Instantiation: :class:`~pypeit.par.pypeitpar.ReduxPar` -====================== ============== ======= ============================================ ========================================================================================================================================================================================================================================================================================================================================================================================================== -Key Type Options Default Description -====================== ============== ======= ============================================ ========================================================================================================================================================================================================================================================================================================================================================================================================== -``calwin`` int, float .. 0 The window of time in hours to search for calibration frames for a science frame -``chk_version`` bool .. True If True enforce strict PypeIt version checking to ensure that all files were created with the current version of PypeIt. If set to False, the code will attempt to read out-of-date files and keep going. Beware (!!) that this can lead to unforeseen bugs that either cause the code to crash or lead to erroneous results. I.e., you really need to know what you are doing if you set this to False! -``detnum`` int, list .. .. Restrict reduction to a list of detector indices. In case of mosaic reduction (currently only available for Gemini/GMOS and Keck/DEIMOS) ``detnum`` should be a list of tuples of the detector indices that are mosaiced together. E.g., for Gemini/GMOS ``detnum`` would be ``[(1,2,3)]`` and for Keck/DEIMOS it would be ``[(1, 5), (2, 6), (3, 7), (4, 8)]`` -``ignore_bad_headers`` bool .. False Ignore bad headers (NOT recommended unless you know it is safe). -``maskIDs`` str, int, list .. .. Restrict reduction to a set of slitmask IDs Example syntax -- ``maskIDs = 818006,818015`` This must be used with detnum (for now). -``qadir`` str .. ``QA`` Directory relative to calling directory to write quality assessment files. -``quicklook`` bool .. False Run a quick look reduction? This is usually good if you want to quickly reduce the data (usually at the telescope in real time) to get an initial estimate of the data quality. -``redux_path`` str .. ``/Users/westfall/Work/packages/pypeit/doc`` Path to folder for performing reductions. Default is the current working directory. -``scidir`` str .. ``Science`` Directory relative to calling directory to write science files. -``slitspatnum`` str, list .. .. Restrict reduction to a set of slit DET:SPAT values (closest slit is used). Example syntax -- slitspatnum = DET01:175,DET01:205 or MSC02:2234 If you are re-running the code, (i.e. modifying one slit) you *must* have the precise SPAT_ID index. -``sortroot`` str .. .. A filename given to output the details of the sorted files. If None, the default is the root name of the pypeit file. If off, no output is produced. -``spectrograph`` str .. .. Spectrograph that provided the data to be reduced. See :ref:`instruments` for valid options. -====================== ============== ======= ============================================ ========================================================================================================================================================================================================================================================================================================================================================================================================== +====================== ============== ======= ===================================== ========================================================================================================================================================================================================================================================================================================================================================================================================== +Key Type Options Default Description +====================== ============== ======= ===================================== ========================================================================================================================================================================================================================================================================================================================================================================================================== +``calwin`` int, float .. 0 The window of time in hours to search for calibration frames for a science frame +``chk_version`` bool .. True If True enforce strict PypeIt version checking to ensure that all files were created with the current version of PypeIt. If set to False, the code will attempt to read out-of-date files and keep going. Beware (!!) that this can lead to unforeseen bugs that either cause the code to crash or lead to erroneous results. I.e., you really need to know what you are doing if you set this to False! +``detnum`` int, list .. .. Restrict reduction to a list of detector indices. In case of mosaic reduction (currently only available for Gemini/GMOS and Keck/DEIMOS) ``detnum`` should be a list of tuples of the detector indices that are mosaiced together. E.g., for Gemini/GMOS ``detnum`` would be ``[(1,2,3)]`` and for Keck/DEIMOS it would be ``[(1, 5), (2, 6), (3, 7), (4, 8)]`` +``ignore_bad_headers`` bool .. False Ignore bad headers (NOT recommended unless you know it is safe). +``maskIDs`` str, int, list .. .. Restrict reduction to a set of slitmask IDs Example syntax -- ``maskIDs = 818006,818015`` This must be used with detnum (for now). +``qadir`` str .. ``QA`` Directory relative to calling directory to write quality assessment files. +``quicklook`` bool .. False Run a quick look reduction? This is usually good if you want to quickly reduce the data (usually at the telescope in real time) to get an initial estimate of the data quality. +``redux_path`` str .. ``/Users/rcooke/Software/PypeIt/doc`` Path to folder for performing reductions. Default is the current working directory. +``scidir`` str .. ``Science`` Directory relative to calling directory to write science files. +``slitspatnum`` str, list .. .. Restrict reduction to a set of slit DET:SPAT values (closest slit is used). Example syntax -- slitspatnum = DET01:175,DET01:205 or MSC02:2234 If you are re-running the code, (i.e. modifying one slit) you *must* have the precise SPAT_ID index. +``sortroot`` str .. .. A filename given to output the details of the sorted files. If None, the default is the root name of the pypeit file. If off, no output is produced. +``spectrograph`` str .. .. Spectrograph that provided the data to be reduced. See :ref:`instruments` for valid options. +====================== ============== ======= ===================================== ========================================================================================================================================================================================================================================================================================================================================================================================================== ---- @@ -697,6 +697,7 @@ Key Type Options ``align`` bool .. False If set to True, the input frames will be spatially aligned by cross-correlating the whitelight images with either a reference image (see ``reference_image``) or the whitelight image that is generated using the first spec2d listed in the coadd3d file. Alternatively, the user can specify the offsets (i.e. Delta RA x cos(dec) and Delta Dec, both in arcsec) in the spec2d block of the coadd3d file. See the documentation for examples of this usage. ``astrometric`` bool .. True If true, an astrometric correction will be applied using the alignment frames. ``combine`` bool .. False If set to True, the input frames will be combined. Otherwise, a separate datacube will be generated for each input spec2d file, and will be saved as a spec3d file. +``correct_dar`` bool .. True If True, the data will be corrected for differential atmospheric refraction (DAR). ``dec_max`` float .. .. Maximum DEC to use when generating the WCS. If None, the default is maximum DEC based on the WCS of all spaxels. Units should be degrees. ``dec_min`` float .. .. Minimum DEC to use when generating the WCS. If None, the default is minimum DEC based on the WCS of all spaxels. Units should be degrees. ``grating_corr`` bool .. True This option performs a small correction for the relative blaze function of all input frames that have (even slightly) different grating angles, or if you are flux calibrating your science data with a standard star that was observed with a slightly different setup. From 27ebb93bbf3635da503a82a56e839cedaf360cae Mon Sep 17 00:00:00 2001 From: rcooke Date: Fri, 23 Feb 2024 20:18:28 +0000 Subject: [PATCH 8/8] new release docs --- doc/releases/1.15.1dev.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/releases/1.15.1dev.rst diff --git a/doc/releases/1.15.1dev.rst b/doc/releases/1.15.1dev.rst new file mode 100644 index 0000000000..6adada653b --- /dev/null +++ b/doc/releases/1.15.1dev.rst @@ -0,0 +1,32 @@ + +Version 1.15.1dev +================= + +Installation Changes +-------------------- + +Dependency Changes +------------------ + +Functionality/Performance Improvements and Additions +---------------------------------------------------- + +Instrument-specific Updates +--------------------------- + +Script Changes +-------------- + +Datamodel Changes +----------------- + +Under-the-hood Improvements +--------------------------- + +Bug Fixes +--------- + +- The subpixel algorithm used to resample datacubes that are generated by `pypeit_coadd_datacube` + produced error cubes that were not properly propagating the noise. The error cubes of the NGP + algorithm were unaffected. The error cubes are now regularly inspected with vet tests to ensure + the error cubes are reliable.