def _slice0(cube, axis, scale): """ 0th moment along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float Returns ------- moment0_error : array """ shp = _moment_shp(cube, axis) result = np.zeros(shp) view = [slice(None)] * 3 valid = np.zeros(shp, dtype=np.bool) for i in range(cube.shape[axis]): view[axis] = i plane = cube._mask.include(data=cube._data, wcs=cube._wcs, view=view) valid |= plane result += plane result = scale * np.sqrt(result) result[~valid] = np.nan return result
def _slice1(cube, axis, scale, moment0, moment1): """ 1st moment along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float moment0 : 0th moment moment1 : 1st moment Returns ------- moment1_error : array """ shp = _moment_shp(cube, axis) result = np.zeros(shp) view = [slice(None)] * 3 pix_cen = cube._pix_cen()[axis] for i in range(cube.shape[axis]): view[axis] = i result += np.power((pix_cen[view] - moment1), 2) return (scale / moment0) * np.sqrt(result)
def moment_raywise(cube, order, axis): """ Compute moments by accumulating the answer one ray at a time """ shp = _moment_shp(cube, axis) out = np.zeros(shp) * np.nan pix_cen = cube._pix_cen()[axis] pix_size = cube._pix_size()[axis] for x, y, slc in cube._iter_rays(axis): # the intensity, i.e. the weights include = cube._mask.include(data=cube._data, wcs=cube._wcs, view=slc) if not include.any(): continue data = cube.flattened(slc).value * pix_size[slc][include] if order == 0: out[x, y] = data.sum() continue order1 = (data * pix_cen[slc][include]).sum() / data.sum() if order == 1: out[x, y] = order1 continue ordern = (data * (pix_cen[slc][include] - order1) ** order).sum() ordern /= data.sum() out[x, y] = ordern return out
def _slice1(cube, axis, scale, moment0, moment1): """ 1st moment along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float or SpectralCube moment0 : 0th moment moment1 : 1st moment Returns ------- moment1_error : array """ if isinstance(scale, SpectralCube): # scale should then have the same shape as the cube. if cube.shape != scale.shape: raise IndexError("When scale is a SpectralCube, it must have the" " same shape as the cube.") _scale_cube = True else: _scale_cube = False # I don't think there is a way to do this with one pass. # The first 2 moments always have to be pre-computed. # Divide moment0 by the pixel size in the given axis so it represents the # sum. spec_unit = cube.spectral_axis.unit axis_sum = u.Quantity(moment0 / (cube._pix_size_slice(axis) * spec_unit)) shp = _moment_shp(cube, axis) result = np.zeros(shp) * spec_unit ** 2 view = [slice(None)] * 3 pix_cen = u.Quantity(cube._pix_cen()[axis] * spec_unit) # term2 does not depend on the plane. term2 = moment1 / axis_sum for i in range(cube.shape[axis]): view[axis] = i term1 = pix_cen[view] / axis_sum if _scale_cube: noise_plane = \ np.nan_to_num(scale.filled_data[view]) else: noise_plane = scale result += np.power((term1 - term2) * noise_plane, 2) return np.sqrt(result)
def _slice0(cube, axis, scale): """ 0th moment along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float Returns ------- moment0_error : array """ if isinstance(scale, SpectralCube): # scale should then have the same shape as the cube. if cube.shape != scale.shape: raise IndexError("When scale is a SpectralCube, it must have the" " same shape as the cube.") _scale_cube = True else: _scale_cube = False shp = _moment_shp(cube, axis) result = np.zeros(shp) * cube.unit ** 2 view = [slice(None)] * 3 valid = np.zeros(shp, dtype=np.bool) for i in range(cube.shape[axis]): view[axis] = i plane = cube._mask.include(data=cube._data, wcs=cube._wcs, view=view) valid |= plane if _scale_cube: noise_plane = np.nan_to_num(scale.filled_data[view]) else: noise_plane = scale result += plane * np.power(noise_plane, 2) out_result = np.sqrt(result) * cube._pix_size_slice(axis) out_result[~valid] = np.nan return out_result
def _cube1(cube, axis, scale, moment0, moment1): ''' Moment 1 error computed cube-wise. ''' if isinstance(scale, SpectralCube): # scale should then have the same shape as the cube. if cube.shape != scale.shape: raise IndexError("When scale is a SpectralCube, it must have the" " same shape as the cube.") noise_plane = scale.filled_data[:] else: noise_plane = scale # I don't think there is a way to do this with one pass. # The first 2 moments always have to be pre-computed. # Divide moment0 by the pixel size in the given axis so it represents the # sum. spec_unit = cube.spectral_axis.unit axis_sum = u.Quantity(moment0 / (cube._pix_size_slice(axis) * spec_unit)) shp = _moment_shp(cube, axis) result = np.zeros(shp) * spec_unit pix_cen = cube._pix_cen()[axis] * spec_unit term1 = pix_cen / axis_sum term2 = moment1 / axis_sum result = np.sqrt(np.sum(np.power((term1 - term2) * np.nan_to_num(noise_plane), 2), axis=axis)) good_pix = np.isfinite(moment0) + np.isfinite(moment1) result[~good_pix] = np.NaN return result
def _slice2(cube, axis, scale, moment0, moment1, moment2, moment1_err): """ 2nd moment error along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float moment0 : 0th moment moment1 : 1st moment moment2 : 2nd moment moment1_err : 1st moment error Returns ------- moment1_error : array """ shp = _moment_shp(cube, axis) term1 = np.zeros(shp) term2 = np.zeros(shp) view = [slice(None)] * 3 pix_cen = cube._pix_cen()[axis] pix_size = cube._pix_size()[axis] for i in range(cube.shape[axis]): view[axis] = i plane = cube._get_filled_data(fill=0, view=view) term1 += scale**2 * \ np.power((np.power((pix_cen[view] - moment1), 2) - moment2), 2) term2 += (plane*pix_size[view]) * (pix_cen[view] - moment1) return (1/moment0) * np.sqrt(term1 + 4*np.power(moment1_err*term2, 2))
def _slice2(cube, axis, scale, moment0, moment1, moment2, moment1_err): """ 2nd moment error along an axis, calculated slicewise Parameters ---------- cube : SpectralCube axis : int scale : float or SpectralCube moment0 : 0th moment moment1 : 1st moment moment2 : 2nd moment moment1_err : 1st moment error Returns ------- moment1_error : array """ if isinstance(scale, SpectralCube): # scale should then have the same shape as the cube. if cube.shape != scale.shape: raise IndexError("When scale is a SpectralCube, it must have the" " same shape as the cube.") _scale_cube = True else: _scale_cube = False # Divide moment0 by the pixel size in the given axis so it represents the # sum. spec_unit = cube.spectral_axis.unit axis_sum = u.Quantity(moment0 / (cube._pix_size_slice(axis) * spec_unit)) shp = _moment_shp(cube, axis) term1 = np.zeros(shp) * spec_unit ** 4 term2 = np.zeros(shp) * spec_unit * cube.unit view = [slice(None)] * 3 pix_cen = cube._pix_cen()[axis] * spec_unit # term12 does not depend on plane. term12 = moment2 / axis_sum for i in range(cube.shape[axis]): view[axis] = i plane = np.nan_to_num(cube.filled_data[view]) term11 = np.power((pix_cen[view] - moment1), 2) / axis_sum if _scale_cube: noise_plane = \ np.nan_to_num(scale.filled_data[view]) else: noise_plane = scale term1 += np.power((term11 - term12) * noise_plane, 2) term2 += np.nan_to_num(plane) * (pix_cen[view] - moment1) term2 = 4 * np.power((moment1_err * term2) / (axis_sum), 2) return np.sqrt(term1 + term2)