FASTANS is an accelerated, Python-based implementation of the Targeted Functional Network Stimulation (TANS) approach described in Lynch et al. [1,2]. The github repository with the original Matlab code can be found here: https://github.com/cjl2007/Targeted-Functional-Network-Stimulation
🚀 While the original implementation usually takes several hours to run [2], FASTANS allows optimization of TMS coil placements within minutes, without any particular need for high performance computing or parallelization.
[1] Lynch, C. J., Elbau, I. G., Ng, T. H., Wolk, D., Zhu, S., Ayaz, A., ... & Liston, C. (2022). Automated optimization of TMS coil placement for personalized functional network engagement. Neuron, 110(20), 3263-3277.
[2] Lynch, C. J., Elbau, I. G., Zhu, S., Ayaz, A., Bukhari, H., Power, J. D., & Liston, C. (2023). Precision mapping and transcranial magnetic stimulation of individual-specific functional brain networks in humans. STAR protocols, 4(1), 102118.
FASTANS supports three use cases/file format configurations (for illustration, see figure below). TMS coil placements can be optimized based on:
-
Continuous FC maps in T1 volume space
Example scripts:
Negative FC target: FASTANS_TMS_optimization_pipeline_EXAMPLE_continuous_FC_volume_negative_FC.py
Positive FC target: FASTANS_TMS_optimization_pipeline_EXAMPLE_continuous_FC_volume_negative_FC.py
-
Continuous FC maps in surface space (fs_LR_32k)
Example scripts:
Negative FC target: FASTANS_TMS_optimization_pipeline_EXAMPLE_continuous_FC_surface_negative_FC.py
Positive FC target: FASTANS_TMS_optimization_pipeline_EXAMPLE_continuous_FC_surface_positive_FC.py
-
Parcellated FC maps in surface space (fs_LR_32k)
Example script:
FASTANS_TMS_optimization_pipeline_EXAMPLE_parcellated_FC_surface.py
Note: The example below follows use case 3.
- Download/clone this code repository.
- In the example script(s) above (FASTANS_TMS_optimization_pipeline_EXAMPLE_XXX.py) and FASTANS.py (within the code folder), edit the FASTANS_installation_folderpath variable according to your download location of the FASTANS code repository.
- Additionally: In the example script(s) above (FASTANS_TMS_optimization_pipeline_EXAMPLE_XXX.py), edit the simnibs_installation_path variable according to the location of your SimNIBS 4.5 installation - this is needed to find the correct TMS coil (.ccd) files provided by SimNIBS (usually stored in /SimNIBSInstallationFolder/resources/coil_models/Drakaki_BrainStim_2022/).
Software dependencies:
- Connectome Workbench (https://humanconnectome.org/software/get-connectome-workbench) - needs to be available in $PATH.
- SimNIBS 4.5 (https://simnibs.github.io/simnibs/build/html/installation/simnibs_installer.html).
Recommended way of installing SimNIBS 4.5 (Linux):
- Download and install the Miniconda Python 3 distribution (https://www.anaconda.com/docs/getting-started/miniconda/install#linux-terminal-installer).
- Download the SimNIBS Linux environment file (https://github.com/simnibs/simnibs/blob/v4.5.0/environment_linux.yml).
- Run in a terminal window:
export PATH="$HOME/miniconda3/bin:$PATH" # This part can change depending on your miniconda installation conda env create -f ~/Downloads/environment_linux.yml # This part can change depending on your download location of the SimNIBS Linux environment file conda activate simnibs_env pip install https://github.com/simnibs/simnibs/releases/download/v4.5.0/simnibs-4.5.0-cp311-cp311-linux_x86_64.whl
- Wihtin the SimNIBS conda environment, install a Python IDE, e.g., Spyder:
pip install spyder
- (Optional) To setup the menu icons, file associations, the MATLAB library and add SimNIBS to the system path, run the postinstall_simnibs script:
mkdir $HOME/SimNIBS postinstall_simnibs --setup-links -d $HOME/SimNIBS
Note: These instructions are largely based on the installation instructions given on the SimNIBS website: https://simnibs.github.io/simnibs/build/html/installation/conda.html
This tutorial uses example data available from: https://drive.google.com/drive/folders/10s5uoIkANYWtr-5KzDY7NOfsEsdqldGb?usp=drive_link
The example_data folder contains all necessary input files as well as all output files generated by FASTANS using the following configurations in the FASTANS_TMS_optimization_pipeline.py script. If you want to run the pipeline and generate the output files yourself, please adjust the paths according to your download path of the example data.
#=============================================================================
# FASTANS configuration
#=============================================================================
# Name of output folder
output_foldername = 'Frontoparietal'
# Full path to output folder
output_folderpath = os.path.join('/.../FASTANS/resources/example_data/FASTANS', output_foldername)
# Path to subject-specific SimNIBS m2m folder
m2m_folderpath = '/.../FASTANS/resources/example_data/m2m_FASTANS_example'
# Functional network map (.dlabel.nii/.dscalar.nii/.dtseries.nii file; 32k_fs_LR space)
FCmap_filepath = '/.../FASTANS/resources/example_data/PFM/PFM_Lynch2024priors.dlabel.nii'
# Subject midthickness surfaces (.surf.gii files; 32k_fs_LR space)
surface_midthickness_left_filepath = '/.../FASTANS/resources/example_data/data/anat/midthickness_surface_left.32k_fs_LR.surf.gii'
surface_midthickness_right_filepath = '/.../FASTANS/resources/example_data/data/anat/midthickness_surface_right.32k_fs_LR.surf.gii'
# Sulcal depth map (.dscalar.nii file; 32k_fs_LR space)
sulcal_depth_filepath = '/.../FASTANS/resources/example_data/data/anat/sulcal_depth.32k_fs_LR.dscalar.nii'
# Type of FC map ('metric' or 'parcellation') — this pipeline expects 'parcellation'.
FCmap_type = 'parcellation'
# Parcellation label IDs: targets and avoidance
target_ids = [9] # 9 = Frontoparietal
avoidance_ids = [13,14,1,2,3,4] # 13 = Salience, 14 = Cingulo-opercular, 1-4 = Default Mode (sub)networks
# Percentiles used to define E-field "hotspots" (higher = smaller, more focal)
hotspot_percentiles = np.arange(99.0, 99.9, 0.1)
# Search space restricting stimulation to left PFC (choose variant as needed)
search_space_filepath = os.path.join(FASTANS_installation_folderpath, 'resources', 'search_spaces', 'SearchSpace_PFC_L.dscalar.nii')
# Alternative search spaces:
# search_space_filepath = '/.../SearchSpace_PFC_L_noPCG.dscalar.nii'
# search_space_filepath = '/.../SearchSpace_PFC_L_noPCG+DMPFC.dscalar.nii'
# search_space_filepath = '/.../SearchSpace_PFC_L_noPCG+DMPFC+IFG.dscalar.nii'
# TMS coil model (SimNIBS naming); choose matching to actual hardware
coil_model = 'MagVenture_Cool-B65'
Example outputs can be inspected in Connectome Workbench viewer (wb_view) by loading the FASTANS_example.scene file.
This scene will visualize the following input and output files:
- The midthickness surfaces (upper row), incl. their inflated version (lower row).
- The individual functional network parcellation (derived from the precision functional mapping (PFM) procedure described below):
- The "target regions" -- in this case, the frontoparietal network. This output is generated using the following lines of code:
FASTANS.extract_parcel(FCmap_filepath, target_ids,
os.path.join(output_folderpath,
'TargetRegions.dlabel.nii'))
- The "avoidance regions -- in this case, the cingulo-opercular/action-mode, salience, and default mode (sub-) networks. This output is generated using the following lines of code:
FASTANS.extract_parcel(FCmap_filepath, avoidance_ids,
os.path.join(output_folderpath,
'AvoidanceRegions.dlabel.nii'))
- The "target patch", i.e., the largest patch of the frontoparietal target network within the search space (i.e., the left prefrontal cortex). This output is generated using the following lines of code:
FASTANS.mask_cifti(os.path.join(output_folderpath, 'TargetRegions.dlabel.nii'),
'SearchSpace',
search_space_filepath,
'binary')
FASTANS.cifti_extract_largest_cluster(os.path.join(output_folderpath, 'TargetRegions_SearchSpace.dlabel.nii'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
- The "target patch", i.e., the largest patch of the frontoparietal target network within the search space (i.e., the left prefrontal cortex), restricted to the gyral crown. This output is generated using the following lines of code:
FASTANS.mask_cifti(os.path.join(output_folderpath, 'TargetRegions_SearchSpace.dlabel.nii'),
'SulcalCrown',
sulcal_depth_filepath,
'metric',
mask_threshold=0.5)
FASTANS.cifti_extract_largest_cluster(os.path.join(output_folderpath, 'TargetRegions_SearchSpace_SulcalCrown.dlabel.nii'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
- The final E-field simulations resulting from the optimized TMS coil placement. This output is generated using the lines of code detailed further below.
Additionally, Gmsh can be used to inspect the search grids and final E-field simulation.
- Coarse search grid of TMS coil placements (step 1; zoomed-in version below). This output is generated using the following lines of code:
target_coordinates = FASTANS.extract_target_coordinates(os.path.join(output_folderpath, 'TargetRegions_SearchSpace_TargetPatch.dlabel.nii'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
search_grid_coarse = FASTANS.generate_search_grid(m2m_folderpath,
os.path.join(output_folderpath, 'SimNIBS', 'SearchGrid', 'Step1_coarse'),
target_coordinates,
coil_scalp_distance,
35, # radius
10, # resolution
30, # angle resolution
[-90, 60])
- Fine search grid of TMS coil placements (step 2; zoomed-in version below). This output is generated using the following lines of code:
simulation_results_cortex = FASTANS.simnibs_accelerated_simulations_cortex(search_grid_coarse,
coil_filepath,
didt,
m2m_folderpath,
os.path.join(output_folderpath, 'SimNIBS', 'SearchGrid', 'Step1_coarse'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
best_coil_placements = FASTANS.extract_best_coil_placements_hotspot(simulation_results_cortex,
search_grid_coarse,
hotspot_percentiles,
FCmap_filepath,
target_ids,
avoidance_ids,
n_placements,
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
target_coordinates = best_coil_placements[0][0:3, 3]
search_grid_fine = FASTANS.generate_search_grid(m2m_folderpath,
os.path.join(output_folderpath, 'SimNIBS', 'SearchGrid', 'Step2_fine'),
target_coordinates,
coil_scalp_distance,
15, # radius
5, # resolution
10, # angle resolution
[-90, 80])
- Final E-field simulation. This output is generated using the following lines of code:
simulation_results_cortex = FASTANS.simnibs_accelerated_simulations_cortex(search_grid_fine,
coil_filepath,
didt,
m2m_folderpath,
os.path.join(output_folderpath, 'SimNIBS', 'SearchGrid', 'Step2_fine'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
best_coil_placements = FASTANS.extract_best_coil_placements_hotspot(simulation_results_cortex,
search_grid_fine,
hotspot_percentiles,
FCmap_filepath,
target_ids,
avoidance_ids,
n_placements,
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
FASTANS.run_final_simulation(output_foldername,
best_coil_placements,
m2m_folderpath,
coil_filepath,
coil_scalp_distance,
didt,
os.path.join(output_folderpath, 'SimNIBS', 'Simulations'),
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)
Optional: If you want to generate the individual functional network parcellation yourself, run the following lines of code after adjusting paths according to your download path of the example data:
# Full path to output folder
output_folderpath = '/.../FASTANS/resources/example_data/PFM'
# Preprocessed functional (resting-state) timecourses (.dtseries.nii file; 32k_fs_LR space)
functional_data_filepath = '/.../FASTANS/resources/example_data/data/func/processed_restingstate_timecourses.dtseries.nii'
# Subject midthickness surfaces (.surf.gii files; 32k_fs_LR space)
surface_midthickness_left_filepath = '/.../FASTANS/resources/example_data/data/anat/midthickness_surface_left.32k_fs_LR.surf.gii'
surface_midthickness_right_filepath = '/.../FASTANS/resources/example_data/data/anat/midthickness_surface_right.32k_fs_LR.surf.gii'
# Lynch 2024 parcellation
FASTANS.fast_pfm(functional_data_filepath,
'Lynch2024',
output_folderpath,
surface_midthickness_left_filepath,
surface_midthickness_right_filepath)