Coverage for nilearn/interfaces/fmriprep/tests/test_load_confounds_strategy.py: 0%

74 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-16 12:32 +0200

1import re 

2 

3import pandas as pd 

4import pytest 

5 

6from nilearn.interfaces.fmriprep import load_confounds, load_confounds_strategy 

7from nilearn.interfaces.fmriprep.load_confounds_strategy import ( 

8 preset_strategies, 

9) 

10from nilearn.interfaces.fmriprep.tests._testing import create_tmp_filepath 

11 

12 

13@pytest.mark.parametrize("fmriprep_version", ["1.4.x", "21.x.x"]) 

14@pytest.mark.parametrize( 

15 "denoise_strategy,image_type", 

16 [ 

17 ("simple", "regular"), 

18 ("scrubbing", "regular"), 

19 ("compcor", "regular"), 

20 ("ica_aroma", "ica_aroma"), 

21 ], 

22) 

23@pytest.mark.filterwarnings("ignore::RuntimeWarning") 

24def test_load_confounds_strategy( 

25 tmp_path, denoise_strategy, image_type, fmriprep_version 

26): 

27 """Smoke test with no extra inputs.""" 

28 file_nii, _ = create_tmp_filepath( 

29 tmp_path, 

30 image_type=image_type, 

31 copy_confounds=True, 

32 copy_json=True, 

33 fmriprep_version=fmriprep_version, 

34 ) 

35 confounds, _ = load_confounds_strategy( 

36 file_nii, denoise_strategy=denoise_strategy 

37 ) 

38 assert isinstance(confounds, pd.DataFrame) 

39 

40 

41@pytest.mark.parametrize("fmriprep_version", ["1.4.x", "21.x.x"]) 

42@pytest.mark.parametrize( 

43 "denoise_strategy,image_type", 

44 [ 

45 ("simple", "regular"), 

46 ("scrubbing", "regular"), 

47 ("compcor", "regular"), 

48 ("ica_aroma", "ica_aroma"), 

49 ], 

50) 

51@pytest.mark.filterwarnings("ignore::RuntimeWarning") 

52def test_strategies(tmp_path, denoise_strategy, image_type, fmriprep_version): 

53 """Check defaults setting of each preset strategy.""" 

54 file_nii, _ = create_tmp_filepath( 

55 tmp_path, 

56 image_type=image_type, 

57 copy_confounds=True, 

58 copy_json=True, 

59 fmriprep_version=fmriprep_version, 

60 ) 

61 confounds, _ = load_confounds_strategy( 

62 file_nii, denoise_strategy=denoise_strategy 

63 ) 

64 # Check that all fixed name model categories have been successfully loaded 

65 list_check = _get_headers(denoise_strategy) 

66 for col in confounds.columns: 

67 # Check that all possible names exists 

68 checker = [ 

69 re.match(keyword, col) is not None for keyword in list_check 

70 ] 

71 assert sum(checker) == 1 

72 

73 

74patterns = { 

75 "high_pass": ["cosine+"], 

76 "motion": ["trans_[xyz]$", "rot_[xyz]$"], 

77 "wm_csf": ["csf$", "white_matter$"], 

78 "global": ["global_signal$"], 

79 "global_signal": ["global_signal$"], 

80 "compcor": ["[tawc]_comp_cor_+"], 

81} 

82 

83 

84def _get_headers(denoise_strategy): 

85 """Retrieve the relevant header pattern for each strategy to check.""" 

86 default_params = preset_strategies[denoise_strategy].copy() 

87 

88 list_check = [] 

89 noise_components = default_params.pop("strategy") 

90 for strategy in noise_components: 

91 if strategy in patterns: 

92 list_check += patterns[strategy] 

93 

94 for key, value in default_params.items(): 

95 if key in ["motion", "wm_csf", "global_signal"] and value != "basic": 

96 for item in patterns[key]: 

97 list_check.append(item.replace("$", "_+")) 

98 return list_check 

99 

100 

101@pytest.mark.parametrize( 

102 "fmriprep_version, volumes_left, len_sample_mask", 

103 [("1.4.x", 22, 29), ("21.x.x", 0, 5)], 

104) 

105@pytest.mark.filterwarnings("ignore::RuntimeWarning") 

106def test_strategy_scrubbing( 

107 tmp_path, fmriprep_version, volumes_left, len_sample_mask 

108): 

109 """Check user specified input for scrubbing strategy.""" 

