def get_elliptical_distortion(
        self,
        mask_radius,
        scale=100,
        amplitude=1000,
        spread=2,
        direct_beam_amplitude=500,
        asymmetry=1,
        rotation=0,
        center=None,
    ):
        """Determine elliptical distortion of the diffraction pattern.

        Parameters
        ----------
        mask_radius : int
             The radius in pixels for a mask over the direct beam disc
             (the direct beam disc within given radius will be excluded
             from the fit)
        scale : float
            An initial guess for the diffraction calibration
            in 1/Angstrom units
        amplitude : float
            An initial guess for the amplitude of the polycrystalline rings
            in arbitrary units
        spread : float
            An initial guess for the spread within each ring (Gaussian width)
        direct_beam_amplitude : float
            An initial guess for the background intensity from the direct
            beam disc in arbitrary units
        asymmetry : float
            An initial guess for any elliptical asymmetry in the
            pattern (for a perfectly circular pattern asymmetry=1)
        rotation : float
            An initial guess for the rotation of the (elliptical) pattern
            in radians.
        center : None or list
            The center of the diffraction pattern.

        Returns
        -------
        fit_params : np.array()
            Array of fitting parameters. [scale, amplitude, spread,
                                          direct_beam_amplitude, asymmetry,
                                          rotation].
        affine_matrix : np.array()
            Array defining the affine transformation that corrects for lens
            distortions in the diffraction pattern.

        See Also
        --------
            pyxem.utils.calibration_utils.call_ring_pattern

        """
        # Check that necessary calibration data is provided
        if self.diffraction_pattern is None:
            raise ValueError(
                "This method requires a calibration diffraction pattern"
                " to be provided. Please set self.diffraction_pattern equal"
                " to some Signal2D."
            )
        standard_dp = self.diffraction_pattern
        image_size = standard_dp.data.shape[0]
        if center is None:
            center = [(image_size -1)/2, (image_size -1)/2]
        # Set diffraction pattern variable
        x, y = np.mgrid[0:image_size, 0:image_size]
        radius_map = calc_radius_with_distortion(x, y, center[0], center[1], 1, 0)
        mask = radius_map < mask_radius
        ref = standard_dp.data[~mask]
        fullx,fully = [x,y]
        pts = np.array([fully[~mask], fullx[~mask]]).ravel()
        # Set initial parameters for fitting
        x0 = [scale, amplitude, spread, direct_beam_amplitude, asymmetry, rotation]
        # Fit ring pattern to experimental data
        xf, cov = curve_fit(call_ring_pattern(center[0], center[1]), pts, ref, p0=x0)
        # Set ring fitting parameters to attribute
        self.ring_params = xf
        # Calculate affine transform parameters from fit parameters
        scaling = np.array([[1, 0], [0, xf[4] ** -0.5]])
        rotation = np.array([[cos(xf[5]), -sin(xf[5])], [sin(xf[5]), cos(xf[5])]])
        correction = np.linalg.inv(np.dot(rotation.T, np.dot(scaling, rotation)))
        affine = np.array(
            [
                [correction[0, 0], correction[0, 1], 0.00],
                [correction[1, 0], correction[1, 1], 0.00],
                [0.00, 0.00, 1.00],
            ]
        )
        # Set affine matrix to attribute
        self.affine_matrix = affine
        return affine
Exemple #2
0
    def get_elliptical_distortion(self,
                                  mask_radius,
                                  scale=100,
                                  amplitude=1000,
                                  spread=2,
                                  direct_beam_amplitude=500,
                                  asymmetry=1,
                                  rotation=0):
        """Determine elliptical distortion of the diffraction pattern.

        Parameters
        ----------
        mask_radius : int
            The radius in pixels for a mask over the direct beam disc
            (the direct beam disc within given radius will be excluded
            from the fit)
        scale : float
            An initial guess for the diffraction calibration
            in 1/Angstrom units
        amplitude : float
            An initial guess for the amplitude of the polycrystalline rings
            in arbitrary units
        spread : float
            An initial guess for the spread within each ring (Gaussian width)
        direct_beam_amplitude : float
            An initial guess for the background intensity from the direct
            beam disc in arbitrary units
        asymmetry : float
            An initial guess for any elliptical asymmetry in the
            pattern (for a perfectly circular pattern asymmetry=1)
        rotation : float
            An initial guess for the rotation of the (elliptical) pattern
            in radians.

        Returns
        -------
        fit_params : np.array()
            Array of fitting parameters. [scale, amplitude, spread,
                                          direct_beam_amplitude, asymmetry,
                                          rotation].
        affine_matrix : np.array()
            Array defining the affine transformation that corrects for lens
            distortions in the diffraction pattern.

        See Also
        --------
            pyxem.utils.calibration_utils.call_ring_pattern

        """
        # Check that necessary calibration data is provided
        if self.calibration_data.au_x_grating_dp is None:
            raise ValueError(
                "This method requires an Au X-grating diffraction "
                "pattern to be provided. Please update the "
                "CalibrationDataLibrary.")
        # Set diffraction pattern variable
        standard_dp = self.calibration_data.au_x_grating_dp
        # Define grid values and center indices for ring pattern evaluation
        image_size = standard_dp.data.shape[0]
        xi = np.linspace(0, image_size - 1, image_size)
        yi = np.linspace(0, image_size - 1, image_size)
        x, y = np.meshgrid(xi, yi)
        xcenter = (image_size - 1) / 2
        ycenter = (image_size - 1) / 2
        # Calculate eliptical parameters
        mask = calc_radius_with_distortion(x, y, (image_size - 1) / 2,
                                           (image_size - 1) / 2, 1, 0)
        # Mask direct beam
        mask[mask > mask_radius] = 0
        standard_dp.data[mask > 0] *= 0
        # Manipulate measured data for fitting
        ref = standard_dp.data[standard_dp.data > 0]
        ref = ref.ravel()
        # Define points for fitting
        pts = np.array(
            [x[standard_dp.data > 0].ravel(),
             y[standard_dp.data > 0].ravel()]).ravel()
        # Set initial parameters for fitting
        x0 = [
            scale, amplitude, spread, direct_beam_amplitude, asymmetry,
            rotation
        ]
        # Fit ring pattern to experimental data
        xf, cov = curve_fit(call_ring_pattern(xcenter, ycenter),
                            pts,
                            ref,
                            p0=x0)
        # Set ring fitting parameters to attribute
        self.ring_params = xf
        # Calculate affine transform parameters from fit parameters
        scaling = np.array([[1, 0], [0, xf[4]**-0.5]])

        rotation = np.array([[cos(xf[5]), -sin(xf[5])],
                             [sin(xf[5]), cos(xf[5])]])

        correction = np.linalg.inv(
            np.dot(rotation.T, np.dot(scaling, rotation)))

        affine = np.array([[correction[0, 0], correction[0, 1], 0.00],
                           [correction[1, 0], correction[1, 1], 0.00],
                           [0.00, 0.00, 1.00]])
        # Set affine matrix to attribute
        self.affine_matrix = affine

        return affine