Exemple #1
0
def fermi_edge(E, E_f, dE, c, d):
    """
    The typical shape of a fermi edge for constant DOS. Suitable as a fit function, therefore it takes only floats,
    no quantities.

    :param E: The x-Axis of the data consists of energies in eV

    :param E_f: The Fermi energy in eV.

    :param dE: Energy Resolution. The broadening of the Fermi edge on top of the thermal broadening,
        which is introduced by all experimental errors, in eV.

    :param c: The height of the Fermi edge, in whichever units the data is given, e.g. "counts".

    :param d: Offset of the lower level of the fermi edge, e.g. "dark counts".

    :return: The value of the Fermi distribution at the energy E.
    """
    E = u.to_ureg(E, 'eV').magnitude
    E_f = u.to_ureg(E_f, 'eV').magnitude
    dE = u.to_ureg(dE, 'eV').magnitude
    c = u.to_ureg(c)
    d = u.to_ureg(d)
    return 0.5 * (1 + scipy.special.erf((E_f - E) / (np.sqrt((
        (1.7 * kBT_in_eV.magnitude)**2) + dE**2) * np.sqrt(2)))) * c + d
Exemple #2
0
    def __init__(self, name, epsilon=1., n=1.):
        """
		The constructor.
		Can be initialized with an epsilon or an n value. If you give neither, you'll end up with Vacuum.
		All values can be complex.

		:param name: The name of the material. E.g. ITO

		:param epsilon: The relative dielectric constant of the medium.

		:param n: The refraction index,

		:return: nothing
		"""
        self.name = name
        epsilon = u.to_ureg(epsilon, 'dimensionless')
        n = u.to_ureg(n, 'dimensionless')
        if epsilon != 1.:
            self.dielconstant = epsilon
            self.refracindex = numpy.sqrt(epsilon)
        elif n != 1.:
            self.dielconstant = n**2
            self.refracindex = n
        else:
            self.dielconstant = 1.0 * u.ureg('dimensionless')
            self.refracindex = 1.0 * u.ureg('dimensionless')
Exemple #3
0
    def fit_fermi_edge(energies, intensities, guess=None):
        """
		This function fits a fermi edge to data. Uses numpy.optimize.curve_fit under the hood.

		:param energies: A quantity or array of energies. If no quantity, electronvolts are assumed.

		:param intensities: Quantity or array: The corresponding intensity values to powers.

		:param guess: optional: A tuple of start parameters (E_f, dE, c, d) as defined in fermi_edge method.

		:return: The coefficients and uncertainties of the fitted fermi edge E_f, dE, c, d, as defined in fermi_edge
			method.
		"""
        if u.is_quantity(energies):
            assert u.same_dimension(energies, "eV")
            energies = u.to_ureg(energies)
        else:
            energies = u.to_ureg(energies, 'eV')
        intensities = u.to_ureg(intensities)
        if guess is None:
            guess = (29.6, 0.1, 1.0, 0.01)  # Just typical values
        else:  # to assure the guess is represented in the correct units:
            energyunit = energies.units
            countsunit = intensities.units
            unitslist = [energyunit, energyunit, countsunit, countsunit]
            guesslist = []
            for guesselement, guessunit in zip(guess, unitslist):
                guesslist.append(u.to_ureg(guesselement, guessunit).magnitude)
            guess = tuple(guess)
        return curve_fit(fermi_edge, energies.magnitude, intensities.magnitude,
                         guess)
