def oned_circle_kernel(x: ndarray, center: float, fwhm: float): """Calculate the convolution kernel for a circular fiber. Parameters ---------- x: array Value to evaluate kernel at. center: float Center of kernel. fwhm: float FWHM of desired kernel. Returns ------- Collapsed circle kernel Notes: Tries to represent the broadening by the fiber of a fiber feed spectrograph. Artigau 2018 - stated mathematically equivalent to a cosine between -pi/2 and pi/2. This is what has tried to be created. """ fwhm_scale = 2.0943951 # Numerically derived A = 1 # Amplitude B = fwhm_scale / fwhm # Scale to give specific fwhm result = A * np.cos(B * (x - center)) # Limit to main cos lobe only upper_xi = center + np.pi / 2 / B lower_xi = center - np.pi / 2 / B mask = mask_between(x, lower_xi, upper_xi) result[~mask] = 0 return result
def test_mask_between(x, x1, x2): """Correctly masks out values.""" x = np.array(x) xmin = min(x1, x2) xmax = max(x1, x2) mask = mask_between(x, xmin, xmax) assert np.all(x[mask] >= xmin) assert np.all(x[mask] < xmax) # Dropped values are all outside range. assert np.all((x[~mask] >= xmax) | (x[~mask] < xmin))
def element_rot_convolution(single_wav: float) -> float: """Embarrassingly parallel part of rotational convolution. Calculates the convolution value for a single pixel. The parameters extended_wav, extended_flux, vsini, epsilon and normalize are obtained from the outer scope. Parameters ---------- single_wav: float Wavelength value to calculate convolution at. Returns ------- sum_val: float Sum of flux convolved for this pixel/wavelength. """ # Select all values such that they are within the fwhm limits delta_lambda_l = single_wav * vsini / c_kmps index_mask = mask_between(extended_wav, single_wav - delta_lambda_l, single_wav + delta_lambda_l) flux_2convolve = extended_flux[index_mask] rotation_profile = rotation_kernel( extended_wav[index_mask] - single_wav, delta_lambda_l, vsini=vsini, epsilon=epsilon, ) sum_val = np.sum(rotation_profile * flux_2convolve) if normalize: # Correct for the effect of non-equidistant sampling unitary_rot_val = np.sum(rotation_profile) # Affects precision return sum_val / unitary_rot_val else: return sum_val
def element_res_convolution(single_wav: float) -> float: """Embarrassingly parallel component of resolution convolution. Calculates the convolution value for a single pixel. The parameters extended_wav, fwhm_lim, R and normalize are obtained from the outer scope. Parameters ---------- single_wav: float Wavelength value to calculate convolution at. Returns ------- sum_val: float Sum of flux convolved for this pixel/wavelength """ fwhm = single_wav / R # Mask of wavelength range within fwhm_lim* fwhm of wav fwhm_space = fwhm_lim * fwhm index_mask = mask_between(extended_wav, single_wav - fwhm_space, single_wav + fwhm_space) flux_2convolve = extended_flux[index_mask] # Gaussian Instrument Profile for given resolution and wavelength instrument_profile = unitary_gaussian(extended_wav[index_mask], single_wav, fwhm=fwhm) sum_val = np.sum(instrument_profile * flux_2convolve) if normalize: # Correct for the effect of convolution with non-equidistant positions unitary_val = np.sum(instrument_profile) # Affects precision return sum_val / unitary_val else: return sum_val