Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversion failure on GE data #123

Open
mcraig-ibme opened this issue Dec 12, 2023 · 18 comments
Open

Conversion failure on GE data #123

mcraig-ibme opened this issue Dec 12, 2023 · 18 comments

Comments

@mcraig-ibme
Copy link

I am getting a conversion failure on GE MRS data - the command line and backtrace are below, however the root cause seems to be zeros in one column of the affine matrix. If I print out the calculated affine I get:

[[-22.80869862   0.          -3.10708493 -31.39293289]
 [ 11.13030002   0.          22.59598556  53.63864517]
 [ 15.99623983   0.         -20.15277751  29.13773346]
 [  0.           0.           0.           1.        ]]

Any ideas what might be going wrong, and whether there's any way to work around this?
Many thanks,
Martin

spec2nii ge -o mrs_mask -f mrs_data -j P03072.7

/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py:1088: RuntimeWarning: invalid value encountered in divide
  R = RZS / zooms
/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py:2180: RuntimeWarning: invalid value encountered in det
  r = _umath_linalg.det(a, signature=signature)
Traceback (most recent call last):
  File "/home/bbzmsc/.conda/envs/brightmind/bin/spec2nii", line 10, in <module>
    sys.exit(main())
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 679, in main
    spec2nii(*args)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 290, in __init__
    args.func(args)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 628, in ge
    self.imageOut, self.fileoutNames = read_pfile(args.file, args.fileout)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/GE/ge_pfile.py", line 71, in read_pfile
    data, fname_suffix = _process_svs_pfile(pfile)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/GE/ge_pfile.py", line 113, in _process_svs_pfile
    out_nmrs.append(gen_nifti_mrs_hdr_ext(dd, dwelltime, mm, orientation.Q44, no_conj=True))
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nifti_mrs/create_nmrs.py", line 128, in gen_nifti_mrs_hdr_ext
    tmp_img = nib.nifti2.Nifti2Image(
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1848, in __init__
    super().__init__(dataobj, affine, header, extra, file_map, dtype)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/analyze.py", line 909, in __init__
    super().__init__(dataobj, affine, header, extra, file_map)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/spatialimages.py", line 531, in __init__
    self.update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 2273, in update_header
    super().update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1884, in update_header
    super().update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/spatialimages.py", line 565, in update_header
    self._affine2header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1894, in _affine2header
    hdr.set_qform(self._affine, code='unknown')
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1100, in set_qform
    P, S, Qs = npl.svd(R)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py", line 1681, in svd
    u, s, vh = gufunc(a, signature=signature, extobj=extobj)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py", line 121, in _raise_linalgerror_svd_nonconvergence
    raise LinAlgError("SVD did not converge")
numpy.linalg.LinAlgError: SVD did not converge
@wtclarke
Copy link
Owner

Hi Martin,

What's the data specifically? SVS/MRSI? What particular sequence? Orientation etc?

GE is definitely the vendor I have least experience with and least test data currently, so there is likely stuff I get not entirely right. Are you able to share the data?

@mcraig-ibme
Copy link
Author

Hi, thanks for the response, still waiting to find out if I'm allowed to share the data, it's MRS but I don't know more details of the sequence, sorry, it's not my area of expertise! I will get back to you if I can find out some more details.

@wtclarke
Copy link
Owner

wtclarke commented Dec 13, 2023

If it turns out you can't share it we can do some digging here.

You could:

  1. Stick a breakpoint here and inspect the value of psd, which will give us a good idea of the sequence.
  2. Then the place where the NIfTI orientation is calculated is in this _calculate_affine function. From the backtrace it looks like there is a zero somewhere there shouldn't be. What do voxel_size and dcos evaluate to in that function?

@JonteP
Copy link

JonteP commented Dec 18, 2023

I have the exact same issue with GE data. Interestingly, we run the same sequence with same voxel dimensions in three different locations and only one of them behaves like this.

psd=probe-p
dcos=[[-0.84649784 0.15044474 -0.51069346]
[-0.24917919 0.73573466 0.62976525]
[-0.47047969 -0.66034907 0.5853101 ]]
voxel_size=[25. 30. 0.]

hacking ge_pfile.py to force voxel_size to the expected dimensions [25,30,20] makes everything run fine and the stored voxel placement looks correct.

Comparing the three voxels, the other two are placed close to the midline with mainly rotations around the x-axis (dorsal ACC and V1), while this one that causes trouble is placed at the dorsolateral PFC with much more rotations applied. Can that make a difference?

@wtclarke
Copy link
Owner

Hi @JonteP , do you have access to the GE distributed pfile reading software? If so can you tell me if that also reads the wrong voxel sizes?

I believe the sizes should be in:
rhi_user8
rhi_user9
rhi_user10

What version of scanner software are you on?

@JonteP
Copy link

JonteP commented Dec 18, 2023

Hi @JonteP , do you have access to the GE distributed pfile reading software? If so can you tell me if that also reads the wrong voxel sizes?

I believe the sizes should be in: rhi_user8 rhi_user9 rhi_user10

What version of scanner software are you on?

I don't believe I have access to that software. I tried running Osprey's CoRegister function on the p-file with a t1 and it seems to read the voxel placement and dimensions fine.

The software version listed in json sidecars from other sequences that were converted with dcm2niix is "27\LX\MR Software release:MP26.0_R02_1941.a".

Hope that helps!

@wtclarke
Copy link
Owner

Great, are you able to share the data?

@JonteP
Copy link

JonteP commented Dec 18, 2023

I'm sorry, I do not own the data. Maybe it helps to look at Osprey's GELoad.m?

It identifies the version as 26.002 so the magic happens under case {'26.002','27','27.001','28.002','28.003','30'}

hdr.geometry.size will be set to [25 20 30].

@wtclarke
Copy link
Owner

@mcraig-ibme and @JonteP I have a proposed fix, but without any test data and a matching image of what the voxel orientation should look like I don't know whether its right. Would you be so kind as to test the 123-conversion-failure-on-ge-data-1 branch on your data?

@mcraig-ibme Your example data now generates a valid file, but I can't tell if the orientation information is correct.

@JonteP
Copy link

JonteP commented Mar 21, 2024

I just tried that branch and while it now converts without any issue, the voxel placement still seems problematic.
We have 3 voxel placements, 2 of which are in the dorsal ACC and medial occipital cortex. These are basically only rotated within a sagittal plane and both are oriented correctly after spec2nii conversion. The third voxel placement is within the dorsolateral PFC, and rotated in all three dimensions. These were problematic to convert before, and now appear to be oriented the wrong way. Note how it is elongated in the z-direction rather than y:
image

@wtclarke
Copy link
Owner

wtclarke commented Mar 21, 2024 via email

@JonteP
Copy link

JonteP commented Mar 21, 2024

Again, Osprey handles this correctly if I load the P-file directly (looks more or less like a 90 degree rotation is needed in each dimension):
image

@wtclarke
Copy link
Owner

Ok, but I can't reverse engineer their entire code, especially without test data. I've just pushed another update to the same branch. It has similar logic now to osprey, but I don't know the exact ordering of the dimensions that will be needed. As such I've put some debug statements in which will tell me what is happening in your case. Would you be so kind as to run your three examples again an report back whether their orientations are correct and what the printed outputs are?

@JonteP
Copy link

JonteP commented Apr 8, 2024

Took a while, but I tested the latest code now and the voxel placement matches Osprey and looks correct. This is the debug output:
25.0
20.0
30.0
1
[25. 30. 20.]

@wtclarke
Copy link
Owner

wtclarke commented Apr 8, 2024

Great, and thanks for coming back to me. Do the other cases still match?

@JonteP
Copy link

JonteP commented Apr 11, 2024

Yes, they look ok. The debug output for those that already worked previously is:
25.0
30.0
20.0
2
[25. 30. 20.]

@wtclarke
Copy link
Owner

Thanks. @markmikkelsen is collecting me some data to validate this on, at which point I'll get this included in the main release.

@miltoncamachocamacho
Copy link

Hi @wtclarke,

Are there any plans to support the new GE format ScanArchives.h5?

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

4 participants