-
Notifications
You must be signed in to change notification settings - Fork 13
Fixes #732 Multi-Session support #753
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
Conversation
ExampleOkay, so we start with ADNI dataset {"folderHierarchy":["^sub-(.+)$","^(session_\\d{1}).+$","^(ASL|T1w|M0|T2|FLAIR)$","S.+$"],
"tokenOrdering":[1,2,0,3],
"tokenVisitAliases":["session_1","1","session_2","2","session_3","3"
,"session_4","4","session_5","5","session_6","6","session_7","7"],
"tokenSessionAliases":["",""],
"tokenScanAliases":["^ASL$","ASL4D","^T1w$","T1w","^M0$","M0","^T2$","T2w","^FLAIR$","FLAIR"],
"bMatchDirectories":true}We run the first import step... >> x = ExploreASL(pathTest,[1 0 0 0],0);
ExploreASL will run the import workflow and will run the initialization...
==============================================================================================
________ __ ______ ______ __
/ | / | / \ / \ / |
########/ __ __ ______ ## | ______ ______ ______ /###### |/###### |## |
## |__ / \ / | / \ ## | / \ / \ / \ ## |__## |## \__##/ ## |
## | ## \/##/ /###### |## |/###### |/###### |/###### |## ## |## \ ## |
#####/ ## ##< ## | ## |## |## | ## |## | ##/ ## ## |######## | ###### |## |
## |_____ /#### \ ## |__## |## |## \__## |## | ########/ ## | ## |/ \__## |## |_____
## |/##/ ## |## ##/ ## |## ##/ ## | ## |## | ## |## ##/ ## |
########/ ##/ ##/ #######/ ##/ ######/ ##/ #######/ ##/ ##/ ######/ ########/
## |
## |
##/
==================================== ExploreASL Settings =====================================
Dataset Root ...reDevelopment\MATLAB\m.stritt\Server_xASL\test_ADNI\test_out\011_S_4105
Import Modules DCM2NII
Process Modules
bPause False
iWorker 1
nWorkers 1
==============================================================================================
ExploreASL v1.8.0_BETA initialized ...
Matching files:
'sub-001\session_1_2013-07-26_15_10_24.0\ASL\S196762'
'sub-001\session_1_2013-07-26_15_10_24.0\FLAIR\S196758'
'sub-001\session_1_2013-07-26_15_10_24.0\T1w\S196752'
'sub-001\session_2_2015-07-29_12_17_39.0\ASL\S267385'
'sub-001\session_2_2015-07-29_12_17_39.0\FLAIR\S267396'
'sub-001\session_2_2015-07-29_12_17_39.0\T1w\S267391'
#=6
Running import (i.e. dcm2niiX)
==============================================================================================
...We get this temp directory structure ... Then we run the second step of the import ... >> x = ExploreASL(pathTest,[0 1 0 0],0);
ExploreASL will run the import workflow and will run the initialization...
==============================================================================================
________ __ ______ ______ __
/ | / | / \ / \ / |
########/ __ __ ______ ## | ______ ______ ______ /###### |/###### |## |
## |__ / \ / | / \ ## | / \ / \ / \ ## |__## |## \__##/ ## |
## | ## \/##/ /###### |## |/###### |/###### |/###### |## ## |## \ ## |
#####/ ## ##< ## | ## |## |## | ## |## | ##/ ## ## |######## | ###### |## |
## |_____ /#### \ ## |__## |## |## \__## |## | ########/ ## | ## |/ \__## |## |_____
## |/##/ ## |## ##/ ## |## ##/ ## | ## |## | ## |## ##/ ## |
########/ ##/ ##/ #######/ ##/ ######/ ##/ #######/ ##/ ##/ ######/ ########/
## |
## |
##/
==================================== ExploreASL Settings =====================================
Dataset Root ...reDevelopment\MATLAB\m.stritt\Server_xASL\test_ADNI\test_out\011_S_4105
Import Modules NII2BIDS
Process Modules
bPause False
iWorker 1
nWorkers 1
==============================================================================================
ExploreASL v1.8.0_BETA initialized ...
================================== dataset_description.json ==================================
Missing recommended fields: HEDVersion
================================== BIDS JSON Check Results ===================================
Missing recommended ASL fields: SliceEncodingDirection, AcquisitionVoxelSize, LabelingOrientation
The field ArterialSpinLabelingType is PASL, please check the dependencies below:
The following fields should be empty: LabelingDuration
================================== BIDS JSON Check Results ===================================
Missing recommended ASL fields: SliceEncodingDirection, AcquisitionVoxelSize, LabelingOrientation
The field ArterialSpinLabelingType is PASL, please check the dependencies below:
The following fields should be empty: LabelingDurationWe get this rawdata directory structure for both visits ... The we run the last import step and get ... >> x = ExploreASL(pathTest,[0 0 0 1],0);
ExploreASL will run the import workflow and will run the initialization...
==============================================================================================
________ __ ______ ______ __
/ | / | / \ / \ / |
########/ __ __ ______ ## | ______ ______ ______ /###### |/###### |## |
## |__ / \ / | / \ ## | / \ / \ / \ ## |__## |## \__##/ ## |
## | ## \/##/ /###### |## |/###### |/###### |/###### |## ## |## \ ## |
#####/ ## ##< ## | ## |## |## | ## |## | ##/ ## ## |######## | ###### |## |
## |_____ /#### \ ## |__## |## |## \__## |## | ########/ ## | ## |/ \__## |## |_____
## |/##/ ## |## ##/ ## |## ##/ ## | ## |## | ## |## ##/ ## |
########/ ##/ ##/ #######/ ##/ ######/ ##/ #######/ ##/ ##/ ######/ ########/
## |
## |
##/
==================================== ExploreASL Settings =====================================
Dataset Root ...reDevelopment\MATLAB\m.stritt\Server_xASL\test_ADNI\test_out\011_S_4105
Import Modules BIDS2LEGACY
Process Modules
bPause False
iWorker 1
nWorkers 1
==============================================================================================
ExploreASL v1.8.0_BETA initialized ...
Parsing BIDS scans: 100%
Note that any warnings may have only printed once if they were repeated for multiple scans
Always run your rawdata folder through the BIDS validator first and aim to avoid warnings
Converting from BIDS to Legacy: .\test_out\011_S_411100%
M0 parsed for .\test_out\011_S_4105\derivatives\ExploreASL\sub-001_2\ASL_1\ASL4D.nii.gz
Creating default dataPar.json since file was not found...
Overwriting x.dir.dataPar...With this derivatives directory ... DiscussionOverall I think the commits are quite clear and the changes make the code a lot more readable. Please don't let us overengineer here and let's try to get this merged until Wednesday. I'll run the |
|
I would do |
That 1 comes directly from the aliases. We can do aliases that do this. According to BIDS things like plain text would be possible too though: https://bids-specification.readthedocs.io/en/stable/02-common-principles.html |
HenkMutsaerts
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice work! Only some minor questions, and the general request to add comments. One hour of typing additional comments will help us (including you ;) a lot in the near future.
Functions/xASL_io_ReadDataPar.m
Outdated
| % Copyright 2015-2021 ExploreASL | ||
|
|
||
| %% Input Check | ||
| if nargin < 1 || isempty(pathDataPar) || ~exist(pathDataPar, 'file') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the first argument is not provided, it gives an error that the data par doesn't exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, easy fix: 4dbefa8 👍
Functions/xASL_io_ReadDataPar.m
Outdated
| % | ||
| % INPUT: | ||
| % pathDataPar - Filename of the input parameter file with either .m or .json extension | ||
| % bDataPar - Read JSON as dataPar.json (BOOLEAN, OPTIONAL, DEFAULT = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would turn it around. If DataPar is the default, then the new option is bStudyPar. Default is off, and special case is to turn it on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, easy fix: 4dbefa8 👍
Functions/xASL_io_ReadDataPar.m
Outdated
|
|
||
| %% Check deprecated fields | ||
| x = xASL_io_CheckDeprecatedFieldsX(x,true); | ||
| if bDataPar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems as if this was done by default previously, is this needed for the studypar as well? Or did it previously just do nothing inside this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you remember the studyPar.json that Beatriz showed us yesterday? It had some of these basic fields that shouldn't be there and that were in a sub-structure. That's partially caused by xASL_io_CheckDeprecatedFieldsX, which was only recently added to xASL_io_ReadDataPar (#717).
| @@ -0,0 +1,71 @@ | |||
| function xASL_imp_NII2BIDS_Session(imPar, bidsPar, studyPar, listSessions, nameSubjectSession, bidsLabel, iSession) | |||
| %xASL_imp_NII2BIDS_SubjectSession NII2BIDS conversion for a single sessions. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a single sessions -> a single session.
Also, add that this is a BIDS session and legacy visit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, fixed the other comments in the header too 9c36709 👍
| sessionLabel = ''; | ||
|
|
||
| % Only one session - no session labeling | ||
| if ~exist(fullfile(imPar.BidsRoot,['sub-' subjectLabel]),'dir') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above. But I would always create a folder for sessions, that makes our life easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely agree, I answered above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I understand. But disagree. My understanding was that BIDS encourages you not to create a ses subfolder when there is only a single session. So it makes your life easier, but goes against BIDS philosophy. We have this here, I would keep it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. BIDS philosophy makes it easier for users here. Sadly that comes with a little bit more work for the developers.
| % imPar - JSON file with structure with import parameter (REQUIRED, STRUCT) | ||
| % bidsPar - Output of xASL_imp_Config (REQUIRED, STRUCT) | ||
| % studyPar - JSON file with the BIDS parameters relevant for the whole study (REQUIRED, STRUCT) | ||
| % nameSubjectSession - name of the subject (REQUIRED, LIST) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LIST should be a cell structure right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, fixed it 088eadb 👍
|
|
||
| subjectLabel = xASL_adm_CorrectName(nameSubject,2); | ||
| % Make a subject directory | ||
| if ~exist(fullfile(imPar.BidsRoot,['sub-' bidsLabel.subject]),'dir') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above 088eadb 😄
| end | ||
|
|
||
| %% 2. Process the anat & perfusion files | ||
| listSessions = xASL_adm_GetFileList(fullfile(imPar.TempRoot,nameSubjectSession),'^ASL.+$',false,[],true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we not mixing up sessions (visits) and runs (sessions) here? A list of sessions should in legacy be based on _1 _2 _3 etc., not on ASL.+
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a bit mixed up almost everywhere. It would be a lot easier if we had written down both notations for each function/section. This should be legacy visits I think (which is BIDS sessions) and there we have ASL_1 for visit 1 etc., right? I mean... it worked so far 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, in legacy we have sessions (BIDS runs) ASL_1 ASL_2 ASL_3.
Also, in legacy we have visits (BIDS sessions) sub-001_1 sub-001_2 sub-001_3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Agree. This is mixed up. But only the terminology is mixed up. It functions correctly...
We have used here in BIDS function the Legacy terminology. It is indeed incorrect to call it sessions, but it is treating it as runs, so we only need to change the names. I would do that in issue #775 - we already mention it there.
| end | ||
| end | ||
|
|
||
| bidsLabel.subject = xASL_adm_CorrectName(subjectName,2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure here that we correct only the 'value' (for the keys sub- and ses-)? Or should this be done somewhere else to ensure that this is always the value?
Please also add a bit more comments, it's quite difficult to follow these scripts. I know that you're in a rush but this will backfire.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like with a few other comments I have to say that this wasn't necessarily created in a rush. This was like this before and just moved. Before it was called nameSubject, but other than that we used the same correction function and everything. Adding more comments to code in general can be helpful though 😉
Regarding the specific functionality: I had to figure this out first too, but a simple debug made it super clear. We extract subject/visit from the name, so you could have something like sub-001_ses-1 or whatever and there we basically only want the 001 and the 1. We need to get rid of the hyphens and underscores, which is why we use xASL_adm_CorrectName. We did this exactly like this before though and was probably originally written by @jan-petr.
Full BIDS Pipeline TestI just tested these six datasets and everything seems fine to me 😄 |
|
@HenkMutsaerts: I created the follow-up issues #754 & #755. Otherwise everything should be fine. We should focus on fixing #754 quickly. |
HenkMutsaerts
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor stuff left, nearly there!
Functions/xASL_bids_BIDS2Legacy.m
Outdated
| %% 10. Create dataPar.json | ||
|
|
||
| % Write DataParFile if it does not exist already | ||
| if ~(xASL_exist(fullfile(pathLegacy, 'dataPar.json'),'file')==2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change this into:
if ~xASL_exist(fullfile(pathLegacy, 'dataPar.json'), 'file')
so in Matlab you can omit the outer () brackets, and with 'file' you don't need to ask if it's equal to 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0d367c3 👍
|
|
||
|
|
||
| %% 1. Input check | ||
| fprintf('================================== BIDS to LEGACY CONVERSION =================================\n'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LEGACY is our internal nomenclature, this has no meaning to the users, if you call it "ExploreASL legacy" this should be fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if ~isempty(visitLabel) | ||
| sessionLabel = ['ses-' visitLabel]; | ||
| else | ||
| sessionLabel = ['ses-' listSessions{iSession}(5:end)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, if it's indeed iterating over sessions and not SubjectSession (what is very confusing as throughout the processing modules, we refer to SubjectSession as what is SubjectRun in BIDS... :)
| xASL_adm_CreateDir(fullfile(imPar.BidsRoot,['sub-' subjectLabel],sessionLabel,'perf')); | ||
| end | ||
| inSessionPath = fullfile(imPar.TempRoot,nameSubjectSession,listSessions{iSession}); | ||
| outSessionPath = fullfile(imPar.BidsRoot,['sub-' subjectLabel],sessionLabel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but we don't get to see what the users do. So we only have to add a check later that it doesn't have twice sub- in the name, same for ses-.
| end | ||
|
|
||
| %% 2. Process the anat & perfusion files | ||
| listSessions = xASL_adm_GetFileList(fullfile(imPar.TempRoot,nameSubjectSession),'^ASL.+$',false,[],true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, in legacy we have sessions (BIDS runs) ASL_1 ASL_2 ASL_3.
Also, in legacy we have visits (BIDS sessions) sub-001_1 sub-001_2 sub-001_3.
|
|
||
| % Get visitAliases from imPar | ||
| visitAliases = imPar.tokenVisitAliases(:,2); | ||
| if isfield(imPar,'tokenVisitAliases') && ~isempty(imPar.tokenVisitAliases) && size(imPar.tokenVisitAliases,2)>1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can omit the ~isempty if you check for (size( , 2)>1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't hurt though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it doesn't add anything. If it is empty, size()>1 will also return 0. So it is just extra time reading, would remove this.
Current versionsourcedata... DCM2NIItemp data... NII2BIDSrawdata... BIDS2LEGACYderivatives... |
jan-petr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the commits I made - they should all be minor.
See my answers. All can be resolved and/or moved to #775. So as far as I am concerned, we can merge.
| if ~isempty(visitLabel) | ||
| sessionLabel = ['ses-' visitLabel]; | ||
| else | ||
| sessionLabel = ['ses-' listSessions{iSession}(5:end)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't remember the history and we have to revamp this whole import to really use correctly sessions and not visits.
Here, obviously, if the visitLabel is missing, it extracts the visit from the session label by removing the first four characters (=="ses-") from the session label.
Again - the sessions/visit run methodology has to be unified for BIDS - I have created new issues for that in 1.9.0. #775
| xASL_adm_CreateDir(fullfile(imPar.BidsRoot,['sub-' subjectLabel],sessionLabel,'perf')); | ||
| end | ||
| inSessionPath = fullfile(imPar.TempRoot,nameSubjectSession,listSessions{iSession}); | ||
| outSessionPath = fullfile(imPar.BidsRoot,['sub-' subjectLabel],sessionLabel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point - let's make a new issue for that. Or rather lets glue that to #775 (I've just done that).
| sessionLabel = ['_' sessionLabel]; | ||
| else | ||
| % Session label is skipped | ||
| sessionLabel = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really understand the issue here. Yes - let's add to #775.
| sessionLabel = ''; | ||
|
|
||
| % Only one session - no session labeling | ||
| if ~exist(fullfile(imPar.BidsRoot,['sub-' subjectLabel]),'dir') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I understand. But disagree. My understanding was that BIDS encourages you not to create a ses subfolder when there is only a single session. So it makes your life easier, but goes against BIDS philosophy. We have this here, I would keep it.
| end | ||
|
|
||
| %% 2. Process the anat & perfusion files | ||
| listSessions = xASL_adm_GetFileList(fullfile(imPar.TempRoot,nameSubjectSession),'^ASL.+$',false,[],true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Agree. This is mixed up. But only the terminology is mixed up. It functions correctly...
We have used here in BIDS function the Legacy terminology. It is indeed incorrect to call it sessions, but it is treating it as runs, so we only need to change the names. I would do that in issue #775 - we already mention it there.
In the studyPar we should not do the deprecated fields moving that we do for the dataPar.json. This fix is related to issue #752.
…odality behavior
1f52e94 to
dccbdcf
Compare
|
Hello ExploreASL experts, Previously, I have performed ExploreASL on OASIS datasets by keeping manually prepared subjects folder inside the analysis folder using version 1.5.1. I was able to run 5-6 subjects simultaneously. For the ADNI dataset, can you please inform me what major changes I need to make to run the ExploreASL on a group of subjects? Will the convert to source options work if I place several subjects with label files inside the ADNI folders? Thanks for your support and consideration. Regards, |




















Linked issue
Check out #732
Major changes
BIDS_fullPipelineTest.mtoxASL_test_FullPipelineTest.mxASL_io_ReadDataPar.mxASL_bids_BIDS2Legacy.mto import modulexASL_imp_DCM2NII_Subject.mxASL_imp_NII2BIDS_SubjectSession.mtoxASL_imp_NII2BIDS_Session.mxASL_imp_NII2BIDS_SubjectSessionRun.mtoxASL_imp_NII2BIDS_Run.m...RunAnat.m&...RunPerf.mRelease notes
Cleaning code of DCM to BIDS import