Datatypes

Molecular NMR parameters, spectra and calculation results are stored in Python objects in the HQS NMR Tool. These data structures are all Pydantic data classes and the data can be accessed as attributes of the class. See NMRResultSpectrum1D for an example.

Note that for the full signature of each datatype you can check out the API-documentation. Here we will just point out the most important attributes of each class.

NMRResultSpectrum1D

The NMRResultSpectrum1D is used to store all of the input and output of a NMR spectrum calculation when using the calculate_spectrum routine. It comprises:

  • The molecular NMR parameters of datatype NMRParameters used for the calculation (molecule_parms).

  • All the parameters handed to calculate_spectrum in form of a NMRCalculationParameters object (calculation_parms).

  • The calculated spectrum of datatype NMRSpectrum1D (spectrum).

Assuming we have obtained an object called result_spectrum of datatype NMRResultSpectrum1D the attributes can be accessed as follows:

molecule_parms = result.molecule_parms
calculation_parms = result.calculation_parms
spectrum = result.spectrum

In the following we will elaborate on the datatype of each of these objects in more detail.

NMRResultGreensFunction1D

The NMRResultGreensFunction1D is the analog datatype to NMRResultSpectrum1D when using calculate_greens_function instead of calculate_spectrum. The only difference is that instead of the attribute spectrum it has the attribute greens_function, which stores a NMRGreensFunction1D datatype.

Assuming we have an object called result_greens_function of datatype NMRResultGreensFunction1D the greens_function attribute can be accessed as follows:

greens_function = result_greens_function.greens_function

NMRParameters

The NMRParameters datatype is defined in the hqs_nmr_parameters repository and holds the reduced set of molecular parameters required for an NMR calculation,

The class holds:

  • A list of chemical shifts in ppm for every nucleus in the system that has NMR parameters.
  • A List of isotopes for every nucleus, in the same ordering as shifts. The NamedTuple Isotope has the two attributes mass_number and symbol.
  • A list containing pairs of atomic indices and the associated J-coupling values. The atomic indices refer to the ordering in the shifts and isotopes lists.

For an example you may run the following code:

from hqs_nmr_parameters.examples import molecules

# Obtain example molecule.
nmr_parameters = molecules["C10H7Br"].spin_system()

print(type(nmr_parameters))        # NMRParameters
print(nmr_parameters.shifts)
print(nmr_parameters.isotopes)
print(nmr_parameters.j_couplings)

NMRParameters objects are used as an input when calculating a spectrum using the calculate_spectrum or calculate_greens_function method.

NMRCalculationParameters

The NMRCalculationParameters datatype is defined in the hqs_nmr repository and stores all possible customization options when performing spectra calculations with calculate_spectrum or calculate_greens_function.

The only parameter the user always has to specify is the spectrometer frequency in MHz, so the most simple and often already sufficient instantiation of this datatype may look as follows:

from hqs_nmr.datatypes import NMRCalculationParameters

calculation_parms = NMRCalculationParameters(frequency_MHz=500)

Another important option the user can set is the homoisotope, which is the Isotope specified as Isotope(mass, symbol) to define the frequency of the rotating frame. Furthermore, the object contains multiple attributes allowing to improve the resolution. For a detailed explanation of the available customization options check out the tutorial notebooks or take a look at the API-documentation.

NMRSolverSettings

The NMRSolverSettings datatype is also defined in the hqs_nmr repository and stores customization options specific for the solver backend. It is stored as an attribute of a NMRCalculationParmameters object and typically does not need to be altered.

It is however important to know that by default a spin-dependent clustering of the molecule into overlapping clusters is performed (for details check here). This is an extremely accurate approximation especially at high field, however in some cases this might not be wanted. In these cases you can set the attribute solve_exactly=True, such that the spectrum of the entire molecule is calculated at once and symmetries will be exploited where applicable, but no approximations are made. Note that this can lead to a significant increase in runtime, so typically it is more advisable to increase the size of the clusters instead. To do so the attribute max_cluster_size has to be specified:

from hqs_nmr.datatypes import NMRSolverSettings

solver_settings = NMRSolverSettings(max_cluster_size=16)

To see all customization options check the API-documentation.

NMRSpectrum1D

The NMRSpectrum1D datatype holds an NMR spectrum comprising the frequencies in ppm (omegas_ppm), an array with the individual spin contributions to the spectrum (values), the full-width-half-maximum in ppm (fwhm_ppm) and the reference energy (reference_energy) to allow easy conversion of attributes from ppm into other units.

Assuming we have performed a NMR spectrum calculation using calculate_spectrum and obtained as output an NMRResultSpectrum1D object we called result_spectrum, we can obtain an object of datatype NMRSpectrum1D as an attribute of this object:

spectrum = result_spectrum.spectrum

The values are a numpy array where each row holds the contribution of the corresponding spin, i.e.:

spectrum.values[0,:]

holds the contribution of the first spin (index 0). The total spectrum that would be measured experimentally can be calculated using

import numpy as np
np.sum(spectrum.values, axis=0)

NMRGreensFunction1D

The NMRGreensFunction1D datatype basically has the same attributes as NMRSpectrum1D, however values is a complex array, as it stores the full NMR Green's function and not just the spectral function. This datatype is typically only used, if one wants to perform post-processing steps that require also the real part of the Green's function.

Assuming we have performed a NMR Green's function calculation using calculate_greens_function and obtained as output an NMRResultGreensFunction1D object called result_greens_function, we can obtain an object of datatype NMRGreensFunction1D as an attribute of this object:

greens_function = result_greens_function.greens_function

The total spectrum can then be obtained as follows:

import numpy as np
np.sum(- np.imag(greens_function.values), axis=0)

Serialization (Saving and Loading)

The datatypes described above have a common interface for data serialization. There exists a function called to_json common to all classes that can take a class object and a file name (with or without the full path) to store the data as a JSON file. For example, if we have an object called spectrum of the data class NMRSpectrum1D and want to save it as spectrum_data.json:

from hqs_nmr.datatypes import to_json

to_json(spectrum, "spectrum_data.json")

There is also the inverse method from_json to load the data again. It needs as additional information the type of class the JSON file has stored, e.g.:

from hqs_nmr.datatypes import from_json, NMRSpectrum1D

spectrum = from_json(NMRSpectrum1D, "spectrum_data.json")