Exemple #4
0
    def __init__(self, sampling_delta, lowcut=None, highcut=None, order=5):
        """
        The initializer of the Butterfilter. All "time and frequency" parameters can and should be given as quantities.
        If raw numerical data is given, it still works, but all values are assumed as dimensionless.

        :param sampling_delta: The spacing of the axis along which to filter the data.
        :type sampling_delta: `pint.Quantity`

        :param lowcut: The low cut, below which the frequency response is faded out.
        :type lowcut: `pint.Quantity`

        :param highcut: The high cut, below which the frequency response is faded out.
        :type highcut: `pint.Quantity`

        :param order: The order of the filter, see scipy docs. If the frequency response looks bad, try increasing this.
        :type order: int
        """
        # Parse Arguments:
        sampling_delta = u.to_ureg(sampling_delta)
        if (lowcut is not None) and (highcut is not None):
            highcut = u.to_ureg(highcut)
            lowcut = u.to_ureg(lowcut)
            assert lowcut.units == highcut.units, "Low and Highcut must be given in same units."
            self.freq_unit = lowcut.units
        elif highcut is not None:
            highcut = u.to_ureg(highcut)
            self.freq_unit = highcut.units
        elif lowcut is not None:
            lowcut = u.to_ureg(lowcut)
            self.freq_unit = lowcut.units
        else:
            raise ValueError("Cannot define filter without high or lowcut.")

        nyq = (1 / (2 * sampling_delta)).to(self.freq_unit)
        self.highcut, self.lowcut = highcut, lowcut
        # Define filters:
        if (lowcut is not None) and (highcut is not None):  # bandpass
            low = lowcut / nyq
            high = highcut / nyq
            # noinspection PyTupleAssignmentBalance,PyTupleAssignmentBalance
            b, a = signal.butter(order, [low, high], btype='band')
        elif lowcut is not None:  # highpass
            low = lowcut / nyq
            # noinspection PyTupleAssignmentBalance
            b, a = signal.butter(order, low, btype='high')
        elif highcut is not None:  # lowpass
            high = highcut / nyq
            # noinspection PyTupleAssignmentBalance
            b, a = signal.butter(order, high, btype='low')
        else:
            raise ValueError("Cannot define filter without high or lowcut.")
        self.b, self.a = b, a
        self.sampling_delta = sampling_delta
        self.order = order
Exemple #5
0
def Kspp(omega, metal=default_metal, diel=default_diel, unit='1/um'):
    omega = u.to_ureg(omega, 'rad/s', convert_quantities=False)
    assert isinstance(metal, snomtools.calcs.materials.metals.Metal
                      ), "ERROR: No metal given to Kspp"
    assert isinstance(diel, snomtools.calcs.materials.dielectrics.Dielectric
                      ), "ERROR: No dielectric given to Kspp"

    wurzel = numpy.sqrt((metal.epsilon(omega) * diel.epsilon(omega)) /
                        (metal.epsilon(omega) + diel.epsilon(omega)))
    k = omega / const.c * numpy.real(wurzel)
    k = u.to_ureg(k, unit)
    return k
Exemple #6
0
    def __init__(self, plasma_freq, damping_freq, central_freq):
        """
		The constructor. All frequencies should be given as angular frequencies (rad/s)

		:param plasma_freq: the (quasi-)plasma frequency of the bound electrons

		:param damping_freq: the damping frequency of the bound electrons

		:param central_freq: the central frequency of the interband transition
		"""
        self.omega_p = units.to_ureg(plasma_freq, 'rad/s')
        self.gamma = units.to_ureg(damping_freq, 'rad/s')
        self.omega_0 = units.to_ureg(central_freq, 'rad/s')
Exemple #7
0
    def filteredslice(self, s, component, df=0):
        """
        Filtered slice of the instance input data.

        :param s: A slice addressing a region of the data to return.
            Can be conveniently made with `numpy.s_[]`.
        :type s: slice

        :param component: The frequency component to return.
        :type component: int

        :param df: The DataArray in the given DataSet to filter, can be specified if multiple are present.
            Given as a valid identifier (index or label).
        :type df: int or str

        :return: The filtered data.
        :rtype: numpy.ndarray
        """
        s = full_slice(s, self.indata.dimensions)
        if s[self.filter_axis_id] != np.s_[:]:
            warnings.warn(
                "Frequency filtering a slice that is not full along the filter axis might return bad results"
            )
        df_in = self.indata.get_datafield(df)
        timedata = df_in.data[s]
        filtered_data = self.butters[component].filtered(
            timedata, axis=self.filter_axis_id)
        return u.to_ureg(filtered_data, df_in.get_unit())
Exemple #8
0
    def guess_parameters(energies, intensities):
        # ToDo: This just takes the 10%-edges of the value range, this could be improved with some cool statistics.
        i_min = min(intensities)
        i_max = max(intensities)
        i_range = i_max - i_min

        # Take the 10%-values from the edge as low and high:
        low_level = i_min + 0.1 * i_range
        high_level = i_max - 0.1 * i_range

        # As a guess for the edge position,
        # take the mean index of the 5% closest values to the middle between high and low:
        n_mean_index = min(int(round(len(energies) * 0.05)), 1)
        middle_index = int(
            np.round(
                np.mean(
                    np.argsort(
                        np.abs(intensities -
                               (high_level - low_level) / 2))[:n_mean_index])))

        guess = (energies[middle_index], u.to_ureg(0.1, 'eV'),
                 high_level - low_level, low_level)
        if verbose:
            print("Guessing start parameters for Fermi Fit: {0}", guess)
        return guess
