Paramagpy: software for fitting magnetic susceptibility tensors using paramagnetic effects measured in NMR spectra

Abstract Paramagnetic metal ions with fast-relaxing electrons generate pseudocontact shifts (PCSs), residual dipolar couplings (RDCs), paramagnetic relaxation enhancements (PREs) and cross-correlated relaxation (CCR) in the nuclear magnetic resonance (NMR) spectra of the molecules they bind to. These effects offer long-range structural information in molecules equipped with binding sites for such metal ions. Here we present the new open-source software Paramagpy, which has been written in Python 3 with a graphic user interface. Paramagpy combines the functionalities of different currently available programs to support the fitting of magnetic susceptibility tensors using PCS, RDC, PRE and CCR data and molecular coordinates in Protein Data Bank (PDB) format, including a convenient graphical user interface. Paramagpy uses efficient fitting algorithms to avoid local minima and supports corrections to back-calculated PCS and PRE data arising from cross-correlation effects with chemical shift tensors. The source code is available from 10.5281/zenodo.3594568 .


INTRODUCTION
paramagpy is a python module for calculating paramagnetic effects in NMR spectra of proteins. This currently includes fitting of paramagnetic susceptibility tensors to experimental data associated with pseudocontact shifts (PCS) residual dipolar couplings (RDC), paramagnetic relaxation enhancements (PRE) and cross-correlated relaxation (CCR). A GUI allows easy viewing of data and seamless transition between PCS/RDC/PRE/CCR calculations. Fig. 1

Unix/OSX Installation
Install directly using pip:

$ pip install paramagpy
Or, download the source code and run: $ python setup.py install within the source directory.

Windows Installation
Paramagpy has never been tested on windows, but theoretically it should work. Good luck!

Running the GUI
Once you have installed paramagpy, see Graphic User Interface (GUI) for how to run the GUI.

Examples
Note that all these examples are for scripted calculations using the Paramagpy python module. Most of this functionality is also available by the GUI Graphic User Interface (GUI)

PCS data Fit Tensor to PCS Data
This example shows how to fit a ∆ -tensor to experimental PCS data for the protein calbindin D9k. These data contain amide 1H and 15N chemical shifts between diamagnetic and paramagnetic states with the lanthanide Er3+ bound.

Downloads
• Download the data files 4icbH_mut.pdb and calbindin_Er_HN_PCS.npc from here: • Download the script pcs_fit.py

Script + Explanation
Firstly, the necessary modules are imported from paramagpy. from paramagpy import protein, fit, dataparse, metal The protein is then loaded from a PDB file using paramagpy.protein.load_pdb() into the variable prot. This returns a CustomStructure object which is closely based on the Structure object from BioPython and contains the atomic coordinates. The object, and how to access atomic coordinates is discussed at this link. The PCS data is then loaded from a .npc file using the function paramagpy.dataparse.read_pcs() into the variable rawData. This is a dictionary of (PCS, Error) tuples which may be accessed by rawData [(seq, atom)] where seq is an integer specifying the sequence and atom is the atom name e.g (3,'HA'). Note that these should match the corresponding sequence and atom in the PDB file.
CustomStructure.parse() is called on rawData. The returned array parsedData has a row for each atom with columns [mdl,atm,exp,cal,err,idx], where mdl is the model number from the PDB file, atm is an atom object from the BioPython PDB structure, exp and cal are the experimental and calculated values, err is the experimental uncertainty and idx is the atom index, used to define ensemble averaging behaviour. A quick gridsearch is conducted in a sphere of 10 Angstrom with 10 points per radius using the function paramagpy.fit.svd_gridsearch_fit_metal_from_pcs(). This requires two lists containing the starting metals mStart and parsed experimental dataArray parsedData. This function returns lists containing a new fitted metal object, the calculated PCS values from the fitted model. The Q-factor is then calculated using the function :py:func`paramagpy.fit.qfactor`.
# Calculate the Q-factor qfac = fit.qfactor(data) The fitted tensor parameters are saved by calling the method paramagpy.metal.Metal.save(). Alterntaively they may be displayed using print(mFit.info()) These experimental/calculated PCS values are then plotted in a correlation plot to assess the fit. This is achieved using standard functions of the plotting module matplotlib.

Fit multiple PCS datasets to common position
This example shows how to fit multiple ∆ -tensors to their respective datasets with a common position, but varied magnitude and orientation. This may arise if several lanthanides were investigated at the same binding site, and the data may be used simultaneously to fit a common position. Data from several PCS datasets for calbindin D9k were used here, and is a generalisation of the previous example: Fit Tensor to PCS Data.

Explanation
The protein and PCS datasets are loaded and parsed. These are placed into a list parsedData, for which each element is a PCS dataset of a given lanthanide.
The two fitting functions: • paramagpy.fit.svd_gridsearch_fit_metal_from_pcs() • paramagpy.fit.nlr_fit_metal_from_pcs() can accept a list of metal objects and a list of datasets with arbitrary size. If this list contains more than one element, fitting will be performed to a common position. The starting position is taken only from the first metal of the list.
After fitting, a list of fitted metals is returned. The fitted tensor are then written to files and a correlation plot is made.

Fit Tensor to PDB with Models
This example shows how to fit a ∆ -tensor to experimental PCS data using an NMR structure that contains many models. The tensor can be fit to ensemble averaged PCS values, or to individual models. An ensemble averaged PCS is the mean calculated PCS of all models. No structural averages are ever taken.
Data for calbindin D9k are used as in the previous example Fit Tensor to PCS Data.

