Initializing IltData

For initializing, output sampling and kernel information specified by the parameters tau and kernel respectively are needed. Furthermore, parameters which affect the inversion step can be changed during initialization with the parameters keyword argument. While ILTpy offers a large number of adjustable parameters, the performance of the algorithm does not significantly depend on the exact choice of the different parameters. IltData obtained after iltload can be initialized by IltData.init(tau,kernel). See initialization examples or continue reading about initialization inputs.

In the following sections, inputs which can be provided during initialization are further discussed.

Required initialization inputs

Kernels

Kernels are functions which relate experimental parameters such as timings of an experiment or the input sampling vector \(t\) to spectral parameters such as relaxation time constants \(\tau\). For example, in case of an exponentially decaying data, an exponential kernel of the form : \(e^{-\frac{t}{\tau}}\) is suitable. ILTpy has the following pre-defined kernels listed below which can be used, for instance, as IltData.init(tau,kernel=ilt.Exponential())

  • Exponential()

  • Identity()

  • Gaussian()

  • Diffusion()

  • RealRcKernel()

  • ImagRcKernel()

Users can also define their own kernel functions using the same approach as the pre-defined kernels as shown below.

from iltpy.fit.kernels import IltKernel
class MyKernel(IltKernel): # use base IltKernel class
    def __init__(self):
        ## give the kernel a name
        self.name = 'my_kernel'
        ## Defining a stretched exponential function with a stretching parameter of 0.5
        self.kernel = lambda t,tau : np.exp(-t/tau)**0.5
        ## also include the kernel function as a string
        self.kernel_str = "lambda t,tau : np.exp(-t/tau)**0.5"

The user-defined kernel can now be used during initialization : IltData.init(kernel=MyKernel()).

Note

For all kernel classes, including user-defined kernels, ILTpy checks the following conditions :

  • Is the kernel an instance of IltKernel?

  • Does it have each of the attributes : name, kernel and kernel_str ?

If any of these evaluate to False, an AttributeError is raised.

Tau

The parameter tau is the output sampling vector of the expected distribution. For example, for NMR and EPR relaxation data, the tau parameter should cover the range of expected relaxation constants. Similarly, for diffusion data, tau array should cover a range of expected diffusion coefficients. A logarithmically spaced array based on the input sampling, t, is an appropriate starting point. In case of NMR and EPR relaxation data with exponential or Gaussian kernels, internally generated tau from the input sampling vector, t can be used, therefore, it is not necessary to provide a user-defined tau in case of relaxation data. However, this is only appropriate in case of relaxation data and in all other cases, an appropriate tau vector must be chosen.

Note

The internally generated tau in case of relaxation data consists of 100 logarithmically spaced values ranging from min(t)/1000 to max(t)*100.

Other initialization inputs

Along with tau and kernel, IltData.init() accepts the following keyword arguments.

  • parameters : A python dictionary containing parameters and values as key-value pairs.

  • dim_ndim : In case of datasets where the last dimension is not inverted but regularized, this parameter defines the output sampling vector to be used.

  • sigma : This array is used for calculating the weighting matrix in case of weighted inversions. The shape of sigma must match the shape of input data. See a 2D inversion where sigma was used.

  • g_guess : This array can be provided as an initial guess for g (spectrum or distribution) before the iterative inversion procedure starts.

  • reinitialize : Re-initializes an already initialized IltData object with the default parameters. See updating parameters.

  • verbose : Controls verbosity. Values greater than zero will print initialization progress.

Attention

Kernel and tau (output sampling) must not be provided with the parameters keyword (see changing parameters). These inputs must be provided using their respective keyword arguments kernel and tau.

Note

If not specified, ILTpy-generated dim_ndim is an array with unit spacing and with same number of elements as the size of the uninverted dimension. For instance, for a 2D dataset of shape (16,1024) where only the first dimension is inverted, dim_ndim corresponds to np.arange(1,1025).

See initialization examples.

Changing parameters

ILTpy supports several adjustable parameters (see here) which can be changed with the parameters keyword argument during initialization. Parameters related to the inversion can be changed by passing a python dictionary with key-value pairs to the parameters argument of IltData.init(tau,kernel,parameters) as shown in changing parameters.

Updating parameters

Updating any parameter of an already initialized IltData object can be achieved by calling IltData.init() again with the updated parameter. This is useful in case where a copy of the IltData object is made and only some parameters need to be changed. To reinitialize with default parameters, use IltData.init(reinitialize=True) as shown in updating parameters.

Accessing parameters

After initialization, several adjustable parameters are available in IltData, which can be accessed similarly as the data-related parameters. For instance, the global scaling of regularization matrix, alpha_00 can be accessed by IltData.alpha_00.

Attention

Changes to parameters, data or any other initialization input must be done before or during initialization. If changed after initialization, IltData.init(tau,kernel,parameters) must be used again along with any other initialization inputs to take the changes into account.

Initialization examples

1D inversions :

import iltpy as ilt

