Skip to content

Commit ccb96df

Browse files
committed
RF: allow multiple parameters that need to be matched for populate_intended_for
TO DO: Add more potential matching parameters: imaging field of view, resolution, etc.
1 parent 1bd151b commit ccb96df

File tree

4 files changed

+61
-43
lines changed

4 files changed

+61
-43
lines changed

heudiconv/bids.py

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ def get_key_info_for_fmap_assignment(json_file, matching_parameter='Shims'):
590590
----------
591591
json_file : str or os.path
592592
path to the json file
593-
matching_parameter : str in ['shims', 'imaging_volume']
593+
matching_parameter : str in AllowedFmapParameterMatching
594594
matching_parameter that will be used to match runs
595595
596596
Returns:
@@ -620,7 +620,7 @@ def get_key_info_for_fmap_assignment(json_file, matching_parameter='Shims'):
620620
return key_info
621621

622622

623-
def find_compatible_fmaps_for_run(json_file, fmap_groups, matching_parameter='Shims'):
623+
def find_compatible_fmaps_for_run(json_file, fmap_groups, matching_parameters=['Shims']):
624624
"""
625625
Finds compatible fmaps for a given run, for populate_intended_for.
626626
@@ -631,36 +631,48 @@ def find_compatible_fmaps_for_run(json_file, fmap_groups, matching_parameter='Sh
631631
fmap_groups : dict
632632
key: prefix common to the group
633633
value: list of all fmap paths in the group
634-
matching_parameter : str in ['shims', 'imaging_volume']
635-
matching_parameter that will be used to match runs
634+
matching_parameters : list of str from AllowedFmapParameterMatching
635+
matching_parameters that will be used to match runs
636636
637637
Returns:
638638
-------
639639
compatible_fmap_groups : dict
640640
Subset of the fmap_groups which match json_file, according
641-
to the matching_parameter.
641+
to the matching_parameters.
642642
key: prefix common to the group
643643
value: list of all fmap paths in the group
644644
"""
645-
if matching_parameter not in AllowedFmapParameterMatching:
646-
raise ValueError(
647-
"Fmap matching_parameter %s not allowed." % matching_parameter
648-
)
645+
if type(matching_parameters) is not list:
646+
matching_parameters = [matching_parameters]
649647

650648
lgr.debug('Looking for fmaps for %s', json_file)
651-
json_info = get_key_info_for_fmap_assignment(json_file, matching_parameter)
649+
json_info = {}
650+
for param in matching_parameters:
651+
if param not in AllowedFmapParameterMatching:
652+
raise ValueError(
653+
"Fmap matching_parameter %s not allowed." % param
654+
)
655+
json_info[param] = get_key_info_for_fmap_assignment(json_file, param)
652656

653657
compatible_fmap_groups = {}
654658
for fm_key, fm_group in fmap_groups.items():
655-
# check the key_info for one (the first) of the fmaps in the group:
656-
fm_info = get_key_info_for_fmap_assignment(fm_group[0], matching_parameter)
657-
if json_info == fm_info:
659+
# check the key_info (for all parameters) for one (the first) of
660+
# the fmaps in the group:
661+
compatible = False
662+
for param in matching_parameters:
663+
fm_info = get_key_info_for_fmap_assignment(fm_group[0], param)
664+
if json_info[param] == fm_info:
665+
compatible = True
666+
else:
667+
compatible = False
668+
continue # don't bother checking more params
669+
if compatible:
658670
compatible_fmap_groups[fm_key] = fm_group
659671

660672
return compatible_fmap_groups
661673

662674

663-
def find_compatible_fmaps_for_session(path_to_bids_session, matching_parameter='Shims'):
675+
def find_compatible_fmaps_for_session(path_to_bids_session, matching_parameters=['Shims']):
664676
"""
665677
Finds compatible fmaps for all non-fmap runs in a session.
666678
@@ -669,18 +681,21 @@ def find_compatible_fmaps_for_session(path_to_bids_session, matching_parameter='
669681
path_to_bids_session : str or os.path
670682
path to the session folder (or to the subject folder, if there are no
671683
sessions).
672-
matching_parameter : str in ['shims', 'imaging_volume']
673-
matching_parameter that will be used to match runs
684+
matching_parameters : list of str from AllowedFmapParameterMatching
685+
matching_parameters that will be used to match runs
674686
675687
Returns:
676688
-------
677689
compatible_fmap : dict
678690
Dict of compatible_fmaps_groups (values) for each non-fmap run (keys)
679691
"""
680-
if matching_parameter not in AllowedFmapParameterMatching:
681-
raise ValueError(
682-
"Fmap matching_parameter %s not allowed." % matching_parameter
683-
)
692+
if type(matching_parameters) is not list:
693+
matching_parameters = [matching_parameters]
694+
for param in matching_parameters:
695+
if param not in AllowedFmapParameterMatching:
696+
raise ValueError(
697+
"Fmap matching_parameter %s not allowed." % param
698+
)
684699