Downloads
• Download the data files 2bcb.pdb and calbindin_Er_HN_PCS.npc from here: • Download the script pcs_fit_models.py

Script + Explanation
Firstly, the standard preamble and loading of data. The default method of fitting is to fit the tensor independently to each model of the PDB file. To achieve ensemble averaging behaviour, this requires setting the argument ensembleAverage to true within the fitting function. The default ensemble averaging behaviour is to average atoms with the same serial number in the PDB file. To manipulate ensemble averaging, you can specify the idx column of the input dataArray for paramagpy.fit. nlr_fit_metal_from_pcs(). The idx array contains common integers for corresponding atoms to be averaged. After fitting the Q-factor is calculated (with the ensembleAverage argument set to True), and ensemble averaging of the calculated data values is achieved with the function paramagpy.fit.ensemble_average() ####  Fitting a separate tensor to each model of the PDB is the default behaviour of the fitting functions, the average of all fitted tensors is then returned. The model with the minimum Q-factor is then found by looping over the calculated data and sorting them by the calculated Q-factor. paramagpy Documentation, Release 1.0

Constrained Fitting
This example shows how to fit a ∆ -tensor with constraints applied. The two cases here constrain position to fit a tensor to a known metal ion position form an X-ray structure, and fit an axially symmetric tensor with only 6 of the usual 8 parameters.

Downloads
• Download the data files 4icbH_mut.pdb and calbindin_Er_HN_PCS.npc from here: • Download the script pcs_fit_constrained.py

Script + Explanation
The necessary modules are imported and data is loaded The calcium ion from the X-ray structure is contained in a heteroatom of the PDB file. We set the starting position of the tensor to this position. To fit the the anisotropy and orientation without position, the linear PCS equation can be solved analytically by the SVD gridsearch method but using only one point with a radius of zero. The Q-factor is then calculated and the tensor is saved. To fit an axially symmetric tensor, we can used the Non-linear regression method and specify exactly which parameters we want to fit. This will be the axiality ax, two Euler angles b and g and the position coordinates. Note that in the output, the rhombic rh and alpha a parameters are redundant. paramagpy Documentation, Release 1.0

Fit a tensor to PCS data with uncertainties
This example shows how to conduct a weighted fit of a ∆ -tensor to experimental PCS data with experimental errors.

Downloads
• Download the data files 4icbH_mut.pdb and calbindin_Er_HN_PCS_errors.npc from here: • Download the script pcs_fit_error.py

Script + Explanation
This script follows very closely the script Fit Tensor to PCS Data. The only difference being that errors are included in the fourth column of the .npc file and errorbars are included in the plotting routine.

Propagate Uncertainty to Fitted Tensor Parameters
This example shows the various error analysis functions available in paramagpy for estimating the unceratinty in fitted parameters for a paramagnetic center.

Downloads
• Download the data files 2bcb.pdb and calbindin_Er_HN_PCS_errors.npc from here: • Download the script pcs_fit_uncertainty.py

Script + Explanation
This start of this script follows the script Fit Tensor to PCS Data to fit the tensor.

Uncertainty from sample fraction
A final, but generally not recommended method is to source noise from taking a random fraction of the data and conducting the fit for many iterations to then view the deviation in fitted parameters. This method is often called bootstrapping and is desirable if the experimental uncertainties are unknown and the PDB file does not contain models that capture structural unceratinty. The function paramagpy.fit.fit_error_bootstrap() will repeat the fit for many iterations, each time sampling the desired amount of the experimental data randomly. Two starting metals are initialised. It is important here to set the magnetic field strength and temperature.
# Define an initial tensor mStart1 = metal.Metal(B0=18.8, temperature=308.0) mStart2 = metal.Metal(B0=18.8, temperature=308.0) The alignment tensor is solved using the function paramagpy.fit.svd_fit_metal_from_rdc() which return a tuple of (metal, calculated), where metal is the fitted metal, calculated is the calculated RDC values. The tensors are then saved. Note that we set the argument ensembleAverage to True. This is important because the PDB structure represents and MD simulation. If set to False, a much smaller tensor would be fit.   # Make axis labels and save figure ax.set_xlabel("Experiment") ax.set_ylabel("Calculated") ax.legend() (continues on next page)

Calculate RDC from a known Tensor
This example shows how to calculate theoretical RDC values from a known ∆ -tensor which has been fitted from PCS data. Paramagpy allows seamless calculation of one PCS/PRE/RDC/CCR effect from a tensor fitted from another effect.

Downloads
• Download the data files 4icbH_mut.pdb and calbindin_Er_HN_PCS_tensor.txt from here: • Download the script rdc_calculate.py

Script + Explanation
First the relevant modules are loaded, the protein is loaded and the metal is loaded from file. The magnetic field strength and temperature are also set.

PRE data Fit Tensor to PRE Data
This example demonstrates fitting of the rotational correlation time to 1H PRE data of calbindin D9k. You can fit any parameters of the -tensor you desire, such as position or magnitude as well.

Downloads
• Download the data files 4icbH_mut.pdb, calbindin_Er_H_R2_600.npc and calbindin_Tb_H_R2_800.npc from here: • Download the script pre_fit_proton.py

