Difference between revisions of "Heteronuclear NMR simulations"

From Spinach Documentation Wiki
Jump to: navigation, search
(→‎HSQC spectrum of strychnine)
(sync with Spinach main 3975f139: renamed basis field)
 
(41 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
Heteronuclear liquid-state NMR simulations in ''Spinach'' are set up in the same way as [[Simple_liquid_state_NMR_simulations|homonuclear simulations]], but the pulse sequence parameters must specify multiple spin channels. This tutorial follows two examples from the ''Spinach'' example set: <code>hsqc_strychnine.m</code>, which simulates a phase-sensitive natural-abundance <sup>13</sup>C HSQC spectrum of strychnine, and <code>clip_hsqc_camphor.m</code>, which simulates a natural abundance CLIP-HSQC spectrum of camphor.
 
Heteronuclear liquid-state NMR simulations in ''Spinach'' are set up in the same way as [[Simple_liquid_state_NMR_simulations|homonuclear simulations]], but the pulse sequence parameters must specify multiple spin channels. This tutorial follows two examples from the ''Spinach'' example set: <code>hsqc_strychnine.m</code>, which simulates a phase-sensitive natural-abundance <sup>13</sup>C HSQC spectrum of strychnine, and <code>clip_hsqc_camphor.m</code>, which simulates a natural abundance CLIP-HSQC spectrum of camphor.
  
−
==HSQC spectrum of strychnine==
+
==Strychnine spin system==
−
[[File:strychnine.png|thumb|300px|right|Chemical structure of strychnine]] ''Spinach'' examples are functions rather than scripts so that each run starts from a clean Matlab workspace. We must therefore open a new file and begin with with a function declaration:
+
[[File:strychnine.png|thumb|300px|right|Chemical structure of strychnine]] ''Spinach'' examples are functions rather than scripts: each run starts from a clean Matlab workspace. We must therefore open a new file and begin with with a function declaration:
  
 
     function hsqc_strychnine()
 
     function hsqc_strychnine()
Line 11: Line 11:
 
     [sys,inter]=[[strychnine.m|strychnine]]({'1H','13C'});
 
     [sys,inter]=[[strychnine.m|strychnine]]({'1H','13C'});
  
−
The [[strychnine.m|strychnine]] helper returns the [[sys]] and [[inter]] input structures for the selected isotopes. In this example, both proton and carbon-13 spins are imported. The strychnine data file contains proton shifts and couplings, carbon and nitrogen shifts and coordinates, and one-bond <sup>13</sup>C-<sup>1</sup>H J-couplings. The magnetic field is then set in Tesla:
+
The [[strychnine.m|strychnine]] helper function returns the [[sys]] and [[inter]] input structures for the selected isotopes. In this example, proton and carbon-13 spins are imported. The strychnine data file contains proton shifts and couplings, carbon and nitrogen shifts and coordinates, and one-bond <sup>13</sup>C-<sup>1</sup>H J-couplings. The magnetic field is then set in Tesla:
  
 
     [[sys]].magnet=5.9;
 
     [[sys]].magnet=5.9;
  
−
The next lines request the "greedy" parallelisation option and set the proximity cut-off:
+
The next line requests the "greedy" parallelisation option:
  
 
     [[sys]].enable={'greedy'};
 
     [[sys]].enable={'greedy'};
−
    [[sys]].tols.prox_cutoff=4.0;
 
  
−
The <code>greedy</code> option is a parallel resource-allocation option: when ''Spinach'' starts a new parallel pool, every worker is allowed to use every CPU core. The proximity cut-off is in Angstrom and supplies a spatial-neighbour criterion to Spinach routines that require one.
+
When ''Spinach'' starts a new parallel pool, this option means that every worker process is allowed to use every CPU core.
  
−
==HSQC basis set==
+
==Basis set specification==
−
The basis set is the same restricted spherical-tensor Liouville-space basis used by many liquid-state examples:
+
The basis set is the same connectivity-adaptive Liouville-space basis used by many liquid-state examples:
  
 
     [[bas]].formalism='sphten-liouv';
 
     [[bas]].formalism='sphten-liouv';
 
     [[bas]].approximation='IK-2';
 
     [[bas]].approximation='IK-2';
 
     [[bas]].connectivity='scalar_couplings';
 
     [[bas]].connectivity='scalar_couplings';
−
     [[bas]].space_level=1;
+
     [[bas]].prox_level=1;
  
−
The <code>sphten-liouv</code> formalism is required by [[hsqc.m|hsqc.m]]. The IK-2 approximation builds a restricted state space rather than the complete Liouville space, and <code>scalar_couplings</code> instructs the basis generator to use the scalar-coupling graph for connectivity. The <code>space_level</code> setting controls how far spatially local correlations are allowed into the basis.
+
The IK-2 approximation builds a restricted state space rather than the complete Liouville space, and <code>scalar_couplings</code> instructs the basis generator to use the scalar-coupling graph for connectivity. The <code>prox_level</code> setting controls how far spatially local correlations are allowed into the basis: since HSQC does not rely on spatial proximity, this parameter is set to 1.
  
 
==HSQC sequence parameters==
 
==HSQC sequence parameters==
−
The sequence parameters in the example are:
+
The following parameters are required by the [[hsqc.m|HSQC pulse sequence function]]:
  
 
     [[Appendix_E:_experiment_parameters|parameters]].J=140;
 
     [[Appendix_E:_experiment_parameters|parameters]].J=140;
Line 45: Line 44:
 
     [[Appendix_E:_experiment_parameters|parameters]].axis_units='ppm';
 
     [[Appendix_E:_experiment_parameters|parameters]].axis_units='ppm';
  
−
The [[hsqc.m|hsqc.m]] header specifies <code>parameters.sweep</code>, <code>parameters.npoints</code>, <code>parameters.spins</code>, <code>parameters.decouple_f1</code>, <code>parameters.decouple_f2</code>, and <code>parameters.J</code>. Here <code>parameters.J</code> is the working heteronuclear scalar coupling in Hz, used to set the transfer delay. The two entries in <code>parameters.sweep</code> are the F1 and F2 sweep widths in Hz, and the two entries in <code>parameters.offset</code> are the corresponding transmitter or receiver offsets in Hz. The point counts in <code>parameters.npoints</code> are the acquired F1 and F2 dimensions, and <code>parameters.zerofill</code> gives the Fourier transform sizes used during processing. The spin list <code>{'13C','1H'}</code> means that the indirect F1 dimension is carbon-13 and the directly detected F2 dimension is proton. The <code>decouple_f1</code> field lists spins that receive midpoint 180-degree refocusing pulses during F1 evolution, and <code>decouple_f2</code> lists spins decoupled during F2 acquisition. The plotted axes are requested in ppm.
+
Here <code>parameters.J</code> is the working heteronuclear scalar coupling in Hz, used to set the transfer delay. The two entries in <code>parameters.sweep</code> are the F1 and F2 sweep widths in Hz, and the two entries in <code>parameters.offset</code> are the corresponding transmitter or receiver offsets in Hz. The point counts in <code>parameters.npoints</code> are the acquired F1 and F2 dimensions, and <code>parameters.zerofill</code> gives the Fourier transform sizes used during processing. The spin list <code>{'13C','1H'}</code> means that the indirect F1 dimension is carbon-13 and the directly detected F2 dimension is proton. The <code>decouple_f1</code> field lists spins that receive midpoint 180-degree refocusing pulses during F1 evolution, and <code>decouple_f2</code> lists spins decoupled during F2 acquisition.
  
−
==HSQC spin-system construction==
+
==Spin system construction==
−
The Spinach spin-system object is created first:
+
We now create the spin system object from the information we have supplied above:
  
 
     [[Appendix_D:_kernel_data_structures|spin_system]]=[[create.m|create]]([[sys]],[[inter]]);
 
     [[Appendix_D:_kernel_data_structures|spin_system]]=[[create.m|create]]([[sys]],[[inter]]);
Line 58: Line 57:
 
The [[dilute.m|dilute]] function returns a cell array of spin systems. With the default tuple size, each returned subsystem contains a single instance of the specified dilute isotope and all other carbon-13 spins have been removed. This makes a natural-abundance <sup>13</sup>C HSQC simulation practical: the final spectrum is obtained as a sum over all single-carbon isotopomers.
 
The [[dilute.m|dilute]] function returns a cell array of spin systems. With the default tuple size, each returned subsystem contains a single instance of the specified dilute isotope and all other carbon-13 spins have been removed. This makes a natural-abundance <sup>13</sup>C HSQC simulation practical: the final spectrum is obtained as a sum over all single-carbon isotopomers.
  
−
The example then preallocates the complex answer:
+
We are going to be summing spectra up and we must therefore preallocate the sum:
  
 
     spectrum=zeros([[Appendix_E:_experiment_parameters|parameters]].zerofill(2),...
 
     spectrum=zeros([[Appendix_E:_experiment_parameters|parameters]].zerofill(2),...
Line 65: Line 64:
 
The first dimension of the matrix corresponds to the direct F2 dimension, and the second dimension corresponds to the indirect F1 dimension. The use of <code>'like',1i</code> requests a complex array.
 
The first dimension of the matrix corresponds to the direct F2 dimension, and the second dimension corresponds to the indirect F1 dimension. The use of <code>'like',1i</code> requests a complex array.
  
−
==HSQC isotopomer loop==
+
==Strychnine HSQC simulation and isotopomer loop==
−
Each isotopomer is processed independently:
+
[[File:strychnine_hsqc.png|thumb|400px|right|HSQC simulation for strychnine.]] Each isotopomer is to be simulated independently in a parallel loop:
  
 
     parfor n=1:numel(subsystems)
 
     parfor n=1:numel(subsystems)
−
 
+
−
The basis set is built inside the loop:
+
        % Build the basis
−
 
 
 
         subsystem=[[basis.m|basis]](subsystems{n},[[bas]]);
 
         subsystem=[[basis.m|basis]](subsystems{n},[[bas]]);
−
 
+
−
This is necessary because [[dilute.m|dilute]] removes basis-set information when it changes the spin system. The HSQC simulation is then run in the liquid-state context with NMR assumptions:
+
        % Simulation
−
 
 
 
         fid=[[liquid.m|liquid]](subsystem,@[[hsqc.m|hsqc]],[[Appendix_E:_experiment_parameters|parameters]],'nmr');
 
         fid=[[liquid.m|liquid]](subsystem,@[[hsqc.m|hsqc]],[[Appendix_E:_experiment_parameters|parameters]],'nmr');
−
 
+
−
The [[liquid.m|liquid]] context builds the isotropic Liouvillian, applies offsets and any other common sequence settings, and passes the resulting Hamiltonian, relaxation superoperator, and kinetics superoperator to [[hsqc.m|hsqc.m]]. The HSQC sequence returns two components of the States quadrature signal:
+
        % Apodisation
−
 
 
 
         fid.pos=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.pos,{{'sqcos'},{'sqcos'}});
 
         fid.pos=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.pos,{{'sqcos'},{'sqcos'}});
 
         fid.neg=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.neg,{{'sqcos'},{'sqcos'}});
 
         fid.neg=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.neg,{{'sqcos'},{'sqcos'}});