Exemple #9
0
    def fftslice(self, s, df=0):
        """
        Get the fourier-transformed data of a specific slice of a DataArray of the instance input.

        :param s: The slice, addressing a selection of the instance input data.
            Can be conveniently made with `numpy.s_[]`.
        :type s: slice

        :param df: An identifier (index or label) of the DataArray to transform.
        :type df: int or str

        :return: The fourier-transformed data for the selection.
        :rtype: pint.Quantity
        """
        s = full_slice(s, self.indata.dimensions)
        if s[self.axis_to_transform_id] != np.s_[:]:
            warnings.warn(
                "FFT of a slice that is not full along the FFT axis might return bad results"
            )
        df_in = self.indata.get_datafield(df)
        timedata = df_in.data[s].magnitude
        freqdata = fftpack.fftshift(fftpack.fft(
            timedata, axis=self.axis_to_transform_id),
                                    axes=self.axis_to_transform_id)
        return u.to_ureg(freqdata, df_in.get_unit())
Exemple #10
0
def show_state_parabola(dispersion_data, guess_origin=None, guess_mass=None, guess_energyoffset=None,
                        k_axisid='k_y'):
    """
    Calculates a free electron like parabola for a intermediate state with given parameters. Returns a tuple of x (k||)
    and y (energy) values, that can be used for plotting. Useful for finding out the specific band mass.

    :param dispersion_data: 2D-DataSet with an energy and a k-space dimension.
    :type dispersion_data: ds.DataSet

    :param guess_origin: The origin k value of the parable, given in ``1/angstrom``.
    :type guess_origin: pint.Quantity **or** float, optional

    :param guess_mass: The bandmass of the intermediate state you are interested. Typically given in
        units of m_e (electronmass).
    :type guess_mass: pint.Quantity **or** float, optional

    :param guess_energyoffset: The origin of the parable on the energy axis. Typically, something like the drift
        voltage in PEEM.
    :type guess_energyoffset: pint.Quantity **or** float, optional

    :param k_axisid: The name (label) of the k-axis of the data. Default: ``y``
    :type k_axisid: str

    :return: The adjusted free electron like parabola  as a tuple of x and y values (k, parab_data) for plotting and
        the corresponding bandmass, used in the plot. Bandmass is  typically given in units of ``m_e`` (electronmass).
    """
    # Define parabola and parameters for fit
    if guess_energyoffset is None:
        energy_offset = u.to_ureg(30, "eV")
    else:
        energy_offset = u.to_ureg(guess_energyoffset, "eV")
    k = dispersion_data.get_axis(k_axisid).data
    if guess_origin is None:
        origin = k.mean()
    else:
        origin = u.to_ureg(guess_origin, "1/angstrom")
    if guess_mass is None:
        bandmass = u.to_ureg(1, "m_e")
    else:
        bandmass = u.to_ureg(guess_mass, "m_e")

    # Calculate a parabola with set electronmass
    parab_data = bandDispersionRelation(k, bandmass, origin, energy_offset)

    return (k, parab_data), bandmass