Script + Explanation
Firstly, the necessary modules are imported from paramagpy. from paramagpy import protein, fit, dataparse, metal The protein is then loaded from a PDB file. The PRE data is loaded. Note that the Er data was recorded at 600 MHz and the Tb data was recorded at 800 MHz. rawData_er = dataparse.read_pre('../data_files/calbindin_Er_H_R2_600.pre') rawData_tb = dataparse.read_pre('../data_files/calbindin_Tb_H_R2_800.pre') The ∆ -tensors that were fitted from PCS data are loaded from file and the relevant 0 magnetic field strengths are set. The fitted tensors are saved to file. Note that the Er dataset gives a reasonable of around 4 ns which is close to the literature value of 4.25 ns. However, the Tb dataset gives an unreasonably large value of 18 ns. This is due to magnetisation attenuation due to 1H-1H RDCs present during the relaxation evolution time as discussed in literature giving rise to artificially large measured PREs for lanthanides with highly anisotropic ∆ -tensors. This is also reflected in the correlation plot below.

Calculate 15N PREs with cross-correlation effects
This example shows how to conduct a weighted fit of a ∆ -tensor to experimental PCS data with experimental errors.

Downloads
• Download the data files 4icbH_mut.pdb, calbindin_Tb_N_R1_600.pre and calbindin_Tb_HN_PCS_tensor.txt from here: • Download the script pre_calc_nitrogen.py

Script + Explanation
First the relevant modules are loaded, the protein and data are read and the data is parsed by the protein. The Tb tensor fitted from PCS data is loaded and the relevant parameters, in this case the magnetic field strength, temperature and rotational correlation time are set. met = metal.load_tensor('../data_files/calbindin_Tb_HN_PCS_tensor.txt') met.B0 = 14.1 met.T = 298.0 met.taur = 4.25E-9 A loop is conducted over the nitrogen atoms that are present in the experimental data. The PRE is calculated using the function paramagpy.metal.atom_pre(). Calculations without CSA are appended to the list cal and calculations including CSA cross-correlation with the Curie-spin relaxation are appended to the list cal_csa. paramagpy Documentation, Release 1.0

Fit spectral power density tensor
This example shows how to fit the spectral power density tensor to anisotropic PREs. The data and theory are derived from https://doi.org/10.1039/C8CP01332B.

Downloads
• Download the data files parashift_Tb.pdb and parashift_Tb_R1_exp.pre from here: • Download the script pre_fit_aniso_dipolar.py The spectral power density tensor is written here explicitly and set to the attribute g_tensor. The values here are sourced from the original paper, and arise from the robust linear fit to the experimental data. We will use this tensor for comparison to the fit achieved by paramagpy. An starting tensor with no parameters is also initialised and will be used for fitting to the exerimental data with paramagpy.

Script + Explanation
The fit is conducted by setting the usegsbm flag to True. This uses anisotropic SBM theory to fit the spectral power density tensor in place of the isotropic SBM theory. The relevant fitting parameters must be specified as 't1e', 'gax', 'grh', 'a','b','g' which represent the electronic relaxation time, the axial and rhombic componenets of the power spectral density tensor and the 3 Euler angles alpha, beta and gamma respectively. Note that the fitted t1e parameter is only an estimate of the electronic relaxation time. [mfit], Finally the results of the fit are plotted alongside the isotropic theory and the literature fit. Note that the difference in the fit from paramagpy is small, and probably arises because the original paper uses a Robust linear fit, which may include weighting with experimental uncertainties. However paramagpy weights values evely here because the experimental uncertainties are unknown.

CCR data Calculate Cross-correlated Relaxation
This example shows how to calculate dipole-dipole/Curie-spin cross-correlated relaxation as measured for data in the literature by Pintacuda et. al.

Downloads
• Download the data files 1bzrH.pdb, myoglobin_cn.ccr and myoglobin_f.ccr from here: • Download the script ccr_calculate.py

Script + Explanation
First the relevant modules are loaded, and the iron atom (paramagnetic centre) is identified as the variable ironAtom. Two paramagnetic centres are defined for the high and low spin iron atom. The positions are set to that of the iron centre along with other relevant parameters. The measured isotropic -tensor magnitudes are also set. met_cn = metal.Metal(position=ironAtom.position, B0=18.79, temperature=303.0, taur=5.7E-9) met_f = met_cn.copy() met_cn.iso = 4.4E-32 met_f.iso = 30. 1E-32 The experimental data are loaded and parsed by the protein.
Note that the two H and N atoms are provided. The first atom is the nuclear spin undergoing active relaxation. The second atom is the coupling partner. Thus by swapping the H and N atoms to give atom_ccr(N, H), the differential line broadening can be calculated in the indirect dimension. # Plot the data correlations ax.scatter( * zip( * compare_cn), s=7, label="myo_cn") ax.scatter( * zip( * compare_f), s=7, label="myo_f")

Graphic User Interface (GUI)
Paramagpy is equipped with a GUI which is cross-platform and contains most of the functionality of the scripted module. This gives a rapid way for new users to fit and compare PCS, RDC and PRE effects.

Running the GUI
If all this fails, you can contact the author for a prebuilt executable at henry.orton@anu.edu.au

NMR Software Macros
Paramagpy includes scripts for reading/writing PCS values directly from popular NMR software. This drastically improves the iterative process of tensor fitting.

