def angular_integration(IM, origin=None, Jacobian=True, dr=1, dt=None): """Angular integration of the image. Returns the one-dimensional intensity profile as a function of the radial coordinate. Note: the use of Jacobian=True applies the correct Jacobian for the integration of a 3D object in spherical coordinates. Parameters ---------- IM : 2D numpy.array The data image. origin : tuple Image center coordinate relative to *bottom-left* corner defaults to ``rows//2, cols//2``. Jacobian : boolean Include :math:`r\sin\\theta` in the angular sum (integration). Also, ``Jacobian=True`` is passed to :func:`abel.tools.polar.reproject_image_into_polar`, which includes another value of ``r``, thus providing the appropriate total Jacobian of :math:`r^2\sin\\theta`. dr : float Radial coordinate grid spacing, in pixels (default 1). `dr=0.5` may reduce pixel granularity of the speed profile. dt : float Theta coordinate grid spacing in radians. if ``dt=None``, dt will be set such that the number of theta values is equal to the height of the image (which should typically ensure good sampling.) Returns ------ r : 1D numpy.array radial coordinates speeds : 1D numpy.array Integrated intensity array (vs radius). """ polarIM, R, T = reproject_image_into_polar( IM, origin, Jacobian=Jacobian, dr=dr, dt=dt) dt = T[0, 1] - T[0, 0] if Jacobian: # x r sinθ polarIM = polarIM * R * np.abs(np.sin(T)) speeds = np.trapz(polarIM, axis=1, dx=dt) n = speeds.shape[0] return R[:n, 0], speeds # limit radial coordinates range to match speed
def angular_integration(IM, origin=None, Jacobian=True, dr=1, dt=None): """ Angular integration of the image. Returns the one-dimentional intensity profile as a function of the radial coordinate. Note: the use of Jacobian=True applies the correct Jacobian for the integration of a 3D object in spherical coordinates. Parameters ---------- IM : 2D numpy.array The data image. origin : tuple Image center coordinate relative to *bottom-left* corner defaults to ``rows//2+rows%2,cols//2+cols%2``. Jacobian : boolean Include :math:`r\sin\\theta` in the angular sum (integration). Also, ``Jacobian=True`` is passed to :func:`abel.tools.polar.reproject_image_into_polar`, which includes another value of ``r``, thus providing the appropriate total Jacobian of :math:`r^2\sin\\theta`. dr : float Radial coordinate grid spacing, in pixels (default 1). `dr=0.5` may reduce pixel granularity of the speed profile. dt : float Theta coordinate grid spacing in degrees. if ``dt=None``, dt will be set such that the number of theta values is equal to the height of the image (which should typically ensure good sampling.) Returns ------- r : 1D numpy.array radial coordinates speeds : 1D numpy.array Integrated intensity array (vs radius). """ polarIM, R, T = reproject_image_into_polar( IM, origin, Jacobian=Jacobian, dr=dr, dt=dt) dt = T[0,1] - T[0,0] if Jacobian: # x r sinθ polarIM = polarIM * R * np.abs(np.sin(T)) speeds = np.trapz(polarIM, axis=1, dx=dt) n = speeds.shape[0] return R[:n, 0], speeds # limit radial coordinates range to match speed
def radial_integration(IM, radial_ranges=None): """ Intensity variation in the angular coordinate. This function is the :math:`\\theta`-coordinate complement to :func:`abel.tools.vmi.angular_integration` (optionally and more useful) returning intensity vs angle for defined radial ranges, to evaluate the anisotropy parameter. See :doc:`examples/example_O2_PES_PAD.py <examples>` Parameters ---------- IM : 2D numpy.array Image data radial_ranges : list of tuple ranges or int step tuple integration ranges ``[(r0, r1), (r2, r3), ...]`` evaluates the intensity vs angle for the radial ranges ``r0_r1``, ``r2_r3``, etc. int - the whole radial range ``(r0, r_step), (r_step, r_2step), ..)`` Returns ------- intensity_vs_theta: 2D numpy.array Intensity vs angle distribution for each selected radial range. theta: 1D numpy.array Angle coordinates, referenced to vertical direction. radial_midpt: numpy.array Array of radial positions of the mid-point of the integration range """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = 1 if isinstance(radial_ranges, int): radial_ranges = list(zip(r[:-radial_ranges], r[radial_ranges:])) intensity_vs_theta_at_R = [] radial_midpt = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R.append(np.sum(polarIM[subr], axis=0)) radial_midpt.append(np.mean(rr)) return np.array(intensity_vs_theta_at_R), theta, radial_midpt
def calculate_speeds(IM, origin=None, Jacobian=False, dr=1, dt=None): """ Angular integration of the image. Returning the one-dimentional intensity profile as a function of the radial coordinate. Parameters ---------- IM : rows x cols 2D np.array The data image. origin : tuple Image center coordinate relative to *bottom-left* corner defaults to (rows//2+rows%2,cols//2+cols%2). Jacobian : boolean Include r*sinθ in the angular sum (integration). dr : float Radial coordinate grid spacing, in pixels (default 1). dt : float Theta coordinate grid spacing in degrees, defaults to rows//2. Returns ------- speeds : 1D np.array Integrated intensity array (vs radius). r : 1D np.array radial coordinates """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM, origin, Jacobian=Jacobian, dr=dr, dt=dt) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if Jacobian: # x r sinθ sintheta = np.abs(np.sin(theta)) polarIM = polarIM * sintheta[np.newaxis, :] polarIM = polarIM * r[:, np.newaxis] speeds = np.sum(polarIM, axis=1) n = speeds.shape[0] return speeds, r[:n] # limit radial coordinates range to match speed
def radial_integration(IM, radial_ranges=None): """ Intensity variation in the angular coordinate. This function is the :math:`\\theta`-coordinate complement to :func:`abel.tools.vmi.angular_integration` (optionally and more useful) returning intensity vs angle for defined radial ranges, to evaluate the anisotropy parameter. See :doc:`examples/example_O2_PES_PAD.py <examples>` Parameters ---------- IM : 2D np.array Image data radial_ranges : list of tuples integration ranges ``[(r0, r1), (r2, r3), ...]`` Evaluate the intensity vs angle for the radial ranges ``r0_r1``, ``r2_r3``, etc. Returns ------- intensity_vs_theta: 2D np.array Intensity vs angle distribution for each selected radial range. theta: 1D np.array Angle coordinates, referenced to vertical direction. """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = [ (0, r[-1]), ] intensity_vs_theta_at_R = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R.append(np.sum(polarIM[subr], axis=0)) return np.array(intensity_vs_theta_at_R), theta
def radial_integration(IM, radial_ranges=None): """ Intensity variation in the angular coordinate. This function is the :math:`\\theta`-coordinate complement to :func:`abel.tools.vmi.angular_integration` (optionally and more useful) returning intensity vs angle for defined radial ranges, to evaluate the anisotropy parameter. See :doc:`examples/example_O2_PES_PAD.py <examples>` Parameters ---------- IM : 2D np.array Image data radial_ranges : list of tuples integration ranges ``[(r0, r1), (r2, r3), ...]`` Evaluate the intensity vs angle for the radial ranges ``r0_r1``, ``r2_r3``, etc. Returns ------- intensity_vs_theta: 2D np.array Intensity vs angle distribution for each selected radial range. theta: 1D np.array Angle coordinates, referenced to vertical direction. """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = [(0, r[-1]), ] intensity_vs_theta_at_R = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R.append(np.sum(polarIM[subr], axis=0)) return np.array(intensity_vs_theta_at_R), theta
def calculate_speeds(IM, origin=None, Jacobian=False, dr=1, dt=None): """ Angular integration of the image. Returning the one-dimentional intensity profile as a function of the radial coordinate. Parameters ---------- IM : rows x cols 2D np.array The data image. origin : tuple Image center coordinate relative to *bottom-left* corner defaults to (rows//2+rows%2,cols//2+cols%2). Jacobian : boolean Include r*sinθ in the angular sum (integration). dr : float Radial coordinate grid spacing, in pixels (default 1). dt : float Theta coordinate grid spacing in degrees, defaults to rows//2. Returns ------- speeds : 1D np.array Integrated intensity array (vs radius). r : 1D np.array radial coordinates """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM, origin, Jacobian=Jacobian, dr=dr, dt=dt) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if Jacobian: # x r sinθ sintheta = np.abs(np.sin(theta)) polarIM = polarIM*sintheta[np.newaxis, :] polarIM = polarIM*r[:, np.newaxis] speeds = np.sum(polarIM, axis=1) n = speeds.shape[0] return speeds, r[:n] # limit radial coordinates range to match speed
def calculate_angular_distribution(IM, radial_ranges=None): """ Intensity variation in the angular coordinate, theta. This function is the theta-coordinate complement to 'calculate_speeds(IM)' (optionally and more useful) returning intensity vs angle for defined radial ranges. Parameters ---------- IM : 2D np.array Image data radial_ranges : list of tuples [(r0, r1), (r2, r3), ...] Evaluate the intensity vs angle for the radial ranges r0_r1, r2_r3, etc. Returns -------- intensity_vs_theta: 2D np.array Intensity vs angle distribution for each selected radial range. theta: 1D np.array Angle coordinates, referenced to vertical direction. """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = [ (0, r[-1]), ] intensity_vs_theta_at_R = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R.append(np.sum(polarIM[subr], axis=0)) return intensity_vs_theta_at_R, theta
def calculate_angular_distribution(IM, radial_ranges=None): """ Intensity variation in the angular coordinate, theta. This function is the theta-coordinate complement to 'calculate_speeds(IM)' (optionally and more useful) returning intensity vs angle for defined radial ranges. Parameters ---------- IM : 2D np.array Image data radial_ranges : list of tuples [(r0, r1), (r2, r3), ...] Evaluate the intensity vs angle for the radial ranges r0_r1, r2_r3, etc. Returns -------- intensity_vs_theta: 2D np.array Intensity vs angle distribution for each selected radial range. theta: 1D np.array Angle coordinates, referenced to vertical direction. """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = [(0, r[-1]), ] intensity_vs_theta_at_R = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R.append(np.sum(polarIM[subr], axis=0)) return intensity_vs_theta_at_R, theta
def angular_integration(IM, origin=None, Jacobian=True, dr=1, dt=None): r"""Angular integration of the image. Returns the one-dimensional intensity profile as a function of the radial coordinate. Note: the use of ``Jacobian=True`` applies the correct Jacobian for the integration of a 3D object in spherical coordinates. Parameters ---------- IM : 2D numpy.array the image data origin : tuple or None image origin in the (row, column) format. If ``None``, the geometric center of the image (``rows // 2, cols // 2``) is used. Jacobian : bool Include :math:`r\sin\theta` in the angular sum (integration). Also, ``Jacobian=True`` is passed to :func:`abel.tools.polar.reproject_image_into_polar`, which includes another value of `r`, thus providing the appropriate total Jacobian of :math:`r^2\sin\theta`. dr : float radial grid spacing in pixels (default 1). ``dr=0.5`` may reduce pixel granularity of the speed profile. dt : float or None angular grid spacing in radians. If ``None``, the number of theta values will be set to largest dimension (the height or the width) of the image, which should typically ensure good sampling. Returns ------ r : 1D numpy.array radial coordinates speeds : 1D numpy.array integrated intensity array (vs radius). """ polarIM, R, T = reproject_image_into_polar(IM, origin, Jacobian=Jacobian, dr=dr, dt=dt) dt = T[0, 1] - T[0, 0] if Jacobian: # × r sinθ polarIM *= R * np.abs(np.sin(T)) speeds = np.trapz(polarIM, axis=1, dx=dt) n = speeds.shape[0] return R[:n, 0], speeds # limit radial coordinates range to match speed
def radial_integration(IM, origin=None, radial_ranges=None): r""" Intensity variation in the angular coordinate. This function is the :math:`\theta`-coordinate complement to :func:`abel.tools.vmi.angular_integration`. Evaluates intensity vs angle for defined radial ranges. Determines the anisotropy parameter for each radial range. See :doc:`examples/example_O2_PES_PAD.py <example_O2_PES_PAD>`. Parameters ---------- IM : 2D numpy.array the image data origin : tuple or None image origin in the (row, column) format. If ``None``, the geometric center of the image (``rows // 2, cols // 2``) is used. radial_ranges : list of tuple ranges or int step tuple integration ranges ``[(r0, r1), (r2, r3), ...]`` evaluates the intensity vs angle for the radial ranges ``r0_r1``, ``r2_r3``, etc. int the whole radial range ``(0, step), (step, 2*step), ..`` Returns ------- Beta : array of tuples (beta0, error_beta_fit0), (beta1, error_beta_fit1), ... corresponding to the radial ranges Amplitude : array of tuples (amp0, error_amp_fit0), (amp1, error_amp_fit1), ... corresponding to the radial ranges Rmidpt : numpy float 1D array radial mid-point of each radial range Intensity_vs_theta: 2D numpy.array intensity vs angle distribution for each selected radial range theta: 1D numpy.array angle coordinates, referenced to vertical direction """ if origin is not None and not isinstance(origin, tuple): _deprecate('radial_integration() has 2nd argument "origin", ' 'use keyword argument "radial_ranges" or insert "None".') radial_ranges = origin origin = None polarIM, r_grid, theta_grid = reproject_image_into_polar(IM, origin) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = 1 if isinstance(radial_ranges, int): rr = np.arange(0, r[-1], radial_ranges) # @DanHickstein clever code to map ranges radial_ranges = list(zip(rr[:-1], rr[1:])) Intensity_vs_theta = [] radial_midpt = [] Beta = [] Amp = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R = np.sum(polarIM[subr], axis=0) Intensity_vs_theta.append(intensity_vs_theta_at_R) radial_midpt.append(np.mean(rr)) beta, amp = anisotropy_parameter(theta, intensity_vs_theta_at_R) Beta.append(beta) Amp.append(amp) return Beta, Amp, radial_midpt, Intensity_vs_theta, theta
def radial_integration(IM, radial_ranges=None): """ Intensity variation in the angular coordinate. This function is the :math:`\\theta`-coordinate complement to :func:`abel.tools.vmi.angular_integration` Evaluates intensity vs angle for defined radial ranges. Determines the anisotropy parameter for each radial range. See :doc:`examples/example_PAD.py <examples>` Parameters ---------- IM : 2D numpy.array Image data radial_ranges : list of tuple ranges or int step tuple integration ranges ``[(r0, r1), (r2, r3), ...]`` evaluates the intensity vs angle for the radial ranges ``r0_r1``, ``r2_r3``, etc. int the whole radial range ``(0, step), (step, 2*step), ..`` Returns ------- Beta : array of tuples (beta0, error_beta_fit0), (beta1, error_beta_fit1), ... corresponding to the radial ranges Amplitude : array of tuples (amp0, error_amp_fit0), (amp1, error_amp_fit1), ... corresponding to the radial ranges Rmidpt : numpy float 1d array radial-mid point of each radial range Intensity_vs_theta: 2D numpy.array Intensity vs angle distribution for each selected radial range. theta: 1D numpy.array Angle coordinates, referenced to vertical direction. """ polarIM, r_grid, theta_grid = reproject_image_into_polar(IM) theta = theta_grid[0, :] # theta coordinates r = r_grid[:, 0] # radial coordinates if radial_ranges is None: radial_ranges = 1 if isinstance(radial_ranges, int): rr = np.arange(0, r[-1], radial_ranges) # @DanHickstein clever code to map ranges radial_ranges = list(zip(rr[:-1], rr[1:])) Intensity_vs_theta = [] radial_midpt = [] Beta = [] Amp = [] for rr in radial_ranges: subr = np.logical_and(r >= rr[0], r <= rr[1]) # sum intensity across radius of spectral feature intensity_vs_theta_at_R = np.sum(polarIM[subr], axis=0) Intensity_vs_theta.append(intensity_vs_theta_at_R) radial_midpt.append(np.mean(rr)) beta, amp = anisotropy_parameter(theta, intensity_vs_theta_at_R) Beta.append(beta) Amp.append(amp) return Beta, Amp, radial_midpt, Intensity_vs_theta, theta