mne-python icon indicating copy to clipboard operation
mne-python copied to clipboard

snirf import - source or detector position

Open jeanbaptiste-billaud opened this issue 1 year ago • 10 comments

Describe the bug

The import of snirf data from an Artinis-portalite device cause an assert error. The device have 3 sources but only one detector which leads to a 2D position format error.

Expected results

in RawSNIRF class code:

detPos2D = np.array(dat.get('nirs/probe/detectorPos2D'))

shape of detPos2D:

detPos2D.shape --> (2,)
len(detPos2D.shape) --> 1

Solution

  1. for oxy4 file directly converted in snirf : correction of detPos2D to be able to create detPos3D
detPos2D = np.array(dat.get('nirs/probe/detectorPos2D'))
if len(detPos2D.shape) == 1:
> detPos2D = detPos2D.reshape(len(detectors), 2)
  1. for oxy4 file converted in nirs then in snirf : correction of detPos3D
if len(detectors) != detPos3D.shape[0]:
> detPos3D = detPos3D.T   
> assert len(detectors) == detPos3D.shape[0]

jeanbaptiste-billaud avatar Jul 29 '22 12:07 jeanbaptiste-billaud

Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴🏽‍♂️

welcome[bot] avatar Jul 29 '22 12:07 welcome[bot]

ping @rob-luke, our fNIRS expert

drammock avatar Aug 02 '22 15:08 drammock

Thanks for submitting this issue @Helianthus89. Sorry for the delayed response.

I have not used the Artinis-portalite before, but if the file is in snirf format we should (in theory) be able to read it. Can you share an example file with me and I can try and debug what the issue is?

rob-luke avatar Aug 26 '22 05:08 rob-luke

@rob-luke , here you'll find a file in both format oxy4 and snirf, and the optode template to be able to convert oxy4 to an other format. I also include my modified version of the mne import function.

portalite_mne.zip

jeanbaptiste-billaud avatar Aug 26 '22 07:08 jeanbaptiste-billaud

Sorry for the delay getting back to you @Helianthus89

The file you provided is not a valid SNIRF file. I tested this by using the SNIRF validator from the Boston University Neurophotonics Center.

In [1]: import snirf

In [2]: v = snirf.validateSnirf("/Users/rluke/Downloads/portalite_mne/portalite_record.snirf")

In [3]: v
Out[3]: <snirf.pysnirf2.ValidationResult object at 0x10877d820> is_valid False

There are a number of errors with the file. It would be great if you could ask the manufacturer to ensure their files are valid using the official validator.

However, we can try and make it so you can load the file in MNE. I have managed to get the files to load, and I can submit this fix as a pull request to MNE. But first, can you help me understand how the portalite system works—how do you tell the software where the source and detector optodes are? Or does that not matter? Can you share with me where the sources and detectors were placed for the file you shared?

Thanks, Rob

rob-luke avatar Sep 11 '22 09:09 rob-luke

And for anyone reading along, a fix seems to be to edit line 203 of the snirf.py to include

            # Fix issue when there is only one optode
            if detPos3D.shape == (3, 1):
                detPos3D = detPos3D.T
            if srcPos3D.shape == (3, 1):
                srcPos3D = srcPos3D.T
            assert len(sources) == srcPos3D.shape[0]
            assert len(detectors) == detPos3D.shape[0]

rob-luke avatar Sep 11 '22 09:09 rob-luke

@rob-luke,

I'm really not surprise by the issue that you get from the snirf file. Artinis is my 1st experience on fnirs, until now i almost work on MRI and a little bit on EEG. In any case, both modalities have common file format accross manufacturers. In the present case, Artinis use a proprietary file format, the oxy file, and the only tool for convert oxy file in an other format is the toolbox oxysoft2matlab, that's probably out of date (https://github.com/jayd1860/oxysoft2matlab). I also try to use the oxyfile MNE reader, avaible on the website of Artinis, without success despite some email exchanges with their support.

I can't tell you how the portalite system work, data was acquiered before my recruitment, but i guess that's work with the same way that other Artinis devices.

However, in the cas of portalite, there's not 3D optodes position, only 1D because there's 3 sources and 1 detector with a distance of 30, 35, and 40 mm, lined up on the same axis.

jeanbaptiste-billaud avatar Sep 12 '22 07:09 jeanbaptiste-billaud

Thanks for the feedback @Helianthus89 Can I use the snirf file you shared as test data for MNE? Then I can submit a fix for the bug you found where there is only 1 source or detector.

We will also need to find a way to allow you to specify the S-D distance manually (for beer-lambert law), as you don't have accurate spatial information in the file. Once the fix for the data input is merged I can tackle this change to the API for beer lambert.

rob-luke avatar Sep 13 '22 12:09 rob-luke

We will also need to find a way to allow you to specify the S-D distance manually (for beer-lambert law), as you don't have accurate spatial information in the file. Once the fix for the data input is merged I can tackle this change to the API for beer lambert.

To me the right fix is to create and apply a montage with S* and D* channels that is as close to reality as possible. Then you get a lot of stuff for free (e.g., all sensor plots become reasonable instead of potentially nonsensical) in addition to having things set up properly for beer-lambert

larsoner avatar Sep 13 '22 13:09 larsoner

@rob-luke, of course you can use data-files i shared here, data are anonymised so it's ok. I'm not sur to well understand the last part of your post. After adapted the import function to be able to transform 1D to 3D optodes positions, i was able to process my data like any other nirs data (OD then BL). Do you think that the lack of precision about optodes location could be induce a wrong Beer-Lambert conversion ?

jeanbaptiste-billaud avatar Sep 13 '22 13:09 jeanbaptiste-billaud

Hi @jeanbaptiste-billaud,

Just came across this issue by doing a search for Artinis support in MNE. Hopefully you managed to solve your issue already. I had issues with non-supported fNIRS devices in the past and used some workarounds that you can find here: https://github.com/HanBnrd/NIRSimple/blob/master/examples/simple_probe.ipynb. You will however lose optode positions in that process, but it can be useful in cases where you only care about source-detector distances and not positions.

Hope that helps, good luck!

HanBnrd avatar Apr 02 '23 17:04 HanBnrd