CCPNMR Analysis 2.4
Download the two scripts: • paramagpy_ccpnmr_macro.py • paramagpy_fit_pcs.py In the first line of the script paramagpy_fit_pcs.py, replace the shebang with the path to the python version on your machine that contains the paramagpy installation. On my computer this is set to. #!/usr/bin/python3 Open CCPNMR analysis and navigate to Menu->Macro->Organise Macros. At the lower right click Add Macro and open the script paramagpy_ccpnmr_macro.py, then select paramagpyMACRO and click Load Macro. You can then select if from the list and click Run to reveal the screen below.
The popup window allows you to select a diamagnetic and paramagnetic spectrum and has 3 available buttons: • Write PCS: This will calculate the difference between assigned peaks in the paramagnetic and diamagnetic spectra and write them to a .npc file (as specified in the relevant field).
• Fit Tensor: This will call the paramagpy script paramagpy_fit_pcs.py to fit the tensor the the written PCS values.
• Read PCS: This will read back-calculated PCS values from file (as specified in the relevant field) and plot the expected peaks on the paramagnetic spectrum in red.
Note, to alter the parameters for fitting of the PCS tensor, you can change the values within the script param-agpy_fit_pcs.py.

Sparky
Download the 3 scripts: • paramagpy_sparky_macro.py • sparky_init.py • paramagpy_fit_pcs.py Place the first two scripts paramagpy_sparky_macro.py and sparky_init.py in the Sparky directorỹ /Sparky/Python. Note that the Sparky directory usually contains the Projects, Lists and Save folders. You may need to create the Python directory here in which to place the two scripts.
Place the third script paramagpy_fit_pcs.py in your home directory.
Open Sparky and navigate to Extensions->Read and write PCS files.
The popup window allows you to select a diamagnetic and paramagnetic spectrum and has 3 available buttons: • Write PCS: This will calculate the difference between assigned peaks in the paramagnetic and diamagnetic spectra and write them to a .npc file (as specified in the relevant field).
• Read PCS: This will read back-calculated PCS values from file (as specified in the relevant field) and plot the expected peaks on the paramagnetic spectrum in green.
• Clear PCS: This will remove all calculated PCS peaks from the spectrum.
Note, to perform the tensor fitting, you will need to execute the paramagpy script in a separate terminal including an argument with the experimental PCS file such as: user@computer:~$ ./paramagpy_fit_pcs.py pcsexp.npc To alter the parameters for fitting of the PCS tensor, you can change the values within the script param-agpy_fit_pcs.py.

Proof of equivalence between the matrix representation of Curie-spin dipole-dipole cross-correlated relaxation (Paramagpy implementation) and the original description by Ghose and Prestegard
This proof concerns equations 24-27 of the article on the software Paramagpy, which describe the cross-correlated relaxation between the Curie spin and dipole-dipole relaxation mechanisms. For a specific example, we consider the case of a 15 N -1 H group, with the Curie-spin shielding tensor at the site of the 1 H spin located at ⃗ = [ , , ] and distance from the paramagnetic centre.
We choose the orientation of the electron-1 H vector to be aligned with the -axis such that → . In the case of an isotropic magnetic susceptibility, = = 0 and the tensor is represented by a diagonal matrix with three identical elements iso , yielding the following simplification The nuclear dipole shielding tensor arising from the 15 N spin can be described in the same coordinate frame for an arbitrary orientation of the bond vector ⃗ HN = [ , , ] with bond length HN by and , , denote the coordinates of the 15 N spin relative to the 1 H spin.
The effective shielding tensor at the site of the 1 H spin, when the 15 N partner is in the spin-up state, is given by the sum of the two tensors Note that this matrix is symmetric. Therefore we can ignore equation 18 of the main text and only need to substitute matrix elements into equation 19. Expanding and simplifying (via symbolic processing in the program paramagpy Documentation, Release 1.0

Mathematica), this yields
The angle between the electron-nuclear vector ⃗ and the nuclear bond vector ⃗ HN is captured by the dot product formula Using above equation to substitute $z$ yields where the first two terms account for the dipolar and Curie spin auto-relaxation terms respectively, and the last term accounts for their cross-correlation. The 2 relaxation rate can be calculated by substitution of ∆ 2 into equation 21 of the main text.
Curie 2 The same derivation for ↓ yields the same result except for a sign change in the cross term: Curie 2 Taking the difference we obtain Substituting iso and the spin of 15 N as I=1/2 yields Curie×DD 2 = 9 45 The differential line width can be calculated from the relaxation rate as ∆ = Curie×DD 2 / and thus this equation matches equation 7 from Bertini et al.. paramagpy.metal.make_tensor paramagpy.metal.make_tensor(x, y, z, axial, rhombic, alpha, beta, gamma, lanthanide=None, temperature=298.15) Make a ChiTensor isntance from given parameters. This is designed to use pdb coordinates (x, y, z) and euler angles from an output like Numbat. • shift (float) -a bulk shift value applied to all PCS calculations. This is a correction parameter that may arise due to an offset between diamagnetic and paramagnetic PCS datasets.
This defualts to 0.0, meaning CSAxDSA crosscorrelation is not accounted for. If the metal has an anisotropic magnetic susceptibility, this is taken into account.

Parameters
• position (array of floats) -three coordinates (x,y,z) this is the position of the nuclear spin • gamma (float) -the gyromagnetic ratio of the relaxing spin • dipole_shift_tensor (3x3 array of floats) -this is the dipole shift tensor arising from the nuclear spin of the coupling partner If the metal has an anisotropic magnetic susceptibility, this is taken into account, resulting in orientation dependent PRE as predicted by Vega and Fiat. CSA cross-correlated relaxation may be included by providing an appropriate CSA tensor.

