jjhelmus / nmrglue

A module for working with NMR data in Python
BSD 3-Clause "New" or "Revised" License
208 stars 85 forks source link

Echo anti-echo aquisition #149

Closed aj-adkins closed 3 years ago

aj-adkins commented 3 years ago

I am trying to process data in which the echo anti-echo (or rance-kay) method needs to be applied, but I do not see that this is a feature of nmrglue. I am attempting to do this by manipulating the data manually. I have read that the data needs to be separated into the echo or N-type spectrum and the anti-echo or P-type spectrum, but how would I actually go about obtaining or separating these two spectra within the the numpy array in nmrglue? Any help is much appreciated.

kaustubhmote commented 3 years ago

If the data are arranged as "one fid per row", you can separate them using Numpy's array-slicing syntax:

dataP, dataN = data[0::2], data[1::2]

If you need to convert the data into a "one row per fid" format, you can reshape using the value of the number of points in the direct dimension. For Bruker datasets, this would look like this:


dic, data = ng.bruker.read(filename)
data = data.reshape(-1, dic["acqus"]["TD"])

You should also look at the function given here: nmrgle/process/nmrtxt/rance_kay.py to see how to do the reshuffling. This function is currently not available directly from nmrglue.

aj-adkins commented 3 years ago

Thank you so much, this will be a lot of help! Just curious, my dataset is in the Varian format, so would it be different than this method with Bruker data or is it relatively the same?

kaustubhmote commented 3 years ago

The splitting part should be identical. The reading part will be similar except for using the function in the agilent module, and the reshaping part will only differ in the parameter to be looked up from the dictionary.

dic, data = ng.agilent.read(filepath)
data = data.reshape(-1, dic["np"])
dataP, dataN = data[0::2], data[1::2]
aj-adkins commented 3 years ago

Ok so I tried reshuffling the data according to your instructions and following the function within rance_kay.py, and I've tried a number of techniques, but in all cases the spectrum ends up looking like some variation of this:

download (2) For reference, the correct spectrum should look like this:

download (3) Maybe I am reconstructing the data array incorrectly? Here is my code (excluding standard processing and plotting):

import nmrglue as ng
import numpy as np
import matplotlib.pyplot as plt

vdic, vdata = ng.varian.read('EJS218_0mM_15NHSQC_20C_112018.fid', torder='f', as_2d=True)
vdata = vdata.reshape(-1, vdic["np"])
dataP, dataN = vdata[0::2], vdata[1::2] 
shuffle = np.empty(vdata.shape, vdata.dtype)

for i in range(0, int(0.5*vdata.shape[0]), 2):
    shuffle[2*i] = 1.*(dataP[i].real - dataN[i].real) + 1.*(dataP[i].imag - dataN[i].imag)*1j
    shuffle[2*i+1] = -1.*(dataP[i].imag - dataN[i].imag) + 1.*(dataP[i].real - dataN[i].real)*1j

C = ng.convert.converter()
C.from_varian(vdic, shuffle)
dic, data = C.to_pipe()

I apologize, I am by no means an expert at NMR nor programming.

kaustubhmote commented 3 years ago

I think the P and N datasets should be added while setting shuffle[2*i+1] instead of being subtracted.

Also, I think you are basing this on the function that is appropriate for the way Bruker stores the data. I think the way Varian does this is slightly different. I don't have a handy Varian dataset that I can check this against, but since you seem to have nmrpipe, I suggest looking up the var_ranceY.M macros in nmrpipe/nmrtxt and comparing that with the bruk_ranceY.M in the same folder to see the difference.

aj-adkins commented 3 years ago

Just a follow up on this issue, I looked at the code for the var_ranceY.M macro in NMRPipe and it gave me a little bit of insight into my own goal.

I figured out that keeping the data in its original shape instead of reshaping and reshuffling the data simply by stacking the two sets next to each other yields a result closer to what I am seeking.

Here is what this method yields: download (6)

And here is what it should look like: download (3)

And here is the code (for the first version):

vdic, vdata = ng.varian.read('EJS218_0mM_15NHSQC_20C_112018.fid', torder='f', as_2d=True)
dataP, dataN = vdata[0::2], vdata[1::2] 

shuffle = np.empty(vdata.shape, vdata.dtype)
x = int(0.5*vdata.shape[0])
for i in range(0, x):
    shuffle[i] =  1.*(dataP[i].real - dataN[i].real) + 1.*(dataP[i].imag - dataN[i].imag)*1j
    shuffle[i+x] = 1.*(dataP[i].imag + dataN[i].imag) + 1.*(dataP[i].real + dataN[i].real)*1j

C = ng.convert.converter()
C.from_varian(vdic, shuffle)
dic, data = C.to_pipe()

Some differences to note, the spectrum seems to be similar but with extra points, and it is flipped about the y-axis. Also, the scales on the axes are way off from the actual chemical shift values. I'm assuming that there is one additional bit of processing that I need but I'm not sure what it is.

kaustubhmote commented 3 years ago

Not quite sure what might be missing here, but if it is possible for you to share the dataset, I'll be happy to take a look.

aj-adkins commented 3 years ago

Here is the dataset. Thank you so much for your help once again.

EJS218_0mM_15NHSQC_20C_112018.fid.zip

kaustubhmote commented 3 years ago

Your Echo-antiecho processing is correct, but the loop you are using to put fids in the shuffle array has a bug. The real and the imaginary datasets should be interleaved, not stacked one after the other. The following works (i.e., gives the same result if processed in pipe/nmrglue).

summ, diff = data[0::2], data[1::2]
A = summ - diff
B = -1j * (summ + diff)
shuffled = np.empty(data.shape, data.dtype)
shuffled[0::2] = A
shuffled[1::2] = B

# use shuffled to process the 2d using the standard way
aj-adkins commented 3 years ago

Thank you so much! I suspected I was doing the interleaving wrong, I just had slightly better results from stacking the data.

The only thing is that when I process and plot the data in exactly the same way, the scales of the axes are still off. For example, the 15N axis is on the order of 0.5-1.5 when it should be 105-135. Would this also be a problem with the conversion?

Edit: I actually just figured the rest out, thank you so much for your help!