685700
lgr.debug('Looking for fmaps for session: %s', path_to_bids_session)
686701

@@ -704,7 +719,7 @@ def find_compatible_fmaps_for_session(path_to_bids_session, matching_parameter='
704719

705720
# Loop through session_jsons and find the compatible fmap_groups for each
706721
compatible_fmaps = {
707-
j: find_compatible_fmaps_for_run(j, fmap_groups, matching_parameter)
722+
j: find_compatible_fmaps_for_run(j, fmap_groups, matching_parameters)
708723
for j in session_jsons
709724
}
710725
return compatible_fmaps
@@ -722,7 +737,7 @@ def select_fmap_from_compatible_groups(json_file, compatible_fmap_groups, criter
722737
compatible_fmap_groups : dict
723738
fmap_groups that are compatible with the specific json_file
724739
criterion : str in ['First', 'Closest']
725-
matching_parameter that will be used to decide which fmap to use
740+
matching_parameters that will be used to decide which fmap to use
726741
727742
Returns:
728743
-------
@@ -798,11 +813,11 @@ def select_fmap_from_compatible_groups(json_file, compatible_fmap_groups, criter
798813
return selected_fmap_key
799814

800815

801-
def populate_intended_for(path_to_bids_session, matching_parameter='Shims', criterion='Closest'):
816+
def populate_intended_for(path_to_bids_session, matching_parameters='Shims', criterion='Closest'):
802817
"""
803818
Adds the 'IntendedFor' field to the fmap .json files in a session folder.
804819
It goes through the session folders and for every json file, it finds
805-
compatible_fmaps: fmaps that have the same matching_parameter as the json
820+
compatible_fmaps: fmaps that have the same matching_parameters as the json
806821
file (e.g., same 'Shims').
807822
808823
If there are more than one compatible_fmaps, it will use the criterion
@@ -816,17 +831,20 @@ def populate_intended_for(path_to_bids_session, matching_parameter='Shims', crit
816831
path_to_bids_session : str or os.path
817832
path to the session folder (or to the subject folder, if there are no
818833
sessions).
819-
matching_parameter : str in ['shims', 'imaging_volume']
820-
matching_parameter that will be used to match runs
834+
matching_parameters : list of str from AllowedFmapParameterMatching
835+
matching_parameters that will be used to match runs
821836
criterion : str in ['First', 'Closest']
822-
matching_parameter that will be used to decide which of the matching
837+
matching_parameters that will be used to decide which of the matching
823838
fmaps to use
824839
"""
825840

826-
if matching_parameter not in AllowedFmapParameterMatching:
827-
raise ValueError(
828-
"Fmap matching_parameter %s not allowed." % matching_parameter
829-
)
841+
if type(matching_parameters) is not list:
842+
matching_parameters = [matching_parameters]
843+
for param in matching_parameters:
844+
if param not in AllowedFmapParameterMatching:
845+
raise ValueError(
846+
"Fmap matching_parameter %s not allowed." % param
847+
)
830848
if criterion not in AllowedCriteriaForFmapAssignment:
831849
raise ValueError(
832850
"Fmap assignment criterion '%s' not allowed." % criterion
@@ -851,7 +869,7 @@ def populate_intended_for(path_to_bids_session, matching_parameter='Shims', crit
851869

852870
compatible_fmaps = find_compatible_fmaps_for_session(
853871
path_to_bids_session,
854-
matching_parameter=matching_parameter
872+
matching_parameters=matching_parameters
855873
)
856874
selected_fmaps = {}
857875
for json_file, fmap_groups in compatible_fmaps.items():

heudiconv/heuristics/example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33

44
# Dictionary to specify options for the `populate_intended_for`.
5-
# Valid options are defined in 'bids.py' (for 'matching_parameter':
5+
# Valid options are defined in 'bids.py' (for 'matching_parameters':
66
# ['Shims', 'ImagingVolume',]; for 'criterion': ['First', 'Closest']
77
POPULATE_INTENDED_FOR_OPTS = {
8-
'matching_parameter': 'ImagingVolume',
8+
'matching_parameters': 'ImagingVolume',
99
'criterion': 'Closest'
1010
}
1111

heudiconv/tests/test_bids.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,20 @@ def mock_nibabel_load(file):
115115
with pytest.raises(FileNotFoundError):
116116
assert get_key_info_for_fmap_assignment('foo.json')
117117

118-
# 2) matching_parameter = 'Shims'
118+
# 2) matching_parameters = 'Shims'
119119
save_json(json_name, {SHIM_KEY: A_SHIM}) # otherwise get_key_info_for_fmap_assignment will give an error
120120
key_info = get_key_info_for_fmap_assignment(
121121
json_name, matching_parameter='Shims'
122122
)
123123
assert key_info == [A_SHIM]
124124

125-
# 3) matching_parameter = 'ImagingVolume'
125+
# 3) matching_parameters = 'ImagingVolume'
126126
key_info = get_key_info_for_fmap_assignment(
127127
json_name, matching_parameter='ImagingVolume'
128128
)
129129
assert key_info == [MY_AFFINE, MY_DIM[1:3]]
130130

131-
# 4) invalid matching_parameter:
131+
# 4) invalid matching_parameters:
132132
with pytest.raises(ValueError):
133133
assert get_key_info_for_fmap_assignment(
134134
json_name, matching_parameter='Invalid'
@@ -689,7 +689,7 @@ def test_find_compatible_fmaps_for_run(tmpdir, simulation_function):
689689
compatible_fmaps = find_compatible_fmaps_for_run(
690690
json_file,
691691
expected_fmap_groups,
692-
matching_parameter='Shims'
692+
matching_parameters='Shims'
693693
)
694694
assert compatible_fmaps == expected_compatible_fmaps[json_file]
695695

@@ -723,7 +723,7 @@ def test_find_compatible_fmaps_for_session(tmpdir, folder, expected_prefix, simu
723723
session_folder = op.join(str(tmpdir), folder)
724724
_, _, _, expected_compatible_fmaps = simulation_function(session_folder)
725725

726-
compatible_fmaps = find_compatible_fmaps_for_session(session_folder, matching_parameter='Shims')
726+
compatible_fmaps = find_compatible_fmaps_for_session(session_folder, matching_parameters='Shims')
727727

728728
assert compatible_fmaps == expected_compatible_fmaps
729729

@@ -802,7 +802,7 @@ def test_populate_intended_for(tmpdir, folder, expected_prefix, simulation_funct
802802

803803
session_folder = op.join(str(tmpdir), folder)
804804
session_struct, expected_result, _, _ = simulation_function(session_folder)
805-
populate_intended_for(session_folder, matching_parameter='Shims', criterion='First')
805+
populate_intended_for(session_folder, matching_parameters='Shims', criterion='First')
806806

807807
# Now, loop through the jsons in the fmap folder and make sure it matches
808808
# the expected result:

heudiconv/tests/test_convert.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,12 @@ def test_populate_intended_for(tmpdir, monkeypatch, capfd,
139139
More tests can be added here.
140140
"""
141141

142-
def mock_populate_intended_for(session, matching_parameter='Shims', criterion='Closest'):
142+
def mock_populate_intended_for(session, matching_parameters='Shims', criterion='Closest'):
143143
"""
144144
Pretend we run populate_intended_for, but just print out the arguments.
145145
"""
146146
print('session: {}'.format(session))
147-
print('matching_parameter: {}'.format(matching_parameter))
147+
print('matching_parameters: {}'.format(matching_parameters))
148148
print('criterion: {}'.format(criterion))
149149
return
150150
# mock the "populate_intended_for":
@@ -182,7 +182,7 @@ def mock_populate_intended_for(session, matching_parameter='Shims', criterion='C
182182
"\n".join([
183183
"session: " + outfolder.format(sID=s, ses=sesID),
184184
# "ImagingVolume" is defined in heuristic file; "Shims" is the default
185-
"matching_parameter: " + "ImagingVolume",
185+
"matching_parameters: " + "ImagingVolume",
186186
"criterion: Closest"
187187
]) in output.out
188188
for s in subjects

0 commit comments

Comments
 (0)