@@ -279,6 +279,7 @@ def init_bold_wf(
279279 spaces = config .workflow .spaces
280280 nonstd_spaces = set (spaces .get_nonstandard ())
281281 freesurfer_spaces = spaces .get_fs_spaces ()
282+ surf_std = [x for x in spaces .get_standard (dim = (2 ,)) if x .space != 'fsaverage' ]
282283
283284 #
284285 # Resampling outputs workflow:
@@ -503,6 +504,39 @@ def init_bold_wf(
503504 (merge_bold_sources , ds_bold_std_wf , [('out' , 'inputnode.source_files' )]),
504505 ]) # fmt:skip
505506
507+ # Goodvoxels mask might be needed in any surface resampling
508+ if config .workflow .project_goodvoxels and (config .workflow .cifti_output or surf_std ):
509+ from .resampling import init_goodvoxels_bold_mask_wf
510+
511+ goodvoxels_bold_mask_wf = init_goodvoxels_bold_mask_wf (mem_gb ['resampled' ])
512+ ds_goodvoxels_mask = pe .Node (
513+ DerivativesDataSink (
514+ base_directory = fmriprep_dir ,
515+ dismiss_entities = dismiss_echo (),
516+ compress = True ,
517+ space = 'T1w' ,
518+ desc = 'goodvoxels' ,
519+ suffix = 'mask' ,
520+ ),
521+ name = 'ds_goodvoxels_mask' ,
522+ run_without_submitting = True ,
523+ )
524+ ds_goodvoxels_mask .inputs .source_file = bold_file
525+
526+ workflow .__postdesc__ += """\
527+ A "goodvoxels" mask was applied during volume-to-surface sampling, excluding
528+ voxels whose time-series have a locally high coefficient of variation.
529+ """
530+ workflow .connect ([
531+ (inputnode , goodvoxels_bold_mask_wf , [('anat_ribbon' , 'inputnode.anat_ribbon' )]),
532+ (bold_anat_wf , goodvoxels_bold_mask_wf , [
533+ ('outputnode.bold_file' , 'inputnode.bold_file' ),
534+ ]),
535+ (goodvoxels_bold_mask_wf , ds_goodvoxels_mask , [
536+ ('outputnode.goodvoxels_mask' , 'in_file' ),
537+ ]),
538+ ]) # fmt:skip
539+
506540 if config .workflow .run_reconall and freesurfer_spaces :
507541 workflow .__postdesc__ += """\
508542 Non-gridded (surface) resamplings were performed using `mri_vol2surf`
@@ -550,7 +584,6 @@ def init_bold_wf(
550584 from .resampling import (
551585 init_bold_fsLR_resampling_wf ,
552586 init_bold_grayords_wf ,
553- init_goodvoxels_bold_mask_wf ,
554587 )
555588
556589 bold_MNI6_wf = init_bold_volumetric_resample_wf (
@@ -569,42 +602,12 @@ def init_bold_wf(
569602 )
570603
571604 if config .workflow .project_goodvoxels :
572- goodvoxels_bold_mask_wf = init_goodvoxels_bold_mask_wf (mem_gb ['resampled' ])
573-
574- workflow .connect ([
575- (inputnode , goodvoxels_bold_mask_wf , [('anat_ribbon' , 'inputnode.anat_ribbon' )]),
576- (bold_anat_wf , goodvoxels_bold_mask_wf , [
577- ('outputnode.bold_file' , 'inputnode.bold_file' ),
578- ]),
579- ]) # fmt:skip
580-
581- ds_goodvoxels_mask = pe .Node (
582- DerivativesDataSink (
583- base_directory = fmriprep_dir ,
584- dismiss_entities = dismiss_echo (),
585- compress = True ,
586- space = 'T1w' ,
587- desc = 'goodvoxels' ,
588- suffix = 'mask' ,
589- ),
590- name = 'ds_goodvoxels_mask' ,
591- run_without_submitting = True ,
592- )
593- ds_goodvoxels_mask .inputs .source_file = bold_file
594605 workflow .connect ([
595- (goodvoxels_bold_mask_wf , ds_goodvoxels_mask , [
596- ('outputnode.goodvoxels_mask' , 'in_file' ),
597- ]),
598606 (goodvoxels_bold_mask_wf , bold_fsLR_resampling_wf , [
599607 ('outputnode.goodvoxels_mask' , 'inputnode.volume_roi' ),
600608 ]),
601609 ]) # fmt:skip
602610
603- bold_fsLR_resampling_wf .__desc__ += """\
604- A "goodvoxels" mask was applied during volume-to-surface sampling in fsLR space,
605- excluding voxels whose time-series have a locally high coefficient of variation.
606- """
607-
608611 bold_grayords_wf = init_bold_grayords_wf (
609612 grayord_density = config .workflow .cifti_output ,
610613 mem_gb = 1 ,
@@ -670,6 +673,105 @@ def init_bold_wf(
670673 ]),
671674 ]) # fmt:skip
672675
676+ if surf_std :
677+ from smriprep .workflows .surfaces import init_resample_surfaces_wf
678+
679+ from .resampling import (
680+ init_wb_surf_surf_wf ,
681+ init_wb_vol_surf_wf ,
682+ )
683+
684+ workflow .__postdesc__ += (
685+ 'Non-gridded (surface) resamplings were performed using the Connectome Workbench.'
686+ )
687+ config .loggers .workflow .debug ('Creating BOLD surface workbench resampling workflow.' )
688+
689+ wb_vol_surf_wf = init_wb_vol_surf_wf (
690+ omp_nthreads = omp_nthreads ,
691+ mem_gb = mem_gb ['resampled' ],
692+ dilate = True ,
693+ )
694+ workflow .connect ([
695+ (inputnode , wb_vol_surf_wf ,[
696+ ('white' , 'inputnode.white' ),
697+ ('pial' , 'inputnode.pial' ),
698+ ('midthickness' , 'inputnode.midthickness' ),
699+ ]),
700+ (bold_anat_wf , wb_vol_surf_wf , [
701+ ('outputnode.bold_file' , 'inputnode.bold_file' ),
702+ ]),
703+ ]) # fmt:skip
704+
705+ if config .workflow .project_goodvoxels :
706+ workflow .connect ([
707+ (goodvoxels_bold_mask_wf , wb_vol_surf_wf , [
708+ ('outputnode.goodvoxels_mask' , 'inputnode.volume_roi' ),
709+ ]),
710+ ]) # fmt:skip
711+
712+ for ref_ in surf_std :
713+ template = ref_ .space
714+ density = ref_ .spec .get ('density' ) or ref_ .spec .get ('den' ) or None
715+ if density is None :
716+ config .loggers .warning (f'Cannot resample { ref_ } without density specified.' )
717+ continue
718+
719+ resample_surfaces_wf = init_resample_surfaces_wf (
720+ name = f'resample_surfaces_wf_{ template } _{ density } ' ,
721+ surfaces = ['midthickness' ],
722+ template = template ,
723+ density = density ,
724+ )
725+
726+ wb_surf_surf_wf = init_wb_surf_surf_wf (
727+ template = template ,
728+ density = density ,
729+ omp_nthreads = omp_nthreads ,
730+ mem_gb = mem_gb ['resampled' ],
731+ )
732+
733+ ds_bold_surf_wb = pe .Node (
734+ DerivativesDataSink (
735+ base_directory = fmriprep_dir ,
736+ hemi = ['L' , 'R' ],
737+ dismiss_entities = dismiss_echo (),
738+ space = template ,
739+ density = density ,
740+ suffix = 'bold' ,
741+ TaskName = all_metadata [0 ].get ('TaskName' ),
742+ extension = '.func.gii' ,
743+ ** prepare_timing_parameters (all_metadata [0 ]),
744+ ),
745+ iterfield = ('in_file' , 'hemi' ),
746+ name = f'ds_bold_surf_wb_{ template } _{ density } ' ,
747+ run_without_submitting = True ,
748+ )
749+ ds_bold_surf_wb .inputs .source_file = bold_file
750+
751+ workflow .connect ([
752+ (inputnode , resample_surfaces_wf , [
753+ ('midthickness' , 'inputnode.midthickness' ),
754+ ('sphere_reg_fsLR' , 'inputnode.sphere_reg_fsLR' ),
755+ ]),
756+ (wb_vol_surf_wf , wb_surf_surf_wf , [
757+ ('outputnode.bold_fsnative' , 'inputnode.bold_fsnative' ),
758+ ]),
759+ (inputnode , wb_surf_surf_wf , [
760+ ('midthickness' , 'inputnode.midthickness' ),
761+ ('sphere_reg_fsLR' , 'inputnode.sphere_reg_fsLR' ),
762+ ]),
763+ (resample_surfaces_wf , wb_surf_surf_wf , [
764+ (
765+ f'outputnode.midthickness_{ template } ' ,
766+ 'inputnode.midthickness_resampled'
767+ ),
768+ ]),
769+ (wb_surf_surf_wf , ds_bold_surf_wb , [
770+ ('outputnode.bold_resampled' , 'in_file' ),
771+ # TODO: json metadata?
772+ ]),
773+ ]) # fmt:skip
774+
673775 bold_confounds_wf = init_bold_confs_wf (
674776 mem_gb = mem_gb ['largemem' ],
675777 metadata = all_metadata [0 ],
0 commit comments