Exemple #11
0
def kscale_axes(data, yscalefactor, xscalefactor, yzero=None, xzero=None, y_axisid='y', x_axisid='x'):
    """
    Scales the x- and y-axis of a given set of dldpixels from an nD-Dataset to k-space, depending on a before
    determined scalefactor.

    :param data: nD-DataSet with y-pixel, x-pixel, and possibly other dimensions.
    :type data: ds.DataSet

    :param yscalefactor: The scalefactor translating unscaled ky-axis units to k-space. Typically given in
        ``angstrom**-1 per pixel``.
    :type yscalefactor: pint.Quantity

    :param xscalefactor: The scalefactor translating unscaled kx-axis units to k-space. Typically given in
        ``angstrom**-1 per pixel``.
    :type xscalefactor: pint.Quantity

    :param yzero: The offset of the Gamma-point in k_y direction, given in unscaled units (typically pixels).
    :type yzero: pint.Quantity, optional

    :param xzero: The offset of the Gamma-point in k_x direction, given in unscaled units (typically pixels).
    :type xzero: pint.Quantity, optional

    :param y_axisid: The name (label) of the x-axis of the data. Default: ``y``
    :type y_axisid: str

    :param x_axisid: The name (label) of the y-axis of the data. Default: ``x``
    :type x_axisid: str

    :return: The k-scaled 4D-Dataset.
    :rtype: ds.DataSet
    """
    if yzero is None:
        yzero = data.get_axis(y_axisid).mean()
    else:
        yzero = u.to_ureg(yzero, data.get_axis(y_axisid).units)
    data.get_axis(y_axisid).scale_linear(yscalefactor, yscalefactor * (-yzero), 'angstrom**-1',
                                         label='k_y',
                                         plotlabel="k_y / Angstroem^-1")
    if xzero is None:
        xzero = data.get_axis(x_axisid).mean()
    else:
        xzero = u.to_ureg(xzero, data.get_axis(x_axisid).units)
    data.get_axis(x_axisid).scale_linear(xscalefactor, xscalefactor * (-xzero), 'angstrom**-1',
                                         label='k_x',
                                         plotlabel="k_x / Angstroem^-1")
Exemple #12
0
    def from_xy(cls, energies, intensities, guess):
        if u.is_quantity(energies):
            assert u.same_dimension(energies, "eV")
            energies = u.to_ureg(energies)
        else:
            energies = u.to_ureg(energies, 'eV')
        intensities = u.to_ureg(intensities)

        energyunit = str(energies.units)
        countsunit = str(intensities.units)

        f = cls()
        f.coeffs, f.accuracy = cls.fit_fermi_edge(energies, intensities, guess)
        f.E_f_unit = energyunit
        f.dE_unit = energyunit
        f.c_unit = countsunit
        f.d_unit = countsunit
        return f
Exemple #13
0
def powerlaw_folder_peem_dld(folderpath,
                             pattern="mW",
                             powerunit=None,
                             powerunitlabel=None):
    """

	:param folderpath: The (relative or absolute) path of the folders containing the powerlaw measurement series.

	:param pattern: string: A pattern the powers in the filenames are named with. For example in the default case
		"mW", the filename containing '50,2mW' or '50.2mW' or '50.2 mW' would accord to a power of 50.2 milliwatts. The
		power units for the axis quantities are also cast from this pattern if not explicitly given with powerunit.

	:param powerunit: A valid unit string that will be cast as the unit for the power axis values. If not given,
		the pattern parameter will be cast as unit.

	:param powerunitlabel: string: Will be used as the unit for the power axis plotlabel. Can be for example a LaTeX
		siunitx command. If not given, the powerunit parameter will be used.

	:return: The dataset containing the images stacked along a power axis.
	"""
    if powerunit is None:
        powerunit = pattern
    if powerunitlabel is None:
        powerunitlabel = powerunit
    pat = re.compile('(\d*[,|.]?\d+)\s?' + pattern)

    # Translate input path to absolute path:
    folderpath = os.path.abspath(folderpath)

    # Inspect the given folder for the tif files of the powerlaw:
    powerfiles = {}
    for filename in filter(is_tif, os.listdir(folderpath)):
        found = re.search(pat, filename)
        if found:
            power = float(found.group(1).replace(',', '.'))
            powerfiles[power] = filename

    axlist = []
    datastack = []
    for power in iter(sorted(powerfiles.keys())):
        datastack.append(
            peem_dld_read_terra(os.path.join(folderpath, powerfiles[power])))
        axlist.append(power)
    powers = u.to_ureg(axlist, powerunit)

    pl = 'Power / ' + powerunitlabel  # Plot label for power axis.
    poweraxis = snomtools.data.datasets.Axis(powers,
                                             label='power',
                                             plotlabel=pl)

    return snomtools.data.datasets.stack_DataSets(datastack,
                                                  poweraxis,
                                                  axis=-1,
                                                  label="Powerlaw " +
                                                  folderpath)
