Neurovascular effects of tadalafil in patients with cerebral small vessel disease: ETLAS-2 substudy.
The 6 matches
- [1] § Materials and methods › MRI analysis › Dual-echo pCASL MRI ↔ dual_echo_pcasl_ETLAS2_scripts.py, lines 625–714 · score 0.79 · design matrix, hypercapnia response, visual stimulation, convolved, Gamma, cosine
- [2] § Materials and methods › MRI ↔ dp_pcasl_tools.py, lines 213–232 · score 0.68 · diffusion weighted, arterial transit, DP pCASL, attenuated, exchange
- [3] § Materials and methods › MRI analysis › BOLD fMRI ↔ dual_echo_pcasl_ETLAS2_scripts.py, lines 508–623 · score 0.67 · fMRI, design matrix, motion corrected, FWHM, HRF, smoothed
- [4] § Materials and methods › MRI analysis › Dual-echo pCASL MRI ↔ dual_echo_pcasl_ETLAS2_scripts.py, lines 438–475 · score 0.64 · partition coefficient, efficiency, relaxation, slice, delay, post
- [5] § Materials and methods › Dual-echo pCASL MRI ↔ dual_echo_pcasl_ETLAS2_scripts.py, lines 508–623 · score 0.60 · dual echo pCASL, Visual stimulation, CO2, repetition, matrix, duration
- [6] § Materials and methods › Statistical analysis ↔ dp_pcasl_tools.py, lines 30–74 · score 0.55 · GLM fitting, DP pCASL, Tools, pipelining
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 714 lines · 35 KB · CC-BY-4.0 · 4 matches
- """Dual-echo pCASL processing scripts for ETLAS2 dataset.
- This module contains core processing pipelines used in the ETLAS2 paper:
- Neurovascular effects of tadalafil in patients with
- cerebral small vessel disease: ETLAS-2 substudy
- - motion correction and template registration for dual-echo pCASL (echo 1 + echo 2)
- - CBF scaling image generation
- - first-level GLM fitting for calibrated fMRI with hypercapnia/visual stimuli
- The functions expect BIDS-like subject/session folder structure for input data.
- """
- import ants
- import pandas as pd
- import antspynet
- import numpy as np
- import json
- import os
- import nilearn.glm as glm
- import nibabel as nib
- from scipy.stats import gamma
- import shutil
- def motion_correction_to_template(subject, rawdata_folder, dual_echo_pcasl_folder, transformations_folder, template_fn):
- """Run rigid registration of pCASL/M0 to T1w and MNI template.
- This function performs motion correction on dual-echo pCASL data using control
- volumes, registers the corrected series to anatomical T1w and template space,
- and applies the full transform chain to both echo 1 and echo 2 volumes.
- Scaling images for CBF quantification are also computed and warped to template.
- Optionally processes follow-up session data with longitudinal T1 alignment.
- Parameters:
- - subject: subject label (e.g. sub-001)
- - rawdata_folder: base input folder with BIDS-like structure
- - dual_echo_pcasl_folder: output folder for processed pCASL images
- - transformations_folder: output folder for transform matrices
- - template_fn: full path to target template image (e.g. MNI)
- """
- # ------------------------------------------------------------------
- # Load input images from baseline session (T1w, pCASL echo1/echo2, M0 scans)
- # - T1 is anatomical reference
- # - pcasl_e1/e2 are perfusion series requiring motion correction
- # - m0_e1/e2 are baseline M0 acquisitions; averaged across time for scaling
- # ------------------------------------------------------------------
- t1 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'anat', f'{subject}_ses-baseline_T1w.nii.gz'))
- pcasl_e1 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-1_asl.nii.gz'))
- pcasl_e2 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-2_asl.nii.gz'))
- # M0 average across all M0 timepoints for each echo.
- m0_e1 = ants.get_average_of_timeseries(ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-1_m0scan.nii.gz')))
- m0_e2 = ants.get_average_of_timeseries(ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-2_m0scan.nii.gz')))
- template = ants.image_read(template_fn)
- # ------------------------------------------------------------------
- # Perform motion correction using control volumes only (avoid label-control contrast drift).
- # 1) select even frames (control) from echo1
- # 2) rigid motion correct to a midpoint reference
- # 3) get motion parameters (FD) for later QC/o output
- # ------------------------------------------------------------------
- pcasl_e1_con = ants.list_to_ndimage(pcasl_e1, ants.ndimage_to_list(pcasl_e1)[0::2])
- pcasl_e1_con_registration_init = ants.motion_correction(pcasl_e1_con, aff_metric='meansquares')
- pcasl_e1_con_registration = ants.motion_correction(
- pcasl_e1_con,
- fixed=ants.get_average_of_timeseries(pcasl_e1_con_registration_init['motion_corrected']),
- aff_metric='meansquares'
- )
- # Reference for subsequent registration is average motion-corrected control series.
- reference = ants.get_average_of_timeseries(pcasl_e1_con_registration['motion_corrected'])
- # Brain extraction for bias correction. This mask is used to avoid background influence.
- reference_mask = antspynet.utilities.brain_extraction(reference, modality='bold')
- ref_tmp = ants.image_clone(reference)
- ref_tmp[reference_mask < 0.1] = np.nan
- # N4 bias correction to reduce intensity non-uniformity before registration.
- reference_n4 = ants.n4_bias_field_correction(reference / np.nanmean(ref_tmp.numpy(), axis=(0,1)), mask=reference_mask > 0.1)
- # Register to anatomical T1 and M0 to reference
- pcasl_to_t1 = ants.registration(
- t1,
- reference_n4,
- type_of_transform='Rigid',
- aff_metric='mattes',
- initial_transform='Identity',
- aff_iterations=(200),
- aff_shrink_factors=(1),
- aff_smoothing_sigmas=(0)
- )
- pcasl_xfms = pcasl_e1_con_registration['motion_parameters']
- m0_to_pcasl = ants.registration(
- reference_n4,
- m0_e1,
- type_of_transform='Rigid',
- aff_metric='mattes',
- initial_transform='Identity',
- aff_iterations=(200),
- aff_shrink_factors=(1),
- aff_smoothing_sigmas=(0)
- )
- # Prepare a reference 4D image in template field-of-view for resampling.
- # We copy orientation from template while maintaining ASL time dimension shape.
- direction = pcasl_e1.direction.copy()
- direction[0:3,0:3] = template.direction
- reference_image = ants.from_numpy(
- np.zeros(template.shape + (pcasl_e1.shape[-1],)),
- origin=template.origin + (pcasl_e1.origin[-1],),
- spacing=template.spacing + (pcasl_e1.spacing[-1],),
- direction=direction
- )
- # The T1w-to-MNI transform is external (SAMSEG / preprocessing output).
- t1_to_template_xfm_fn = os.path.join(transformations_folder, subject, f'{subject}_ses-baseline_T1w-to-MNI.mat')
- # Apply chain of transforms to each pCASL timepoint:
- # 1) subject T1 -> template (inverse because we are moving data to template)
- # 2) pCASL->T1 from registration
- # 3) volume-level motion transform per volume (from motion correction)
- # This is done for both echos.
- pcasl_e1_mc = ants.list_to_ndimage(reference_image, [
- ants.apply_transforms(template,
- ants.ndimage_to_list(pcasl_e1)[i],
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], pcasl_xfms[int(i/2)][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear')
- for i in range(len(ants.ndimage_to_list(pcasl_e1)))
- ])
- pcasl_e2_mc = ants.list_to_ndimage(reference_image, [
- ants.apply_transforms(template,
- ants.ndimage_to_list(pcasl_e2)[i],
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], pcasl_xfms[int(i/2)][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear')
- for i in range(len(ants.ndimage_to_list(pcasl_e2)))])
- # Calculate ASL scaling from M0 (mgr to perfusion units).
- # This is needed later to convert posted ASL signal to quantitative CBF.
- scaling_e1 = calculate_cbf_scaling(m0_e1, os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-1_asl.json'))
- scaling_e2 = calculate_cbf_scaling(m0_e2, os.path.join(rawdata_folder, subject, 'ses-baseline', 'perf', f'{subject}_ses-baseline_echo-1_asl.json'))
- # Warp M0 volumes into template space for consistent quantification.
- m0_e1_mc = ants.apply_transforms(
- template,
- m0_e1,
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear'
- )
- m0_e2_mc = ants.apply_transforms(
- template,
- m0_e2,
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear'
- )
- # Upsample/dilate mask areas to reduce edge artifacts in scaling division.
- # This is an ExploreASL-inspired heuristic with erode+dilate combination.
- m0_mask = antspynet.utilities.brain_extraction(m0_e2, modality='bold')
- m0_mask_eroded = ants.morphology(m0_mask, 'erode', 1, mtype='grayscale')
- m0_mask_dilated = ants.morphology(m0_mask, 'dilate', 1, mtype='grayscale')
- scaling_e1_dilated = (
- scaling_e1 * ants.smooth_image(m0_mask_eroded, 1)
- + ants.morphology(scaling_e1 * (m0_mask > 0.999), 'dilate', 1, mtype='grayscale')
- * ants.smooth_image(m0_mask_dilated - m0_mask_eroded, 1)
- )
- scaling_e2_dilated = (
- scaling_e2 * ants.smooth_image(m0_mask_eroded, 1)
- + ants.morphology(scaling_e2 * (m0_mask > 0.999), 'dilate', 1, mtype='grayscale')
- * ants.smooth_image(m0_mask_dilated - m0_mask_eroded, 1)
- )
- # Reproject dilated scaling images to template space.
- scaling_e1_mc = ants.apply_transforms(
- template,
- scaling_e1_dilated,
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear'
- )
- scaling_e2_mc = ants.apply_transforms(
- template,
- scaling_e2_dilated,
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False],
- interpolator='linear'
- )
- # Warp a brain mask to template space and binarize after interp.
- m0_mask_mc = (
- ants.apply_transforms(
- template,
- m0_mask,
- [t1_to_template_xfm_fn, pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False],
- interpolator='genericLabel'
- ) > 0.999
- )
- # Save transform files for later QC and reuse.
- # - asl-to-T1 uses pcasl_to_t1 full forward transform
- # - m0-to-asl uses m0_to_pcasl transform
- # - per-volume motion transforms are stored in asl_mc/
- os.makedirs(os.path.join(transformations_folder, subject), exist_ok=True)
- os.makedirs(os.path.join(transformations_folder, subject, 'asl_mc'), exist_ok=True)
- shutil.copyfile(pcasl_to_t1['fwdtransforms'][0], os.path.join(transformations_folder, subject, f'{subject}_ses-baseline_asl-to-T1w.mat'))
- shutil.copyfile(m0_to_pcasl['fwdtransforms'][0], os.path.join(transformations_folder, subject, f'{subject}_ses-baseline_m0scan-to-asl.mat'))
- for i, xfm in enumerate(pcasl_xfms):
- shutil.copyfile(xfm[0], os.path.join(transformations_folder, subject, 'asl_mc', f'{subject}_ses-baseline_asl-moco_{i:03}.mat'))
- # Ensure output directory exists and store final processed images.
- out_basename = os.path.join(dual_echo_pcasl_folder, subject, 'ses-baseline', f'{subject}_ses-baseline')
- os.makedirs(os.path.join(dual_echo_pcasl_folder, subject, 'ses-baseline'), exist_ok=True)
- scaling_e1.to_filename(out_basename + '_echo-1_scaling.nii.gz')
- scaling_e1_dilated.to_filename(out_basename + '_echo-1_scaling_dilated.nii.gz')
- scaling_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_scaling.nii.gz')
- scaling_e2.to_filename(out_basename + '_echo-2_scaling.nii.gz')
- scaling_e2_dilated.to_filename(out_basename + '_echo-2_scaling_dilated.nii.gz')
- scaling_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_scaling.nii.gz')
- # Save output volumes from baseline run
- pcasl_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_asl.nii.gz')
- pcasl_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_asl.nii.gz')
- m0_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_m0scan.nii.gz')
- m0_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_m0scan.nii.gz')
- m0_mask_mc.to_filename(out_basename + '_rec-moco_brainmask.nii.gz')
- # Save framewise displacement (repeated for label/control alternation) for QC.
- motion = np.zeros(len(pcasl_e1_con_registration['FD']) * 2)
- motion[0::2] = pcasl_e1_con_registration['FD']
- motion[1::2] = pcasl_e1_con_registration['FD']
- np.savetxt(out_basename + '_rec-moco_framewisedisplacement.txt', motion)
- # Optional follow-up session processing. If present, process follow-up data similarly to baseline.
- # Follow-up pipeline replicates motion correction + template registration chain,
- # then adds follow-up->baseline T1 alignment for longitudinal consistency.
- dual_session = os.path.exists(os.path.join(rawdata_folder, subject, 'ses-followup', 'perf'))
- if dual_session:
- # Load baseline and follow-up anatomical volumes.
- t1_baseline = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-baseline', 'anat', f'{subject}_ses-baseline_T1w.nii.gz'))
- t1 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-followup', 'anat', f'{subject}_ses-followup_T1w.nii.gz'))
- # Load follow-up pCASL echo series and M0 scans.
- pcasl_e1 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-1_asl.nii.gz'))
- pcasl_e2 = ants.image_read(os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-2_asl.nii.gz'))
- m0_e1 = ants.get_average_of_timeseries(ants.image_read(os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-1_m0scan.nii.gz')))
- m0_e2 = ants.get_average_of_timeseries(ants.image_read(os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-2_m0scan.nii.gz')))
- # Motion correction on follow-up echo1 control frames.
- pcasl_e1_con = ants.list_to_ndimage(pcasl_e1, ants.ndimage_to_list(pcasl_e1)[0::2])
- pcasl_e1_con_registration_init = ants.motion_correction(pcasl_e1_con, aff_metric='meansquares')
- pcasl_e1_con_registration = ants.motion_correction(
- pcasl_e1_con,
- fixed=ants.get_average_of_timeseries(pcasl_e1_con_registration_init['motion_corrected']),
- aff_metric='meansquares'
- )
- # Build follow-up reference image and bias correction mask.
- reference = ants.get_average_of_timeseries(pcasl_e1_con_registration['motion_corrected'])
- reference_mask = antspynet.utilities.brain_extraction(reference, modality='bold')
- ref_tmp = ants.image_clone(reference)
- ref_tmp[reference_mask < 0.1] = np.nan
- reference_n4 = ants.n4_bias_field_correction(reference / np.nanmean(ref_tmp.numpy(), axis=(0,1)), mask=reference_mask > 0.1)
- # Register follow-up reference to follow-up T1 and M0 to reference.
- pcasl_to_t1 = ants.registration(
- t1,
- reference_n4,
- type_of_transform='Rigid',
- aff_metric='mattes',
- initial_transform='Identity',
- aff_iterations=(200),
- aff_shrink_factors=(1),
- aff_smoothing_sigmas=(0)
- )
- pcasl_xfms = pcasl_e1_con_registration['motion_parameters']
- m0_to_pcasl = ants.registration(
- reference_n4,
- m0_e1,
- type_of_transform='Rigid',
- aff_metric='mattes',
- initial_transform='Identity',
- aff_iterations=(200),
- aff_shrink_factors=(1),
- aff_smoothing_sigmas=(0)
- )
- # Register follow-up T1 to baseline T1, enabling longitudinal transform chain.
- t1_followup_to_baseline = ants.registration(
- t1_baseline,
- t1,
- type_of_transform='Rigid',
- aff_metric='mattes',
- initial_transform='Identity',
- aff_iterations=(200),
- aff_shrink_factors=(1),
- aff_smoothing_sigmas=(0)
- )
- # Prepare workspace for follow-up pCASL resampling in template space.
- direction = pcasl_e1.direction.copy()
- direction[0:3,0:3] = template.direction
- reference_image = ants.from_numpy(
- np.zeros(template.shape + (pcasl_e1.shape[-1],)),
- origin=template.origin + (pcasl_e1.origin[-1],),
- spacing=template.spacing + (pcasl_e1.spacing[-1],),
- direction=direction
- )
- # Apply full transform chain to follow-up echo1 and echo2 volumes:
- # template <- (T1_baseline<-T1_followup <-- pcasl_t1 <-- pcasl_vol_moco).
- pcasl_e1_mc = ants.list_to_ndimage(reference_image, [
- ants.apply_transforms(
- template,
- ants.ndimage_to_list(pcasl_e1)[i],
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], pcasl_xfms[int(i/2)][0]],
- whichtoinvert=[True, False, False, False],
- interpolator='linear'
- )
- for i in range(len(ants.ndimage_to_list(pcasl_e1)))
- ])
- pcasl_e2_mc = ants.list_to_ndimage(reference_image, [
- ants.apply_transforms(
- template,
- ants.ndimage_to_list(pcasl_e2)[i],
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], pcasl_xfms[int(i/2)][0]],
- whichtoinvert=[True, False, False, False],
- interpolator='linear'
- )
- for i in range(len(ants.ndimage_to_list(pcasl_e2)))
- ])
- # Recompute scaling for follow-up M0 images and warp to template.
- scaling_e1 = calculate_cbf_scaling(m0_e1, os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-1_asl.json'))
- scaling_e2 = calculate_cbf_scaling(m0_e2, os.path.join(rawdata_folder, subject, 'ses-followup', 'perf', f'{subject}_ses-followup_echo-1_asl.json'))
- m0_e1_mc = ants.apply_transforms(
- template,
- m0_e1,
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- interpolator='linear',
- whichtoinvert=[True, False, False, False]
- )
- m0_e2_mc = ants.apply_transforms(
- template,
- m0_e2,
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- interpolator='linear',
- whichtoinvert=[True, False, False, False]
- )
- # Dilate follow-up scale masks and intensity maps in the same manner as baseline.
- m0_mask = antspynet.utilities.brain_extraction(m0_e2, modality='bold')
- m0_mask_eroded = ants.morphology(m0_mask, 'erode', 1, mtype='grayscale')
- m0_mask_dilated = ants.morphology(m0_mask, 'dilate', 1, mtype='grayscale')
- scaling_e1_dilated = (
- scaling_e1 * ants.smooth_image(m0_mask_eroded, 1)
- + ants.morphology(scaling_e1 * (m0_mask > 0.999), 'dilate', 1, mtype='grayscale')
- * ants.smooth_image(m0_mask_dilated - m0_mask_eroded, 1)
- )
- scaling_e2_dilated = (
- scaling_e2 * ants.smooth_image(m0_mask_eroded, 1)
- + ants.morphology(scaling_e2 * (m0_mask > 0.999), 'dilate', 1, mtype='grayscale')
- * ants.smooth_image(m0_mask_dilated - m0_mask_eroded, 1)
- )
- scaling_e1_mc = ants.apply_transforms(
- template,
- scaling_e1_dilated,
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False, False],
- interpolator='linear'
- )
- scaling_e2_mc = ants.apply_transforms(
- template,
- scaling_e2_dilated,
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- whichtoinvert=[True, False, False, False],
- interpolator='linear'
- )
- m0_mask_mc = (
- ants.apply_transforms(
- template,
- m0_mask,
- [t1_to_template_xfm_fn, t1_followup_to_baseline['fwdtransforms'][0], pcasl_to_t1['fwdtransforms'][0], m0_to_pcasl['fwdtransforms'][0]],
- interpolator='genericLabel',
- whichtoinvert=[True, False, False, False]
- ) > 0.999
- )
- # Save follow-up transforms and output files (same patterns as baseline)
- os.makedirs(os.path.join(transformations_folder, subject), exist_ok=True)
- os.makedirs(os.path.join(transformations_folder, subject, 'asl_mc'), exist_ok=True)
- shutil.copyfile(t1_followup_to_baseline['fwdtransforms'][0], os.path.join(transformations_folder, subject, f'{subject}_followup-T1w-to-baseline-T1w.mat'))
- shutil.copyfile(pcasl_to_t1['fwdtransforms'][0], os.path.join(transformations_folder, subject, f'{subject}_ses-followup_asl-to-T1w.mat'))
- shutil.copyfile(m0_to_pcasl['fwdtransforms'][0], os.path.join(transformations_folder, subject, f'{subject}_ses-followup_m0scan-to-asl.mat'))
- for i, xfm in enumerate(pcasl_xfms):
- shutil.copyfile(xfm[0], os.path.join(transformations_folder, subject, 'asl_mc', f'{subject}_ses-followup_asl-moco_{i:03}.mat'))
- out_basename = os.path.join(dual_echo_pcasl_folder, subject, 'ses-followup', f'{subject}_ses-followup')
- os.makedirs(os.path.join(dual_echo_pcasl_folder, subject, 'ses-followup'), exist_ok=True)
- scaling_e1.to_filename(out_basename + '_echo-1_scaling.nii.gz')
- scaling_e1_dilated.to_filename(out_basename + '_echo-1_scaling_dilated.nii.gz')
- scaling_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_scaling.nii.gz')
- scaling_e2.to_filename(out_basename + '_echo-2_scaling.nii.gz')
- scaling_e2_dilated.to_filename(out_basename + '_echo-2_scaling_dilated.nii.gz')
- scaling_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_scaling.nii.gz')
- pcasl_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_asl.nii.gz')
- pcasl_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_asl.nii.gz')
- m0_e1_mc.to_filename(out_basename + '_rec-moco_echo-1_m0scan.nii.gz')
- m0_e2_mc.to_filename(out_basename + '_rec-moco_echo-2_m0scan.nii.gz')
- m0_mask_mc.to_filename(out_basename + '_rec-moco_brainmask.nii.gz')
- motion = np.zeros(len(pcasl_e1_con_registration['FD']) * 2)
- motion[0::2] = pcasl_e1_con_registration['FD']
- motion[1::2] = pcasl_e1_con_registration['FD']
- np.savetxt(out_basename + '_rec-moco_framewisedisplacement.txt', motion)
- def calculate_cbf_scaling(m0, sidecar_fn, blood_t1=1.65, lambda_full=0.9):
- """Compute voxel-wise pCASL scaling from M0 image and BIDS sidecar metadata.
- This function uses the general kinetic model from Alsop et al., MRM 2000
- (DOI: 10.1002/mrm.10559), applying a single-bolus correction and
- optional slice-timing support.
- Parameters:
- - m0: M0 image (anatomical reference)
- - sidecar_fn: path to BIDS JSON sidecar with pCASL acquisition parameters
- - blood_t1: T1 relaxation time of blood (seconds)
- - lambda_full: brain-blood partition coefficient
- Returns:
- - scaling: voxel-wise scaling image in units ml/100g/min (same geometry as m0 input)
- """
- sidecar = json.load(open(sidecar_fn))
- # Extract pCASL parameters from sidecar metadata.
- inversion_eff = sidecar.get('LabelingEfficiency', 0.95)
- bolus_duration = sidecar.get('LabelingDuration', 1.65)
- postlabeling_delay = sidecar.get('PostLabelingDelay', 2.0)
- slice_time = sidecar.get('SliceTiming', np.zeros(m0.shape[2]))
- # Convert slice timing to seconds if needed and add post-labeling delay.
- slice_time = np.array(slice_time, dtype=float)
- if slice_time.max() > 4:
- slice_time *= 0.001
- slice_time += postlabeling_delay
- # Apply kinetic model (Eq. 1 in Alsop et al., MRM 2000) to compute scaling.
- # Output is in ml/100g/min.
- scaling = m0 * 2.0 * inversion_eff * blood_t1 * (1.0 / lambda_full) * (
- np.exp(-slice_time / blood_t1) - np.exp(-(bolus_duration + slice_time) / blood_t1)
- ) / 6000.0
- return scaling
- def hypercapnia_response_function(tr, oversampling=16, onset=0.0, time_length=240):
- """Generate a canonical hypercapnia response function using a gamma distribution.
- Parameters:
- - tr: repetition time (seconds)
- - oversampling: factor for temporal upsampling of the response function
- - onset: delay before response begins (seconds)
- - time_length: total duration of response function (seconds)
- Returns:
- - response_function: normalized gamma PDF used as HRF for hypercapnia regressors
- """
- # Calculate temporal resolution after oversampling
- dt = tr / oversampling
- # Create time vector with oversampled resolution, then shift by onset delay
- time_stamps = np.linspace(0, time_length, np.rint(time_length / dt).astype(int))
- time_stamps -= onset
- # Gamma function parameters estimated from hypercapnia data
- # delay: shape parameter (governs rise time)
- # dispersion: scale parameter (governs width/duration of response)
- delay = 1.55
- dispersion = 33
- # Compute gamma probability density function and normalize to sum to 1
- response_function = gamma.pdf(time_stamps, delay, scale=dispersion, loc=0)
- response_function /= response_function.sum()
- return response_function
- def fit_calibrated_fmri_glm(subject, session, rawdata_folder, dual_echo_pcasl_folder):
- """Fit calibrated fMRI GLM for one subject/session using echo 1/2 outputs.
- This function uses pre-processed, motion-corrected pCASL images and session
- event timings to estimate task- and hypercapnia-related responses.
- """
- # ------------------------------------------------------------------
- # File I/O and initial metadata loading
- # ------------------------------------------------------------------
- output_folder = os.path.join(dual_echo_pcasl_folder, subject, session, 'glm_results')
- os.makedirs(output_folder, exist_ok=True)
- sidecar = json.load(open(os.path.join(rawdata_folder, subject, session, 'perf', f'{subject}_{session}_echo-1_asl.json')))
- pcasl_e1 = nib.load(os.path.join(dual_echo_pcasl_folder, subject, session, f'{subject}_{session}_rec-moco_echo-1_asl.nii.gz'))
- pcasl_e2 = nib.load(os.path.join(dual_echo_pcasl_folder, subject, session, f'{subject}_{session}_rec-moco_echo-2_asl.nii.gz'))
- events = pd.read_table(os.path.join(rawdata_folder, subject, session, 'perf', f'{subject}_{session}_echo-1_events.tsv'))
- context = pd.read_csv(os.path.join(rawdata_folder, subject, session, 'perf', f'{subject}_{session}_echo-1_aslcontext.tsv'), sep='\t')
- motion = np.loadtxt(os.path.join(dual_echo_pcasl_folder, subject, session, f'{subject}_{session}_rec-moco_framewisedisplacement.txt'))
- # ------------------------------------------------------------------
- # Ensure t_r is in seconds and construct frame times for design matrix.
- # ------------------------------------------------------------------
- t_r = sidecar['RepetitionTime']
- if t_r > 1000:
- t_r /= 1000.0
- n_frames = sidecar['TotalAcquiredPairs'] * 2
- frame_times = np.arange(n_frames) * t_r
- # ------------------------------------------------------------------
- # Construct first-level GLM design matrix for main task and hypercapnia.
- # ------------------------------------------------------------------
- X1 = glm.first_level.make_first_level_design_matrix(
- frame_times,
- events=events[events['trial_type'] != 'Hypercapnia, 5% CO2'],
- drift_model='cosine',
- high_pass=0.001,
- add_regs=pd.DataFrame(motion, columns=['FD']),
- hrf_model='glover'
- )
- # In pCASL, label/control toggles; encode as +1 / -1 for ASL difference.
- X1['ASL'] = np.array((context == 'label') * -1)
- # Hypercapnia event regressor, using a custom response function.
- onset = events[events['trial_type'] == 'Hypercapnia, 5% CO2']['onset'].values
- duration = events[events['trial_type'] == 'Hypercapnia, 5% CO2']['duration'].values
- amplitude = np.ones_like(onset)
- exp_condition = np.vstack((onset, duration, amplitude))
- # Custom hypercapnia response function estimated from the patient group data.
- HC_reg = glm.first_level.compute_regressor(
- exp_condition,
- hypercapnia_response_function,
- frame_times
- )
- X1['Hypercapnia'] = HC_reg[0]
- # pCASL contrast terms for interactions with label/control pattern.
- X1['ASL Hypercapnia'] = X1['Hypercapnia'] * X1['ASL']
- X1['ASL visual stimulation'] = X1['visual stimulation'] * X1['ASL']
- X1['ASL visual stimulation, hypercapnia'] = X1['visual stimulation, hypercapnia'] * X1['ASL']
- X1.to_csv(os.path.join(output_folder, f'design_matrix.csv'))
- # Set up GLM
- pcasl_glm = glm.first_level.FirstLevelModel(
- noise_model='ar1',
- standardize=False,
- minimize_memory=False,
- signal_scaling=False,
- mask_img=False,
- n_jobs=-1,
- smoothing_fwhm=None
- )
- # Fit GLM to echo-1 data
- glm_e1_results = pcasl_glm.fit(pcasl_e1, design_matrices=X1)
- # Compute and write all contrasts, echo-1
- for contrast in glm_e1_results.design_matrices_[0].keys():
- results = glm_e1_results.compute_contrast(contrast, output_type='all')
- for k in results.keys():
- results[k].to_filename(os.path.join(output_folder, f'glm_e1_{contrast.replace(" ", "_").replace(",", "")}_{k}.nii.gz'))
- # Read nuisance regressors, echo-1
- drift1_e1 = ants.image_read(os.path.join(output_folder, "glm_e1_drift_1_effect_size.nii.gz"))
- drift2_e1 = ants.image_read(os.path.join(output_folder, "glm_e1_drift_2_effect_size.nii.gz"))
- FD_e1 = ants.image_read(os.path.join(output_folder, "glm_e1_FD_effect_size.nii.gz"))
- # Regress out nuisances, echo-1
- pcasl_e1_nn = ants.image_read(os.path.join(dual_echo_pcasl_folder, subject, session, f'{subject}_{session}_rec-moco_echo-1_asl.nii.gz'))
- for i in range(pcasl_e1.shape[-1]):
- pcasl_e1_nn[:, :, :, i] = pcasl_e1_nn[:,:,:,i] - (drift1_e1 * X1['drift_1'].array[i] + drift2_e1 * X1['drift_2'].array[i] + FD_e1 * X1['FD'].array[i]).numpy()
- pcasl_e1_nn.to_filename(os.path.join(output_folder, f'pcasl_e1_nuisance-regressed.nii.gz'))
- # Fit GLM to echo-2 data
- glm_e2_results = pcasl_glm.fit(pcasl_e2, design_matrices=X1)
- # Compute and write all contrasts, echo-2
- for contrast in glm_e2_results.design_matrices_[0].keys():
- results = glm_e2_results.compute_contrast(contrast, output_type='all')
- for k in results.keys():
- results[k].to_filename(os.path.join(output_folder, f'glm_e2_{contrast.replace(" ", "_").replace(",", "")}_{k}.nii.gz'))
- # Read nuisance regressors, echo-2
- drift1_e2 = ants.image_read(os.path.join(output_folder, "glm_e2_drift_1_effect_size.nii.gz"))
- drift2_e2 = ants.image_read(os.path.join(output_folder, "glm_e2_drift_2_effect_size.nii.gz"))
- FD_e2 = ants.image_read(os.path.join(output_folder, "glm_e2_FD_effect_size.nii.gz"))
- # Regress out nuisances, echo-2
- pcasl_e2_nn = ants.image_read(os.path.join(dual_echo_pcasl_folder, subject, session, f'{subject}_{session}_rec-moco_echo-2_asl.nii.gz'))
- for i in range(pcasl_e1.shape[-1]):
- pcasl_e2_nn[:, :, :, i] = pcasl_e2_nn[:, :, :, i] - (drift1_e2 * X1['drift_1'].array[i] + drift2_e2 * X1['drift_2'].array[i] + FD_e2 * X1['FD'].array[i]).numpy()
- pcasl_e2_nn.to_filename(os.path.join(output_folder, f'pcasl_e2_nuisance-regressed.nii.gz'))
- def get_design(framewise_displacement):
- """Construct an experimental design matrix for the dual-echo experiment.
- This design is tied to the original scan protocol (640 time points, 4.5s TR,
- specific hypercapnia and visual stimulation onsets). pCASL alternates label
- and control volumes along the time axis, so we create regressors with doubled
- time dimension (640) from underlying event definitions (320 points) and
- distributed on every second frame.
- """
- # Apply framewise displacement from motion correction to both repeated echoes.
- # Input framewise_displacement is length 320, output vector length 640: one FD
- # entry for each echo volume (even and odd indexes).
- fd = np.zeros(640)
- fd[0::2] = framewise_displacement
- fd[1::2] = framewise_displacement
- design = glm.first_level.make_first_level_design_matrix(
- np.arange(640) * 2.25, # correct TR value for data series
- drift_model='cosine',
- high_pass=0.001,
- add_regs=pd.DataFrame(fd, columns=['framewise_displacement'])
- ).drop('constant', axis=1)
- # Define event timing at the 320-sample (non-echo duplicated) level.
- time_stamps = np.arange(320) * 4.5
- # Hypercapnia stimulus blocks: 64 ON / 64 OFF / 64 ON ...
- hc_stim = np.array([0]*64 + [1]*64 + [0]*64 + [1]*64 + [0]*64)
- # Visual task blocks: 32s OFF, 8s ON, repeated 5 times.
- vis_stim = np.array(([0]*32 + [1]*8 + [0]*8 + [1]*8 + [0]*8) * 5)
- # Data-driven kernels for ASL/BOLD responses, based on earlier model estimates.
- vis_hrf_asl = [0, 0.7210, 0.2563, 0.0216, 0.0010]
- vis_hrf_bold = [0, 0.8545, 0.2876, -0.0532, -0.0643, -0.0206, -0.0035, -0.0004]
- # Use a gamma function for the hypercapnia response (same model as hypercapnia_response_function)
- hc_hrf = gamma.pdf(time_stamps, 1.55, scale=33, loc=0)
- hc_hrf /= hc_hrf.sum()
- # Convolve condition time-series with HRF and split into echo 1/echo 2 (
- # control-label alternation) rows.
- hc_resp = np.zeros(640)
- hc_resp[0::2] = np.convolve(hc_stim, hc_hrf)[0:320]
- hc_resp[1::2] = np.convolve(hc_stim, hc_hrf)[0:320]
- vis_resp_nc_asl = np.zeros(640)
- vis_resp_nc_asl[0::2] = np.convolve(vis_stim * (1 - hc_stim), vis_hrf_asl)[0:320]
- vis_resp_nc_asl[1::2] = np.convolve(vis_stim * (1 - hc_stim), vis_hrf_asl)[0:320]
- vis_resp_hc_asl = np.zeros(640)
- vis_resp_hc_asl[0::2] = np.convolve(vis_stim * hc_stim, vis_hrf_asl)[0:320]
- vis_resp_hc_asl[1::2] = np.convolve(vis_stim * hc_stim, vis_hrf_asl)[0:320]
- vis_resp_nc_bold = np.zeros(640)
- vis_resp_nc_bold[0::2] = np.convolve(vis_stim * (1 - hc_stim), vis_hrf_bold)[0:320]
- vis_resp_nc_bold[1::2] = np.convolve(vis_stim * (1 - hc_stim), vis_hrf_bold)[0:320]
- vis_resp_hc_bold = np.zeros(640)
- vis_resp_hc_bold[0::2] = np.convolve(vis_stim * hc_stim, vis_hrf_bold)[0:320]
- vis_resp_hc_bold[1::2] = np.convolve(vis_stim * hc_stim, vis_hrf_bold)[0:320]
- # Multiplicative label/control regressors for echo-specific contrast (ASL-style).
- c_e1 = [1, 0, 1, 0] * 160
- c_e2 = [0, 1, 0, 1] * 160
- l_e1 = [0, 0, -1, 0] * 160
- l_e2 = [0, 0, 0, -1] * 160
- design['01_constant_e1'] = c_e1
- design['02_constant_e2'] = c_e2
- design['03_label_e1'] = l_e1
- design['04_label_e2'] = l_e2
- design['05_hypercapnia_constant_e1'] = hc_resp * c_e1
- design['06_hypercapnia_constant_e2'] = hc_resp * c_e2
- design['07_hypercapnia_label_e1'] = hc_resp * l_e1
- design['08_hypercapnia_label_e2'] = hc_resp * l_e2
- design['09_visualresponse_constant_e1'] = vis_resp_nc_bold * c_e1
- design['10_visualresponse_constant_e2'] = vis_resp_nc_bold * c_e2
- design['11_visualresponse_label_e1'] = vis_resp_nc_asl * l_e1
- design['12_visualresponse_label_e2'] = vis_resp_nc_asl * l_e2
- design['13_visualresponse_hypercapnia_constant_e1'] = vis_resp_hc_bold * c_e1
- design['14_visualresponse_hypercapnia_constant_e2'] = vis_resp_hc_bold * c_e2
- design['15_visualresponse_hypercapnia_label_e1'] = vis_resp_hc_asl * l_e1
- design['16_visualresponse_hypercapnia_label_e2'] = vis_resp_hc_asl * l_e2
- return design
dual_echo_pcasl_ETLAS2_scripts.py, under CC-BY-4.0 · at the source
Overview
- Neurovascular Research Unit, Department of Neurology, Copenhagen University Hospital—Herlev and Gentofte, Herlev 2730, Denmark
- Danish Research Centre for Magnetic Resonance, Department of Radiology and Nuclear Medicine, Copenhagen University Hospital—Amager and Hvidovre, Hvidovre 2650, Denmark
- Department of Clinical Medicine, University of Copenhagen, Copenhagen 2200, Denmark
- Child and Adolescent Mental Health Center, Copenhagen University Hospital, Mental Health Services CPH, Hellerup 2900, Denmark
- Department of Psychology, University of Copenhagen, Copenhagen 1353, Denmark
- Department of Radiology, Copenhagen University Hospital—Herlev and Gentofte, Herlev 2730, Denmark
- Department of Neurology, Copenhagen University Hospital—Bispebjerg and Frederiksberg, Copenhagen 2400, Denmark
- Department of Neurology, Copenhagen University Hospital—Rigshospitalet, Glostrup 2600, Denmark
- Department of Neurology, Copenhagen University Hospital—North Zealand, Hillerød 3400, Denmark
- Department of Brain and Spinal Cord Injury, Neuroscience Centre, Copenhagen University Hospital—Rigshospitalet, Glostrup 2600, Denmark
Abstract
Cerebral small vessel disease is a major contributor to stroke and cognitive impairment, often associated with reduced cerebral blood flow and cerebrovascular reactivity. In this study, we used MRI to investigate if daily treatment with the phosphodiesterase-5 inhibitor tadalafil over 3 months improved cerebral blood flow and cerebrovascular reactivity in patients with cerebral small vessel disease.
Using a randomized, placebo-controlled, parallel-group design, this MRI sub-study was prospectively performed as part of the Effect of Tadalafil in Lacunar Stroke 2 trial, which included a total of 76 participants, of whom 60 were included in the per-protocol analysis. Patients with cerebral small vessel disease and prior stroke or transient ischaemic attack received either tadalafil (20 mg/
In total, 60 participants (median age: 66.5, 14 females) were included in this per-protocol sub-study analysis (28 on tadalafil and 32 on placebo). Forty-two pseudo-continuous arterial spin labelling datasets (20 on tadalafil and 22 on placebo), 53 blood-oxygen-level-depen
Three months of tadalafil treatment significantly enhanced whole-brain cerebral blood flow in patients with cerebral small vessel disease without altering cerebrovascular reactivity, neurovascular coupling, arterial transit time, and event-related blood-oxygen-level-depen
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 6 matches between paragraphs and lines of code.
Zenodo 19233779
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
6 files
- cli_dual_echo_pcasl_prep
rocess.py , Python, 15 lines - cli_fit_calibrated_fmri_
glm.py , Python, 14 lines - dp_pcasl_tools.py, Python, 410 lines, 2 matches
- dual_echo_pcasl_ETLAS2_s
cripts.py , Python, 714 lines, 4 matches - summary_of_data.m, MATLAB, 146 lines
- README.md, Text, 57 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 5 scripts, each with its path and the digest of its content;
- 6 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data availability
The data that support the findings of this study are available from the corresponding author upon reasonable request. Python and MATLAB scripts used for MRI processing and data collection are available at: https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 10 authors, 5 keywords, 4 funders, 26 references.
Cite
This paper
Ölmestig, J., Mortensen, K. N., Fagerlund, B., Naveed, N., Nordling, M. M., Christensen, H., Iversen, H. K., Poulsen, M. B., Siebner, H. R., & Kruuse, C. (2026). Neurovascular effects of tadalafil in patients with cerebral small vessel disease: ETLAS-2 substudy. Brain communications, 8(4), fcag309. https://
BibTeX
@article{olmestig2026neu
author = {Ölmestig, Joakim and Mortensen, Kristian N and Fagerlund, Birgitte and Naveed, Nadia and Nordling, Mette M and Christensen, Hanne and Iversen, Helle K and Poulsen, Mai B and Siebner, Hartwig R and Kruuse, Christina},
title = {{Neurovascular effects of tadalafil in patients with cerebral small vessel disease: ETLAS-2 substudy}},
journal = {Brain communications},
year = {2026},
month = aug,
volume = {8},
number = {4},
pages = {fcag309},
publisher = {Oxford University Press},
issn = {2632-1297},
doi = {10.1093/
url = {https://
pmid = {42643719},
pmcid = {PMC13504703}
}
RIS
TY - JOUR
AU - Ölmestig, Joakim
AU - Mortensen, Kristian N
AU - Fagerlund, Birgitte
AU - Naveed, Nadia
AU - Nordling, Mette M
AU - Christensen, Hanne
AU - Iversen, Helle K
AU - Poulsen, Mai B
AU - Siebner, Hartwig R
AU - Kruuse, Christina
TI - Neurovascular effects of tadalafil in patients with cerebral small vessel disease: ETLAS-2 substudy
T2 - Brain communications
J2 - Brain Commun
PY - 2026
DA - 2026/
VL - 8
IS - 4
SP - fcag309
SN - 2632-1297
PB - Oxford University Press
DO - 10.1093/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1093/
"type": "article-journal",
"title": "Neurovascular effects of tadalafil in patients with cerebral small vessel disease: ETLAS-2 substudy",
"container-title": "Brain communications",
"author": [
{
"family": "Ölmestig",
"given": "Joakim"
},
{
"family": "Mortensen",
"given": "Kristian N"
},
{
"family": "Fagerlund",
"given": "Birgitte"
},
{
"family": "Naveed",
"given": "Nadia"
},
{
"family": "Nordling",
"given": "Mette M"
},
{
"family": "Christensen",
"given": "Hanne"
},
{
"family": "Iversen",
"given": "Helle K"
},
{
"family": "Poulsen",
"given": "Mai B"
},
{
"family": "Siebner",
"given": "Hartwig R"
},
{
"family": "Kruuse",
"given": "Christina"
}
],
"container-title-short":
"volume": "8",
"issue": "4",
"page": "fcag309",
"DOI": "10.1093/
"PMID": "42643719",
"PMCID": "PMC13504703",
"ISSN": "2632-1297",
"publisher": "Oxford University Press",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
13
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1371/journal.pbio.3003856 [code]
- Aging and metabolism contribute separately to brain-body health.Journal: PLoS biologyIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools, structural MRI / diffusion, clinical / translational
- [2] doi:10.1038/s41467-026-73668-y [code]
- Convergent and divergent brain-cognition development in early adolescence.Journal: Nature communicationsIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools, fMRI
- [3] doi:10.1016/j.xcrm.2026.102943 [code]
- Parent-of-origin effects in Alzheimer's liability dissociate neurocognitive and cardiovascular traits in at-risk individuals.Journal: Cell reports. MedicineIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools, clinical / translational
- [4] doi:10.1038/s41586-026-10631-3 [code]
- A prognostic human brain network for diffuse midline glioma.Journal: NatureIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools, clinical / translational
- [5] doi:10.1038/s41467-026-76452-0 [code]
- Music evokes shared neural representations of imagined narratives across sensory modalities.Journal: Nature communicationsIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools
- [6] doi:10.1038/s41467-026-71568-9 [code]
- Convergent and selective representations of pain, appetitive processes, aversive processes, and cognitive control in the insula.Journal: Nature communicationsIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools
- [7] doi:10.1038/s41398-026-04025-2 [code]
- Brain energetic landscapes shape state dysregulation in major depressive disorder: a morphological network controllability perspective.Journal: Translational psychiatryIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools
- [8] doi:10.1038/s41467-026-71151-2 [code]
- Common and distinct neural correlates of social interaction processing and theory of mind in narratives.Journal: Nature communicationsIn common: ANTs, Nilearn, Image Processing Toolbox, 6 other tools
- [9] doi:10.1002/epi.70296 [code]
- Fully automated three-dimensional deep learning-based magnetic resonance imaging segmentation of brain cavities in epilepsy surgery.Journal: EpilepsiaIn common: ANTs, Nilearn, Image Processing Toolbox, 5 other tools, structural MRI / diffusion, clinical / translational
- [10] doi:10.1038/s41467-026-76812-w [code]
- Assessing molecular, cellular and transcriptomic bases of laminar perfusion and cytoarchitecture coupling in the human cortex.Journal: Nature communicationsIn common: ANTs, Nilearn, NiBabel, 5 other tools, stroke, structural MRI / diffusion
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 5 scripts, and 6 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:c2ba345b636c956a…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[.
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
