pyextal.larbed.analysis ======================= .. py:module:: pyextal.larbed.analysis .. autoapi-nested-parse:: Extraction of LARBED rocking curves from a raw 4D-STEM stack. Classes ------- .. autoapisummary:: pyextal.larbed.analysis.LARBEDAnalysis Module Contents --------------- .. py:class:: LARBEDAnalysis(file_name) Turns a raw EMPAD scan into one rocking curve per reflection. The usual sequence is :meth:`load_data`, :meth:`average_data` (or :meth:`align_data`), :meth:`assign_gvector`, :meth:`calculate_grid_vectors`, :meth:`calculate_g_vectors`, and :meth:`IntegrateLarbed`. The result can then be handed to the refinement stage with :meth:`to_dinfo` or :meth:`save_h5`, or written as loose ``.npy`` files with :meth:`save_larbed`. :ivar file_name: Path to the raw ``.raw`` file. :vartype file_name: str :ivar data: The 4D stack (scan_x, scan_y, det_x, det_y). :vartype data: np.ndarray :ivar center: Direct-beam position on the detector. :vartype center: tuple[float, float] :ivar IntRadius: Aperture half-width used by :meth:`align_data` and :meth:`ZeroLarbed`. :vartype IntRadius: int :ivar grid: Reciprocal-lattice nodes as ``(index, pixel)`` pairs. :vartype grid: list :ivar g_vectors: Miller index of each grid node. :vartype g_vectors: list :ivar Store_Larbed: Integrated intensity map per reflection. :vartype Store_Larbed: list :ivar Store_LarbedVariance: Propagated variance per reflection. :vartype Store_LarbedVariance: list :ivar Store_bkg: Subtracted background per reflection. :vartype Store_bkg: list :ivar Store_bkg_info: With a fitted background, ``n_fit`` (fit pixels) and ``noise_gain`` per reflection. :vartype Store_bkg_info: list :ivar noise: The detector noise model measured by :meth:`estimate_noise`. :vartype noise: dict .. py:attribute:: file_name .. py:attribute:: data :value: [] .. py:attribute:: average_raw :value: None .. py:attribute:: average_aligned :value: None .. py:attribute:: aligned :value: False .. py:attribute:: g_grid :value: None .. py:attribute:: g_vectors :value: None .. py:attribute:: Larbed :value: [] .. py:attribute:: LarbedDeconvolved :value: [] .. py:attribute:: gg_pixels :value: [] .. py:attribute:: mtf_2d :value: None .. py:attribute:: mixing :value: None .. py:attribute:: center :value: (64, 64) .. py:attribute:: IntRadius :value: 4 .. py:attribute:: IntZero :value: [] .. py:attribute:: noise :value: None .. py:property:: detector_shape Detector shape (det_x, det_y) of the loaded stack. :type: tuple[int, int] .. py:method:: load_data(type=0) Reads the raw file and centres the direct beam on the detector midpoint. :param type: Detector layout, passed to :func:`pyextal.larbed.empad.ReadRaw`. Defaults to 0. :type type: int, optional .. py:method:: align_data(iterations=3) Aligns the stack on the direct beam and stores before/after averages. :param iterations: Number of alignment passes. Defaults to 3. :type iterations: int, optional .. py:method:: deconv_DPstack(mtf_2d, background=0, niter=100, varB=6.29, delta=0, A=1, g=580, m=None) Deconvolves every diffraction pattern in the stack against the MTF. :param mtf_2d: The modulation transfer function. :type mtf_2d: np.ndarray :param background: Pattern background. Defaults to 0. :type background: float, optional :param niter: Lucy-Richardson iterations. Defaults to 100. :type niter: int, optional :param varB: Background variance. Defaults to 6.29. :type varB: float, optional :param delta: Squared percentage gain error. Defaults to 0. :type delta: float, optional :param A: Fano/conversion-gain parameter. Defaults to 1. :type A: float, optional :param g: Detector gain. Defaults to 580. :type g: float, optional :param m: Mixing factor. Derived from ``mtf_2d`` when None. Defaults to None. :type m: float, optional .. py:method:: deconv_Larbedstack(background=0, niter=100, varB=6.29, delta=0.0, A=1, g=1, mtf_2d=None, pad_size=None, m=1) Deconvolves the integrated rocking curves against the MTF. .. note:: Legacy. Because the rocking curves are already integrated over an aperture, deconvolution mainly adds noise; this step is normally skipped. It also discards the propagated variance. :param background: Background level. Defaults to 0. :type background: float, optional :param niter: Lucy-Richardson iterations. Defaults to 100. :type niter: int, optional :param varB: Background variance. Defaults to 6.29. :type varB: float, optional :param delta: Squared percentage gain error. Defaults to 0.0. :type delta: float, optional :param A: Fano/conversion-gain parameter. Defaults to 1. :type A: float, optional :param g: Detector gain. Defaults to 1. :type g: float, optional :param mtf_2d: MTF to use. Falls back to ``self.mtf_2d``. Defaults to None. :type mtf_2d: np.ndarray, optional :param pad_size: Edge padding applied before deconvolution. Defaults to None (no padding). :type pad_size: int, optional :param m: Mixing factor. Defaults to 1. :type m: float, optional .. py:method:: average_data() Averages the stack without aligning it. .. py:method:: assign_gvector(g1, g2, g3=None, g4=None) Records the detector pixel positions of the basis reflections. Supply two basis vectors for a zone-axis grid, or four to include HOLZ reflections. :param g1: Pixel position of the first basis reflection. :type g1: tuple[float, float] :param g2: Pixel position of the second. :type g2: tuple[float, float] :param g3: Pixel position of the third. Defaults to None. :type g3: tuple[float, float], optional :param g4: Pixel position of the fourth. Defaults to None. :type g4: tuple[float, float], optional .. py:method:: calculate_g_vectors(g1, g2, g3=None, g4=None) Assigns a Miller index to every node of the pixel grid. The number of basis vectors must match what was passed to :meth:`assign_gvector`. :param g1: Miller index of the first basis reflection. :type g1: tuple[int, int, int] :param g2: Miller index of the second. :type g2: tuple[int, int, int] :param g3: Miller index of the third. Defaults to None. :type g3: tuple[int, int, int], optional :param g4: Miller index of the fourth. Defaults to None. :type g4: tuple[int, int, int], optional .. py:method:: calculate_grid_vectors(crop=1, order=3, Adjust=True) Builds the reciprocal-space grid of reflections on the detector. Dispatches on how many basis vectors :meth:`assign_gvector` was given: four selects the HOLZ grid, two selects either the peak-snapped or the plain lattice grid depending on ``Adjust``. :param crop: Half-width of the peak search window used when ``Adjust`` is True. Defaults to 1. :type crop: int, optional :param order: Grid extent. Must be a 4-tuple for the HOLZ grid, an int otherwise. Defaults to 3. :type order: int | tuple[int, int, int, int], optional :param Adjust: Snap each two-vector grid node onto the nearest observed peak. Defaults to True. :type Adjust: bool, optional .. py:method:: plot_averages(ratio=0.2) Plots the stack average before and after alignment. :param ratio: Fraction of the maximum used as the display ceiling. Defaults to 0.2. :type ratio: float, optional .. py:method:: ZeroLarbed(ratio=1) Integrates and plots the rocking curve of the direct beam. :param ratio: Fraction of the maximum used as the display ceiling. Defaults to 1. :type ratio: float, optional .. py:method:: plot_grid_vectors(ratio=0.2) Overlays the reflection grid on the stack average. :param ratio: Fraction of the maximum used as the display ceiling. Defaults to 0.2. :type ratio: float, optional .. py:method:: IntegrateLarbed(ri=4, ro=(0, 0), g=1, m=1, DQE=1, varB=0.0, Variance=False, bkg_fit=None, mask_neighbours=True, clip=True, rho=None) Integrates each reflection into a rocking curve. Reflections whose background-subtracted sum is nowhere positive are dropped from ``grid`` and ``g_vectors`` as well as from the output. By default the background is the mean of the ``ro`` annulus. That mean is biased high next to a bright reflection, whose convex tail runs through the annulus, and the clipping at zero then wipes out much of a weak rocking curve. With ``bkg_fit`` set, a polynomial surface is fitted instead, for each reflection on each frame, to the annulus pixels that are outside the aperture and (with ``mask_neighbours``) away from the other reflections; the fitted surface summed under the aperture is what gets subtracted. See :func:`pyextal.larbed.empad.BackgroundFitWeights`. :param ri: Aperture half-width in pixels. Defaults to 4. :type ri: int, optional :param ro: Inner and outer radii of the background annulus. ``(0, 0)`` disables background subtraction. Defaults to (0, 0). :type ro: tuple[int, int], optional :param g: Detector gain. Defaults to 1. :type g: float, optional :param m: Mixing factor. Defaults to 1. :type m: float, optional :param DQE: Detective quantum efficiency. Defaults to 1. :type DQE: float, optional :param varB: Per-pixel background variance. Defaults to 0.0. :type varB: float, optional :param Variance: Also propagate the counting variance. Defaults to False. :type Variance: bool, optional :param bkg_fit: Fit the background as a polynomial of order 0 (constant), 1 (plane) or 2 (quadratic) instead of using the annulus mean. Order 2 needs an annulus spanning a range of radii that stays clear of the neighbouring reflections, e.g. ``ri=3, ro=(4, 6)``. Defaults to None (annulus mean). :type bkg_fit: int, optional :param mask_neighbours: With ``bkg_fit``, leave pixels within ``ri`` of the other grid reflections out of the fit. Defaults to True. :type mask_neighbours: bool, optional :param clip: Set negative intensities to zero. Passing False keeps the noise around zero unbiased; note that the jaxGeo ``oversub`` model and :mod:`pyextal.acom.quality` were written for clipped data. Defaults to True. :type clip: bool, optional :param rho: Inter-pixel noise correlation kernel from :meth:`estimate_noise`. The variance then includes the covariance between neighbouring pixels, both inside the aperture and between the aperture and the background-fit pixels. Needs ``bkg_fit`` or no background. Defaults to None (independent pixels). :type rho: np.ndarray, optional :raises ValueError: If ``bkg_fit`` is set without a background annulus, or ``rho`` with the annulus-mean background. .. py:method:: estimate_noise(**kwargs) Measures the detector noise model from the scan itself. See :func:`pyextal.larbed.empad.EstimatePixelNoise`. Pass the result to :meth:`IntegrateLarbed` as ``m=noise['gm'] / g`` and ``rho=noise['rho']``. :param \*\*kwargs: Passed to :func:`pyextal.larbed.empad.EstimatePixelNoise`. :returns: ``gm``, ``rho``, ``gain_sum`` and ``n_pixels``; also stored as ``self.noise``. :rtype: dict .. py:method:: plot_IntegratedLarbed(index, Variance=False) Plots one integrated rocking curve, or all of them. :param index: Index of the reflection, or ``'all'``. :type index: int | str :param Variance: Plot the variance map instead. Defaults to False. :type Variance: bool, optional .. py:method:: deconvolve_image(index, niter=100, varB=6.29, delta=0, A=1, g=580) Deconvolves a single integrated rocking curve against the MTF. :param index: Index of the reflection. :type index: int :param niter: Lucy-Richardson iterations. Defaults to 100. :type niter: int, optional :param varB: Background variance. Defaults to 6.29. :type varB: float, optional :param delta: Squared percentage gain error. Defaults to 0. :type delta: float, optional :param A: Fano/conversion-gain parameter. Defaults to 1. :type A: float, optional :param g: Detector gain. Defaults to 580. :type g: float, optional :returns: The deconvolved rocking curve. :rtype: np.ndarray .. py:method:: plot_larbed(rotation=-22, order_option=1, order=6, Circle_radius=8, a_expansion=1.6, ratio=0.2, Variance=False) Plots every rocking curve at the position of its reflection. :param rotation: Rotation applied to each rocking curve in degrees, aligning the tilt-scan axes with the pattern. Defaults to -22. :type rotation: float, optional :param order_option: ``0`` filters reflections by the largest Miller index, ``1`` by the length of the g-vector. Defaults to 1. :type order_option: int, optional :param order: Cutoff for the filter above. Defaults to 6. :type order: int, optional :param Circle_radius: Radius of each rocking-curve disk. Defaults to 8. :type Circle_radius: float, optional :param a_expansion: Scaling applied to the disk positions. Defaults to 1.6. :type a_expansion: float, optional :param ratio: Fraction of the display maximum used as the ceiling. Defaults to 0.2. :type ratio: float, optional :param Variance: Plot variance maps instead of intensities. Defaults to False. :type Variance: bool, optional .. py:method:: stack() Packs the integrated results into the arrays the refinement stage wants. :returns: The intensity stack shaped (n_beams, ny, nx), the matching variance stack (None if :meth:`IntegrateLarbed` was run with ``Variance=False``), and the Miller indices shaped (n_beams, 3). :rtype: tuple[np.ndarray, np.ndarray | None, np.ndarray] :raises RuntimeError: If :meth:`IntegrateLarbed` has not been run. .. py:method:: to_dinfo(datpath, thickness, gl, tiltX=0.0, tiltY=0.0) Builds a :class:`pyextal.dinfo.LARBEDDiffractionInfo` from the results. This is the direct handoff into the refinement stage, replacing a :meth:`save_larbed` / ``np.load`` round-trip. :param datpath: Path to the crystal ``.dat`` file. :type datpath: str | pathlib.Path :param thickness: Initial sample thickness estimate in Angstroms. :type thickness: float :param gl: Tilt step size, as the number of steps spanning the x-axis reflection. See ``LARBED_Calibration.md``. :type gl: float :param tiltX: Initial tilt about x in degrees. Defaults to 0.0. :type tiltX: float, optional :param tiltY: Initial tilt about y in degrees. Defaults to 0.0. :type tiltY: float, optional :returns: Ready to pass to :class:`pyextal.roi.LARBEDROI`. :rtype: pyextal.dinfo.LARBEDDiffractionInfo .. py:method:: save_h5(h5path, *, prefix='', crystal_dat='', date='') Writes the integrated results into the ``/raw`` group of an HDF5 file. This is the same file the pre-refinement and JAX refinement stages append to, so one dataset lives in one file end to end. :param h5path: Path to the HDF5 file, created if absent. :type h5path: str | pathlib.Path :param prefix: Acquisition prefix recorded as provenance. Defaults to "". :type prefix: str, optional :param crystal_dat: Name of the crystal ``.dat`` file recorded as provenance. Defaults to "". :type crystal_dat: str, optional :param date: Acquisition date. Defaults to today. :type date: str, optional .. py:method:: save_larbed(filename) Writes the integrated results as loose ``.npy`` files. :param filename: Path prefix. Four files are written, suffixed ``_Store_Larbed.npy``, ``_Store_LarbedDeconvolved.npy``, ``_Store_LarbedVariance.npy``, and ``_g_vectors.npy``. :type filename: str .. py:method:: out_larbed() Returns the integrated results as Python lists. :returns: ``(Store_Larbed, Store_bkg, Store_LarbedVariance, g_vectors)``. :rtype: tuple