Parameters
• position (array of floats) -three coordinates (x,y,z) in meters • gamma (float) -the gyromagnetic ratio of the spin • csa (3x3 matrix (optional)) -the CSA tensor of the given spin. This defualts to 0.0, meaning CSAxDSA crosscorrelation is not accounted for. Returns value -The R1 relaxation rate in /s Return type float

paramagpy.metal.Metal.dsa_r2
Metal.dsa_r2(position, gamma, csa=0.0) Calculate R2 relaxation due to Curie Spin If the metal has an anisotropic magnetic susceptibility, this is taken into account, resulting in orientation dependent PRE as predicted by Vega and Fiat. CSA cross-correlated relaxation may be included by providing an appropriate CSA tensor. Parameters • position (array of floats) -three coordinates (x,y,z) • gamma (float) -the gyromagnetic ratio of the spin • csa (3x3 matrix (optional)) -the CSA tensor of the given spin. This defualts to 0.0, meaning CSAxDSA crosscorrelation is not accounted for. Returns value -The R2 relaxation rate in /s Return type float paramagpy.metal.Metal.fast_ccr

This is generally used for speed in fitting DDxDSA data
If the metal has an anisotropic magnetic susceptibility, this is taken into account. Parameters • posarray (array with shape (n,3)) -array of positions in meters • gammaarray (array with shape (n,3)) -array of gyromagnetic ratios of the spins • dstarray (array with shape (n,3,3)) -array of nuclear dipole shift tensors arising from the coupling partners Returns rates -The R2 differential line broadening rates in /s Return type array with shape (n,1)
Parameters posarray (array) -an array of positions with shape (n,3) Returns dipole_shift_tensor_array -and array of dipole shift tensors at corresponding positions. This has shape (n,3,3) Return type array

Returns rates -The R2 relaxation rates in /s
Return type array with shape (n,1)

paramagpy.metal.Metal.fast_first_invariant_squared
static Metal.fast_first_invariant_squared(t) Vectorised version of paramagpy.metal.Metal.first_invariant_squared() This is generally used for speed in fitting PRE data Parameters tensorarray (array with shape (n,3,3)) -array of shielding tensors Returns firstInvariantSquared -the first invariants squared of the tensors Return type array with shape (n,1)

Metal.fast_pcs(posarray)
A vectorised version of paramagpy.metal.Metal.pcs() This efficient algorithm calculates the PCSs for an array of positions and is best used where speed is required for fitting. Parameters posarray (array with shape (n,3)) -array of 'n' positions (x, y, z) in meters Returns pcs -the peudo-contact shift in parts-per-million (ppm) Return type array of floats with shape (n,1)

Metal.fast_racs(csaarray)
A vectorised version of paramagpy.metal.Metal.racs() This is generally used when speed is required for fitting Parameters csaarray (array with shape (n,3,3)) -array of chemical shift anisotropy tensors Returns racs_array -the residual anisotropic chemical shift in parts-per-million (ppm) Return type array of floats with shape (n,1)

This is generally used when speed is required for fitting
Parameters posarray (array with shape (n,3)) -an array of 'n' positions (x, y, z) in meters Returns rads_array -the residual anisotropic dipole shift in parts-per-million (ppm) Return type array of floats with shape (n,1)

Metal.fast_rdc(vecarray, gammaProdArray)
A vectorised version of paramagpy.metal.Metal.rdc() method. This is generally used for speed in fitting RDC data Parameters • vecarray (array with shape (n,3)) -array of internuclear vectors in meters • gammaProdArray (array with shape (n,1)) -the products of gyromagnetic ratios of spins A and B where each has units of rad/s/T Returns rdc_array -the RDC values in Hz Return type array with shape (n,1)

paramagpy.metal.Metal.fast_second_invariant_squared static Metal.fast_second_invariant_squared(t)
Vectorised version of paramagpy.metal.Metal.second_invariant_squared() This is generally used for speed in fitting PRE data Parameters tensorarray (array with shape (n,3,3)) -array of shielding tensors Returns secondInvariantSquared -the second invariants squared of the tensors Return type array with shape (n,1)

paramagpy.metal.Metal.first_invariant_squared static Metal.first_invariant_squared(t)
Calculate the antisymmetric contribution to relaxation via the first invariant of a tensor. This is required for PRE calculations using the shilding tensor Parameters tensor (3x3 matrix) -a second rank tensor Returns firstInvariantSquared -the first invariant squared of the shift tensor Return type float

paramagpy.metal.Metal.g_sbm_r1
Metal.g_sbm_r1(position, gamma) Calculate R1 relaxation due to Solomon-Bloembergen-Morgan theory from anisotropic power spectral density tensor Parameters • position (array of floats) -three coordinates (x,y,z) • gamma (float) -the gyromagnetic ratio of the spin Returns value -The R1 relaxation rate in /s Return type float paramagpy Documentation, Release 1.0

Metal.get_params(params)
Get tensor parameters that have been scaled appropriately This is often used to get parameter values during fitting where floating point errors would otherwise occur on the small values encountered.
Parameters params (list of str) -each element of the list is a string that corresponds to an attribute of the Metal to be retrieved. Returns scaled_params -a list with respective scaled parameter values from the input.