# Assuming data1D and t1 are numpy arrays with the data and the sampling vector.
data1D_ILT = ilt.iltload(data=data1D,t=t1)

# define an appropriate output sampling
tau = np.logspace(-1,2,100)

# provide tau and kernel, initialize
data1D_ILT.init(tau,kernel=ilt.Exponential())

See an example for 1D inversion.

Multi-dimensional inversions (all dimensions are inverted) :

This code snippet demonstrates initialization with exponential kernels along both dimensions and different output sampling vectors.

import iltpy as ilt

# Assuming data2D is a 2D numpy array and
# t1,t2 are numpy arrays with sampling vectors corresponding to each dimension.
data2D_ILT = ilt.iltload(data=data2D,t=[t1,t2])

# specify appropriate tau (output sampling vector) in both dimensions and specify kernel in both dimensions
tau1 = np.logspace(-2,2,100)
tau2 = np.logspace(-1,3,100)
data2D_ILT.init(tau =[tau1,tau2],kernel=[ilt.Exponential(),ilt.Exponential()])

# The same scheme can be used for any nD inversion by specifying n number of t, tau and kernels.
# e.g. in case of 3D data:
# data3D_ILT = ilt.iltload(data=data3D,t=[t1,t2,t3])
# data3D_ILT.init(tau =[tau1,tau2,tau3],kernel=[ilt.Exponential(),ilt.Exponential(),ilt.Exponential()])

This scheme extends naturally to higher dimensions by supplying a list of kernels and output sampling vectors matching the number of dimensions. See an example for 2D inversion or 3D inversion where all dimensions are inverted.

Multi-dimensional inversions (only some dimensions are inverted) :

import iltpy as ilt

data2D_ILT = ilt.iltload(data=data2D,t=t1)

# define an appropriate output sampling for the dimension to be inverted
tau1 = np.logspace(-1,2,100)

# initialize
data2D_ILT.init(tau=tau1,kernel=ilt.Exponential())

See an example for a 2D inversion where only the first dimension is inverted or a 3D inversion where only the first two dimensions are inverted.

Changing parameters :

import iltpy as ilt

# assuming data2d is a dataset where only the first dimension needs to be inverted.
data2D_ILT = ilt.iltload(data=data2D,t=t1)

## example:
# set the global scaling for regularization to 5
# switch zero-crossing penalty off.
# change convergence limit
# use svd compression in both dimensions
# use 8 singular values in both dimensions (specified by `s`)
parameter_dict = {'alpha_00':5,'reg_zc':False,'conv_limit':1e-9,'compress':[True,True],'s':[8,8]}

# initialize
data2D_ILT.init(tau=np.logspace(-2,5,100),kernel=ilt.Exponential(),parameters=parameter_dict)

Updating parameters of a pre-initialized IltData object :

import iltpy as ilt

# assuming data2d is a dataset where only the first dimension needs to be inverted.
data2D_ILT = ilt.iltload(data=data2D,t=t1)

# initialize
parameter_dict = {'alpha_00':2,'conv_limit':1e-9}
data2D_ILT.init(tau=np.logspace(-2,5,100),kernel=ilt.Exponential(),parameters=parameter_dict)

# Suppose, another inversion with a Gaussian kernel needs to be done while keeping all other parameters the same
# So that we don't overwrite the first inversion results, we make a copy first.
from copy import deepcopy
data2D_ILT_Gaussian = deepcopy(data2D_ILT)

# In this case we only want to update the kernel
# This retains any user inputs provided for the initialization of the original data2D_ILT, for instance the tau vector and parameters.
data2D_ILT_Gaussian.init(kernel=ilt.Gaussian())

# to reinitialize data2D_ILT_Gaussian with the default parameters use :
# this will use the default parameters
data2D_ILT_Gaussian.init(tau=np.logspace(-2,5,100),kernel=ilt.Gaussian(),reinitialize=True)
  • Note that this also applies in the following situation :

import iltpy as ilt

# assuming data2d is a dataset where only the first dimension needs to be inverted.
data2D_ILT = ilt.iltload(data=data2D,t=t1)

# initialize
data2D_ILT.init(tau=np.logspace(-2,5,100),kernel=ilt.Exponential(),parameters={'alpha_00':2,'conv_limit':1e-9})
# At this point, value of alpha_00 and conv_limit is 2 and 1e-9 respectively.

# now if 'alpha_00' is changed again for the same object without defining it again, it will retain the value of 'conv_limit' as 1e-9
data2D_ILT.init(tau=np.logspace(-2,5,100),kernel=ilt.Exponential(),parameters={'alpha_00':1})
# At this point, value of alpha_00 and conv_limit is 1 and 1e-9 respectively.

# if you would like to reset conv_limit or any other parameter to its default value for an already initialized IltData object:
data2D_ILT.init(tau=np.logspace(-2,5,100),kernel=ilt.Exponential(),parameters={'alpha_00':1},reinitialize=True)
# At this point, value of alpha_00 and conv_limit is 1 and 1e-6 (default for conv_limit) respectively.