Exemple #14
0
def energy_scale_linear(channel_axis, a, b):
    """
	Energy scaling calculated for the time channel axis of a DataSet containing DLD PEEM data, Linear version.

	:param channel_axis: The Axis instance containing the channel numbers as data.

	:param a: The fit parameter a as in the energy calibration files from Terra (.kalfit.txt).

	:param b: The fit parameter b as in the energy calibration files from Terra (.kalfit.txt).

	:return: A new Axis instance with energy scaling, that can replace the channel axis in the DataSet.
	"""
    a = u.to_ureg(a, 'eV')
    b = u.to_ureg(b, 'eV')
    channels = channel_axis.get_data()
    energy_points = a * channels + b
    return snomtools.data.datasets.Axis(
        energy_points,
        label="energy",
        plotlabel="Electron Energy / \\si{\electronvolt}")
Exemple #15
0
def energy_scale_quadratic(channel_axis, C, t_0):
    """
	Energy scaling calculated for the time channel axis of a DataSet containing DLD PEEM data, Quadratic version.

	:param channel_axis: The Axis instance containing the channel numbers as data.

	:param C: The fit parameter C as in the energy calibration files from Terra (.kalfit.txt).

	:param t_0: The fit parameter C as in the energy calibration files from Terra (.kalfit.txt).

	:return: A new Axis instance with energy scaling, that can replace the channel axis in the DataSet.
	"""
    t_0 = u.to_ureg(t_0, '')
    c_square = u.to_ureg(C**2, 'eV')
    channels = channel_axis.get_data()
    energy_points = c_square / (channels - t_0)**2
    return snomtools.data.datasets.Axis(
        energy_points,
        label="energy",
        plotlabel="Electron Energy / \\si{\electronvolt}")
Exemple #16
0
def Vspp(omega, metal=default_metal, diel=default_diel, unit='m/s'):
    omega = u.to_ureg(omega, 'rad/s', convert_quantities=False)
    assert isinstance(metal, (snomtools.calcs.materials.metals.Metal,
            snomtools.calcs.materials.literature.Literature_Material)), \
     "ERROR: No metal given to Vspp"
    assert isinstance(diel, snomtools.calcs.materials.dielectrics.Dielectric
                      ), "ERROR: No dielectric given to Vspp"

    wurzel = numpy.sqrt((metal.epsilon(omega) * diel.epsilon(omega)) /
                        (metal.epsilon(omega) + diel.epsilon(omega)))
    return const.c / wurzel
Exemple #17
0
    def from_coeffs(cls, coeffs, energyunit='eV', countsunit=None):
        # Parse input and handle units:
        E_f, d_E, c, d = coeffs
        E_f = u.to_ureg(E_f, energyunit)
        d_E = u.to_ureg(d_E, energyunit)
        c = u.to_ureg(c, countsunit)
        d = u.to_ureg(d, countsunit)

        # Prepare variables:
        energyunit = str(E_f.units)
        countsunit = str(c.units)
        coeffs = (E_f.magnitude, d_E.magnitude, c, d)

        # Make instance:
        f = cls()
        f.coeffs = coeffs
        f.E_f_unit = energyunit
        f.dE_unit = energyunit
        f.c_unit = countsunit
        f.d_unit = countsunit
        return f
Exemple #18
0
    def n(self, omega=0.):
        """
		The complex refraction index of the medium.

		:param omega: just for compatibility with the metal function, and for determining the output type.

		:return: the refraction index. will be the same type as omega
		"""
        omega = u.to_ureg(omega, 'THz')  # Just to check if input is valid.
        omega = omega.magnitude  # For addition with dimensionless epsilon
        myn = omega * 0 + self.refracindex  # to conserve format of input array
        return myn
Exemple #19
0
    def epsilon(self, omega=0):
        """
		The dielectric constant of the medium.

		:param omega: just for compatibility with the metal function, and for determining the output type.

		:return: the dielectric function. will be the same type as omega
		"""
        omega = u.to_ureg(omega, 'THz')  # Just to check if input is valid.
        omega = omega.magnitude  # For addition with dimensionless epsilon
        eps = omega * 0 + self.dielconstant  # to conserve format of input array
        return eps