Metal.info(comment=True)
Get basic information about the Metal object

paramagpy.metal.Metal.make_mesh
Metal.make_mesh(density=2, size=40.0) Construct a 3D grid of points to map an isosurface This is contained in a cube Parameters • density (int (optional)) -the points per Angstrom in the grid Metal.pcs_mesh(mesh) Calculate a PCS value at each location of cubic grid of points Parameters mesh (array with shape (n,n,n,3)) -a cubic grid as generated by the method <make_mesh> Returns pcs_mesh -The same grid shape, with PCS values at the respective locations Return type array with shape (n,n,n,1) paramagpy Documentation, Release 1.0 paramagpy.metal.Metal.pre Metal.pre(position,gamma,rtype,dsa=True,sbm=True,gsbm=False,csa=0.0) Calculate the PRE for a set of spins using Curie and or SBM theory Parameters • position (array of floats) -position in meters • gamma (float) -gyromagnetic ratio of the spin • rtype (str) -either 'r1' or 'r2', the relaxation type • dsa (bool (optional)) -when True (defualt), DSA or Curie spin relaxation is included • sbm (bool (optional)) -when True (defualt), SBM spin relaxation is included • gsbm (bool (optional)) -when True (default=False), anisotropic dipolar relaxation is included using the spectral power density gensor <g_tensor> NOTE: when true, ignores relaxation of type SBM NOTE: only implemented for R1 relaxation calculations • csa (array with shape (3,3) (optional)) -CSA tensor of the spin.
This defualts to 0.0, meaning CSAxDSA crosscorrelation is not accounted for. Returns rate -The PRE rate in /s Return type float paramagpy.metal.Metal.pre_mesh Metal.pre_mesh(mesh, gamma=267512897.63847807, rtype='r2', dsa=True, sbm=True) Calculate a PRE value at each location of cubic grid of points Parameters • mesh (array with shape (n,n,n,3)) -a cubic grid as generated by the method <make_mesh> • gamma (float) -the gyromagnetic ratio of the spin • rtype (str) -either 'r1' or 'r2', the relaxation type • dsa (bool (optional)) -when True (defualt), DSA or Curie spin relaxation is included • sbm (bool (optional)) -when True (defualt), SBM spin relaxation is included Returns pre_mesh -The same grid shape, with PRE values at the respective locations Return type array with shape (n,n,n,1)

Metal.racs(csa)
Calculate the residual anisotropic chemical shift at the given postition.
The partial alignment induced by an anisotropic magnetic susecptiblity causes the chemical shift tensor at a nuclear position to average to a value different to the isotropic value.  Write a PyMol script to file which allows loading of the isosurface file Parameters • mesh (3D scalar np.ndarray of floats) -the scalar field of PCS or PRE values in a cubic grid • bounds (tuple (origin, low, high, points)) -as generated by paramagpy.metal.Metal.make_mesh() • fileName (str (optional)) -the filename of the isosurface file paramagpy.metal.Metal.write_pymol_script Metal.write_pymol_script(isoval=1.0,surfaceName='isomap',meshName='./isomap.pml.ccp4',pdbFile=None) Write a PyMol script to file which allows loading of the isosurface file Parameters • isoval (float (optional)) -the contour level of the isosurface • surfaceName (str (optional)) -the name of the isosurface file within Py-Mol • scriptName (str (optional)) -the name of the PyMol script to load the tensor isosurface • meshName (str (optional)) -the name of the binary isosurface file • pdbFile (str (optional)) -if not <None>, the file name of the PDB file to be loaded with the isosurface. Factor for conversion between magnetic susceptibility and alignment tensors ax axiality b beta euler anglue eigenvalues The eigenvalues defining the magnitude of the principle axes fit_scaling fundamental_attributes g gamma euler anglue g_eigenvalues The eigenvalues defining the magnitude of the principle axes g_isotropy Estimate of the spectral power density tensor isotropy g_tensor The magnetic susceptibility tensor matrix representation gax axial componenet of spectral power density tensor grh axial componenet of spectral power density tensor iso isotropy isotropy The magnidue of the isotropic component of the tensor lanth_axrh lanth_lib lower_coords rh rhombicity rotationMatrix The rotation matrix as defined by the euler angles saupe_factor Factor for conversion between magnetic susceptibility and saupe tensors tauc The effective rotational correlation time. tensor The magnetic susceptibility tensor matrix representation tensor_alignment The alignment tensor matrix representation tensor_saupe The saupe tensor matrix representation tensor_traceless The traceless magnetic susceptibility tensor matrix representation upper_coords upper_triang Fetch 5 unique matrix element defining the magnetic susceptibility tensor upper_triang_alignment Fetch 5 unique matrix element defining the alignment tensor upper_triang_saupe Fetch 5 unique matrix element defining the magnetic susceptibility tensor x x coordinate y y coordinate Continued on next page

Metal.rotationMatrix
The rotation matrix as defined by the euler angles paramagpy.metal.Metal.saupe_factor

Metal.tauc
The effective rotational correlation time.
This is calculated by combining the rotational correaltion time and the electronic relaxation time:

Metal.tensor_traceless
The traceless magnetic susceptibility tensor matrix representation

Protein module
This module handles the protein structure coordinates and includes methods for loading a PDB file and calculating atomic properites such as CSA or gyromagnetic ratio