110 file_nii, _ = create_tmp_filepath( 

111 tmp_path, 

112 image_type="regular", 

113 copy_confounds=True, 

114 copy_json=True, 

115 fmriprep_version=fmriprep_version, 

116 ) 

117 confounds, sample_mask = load_confounds_strategy( 

118 file_nii, denoise_strategy="scrubbing", fd_threshold=0.15 

119 ) 

120 # For "1.4.x" 

121 # out of 30 vols, should have 6 motion outliers from scrubbing, 

122 # and 2 vol removed by scrubbing strategy "full" 

123 assert len(sample_mask) == volumes_left 

124 

125 # shape of confound regressors untouched 

126 assert confounds.shape[0] == 30 

127 

128 # also load confounds with very liberal scrubbing thresholds 

129 # this should not produce an error 

130 confounds, sample_mask = load_confounds_strategy( 

131 file_nii, 

132 denoise_strategy="scrubbing", 

133 fd_threshold=1, 

134 std_dvars_threshold=5, 

135 ) 

136 # only non-steady volumes removed 

137 assert len(sample_mask) == len_sample_mask 

138 

139 # maker sure global signal works 

140 confounds, sample_mask = load_confounds_strategy( 

141 file_nii, denoise_strategy="scrubbing", global_signal="full" 

142 ) 

143 for check in [ 

144 "global_signal", 

145 "global_signal_derivative1", 

146 "global_signal_power2", 

147 "global_signal_derivative1_power2", 

148 ]: 

149 assert check in confounds.columns 

150 

151 

152@pytest.mark.parametrize("fmriprep_version", ["1.4.x", "21.x.x"]) 

153def test_strategy_compcor(tmp_path, fmriprep_version): 

154 """Check user specified input for compcor strategy.""" 

155 file_nii, _ = create_tmp_filepath( 

156 tmp_path, 

157 image_type="regular", 

158 copy_confounds=True, 

159 copy_json=True, 

160 fmriprep_version=fmriprep_version, 

161 ) 

162 confounds, _ = load_confounds_strategy( 

163 file_nii, denoise_strategy="compcor" 

164 ) 

165 compcor_col_str_anat = "".join(confounds.columns) 

166 assert "t_comp_cor_" not in compcor_col_str_anat 

167 # this one comes from the white matter mask 

168 expected = ( 

169 "a_comp_cor_57" if fmriprep_version == "1.4.x" else "w_comp_cor_00" 

170 ) 

171 assert expected not in compcor_col_str_anat 

172 assert "global_signal" not in compcor_col_str_anat 

173 

174 # test the global signal option 

175 confounds, _ = load_confounds_strategy( 

176 file_nii, denoise_strategy="compcor", global_signal="basic" 

177 ) 

178 compcor_col_str_anat = "".join(confounds.columns) 

179 assert "global_signal" in compcor_col_str_anat 

180 

181 

182@pytest.mark.parametrize("fmriprep_version", ["1.4.x", "21.x.x"]) 

183def test_irrelevant_input(tmp_path, fmriprep_version): 

184 """Check invalid input raising correct warning or error message.""" 

185 file_nii, _ = create_tmp_filepath( 

186 tmp_path, 

187 image_type="regular", 

188 copy_confounds=True, 

189 copy_json=True, 

190 fmriprep_version=fmriprep_version, 

191 ) 

192 warning_message = ( 

193 r"parameters accepted: \['motion', 'wm_csf', " 

194 "'global_signal', 'demean']" 

195 ) 

196 with pytest.warns(UserWarning, match=warning_message): 

197 load_confounds_strategy( 

198 file_nii, denoise_strategy="simple", ica_aroma="full" 

199 ) 

200 # invalid strategy 

201 with pytest.raises(KeyError, match="blah"): 

202 load_confounds_strategy(file_nii, denoise_strategy="blah") 

203 

204 

205def test_empty_strategy(tmp_path): 

206 """Ensure to return None for confounds and raise a warning 

207 when strategy is empty. 

208 """ 

209 file_nii, _ = create_tmp_filepath( 

210 tmp_path, 

211 image_type="regular", 

212 copy_confounds=True, 

213 copy_json=True, 

214 ) 

215 

216 warning_message = "strategy is empty, confounds will return None." 

217 with pytest.warns(UserWarning, match=warning_message): 

218 confounds, sample_mask = load_confounds(file_nii, strategy=[]) 

219 

220 assert confounds is None