Beispiel #1
0
def get_core_loss_eels_line_scan_signal():
    """Get an artificial core loss electron energy loss line scan spectrum.

    Similar to a Mn-L32 and Fe-L32 edge from a perovskite oxide.

    Returns
    -------
    artificial_core_loss_line_scan_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_core_loss_eels_line_scan_signal()
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get low loss signal with the same size

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    x = np.arange(400, 800, 1)
    arctan_mn = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan_mn.minimum_at_zero = True
    arctan_fe = components1d.Arctan(A=1, k=0.2, x0=612)
    arctan_fe.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)
    fe_l3_g = components1d.Gaussian(A=100, centre=605, sigma=4)
    fe_l2_g = components1d.Gaussian(A=10, centre=630, sigma=3)

    mn_intensity = [1, 1, 1, 1, 1, 1, 0.8, 0.5, 0.2, 0, 0, 0]
    fe_intensity = [0, 0, 0, 0, 0, 0, 0.2, 0.5, 0.8, 1, 1, 1]
    data = np.zeros((len(mn_intensity), len(x)))
    for i in range(len(mn_intensity)):
        data[i] += arctan_mn.function(x) * mn_intensity[i]
        data[i] += mn_l3_g.function(x) * mn_intensity[i]
        data[i] += mn_l2_g.function(x) * mn_intensity[i]
        data[i] += arctan_fe.function(x) * fe_intensity[i]
        data[i] += fe_l3_g.function(x) * fe_intensity[i]
        data[i] += fe_l2_g.function(x) * fe_intensity[i]
        data[i] += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(
        beam_energy=200, convergence_angle=26, collection_angle=20)
    return s
Beispiel #2
0
def get_low_loss_eels_line_scan_signal(add_noise=True, random_state=None):
    """Get an artificial low loss electron energy loss line scan spectrum.

    The zero loss peak is offset by 4.1 eV.

    Parameters
    ----------
    %s

    %s

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    artificial_low_loss_line_scan_signal : :py:class:`~hyperspy._signals.eels.EELSSpectrum`


    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    random_state = check_random_state(random_state)

    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data_signal = zero_loss.function(x)
    data_signal += plasmon.function(x)
    data = np.zeros((12, len(x)))
    for i in range(12):
        data[i] += data_signal
        if add_noise:
            data[i] += random_state.uniform(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.axes_manager.signal_axes[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #3
0
def _create_signal(
    shape,
    dim,
    dtype,
):
    data = np.arange(np.product(shape)).reshape(shape).astype(dtype)
    if dim == 1:
        if len(shape) > 2:
            s = EELSSpectrum(data)
            s.set_microscope_parameters(beam_energy=100.,
                                        convergence_angle=1.,
                                        collection_angle=10.)
        else:
            s = EDSTEMSpectrum(data)
            s.set_microscope_parameters(beam_energy=100.,
                                        live_time=1.,
                                        tilt_stage=2.,
                                        azimuth_angle=3.,
                                        elevation_angle=4.,
                                        energy_resolution_MnKa=5.)
    else:
        s = BaseSignal(data)
        s.axes_manager.set_signal_dimension(dim)
    for i, axis in enumerate(s.axes_manager._axes):
        i += 1
        axis.offset = i * 0.5
        axis.scale = i * 100
        axis.name = "%i" % i
        if axis.navigate:
            axis.units = "m"
        else:
            axis.units = "eV"

    return s
Beispiel #4
0
def get_low_loss_eels_line_scan_signal():
    """Get an artificial low loss electron energy loss line scan spectrum.

    The zero loss peak is offset by 4.1 eV.

    Returns
    -------
    artificial_low_loss_line_scan_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_core_loss_eels_signal : get a core loss signal
    get_core_loss_eels_model : get a core loss model
    get_core_loss_eels_line_scan_signal : core loss signal with the same size

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data_signal = zero_loss.function(x)
    data_signal += plasmon.function(x)
    data = np.zeros((12, len(x)))
    for i in range(12):
        data[i] += data_signal
        data[i] += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.axes_manager.signal_axes[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(
        beam_energy=200, convergence_angle=26, collection_angle=20)
    return s
Beispiel #5
0
def _create_signal(shape, dim, dtype,):
    data = np.arange(np.product(shape)).reshape(
        shape).astype(dtype)
    if dim == 1:
        if len(shape) > 2:
            s = EELSSpectrum(data)
            s.set_microscope_parameters(
                beam_energy=100.,
                convergence_angle=1.,
                collection_angle=10.)
        else:
            s = EDSTEMSpectrum(data)
            s.set_microscope_parameters(
                beam_energy=100.,
                live_time=1.,
                tilt_stage=2.,
                azimuth_angle=3.,
                elevation_angle=4.,
                energy_resolution_MnKa=5.)
    else:
        s = BaseSignal(data)
        s.axes_manager.set_signal_dimension(dim)
    for i, axis in enumerate(s.axes_manager._axes):
        i += 1
        axis.offset = i * 0.5
        axis.scale = i * 100
        axis.name = "%i" % i
        if axis.navigate:
            axis.units = "m"
        else:
            axis.units = "eV"

    return s
def get_low_loss_eels_signal():
    """Get an artificial low loss electron energy loss spectrum.

    The zero loss peak is offset by 4.1 eV.

    Returns
    -------
    artificial_low_loss_signal : :py:class:`~hyperspy._signals.eels.EELSSpectrum`

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_core_loss_eels_signal, get_core_loss_eels_model,
    get_low_loss_eels_line_scan_signal, get_core_loss_eels_line_scan_signal

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data = zero_loss.function(x)
    data += plasmon.function(x)
    data += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.axes_manager[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #7
0
def get_core_loss_eels_signal():
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Returns
    -------
    artificial_core_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_core_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """
    x = np.arange(400, 800, 1)
    arctan = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    data += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #8
0
def create_ll_signal(signal_shape=1000):
    offset = 0
    zlp_param = {'A': 10000.0, 'centre': 0.0 + offset, 'sigma': 15.0}
    zlp = Gaussian(**zlp_param)
    plasmon_param = {'A': 2000.0, 'centre': 200.0 + offset, 'sigma': 75.0}
    plasmon = Gaussian(**plasmon_param)
    axis = np.arange(signal_shape)
    data = zlp.function(axis) + plasmon.function(axis)
    ll = EELSSpectrum(data)
    ll.axes_manager[-1].offset = -offset
    ll.axes_manager[-1].scale = 0.1
    return ll
Beispiel #9
0
    def setUp(self):
        """To test the kramers_kronig_analysis we will generate 3
        EELSSpectrum instances. First a model energy loss function(ELF),
        in our case following the Drude bulk plasmon peak. Second, we
        simulate the inelastic scattering to generate a model scattering
        distribution (SPC). Finally, we use a lorentzian peak with
        integral equal to 1 to simulate a ZLP.

        """

        # Parameters
        i0 = 1.
        t = signals.Signal(np.arange(10, 70, 10).reshape((2, 3)))  # thickness
        t.axes_manager.set_signal_dimension(0)
        scale = 0.02

        # Create an 3x2x2048 spectrum with Drude plasmon
        s = EELSSpectrum(np.zeros((2, 3, 2 * 2048)))
        s.set_microscope_parameters(beam_energy=300.0,
                                    convergence_angle=5,
                                    collection_angle=10.0)
        s.axes_manager.signal_axes[0].scale = scale
        k = eels_constant(s, i0, t)

        vpm = VolumePlasmonDrude()
        m = create_model(s, auto_background=False)
        m.append(vpm)
        vpm.intensity.map['values'][:] = 1
        vpm.plasmon_energy.map['values'] = np.array([[8., 18.4, 15.8],
                                                     [16.6, 4.3, 3.7]])
        vpm.fwhm.map['values'] = np.array([[2.3, 4.8, 0.53], [3.7, 0.3, 0.3]])
        vpm.intensity.map['is_set'][:] = True
        vpm.plasmon_energy.map['is_set'][:] = True
        vpm.fwhm.map['is_set'][:] = True
        s.data = (m.as_signal() * k).data

        # Create ZLP
        z = s.deepcopy()
        z.axes_manager.signal_axes[0].scale = scale
        z.axes_manager.signal_axes[0].offset = -10
        zlp = Lorentzian()
        zlp.A.value = i0
        zlp.gamma.value = 0.2
        zlp.centre.value = 0.0
        z.data[:] = zlp.function(z.axes_manager[-1].axis).reshape((1, 1, -1))
        z.data *= scale
        self.s = s
        self.thickness = t
        self.k = k
        self.zlp = z
Beispiel #10
0
def get_core_loss_eels_signal(add_powerlaw=False,
                              add_noise=True,
                              random_state=None):
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Some random noise is also added to the spectrum, to simulate
    experimental noise.

    Parameters
    ----------
    %s
    %s

    %s

    Example
    -------
    >>> import hs.datasets.artifical_data as ad
    >>> s = ad.get_core_loss_eels_signal()
    >>> s.plot()

    With the powerlaw background

    >>> s = ad.get_core_loss_eels_signal(add_powerlaw=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> s1 = ad.get_core_loss_eels_signal(random_state=10)
    >>> s2 = ad.get_core_loss_eels_signal(random_state=10)
    >>> (s1.data == s2.data).all()
    True

    See also
    --------
    get_core_loss_eels_line_scan_signal, get_low_loss_eels_line_scan_signal,
    get_core_loss_eels_model

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    random_state = check_random_state(random_state)

    x = np.arange(400, 800, 1)
    arctan = components1d.EELSArctan(A=1, k=0.2, x0=688)
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    if add_noise:
        data += random_state.uniform(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #11
0
def get_core_loss_eels_line_scan_signal(add_powerlaw=False,
                                        add_noise=True,
                                        random_state=None):
    """Get an artificial core loss electron energy loss line scan spectrum.

    Similar to a Mn-L32 and Fe-L32 edge from a perovskite oxide.

    Parameters
    ----------
    %s
    %s

    %s

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_core_loss_eels_line_scan_signal()
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_line_scan_signal, get_core_loss_eels_model

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    random_state = check_random_state(random_state)

    x = np.arange(400, 800, 1)
    arctan_mn = components1d.EELSArctan(A=1, k=0.2, x0=688)
    arctan_fe = components1d.EELSArctan(A=1, k=0.2, x0=612)
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)
    fe_l3_g = components1d.Gaussian(A=100, centre=605, sigma=4)
    fe_l2_g = components1d.Gaussian(A=10, centre=630, sigma=3)

    mn_intensity = [1, 1, 1, 1, 1, 1, 0.8, 0.5, 0.2, 0, 0, 0]
    fe_intensity = [0, 0, 0, 0, 0, 0, 0.2, 0.5, 0.8, 1, 1, 1]
    data = np.zeros((len(mn_intensity), len(x)))
    for i in range(len(mn_intensity)):
        data[i] += arctan_mn.function(x) * mn_intensity[i]
        data[i] += mn_l3_g.function(x) * mn_intensity[i]
        data[i] += mn_l2_g.function(x) * mn_intensity[i]
        data[i] += arctan_fe.function(x) * fe_intensity[i]
        data[i] += fe_l3_g.function(x) * fe_intensity[i]
        data[i] += fe_l2_g.function(x) * fe_intensity[i]
        if add_noise:
            data[i] += random_state.uniform(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function_nd(np.stack([x] * len(mn_intensity)))

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #12
0
def get_core_loss_eels_signal(add_powerlaw=False):
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Some random noise is also added to the spectrum, to simulate
    experimental noise.

    Parameters
    ----------
    add_powerlaw : bool
        If True, adds a powerlaw background to the spectrum.
        Default False.

    Returns
    -------
    artificial_core_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> import hs.datasets.artifical_data as ad
    >>> s = ad.get_core_loss_eels_signal()
    >>> s.plot()

    With the powerlaw background

    >>> s = ad.get_core_loss_eels_signal(add_powerlaw=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> np.random.seed(seed=10)
    >>> s1 = ad.get_core_loss_eels_signal()
    >>> np.random.seed(seed=10)
    >>> s2 = ad.get_core_loss_eels_signal()
    >>> (s1.data == s2.data).all()
    True

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    x = np.arange(400, 800, 1)
    arctan = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    data += np.random.random(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(
        beam_energy=200, convergence_angle=26, collection_angle=20)
    return s
def get_eels_spectrum_map(add_noise=True):
    """Get an artificial atomic resolution EELS map of LaMnO3

    Containing the Mn-L23 and La-M54 edges.

    Parameters
    ----------
    add_noise : bool
        If True, will add Gaussian noise to the spectra.
        Default True.

    Returns
    -------
    eels_map : HyperSpy EELSSpectrum

    Example
    -------
    >>> import atomap.api as am
    >>> s_eels_map = am.dummy_data.get_eels_spectrum_map()
    >>> s_eels_map.plot()

    Not adding noise

    >>> s_eels_map = am.dummy_data.get_eels_spectrum_map(add_noise=False)

    See also
    --------
    get_eels_spectrum_survey_image : signal with same spatial dimensions

    """
    x_size, y_size = 100, 100
    e0, e1 = 590, 900

    la_spatial = _make_eels_map_spatial_image_la(x_size=x_size, y_size=y_size)
    mn_spatial = _make_eels_map_spatial_image_mn(x_size=x_size, y_size=y_size)

    # Generate EELS spectra
    mn_data = _make_mn_eels_spectrum(energy_range=(e0, e1))
    la_data = _make_la_eels_spectrum(energy_range=(e0, e1))

    # Generate 3D-data
    # La
    data_3d_la = np.zeros(shape=(x_size, y_size, (e1 - e0)))
    data_3d_la[:, :] = la_data
    temp_3d_la = np.zeros(shape=(x_size, y_size, (e1 - e0)))
    temp_3d_la = temp_3d_la.swapaxes(0, 2)
    temp_3d_la[:] += la_spatial.data
    temp_3d_la = temp_3d_la.swapaxes(0, 2)
    data_3d_la *= temp_3d_la

    # Mn
    data_3d_mn = np.zeros(shape=(x_size, y_size, (e1 - e0)))
    data_3d_mn[:, :] = mn_data
    temp_3d_mn = np.zeros(shape=(x_size, y_size, (e1 - e0)))
    temp_3d_mn = temp_3d_mn.swapaxes(0, 2)
    temp_3d_mn[:] += mn_spatial.data
    temp_3d_mn = temp_3d_mn.swapaxes(0, 2)
    data_3d_mn *= temp_3d_mn

    data_3d = data_3d_mn + data_3d_la

    # Adding background and add noise
    background = components1d.PowerLaw(A=1e10, r=3, origin=0)
    background_data = background.function(np.arange(e0, e1, 1))
    temp_background_data = np.zeros(shape=(x_size, y_size, (e1 - e0)))
    temp_background_data[:, :] += background_data
    data_3d += background_data

    if add_noise:
        data_noise = np.random.random((x_size, y_size, (e1 - e0))) * 0.7
        data_3d += data_noise

    s_3d = EELSSpectrum(data_3d)
    return s_3d
def disc_edge_sigma(im, sigma=2, cyx=None, r=None, use_hyperspy=False, plot=True, widget=None, logger=None):
    '''
    Calculates disc edge width by averaging sigmas from fitting Erfs to unwrapped disc.
    
    Parameters
    ----------
    im : 2-D array
        Image of disc.
    sigma : scalar
        Estimate of edge stdev.
    cyx : length 2 iterable or None
        Centre coordinates of disc. If None, these are calculated.
    r : scalar or None
        Disc radius in pixels. If None, the value is calculated.
    use_hyperspy : bool
        If True, HyperSpy is used for fitting and plotting. If False,
        scipy and matplotlib are used.
    plot : bool
        Determines if images are plotted.
    
    Returns
    -------
    sigma_wt_avg : scalar
        Average sigma value, weighted if possible by fit error.
    sigma_wt_std : scalar
        Average sigma standard deviation, weighted if possible by fit error.
        Nan if no weighting is posible.
    sigma_std : scalar
        Standard deviation of all sigma values.
    (sigma_vals, sigma_stds) : tuple of 1-D arrays
        Sigma values and standard deviations from fit.
    
    Notes
    -----
    `sigma` is used for initial value and for setting range of fit.
    Increasing value widens region fitted to.
    
    Examples
    --------
    >>> import fpd
    >>> import matplotlib.pylab as plt
    >>>
    >>> plt.ion()
    >>>
    >>> im = fpd.synthetic_data.disk_image(intensity=16, radius=32, sigma=5.0, size=256, noise=True)
    >>> cyx, r = fpd.fpd_processing.find_circ_centre(im, 2, (22, int(256/2.0), 1), spf=1, plot=False)
    >>>
    >>> returns = fpd.fpd_processing.disc_edge_sigma(im, sigma=6, cyx=cyx, r=r, plot=True)
    >>> sigma_wt_avg, sigma_wt_std, sigma_std, (sigma_vals, sigma_stds) = returns

    '''
    

    detY, detX = im.shape
    
    if cyx is None or r is None:
        cyx_, r_ = fpdp_new.find_circ_centre(im, 2, (3, int(detY / 2.0), 1), spf=1, plot=plot, widget=widget)
    if cyx is None:
        cyx = cyx_
    if r is None:
        r = r_
    cy, cx = cyx
    
    # set up coordinated
    yi, xi = np.indices((detY, detX), dtype=float)
    yi-=cy
    xi-=cx
    ri2d = (yi**2+xi**2)**0.5
    ti2d = np.arctan2(yi, xi)

    interp_pix = 0.25   # interpolation resolution
    rr, tt = np.meshgrid(np.arange(0, 2.5*r, interp_pix), 
                         np.arange(-180,180,1*4)/180.0*np.pi, 
                         indexing='ij')
    xx = rr*np.sin(tt)+cx
    yy = rr*np.cos(tt)+cy

    # MAP TO RT  
    rt_val = sp.ndimage.interpolation.map_coordinates(im.astype(float), 
                                                      np.vstack([yy.flatten(), xx.flatten()]) )
    rt_val = rt_val.reshape(rr.shape)

    if plot:
        if widget is not None:
            fig = widget.setup_docking("Aperture")
            ax = fig.get_fig().subplots()
            ax.matshow(rt_val)
            docked = widget.setup_docking("", "Top", figsize=(6, 8))
            fig = docked.get_fig()
            fig.clf()
            ax = fig.subplots(1, 1)
            f = fig.canvas

            ax.plot(rt_val[:,::18])
            ax.set_xlabel('Interp pixels')
            ax.set_ylabel('Intensity')

        else:
            plt.matshow(rt_val)
            plt.figure()
            plt.plot(rt_val[:,::18])
            plt.xlabel('Interp pixels')
            plt.ylabel('Intensity')
    
    
    # Fit edge
    der = -np.diff(rt_val, axis=0)
    
    # fit range
    ri2d_edge_min = np.concatenate((ri2d[[0, -1], :], ri2d[:, [0, -1]].T), axis=1).min()
    rmin = max( (r-3*sigma), 0 )
    rmax = min( (r+3*sigma), ri2d_edge_min )
    
    if use_hyperspy:
        from hyperspy.signals import EELSSpectrum
        from hyperspy.component import Component
        s = EELSSpectrum(rt_val.T)
        #s.align1D()
        #s.plot()
        
        s_av = s#.sum(0)
        #s_av.plot()
    
        s_av.metadata.set_item("Acquisition_instrument.TEM.Detector.EELS.collection_angle", 1)
        s_av.metadata.set_item("Acquisition_instrument.TEM.beam_energy ", 1)
        s_av.metadata.set_item("Acquisition_instrument.TEM.convergence_angle", 1)
    
        m = s_av.create_model(auto_background=False)
    
        # http://hyperspy.org/hyperspy-doc/v0.8/user_guide/model.html   
        class My_Component(Component):
            """
            """
            def __init__(self, origin=0, A=1, sigma=1):
                # Define the parameters
                Component.__init__(self, ('origin', 'A', 'sigma'))
                #self.name = 'Erf'

                # Optionally we can set the initial values
                self.origin.value = origin
                self.A.value = A
                self.sigma.value = sigma

            # Define the function as a function of the already defined parameters, x
            # being the independent variable value
            def function(self, x):
                p1 = self.origin.value
                p2 = self.A.value
                p3 = self.sigma.value
                #return p1 + x * p2 + p3
                return p2*( sp.special.erf( (x-p1)/(np.sqrt(2)*p3) )+1.0 ) /2.0

        g = My_Component()
        m.append(g)
        
        # set defaults
        sigma = sigma
        m.set_parameters_value('sigma',  sigma/interp_pix, component_list=[g])
        m.set_parameters_value('A', -np.percentile(rt_val, 90), component_list=[g])
        m.set_parameters_value('origin', r/interp_pix, component_list=[g])
        
        # set fit range
        m.set_signal_range(rmin/interp_pix, rmax/interp_pix)
        
        m.multifit()
        if plot:
            m.plot()

        sigma_vals = np.abs(g.sigma.map['values'])*interp_pix
        sigma_stds = np.abs(g.sigma.map['std'])*interp_pix
    else:
        # non-hyperspy
        from scipy.optimize import curve_fit
        
        def function(x, p1, p2, p3):
            #p1, p2, p3 = origin, A, sigma
            return p2*( sp.special.erf( (x-p1)/(np.sqrt(2)*p3) )+1.0 ) /2.0
        
        # fit range
        x = np.arange(len(rt_val))
        xmin, xmax = rmin/interp_pix, rmax/interp_pix
        b = np.logical_and(x >= xmin, x <= xmax) 
        
        p0 = (r/interp_pix, -np.percentile(rt_val, 90), sigma/interp_pix)
        popts = []
        perrs = []
        for rt_vali in rt_val.T:
            yi = rt_vali[b]
            xi = x[b]
            popt, pcov = curve_fit(f=function, xdata=xi, ydata=yi, p0=p0)
            perr = np.sqrt(np.diag(pcov))
            
            popts.append(popt)
            perrs.append(perr)
        popts = np.array(popts)
        perrs = np.array(perrs)
        
        sigma_vals = np.abs(popts[:, 2])*interp_pix
        sigma_stds = np.abs(perrs[:, 2])*interp_pix
        
        if plot:
            A = np.percentile(popts[:, 1], 50)
            fits = np.array([function(x, *pi) for pi in popts])
            
            inds = np.arange(len(sigma_vals))[::10]
            if widget is not None:
                docked = widget.setup_docking("", "Top", figsize=(6,8))
                fig = docked.get_fig()
                fig.clf()
                ax = fig.subplots(1, 1)
                f = fig.canvas
            else:
                f, ax = plt.subplots(1, 1, figsize=(6, 8))
            pad = 0.2 * A
            for j,i in enumerate(inds):
                ax.plot(x, rt_val[:, i] + pad*j, 'x')
                ax.plot(x[b], fits[i][b] + pad*j, 'b-')
            pass
    
    # calculate averages
    sigma_std = sigma_vals.std()
    
    err_is = np.where(np.isfinite(sigma_stds))[0]
    if err_is.size > 1:
        if logger is not None:
            logger.log('Calculating weighted average...')
        else:
            print('Calculating weighted average...')
        vs = sigma_vals[err_is]
        ws = 1.0/sigma_stds[err_is]**2
        sigma_wt_avg = (vs*ws).sum()/ws.sum()
        sigma_wt_std = (1.0/ws.sum())**0.5
    else:
        if logger is not None:
            logger.log('Calculating unweighted average...')
        else:
            print('Calculating unweighted average...')

        sigma_wt_avg = sigma_vals.mean()
        sigma_wt_std = np.nan
    
    
    
    sigma_pcts = np.percentile(sigma_vals, [10, 50, 90])
    if logger is not None:
        logger.log('Avg: %0.3f +/- %0.3f' % (sigma_wt_avg, sigma_wt_std))
        logger.log('Std: %0.3f' % (sigma_std))
        logger.log('Percentiles (10, 50, 90): %0.3f, %0.3f, %0.3f' % tuple(sigma_pcts))
    else:
        print('Avg: %0.3f +/- %0.3f' % (sigma_wt_avg, sigma_wt_std))
        print('Std: %0.3f' % (sigma_std))
        print('Percentiles (10, 50, 90): %0.3f, %0.3f, %0.3f' %tuple(sigma_pcts))
    
    return(sigma_wt_avg, sigma_wt_std, sigma_std, (sigma_vals, sigma_stds))
Beispiel #15
0
def test_eels():
    s = EELSSpectrum(([0, 1]))
    s0 = s.deepcopy()
    s.axes_manager[0].convert_to_non_uniform_axis()
    with pytest.raises(NotImplementedError):
        s.align_zero_loss_peak()
    with pytest.raises(NotImplementedError):
        s.create_model(ll=s)
    with pytest.raises(NotImplementedError):
        s.fourier_log_deconvolution(0)
    with pytest.raises(NotImplementedError):
        s.fourier_ratio_deconvolution(s)
    with pytest.raises(NotImplementedError):
        s.fourier_ratio_deconvolution(s0)
    with pytest.raises(NotImplementedError):
        s0.fourier_ratio_deconvolution(s)
    with pytest.raises(NotImplementedError):
        s.richardson_lucy_deconvolution(s)
    with pytest.raises(NotImplementedError):
        s.kramers_kronig_analysis()
    m = s.create_model()
    g = EELSCLEdge('N_K')
    with pytest.raises(NotImplementedError):
        m.append(g)
Beispiel #16
0
def get_core_loss_eels_signal(add_powerlaw=False):
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Some random noise is also added to the spectrum, to simulate
    experimental noise.

    Parameters
    ----------
    add_powerlaw : bool
        If True, adds a powerlaw background to the spectrum.
        Default False.

    Returns
    -------
    artificial_core_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> import hs.datasets.artifical_data as ad
    >>> s = ad.get_core_loss_eels_signal()
    >>> s.plot()

    With the powerlaw background

    >>> s = ad.get_core_loss_eels_signal(add_powerlaw=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> np.random.seed(seed=10)
    >>> s1 = ad.get_core_loss_eels_signal()
    >>> np.random.seed(seed=10)
    >>> s2 = ad.get_core_loss_eels_signal()
    >>> (s1.data == s2.data).all()
    True

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """
    x = np.arange(400, 800, 1)
    arctan = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    data += np.random.random(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s