Exemple #20
0
def fit_xy_linear(xdata, ydata):
    """
	A simple linear fit to data given as x and y values. Fits y = m*x + c and returns c tuple of (m, c), where m and
	c are quantities according to the physical dimensions of data. Numerical data is assumed as dimensionless.

	:param xdata: DataArray or Quantity or numpy array: The x values.

	:param ydata: DataArray or Quantity or numpy array: The y values.

	:return:tuple: (m, c)
	"""
    if isinstance(xdata, snomtools.data.datasets.DataArray):
        xdata = xdata.get_data()
    else:
        xdata = u.to_ureg(xdata)
    if isinstance(ydata, snomtools.data.datasets.DataArray):
        ydata = ydata.get_data()
    else:
        ydata = u.to_ureg(ydata)
    xdata = snomtools.data.tools.assure_1D(xdata)
    ydata = snomtools.data.tools.assure_1D(ydata)

    m, c = numpy.polyfit(xdata.magnitude, ydata.magnitude, deg=1, full=False)

    one_xunit = u.to_ureg(str(xdata.units))
    one_yunit = u.to_ureg(str(ydata.units))
    m = u.to_ureg(m, one_yunit / one_xunit)
    c = u.to_ureg(c, one_yunit)
    return m, c
Exemple #21
0
    def fit_powerlaw(powers, intensities, guess=None):
        """
		This function fits a powerlaw to data.

		:param powers: A quantity or array of powers. If no quantity, milliwatts are assumed.

		:param intensities: Quantity or array: The corresponding intensity values to powers.

		:return: The powerlaw coefficients of the fitted polynom.
		"""
        if u.is_quantity(powers):
            assert u.same_dimension(powers, "watts")
            powers = u.to_ureg(powers)
        else:
            powers = u.to_ureg(powers, 'mW')
        intensities = u.to_ureg(intensities)

        if guess is None:
            guess_amplitude = 1.
            guess_exponent = 2.
            guess_offset = min(intensities).magnitude
        else:
            assert len(guess) == 3
            guess_amplitude = u.to_ureg(guess[0], str(powers.units)).magnitude
            guess_exponent = u.to_ureg(guess[1], 'dimensionless').magnitude
            guess_offset = u.to_ureg(guess[2], str(powers.units)).magnitude
        guess = (guess_amplitude, guess_exponent, guess_offset)

        return scipy.optimize.curve_fit(Powerlaw.fitfunction,
                                        powers.magnitude,
                                        intensities.magnitude,
                                        guess,
                                        maxfev=100000)
Exemple #22
0
    def fermi_edge(self, E):
        """
		The shape of a fermi edge for the known fit parameters of the Fermi_Edge instance.

		:param E: Electron Energy (Quantity or numerical in eV).

		:return: The value of the Fermi distribution at the energy E. Returned as Quantity in whichever unit the fit
			data was given.
		"""
        E = u.to_ureg(E, "eV")
        return 0.5 * (1 + scipy.special.erf(
            (self.E_f - E) /
            (np.sqrt(((1.7 * kBT_in_eV)**2) + self.dE**2) * np.sqrt(2)))
                      ) * self.c + self.d
Exemple #23
0
    def fit_powerlaw(powers, intensities):
        """
		This function fits a powerlaw to data.

		:param powers: A quantity or array of powers. If no quantity, milliwatts are assumed.

		:param intensities: Quantity or array: The corresponding intensity values to powers.

		:return: The powerlaw coefficients of the fitted polynom.
		"""
        if u.is_quantity(powers):
            assert u.same_dimension(powers, "watts")
            powers = u.to_ureg(powers)
        else:
            powers = u.to_ureg(powers, 'mW')
        intensities = u.to_ureg(intensities)

        # Do the fit with numpy.ma functions to ignore invalid numbers like log(0)
        # (these occur often when using dark count subtraction)
        return numpy.ma.polyfit(numpy.ma.log(powers.magnitude),
                                numpy.ma.log(intensities.magnitude),
                                deg=1,
                                full=False)
