@@ -135,7 +135,7 @@ def _run_interface(self, runtime):
135
135
out_ents = self .inputs .contrast_info [0 ]['entities' ]
136
136
fname_fmt = os .path .join (runtime .cwd , '{}_{}.nii.gz' ).format
137
137
for name , weights , contrast_type in prepare_contrasts (
138
- self .inputs .contrast_info , mat .columns . tolist () ):
138
+ self .inputs .contrast_info , mat .columns ):
139
139
contrast_metadata .append (
140
140
{'contrast' : name ,
141
141
'stat' : contrast_type ,
@@ -178,12 +178,12 @@ def _match(query, metadata):
178
178
class SecondLevelModel (NistatsBaseInterface , SecondLevelEstimatorInterface , SimpleInterface ):
179
179
def _run_interface (self , runtime ):
180
180
from nistats import second_level_model as level2
181
+ from nistats .contrasts import compute_fixed_effects
182
+
181
183
smoothing_fwhm = self .inputs .smoothing_fwhm
182
184
if not isdefined (smoothing_fwhm ):
183
185
smoothing_fwhm = None
184
186
185
- model = level2 .SecondLevelModel (smoothing_fwhm = smoothing_fwhm )
186
-
187
187
effect_maps = []
188
188
variance_maps = []
189
189
stat_maps = []
@@ -196,46 +196,76 @@ def _run_interface(self, runtime):
196
196
# Only keep files which match all entities for contrast
197
197
stat_metadata = _flatten (self .inputs .stat_metadata )
198
198
input_effects = _flatten (self .inputs .effect_maps )
199
+ input_variances = _flatten (self .inputs .variance_maps )
199
200
200
201
filtered_effects = []
202
+ filtered_variances = []
201
203
names = []
202
- for m , eff in zip (stat_metadata , input_effects ):
204
+ for m , eff , var in zip (stat_metadata , input_effects , input_variances ):
203
205
if _match (out_ents , m ):
204
206
filtered_effects .append (eff )
207
+ filtered_variances .append (var )
205
208
names .append (m ['contrast' ])
206
209
207
- # Dummy code contrast of input effects
208
- design_matrix = pd . get_dummies ( names )
210
+ mat = pd . get_dummies ( names )
211
+ contrasts = prepare_contrasts ( self . inputs . contrast_info , mat . columns )
209
212
210
- # Fit single model for all inputs
211
- model .fit (filtered_effects , design_matrix = design_matrix )
213
+ # Only fit model if any non-FEMA contrasts at this level
214
+ if any (c [2 ] != 'FEMA' for c in contrasts ):
215
+ if len (filtered_effects ) < 2 :
216
+ raise RuntimeError (
217
+ "At least two inputs are required for a 't' for 'F' "
218
+ "second level contrast" )
219
+ model = level2 .SecondLevelModel (smoothing_fwhm = smoothing_fwhm )
220
+ model .fit (filtered_effects , design_matrix = mat )
212
221
213
- for name , weights , contrast_type in prepare_contrasts (
214
- self .inputs .contrast_info , design_matrix .columns .to_list ()):
222
+ for name , weights , contrast_type in contrasts :
215
223
contrast_metadata .append (
216
224
{'contrast' : name ,
217
225
'stat' : contrast_type ,
218
226
** out_ents })
219
227
220
- maps = model .compute_contrast (
221
- second_level_contrast = weights ,
222
- second_level_stat_type = contrast_type ,
223
- output_type = 'all' )
228
+ # Pass-through happens automatically as it can handle 1 input
229
+ if contrast_type == 'FEMA' :
230
+ # Filter effects and variances based on weights
231
+ ix = weights [0 ].astype (bool )
232
+
233
+ ffx_res = compute_fixed_effects (
234
+ np .array (filtered_effects )[ix ],
235
+ np .array (filtered_variances )[ix ]
236
+ )
237
+
238
+ maps = {
239
+ 'effect_size' : ffx_res [0 ],
240
+ 'effect_variance' : ffx_res [1 ],
241
+ 'stat' : ffx_res [2 ]
242
+ }
243
+ else :
244
+ maps = model .compute_contrast (
245
+ second_level_contrast = weights ,
246
+ second_level_stat_type = contrast_type ,
247
+ output_type = 'all'
248
+ )
224
249
225
250
for map_type , map_list in (('effect_size' , effect_maps ),
226
251
('effect_variance' , variance_maps ),
227
252
('z_score' , zscore_maps ),
228
253
('p_value' , pvalue_maps ),
229
254
('stat' , stat_maps )):
230
- fname = fname_fmt (name , map_type )
231
- maps [map_type ].to_filename (fname )
232
- map_list .append (fname )
255
+ if map_type in maps :
256
+ fname = fname_fmt (name , map_type )
257
+ maps [map_type ].to_filename (fname )
258
+ map_list .append (fname )
233
259
234
260
self ._results ['effect_maps' ] = effect_maps
235
261
self ._results ['variance_maps' ] = variance_maps
236
262
self ._results ['stat_maps' ] = stat_maps
237
- self ._results ['zscore_maps' ] = zscore_maps
238
- self ._results ['pvalue_maps' ] = pvalue_maps
239
263
self ._results ['contrast_metadata' ] = contrast_metadata
240
264
265
+ # These are "optional" as fixed effects do not support these
266
+ if zscore_maps :
267
+ self ._results ['zscore_maps' ] = zscore_maps
268
+ if pvalue_maps :
269
+ self ._results ['pvalue_maps' ] = pvalue_maps
270
+
241
271
return runtime
0 commit comments