paramagpy.protein
Functions load_pdb(fileName[, ident]) Read PDB from file into biopython structure object rotation_matrix(axis, theta) Return the rotation matrix associated with counterclockwise rotation about the given axis by theta radians. Return the rotation matrix associated with counterclockwise rotation about the given axis by theta radians.
Parameters axis (array of floats) -the [x,y,z] axis for rotation.

Returns matrix -the rotation matrix
Return type numpy 3x3 matrix object

copy()
Create a copy of the Atom. detach_parent() Remove reference to parent.

dipole_shift_tensor(position)
Calculate the magnetic field shielding tensor at the given postition due to the nuclear dipole flag_disorder() Set the disordered flag to 1. get_altloc() Return alternative location specifier. get_anisou() Return anisotropic B factor. get_bfactor() Return B factor. get_coord() Return atomic coordinates. get_full_id() Return the full id of the atom. Continued on next page paramagpy Documentation, Release 1.0 Apply rotation and translation to the atomic coordinates.
The standard deviation of atomic parameters consists of 3 positional, 1 B factor and 1 occupancy standard deviation. Parameters sigatm_array (Numeric array (length 5)) -standard deviations of atomic parameters.

paramagpy.protein.CustomStructureBuilder.set_symmetry
CustomStructureBuilder.set_symmetry(spacegroup, cell) Set symmetry.   Perform uncertainty analysis sourcing noise from fractioning the experimental data. This function takes a fitting routine <fittingFunction> and repeats it for the specified iterations in a Bootstrap approach. With each iteration, a random subset of the experimental data is sampled as specified by the <fraction> argument. The standard deviation in the fitted parameters is then returned.

Parameters
• fittingFunction (function) -the fitting routine to be used. This could be 'nlr_fit_metal_from_ccr' for example • iterations (int) -the number of iterations for the Monte-Carlo simulation • kwargs (dict) -all key-word arguments will be bundled into this variable and parsed to the fittingFunction.

Returns
• sample_metals (list of list of metals) -the metals fitted to the data with noise at each iteration • std_metals (list of metals) -the standard deviation in fitted parameters over all iterations of the Monte Carlo simulation. These are stored within the metal object. All unfitted parameters are zero.

paramagpy.fit.fit_error_models
paramagpy.fit.fit_error_models(fittingFunction, **kwargs) Perform uncertainty analysis sourcing noise from cooridinates as defined by models of the PDB structure. This function takes a fitting routine <fittingFunction> and repeats it for each model. The standard deviation in the fitted parameters is then returned.

Parameters
• fittingFunction (function) -the fitting routine to be used. This could be 'nlr_fit_metal_from_ccr' for example • kwargs (dict) -all key-word arguments will be bundled into this variable and parsed to the fittingFunction.

Returns
• sample_metals (list of list of metals) -the metals fitted to the data with noise at each iteration • std_metals (list of metals) -the standard deviation in fitted parameters over all iterations of the Monte Carlo simulation. These are stored within the metal object. All unfitted parameters are zero.

paramagpy.fit.fit_error_monte_carlo
paramagpy.fit.fit_error_monte_carlo(fittingFunction, iterations, **kwargs) Perform uncertainty analysis sourcing noise from experimental uncertainties This function takes a fitting routine <fittingFunction> and repeats it for the specified iterations in a Monte-Carlo approach. With each iteration, random noise sourced from a uniform distribution scaled by the experimental uncertainties is added to the experimental values. The standard deviation in the fitted parameters is then returned.
NOTE: the 'err' column of the dataArrays must be set to non-zero values for this method to work.

Parameters
• fittingFunction (function) -the fitting routine to be used. This could be 'nlr_fit_metal_from_ccr' for example • iterations (int) -the number of iterations for the Monte-Carlo simulation • kwargs (dict) -all key-word arguments will be bundled into this variable and parsed to the fittingFunction.

Returns
• sample_metals (list of list of metals) -the metals fitted to the data with noise at each iteration • std_metals (list of metals) -the standard deviation in fitted parameters over all iterations of the Monte Carlo simulation. These are stored within the metal object. All unfitted parameters are zero.

Parameters
• metals (list of Metal objects) -the metals for which the standard deviation in parameters will be calculated • params (list of str) -the parameters for the standard deviation calculation. For example ['x','y','z','ax','rh','a','b','g','shift'] Returns std_metal -the returned metal object has attributes equal to the standard deviation in the given parameter. All other attributes are zero.

Reference Guide
• progress (object, optional) -to keep track of the calculation, progress.set (x) is called each iteration and varies from 0.0 -> 1.0 when the calculation is complete.

Returns
• fitMetals (list of metals) -a list of the fitted tensors.
• dataArrays (list of dataArray) -each dataArray is copy of the original dataArray with the 'cal' column populated with back-calculated values from the fitted tensor.