Exemple #24
0
def show_kscale(dispersion_data, guess_zeropixel=None, guess_scalefactor=None, guess_energyoffset=None,
                guess_kfov=None, k_axisid='y'):
    """
    Calculates a free electron parabola with given parameters to approximate a photoemission horizon. Returns a tuple
    of x (x-pixels) and y (energy) values, that can be used for plotting.  Useful to test k scale.

    :param dispersion_data: 2D-DataSet with an energy and a k-space dimension.
    :type dispersion_data: ds.DataSet

    :param guess_zeropixel: The origin pixel value of the parable, given in pixels or unscaled k-axis units.
    :type guess_zeropixel: pint.Quantity **or** float, optional

    :param guess_scalefactor: The scalefactor translating unscaled k-axis units to k-space. Typically given in
        ``angstrom**-1 per pixel``. Alternatively, ``guess_kfov`` can be used to give full kspace width instead,
        see below.
    :type guess_scalefactor: pint.Quantity **or** float, optional

    :param guess_energyoffset: The origin of the parable on the energy axis. Typically, something like the drift
        voltage in PEEM.
    :type guess_energyoffset: pint.Quantity **or** float, optional

    :param guess_kfov: Only used if ``guess_scalefactor`` is not given. Then, this can be given (in ``angstrom**-1``)
        to guess the kspace-Field-of-View (full kspace image width) instead of a factor per pixel.
        If neither ``guess_scalefactor`` or this parameter are given, a generic value for ``guess_kfov`` of
        ``1.5 angstrom**-1`` is used.
    :type guess_kfov: pint.Quantity **or** float, optional

    :param k_axisid: The name (label) of the k-axis of the data. Default: ``y``
    :type k_axisid: str

    :return: parab_data, scalefactor & zeropixel with parab_data being the calculated free electron parabola. As
        scalefactor & zeropoint are just the replicated input parameters, it can be ignored or used for info/debugging.
        The scalefactor is typically given in unit ``1/angstrom per pixel`` and the zeropoint in unit ``pixel``
    """
    # Define parabola and parameters for fit
    if guess_energyoffset is None:
        energy_offset = u.to_ureg(30, "eV")
    else:
        energy_offset = u.to_ureg(guess_energyoffset, "eV")
    dldpixels = dispersion_data.get_axis(k_axisid).data
    if guess_zeropixel is None:
        zeropoint = dldpixels.mean()
    else:
        zeropoint = u.to_ureg(guess_zeropixel, "pixel")
    if guess_kfov is None:
        guess_kfov = u.to_ureg(1.5, "1/angstrom")
    else:
        guess_kfov = u.to_ureg(guess_kfov, "1/angstrom")
    if guess_scalefactor is None:
        scalefactor = guess_kfov / (dldpixels.max() - dldpixels.min())
    else:
        scalefactor = u.to_ureg(guess_scalefactor, "1/angstrom per pixel")

    # Calculate a free electron parabola with given parameters
    parab_data = freeElectronParabola(dldpixels, scalefactor, zeropoint, energy_offset)

    return (dldpixels, parab_data), scalefactor, zeropoint
Exemple #25
0
    def __init__(self,
                 name,
                 plasma_freq,
                 damping_freq,
                 interband_transitions=None):
        """
		The constructor.

		:param name: A string for the name of the material. e.g. "Au"

		:param plasma_freq: the plasma frequency of the free electrons in (rad/s)

		:param damping_freq: the damping frequency of the free electrons in (rad/s)

		:param interband_transitions: a list of interband transitions, given either as instance of the
			InterbandTransition class or as list or tuple of 3 elements containing the frequencies to initialize one.

		:return: nothing
		"""
        self.name = name
        self.omega_p = units.to_ureg(plasma_freq, 'rad/s')
        self.gamma = units.to_ureg(damping_freq, 'rad/s')
        self.interbands = []
        if interband_transitions:
            for trans in interband_transitions:
                if isinstance(trans, InterbandTransition):
                    self.interbands.append(trans)
                elif isinstance(
                        trans,
                        list) or isinstance(trans, tuple) and len(trans) == 3:
                    self.interbands.append(
                        InterbandTransition(trans[0], trans[1], trans[2]))
                else:
                    print(
                        "ERROR: Metal: Interband transition could not be cast. Ignoring the transition."
                    )
Exemple #26
0
    def __init__(self, data, angle, rot_plane_axes=(1, 0), axes_mode='keep'):
        # TODO: Implement other axes handling modes.
        assert isinstance(data, ds.DataSet) or isinstance(data, ds.ROI), "Invalid input data."
        self.data_original = data
        self.data_rotated = None
        self.angle = u.to_ureg(angle, 'degree')
        self.rot_plane = (self.data_original.get_axis_index(rot_plane_axes[0]),
                          self.data_original.get_axis_index(rot_plane_axes[1]))
        self.axes_mode = axes_mode

        # Interpolation settings:
        self.reshape = False
        self.order = 1
        self.mode = 'constant'
        self.cval = np.nan
        self.prefilter = False
