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
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
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_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
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
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
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
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
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
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
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))
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)
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