Instrument

Added in version 2.0.0

The Instrument replaces the resolution and kernel_type attribures in the FitMeasurement class.

Since version 2.0.0 the class Instrument is used in Nexus to describe the influence of the instrument on the measurement. This includes for example the energy resolution of a Moessbauer source, the temporal resolution of a detector or the angular resolution of a setup. Especially for fitting of Synchrotron Moessbauer Source (SMS) data this is a great improvement since the energy resolution of the source can be described by a convolution with multiple or user-defined distributions.

An Insturment can have as many fit parameters as needed.

You can find a number of pre-defined instrument functions in the module nexus.lib.instrument or you can define your own instrument function. The follwoing examples show hot to use the Instrument class and how to define your own instrument function.

import nexus as nx
import numpy as np
import matplotlib.pyplot as plt

# Lorentzian lineshpae, e.g. a Moessbauer instrument
# loaded from library
# linewidth here is one Gamma
# this definition is enough to be used with the FitMeasurment classes
moessbauer_instrument = nx.lib.instrument.Lorentz(
    fwhm = 1.0,  # can also be a Var object
    relative_truncation_threshold = 0.0,  # default is 1e-3, with 0 no truncation is used
    norm_factor = 1.0)   # default is 1

# code to get the actual kernel shape
# grid for the calculation
detuning = np.linspace(-15, 15, 1001)  # detuing in Gamma

# the InstrumentFunction() calls the actual kernel implementation on the provided grid
kernel = moessbauer_instrument.InstrumentFunction(detuning)

# the kernel sum is normalized to the norm_factor
# with 1.0 it keeps the correct intensity of the theoretical curve.
print(np.sum(kernel))

#plotting the kernel
plt.plot(detuning, kernel)
plt.show()
../../_images/Lorentzian.png

The norm_factor accounts the scaling of the convoluted curve. With a factor of 1, the kernel is normalized to a sum of one and after convolution the intensity of the theoretical response of the sample is preserved. For energy spectra or time spectra this is the correct choice, as the intensity of the theoretical curve is determined by the sample properties and not by the instrument. The Lamb-Moessbauer factor of a Moessbauer source is not included in the kernel by default, as for data fitting the norm_factor behaves just like a scaling factor.

Intensities with a Moessbauer source

In case you want to calculate the absolute intensity behind a Moessbauer source correctly, the norm_factor has to be set to the Lamb-Moessbauer factor of the source. This corresponds to the transmission integral formalism (see also What Nexus calculates).

To define your own instrument function, you can inherit from the Instrument class.

# definition of the witch of Agnesi function with one fit parameter center_shift and one fixed parameter a
class InstrumentDefinedInPython(nx.Instrument):
    def __init__(self, id, center_shift, a):
        super().__init__(id)

        # register fit variables
        self.fit_variables = [center_shift]

        # make parameters available in functions calls
        self.center_shift = center_shift
        self.a = a

    # implementation of the actual instrumental function
    # Witch of Agnesi function here
    def InstrumentFunction(self, grid):
        # IMPORTANT - Do not remove this steps to get proper center to avoid shifts during convolution
        grid = np.array(grid)
        center = grid[grid.size // 2]

        # implementation of Witch of Agnesi function
        # the center value is important to garantee the correct center point during convolution
        # the center_shift.value is the additional user provided shift from the fit varibale
        kernel = 8 * self.a**3/(np.square(grid - center - self.center_shift.value) + 4 * self.a**2)

        # OPTIONAL - Truncation for faster convolution.
        # DO NOT DO THIS for asymmetric or shifted functions due to possible shifts during convolution.
        # The relative truncation value is important for the kernel type.
        # For Lorentzian it is around 30 gamma ~ 1.1e-3
        # as the curve is possibly shifted by center_shift.value no truncation
        # kernel = self.TruncateKernel(kernel, relative_truncation_threshold = 1e-3)

        # IMPORTANT - normalize kernel
        # keeps the correct intensity of the theoretical curve
        kernel = self.NormalizeKernel(kernel, 1.0)

        return kernel

and then

# one fixed and one fit parameter for our user-defined function
shift = nx.Var(value=1, min=0, max=10, fit=True, id="my fit parameter")
a = 0.3

# intilazation of witch of Agnesi function
woa = InstrumentDefinedInPython("Witch of Agnesi", shift, a)

kernel = woa.InstrumentFunction(detuning)

# the kernel is nomralized in sum to norm_factor
print(np.sum(kernel))

#plotting the kernel
plt.title(woa.id)
plt.plot(detuning, kernel)
plt.show()
../../_images/WOA.png

Notebooks

instrument - nb_instrument.ipynb.

Please have a look to the API Reference for more information.