Exemple #27
0
    def resultAC(self, s):
        """
        Return the autocorrelation trace according to the fit result for a specific slice.
        Can be used to compare the fit with the data.

        ..warning::
            This will throw an exception if the result doesn't exist yet.

        :param s: A slice addressing a single point on the result data.

        :return: A tuple of (Delays, Fitted Autocorrelation)
        :rtype: tuple(Quantity, Quantity)
        """
        if self.result is None:
            raise ValueError(
                "A result AC cannot be calculated without a result.")
        assert (self.result.get_datafield(0)[s].shape == ()
                ), "Trying to address multiple elements at once."

        # Set global variables for copypasted methods.
        global gpuOBE_stepsize
        gpuOBE_stepsize = self.cuda_IAC_stepsize.magnitude
        global gpuOBE_laserBlau
        gpuOBE_laserBlau = self.laser_lambda.magnitude
        global gpuOBE_LaserBlauFWHM
        gpuOBE_LaserBlauFWHM = self.laser_AC_FWHM.magnitude
        # gpuOBE_normparameter is used in TauACCopol to switch between normalizing the curve before scaling and offset.
        # It must be True to fit including Amplitude and Offset, as done below!
        global gpuOBE_normparameter
        gpuOBE_normparameter = True
        global gpuOBE_Phaseresolution
        gpuOBE_Phaseresolution = False

        ExpDelays = self.fitaxis.data.magnitude
        ac = TauACCoPol(
            ExpDelays,
            self.laser_lambda.magnitude,
            self.laser_AC_FWHM.magnitude,
            self.result.get_datafield('lifetimes').data[s].magnitude,
            self.result.get_datafield('amplitude').data[s].magnitude,
            self.result.get_datafield('offset').data[s].magnitude,
            self.result.get_datafield('center').data[s].magnitude,
            normparameter=True,
            Phase=False)
        return ExpDelays, u.to_ureg(ac, self.countunit)
Exemple #28
0
def fov_scale_absolute(pixel_axis, fov, unit='m'):
    """
	Transforms an Axis from pixels to a real space length from a known field of view.

	:param pixel_axis: The Axis to transform.

	:param fov: Quantity: The absolute size of the FoV. If a number instead of a quantity is given, m is assumed as
		unit.

	:param unit: String: Specifies the output unit for the Axis, Must evaluate to a length unit.

	:return: The converted Axis.
	"""
    assert isinstance(pixel_axis, snomtools.data.datasets.Axis
                      ), "No Axis instance given to scale function."
    length_per_pixel = fov / len(pixel_axis)
    length_per_pixel = u.to_ureg(length_per_pixel, 'meters/pixel')
    return pixel_axis.scale_linear(length_per_pixel, unit=unit)
Exemple #29
0
    def fermi_edge(self, E):
        """
        The shape of a fermi edge for the known fit parameters of the Fermi_Edge instance.
        This is the equivalent of the standalone `fermi_fit` function outside the class,
        only it is aware of the units of the class parameters.

        :param E: Electron Energy (Quantity or numerical in eV).

        :return: The value of the Fermi distribution at the energy E. Returned as Quantity in whichever unit the fit
            data was given.
        """
        E = u.to_ureg(E, self.E_f_unit)
        E_f = self.E_f
        dE = self.dE
        c = self.c
        d = self.d
        return 0.5 * (1 + scipy.special.erf(((E_f - E) / (np.sqrt((
            (1.7 * kBT_in_eV)**2) + dE**2) * np.sqrt(2))).magnitude)) * c + d
Exemple #30
0
def fov_scale_relative(pixel_axis, length_per_pixel, unit='m'):
    """
	Transforms an Axis from pixels to a real space length from a known length per pixel scaling.

	:param pixel_axis: The Axis to transform.

	:param length_per_pixel: Quantity: The relative scale in length per pixel. If a number instead of a quantity is
		given, m/pixel is assumed as unit.

	:param unit: String: Specifies the output unit for the Axis, Must evaluate to a length unit.

	:return: The converted Axis.
	"""
    assert isinstance(pixel_axis, snomtools.data.datasets.Axis
                      ), "No Axis instance given to scale function."
    length_per_pixel = u.to_ureg(length_per_pixel,
                                 'meters/pixel',
                                 convert_quantities=False)
    return pixel_axis.scale_linear(length_per_pixel, unit=unit)