def splice(self, wave): """ Routine to splice together sensitivity functions into one global sensitivity function for spectrographs with multiple detectors extending across the wavelength direction. Parameters ---------- wave: ndarray, shape (nspec, norddet) Returns ------- wave_splice: ndarray, shape (nspec_splice,) sensfunc_splice: ndarray, shape (nspec_splice,) """ msgs.info('Merging sensfunc for {:d} detectors {:}'.format( self.norderdet, self.par['multi_spec_det'])) wave_splice_min = wave.min() wave_splice_max = wave.max() wave_splice, _, _ = coadd.get_wave_grid(wave, wave_method='linear', wave_grid_min=wave_splice_min, wave_grid_max=wave_splice_max, samp_fact=1.0) sensfunc_splice = np.zeros_like(wave_splice) for idet in range(self.norderdet): wave_min = self.out_table['WAVE_MIN'][idet] wave_max = self.out_table['WAVE_MAX'][idet] if idet == 0: # If this is the bluest detector, extrapolate to wave_extrap_min wave_mask_min = wave_splice_min wave_mask_max = wave_max elif idet == (self.norderdet - 1): # If this is the reddest detector, extrapolate to wave_extrap_max wave_mask_min = wave_min wave_mask_max = wave_splice_max else: wave_mask_min = wave_min wave_mask_max = wave_max splice_wave_mask = (wave_splice >= wave_mask_min) & (wave_splice <= wave_mask_max) sensfunc_splice[splice_wave_mask] = self.eval_sensfunc( wave_splice[splice_wave_mask], idet) # Interpolate over gaps zeros = sensfunc_splice == 0. if np.any(zeros): msgs.info( "Interpolating over gaps (and extrapolating with fill_value=1, if need be)" ) interp_func = scipy.interpolate.interp1d( wave_splice[np.invert(zeros)], sensfunc_splice[np.invert(zeros)], kind='nearest', fill_value=0., bounds_error=False) # #kind='nearest', fill_value='extrapoloate', bounds_error=False) # extrapolate fails for JXP, even on 1.4.1 zero_values = interp_func(wave_splice[zeros]) sensfunc_splice[zeros] = zero_values self.steps.append(inspect.stack()[0][3]) return wave_splice, sensfunc_splice
def get_wave_grid(self, **kwargs_wave): """ Routine to create a wavelength grid for 2d coadds using all of the wavelengths of the extracted objects. Calls coadd1d.get_wave_grid. Args: **kwargs_wave (dict): Optional argumments for coadd1d.get_wve_grid function Returns: tuple: Returns the following: - wave_grid (np.ndarray): New wavelength grid, not masked - wave_grid_mid (np.ndarray): New wavelength grid evaluated at the centers of the wavelength bins, that is this grid is simply offset from wave_grid by dsamp/2.0, in either linear space or log10 depending on whether linear or (log10 or velocity) was requested. For iref or concatenate the linear wavelength sampling will be calculated. - dsamp (float): The pixel sampling for wavelength grid created. """ nobjs_tot = int(np.array([len(spec) for spec in self.stack_dict['specobjs_list']]).sum()) # TODO: Do we need this flag since we can determine whether or not we have specobjs from nobjs_tot? # This all seems a bit hacky if self.par['coadd2d']['use_slits4wvgrid'] or nobjs_tot==0: nslits_tot = np.sum([slits.nslits for slits in self.stack_dict['slits_list']]) waves = np.zeros((self.nspec, nslits_tot*3)) gpm = np.zeros_like(waves, dtype=bool) box_radius = 3. indx = 0 # Loop on the exposures for waveimg, slitmask, slits in zip(self.stack_dict['waveimg_stack'], self.stack_dict['slitmask_stack'], self.stack_dict['slits_list']): slits_left, slits_righ, _ = slits.select_edges() row = np.arange(slits_left.shape[0]) # Loop on the slits for kk, spat_id in enumerate(slits.spat_id): mask = slitmask == spat_id # Create apertures at 5%, 50%, and 95% of the slit width to cover full range of wavelengths # on this slit trace_spat = slits_left[:, kk][:,np.newaxis] + np.outer((slits_righ[:,kk] - slits_left[:,kk]),[0.05,0.5,0.95]) box_denom = moment1d(waveimg * mask > 0.0, trace_spat, 2 * box_radius, row=row)[0] wave_box = moment1d(waveimg * mask, trace_spat, 2 * box_radius, row=row)[0] / (box_denom + (box_denom == 0.0)) waves[:, indx:indx+3] = wave_box # TODO -- This looks a bit risky gpm[:, indx: indx+3] = wave_box > 0. indx += 3 else: waves = np.zeros((self.nspec, nobjs_tot)) gpm = np.zeros_like(waves, dtype=bool) indx = 0 for spec_this in self.stack_dict['specobjs_list']: for spec in spec_this: waves[:, indx] = spec.OPT_WAVE # TODO -- OPT_MASK is likely to become a bpm with int values gpm[:, indx] = spec.OPT_MASK indx += 1 wave_grid, wave_grid_mid, dsamp = coadd.get_wave_grid(waves, masks=gpm, **kwargs_wave) return wave_grid, wave_grid_mid, dsamp