−
 
+
−
Both components are multiplied by square-cosine windows in both dimensions. The direct dimension is transformed first:
+
        % F2 Fourier transform
−
 
 
 
         f1_pos=fftshift(fft(fid.pos,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
 
         f1_pos=fftshift(fft(fid.pos,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
 
         f1_neg=fftshift(fft(fid.neg,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
 
         f1_neg=fftshift(fft(fid.neg,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
−
 
+
−
The States signal is then formed:
+
        % Form States signal
−
 
 
 
         fid=f1_pos+conj(f1_neg);
 
         fid=f1_pos+conj(f1_neg);
−
 
+
−
and the indirect dimension is transformed and added to the accumulated spectrum:
+
        % F1 Fourier transform
−
 
 
 
         spectrum=spectrum+fftshift(fft(fid,[[Appendix_E:_experiment_parameters|parameters]].zerofill(1),2),2);
 
         spectrum=spectrum+fftshift(fft(fid,[[Appendix_E:_experiment_parameters|parameters]].zerofill(1),2),2);
−
 
+
−
The loop is then closed:
 
−
 
 
 
     end
 
     end
  
−
Because each subsystem is independent, the loop is a natural use case for Matlab <code>parfor</code>.
+
Here, the basis set is built inside the loop; this is necessary because [[dilute.m|dilute]] removes basis-set information when it changes the spin system. The HSQC simulation is then run in the liquid-state context with NMR assumptions. The [[liquid.m|liquid]] context builds the isotropic Liouvillian, applies offsets and any other common sequence settings, and passes the resulting Hamiltonian, relaxation superoperator, and kinetics superoperator to [[hsqc.m|hsqc.m]]. The HSQC sequence returns two components of the States quadrature signal. Both States components are multiplied by square-cosine windows in both dimensions. The direct dimension is transformed first, the States signal is then formed and the indirect dimension is transformed and added to the accumulated spectrum. Because each subsystem is independent, the loop is a natural use case for Matlab <code>parfor</code>.
  
−
==HSQC plotting==
+
==Strychnine HSQC plotting==
−
[[File:strychnine_hsqc.png|thumb|400px|right|HSQC simulation for strychnine.]]
+
The final stage is to open a figure, scale it, and plot positive contours:
−
The final stage opens a figure, scales it, and plots positive contours:
 
  
 
     [[kfigure.m|kfigure]](); [[scale_figure.m|scale_figure]]([1.5 2.0]);
 
     [[kfigure.m|kfigure]](); [[scale_figure.m|scale_figure]]([1.5 2.0]);
Line 112: Line 102:
 
The [[plot_2d.m|plot_2d]] arguments are the spin system, the real part of the spectrum, the experiment parameters, the number of contours, positive and negative contour elevation ranges, the non-linear contour-spacing curvature, the colour-map size, the colour-map curvature, and the contour sign selection. In this example the last argument requests positive contours only.
 
The [[plot_2d.m|plot_2d]] arguments are the spin system, the real part of the spectrum, the experiment parameters, the number of contours, positive and negative contour elevation ranges, the non-linear contour-spacing curvature, the colour-map size, the colour-map curvature, and the contour sign selection. In this example the last argument requests positive contours only.
  
−
==CLIP-HSQC spectrum of camphor==
+
==Camphor spin system import==
−
The <code>clip_hsqc_camphor.m</code> example also begins with a function declaration:
+
[[File:camphor.jpg|thumb|200px|right|Chemical structure of camphor.]] Create a new function file. The difference with the previous example is that here we will import spin system information from a Gaussian log file:
−
 
 
−
    function clip_hsqc_camphor()
 
−
 
 
−
The spin system is imported from a Gaussian log file:
 
  
 
     options.min_j=3.0; options.no_xyz=0;
 
     options.min_j=3.0; options.no_xyz=0;
Line 123: Line 109:
 
                       {{'H','1H'},{'C','13C'}},[31.8 182.1],options);
 
                       {{'H','1H'},{'C','13C'}},[31.8 182.1],options);
  
−
The [[gparse.m|gparse]] function reads the Gaussian output file. The [[g2spinach.m|g2spinach]] function converts the parsed electronic-structure data into Spinach input structures. The particle list imports hydrogen atoms as <sup>1</sup>H and carbon atoms as <sup>13</sup>C. The reference vector <code>[31.8 182.1]</code> supplies the absolute shielding references used by the conversion to chemical shifts. The <code>options.min_j=3.0</code> setting discards scalar couplings smaller than 3 Hz, and <code>options.no_xyz=0</code> keeps the coordinate information.
+
[[File:camphor_clip_hsqc.png|thumb|400px|right|CLIP-HSQC simulation for camphor.]] The [[gparse.m|gparse]] function reads the Gaussian output file. The [[g2spinach.m|g2spinach]] function converts the parsed electronic-structure data into Spinach input structures. The particle list imports hydrogen atoms as <sup>1</sup>H and carbon atoms as <sup>13</sup>C. The reference vector <code>[31.8 182.1]</code> supplies the absolute shielding references used by the conversion to chemical shifts. The <code>options.min_j=3.0</code> setting discards scalar couplings smaller than 3 Hz, and <code>options.no_xyz=0</code> keeps the coordinate information. We then specify the magnetic field:
−
 
 
−
The magnetic field is then specified:
 
  
 
     [[sys]].magnet=14.1;
 
     [[sys]].magnet=14.1;
  
−
The next block replaces the isotropic parts of the shielding tensors with experimental chemical shifts:
+
and replace the isotropic parts of the shielding tensors with experimental chemical shifts:
  
 
     [[inter]].zeeman.matrix=[[shift_iso.m|shift_iso]]([[inter]].zeeman.matrix,1:26,...
 
     [[inter]].zeeman.matrix=[[shift_iso.m|shift_iso]]([[inter]].zeeman.matrix,1:26,...
Line 138: Line 122:
 
                                       0.99  0.90  0.90  0.90  2.33 1.76]);
 
                                       0.99  0.90  0.90  0.90  2.33 1.76]);
  
−
The [[shift_iso.m|shift_iso]] function preserves the anisotropic rank-1 and rank-2 parts of each tensor and replaces only the isotropic component with the supplied value. In this example, the source comment states that coordinates, shielding anisotropies, and J-couplings come from DFT, while isotropic chemical shifts come from experimental data.
+
The [[shift_iso.m|shift_iso]] function preserves the anisotropic parts of each tensor and replaces only the isotropic component with the supplied value.
−
 
 
−
==CLIP-HSQC basis set and options==
 
−
The basis set specification is:
 
−
 
 
−
    [[bas]].formalism='sphten-liouv';
 
−
    [[bas]].approximation='IK-2';
 
−
    [[bas]].connectivity='scalar_couplings';
 
−
    [[bas]].space_level=1;
 
−
 
 
−
The algorithmic options are:
 
−
 
 
−
    [[sys]].enable={'greedy'};
 
−
    [[sys]].tols.prox_cutoff=4.0;
 
−
 
 
−
As in the strychnine example, this requests Spinach's greedy parallelisation option and sets the proximity cut-off to 4 Angstrom.
 
−
 
 
−
==CLIP-HSQC sequence parameters==
 
−
The CLIP-HSQC example uses the following sequence parameters:
 
−
 
 
−
    [[Appendix_E:_experiment_parameters|parameters]].J=140;
 
−
    [[Appendix_E:_experiment_parameters|parameters]].sweep=[8000 1500];
 
−
    [[Appendix_E:_experiment_parameters|parameters]].offset=[4000 1000];
 
−
    [[Appendix_E:_experiment_parameters|parameters]].npoints=[128 128];
 
−
    [[Appendix_E:_experiment_parameters|parameters]].zerofill=[512 512];
 
−
    [[Appendix_E:_experiment_parameters|parameters]].spins={'13C','1H'};
 
−
    [[Appendix_E:_experiment_parameters|parameters]].axis_units='ppm';
 
−
 
 
−
The [[clip_hsqc.m|clip_hsqc.m]] header requires <code>parameters.sweep</code>, <code>parameters.npoints</code>, <code>parameters.spins</code>, and <code>parameters.J</code>. As above, <code>parameters.J</code> is the working scalar coupling in Hz, <code>parameters.sweep</code> gives the F1 and F2 sweep widths, <code>parameters.offset</code> gives the corresponding offsets, <code>parameters.npoints</code> gives the acquired point counts, <code>parameters.zerofill</code> gives the Fourier transform sizes, <code>parameters.spins={'13C','1H'}</code> specifies carbon-13 in F1 and proton in F2, and <code>parameters.axis_units='ppm'</code> requests ppm axes.
 
  
−
==CLIP-HSQC simulation==
+
==Camphor CLIP-HSQC simulation==
−
The spin-system construction and isotopomer generation steps are the same as in the HSQC example:
+
Use exactly the same basis set and other options as we have used above for strychnine, and the same parallel loop over isotopomers. The only difference now should be that CLIP-HSQC pulse sequence is called instead of HSQC:
  
−
     [[Appendix_D:_kernel_data_structures|spin_system]]=[[create.m|create]]([[sys]],[[inter]]);
+
     fid=[[liquid.m|liquid]](subsystem,@[[clip_hsqc.m|clip_hsqc]],[[Appendix_E:_experiment_parameters|parameters]],'nmr');
−
    subsystems=[[dilute.m|dilute]]([[Appendix_D:_kernel_data_structures|spin_system]],'13C');
 
  
−
The answer is again preallocated as a complex matrix:
+
and the plot must use negative contours:
−
 
 
−
    spectrum=zeros([[Appendix_E:_experiment_parameters|parameters]].zerofill(2),...
 
−
                    [[Appendix_E:_experiment_parameters|parameters]].zerofill(1),'like',1i);
 
−
 
 
−
The isotopomer loop starts with basis construction:
 
−
 
 
−
    parfor n=1:numel(subsystems)
 
−
       
 
−
        subsystem=[[basis.m|basis]](subsystems{n},[[bas]]);
 
−
 
 
−
The simulation call differs only in the pulse sequence function handle:
 
−
 
 
−
        fid=[[liquid.m|liquid]](subsystem,@[[clip_hsqc.m|clip_hsqc]],[[Appendix_E:_experiment_parameters|parameters]],'nmr');
 
−
 
 
−
The [[clip_hsqc.m|clip_hsqc.m]] sequence returns <code>fid.pos</code> and <code>fid.neg</code> as the two States quadrature components. The data processing matches the HSQC example:
 
−
 
 
−
        fid.pos=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.pos,{{'sqcos'},{'sqcos'}});
 
−
        fid.neg=[[apodisation.m|apodisation]]([[Appendix_D:_kernel_data_structures|spin_system]],fid.neg,{{'sqcos'},{'sqcos'}});
 
−
       
 
−
        f1_pos=fftshift(fft(fid.pos,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
 
−
        f1_neg=fftshift(fft(fid.neg,[[Appendix_E:_experiment_parameters|parameters]].zerofill(2),1),1);
 
−
       
 
−
        fid=f1_pos+conj(f1_neg);
 
−
       
 
−
        spectrum=spectrum+fftshift(fft(fid,[[Appendix_E:_experiment_parameters|parameters]].zerofill(1),2),2);
 
−
       
 
−
    end
 
−
 
 
−
The summation over the isotopomer loop produces the natural-abundance <sup>13</sup>C CLIP-HSQC spectrum.
 
−
 
 
−
==CLIP-HSQC plotting==
 
−
[[File:camphor_clip_hsqc.png|thumb|400px|right|CLIP-HSQC simulation for camphor.]]
 
−
The example plots negative contours:
 
  
 
     [[kfigure.m|kfigure]](); [[scale_figure.m|scale_figure]]([1.5 2.0]);
 
     [[kfigure.m|kfigure]](); [[scale_figure.m|scale_figure]]([1.5 2.0]);
Line 213: Line 135:
 
             20,[0.05 0.5 0.05 0.5],2,256,6,'negative');
 
             20,[0.05 0.5 0.05 0.5],2,256,6,'negative');
  
−
The contour-level vector differs from the strychnine example, and the last argument requests negative contours only.
+
==Exercises==
 +
These are open-ended exploration tasks, see the [[Built-in_experiments|built-in pulse sequence list]] for what is available. Suggestions:
 +
# Run other pulse sequences in the same family, for example, [[hmqc.m]]
 +
# Set the working ''J''-coupling to a deliberately incorrect value and observe the effect.
 +
# Increase and decrease the number of acquired points in <code>parameters.npoints</code> parameter.
 +
# Turn the decoupling off in one or both dimensions and observe the changes in the simulated spectrum.
 +
# Decrease the ''J''-coupling drop threshold in the spin system import command and observe the effect on the simulation time.  
 +
 
  
−
''Version 2.12, authors: [[Ilya Kuprov]], [[Luke Edwards]]''
+
''Version 2.12, authors: [[Ilya Kuprov]]''

Latest revision as of 11:00, 18 September 2026

Heteronuclear liquid-state NMR simulations in Spinach are set up in the same way as homonuclear simulations, but the pulse sequence parameters must specify multiple spin channels. This tutorial follows two examples from the Spinach example set: hsqc_strychnine.m, which simulates a phase-sensitive natural-abundance 13C HSQC spectrum of strychnine, and clip_hsqc_camphor.m, which simulates a natural abundance CLIP-HSQC spectrum of camphor.

Strychnine spin system

Chemical structure of strychnine

Spinach examples are functions rather than scripts: each run starts from a clean Matlab workspace. We must therefore open a new file and begin with with a function declaration:

    function hsqc_strychnine()

Unlike the previous tutorial where we had specified the spin system manually, here we use one of the standard spin systems supplied with Spinach - the strychnine spin system:

    [sys,inter]=strychnine({'1H','13C'});

The strychnine helper function returns the sys and inter input structures for the selected isotopes. In this example, proton and carbon-13 spins are imported. The strychnine data file contains proton shifts and couplings, carbon and nitrogen shifts and coordinates, and one-bond 13C-1H J-couplings. The magnetic field is then set in Tesla:

    sys.magnet=5.9;

The next line requests the "greedy" parallelisation option:

    sys.enable={'greedy'};

When Spinach starts a new parallel pool, this option means that every worker process is allowed to use every CPU core.

Basis set specification

The basis set is the same connectivity-adaptive Liouville-space basis used by many liquid-state examples:

    bas.formalism='sphten-liouv';
    bas.approximation='IK-2';
    bas.connectivity='scalar_couplings';
    bas.prox_level=1;

The IK-2 approximation builds a restricted state space rather than the complete Liouville space, and scalar_couplings instructs the basis generator to use the scalar-coupling graph for connectivity. The prox_level setting controls how far spatially local correlations are allowed into the basis: since HSQC does not rely on spatial proximity, this parameter is set to 1.

HSQC sequence parameters

The following parameters are required by the HSQC pulse sequence function:

    parameters.J=140;
    parameters.sweep=[10000 3000];
    parameters.offset=[4000 1000];
    parameters.npoints=[128 128];
    parameters.zerofill=[512 512];
    parameters.spins={'13C','1H'};
    parameters.decouple_f1={'1H'};
    parameters.decouple_f2={'13C'};
    parameters.axis_units='ppm';

Here parameters.J is the working heteronuclear scalar coupling in Hz, used to set the transfer delay. The two entries in parameters.sweep are the F1 and F2 sweep widths in Hz, and the two entries in parameters.offset are the corresponding transmitter or receiver offsets in Hz. The point counts in parameters.npoints are the acquired F1 and F2 dimensions, and parameters.zerofill gives the Fourier transform sizes used during processing. The spin list {'13C','1H'} means that the indirect F1 dimension is carbon-13 and the directly detected F2 dimension is proton. The decouple_f1 field lists spins that receive midpoint 180-degree refocusing pulses during F1 evolution, and decouple_f2 lists spins decoupled during F2 acquisition.

Spin system construction

We now create the spin system object from the information we have supplied above:

    spin_system=create(sys,inter);

The create function performs Spinach input processing and prints a report that should be checked for warnings. Natural-abundance carbon is handled by isotope dilution:

    subsystems=dilute(spin_system,'13C');

The dilute function returns a cell array of spin systems. With the default tuple size, each returned subsystem contains a single instance of the specified dilute isotope and all other carbon-13 spins have been removed. This makes a natural-abundance 13C HSQC simulation practical: the final spectrum is obtained as a sum over all single-carbon isotopomers.

We are going to be summing spectra up and we must therefore preallocate the sum:

    spectrum=zeros(parameters.zerofill(2),...
                   parameters.zerofill(1),'like',1i);

The first dimension of the matrix corresponds to the direct F2 dimension, and the second dimension corresponds to the indirect F1 dimension. The use of 'like',1i requests a complex array.

Strychnine HSQC simulation and isotopomer loop

HSQC simulation for strychnine.

Each isotopomer is to be simulated independently in a parallel loop:

    parfor n=1:numel(subsystems)

        % Build the basis
        subsystem=basis(subsystems{n},bas);

        % Simulation
        fid=liquid(subsystem,@hsqc,parameters,'nmr');

        % Apodisation
        fid.pos=apodisation(spin_system,fid.pos,{{'sqcos'},{'sqcos'}});
        fid.neg=apodisation(spin_system,fid.neg,{{'sqcos'},{'sqcos'}});

        % F2 Fourier transform
        f1_pos=fftshift(fft(fid.pos,parameters.zerofill(2),1),1);
        f1_neg=fftshift(fft(fid.neg,parameters.zerofill(2),1),1);

        % Form States signal
        fid=f1_pos+conj(f1_neg);

        % F1 Fourier transform
        spectrum=spectrum+fftshift(fft(fid,parameters.zerofill(1),2),2);

    end

Here, the basis set is built inside the loop; this is necessary because dilute removes basis-set information when it changes the spin system. The HSQC simulation is then run in the liquid-state context with NMR assumptions. The liquid context builds the isotropic Liouvillian, applies offsets and any other common sequence settings, and passes the resulting Hamiltonian, relaxation superoperator, and kinetics superoperator to hsqc.m. The HSQC sequence returns two components of the States quadrature signal. Both States components are multiplied by square-cosine windows in both dimensions. The direct dimension is transformed first, the States signal is then formed and the indirect dimension is transformed and added to the accumulated spectrum. Because each subsystem is independent, the loop is a natural use case for Matlab parfor.

Strychnine HSQC plotting

The final stage is to open a figure, scale it, and plot positive contours:

    kfigure(); scale_figure([1.5 2.0]);
    plot_2d(spin_system,real(spectrum),parameters,...
            20,[0.05 1.0 0.05 1.0],2,256,6,'positive');

The plot_2d arguments are the spin system, the real part of the spectrum, the experiment parameters, the number of contours, positive and negative contour elevation ranges, the non-linear contour-spacing curvature, the colour-map size, the colour-map curvature, and the contour sign selection. In this example the last argument requests positive contours only.

Camphor spin system import

Chemical structure of camphor.

Create a new function file. The difference with the previous example is that here we will import spin system information from a Gaussian log file:

    options.min_j=3.0; options.no_xyz=0;
    [sys,inter]=g2spinach(gparse('../standard_systems/camphor.log'),...
                     {{'H','1H'},{'C','13C'}},[31.8 182.1],options);
CLIP-HSQC simulation for camphor.

The gparse function reads the Gaussian output file. The g2spinach function converts the parsed electronic-structure data into Spinach input structures. The particle list imports hydrogen atoms as 1H and carbon atoms as 13C. The reference vector [31.8 182.1] supplies the absolute shielding references used by the conversion to chemical shifts. The options.min_j=3.0 setting discards scalar couplings smaller than 3 Hz, and options.no_xyz=0 keeps the coordinate information. We then specify the magnetic field:

    sys.magnet=14.1;

and replace the isotropic parts of the shielding tensors with experimental chemical shifts:

    inter.zeeman.matrix=shift_iso(inter.zeeman.matrix,1:26,...
                                  [ 29.70 26.80 44.20 59.70 42.80 ...
                                   218.1  49.70 17.80 17.30  7.80 ...
                                     1.35  1.67  1.97  1.31  1.96 ...
                                     0.85  0.85  0.85  0.99  0.99 ...
                                     0.99  0.90  0.90  0.90  2.33 1.76]);

The shift_iso function preserves the anisotropic parts of each tensor and replaces only the isotropic component with the supplied value.

Camphor CLIP-HSQC simulation

Use exactly the same basis set and other options as we have used above for strychnine, and the same parallel loop over isotopomers. The only difference now should be that CLIP-HSQC pulse sequence is called instead of HSQC:

    fid=liquid(subsystem,@clip_hsqc,parameters,'nmr');

and the plot must use negative contours:

    kfigure(); scale_figure([1.5 2.0]);
    plot_2d(spin_system,real(spectrum),parameters,...
            20,[0.05 0.5 0.05 0.5],2,256,6,'negative');

Exercises

These are open-ended exploration tasks, see the built-in pulse sequence list for what is available. Suggestions:

  1. Run other pulse sequences in the same family, for example, hmqc.m
  2. Set the working J-coupling to a deliberately incorrect value and observe the effect.
  3. Increase and decrease the number of acquired points in parameters.npoints parameter.
  4. Turn the decoupling off in one or both dimensions and observe the changes in the simulated spectrum.
  5. Decrease the J-coupling drop threshold in the spin system import command and observe the effect on the simulation time.


Version 2.12, authors: Ilya Kuprov