Parameters
• initMetals (list of Metal objects) -a list of metals used as starting points for fitting. a list must always be provided, but may also contain only one element. If multiple metals are provided, each metal is fitted to their respective PRE dataset by index in <dataArrays, but all are fitted to a common position.
• dataArrays (list of PRE dataArray) -each PRE dataArray must correspond to an associated metal for fitting. each PRE dataArray has structure determined by paramagpy.protein.CustomStructure.parse().
• rtypes (list of str, optional) -the relaxtion type, either 'r1' or 'r2'. A list must be provided with each element corresponding to an associated dataset. Defaults to 'r2' for all datasets of None is specified.
• params (list of str) -the parameters to be fit. For example ['x','y','z','ax','rh','a','b','g','shift'] • usesbm (bool, optional) -include Solomon-Bloemenbergen-Morgan (Dipoledipole) relaxation theory. default is True • usegsbm (bool, optional) -include anisotropic dipolar relaxation theory. note that the g-tensor must be set for this default is False • usedsa (bool, optional) -include Dipolar-Shielding-Anisotropy (Curie Spin) relaxation theory. default is True • usecsa (bool, optional) -include Chemical-Shift-Anisotropy cross-correlated realxation theory. default is False • ensembleAverage (bool, optional) -when False, each model of the structure is fit independently. The parameters for each fitted tensor are then averaged before returning the final averaged tensor. When True, the structure models are treated as an ensemble and ensemble averaging of calculated PCS/PRE/RDC/CCR values is conducted at all stages of fitting to fit a single tensor to all models simultaneously. The 'idx' column of the dataArray determines the ensemble averaging behaviour with common indices for atoms between models resulting in their summation.
• progress (object, optional) -to keep track of the calculation, progress.set(x) is called each iteration and varies from 0.0 -> 1.0 when the calculation is complete.

Returns
• fitMetals (list of metals) -a list of the fitted tensors.
• dataArrays (list of dataArray) -each dataArray is copy of the original dataArray with the 'cal' column populated with back-calculated values from the fitted tensor.

paramagpy.fit.qfactor
paramagpy.fit.qfactor(dataArray, ensembleAverage=False, calDenominator=False) Calculate the Q-factor to judge tensor fit quality A lower value indicates a better fit. The Q-factor is calculated using the following equation: where and are usually indexed over models and atoms respectively.

Parameters
• dataArray (numpy array) -the dataArray must contain the columns 'exp', 'cal' and 'idx' corresponding to the experimenta, calculated and index values respectively. The index value determines the ensemble averaging behaviour, and can be ignored if the argument <ensembleAverage> is False.
• ensembleAverage (bool, optional) -when False, the q-factor calculation squares each difference independently. When True, the q-factor calculates an ensemble average before taking the square of differences. The 'idx' column of the dataArray determines the ensemble averaging behaviour with common indices for atoms between models resulting in their summation.
• calDenominator (bool, optional) -when False, the standard Q-factor is calculated with only the sum of squares for the experimental values used in the denominator when True, the Q-factor established by Ubbink et al. is calculated which has a sum of absolute values of exp and cal values squared in the denominator.
Returns qfactor -the Q-factor • idx (array of ints) -an index assigned to each atom. Common indices determine summation between models for ensemble averaging.
• errors (array of floats) -the standard deviation representing experimental uncertainty in the measured value • idx (array of ints) -an index assigned to each atom. Common indices determine summation between models for ensemble averaging.
• errors (array of floats) -the standard deviation representing experimental uncertainty in the measured value • idx (array of ints) -an index assigned to each atom. Common indices determine summation between models for ensemble averaging.
• errors (array of floats) -the standard deviation representing experimental uncertainty in the measured value

Returns
• calc (array of floats) -the calculated RDC values from the fitted tensor • sol (array of floats) -sol is the solution to the linearised PCS equation and consists of the tensor matrix elements paramagpy.fit.svd_fit_metal_from_rdc paramagpy.fit.svd_fit_metal_from_rdc(initMetals, dataArrays, params=('ax', 'rh', 'a', 'b', 'g'), ensembleAverage=False, progress=None) Fit deltaChi tensor to RDC values using Single Value Decomposition. Note this is a weighted SVD calculation which takes into account experimental errors.

Parameters
• initMetals (list of Metal objects) -a list of metals used as starting points for fitting. a list must always be provided, but may also contain only one element. If multiple metals are provided, each metal is fitted to their respective RDC dataset by index in <dataArrays>.
• params (list of str) -the parameters to be fit. NOTE: This is a dummy argument and does not influence the fitting. The default parameters ('ax','rh','a','b','g') are the only option.
• ensembleAverage (bool, optional) -when False, each model of the structure is fit independently. The parameters for each fitted tensor are then averaged before returning the final averaged tensor. When True, the structure models are treated as an ensemble and ensemble averaging of calculated PCS/PRE/RDC/CCR values is conducted at all stages of fitting to fit a single tensor to all models simultaneously. The 'idx' column of the dataArray determines the ensemble averaging behaviour with common indices for atoms between models resulting in their summation.
• progress (object, optional) -to keep track of the calculation, progress.set(x) is called each iteration and varies from 0.0 -> 1.0 when the calculation is complete.

Returns
• fitMetals (list of metals) -a list of the fitted tensors.
• dataArrays (list of dataArray) -each dataArray is copy of the original dataArray with the 'cal' column populated with back-calculated values from the fitted tensor.

Parameters
• initMetals (list of Metal objects) -a list of metals used as starting points for fitting. a list must always be provided, but may also contain only one element. If multiple metals are provided, each metal is fitted to their respective PCS dataset by index in <dataArrays, but all are fitted to a common position.
• dataArrays (list of PCS dataArray) -each PCS dataArray must correspond to an associated metal for fitting. each PCS dataArray has structure determined by paramagpy.protein.CustomStructure.parse().
• ensembleAverage (bool, optional) -when False, each model of the structure is fit independently. The parameters for each fitted tensor are then averaged before returning the final averaged tensor. When True, the structure models are treated as