rapidtide 2.9.6__py3-none-any.whl → 3.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cloud/gmscalc-HCPYA +1 -1
- cloud/mount-and-run +2 -0
- cloud/rapidtide-HCPYA +3 -3
- rapidtide/Colortables.py +538 -38
- rapidtide/OrthoImageItem.py +1094 -51
- rapidtide/RapidtideDataset.py +1709 -114
- rapidtide/__init__.py +0 -8
- rapidtide/_version.py +4 -4
- rapidtide/calccoherence.py +242 -97
- rapidtide/calcnullsimfunc.py +240 -140
- rapidtide/calcsimfunc.py +314 -129
- rapidtide/correlate.py +1211 -389
- rapidtide/data/examples/src/testLD +56 -0
- rapidtide/data/examples/src/test_findmaxlag.py +2 -2
- rapidtide/data/examples/src/test_mlregressallt.py +32 -17
- rapidtide/data/examples/src/testalign +1 -1
- rapidtide/data/examples/src/testatlasaverage +35 -7
- rapidtide/data/examples/src/testboth +21 -0
- rapidtide/data/examples/src/testcifti +11 -0
- rapidtide/data/examples/src/testdelayvar +13 -0
- rapidtide/data/examples/src/testdlfilt +25 -0
- rapidtide/data/examples/src/testfft +35 -0
- rapidtide/data/examples/src/testfileorfloat +37 -0
- rapidtide/data/examples/src/testfmri +92 -42
- rapidtide/data/examples/src/testfuncs +3 -3
- rapidtide/data/examples/src/testglmfilt +8 -6
- rapidtide/data/examples/src/testhappy +84 -51
- rapidtide/data/examples/src/testinitdelay +19 -0
- rapidtide/data/examples/src/testmodels +33 -0
- rapidtide/data/examples/src/testnewrefine +26 -0
- rapidtide/data/examples/src/testnoiseamp +2 -2
- rapidtide/data/examples/src/testppgproc +17 -0
- rapidtide/data/examples/src/testrefineonly +22 -0
- rapidtide/data/examples/src/testretro +26 -13
- rapidtide/data/examples/src/testretrolagtcs +16 -0
- rapidtide/data/examples/src/testrolloff +11 -0
- rapidtide/data/examples/src/testsimdata +45 -28
- rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/model_meta.json +80 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.png +0 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.txt +1 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/model.pth +0 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/model_meta.json +138 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.png +0 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/model.pth +0 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/model_meta.json +128 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.png +0 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model.pth +0 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model_meta.json +49 -0
- rapidtide/data/models/model_revised_tf2/model.keras +0 -0
- rapidtide/data/models/{model_serdar → model_revised_tf2}/model_meta.json +1 -1
- rapidtide/data/models/model_serdar2_tf2/model.keras +0 -0
- rapidtide/data/models/{model_serdar2 → model_serdar2_tf2}/model_meta.json +1 -1
- rapidtide/data/models/model_serdar_tf2/model.keras +0 -0
- rapidtide/data/models/{model_revised → model_serdar_tf2}/model_meta.json +1 -1
- rapidtide/data/reference/HCP1200v2_MTT_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_binmask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_csf_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_gray_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_graylaghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_graylaghist.tsv.gz +0 -0
- rapidtide/data/reference/HCP1200v2_laghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_laghist.tsv.gz +0 -0
- rapidtide/data/reference/HCP1200v2_mask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxcorr_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxtime_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxwidth_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_negmask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_timepercentile_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_white_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_whitelaghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_whitelaghist.tsv.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2.xml +131 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_regions.txt +60 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_space-MNI152NLin6Asym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_1mm_Brain_FAST_seg.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_1mm_Brain_Mask.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_2mm_Brain_FAST_seg.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_2mm_Brain_Mask.nii.gz +0 -0
- rapidtide/decorators.py +91 -0
- rapidtide/dlfilter.py +2553 -414
- rapidtide/dlfiltertorch.py +5201 -0
- rapidtide/externaltools.py +328 -13
- rapidtide/fMRIData_class.py +108 -92
- rapidtide/ffttools.py +168 -0
- rapidtide/filter.py +2704 -1462
- rapidtide/fit.py +2361 -579
- rapidtide/genericmultiproc.py +197 -0
- rapidtide/happy_supportfuncs.py +3255 -548
- rapidtide/helper_classes.py +587 -1116
- rapidtide/io.py +2569 -468
- rapidtide/linfitfiltpass.py +784 -0
- rapidtide/makelaggedtcs.py +267 -97
- rapidtide/maskutil.py +555 -25
- rapidtide/miscmath.py +835 -144
- rapidtide/multiproc.py +217 -44
- rapidtide/patchmatch.py +752 -0
- rapidtide/peakeval.py +32 -32
- rapidtide/ppgproc.py +2205 -0
- rapidtide/qualitycheck.py +353 -40
- rapidtide/refinedelay.py +854 -0
- rapidtide/refineregressor.py +939 -0
- rapidtide/resample.py +725 -204
- rapidtide/scripts/__init__.py +1 -0
- rapidtide/scripts/{adjustoffset → adjustoffset.py} +7 -2
- rapidtide/scripts/{aligntcs → aligntcs.py} +7 -2
- rapidtide/scripts/{applydlfilter → applydlfilter.py} +7 -2
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/scripts/{atlasaverage → atlasaverage.py} +7 -2
- rapidtide/scripts/{atlastool → atlastool.py} +7 -2
- rapidtide/scripts/{calcicc → calcicc.py} +7 -2
- rapidtide/scripts/{calctexticc → calctexticc.py} +7 -2
- rapidtide/scripts/{calcttest → calcttest.py} +7 -2
- rapidtide/scripts/{ccorrica → ccorrica.py} +7 -2
- rapidtide/scripts/delayvar.py +28 -0
- rapidtide/scripts/{diffrois → diffrois.py} +7 -2
- rapidtide/scripts/{endtidalproc → endtidalproc.py} +7 -2
- rapidtide/scripts/{fdica → fdica.py} +7 -2
- rapidtide/scripts/{filtnifti → filtnifti.py} +7 -2
- rapidtide/scripts/{filttc → filttc.py} +7 -2
- rapidtide/scripts/{fingerprint → fingerprint.py} +20 -16
- rapidtide/scripts/{fixtr → fixtr.py} +7 -2
- rapidtide/scripts/{gmscalc → gmscalc.py} +7 -2
- rapidtide/scripts/{happy → happy.py} +7 -2
- rapidtide/scripts/{happy2std → happy2std.py} +7 -2
- rapidtide/scripts/{happywarp → happywarp.py} +8 -4
- rapidtide/scripts/{histnifti → histnifti.py} +7 -2
- rapidtide/scripts/{histtc → histtc.py} +7 -2
- rapidtide/scripts/{glmfilt → linfitfilt.py} +7 -4
- rapidtide/scripts/{localflow → localflow.py} +7 -2
- rapidtide/scripts/{mergequality → mergequality.py} +7 -2
- rapidtide/scripts/{pairproc → pairproc.py} +7 -2
- rapidtide/scripts/{pairwisemergenifti → pairwisemergenifti.py} +7 -2
- rapidtide/scripts/{physiofreq → physiofreq.py} +7 -2
- rapidtide/scripts/{pixelcomp → pixelcomp.py} +7 -2
- rapidtide/scripts/{plethquality → plethquality.py} +7 -2
- rapidtide/scripts/{polyfitim → polyfitim.py} +7 -2
- rapidtide/scripts/{proj2flow → proj2flow.py} +7 -2
- rapidtide/scripts/{rankimage → rankimage.py} +7 -2
- rapidtide/scripts/{rapidtide → rapidtide.py} +7 -2
- rapidtide/scripts/{rapidtide2std → rapidtide2std.py} +7 -2
- rapidtide/scripts/{resamplenifti → resamplenifti.py} +7 -2
- rapidtide/scripts/{resampletc → resampletc.py} +7 -2
- rapidtide/scripts/retrolagtcs.py +28 -0
- rapidtide/scripts/retroregress.py +28 -0
- rapidtide/scripts/{roisummarize → roisummarize.py} +7 -2
- rapidtide/scripts/{runqualitycheck → runqualitycheck.py} +7 -2
- rapidtide/scripts/{showarbcorr → showarbcorr.py} +7 -2
- rapidtide/scripts/{showhist → showhist.py} +7 -2
- rapidtide/scripts/{showstxcorr → showstxcorr.py} +7 -2
- rapidtide/scripts/{showtc → showtc.py} +7 -2
- rapidtide/scripts/{showxcorr_legacy → showxcorr_legacy.py} +8 -8
- rapidtide/scripts/{showxcorrx → showxcorrx.py} +7 -2
- rapidtide/scripts/{showxy → showxy.py} +7 -2
- rapidtide/scripts/{simdata → simdata.py} +7 -2
- rapidtide/scripts/{spatialdecomp → spatialdecomp.py} +7 -2
- rapidtide/scripts/{spatialfit → spatialfit.py} +7 -2
- rapidtide/scripts/{spatialmi → spatialmi.py} +7 -2
- rapidtide/scripts/{spectrogram → spectrogram.py} +7 -2
- rapidtide/scripts/stupidramtricks.py +238 -0
- rapidtide/scripts/{synthASL → synthASL.py} +7 -2
- rapidtide/scripts/{tcfrom2col → tcfrom2col.py} +7 -2
- rapidtide/scripts/{tcfrom3col → tcfrom3col.py} +7 -2
- rapidtide/scripts/{temporaldecomp → temporaldecomp.py} +7 -2
- rapidtide/scripts/{testhrv → testhrv.py} +1 -1
- rapidtide/scripts/{threeD → threeD.py} +7 -2
- rapidtide/scripts/{tidepool → tidepool.py} +7 -2
- rapidtide/scripts/{variabilityizer → variabilityizer.py} +7 -2
- rapidtide/simFuncClasses.py +2113 -0
- rapidtide/simfuncfit.py +312 -108
- rapidtide/stats.py +579 -247
- rapidtide/tests/.coveragerc +27 -6
- rapidtide-2.9.6.data/scripts/fdica → rapidtide/tests/cleanposttest +4 -6
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/resethappytargets +1 -1
- rapidtide/tests/resetrapidtidetargets +1 -1
- rapidtide/tests/resettargets +1 -1
- rapidtide/tests/runlocaltest +3 -3
- rapidtide/tests/showkernels +1 -1
- rapidtide/tests/test_aliasedcorrelate.py +4 -4
- rapidtide/tests/test_aligntcs.py +1 -1
- rapidtide/tests/test_calcicc.py +1 -1
- rapidtide/tests/test_cleanregressor.py +184 -0
- rapidtide/tests/test_congrid.py +70 -81
- rapidtide/tests/test_correlate.py +1 -1
- rapidtide/tests/test_corrpass.py +4 -4
- rapidtide/tests/test_delayestimation.py +54 -59
- rapidtide/tests/test_dlfiltertorch.py +437 -0
- rapidtide/tests/test_doresample.py +2 -2
- rapidtide/tests/test_externaltools.py +69 -0
- rapidtide/tests/test_fastresampler.py +9 -5
- rapidtide/tests/test_filter.py +96 -57
- rapidtide/tests/test_findmaxlag.py +50 -19
- rapidtide/tests/test_fullrunhappy_v1.py +15 -10
- rapidtide/tests/test_fullrunhappy_v2.py +19 -13
- rapidtide/tests/test_fullrunhappy_v3.py +28 -13
- rapidtide/tests/test_fullrunhappy_v4.py +30 -11
- rapidtide/tests/test_fullrunhappy_v5.py +62 -0
- rapidtide/tests/test_fullrunrapidtide_v1.py +61 -7
- rapidtide/tests/test_fullrunrapidtide_v2.py +26 -14
- rapidtide/tests/test_fullrunrapidtide_v3.py +28 -8
- rapidtide/tests/test_fullrunrapidtide_v4.py +16 -8
- rapidtide/tests/test_fullrunrapidtide_v5.py +15 -6
- rapidtide/tests/test_fullrunrapidtide_v6.py +142 -0
- rapidtide/tests/test_fullrunrapidtide_v7.py +114 -0
- rapidtide/tests/test_fullrunrapidtide_v8.py +66 -0
- rapidtide/tests/test_getparsers.py +158 -0
- rapidtide/tests/test_io.py +59 -18
- rapidtide/tests/{test_glmpass.py → test_linfitfiltpass.py} +10 -10
- rapidtide/tests/test_mi.py +1 -1
- rapidtide/tests/test_miscmath.py +1 -1
- rapidtide/tests/test_motionregress.py +5 -5
- rapidtide/tests/test_nullcorr.py +6 -9
- rapidtide/tests/test_padvec.py +216 -0
- rapidtide/tests/test_parserfuncs.py +101 -0
- rapidtide/tests/test_phaseanalysis.py +1 -1
- rapidtide/tests/test_rapidtideparser.py +59 -53
- rapidtide/tests/test_refinedelay.py +296 -0
- rapidtide/tests/test_runmisc.py +5 -5
- rapidtide/tests/test_sharedmem.py +60 -0
- rapidtide/tests/test_simroundtrip.py +132 -0
- rapidtide/tests/test_simulate.py +1 -1
- rapidtide/tests/test_stcorrelate.py +4 -2
- rapidtide/tests/test_timeshift.py +2 -2
- rapidtide/tests/test_valtoindex.py +1 -1
- rapidtide/tests/test_zRapidtideDataset.py +5 -3
- rapidtide/tests/utils.py +10 -9
- rapidtide/tidepoolTemplate.py +88 -70
- rapidtide/tidepoolTemplate.ui +60 -46
- rapidtide/tidepoolTemplate_alt.py +88 -53
- rapidtide/tidepoolTemplate_alt.ui +62 -52
- rapidtide/tidepoolTemplate_alt_qt6.py +921 -0
- rapidtide/tidepoolTemplate_big.py +1125 -0
- rapidtide/tidepoolTemplate_big.ui +2386 -0
- rapidtide/tidepoolTemplate_big_qt6.py +1129 -0
- rapidtide/tidepoolTemplate_qt6.py +793 -0
- rapidtide/util.py +1389 -148
- rapidtide/voxelData.py +1048 -0
- rapidtide/wiener.py +138 -25
- rapidtide/wiener2.py +114 -8
- rapidtide/workflows/adjustoffset.py +107 -5
- rapidtide/workflows/aligntcs.py +86 -3
- rapidtide/workflows/applydlfilter.py +231 -89
- rapidtide/workflows/applyppgproc.py +540 -0
- rapidtide/workflows/atlasaverage.py +309 -48
- rapidtide/workflows/atlastool.py +130 -9
- rapidtide/workflows/calcSimFuncMap.py +490 -0
- rapidtide/workflows/calctexticc.py +202 -10
- rapidtide/workflows/ccorrica.py +123 -15
- rapidtide/workflows/cleanregressor.py +415 -0
- rapidtide/workflows/delayvar.py +1268 -0
- rapidtide/workflows/diffrois.py +84 -6
- rapidtide/workflows/endtidalproc.py +149 -9
- rapidtide/workflows/fdica.py +197 -17
- rapidtide/workflows/filtnifti.py +71 -4
- rapidtide/workflows/filttc.py +76 -5
- rapidtide/workflows/fitSimFuncMap.py +578 -0
- rapidtide/workflows/fixtr.py +74 -4
- rapidtide/workflows/gmscalc.py +116 -6
- rapidtide/workflows/happy.py +1242 -480
- rapidtide/workflows/happy2std.py +145 -13
- rapidtide/workflows/happy_parser.py +277 -59
- rapidtide/workflows/histnifti.py +120 -4
- rapidtide/workflows/histtc.py +85 -4
- rapidtide/workflows/{glmfilt.py → linfitfilt.py} +128 -14
- rapidtide/workflows/localflow.py +329 -29
- rapidtide/workflows/mergequality.py +80 -4
- rapidtide/workflows/niftidecomp.py +323 -19
- rapidtide/workflows/niftistats.py +178 -8
- rapidtide/workflows/pairproc.py +99 -5
- rapidtide/workflows/pairwisemergenifti.py +86 -3
- rapidtide/workflows/parser_funcs.py +1488 -56
- rapidtide/workflows/physiofreq.py +139 -12
- rapidtide/workflows/pixelcomp.py +211 -9
- rapidtide/workflows/plethquality.py +105 -23
- rapidtide/workflows/polyfitim.py +159 -19
- rapidtide/workflows/proj2flow.py +76 -3
- rapidtide/workflows/rankimage.py +115 -8
- rapidtide/workflows/rapidtide.py +1785 -1858
- rapidtide/workflows/rapidtide2std.py +101 -3
- rapidtide/workflows/rapidtide_parser.py +590 -389
- rapidtide/workflows/refineDelayMap.py +249 -0
- rapidtide/workflows/refineRegressor.py +1215 -0
- rapidtide/workflows/regressfrommaps.py +308 -0
- rapidtide/workflows/resamplenifti.py +86 -4
- rapidtide/workflows/resampletc.py +92 -4
- rapidtide/workflows/retrolagtcs.py +442 -0
- rapidtide/workflows/retroregress.py +1501 -0
- rapidtide/workflows/roisummarize.py +176 -7
- rapidtide/workflows/runqualitycheck.py +72 -7
- rapidtide/workflows/showarbcorr.py +172 -16
- rapidtide/workflows/showhist.py +87 -3
- rapidtide/workflows/showstxcorr.py +161 -4
- rapidtide/workflows/showtc.py +172 -10
- rapidtide/workflows/showxcorrx.py +250 -62
- rapidtide/workflows/showxy.py +186 -16
- rapidtide/workflows/simdata.py +418 -112
- rapidtide/workflows/spatialfit.py +83 -8
- rapidtide/workflows/spatialmi.py +252 -29
- rapidtide/workflows/spectrogram.py +306 -33
- rapidtide/workflows/synthASL.py +157 -6
- rapidtide/workflows/tcfrom2col.py +77 -3
- rapidtide/workflows/tcfrom3col.py +75 -3
- rapidtide/workflows/tidepool.py +3829 -666
- rapidtide/workflows/utils.py +45 -19
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +118 -5
- {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/METADATA +30 -223
- rapidtide-3.1.3.dist-info/RECORD +393 -0
- {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/WHEEL +1 -1
- rapidtide-3.1.3.dist-info/entry_points.txt +65 -0
- rapidtide-3.1.3.dist-info/top_level.txt +2 -0
- rapidtide/calcandfitcorrpairs.py +0 -262
- rapidtide/data/examples/src/testoutputsize +0 -45
- rapidtide/data/models/model_revised/model.h5 +0 -0
- rapidtide/data/models/model_serdar/model.h5 +0 -0
- rapidtide/data/models/model_serdar2/model.h5 +0 -0
- rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm.nii.gz +0 -0
- rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm.nii.gz +0 -0
- rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_binmask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_lag_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_mask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_negmask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_sigma_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_strength_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/glmpass.py +0 -434
- rapidtide/refine_factored.py +0 -641
- rapidtide/scripts/retroglm +0 -23
- rapidtide/workflows/glmfrommaps.py +0 -202
- rapidtide/workflows/retroglm.py +0 -643
- rapidtide-2.9.6.data/scripts/adjustoffset +0 -23
- rapidtide-2.9.6.data/scripts/aligntcs +0 -23
- rapidtide-2.9.6.data/scripts/applydlfilter +0 -23
- rapidtide-2.9.6.data/scripts/atlasaverage +0 -23
- rapidtide-2.9.6.data/scripts/atlastool +0 -23
- rapidtide-2.9.6.data/scripts/calcicc +0 -22
- rapidtide-2.9.6.data/scripts/calctexticc +0 -23
- rapidtide-2.9.6.data/scripts/calcttest +0 -22
- rapidtide-2.9.6.data/scripts/ccorrica +0 -23
- rapidtide-2.9.6.data/scripts/diffrois +0 -23
- rapidtide-2.9.6.data/scripts/endtidalproc +0 -23
- rapidtide-2.9.6.data/scripts/filtnifti +0 -23
- rapidtide-2.9.6.data/scripts/filttc +0 -23
- rapidtide-2.9.6.data/scripts/fingerprint +0 -593
- rapidtide-2.9.6.data/scripts/fixtr +0 -23
- rapidtide-2.9.6.data/scripts/glmfilt +0 -24
- rapidtide-2.9.6.data/scripts/gmscalc +0 -22
- rapidtide-2.9.6.data/scripts/happy +0 -25
- rapidtide-2.9.6.data/scripts/happy2std +0 -23
- rapidtide-2.9.6.data/scripts/happywarp +0 -350
- rapidtide-2.9.6.data/scripts/histnifti +0 -23
- rapidtide-2.9.6.data/scripts/histtc +0 -23
- rapidtide-2.9.6.data/scripts/localflow +0 -23
- rapidtide-2.9.6.data/scripts/mergequality +0 -23
- rapidtide-2.9.6.data/scripts/pairproc +0 -23
- rapidtide-2.9.6.data/scripts/pairwisemergenifti +0 -23
- rapidtide-2.9.6.data/scripts/physiofreq +0 -23
- rapidtide-2.9.6.data/scripts/pixelcomp +0 -23
- rapidtide-2.9.6.data/scripts/plethquality +0 -23
- rapidtide-2.9.6.data/scripts/polyfitim +0 -23
- rapidtide-2.9.6.data/scripts/proj2flow +0 -23
- rapidtide-2.9.6.data/scripts/rankimage +0 -23
- rapidtide-2.9.6.data/scripts/rapidtide +0 -23
- rapidtide-2.9.6.data/scripts/rapidtide2std +0 -23
- rapidtide-2.9.6.data/scripts/resamplenifti +0 -23
- rapidtide-2.9.6.data/scripts/resampletc +0 -23
- rapidtide-2.9.6.data/scripts/retroglm +0 -23
- rapidtide-2.9.6.data/scripts/roisummarize +0 -23
- rapidtide-2.9.6.data/scripts/runqualitycheck +0 -23
- rapidtide-2.9.6.data/scripts/showarbcorr +0 -23
- rapidtide-2.9.6.data/scripts/showhist +0 -23
- rapidtide-2.9.6.data/scripts/showstxcorr +0 -23
- rapidtide-2.9.6.data/scripts/showtc +0 -23
- rapidtide-2.9.6.data/scripts/showxcorr_legacy +0 -536
- rapidtide-2.9.6.data/scripts/showxcorrx +0 -23
- rapidtide-2.9.6.data/scripts/showxy +0 -23
- rapidtide-2.9.6.data/scripts/simdata +0 -23
- rapidtide-2.9.6.data/scripts/spatialdecomp +0 -23
- rapidtide-2.9.6.data/scripts/spatialfit +0 -23
- rapidtide-2.9.6.data/scripts/spatialmi +0 -23
- rapidtide-2.9.6.data/scripts/spectrogram +0 -23
- rapidtide-2.9.6.data/scripts/synthASL +0 -23
- rapidtide-2.9.6.data/scripts/tcfrom2col +0 -23
- rapidtide-2.9.6.data/scripts/tcfrom3col +0 -23
- rapidtide-2.9.6.data/scripts/temporaldecomp +0 -23
- rapidtide-2.9.6.data/scripts/threeD +0 -236
- rapidtide-2.9.6.data/scripts/tidepool +0 -23
- rapidtide-2.9.6.data/scripts/variabilityizer +0 -23
- rapidtide-2.9.6.dist-info/RECORD +0 -359
- rapidtide-2.9.6.dist-info/top_level.txt +0 -86
- {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info/licenses}/LICENSE +0 -0
rapidtide/workflows/happy.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
#
|
|
4
|
-
# Copyright 2018-
|
|
4
|
+
# Copyright 2018-2025 Blaise Frederick
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
# you may not use this file except in compliance with the License.
|
|
@@ -16,31 +16,34 @@
|
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
#
|
|
18
18
|
#
|
|
19
|
-
import copy
|
|
20
19
|
import os
|
|
21
20
|
import platform
|
|
22
21
|
import sys
|
|
23
22
|
import time
|
|
24
23
|
import warnings
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
25
26
|
|
|
26
27
|
import numpy as np
|
|
27
|
-
from
|
|
28
|
+
from numpy.typing import NDArray
|
|
28
29
|
|
|
29
30
|
import rapidtide.correlate as tide_corr
|
|
30
31
|
import rapidtide.filter as tide_filt
|
|
31
32
|
import rapidtide.fit as tide_fit
|
|
32
|
-
import rapidtide.glmpass as tide_glmpass
|
|
33
33
|
import rapidtide.happy_supportfuncs as happy_support
|
|
34
|
-
import rapidtide.helper_classes as tide_classes
|
|
35
34
|
import rapidtide.io as tide_io
|
|
35
|
+
import rapidtide.linfitfiltpass as tide_linfitfiltpass
|
|
36
36
|
import rapidtide.maskutil as tide_mask
|
|
37
37
|
import rapidtide.miscmath as tide_math
|
|
38
38
|
import rapidtide.resample as tide_resample
|
|
39
39
|
import rapidtide.stats as tide_stats
|
|
40
40
|
import rapidtide.util as tide_util
|
|
41
|
+
import rapidtide.voxelData as tide_voxelData
|
|
41
42
|
|
|
42
43
|
from .utils import setup_logger
|
|
43
44
|
|
|
45
|
+
MIN_PULSATILITY_VOX_PCT = 7.0
|
|
46
|
+
|
|
44
47
|
warnings.simplefilter(action="ignore", category=FutureWarning)
|
|
45
48
|
|
|
46
49
|
try:
|
|
@@ -50,43 +53,134 @@ try:
|
|
|
50
53
|
except ImportError:
|
|
51
54
|
mklexists = False
|
|
52
55
|
|
|
53
|
-
try:
|
|
54
|
-
import rapidtide.dlfilter as tide_dlfilt
|
|
55
|
-
|
|
56
|
-
dlfilterexists = True
|
|
57
|
-
print("dlfilter exists")
|
|
58
|
-
except ImportError:
|
|
59
|
-
dlfilterexists = False
|
|
60
|
-
print("dlfilter does not exist")
|
|
61
|
-
|
|
62
56
|
|
|
63
|
-
def happy_main(argparsingfunc):
|
|
57
|
+
def happy_main(argparsingfunc: Any) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Process fMRI data to remove cardiac noise using temporal and/or spatial regression.
|
|
60
|
+
|
|
61
|
+
This function performs cardiac noise regression on fMRI data using either
|
|
62
|
+
temporal or spatial regression methods. It calculates cardiac noise signals
|
|
63
|
+
from the cardiac phase information and removes them from the fMRI data.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
args : argparse.Namespace
|
|
68
|
+
Command line arguments containing processing options
|
|
69
|
+
infodict : dict
|
|
70
|
+
Dictionary containing processing information including shared memory settings
|
|
71
|
+
fmri_data : NDArray
|
|
72
|
+
4D fMRI data array (x, y, z, time)
|
|
73
|
+
mask : NDArray
|
|
74
|
+
3D mask array indicating valid voxels
|
|
75
|
+
projmask_byslice : NDArray
|
|
76
|
+
2D mask array for each slice indicating valid projection locations
|
|
77
|
+
cardphasevals : NDArray
|
|
78
|
+
2D array of cardiac phase values for each slice and timepoint
|
|
79
|
+
rawapp_byslice : NDArray
|
|
80
|
+
3D array of raw cardiac signals for each slice and timepoint
|
|
81
|
+
outphases : NDArray
|
|
82
|
+
Array of cardiac phases
|
|
83
|
+
timepoints : int
|
|
84
|
+
Number of timepoints in the fMRI data
|
|
85
|
+
xsize : int
|
|
86
|
+
X dimension of the fMRI data
|
|
87
|
+
ysize : int
|
|
88
|
+
Y dimension of the fMRI data
|
|
89
|
+
numslices : int
|
|
90
|
+
Number of slices in the fMRI data
|
|
91
|
+
outputroot : str
|
|
92
|
+
Root name for output files
|
|
93
|
+
tide_util : module
|
|
94
|
+
Utility module for memory management and other operations
|
|
95
|
+
tide_io : module
|
|
96
|
+
I/O module for reading/writing data
|
|
97
|
+
tide_linfitfiltpass : module
|
|
98
|
+
Linear fitting and filtering module
|
|
99
|
+
tide_filt : module
|
|
100
|
+
Filtering module
|
|
101
|
+
platform : module
|
|
102
|
+
Platform information module
|
|
103
|
+
Path : class
|
|
104
|
+
Path class from pathlib module
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
None
|
|
109
|
+
Function performs in-place processing and saves results to files
|
|
110
|
+
|
|
111
|
+
Notes
|
|
112
|
+
-----
|
|
113
|
+
This function performs multiple steps:
|
|
114
|
+
1. Calculates cardiac noise signals from cardiac phase information
|
|
115
|
+
2. Applies temporal or spatial regression to remove cardiac noise
|
|
116
|
+
3. Saves filtered data and regression coefficients
|
|
117
|
+
4. Handles shared memory cleanup when needed
|
|
118
|
+
|
|
119
|
+
Examples
|
|
120
|
+
--------
|
|
121
|
+
>>> process_fmri_with_cardiac_regression(
|
|
122
|
+
... args, infodict, fmri_data, mask, projmask_byslice,
|
|
123
|
+
... cardphasevals, rawapp_byslice, outphases,
|
|
124
|
+
... timepoints, xsize, ysize, numslices,
|
|
125
|
+
... outputroot, tide_util, tide_io, tide_linfitfiltpass,
|
|
126
|
+
... tide_filt, platform, Path
|
|
127
|
+
... )
|
|
128
|
+
"""
|
|
64
129
|
timings = [["Start", time.time(), None, None]]
|
|
65
130
|
|
|
66
131
|
# get the command line parameters
|
|
67
132
|
args = argparsingfunc
|
|
68
133
|
infodict = vars(args)
|
|
69
134
|
|
|
135
|
+
if args.usepytorch:
|
|
136
|
+
try:
|
|
137
|
+
import rapidtide.dlfiltertorch as tide_dlfilt
|
|
138
|
+
|
|
139
|
+
dlfilterexists = True
|
|
140
|
+
print("pytorch dlfilter initialized")
|
|
141
|
+
except ImportError:
|
|
142
|
+
dlfilterexists = False
|
|
143
|
+
print("pytorch dlfilter could not be initialized")
|
|
144
|
+
else:
|
|
145
|
+
try:
|
|
146
|
+
import rapidtide.dlfilter as tide_dlfilt
|
|
147
|
+
|
|
148
|
+
dlfilterexists = True
|
|
149
|
+
print("tensorflow dlfilter initialized")
|
|
150
|
+
except ImportError:
|
|
151
|
+
dlfilterexists = False
|
|
152
|
+
print("tensorflow dlfilter could not be initialized")
|
|
153
|
+
|
|
70
154
|
fmrifilename = args.fmrifilename
|
|
71
155
|
slicetimename = args.slicetimename
|
|
72
156
|
outputroot = args.outputroot
|
|
73
157
|
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
158
|
+
# delete the old completion file, if present
|
|
159
|
+
Path(f"{outputroot}_DONE.txt").unlink(missing_ok=True)
|
|
160
|
+
|
|
161
|
+
# create the canary file
|
|
162
|
+
Path(f"{outputroot}_ISRUNNING.txt").touch()
|
|
163
|
+
|
|
164
|
+
# if running in Docker or Apptainer/Singularity, this is necessary to enforce memory limits properly
|
|
165
|
+
# otherwise likely to error out in gzip.py or at voxelnormalize step. But do nothing if running in CircleCI
|
|
166
|
+
# because it does NOT like you messing with the container.
|
|
167
|
+
args.containertype = tide_util.checkifincontainer()
|
|
168
|
+
if args.containertype is not None:
|
|
169
|
+
if args.containertype != "CircleCI":
|
|
170
|
+
args.containermemfree, args.containermemswap = tide_util.findavailablemem()
|
|
171
|
+
tide_util.setmemlimit(args.containermemfree)
|
|
172
|
+
else:
|
|
173
|
+
print("running in CircleCI environment - not messing with memory")
|
|
174
|
+
|
|
175
|
+
# load pyfftw wisdom
|
|
176
|
+
args.pyfftw_wisdom = tide_util.configurepyfftw()
|
|
83
177
|
|
|
84
178
|
# Set up loggers for workflow
|
|
85
179
|
setup_logger(
|
|
86
180
|
logger_filename=f"{outputroot}_log.txt",
|
|
87
|
-
timing_filename=f"{outputroot}
|
|
88
|
-
memory_filename=f"{outputroot}
|
|
89
|
-
|
|
181
|
+
timing_filename=f"{outputroot}_desc-runtimings.tsv",
|
|
182
|
+
memory_filename=f"{outputroot}_desc-memusage.tsv",
|
|
183
|
+
isverbose=args.verbose,
|
|
90
184
|
debug=args.debug,
|
|
91
185
|
)
|
|
92
186
|
|
|
@@ -107,6 +201,8 @@ def happy_main(argparsingfunc):
|
|
|
107
201
|
"***********************************************************************************************************************************")
|
|
108
202
|
print("")"""
|
|
109
203
|
|
|
204
|
+
infodict["pid"] = os.getpid()
|
|
205
|
+
|
|
110
206
|
infodict["fmrifilename"] = fmrifilename
|
|
111
207
|
infodict["slicetimename"] = slicetimename
|
|
112
208
|
infodict["outputroot"] = outputroot
|
|
@@ -133,9 +229,15 @@ def happy_main(argparsingfunc):
|
|
|
133
229
|
"CommandLineArgs": args.commandline,
|
|
134
230
|
}
|
|
135
231
|
|
|
232
|
+
# decide if we need to use shared memory
|
|
233
|
+
if args.nprocs > 1:
|
|
234
|
+
infodict["sharedmem"] = True
|
|
235
|
+
else:
|
|
236
|
+
infodict["sharedmem"] = False
|
|
237
|
+
|
|
136
238
|
# save the information file
|
|
137
239
|
if args.saveinfoasjson:
|
|
138
|
-
tide_io.writedicttojson(infodict, outputroot + "
|
|
240
|
+
tide_io.writedicttojson(infodict, outputroot + "_desc-runinfo.json")
|
|
139
241
|
else:
|
|
140
242
|
tide_io.writedict(infodict, outputroot + "_info.txt")
|
|
141
243
|
|
|
@@ -149,8 +251,8 @@ def happy_main(argparsingfunc):
|
|
|
149
251
|
args.mklthreads = mklmaxthreads
|
|
150
252
|
mkl.set_num_threads(args.mklthreads)
|
|
151
253
|
|
|
152
|
-
# if we are going to do
|
|
153
|
-
if (args.
|
|
254
|
+
# if we are going to do noise regression, make sure we are generating app matrix
|
|
255
|
+
if (args.dotemporalregression or args.dospatialregression) and args.cardcalconly:
|
|
154
256
|
print("doing glm fit requires phase projection - setting cardcalconly to False")
|
|
155
257
|
args.cardcalconly = False
|
|
156
258
|
|
|
@@ -171,41 +273,58 @@ def happy_main(argparsingfunc):
|
|
|
171
273
|
|
|
172
274
|
# read in the image data
|
|
173
275
|
tide_util.logmem("before reading in fmri data")
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
timepoints = input_data.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
numslices = input_data.numslices
|
|
180
|
-
|
|
181
|
-
xdim, ydim, slicethickness, tr = tide_io.parseniftisizes(thesizes)
|
|
182
|
-
spaceunit, timeunit = nim_hdr.get_xyzt_units()
|
|
183
|
-
if timeunit == "msec":
|
|
184
|
-
tr /= 1000.0
|
|
276
|
+
input_data = tide_voxelData.VoxelData(fmrifilename, validstart=args.numskip)
|
|
277
|
+
xsize, ysize, numslices, dummy = input_data.getdims()
|
|
278
|
+
timepoints = input_data.realtimepoints
|
|
279
|
+
xdim, ydim, slicethickness, tr = input_data.getsizes()
|
|
280
|
+
numspatiallocs = input_data.numspatiallocs
|
|
185
281
|
mrsamplerate = 1.0 / tr
|
|
186
282
|
print("tr is", tr, "seconds, mrsamplerate is", "{:.3f}".format(mrsamplerate))
|
|
187
|
-
numspatiallocs = int(xsize) * int(ysize) * int(numslices)
|
|
188
283
|
infodict["tr"] = tr
|
|
189
284
|
infodict["mrsamplerate"] = mrsamplerate
|
|
190
285
|
timings.append(["Image data read in", time.time(), None, None])
|
|
191
286
|
|
|
192
287
|
# remap to space by time
|
|
193
|
-
fmri_data = input_data.
|
|
194
|
-
|
|
288
|
+
fmri_data = input_data.byvoxel()
|
|
289
|
+
print("fmri_data has shape", fmri_data.shape)
|
|
195
290
|
|
|
196
291
|
# make and save a mask of the voxels to process based on image intensity
|
|
197
292
|
tide_util.logmem("before mask creation")
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
293
|
+
if args.processmask is not None:
|
|
294
|
+
mask = tide_mask.readamask(
|
|
295
|
+
args.processmask,
|
|
296
|
+
input_data.copyheader(numtimepoints=1),
|
|
297
|
+
xsize,
|
|
298
|
+
thresh=0.001,
|
|
299
|
+
maskname="process",
|
|
300
|
+
debug=args.debug,
|
|
301
|
+
)
|
|
302
|
+
mask = np.uint16(np.where(mask > 0, 1, 0).reshape(numspatiallocs))
|
|
303
|
+
else:
|
|
304
|
+
mask = np.uint16(tide_mask.makeepimask(input_data.nim).dataobj.reshape(numspatiallocs))
|
|
305
|
+
|
|
306
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
203
307
|
timings.append(["Mask created", time.time(), None, None])
|
|
204
308
|
if args.outputlevel > 0:
|
|
205
|
-
maskfilename = outputroot + "_desc-processvoxels_mask"
|
|
206
309
|
bidsdict = bidsbasedict.copy()
|
|
207
|
-
|
|
208
|
-
|
|
310
|
+
maplist = [
|
|
311
|
+
(
|
|
312
|
+
mask.reshape((xsize, ysize, numslices)),
|
|
313
|
+
"processvoxels",
|
|
314
|
+
"mask",
|
|
315
|
+
None,
|
|
316
|
+
"fMRI voxels processed by happy",
|
|
317
|
+
),
|
|
318
|
+
]
|
|
319
|
+
tide_io.savemaplist(
|
|
320
|
+
outputroot,
|
|
321
|
+
maplist,
|
|
322
|
+
None,
|
|
323
|
+
(xsize, ysize, numslices),
|
|
324
|
+
theheader,
|
|
325
|
+
bidsdict,
|
|
326
|
+
debug=args.debug,
|
|
327
|
+
)
|
|
209
328
|
timings.append(["Mask saved", time.time(), None, None])
|
|
210
329
|
mask_byslice = mask.reshape((xsize * ysize, numslices))
|
|
211
330
|
|
|
@@ -213,7 +332,7 @@ def happy_main(argparsingfunc):
|
|
|
213
332
|
if args.projmaskname is not None:
|
|
214
333
|
tide_util.logmem("before reading in projmask")
|
|
215
334
|
projmask = happy_support.readextmask(
|
|
216
|
-
args.projmaskname, nim_hdr, xsize, ysize, numslices, args.debug
|
|
335
|
+
args.projmaskname, input_data.nim_hdr, xsize, ysize, numslices, args.debug
|
|
217
336
|
)
|
|
218
337
|
# * np.float64(mask_byslice)
|
|
219
338
|
projmask_byslice = projmask.reshape(xsize * ysize, numslices)
|
|
@@ -224,22 +343,33 @@ def happy_main(argparsingfunc):
|
|
|
224
343
|
# output mask size
|
|
225
344
|
validprojvoxels = np.where(projmask.reshape(numspatiallocs) > 0)[0]
|
|
226
345
|
print(f"projmask has {len(validprojvoxels)} voxels above threshold.")
|
|
346
|
+
infodict["projmaskvoxels"] = len(validprojvoxels)
|
|
227
347
|
|
|
228
348
|
# filter out motion regressors here
|
|
229
349
|
if args.motionfilename is not None:
|
|
230
350
|
timings.append(["Motion filtering start", time.time(), None, None])
|
|
351
|
+
motiondict = tide_io.readmotion(args.motionfilename, tr=tr, colspec=args.motionfilecolspec)
|
|
352
|
+
confoundregressors, confoundregressorlabels = tide_fit.calcexpandedregressors(
|
|
353
|
+
motiondict,
|
|
354
|
+
labels=["xtrans", "ytrans", "ztrans", "xrot", "yrot", "zrot"],
|
|
355
|
+
deriv=args.motfilt_deriv,
|
|
356
|
+
order=args.motfilt_order,
|
|
357
|
+
)
|
|
358
|
+
tide_util.disablemkl(args.nprocs)
|
|
231
359
|
(motionregressors, motionregressorlabels, filtereddata, confoundr2) = (
|
|
232
|
-
|
|
233
|
-
|
|
360
|
+
tide_linfitfiltpass.confoundregress(
|
|
361
|
+
confoundregressors,
|
|
362
|
+
confoundregressorlabels,
|
|
234
363
|
fmri_data[validprojvoxels, :],
|
|
235
364
|
tr,
|
|
236
365
|
orthogonalize=args.orthogonalize,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
366
|
+
tcstart=args.motskip,
|
|
367
|
+
tchp=args.motionhp,
|
|
368
|
+
tclp=args.motionlp,
|
|
369
|
+
nprocs=args.nprocs,
|
|
241
370
|
)
|
|
242
371
|
)
|
|
372
|
+
tide_util.enablemkl(args.mklthreads)
|
|
243
373
|
if confoundr2 is None:
|
|
244
374
|
print("There are no nonzero confound regressors - exiting")
|
|
245
375
|
sys.exit()
|
|
@@ -258,23 +388,69 @@ def happy_main(argparsingfunc):
|
|
|
258
388
|
append=False,
|
|
259
389
|
debug=args.debug,
|
|
260
390
|
)
|
|
391
|
+
# save motionr2 map
|
|
392
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
393
|
+
bidsdict = bidsbasedict.copy()
|
|
394
|
+
outarray = np.zeros((xsize, ysize, numslices), dtype=float)
|
|
395
|
+
outarray.reshape(numspatiallocs)[validprojvoxels] = confoundr2
|
|
396
|
+
maplist = [
|
|
397
|
+
(
|
|
398
|
+
outarray.reshape((xsize, ysize, numslices)),
|
|
399
|
+
"motionr2",
|
|
400
|
+
"map",
|
|
401
|
+
None,
|
|
402
|
+
"R2 of motion regression",
|
|
403
|
+
),
|
|
404
|
+
]
|
|
405
|
+
tide_io.savemaplist(
|
|
406
|
+
outputroot,
|
|
407
|
+
maplist,
|
|
408
|
+
None,
|
|
409
|
+
(xsize, ysize, numslices),
|
|
410
|
+
theheader,
|
|
411
|
+
bidsdict,
|
|
412
|
+
debug=args.debug,
|
|
413
|
+
)
|
|
261
414
|
if args.savemotionglmfilt:
|
|
262
|
-
|
|
415
|
+
print("prior to save - fmri_data has shape", fmri_data.shape)
|
|
263
416
|
bidsdict = bidsbasedict.copy()
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
417
|
+
maplist = [
|
|
418
|
+
(
|
|
419
|
+
fmri_data.reshape((xsize, ysize, numslices, timepoints)),
|
|
420
|
+
"motionfiltered",
|
|
421
|
+
"bold",
|
|
422
|
+
None,
|
|
423
|
+
"fMRI data after motion regression",
|
|
424
|
+
),
|
|
425
|
+
]
|
|
426
|
+
tide_io.savemaplist(
|
|
427
|
+
outputroot,
|
|
428
|
+
maplist,
|
|
429
|
+
None,
|
|
430
|
+
(xsize, ysize, numslices, timepoints),
|
|
268
431
|
theheader,
|
|
269
|
-
|
|
432
|
+
bidsdict,
|
|
433
|
+
debug=args.debug,
|
|
270
434
|
)
|
|
435
|
+
|
|
271
436
|
timings.append(["Motion filtered data saved", time.time(), numspatiallocs, "voxels"])
|
|
272
437
|
|
|
273
438
|
# get slice times
|
|
274
|
-
slicetimes, normalizedtotr = tide_io.getslicetimesfromfile(slicetimename)
|
|
439
|
+
slicetimes, normalizedtotr, fileisbidsjson = tide_io.getslicetimesfromfile(slicetimename)
|
|
275
440
|
if normalizedtotr and not args.slicetimesareinseconds:
|
|
276
441
|
slicetimes *= tr
|
|
277
|
-
|
|
442
|
+
if args.teoffset is not None:
|
|
443
|
+
teoffset = float(args.teoffset)
|
|
444
|
+
else:
|
|
445
|
+
if fileisbidsjson:
|
|
446
|
+
jsoninfodict = tide_io.readdictfromjson(slicetimename)
|
|
447
|
+
try:
|
|
448
|
+
teoffset = jsoninfodict["EchoTime"]
|
|
449
|
+
except KeyError:
|
|
450
|
+
teoffset = 0.0
|
|
451
|
+
else:
|
|
452
|
+
teoffset = 0.0
|
|
453
|
+
infodict["teoffset"] = teoffset
|
|
278
454
|
timings.append(["Slice times determined", time.time(), None, None])
|
|
279
455
|
|
|
280
456
|
# normalize the input data
|
|
@@ -285,49 +461,77 @@ def happy_main(argparsingfunc):
|
|
|
285
461
|
validprojvoxels,
|
|
286
462
|
time,
|
|
287
463
|
timings,
|
|
464
|
+
LGR=None,
|
|
465
|
+
mpcode=args.mpdetrend,
|
|
466
|
+
nprocs=args.nprocs,
|
|
288
467
|
showprogressbar=args.showprogressbar,
|
|
468
|
+
debug=args.debug,
|
|
289
469
|
)
|
|
290
470
|
normdata_byslice = normdata.reshape((xsize * ysize, numslices, timepoints))
|
|
291
471
|
|
|
292
472
|
# save means, medians, and mads
|
|
293
|
-
theheader =
|
|
294
|
-
theheader["dim"][4] = 1
|
|
295
|
-
meansfilename = outputroot + "_desc-means_map"
|
|
296
|
-
mediansfilename = outputroot + "_desc-medians_map"
|
|
297
|
-
madsfilename = outputroot + "_desc-mads_map"
|
|
473
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
298
474
|
bidsdict = bidsbasedict.copy()
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
475
|
+
maplist = [
|
|
476
|
+
(
|
|
477
|
+
means.reshape((xsize, ysize, numslices)),
|
|
478
|
+
"means",
|
|
479
|
+
"map",
|
|
480
|
+
None,
|
|
481
|
+
"fMRI timecourse mean over time",
|
|
482
|
+
),
|
|
483
|
+
(
|
|
484
|
+
medians.reshape((xsize, ysize, numslices)),
|
|
485
|
+
"medians",
|
|
486
|
+
"map",
|
|
487
|
+
None,
|
|
488
|
+
"fMRI timecourse median over time",
|
|
489
|
+
),
|
|
490
|
+
(
|
|
491
|
+
mads.reshape((xsize, ysize, numslices)),
|
|
492
|
+
"mads",
|
|
493
|
+
"map",
|
|
494
|
+
None,
|
|
495
|
+
"fMRI timecourse MAD over time",
|
|
496
|
+
),
|
|
497
|
+
]
|
|
498
|
+
tide_io.savemaplist(
|
|
499
|
+
outputroot,
|
|
500
|
+
maplist,
|
|
501
|
+
None,
|
|
502
|
+
(xsize, ysize, numslices),
|
|
503
|
+
theheader,
|
|
504
|
+
bidsdict,
|
|
505
|
+
debug=args.debug,
|
|
506
|
+
)
|
|
305
507
|
|
|
306
508
|
# read in estimation mask if present. Otherwise, otherwise use intensity mask.
|
|
307
|
-
infodict["
|
|
509
|
+
infodict["estweightsname"] = args.estweightsname
|
|
308
510
|
if args.debug:
|
|
309
|
-
print(args.
|
|
310
|
-
if args.
|
|
311
|
-
tide_util.logmem("before reading in
|
|
312
|
-
|
|
313
|
-
args.
|
|
511
|
+
print(args.estweightsname)
|
|
512
|
+
if args.estweightsname is not None:
|
|
513
|
+
tide_util.logmem("before reading in estweights")
|
|
514
|
+
estweights = happy_support.readextmask(
|
|
515
|
+
args.estweightsname, input_data.nim_hdr, xsize, ysize, numslices, args.debug
|
|
314
516
|
)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
print("using estmask from file", args.estmaskname)
|
|
517
|
+
estweights_byslice = estweights.reshape(xsize * ysize, numslices)
|
|
518
|
+
print("using estweights from file", args.estweightsname)
|
|
318
519
|
numpasses = 1
|
|
319
520
|
else:
|
|
320
521
|
# just fall back to the intensity mask
|
|
321
|
-
|
|
522
|
+
estweights_byslice = mask_byslice.astype("float64")
|
|
322
523
|
numpasses = 2
|
|
323
524
|
print("Not using separate estimation mask - doing initial estimate using intensity mask")
|
|
324
|
-
|
|
325
|
-
|
|
525
|
+
|
|
526
|
+
# add another pass to refine the waveform after getting the new appflips
|
|
527
|
+
if args.fliparteries or args.doaliasedcorrelation:
|
|
326
528
|
numpasses += 1
|
|
327
|
-
print("Adding a pass to regenerate cardiac waveform using
|
|
529
|
+
print("Adding a pass to regenerate cardiac waveform using better vessel specification")
|
|
328
530
|
|
|
329
531
|
# output mask size
|
|
330
|
-
print(
|
|
532
|
+
print(
|
|
533
|
+
f"estweights has {len(np.where(estweights_byslice[:, :] > 0)[0])} voxels above threshold."
|
|
534
|
+
)
|
|
331
535
|
|
|
332
536
|
infodict["numpasses"] = numpasses
|
|
333
537
|
|
|
@@ -337,43 +541,57 @@ def happy_main(argparsingfunc):
|
|
|
337
541
|
if numpasses > 1:
|
|
338
542
|
print()
|
|
339
543
|
print()
|
|
340
|
-
print("starting pass
|
|
341
|
-
passstring = " - pass
|
|
544
|
+
print(f"starting pass {thispass + 1} of {numpasses}")
|
|
545
|
+
passstring = f" - pass {thispass + 1}"
|
|
546
|
+
passnamefrag = f"pass{thispass + 1}"
|
|
342
547
|
else:
|
|
343
548
|
passstring = ""
|
|
549
|
+
passnamefrag = ""
|
|
344
550
|
# now get an estimate of the cardiac signal
|
|
345
551
|
print("estimating cardiac signal from fmri data")
|
|
346
552
|
tide_util.logmem("before cardiacfromimage")
|
|
347
|
-
(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
553
|
+
tide_util.disablemkl(args.nprocs)
|
|
554
|
+
|
|
555
|
+
# Create configuration for cardiac extraction
|
|
556
|
+
cardiac_config = happy_support.CardiacExtractionConfig(
|
|
557
|
+
notchpct=args.notchpct,
|
|
558
|
+
notchrolloff=args.notchrolloff,
|
|
559
|
+
invertphysiosign=args.invertphysiosign,
|
|
560
|
+
madnorm=args.domadnorm,
|
|
561
|
+
nprocs=args.nprocs,
|
|
562
|
+
arteriesonly=args.arteriesonly,
|
|
563
|
+
fliparteries=args.fliparteries,
|
|
564
|
+
debug=args.debug,
|
|
565
|
+
verbose=args.verbose,
|
|
566
|
+
usemask=args.usemaskcardfromfmri,
|
|
567
|
+
multiplicative=True,
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
result = happy_support.cardiacfromimage(
|
|
358
571
|
normdata_byslice,
|
|
359
|
-
|
|
572
|
+
estweights_byslice,
|
|
360
573
|
numslices,
|
|
361
574
|
timepoints,
|
|
362
575
|
tr,
|
|
363
576
|
slicetimes,
|
|
364
577
|
thecardbandfilter,
|
|
365
578
|
therespbandfilter,
|
|
366
|
-
|
|
367
|
-
madnorm=args.domadnorm,
|
|
368
|
-
nprocs=args.nprocs,
|
|
369
|
-
notchpct=args.notchpct,
|
|
370
|
-
fliparteries=args.fliparteries,
|
|
371
|
-
arteriesonly=args.arteriesonly,
|
|
372
|
-
usemask=args.usemaskcardfromfmri,
|
|
579
|
+
cardiac_config,
|
|
373
580
|
appflips_byslice=appflips_byslice,
|
|
374
|
-
debug=args.debug,
|
|
375
|
-
verbose=args.verbose,
|
|
376
581
|
)
|
|
582
|
+
|
|
583
|
+
# Extract results
|
|
584
|
+
cardfromfmri_sliceres = result.hirescardtc
|
|
585
|
+
cardfromfmri_normfac = result.cardnormfac
|
|
586
|
+
respfromfmri_sliceres = result.hiresresptc
|
|
587
|
+
respfromfmri_normfac = result.respnormfac
|
|
588
|
+
slicesamplerate = result.slicesamplerate
|
|
589
|
+
numsteps = result.numsteps
|
|
590
|
+
sliceoffsets = result.sliceoffsets
|
|
591
|
+
cycleaverage = result.cycleaverage
|
|
592
|
+
slicenorms = result.slicenorms
|
|
593
|
+
|
|
594
|
+
tide_util.enablemkl(args.mklthreads)
|
|
377
595
|
timings.append(
|
|
378
596
|
[
|
|
379
597
|
"Cardiac signal generated from image data" + passstring,
|
|
@@ -383,43 +601,15 @@ def happy_main(argparsingfunc):
|
|
|
383
601
|
]
|
|
384
602
|
)
|
|
385
603
|
infodict["cardfromfmri_normfac"] = cardfromfmri_normfac
|
|
386
|
-
slicetimeaxis =
|
|
387
|
-
0.0, tr * timepoints, num=(timepoints * numsteps), endpoint=False
|
|
604
|
+
slicetimeaxis = (
|
|
605
|
+
np.linspace(0.0, tr * timepoints, num=(timepoints * numsteps), endpoint=False)
|
|
606
|
+
+ teoffset
|
|
388
607
|
)
|
|
389
608
|
if (thispass == 0) and args.doupsampling:
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
)
|
|
395
|
-
|
|
396
|
-
# drop in the raw data
|
|
397
|
-
for theslice in range(numslices):
|
|
398
|
-
upsampleimage[
|
|
399
|
-
:, :, theslice, sliceoffsets[theslice] : timepoints * numsteps : numsteps
|
|
400
|
-
] = fmri_data.reshape((xsize, ysize, numslices, timepoints))[:, :, theslice, :]
|
|
401
|
-
|
|
402
|
-
# interpolate along the slice direction
|
|
403
|
-
for thestep in range(numsteps):
|
|
404
|
-
print(f"interpolating step {thestep}")
|
|
405
|
-
thesrclocs = np.where(sliceoffsets == thestep)[0]
|
|
406
|
-
print(f"sourcelocs: {thesrclocs}")
|
|
407
|
-
thedstlocs = np.linspace(0, numslices, num=len(sliceoffsets), endpoint=False)
|
|
408
|
-
print(f"len(destlocst), destlocs: {len(thedstlocs)}, {thedstlocs}")
|
|
409
|
-
for thetimepoint in range(0, timepoints * numsteps):
|
|
410
|
-
print(f"timepoint: {thetimepoint}")
|
|
411
|
-
for thexyvoxel in range(xsize * ysize):
|
|
412
|
-
theinterps = np.interp(
|
|
413
|
-
thedstlocs,
|
|
414
|
-
1.0 * thesrclocs,
|
|
415
|
-
upsampleimage_byslice[thexyvoxel, thesrclocs, thetimepoint],
|
|
416
|
-
)
|
|
417
|
-
upsampleimage_byslice[thexyvoxel, :, thetimepoint] = 1.0 * theinterps
|
|
418
|
-
|
|
419
|
-
theheader = copy.deepcopy(nim_hdr)
|
|
420
|
-
theheader["dim"][4] = timepoints * numsteps
|
|
421
|
-
theheader["pixdim"][4] = 1.0 / slicesamplerate
|
|
422
|
-
tide_io.savetonifti(upsampleimage, theheader, outputroot + "_upsampled")
|
|
609
|
+
happy_support.upsampleimage(
|
|
610
|
+
input_data, numsteps, sliceoffsets, slicesamplerate, outputroot
|
|
611
|
+
)
|
|
612
|
+
sys.exit(0)
|
|
423
613
|
|
|
424
614
|
if thispass == numpasses - 1:
|
|
425
615
|
tide_io.writebidstsv(
|
|
@@ -438,6 +628,14 @@ def happy_main(argparsingfunc):
|
|
|
438
628
|
append=False,
|
|
439
629
|
debug=args.debug,
|
|
440
630
|
)
|
|
631
|
+
tide_io.writebidstsv(
|
|
632
|
+
outputroot + "_desc-sliceresrespfromfmri_timeseries",
|
|
633
|
+
respfromfmri_sliceres,
|
|
634
|
+
slicesamplerate,
|
|
635
|
+
columns=["respfromfmri"],
|
|
636
|
+
append=False,
|
|
637
|
+
debug=args.debug,
|
|
638
|
+
)
|
|
441
639
|
|
|
442
640
|
# stash away a copy of the waveform if we need it later
|
|
443
641
|
raw_cardfromfmri_sliceres = np.array(cardfromfmri_sliceres)
|
|
@@ -454,6 +652,7 @@ def happy_main(argparsingfunc):
|
|
|
454
652
|
cardiacwaveform = np.array(cardfromfmri_sliceres)
|
|
455
653
|
badpointlist = np.array(thebadcardpts)
|
|
456
654
|
|
|
655
|
+
infodict["badptspct"] = 100.0 * np.mean(thebadcardpts)
|
|
457
656
|
infodict["slicesamplerate"] = slicesamplerate
|
|
458
657
|
infodict["numcardpts_sliceres"] = timepoints * numsteps
|
|
459
658
|
infodict["numsteps"] = numsteps
|
|
@@ -469,6 +668,15 @@ def happy_main(argparsingfunc):
|
|
|
469
668
|
slicesamplerate,
|
|
470
669
|
columns=["cardiacfromfmri_censored"],
|
|
471
670
|
append=True,
|
|
671
|
+
extraheaderinfo={"badptspct": infodict["badptspct"]},
|
|
672
|
+
debug=args.debug,
|
|
673
|
+
)
|
|
674
|
+
tide_io.writebidstsv(
|
|
675
|
+
outputroot + "_desc-sliceresrespfromfmri_timeseries",
|
|
676
|
+
respfromfmri_sliceres * (1.0 - thebadcardpts),
|
|
677
|
+
slicesamplerate,
|
|
678
|
+
columns=["respfromfmri_censored"],
|
|
679
|
+
append=True,
|
|
472
680
|
debug=args.debug,
|
|
473
681
|
)
|
|
474
682
|
peakfreq_bold = happy_support.getcardcoeffs(
|
|
@@ -499,7 +707,7 @@ def happy_main(argparsingfunc):
|
|
|
499
707
|
decimate=True,
|
|
500
708
|
debug=False,
|
|
501
709
|
)
|
|
502
|
-
)
|
|
710
|
+
)[0]
|
|
503
711
|
|
|
504
712
|
if thispass == numpasses - 1:
|
|
505
713
|
tide_io.writebidstsv(
|
|
@@ -508,6 +716,7 @@ def happy_main(argparsingfunc):
|
|
|
508
716
|
args.stdfreq,
|
|
509
717
|
columns=["cardiacfromfmri_" + str(args.stdfreq) + "Hz"],
|
|
510
718
|
append=False,
|
|
719
|
+
extraheaderinfo={"cardiacbpm_bold": float(infodict["cardiacbpm_bold"])},
|
|
511
720
|
debug=args.debug,
|
|
512
721
|
)
|
|
513
722
|
infodict["numcardpts_stdres"] = len(cardfromfmri_stdres)
|
|
@@ -531,7 +740,7 @@ def happy_main(argparsingfunc):
|
|
|
531
740
|
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
532
741
|
normcardfromfmri_stdres,
|
|
533
742
|
args.stdfreq,
|
|
534
|
-
columns=["
|
|
743
|
+
columns=["normcardiacfromfmri_" + str(args.stdfreq) + "Hz"],
|
|
535
744
|
append=True,
|
|
536
745
|
debug=args.debug,
|
|
537
746
|
)
|
|
@@ -573,8 +782,10 @@ def happy_main(argparsingfunc):
|
|
|
573
782
|
)
|
|
574
783
|
|
|
575
784
|
# apply the deep learning filter if we're going to do that
|
|
785
|
+
infodict["used_dlreconstruction_filter"] = False
|
|
576
786
|
if args.dodlfilter:
|
|
577
787
|
if dlfilterexists:
|
|
788
|
+
infodict["used_dlreconstruction_filter"] = True
|
|
578
789
|
if args.mpfix:
|
|
579
790
|
print("performing super dangerous openmp workaround")
|
|
580
791
|
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
|
|
@@ -621,7 +832,7 @@ def happy_main(argparsingfunc):
|
|
|
621
832
|
|
|
622
833
|
# downsample to sliceres from stdres
|
|
623
834
|
# cardfromfmri_sliceres = tide_math.madnormalize(
|
|
624
|
-
# tide_resample.arbresample(dlfilteredcard_stdres, args.stdfreq, slicesamplerate, decimate=True, debug=False))
|
|
835
|
+
# tide_resample.arbresample(dlfilteredcard_stdres, args.stdfreq, slicesamplerate, decimate=True, debug=False))[0]
|
|
625
836
|
stdtimeaxis = (1.0 / args.stdfreq) * np.linspace(
|
|
626
837
|
0.0,
|
|
627
838
|
len(dlfilteredcard_stdres),
|
|
@@ -643,7 +854,7 @@ def happy_main(argparsingfunc):
|
|
|
643
854
|
method="univariate",
|
|
644
855
|
padlen=0,
|
|
645
856
|
)
|
|
646
|
-
)
|
|
857
|
+
)[0]
|
|
647
858
|
if thispass == numpasses - 1:
|
|
648
859
|
tide_io.writebidstsv(
|
|
649
860
|
outputroot + "_desc-slicerescardfromfmri_timeseries",
|
|
@@ -653,7 +864,6 @@ def happy_main(argparsingfunc):
|
|
|
653
864
|
append=True,
|
|
654
865
|
debug=args.debug,
|
|
655
866
|
)
|
|
656
|
-
infodict["used_dlreconstruction_filter"] = True
|
|
657
867
|
peakfreq_dlfiltered = happy_support.getcardcoeffs(
|
|
658
868
|
cardfromfmri_sliceres,
|
|
659
869
|
slicesamplerate,
|
|
@@ -785,6 +995,7 @@ def happy_main(argparsingfunc):
|
|
|
785
995
|
append=True,
|
|
786
996
|
debug=args.debug,
|
|
787
997
|
)
|
|
998
|
+
|
|
788
999
|
tide_io.writebidstsv(
|
|
789
1000
|
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
790
1001
|
pleth_stdres,
|
|
@@ -807,6 +1018,19 @@ def happy_main(argparsingfunc):
|
|
|
807
1018
|
cutoff=args.envcutoff,
|
|
808
1019
|
thresh=args.envthresh,
|
|
809
1020
|
)
|
|
1021
|
+
|
|
1022
|
+
# calculate quality metrics
|
|
1023
|
+
happy_support.calcplethquality(
|
|
1024
|
+
filtpleth_stdres,
|
|
1025
|
+
args.stdfreq,
|
|
1026
|
+
infodict,
|
|
1027
|
+
"_pleth",
|
|
1028
|
+
outputroot,
|
|
1029
|
+
outputlevel=args.outputlevel,
|
|
1030
|
+
initfile=False,
|
|
1031
|
+
debug=args.debug,
|
|
1032
|
+
)
|
|
1033
|
+
|
|
810
1034
|
if thispass == numpasses - 1:
|
|
811
1035
|
tide_io.writebidstsv(
|
|
812
1036
|
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
@@ -816,6 +1040,14 @@ def happy_main(argparsingfunc):
|
|
|
816
1040
|
append=True,
|
|
817
1041
|
debug=args.debug,
|
|
818
1042
|
)
|
|
1043
|
+
tide_io.writebidstsv(
|
|
1044
|
+
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
1045
|
+
filtpleth_stdres,
|
|
1046
|
+
args.stdfreq,
|
|
1047
|
+
columns=["pleth_cleaned"],
|
|
1048
|
+
append=True,
|
|
1049
|
+
debug=args.debug,
|
|
1050
|
+
)
|
|
819
1051
|
tide_io.writebidstsv(
|
|
820
1052
|
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
821
1053
|
plethenv_stdres,
|
|
@@ -825,17 +1057,24 @@ def happy_main(argparsingfunc):
|
|
|
825
1057
|
debug=args.debug,
|
|
826
1058
|
)
|
|
827
1059
|
|
|
828
|
-
#
|
|
829
|
-
happy_support.
|
|
1060
|
+
# check the match between the cleaned bold and physio cardiac signals
|
|
1061
|
+
maxval, maxdelay, failreason = happy_support.checkcardmatch(
|
|
830
1062
|
filtpleth_stdres,
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
"_pleth",
|
|
834
|
-
outputroot,
|
|
835
|
-
outputlevel=args.outputlevel,
|
|
836
|
-
initfile=False,
|
|
1063
|
+
filtcardfromfmri_stdres,
|
|
1064
|
+
slicesamplerate,
|
|
837
1065
|
debug=args.debug,
|
|
838
1066
|
)
|
|
1067
|
+
print(
|
|
1068
|
+
"Input cardiac waveform delay is",
|
|
1069
|
+
"{:.3f}".format(maxdelay),
|
|
1070
|
+
)
|
|
1071
|
+
print(
|
|
1072
|
+
"Correlation coefficient between cardiac regressors is",
|
|
1073
|
+
"{:.3f}".format(maxval),
|
|
1074
|
+
)
|
|
1075
|
+
infodict["corrcoeff_filtraw2filtpleth"] = maxval + 0
|
|
1076
|
+
infodict["delay_filtraw2filtpleth"] = maxdelay + 0
|
|
1077
|
+
infodict["failreason_filtraw2filtpleth"] = failreason + 0
|
|
839
1078
|
|
|
840
1079
|
if args.dodlfilter and dlfilterexists:
|
|
841
1080
|
dlfilteredpleth = thedlfilter.apply(pleth_stdres)
|
|
@@ -895,7 +1134,7 @@ def happy_main(argparsingfunc):
|
|
|
895
1134
|
# find key components of cardiac waveform
|
|
896
1135
|
filtpleth = tide_math.madnormalize(
|
|
897
1136
|
thecardbandfilter.apply(slicesamplerate, pleth_sliceres)
|
|
898
|
-
)
|
|
1137
|
+
)[0]
|
|
899
1138
|
peakfreq_file = happy_support.getcardcoeffs(
|
|
900
1139
|
(1.0 - thebadplethpts_sliceres) * filtpleth,
|
|
901
1140
|
slicesamplerate,
|
|
@@ -941,13 +1180,38 @@ def happy_main(argparsingfunc):
|
|
|
941
1180
|
infodict["pleth"] = False
|
|
942
1181
|
peakfreq = peakfreq_bold
|
|
943
1182
|
if args.outputlevel > 0:
|
|
1183
|
+
extraheaderdict = {"badptspct": infodict["badptspct"]}
|
|
1184
|
+
if infodict["pleth"]:
|
|
1185
|
+
extraheaderdict["cardiacbpm_pleth"] = float(infodict["cardiacbpm_pleth"])
|
|
1186
|
+
if infodict["used_dlreconstruction_filter"]:
|
|
1187
|
+
extraheaderdict["cardiacbpm_dlfiltered"] = float(infodict["cardiacbpm_dlfiltered"])
|
|
944
1188
|
if thispass == numpasses - 1:
|
|
945
1189
|
tide_io.writebidstsv(
|
|
946
1190
|
outputroot + "_desc-slicerescardfromfmri_timeseries",
|
|
947
1191
|
badpointlist,
|
|
948
1192
|
slicesamplerate,
|
|
949
1193
|
columns=["badpts"],
|
|
1194
|
+
extraheaderinfo=extraheaderdict,
|
|
1195
|
+
append=True,
|
|
1196
|
+
debug=args.debug,
|
|
1197
|
+
)
|
|
1198
|
+
badpointlist_stdres = np.round(
|
|
1199
|
+
tide_resample.arbresample(
|
|
1200
|
+
badpointlist,
|
|
1201
|
+
slicesamplerate,
|
|
1202
|
+
args.stdfreq,
|
|
1203
|
+
decimate=True,
|
|
1204
|
+
debug=False,
|
|
1205
|
+
),
|
|
1206
|
+
0,
|
|
1207
|
+
)
|
|
1208
|
+
tide_io.writebidstsv(
|
|
1209
|
+
outputroot + "_desc-stdrescardfromfmri_timeseries",
|
|
1210
|
+
badpointlist_stdres,
|
|
1211
|
+
args.stdfreq,
|
|
1212
|
+
columns=["badpts"],
|
|
950
1213
|
append=True,
|
|
1214
|
+
extraheaderinfo=extraheaderdict,
|
|
951
1215
|
debug=args.debug,
|
|
952
1216
|
)
|
|
953
1217
|
|
|
@@ -963,7 +1227,7 @@ def happy_main(argparsingfunc):
|
|
|
963
1227
|
peakfreq,
|
|
964
1228
|
ncomps=args.hilbertcomponents,
|
|
965
1229
|
)
|
|
966
|
-
)
|
|
1230
|
+
)[0]
|
|
967
1231
|
else:
|
|
968
1232
|
filthiresfund = tide_math.madnormalize(
|
|
969
1233
|
happy_support.getperiodic(
|
|
@@ -972,7 +1236,7 @@ def happy_main(argparsingfunc):
|
|
|
972
1236
|
peakfreq,
|
|
973
1237
|
ncomps=args.hilbertcomponents,
|
|
974
1238
|
)
|
|
975
|
-
)
|
|
1239
|
+
)[0]
|
|
976
1240
|
if args.outputlevel > 1:
|
|
977
1241
|
if thispass == numpasses - 1:
|
|
978
1242
|
tide_io.writebidstsv(
|
|
@@ -1066,7 +1330,7 @@ def happy_main(argparsingfunc):
|
|
|
1066
1330
|
infodict["respsamplerate"] = returnedinputfreq
|
|
1067
1331
|
infodict["numresppts_fullres"] = fullrespts
|
|
1068
1332
|
|
|
1069
|
-
# account for slice time
|
|
1333
|
+
# account for slice time offsets
|
|
1070
1334
|
offsets_byslice = np.zeros((xsize * ysize, numslices), dtype=np.float64)
|
|
1071
1335
|
for i in range(numslices):
|
|
1072
1336
|
offsets_byslice[:, i] = slicetimes[i]
|
|
@@ -1076,11 +1340,15 @@ def happy_main(argparsingfunc):
|
|
|
1076
1340
|
|
|
1077
1341
|
# save the information file
|
|
1078
1342
|
if args.saveinfoasjson:
|
|
1079
|
-
tide_io.writedicttojson(infodict, outputroot + "
|
|
1343
|
+
tide_io.writedicttojson(infodict, outputroot + "_desc-runinfo.json")
|
|
1080
1344
|
else:
|
|
1081
1345
|
tide_io.writedict(infodict, outputroot + "_info.txt")
|
|
1082
1346
|
|
|
1083
1347
|
# interpolate the instantaneous phase
|
|
1348
|
+
print(f"{tr=}")
|
|
1349
|
+
print(f"{timepoints=}")
|
|
1350
|
+
print(f"{numsteps=}")
|
|
1351
|
+
print(f"{args.upsamplefac=}")
|
|
1084
1352
|
upsampledslicetimeaxis = np.linspace(
|
|
1085
1353
|
0.0,
|
|
1086
1354
|
tr * timepoints,
|
|
@@ -1158,20 +1426,12 @@ def happy_main(argparsingfunc):
|
|
|
1158
1426
|
# construct the destination arrays
|
|
1159
1427
|
tide_util.logmem("before making destination arrays")
|
|
1160
1428
|
app = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1161
|
-
app_byslice = app.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1162
1429
|
cine = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1163
|
-
cine_byslice = cine.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1164
1430
|
rawapp = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1165
|
-
rawapp_byslice = rawapp.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1166
1431
|
corrected_rawapp = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1167
|
-
corrected_rawapp_byslice = rawapp.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1168
1432
|
normapp = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1169
|
-
normapp_byslice = normapp.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1170
1433
|
weights = np.zeros((xsize, ysize, numslices, args.destpoints), dtype=np.float64)
|
|
1171
|
-
weight_byslice = weights.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1172
1434
|
derivatives = np.zeros((xsize, ysize, numslices, 4), dtype=np.float64)
|
|
1173
|
-
derivatives_byslice = derivatives.reshape((xsize * ysize, numslices, 4))
|
|
1174
|
-
|
|
1175
1435
|
timings.append(["Output arrays allocated" + passstring, time.time(), None, None])
|
|
1176
1436
|
|
|
1177
1437
|
if args.centric:
|
|
@@ -1185,10 +1445,22 @@ def happy_main(argparsingfunc):
|
|
|
1185
1445
|
# now do the phase projection
|
|
1186
1446
|
#
|
|
1187
1447
|
#
|
|
1448
|
+
app_byslice = app.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1449
|
+
rawapp_byslice = rawapp.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1450
|
+
corrected_rawapp_byslice = corrected_rawapp.reshape(
|
|
1451
|
+
(xsize * ysize, numslices, args.destpoints)
|
|
1452
|
+
)
|
|
1453
|
+
normapp_byslice = normapp.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1454
|
+
weights_byslice = weights.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1455
|
+
cine_byslice = cine.reshape((xsize * ysize, numslices, args.destpoints))
|
|
1456
|
+
derivatives_byslice = derivatives.reshape((xsize * ysize, numslices, 4))
|
|
1457
|
+
|
|
1188
1458
|
demeandata_byslice = demeandata.reshape((xsize * ysize, numslices, timepoints))
|
|
1189
1459
|
means_byslice = means.reshape((xsize * ysize, numslices))
|
|
1190
1460
|
|
|
1191
|
-
timings.append(
|
|
1461
|
+
timings.append(
|
|
1462
|
+
["Phase projection to image prep started" + passstring, time.time(), None, None]
|
|
1463
|
+
)
|
|
1192
1464
|
print("Starting phase projection")
|
|
1193
1465
|
proctrs = range(timepoints) # proctrs is the list of all fmri trs to be projected
|
|
1194
1466
|
procpoints = range(
|
|
@@ -1202,8 +1474,16 @@ def happy_main(argparsingfunc):
|
|
|
1202
1474
|
proctrs = np.where(censortrs < 1)[0]
|
|
1203
1475
|
procpoints = np.where(censorpoints < 1)[0]
|
|
1204
1476
|
|
|
1477
|
+
# preload congrid
|
|
1478
|
+
if args.preloadcongrid:
|
|
1479
|
+
print("Preloading congrid values...")
|
|
1480
|
+
happy_support.preloadcongrid(
|
|
1481
|
+
outphases, args.congridbins, gridkernel=args.gridkernel, cyclic=True, debug=False
|
|
1482
|
+
)
|
|
1483
|
+
print("done")
|
|
1484
|
+
|
|
1205
1485
|
# do phase averaging
|
|
1206
|
-
app_bypoint,
|
|
1486
|
+
app_bypoint, weights_bypoint = happy_support.cardiaccycleaverage(
|
|
1207
1487
|
instantaneous_cardiacphase,
|
|
1208
1488
|
outphases,
|
|
1209
1489
|
cardfromfmri_sliceres,
|
|
@@ -1211,6 +1491,7 @@ def happy_main(argparsingfunc):
|
|
|
1211
1491
|
args.congridbins,
|
|
1212
1492
|
args.gridkernel,
|
|
1213
1493
|
args.centric,
|
|
1494
|
+
cache=args.congridcache,
|
|
1214
1495
|
cyclic=True,
|
|
1215
1496
|
)
|
|
1216
1497
|
if thispass == numpasses - 1:
|
|
@@ -1225,7 +1506,7 @@ def happy_main(argparsingfunc):
|
|
|
1225
1506
|
)
|
|
1226
1507
|
tide_io.writebidstsv(
|
|
1227
1508
|
outputroot + "_desc-cardiaccycleweightfromfmri_timeseries",
|
|
1228
|
-
|
|
1509
|
+
weights_bypoint,
|
|
1229
1510
|
1.0 / (outphases[1] - outphases[0]),
|
|
1230
1511
|
starttime=outphases[0],
|
|
1231
1512
|
columns=["cardiaccycleweightfromfmri"],
|
|
@@ -1259,7 +1540,7 @@ def happy_main(argparsingfunc):
|
|
|
1259
1540
|
timediff = minloc - maxloc
|
|
1260
1541
|
zerophaselocs.append(1.0 * minloc - (minval - outphases[0]) * timediff / phasediff)
|
|
1261
1542
|
# print(idx, [maxloc, maxval], [minloc, minval], phasediff, timediff, zerophaselocs[-1])
|
|
1262
|
-
instantaneous_cardiactime = instantaneous_cardiacphase
|
|
1543
|
+
instantaneous_cardiactime = np.zeros_like(instantaneous_cardiacphase)
|
|
1263
1544
|
|
|
1264
1545
|
whichpeak = 0
|
|
1265
1546
|
for t in procpoints:
|
|
@@ -1282,7 +1563,7 @@ def happy_main(argparsingfunc):
|
|
|
1282
1563
|
outtimes = np.linspace(
|
|
1283
1564
|
0.0, maxtime, num=int(maxtime / args.pulsereconstepsize), endpoint=False
|
|
1284
1565
|
)
|
|
1285
|
-
atp_bypoint,
|
|
1566
|
+
atp_bypoint, atpweights_bypoint = happy_support.cardiaccycleaverage(
|
|
1286
1567
|
instantaneous_cardiactime,
|
|
1287
1568
|
outtimes,
|
|
1288
1569
|
cardfromfmri_sliceres,
|
|
@@ -1303,23 +1584,83 @@ def happy_main(argparsingfunc):
|
|
|
1303
1584
|
debug=args.debug,
|
|
1304
1585
|
)
|
|
1305
1586
|
|
|
1587
|
+
timings.append(
|
|
1588
|
+
["Phase projection to image prep ended" + passstring, time.time(), None, None]
|
|
1589
|
+
)
|
|
1306
1590
|
if not args.verbose:
|
|
1307
|
-
print("
|
|
1591
|
+
print("Setting up for phase projection...")
|
|
1592
|
+
|
|
1593
|
+
# make a vessel map using Wright's method
|
|
1594
|
+
if args.wrightiterations > 0:
|
|
1595
|
+
timings.append(
|
|
1596
|
+
[
|
|
1597
|
+
"Wright mask generation started" + passstring,
|
|
1598
|
+
time.time(),
|
|
1599
|
+
None,
|
|
1600
|
+
None,
|
|
1601
|
+
]
|
|
1602
|
+
)
|
|
1603
|
+
wrightcorrs = happy_support.wrightmap(
|
|
1604
|
+
input_data,
|
|
1605
|
+
demeandata_byslice,
|
|
1606
|
+
rawapp_byslice,
|
|
1607
|
+
projmask_byslice,
|
|
1608
|
+
outphases,
|
|
1609
|
+
cardphasevals,
|
|
1610
|
+
proctrs,
|
|
1611
|
+
args.congridbins,
|
|
1612
|
+
args.gridkernel,
|
|
1613
|
+
args.destpoints,
|
|
1614
|
+
iterations=args.wrightiterations,
|
|
1615
|
+
nprocs=args.nprocs,
|
|
1616
|
+
verbose=False,
|
|
1617
|
+
debug=args.debug,
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
1621
|
+
maplist = [
|
|
1622
|
+
(
|
|
1623
|
+
wrightcorrs,
|
|
1624
|
+
f"wrightcorrspass{passnamefrag}",
|
|
1625
|
+
"map",
|
|
1626
|
+
None,
|
|
1627
|
+
"fMRI timecourse MAD over time",
|
|
1628
|
+
),
|
|
1629
|
+
]
|
|
1630
|
+
tide_io.savemaplist(
|
|
1631
|
+
outputroot,
|
|
1632
|
+
maplist,
|
|
1633
|
+
None,
|
|
1634
|
+
(xsize, ysize, numslices),
|
|
1635
|
+
theheader,
|
|
1636
|
+
bidsdict,
|
|
1637
|
+
debug=args.debug,
|
|
1638
|
+
)
|
|
1639
|
+
timings.append(
|
|
1640
|
+
[
|
|
1641
|
+
"Wright mask generation completed" + passstring,
|
|
1642
|
+
time.time(),
|
|
1643
|
+
None,
|
|
1644
|
+
None,
|
|
1645
|
+
]
|
|
1646
|
+
)
|
|
1308
1647
|
|
|
1648
|
+
timings.append(["Phase projection to image started" + passstring, time.time(), None, None])
|
|
1309
1649
|
# make a lowpass filter for the projected data. Limit frequency to 3 cycles per 2pi (1/6th Fs)
|
|
1310
1650
|
phaseFs = 1.0 / phasestep
|
|
1311
1651
|
phaseFc = phaseFs / 6.0
|
|
1312
|
-
appsmoothingfilter = tide_filt.NoncausalFilter("arb",
|
|
1652
|
+
appsmoothingfilter = tide_filt.NoncausalFilter("arb", padtime=0.0)
|
|
1313
1653
|
appsmoothingfilter.setfreqs(0.0, 0.0, phaseFc, phaseFc)
|
|
1314
1654
|
|
|
1315
1655
|
# setup for aliased correlation if we're going to do it
|
|
1316
|
-
if args.doaliasedcorrelation
|
|
1656
|
+
if args.doaliasedcorrelation:
|
|
1317
1657
|
if args.cardiacfilename and False:
|
|
1318
1658
|
signal_sliceres = pleth_sliceres
|
|
1319
|
-
# signal_stdres = pleth_stdres
|
|
1320
1659
|
else:
|
|
1321
1660
|
signal_sliceres = cardfromfmri_sliceres
|
|
1322
|
-
|
|
1661
|
+
|
|
1662
|
+
# zero out bad points
|
|
1663
|
+
signal_sliceres *= 1.0 - badpointlist
|
|
1323
1664
|
|
|
1324
1665
|
theAliasedCorrelator = tide_corr.AliasedCorrelator(
|
|
1325
1666
|
signal_sliceres,
|
|
@@ -1332,120 +1673,64 @@ def happy_main(argparsingfunc):
|
|
|
1332
1673
|
)
|
|
1333
1674
|
correndloc = tide_util.valtoindex(thealiasedcorrx, args.aliasedcorrelationwidth / 2.0)
|
|
1334
1675
|
aliasedcorrelationpts = correndloc - corrstartloc + 1
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
thecorrfunc_byslice = thecorrfunc.reshape(
|
|
1339
|
-
(xsize * ysize, numslices, aliasedcorrelationpts)
|
|
1340
|
-
)
|
|
1341
|
-
wavedelay = np.zeros((xsize, ysize, numslices), dtype=np.float64)
|
|
1342
|
-
wavedelay_byslice = wavedelay.reshape((xsize * ysize, numslices))
|
|
1343
|
-
waveamp = np.zeros((xsize, ysize, numslices), dtype=np.float64)
|
|
1344
|
-
waveamp_byslice = waveamp.reshape((xsize * ysize, numslices))
|
|
1345
|
-
|
|
1346
|
-
# now project the data
|
|
1347
|
-
fmri_data_byslice = input_data.byslice()
|
|
1348
|
-
for theslice in tqdm(
|
|
1349
|
-
range(numslices),
|
|
1350
|
-
desc="Slice",
|
|
1351
|
-
unit="slices",
|
|
1352
|
-
disable=(not args.showprogressbar),
|
|
1353
|
-
):
|
|
1354
|
-
if args.verbose:
|
|
1355
|
-
print("Phase projecting for slice", theslice)
|
|
1356
|
-
validlocs = np.where(projmask_byslice[:, theslice] > 0)[0]
|
|
1357
|
-
# indexlist = range(0, len(cardphasevals[theslice, :]))
|
|
1358
|
-
if len(validlocs) > 0:
|
|
1359
|
-
for t in proctrs:
|
|
1360
|
-
filteredmr = -demeandata_byslice[validlocs, theslice, t]
|
|
1361
|
-
cinemr = fmri_data_byslice[validlocs, theslice, t]
|
|
1362
|
-
thevals, theweights, theindices = tide_resample.congrid(
|
|
1363
|
-
outphases,
|
|
1364
|
-
cardphasevals[theslice, t],
|
|
1365
|
-
1.0,
|
|
1366
|
-
args.congridbins,
|
|
1367
|
-
kernel=args.gridkernel,
|
|
1368
|
-
cyclic=True,
|
|
1369
|
-
)
|
|
1370
|
-
for i in range(len(theindices)):
|
|
1371
|
-
weight_byslice[validlocs, theslice, theindices[i]] += theweights[i]
|
|
1372
|
-
# rawapp_byslice[validlocs, theslice, theindices[i]] += (
|
|
1373
|
-
# theweights[i] * filteredmr
|
|
1374
|
-
# )
|
|
1375
|
-
rawapp_byslice[validlocs, theslice, theindices[i]] += filteredmr
|
|
1376
|
-
cine_byslice[validlocs, theslice, theindices[i]] += theweights[i] * cinemr
|
|
1377
|
-
for d in range(args.destpoints):
|
|
1378
|
-
if weight_byslice[validlocs[0], theslice, d] == 0.0:
|
|
1379
|
-
weight_byslice[validlocs, theslice, d] = 1.0
|
|
1380
|
-
rawapp_byslice[validlocs, theslice, :] = np.nan_to_num(
|
|
1381
|
-
rawapp_byslice[validlocs, theslice, :] / weight_byslice[validlocs, theslice, :]
|
|
1676
|
+
if thispass == 0:
|
|
1677
|
+
thecorrfunc = np.zeros(
|
|
1678
|
+
(xsize, ysize, numslices, aliasedcorrelationpts), dtype=np.float64
|
|
1382
1679
|
)
|
|
1383
|
-
|
|
1384
|
-
|
|
1680
|
+
thecorrfunc_byslice = thecorrfunc.reshape(
|
|
1681
|
+
(xsize * ysize, numslices, aliasedcorrelationpts)
|
|
1385
1682
|
)
|
|
1683
|
+
wavedelay = np.zeros((xsize, ysize, numslices), dtype=np.float64)
|
|
1684
|
+
wavedelay_byslice = wavedelay.reshape((xsize * ysize, numslices))
|
|
1685
|
+
wavedelayCOM = np.zeros((xsize, ysize, numslices), dtype=np.float64)
|
|
1686
|
+
wavedelayCOM_byslice = wavedelayCOM.reshape((xsize * ysize, numslices))
|
|
1687
|
+
waveamp = np.zeros((xsize, ysize, numslices), dtype=np.float64)
|
|
1688
|
+
waveamp_byslice = waveamp.reshape((xsize * ysize, numslices))
|
|
1386
1689
|
else:
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
int(sliceoffsets[theslice]),
|
|
1432
|
-
)[corrstartloc : correndloc + 1]
|
|
1433
|
-
maxloc = np.argmax(np.abs(thecorrfunc_byslice[theloc, theslice, :]))
|
|
1434
|
-
wavedelay_byslice[theloc, theslice] = (
|
|
1435
|
-
thealiasedcorrx[corrstartloc : correndloc + 1]
|
|
1436
|
-
)[maxloc]
|
|
1437
|
-
waveamp_byslice[theloc, theslice] = thecorrfunc_byslice[
|
|
1438
|
-
theloc, theslice, maxloc
|
|
1439
|
-
]
|
|
1440
|
-
timecoursemin = np.min(
|
|
1441
|
-
corrected_rawapp_byslice[validlocs, theslice, :], axis=1
|
|
1442
|
-
).reshape((-1, 1))
|
|
1443
|
-
app_byslice[validlocs, theslice, :] = (
|
|
1444
|
-
corrected_rawapp_byslice[validlocs, theslice, :] - timecoursemin
|
|
1445
|
-
)
|
|
1446
|
-
normapp_byslice[validlocs, theslice, :] = np.nan_to_num(
|
|
1447
|
-
app_byslice[validlocs, theslice, :] / means_byslice[validlocs, theslice, None]
|
|
1448
|
-
)
|
|
1690
|
+
thecorrfunc *= 0.0
|
|
1691
|
+
wavedelay *= 0.0
|
|
1692
|
+
wavedelayCOM *= 0.0
|
|
1693
|
+
waveamp *= 0.0
|
|
1694
|
+
else:
|
|
1695
|
+
thecorrfunc_byslice = None
|
|
1696
|
+
waveamp_byslice = None
|
|
1697
|
+
wavedelay_byslice = None
|
|
1698
|
+
wavedelayCOM_byslice = None
|
|
1699
|
+
corrstartloc = None
|
|
1700
|
+
correndloc = None
|
|
1701
|
+
thealiasedcorrx = None
|
|
1702
|
+
theAliasedCorrelator = None
|
|
1703
|
+
|
|
1704
|
+
# now project the data
|
|
1705
|
+
appflips_byslice = happy_support.phaseproject(
|
|
1706
|
+
input_data,
|
|
1707
|
+
demeandata_byslice,
|
|
1708
|
+
means_byslice,
|
|
1709
|
+
rawapp_byslice,
|
|
1710
|
+
app_byslice,
|
|
1711
|
+
normapp_byslice,
|
|
1712
|
+
weights_byslice,
|
|
1713
|
+
cine_byslice,
|
|
1714
|
+
projmask_byslice,
|
|
1715
|
+
derivatives_byslice,
|
|
1716
|
+
proctrs,
|
|
1717
|
+
thispass,
|
|
1718
|
+
args,
|
|
1719
|
+
sliceoffsets,
|
|
1720
|
+
cardphasevals,
|
|
1721
|
+
outphases,
|
|
1722
|
+
appsmoothingfilter,
|
|
1723
|
+
phaseFs,
|
|
1724
|
+
thecorrfunc_byslice,
|
|
1725
|
+
waveamp_byslice,
|
|
1726
|
+
wavedelay_byslice,
|
|
1727
|
+
wavedelayCOM_byslice,
|
|
1728
|
+
corrected_rawapp_byslice,
|
|
1729
|
+
corrstartloc,
|
|
1730
|
+
correndloc,
|
|
1731
|
+
thealiasedcorrx,
|
|
1732
|
+
theAliasedCorrelator,
|
|
1733
|
+
)
|
|
1449
1734
|
if not args.verbose:
|
|
1450
1735
|
print(" done")
|
|
1451
1736
|
timings.append(
|
|
@@ -1461,10 +1746,7 @@ def happy_main(argparsingfunc):
|
|
|
1461
1746
|
# calculate the flow field from the normapp
|
|
1462
1747
|
if args.doflowfields:
|
|
1463
1748
|
print("calculating flow fields")
|
|
1464
|
-
flowhdr =
|
|
1465
|
-
flowhdr["dim"][4] = 3
|
|
1466
|
-
flowhdr["toffset"] = 0
|
|
1467
|
-
flowhdr["pixdim"][4] = 1
|
|
1749
|
+
flowhdr = input_data.copyheader(numtimepoints=3, tr=1.0, toffset=0.0)
|
|
1468
1750
|
|
|
1469
1751
|
flowfield = happy_support.calc_3d_optical_flow(
|
|
1470
1752
|
app,
|
|
@@ -1477,47 +1759,112 @@ def happy_main(argparsingfunc):
|
|
|
1477
1759
|
print(f"flow field shape: {flowfield.shape}")
|
|
1478
1760
|
|
|
1479
1761
|
# save the analytic phase projection image
|
|
1480
|
-
theheader =
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
theheader["pixdim"][4] = 2.0 * np.pi / args.destpoints
|
|
1762
|
+
theheader = input_data.copyheader(
|
|
1763
|
+
numtimepoints=args.destpoints, tr=-np.pi, toffset=2.0 * np.pi / args.destpoints
|
|
1764
|
+
)
|
|
1484
1765
|
if thispass == numpasses - 1:
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1766
|
+
maplist = [
|
|
1767
|
+
(
|
|
1768
|
+
app,
|
|
1769
|
+
"app",
|
|
1770
|
+
"info",
|
|
1771
|
+
None,
|
|
1772
|
+
"Cardiac pulsatility waveform with minimum over time removed",
|
|
1773
|
+
),
|
|
1774
|
+
(
|
|
1775
|
+
normapp,
|
|
1776
|
+
"normapp",
|
|
1777
|
+
"info",
|
|
1778
|
+
"percent",
|
|
1779
|
+
"Cardiac pulsatility waveform in percentage change relative to mean",
|
|
1780
|
+
),
|
|
1781
|
+
(
|
|
1782
|
+
cine,
|
|
1783
|
+
"cine",
|
|
1784
|
+
"info",
|
|
1785
|
+
None,
|
|
1786
|
+
"fMRI signal averaged over a single cardiac cycle",
|
|
1787
|
+
),
|
|
1788
|
+
]
|
|
1499
1789
|
if args.outputlevel > 0:
|
|
1500
|
-
|
|
1501
|
-
|
|
1790
|
+
maplist += [
|
|
1791
|
+
(
|
|
1792
|
+
rawapp,
|
|
1793
|
+
"rawapp",
|
|
1794
|
+
"info",
|
|
1795
|
+
None,
|
|
1796
|
+
"Cardiac pulsatility waveform",
|
|
1797
|
+
),
|
|
1798
|
+
]
|
|
1799
|
+
# write the 4D phase projection maps
|
|
1800
|
+
tide_io.savemaplist(
|
|
1801
|
+
outputroot,
|
|
1802
|
+
maplist,
|
|
1803
|
+
None,
|
|
1804
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1805
|
+
theheader,
|
|
1806
|
+
bidsdict,
|
|
1807
|
+
debug=args.debug,
|
|
1808
|
+
)
|
|
1502
1809
|
timings.append(["Phase projected data saved" + passstring, time.time(), None, None])
|
|
1503
1810
|
|
|
1504
1811
|
if args.doaliasedcorrelation and thispass == numpasses - 1:
|
|
1505
|
-
theheader =
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1812
|
+
theheader = input_data.copyheader(
|
|
1813
|
+
numtimepoints=aliasedcorrelationpts,
|
|
1814
|
+
tr=(thealiasedcorrx[1] - thealiasedcorrx[0]),
|
|
1815
|
+
toffset=0.0,
|
|
1816
|
+
)
|
|
1817
|
+
maplist = [
|
|
1818
|
+
(
|
|
1819
|
+
thecorrfunc,
|
|
1820
|
+
"corrfunc",
|
|
1821
|
+
"info",
|
|
1822
|
+
None,
|
|
1823
|
+
"Aliased correlation function",
|
|
1824
|
+
),
|
|
1825
|
+
]
|
|
1826
|
+
tide_io.savemaplist(
|
|
1827
|
+
outputroot,
|
|
1828
|
+
maplist,
|
|
1829
|
+
None,
|
|
1830
|
+
(xsize, ysize, numslices, aliasedcorrelationpts),
|
|
1831
|
+
theheader,
|
|
1832
|
+
bidsdict,
|
|
1833
|
+
debug=args.debug,
|
|
1834
|
+
)
|
|
1518
1835
|
theheader["dim"][4] = 1
|
|
1519
|
-
|
|
1520
|
-
|
|
1836
|
+
maplist = [
|
|
1837
|
+
(
|
|
1838
|
+
wavedelay,
|
|
1839
|
+
"wavedelay",
|
|
1840
|
+
"map",
|
|
1841
|
+
"seconds",
|
|
1842
|
+
"Peak delay of aliased correlation function",
|
|
1843
|
+
),
|
|
1844
|
+
(
|
|
1845
|
+
wavedelayCOM,
|
|
1846
|
+
"wavedelayCOM",
|
|
1847
|
+
"map",
|
|
1848
|
+
"seconds",
|
|
1849
|
+
"Center of mass of aliased correlation function",
|
|
1850
|
+
),
|
|
1851
|
+
(
|
|
1852
|
+
waveamp,
|
|
1853
|
+
"waveamp",
|
|
1854
|
+
"map",
|
|
1855
|
+
None,
|
|
1856
|
+
"Peak amplitude of aliased correlation function",
|
|
1857
|
+
),
|
|
1858
|
+
]
|
|
1859
|
+
tide_io.savemaplist(
|
|
1860
|
+
outputroot,
|
|
1861
|
+
maplist,
|
|
1862
|
+
None,
|
|
1863
|
+
(xsize, ysize, numslices),
|
|
1864
|
+
theheader,
|
|
1865
|
+
bidsdict,
|
|
1866
|
+
debug=args.debug,
|
|
1867
|
+
)
|
|
1521
1868
|
|
|
1522
1869
|
# make and save a voxel intensity histogram
|
|
1523
1870
|
if args.unnormvesselmap:
|
|
@@ -1536,12 +1883,12 @@ def happy_main(argparsingfunc):
|
|
|
1536
1883
|
debug=args.debug,
|
|
1537
1884
|
)
|
|
1538
1885
|
|
|
1539
|
-
# find vessel
|
|
1886
|
+
# find vessel thresholds
|
|
1540
1887
|
tide_util.logmem("before making vessel masks")
|
|
1541
1888
|
hardvesselthresh = tide_stats.getfracvals(np.max(histinput, axis=1), [0.98])[0] / 2.0
|
|
1542
1889
|
softvesselthresh = args.softvesselfrac * hardvesselthresh
|
|
1543
1890
|
print(
|
|
1544
|
-
"hard, soft vessel
|
|
1891
|
+
"hard, soft vessel thresholds set to",
|
|
1545
1892
|
"{:.3f}".format(hardvesselthresh),
|
|
1546
1893
|
"{:.3f}".format(softvesselthresh),
|
|
1547
1894
|
)
|
|
@@ -1551,28 +1898,42 @@ def happy_main(argparsingfunc):
|
|
|
1551
1898
|
vesselmask = np.where(np.max(app, axis=3) > softvesselthresh, 1, 0)
|
|
1552
1899
|
else:
|
|
1553
1900
|
vesselmask = np.where(np.max(normapp, axis=3) > softvesselthresh, 1, 0)
|
|
1901
|
+
infodict["vesselmaskvoxels"] = np.int64(np.sum(vesselmask))
|
|
1902
|
+
infodict["vesselmaskpct"] = (
|
|
1903
|
+
100.0 * infodict["vesselmaskvoxels"] / infodict["projmaskvoxels"]
|
|
1904
|
+
)
|
|
1554
1905
|
maskedapp2d = np.array(app2d)
|
|
1555
1906
|
maskedapp2d[np.where(vesselmask.reshape(numspatiallocs) == 0)[0], :] = 0.0
|
|
1556
1907
|
if args.outputlevel > 1:
|
|
1557
1908
|
if thispass == numpasses - 1:
|
|
1558
|
-
maskedappfilename = outputroot + "_desc-maskedapp_info"
|
|
1559
1909
|
bidsdict = bidsbasedict.copy()
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1910
|
+
maplist = [
|
|
1911
|
+
(
|
|
1912
|
+
maskedapp2d.reshape((xsize, ysize, numslices, args.destpoints)),
|
|
1913
|
+
"maskedapp",
|
|
1914
|
+
"info",
|
|
1915
|
+
None,
|
|
1916
|
+
"Masked analytic phase projection",
|
|
1917
|
+
),
|
|
1918
|
+
]
|
|
1919
|
+
tide_io.savemaplist(
|
|
1920
|
+
outputroot,
|
|
1921
|
+
maplist,
|
|
1922
|
+
None,
|
|
1923
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1564
1924
|
theheader,
|
|
1565
|
-
|
|
1925
|
+
bidsdict,
|
|
1926
|
+
debug=args.debug,
|
|
1927
|
+
)
|
|
1928
|
+
timings.append(
|
|
1929
|
+
[
|
|
1930
|
+
"Vessel masked phase projected data saved" + passstring,
|
|
1931
|
+
time.time(),
|
|
1932
|
+
None,
|
|
1933
|
+
None,
|
|
1934
|
+
]
|
|
1566
1935
|
)
|
|
1567
1936
|
del maskedapp2d
|
|
1568
|
-
timings.append(
|
|
1569
|
-
[
|
|
1570
|
-
"Vessel masked phase projected data saved" + passstring,
|
|
1571
|
-
time.time(),
|
|
1572
|
-
None,
|
|
1573
|
-
None,
|
|
1574
|
-
]
|
|
1575
|
-
)
|
|
1576
1937
|
|
|
1577
1938
|
# save multiple versions of the hard vessel mask
|
|
1578
1939
|
if args.unnormvesselmap:
|
|
@@ -1586,61 +1947,345 @@ def happy_main(argparsingfunc):
|
|
|
1586
1947
|
risediff = (maxphase - minphase) * vesselmask
|
|
1587
1948
|
arteries = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) < 0, vesselmask, 0)
|
|
1588
1949
|
veins = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmask, 0)
|
|
1589
|
-
theheader =
|
|
1590
|
-
theheader["dim"][4] = 1
|
|
1950
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
1591
1951
|
if thispass == numpasses - 1:
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1952
|
+
maplist = [
|
|
1953
|
+
(
|
|
1954
|
+
vesselmask,
|
|
1955
|
+
"vessels",
|
|
1956
|
+
"mask",
|
|
1957
|
+
None,
|
|
1958
|
+
"Vessel mask",
|
|
1959
|
+
),
|
|
1960
|
+
]
|
|
1600
1961
|
if args.outputlevel > 0:
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1962
|
+
maplist += [
|
|
1963
|
+
(
|
|
1964
|
+
minphase,
|
|
1965
|
+
"minphase",
|
|
1966
|
+
"map",
|
|
1967
|
+
"radians",
|
|
1968
|
+
"Cardiac phase where minimum pulsatility signal occurs",
|
|
1969
|
+
),
|
|
1970
|
+
(
|
|
1971
|
+
maxphase,
|
|
1972
|
+
"maxphase",
|
|
1973
|
+
"map",
|
|
1974
|
+
"radians",
|
|
1975
|
+
"Cardiac phase where maximum pulsatility signal occurs",
|
|
1976
|
+
),
|
|
1977
|
+
(
|
|
1978
|
+
arteries,
|
|
1979
|
+
"arteries",
|
|
1980
|
+
"map",
|
|
1981
|
+
None,
|
|
1982
|
+
"Arterial voxels (maybe)",
|
|
1983
|
+
),
|
|
1984
|
+
(
|
|
1985
|
+
veins,
|
|
1986
|
+
"veins",
|
|
1987
|
+
"map",
|
|
1988
|
+
None,
|
|
1989
|
+
"Venous voxels (maybe)",
|
|
1990
|
+
),
|
|
1991
|
+
]
|
|
1992
|
+
tide_io.savemaplist(
|
|
1993
|
+
outputroot,
|
|
1994
|
+
maplist,
|
|
1995
|
+
None,
|
|
1996
|
+
(xsize, ysize, numslices),
|
|
1997
|
+
theheader,
|
|
1998
|
+
bidsdict,
|
|
1999
|
+
debug=args.debug,
|
|
2000
|
+
)
|
|
1610
2001
|
timings.append(["Masks saved" + passstring, time.time(), None, None])
|
|
1611
2002
|
|
|
1612
|
-
#
|
|
1613
|
-
|
|
2003
|
+
# save the mask we used for this pass
|
|
2004
|
+
tide_io.savemaplist(
|
|
2005
|
+
outputroot,
|
|
2006
|
+
[
|
|
2007
|
+
(
|
|
2008
|
+
estweights_byslice.reshape((xsize, ysize, numslices)),
|
|
2009
|
+
f"estweights{passnamefrag}",
|
|
2010
|
+
"map",
|
|
2011
|
+
None,
|
|
2012
|
+
f"Estweights{passstring}",
|
|
2013
|
+
),
|
|
2014
|
+
],
|
|
2015
|
+
None,
|
|
2016
|
+
(xsize, ysize, numslices),
|
|
2017
|
+
theheader,
|
|
2018
|
+
bidsdict,
|
|
2019
|
+
debug=args.debug,
|
|
2020
|
+
)
|
|
2021
|
+
|
|
2022
|
+
# estimate pulsatility
|
|
2023
|
+
(
|
|
2024
|
+
card_min,
|
|
2025
|
+
card_max,
|
|
2026
|
+
card_mean,
|
|
2027
|
+
card_std,
|
|
2028
|
+
card_median,
|
|
2029
|
+
card_mad,
|
|
2030
|
+
card_skew,
|
|
2031
|
+
card_kurtosis,
|
|
2032
|
+
) = tide_stats.fmristats(normapp.reshape(numspatiallocs, -1))
|
|
2033
|
+
maplist = [
|
|
2034
|
+
(
|
|
2035
|
+
card_min,
|
|
2036
|
+
"appmin",
|
|
2037
|
+
"map",
|
|
2038
|
+
None,
|
|
2039
|
+
"Minimum value of analytic phase projection across all phases",
|
|
2040
|
+
),
|
|
2041
|
+
(
|
|
2042
|
+
card_max,
|
|
2043
|
+
"appmax",
|
|
2044
|
+
"map",
|
|
2045
|
+
None,
|
|
2046
|
+
"Maximum value of analytic phase projection across all phases",
|
|
2047
|
+
),
|
|
2048
|
+
(
|
|
2049
|
+
card_mean,
|
|
2050
|
+
"appmean",
|
|
2051
|
+
"map",
|
|
2052
|
+
None,
|
|
2053
|
+
"Mean value of analytic phase projection across all phases",
|
|
2054
|
+
),
|
|
2055
|
+
(
|
|
2056
|
+
card_std,
|
|
2057
|
+
"appstd",
|
|
2058
|
+
"map",
|
|
2059
|
+
None,
|
|
2060
|
+
"Standard deviation of analytic phase projection across all phases",
|
|
2061
|
+
),
|
|
2062
|
+
(
|
|
2063
|
+
card_median,
|
|
2064
|
+
"appmedian",
|
|
2065
|
+
"map",
|
|
2066
|
+
None,
|
|
2067
|
+
"Median of analytic phase projection across all phases",
|
|
2068
|
+
),
|
|
2069
|
+
(
|
|
2070
|
+
card_mad,
|
|
2071
|
+
"appMAD",
|
|
2072
|
+
"map",
|
|
2073
|
+
None,
|
|
2074
|
+
"Median average deviate of analytic phase projection across all phases",
|
|
2075
|
+
),
|
|
2076
|
+
(
|
|
2077
|
+
card_skew,
|
|
2078
|
+
"appskew",
|
|
2079
|
+
"map",
|
|
2080
|
+
None,
|
|
2081
|
+
"Skewness of analytic phase projection across all phases",
|
|
2082
|
+
),
|
|
2083
|
+
(
|
|
2084
|
+
card_kurtosis,
|
|
2085
|
+
"appkurtosis",
|
|
2086
|
+
"map",
|
|
2087
|
+
None,
|
|
2088
|
+
"Kurtosis of analytic phase projection across all phases",
|
|
2089
|
+
),
|
|
2090
|
+
]
|
|
2091
|
+
# write the 3D maps
|
|
2092
|
+
tide_io.savemaplist(
|
|
2093
|
+
outputroot,
|
|
2094
|
+
maplist,
|
|
2095
|
+
None,
|
|
2096
|
+
(xsize, ysize, numslices),
|
|
2097
|
+
theheader,
|
|
2098
|
+
bidsdict,
|
|
2099
|
+
debug=args.debug,
|
|
2100
|
+
)
|
|
2101
|
+
|
|
2102
|
+
pulsatilitymap = 100.0 * (np.max(normapp, axis=3) - np.min(normapp, axis=3))
|
|
2103
|
+
rawrobustmax = tide_stats.getfracval(pulsatilitymap, 0.98, nozero=True)
|
|
2104
|
+
pulsatilityfloor = tide_stats.getfracval(
|
|
2105
|
+
pulsatilitymap, 1.0 - (MIN_PULSATILITY_VOX_PCT / 100.0), nozero=True
|
|
2106
|
+
)
|
|
2107
|
+
rawmedian = tide_stats.getfracval(pulsatilitymap, 0.50, nozero=True)
|
|
2108
|
+
infodict["pulsatilityrobustmax"] = rawrobustmax
|
|
2109
|
+
infodict["pulsatilitymedian"] = rawmedian
|
|
2110
|
+
# make sure at least a minimum percentage of voxels remain in pulsatility mask
|
|
2111
|
+
infodict["pulsatilitythresh"] = np.min([rawmedian * 3.0, pulsatilityfloor])
|
|
2112
|
+
pulsatilitymap = np.where(pulsatilitymap < rawrobustmax, pulsatilitymap, rawrobustmax)
|
|
2113
|
+
pulsatilitymask = np.where(pulsatilitymap > infodict["pulsatilitythresh"], 1.0, 0.0)
|
|
2114
|
+
infodict["pulsatilitymaskvoxels"] = np.int64(np.sum(vesselmask))
|
|
2115
|
+
infodict["pulsatilitymaskpct"] = (
|
|
2116
|
+
100.0 * infodict["pulsatilitymaskvoxels"] / infodict["projmaskvoxels"]
|
|
2117
|
+
)
|
|
2118
|
+
|
|
2119
|
+
# save the information file
|
|
2120
|
+
if args.saveinfoasjson:
|
|
2121
|
+
tide_io.writedicttojson(infodict, outputroot + "_desc-runinfo.json")
|
|
2122
|
+
else:
|
|
2123
|
+
tide_io.writedict(infodict, outputroot + "_info.txt")
|
|
1614
2124
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
2125
|
+
# now get ready to start again with a new mask
|
|
2126
|
+
if args.doaliasedcorrelation and thispass > 0:
|
|
2127
|
+
estweights_byslice = waveamp_byslice * vesselmask.reshape((xsize * ysize, numslices))
|
|
2128
|
+
else:
|
|
2129
|
+
if args.useoriginalvesselmethod:
|
|
2130
|
+
estweights_byslice = vesselmask.reshape((xsize * ysize, numslices)) + 0
|
|
2131
|
+
else:
|
|
2132
|
+
estweights_byslice = pulsatilitymask.reshape((xsize * ysize, numslices)) + 0
|
|
2133
|
+
|
|
2134
|
+
# calculate the lf and hf pulsatility maps
|
|
2135
|
+
lfnormapp = np.zeros_like(normapp)
|
|
2136
|
+
hfnormapp = np.zeros_like(normapp)
|
|
2137
|
+
for thephase in range(args.destpoints):
|
|
2138
|
+
lfnormapp[:, :, :, thephase] = (
|
|
2139
|
+
tide_filt.ssmooth(
|
|
2140
|
+
xdim, ydim, slicethickness, args.pulsatilitysigma, normapp[:, :, :, thephase]
|
|
2141
|
+
)
|
|
2142
|
+
* pulsatilitymask
|
|
2143
|
+
)
|
|
2144
|
+
hfnormapp[:, :, :, thephase] = normapp[:, :, :, thephase] - lfnormapp[:, :, :, thephase]
|
|
2145
|
+
lfnormapp -= np.min(lfnormapp, axis=3)[:, :, :, None]
|
|
2146
|
+
hfnormapp -= np.min(hfnormapp, axis=3)[:, :, :, None]
|
|
2147
|
+
lfpulsatilitymap = (
|
|
2148
|
+
tide_filt.ssmooth(xdim, ydim, slicethickness, args.pulsatilitysigma, pulsatilitymap)
|
|
2149
|
+
* pulsatilitymask
|
|
2150
|
+
)
|
|
2151
|
+
hfpulsatilitymap = pulsatilitymap - lfpulsatilitymap
|
|
2152
|
+
lfpulsatilitymap2 = 100.0 * np.max(lfnormapp, axis=3)
|
|
2153
|
+
lfrobustmax = tide_stats.getfracval(lfpulsatilitymap2, 0.98, nozero=True)
|
|
2154
|
+
lfpulsatilitymap2 = np.where(lfpulsatilitymap2 < lfrobustmax, lfpulsatilitymap2, lfrobustmax)
|
|
2155
|
+
hfpulsatilitymap2 = 100.0 * np.max(hfnormapp, axis=3)
|
|
2156
|
+
hfrobustmax = tide_stats.getfracval(hfpulsatilitymap2, 0.98, nozero=True)
|
|
2157
|
+
hfpulsatilitymap2 = np.where(hfpulsatilitymap2 < hfrobustmax, hfpulsatilitymap2, hfrobustmax)
|
|
2158
|
+
|
|
2159
|
+
# make a vessel map
|
|
2160
|
+
if args.useoriginalvesselmethod:
|
|
2161
|
+
if args.unnormvesselmap:
|
|
2162
|
+
vesselmap = np.max(app, axis=3)
|
|
2163
|
+
else:
|
|
2164
|
+
# vesselmap = np.max(normapp, axis=3)
|
|
2165
|
+
vesselmap = np.where(hfpulsatilitymap > args.pulsatilitythreshold, 1.0, 0.0)
|
|
1618
2166
|
else:
|
|
1619
|
-
vesselmap =
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
2167
|
+
vesselmap = pulsatilitymask
|
|
2168
|
+
veinmap = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmap, 0.0)
|
|
2169
|
+
arterymap = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) < 0, vesselmap, 0.0)
|
|
2170
|
+
|
|
2171
|
+
# specify the 3D maps
|
|
2172
|
+
maplist = [
|
|
2173
|
+
(
|
|
2174
|
+
pulsatilitymap,
|
|
2175
|
+
"pulsatility",
|
|
2176
|
+
"map",
|
|
2177
|
+
"percent",
|
|
2178
|
+
"Cardiac pulsatility in percentage change relative to mean",
|
|
2179
|
+
),
|
|
2180
|
+
(
|
|
2181
|
+
pulsatilitymask,
|
|
2182
|
+
"pulsatility",
|
|
2183
|
+
"mask",
|
|
2184
|
+
None,
|
|
2185
|
+
"Valid cardiac pulsatility voxels",
|
|
2186
|
+
),
|
|
2187
|
+
(
|
|
2188
|
+
lfpulsatilitymap,
|
|
2189
|
+
"lfpulsatility",
|
|
2190
|
+
"map",
|
|
2191
|
+
"percent",
|
|
2192
|
+
"Low spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2193
|
+
),
|
|
2194
|
+
(
|
|
2195
|
+
hfpulsatilitymap,
|
|
2196
|
+
"hfpulsatility",
|
|
2197
|
+
"map",
|
|
2198
|
+
"percent",
|
|
2199
|
+
"High spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2200
|
+
),
|
|
2201
|
+
(
|
|
2202
|
+
lfpulsatilitymap2,
|
|
2203
|
+
"lfpulsatility2",
|
|
2204
|
+
"map",
|
|
2205
|
+
"percent",
|
|
2206
|
+
"Low spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2207
|
+
),
|
|
2208
|
+
(
|
|
2209
|
+
hfpulsatilitymap2,
|
|
2210
|
+
"hfpulsatility2",
|
|
2211
|
+
"map",
|
|
2212
|
+
"percent",
|
|
2213
|
+
"High spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2214
|
+
),
|
|
2215
|
+
(
|
|
2216
|
+
vesselmap,
|
|
2217
|
+
"vessels",
|
|
2218
|
+
"map",
|
|
2219
|
+
None,
|
|
2220
|
+
"Vessel voxels",
|
|
2221
|
+
),
|
|
2222
|
+
(
|
|
2223
|
+
arterymap,
|
|
2224
|
+
"arteries",
|
|
2225
|
+
"map",
|
|
2226
|
+
None,
|
|
2227
|
+
"Arterial voxels (maybe)",
|
|
2228
|
+
),
|
|
2229
|
+
(
|
|
2230
|
+
veinmap,
|
|
2231
|
+
"veins",
|
|
2232
|
+
"map",
|
|
2233
|
+
None,
|
|
2234
|
+
"Venous voxels (maybe)",
|
|
2235
|
+
),
|
|
2236
|
+
]
|
|
2237
|
+
# write the 3D maps
|
|
2238
|
+
tide_io.savemaplist(
|
|
2239
|
+
outputroot,
|
|
2240
|
+
maplist,
|
|
2241
|
+
None,
|
|
2242
|
+
(xsize, ysize, numslices),
|
|
1626
2243
|
theheader,
|
|
1627
|
-
|
|
2244
|
+
bidsdict,
|
|
2245
|
+
debug=args.debug,
|
|
1628
2246
|
)
|
|
1629
|
-
|
|
1630
|
-
|
|
2247
|
+
|
|
2248
|
+
# specify the 4D maps
|
|
2249
|
+
theheader = input_data.copyheader(
|
|
2250
|
+
numtimepoints=args.destpoints, tr=-np.pi, toffset=2.0 * np.pi / args.destpoints
|
|
2251
|
+
)
|
|
2252
|
+
maplist = [
|
|
2253
|
+
(
|
|
2254
|
+
lfnormapp,
|
|
2255
|
+
"lfnormapp",
|
|
2256
|
+
"info",
|
|
2257
|
+
"percent",
|
|
2258
|
+
"Low spatial frequency cardiac pulsatility waveform in percentage change relative to mean",
|
|
2259
|
+
),
|
|
2260
|
+
(
|
|
2261
|
+
hfnormapp,
|
|
2262
|
+
"hfnormapp",
|
|
2263
|
+
"info",
|
|
2264
|
+
"percent",
|
|
2265
|
+
"High spatial frequency cardiac pulsatility waveform in percentage change relative to mean",
|
|
2266
|
+
),
|
|
2267
|
+
]
|
|
2268
|
+
|
|
2269
|
+
# write the 4D maps
|
|
2270
|
+
tide_io.savemaplist(
|
|
2271
|
+
outputroot,
|
|
2272
|
+
maplist,
|
|
2273
|
+
None,
|
|
2274
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1631
2275
|
theheader,
|
|
1632
|
-
|
|
2276
|
+
bidsdict,
|
|
2277
|
+
debug=args.debug,
|
|
1633
2278
|
)
|
|
1634
2279
|
|
|
1635
2280
|
# now generate aliased cardiac signals and regress them out of the data
|
|
1636
|
-
if args.
|
|
2281
|
+
if args.dotemporalregression or args.dospatialregression:
|
|
1637
2282
|
# generate the signals
|
|
1638
2283
|
timings.append(["Cardiac signal regression started", time.time(), None, None])
|
|
1639
2284
|
tide_util.logmem("before cardiac regression")
|
|
1640
2285
|
print("Generating cardiac regressors")
|
|
1641
|
-
cardiacnoise = fmri_data
|
|
2286
|
+
cardiacnoise = np.zeros_like(fmri_data)
|
|
1642
2287
|
cardiacnoise_byslice = cardiacnoise.reshape((xsize * ysize, numslices, timepoints))
|
|
1643
|
-
phaseindices = (cardiacnoise
|
|
2288
|
+
phaseindices = np.zeros_like(cardiacnoise, np.int16)
|
|
1644
2289
|
phaseindices_byslice = phaseindices.reshape((xsize * ysize, numslices, timepoints))
|
|
1645
2290
|
for theslice in range(numslices):
|
|
1646
2291
|
print("Calculating cardiac noise for slice", theslice)
|
|
@@ -1652,39 +2297,91 @@ def happy_main(argparsingfunc):
|
|
|
1652
2297
|
cardiacnoise_byslice[validlocs, theslice, t] = rawapp_byslice[
|
|
1653
2298
|
validlocs, theslice, phaseindices_byslice[validlocs, theslice, t]
|
|
1654
2299
|
]
|
|
1655
|
-
theheader =
|
|
2300
|
+
theheader = input_data.copyheader()
|
|
1656
2301
|
timings.append(["Cardiac signal generated", time.time(), None, None])
|
|
1657
2302
|
if args.savecardiacnoise:
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
2303
|
+
maplist = [
|
|
2304
|
+
(
|
|
2305
|
+
cardiacnoise.reshape((xsize, ysize, numslices, timepoints)),
|
|
2306
|
+
"cardiacnoise",
|
|
2307
|
+
"info",
|
|
2308
|
+
None,
|
|
2309
|
+
"Calculated cardiac noise EVs",
|
|
2310
|
+
),
|
|
2311
|
+
(
|
|
2312
|
+
phaseindices.reshape((xsize, ysize, numslices, timepoints)),
|
|
2313
|
+
"phaseindices",
|
|
2314
|
+
"info",
|
|
2315
|
+
None,
|
|
2316
|
+
"Phase indices",
|
|
2317
|
+
),
|
|
2318
|
+
]
|
|
2319
|
+
tide_io.savemaplist(
|
|
2320
|
+
outputroot,
|
|
2321
|
+
maplist,
|
|
2322
|
+
None,
|
|
2323
|
+
(xsize, ysize, numslices, timepoints),
|
|
1667
2324
|
theheader,
|
|
1668
|
-
|
|
2325
|
+
bidsdict,
|
|
2326
|
+
debug=args.debug,
|
|
1669
2327
|
)
|
|
1670
2328
|
timings.append(["Cardiac signal saved", time.time(), None, None])
|
|
1671
2329
|
|
|
1672
2330
|
# now remove them
|
|
1673
2331
|
tide_util.logmem("before cardiac removal")
|
|
1674
2332
|
print("Removing cardiac signal with GLM")
|
|
1675
|
-
filtereddata = 0.0 * fmri_data
|
|
1676
2333
|
validlocs = np.where(mask > 0)[0]
|
|
1677
2334
|
numvalidspatiallocs = len(validlocs)
|
|
2335
|
+
if args.focaldebug:
|
|
2336
|
+
print(f"{numvalidspatiallocs=}, {fmri_data.shape=}")
|
|
2337
|
+
filtereddata, filtereddata_shm = tide_util.allocarray(
|
|
2338
|
+
fmri_data.shape,
|
|
2339
|
+
"float64",
|
|
2340
|
+
shared=infodict["sharedmem"],
|
|
2341
|
+
name=f"filtereddata_{infodict['pid']}",
|
|
2342
|
+
)
|
|
2343
|
+
datatoremove, datatoremove_shm = tide_util.allocarray(
|
|
2344
|
+
fmri_data.shape,
|
|
2345
|
+
"float64",
|
|
2346
|
+
shared=infodict["sharedmem"],
|
|
2347
|
+
name=f"datatoremove_{infodict['pid']}",
|
|
2348
|
+
)
|
|
1678
2349
|
threshval = 0.0
|
|
1679
|
-
if args.
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
2350
|
+
if args.dospatialregression:
|
|
2351
|
+
regressiontype = "spatial"
|
|
2352
|
+
meanvals, meanvals_shm = tide_util.allocarray(
|
|
2353
|
+
(timepoints),
|
|
2354
|
+
"float64",
|
|
2355
|
+
shared=infodict["sharedmem"],
|
|
2356
|
+
name=f"meanvals_{infodict['pid']}",
|
|
2357
|
+
)
|
|
2358
|
+
rvals, rvals_shm = tide_util.allocarray(
|
|
2359
|
+
(timepoints),
|
|
2360
|
+
"float64",
|
|
2361
|
+
shared=infodict["sharedmem"],
|
|
2362
|
+
name=f"rvals_{infodict['pid']}",
|
|
2363
|
+
)
|
|
2364
|
+
r2vals, r2vals_shm = tide_util.allocarray(
|
|
2365
|
+
(timepoints),
|
|
2366
|
+
"float64",
|
|
2367
|
+
shared=infodict["sharedmem"],
|
|
2368
|
+
name=f"r2vals_{infodict['pid']}",
|
|
2369
|
+
)
|
|
2370
|
+
fitcoffs, fitcoffs_shm = tide_util.allocarray(
|
|
2371
|
+
(timepoints),
|
|
2372
|
+
"float64",
|
|
2373
|
+
shared=infodict["sharedmem"],
|
|
2374
|
+
name=f"fitcoffs_{infodict['pid']}",
|
|
2375
|
+
)
|
|
2376
|
+
fitNorm, fitNorm_shm = tide_util.allocarray(
|
|
2377
|
+
(timepoints),
|
|
2378
|
+
"float64",
|
|
2379
|
+
shared=infodict["sharedmem"],
|
|
2380
|
+
name=f"fitNorm_{infodict['pid']}",
|
|
2381
|
+
)
|
|
2382
|
+
print("Running spatial regression on", timepoints, "timepoints")
|
|
2383
|
+
tide_util.disablemkl(args.nprocs)
|
|
2384
|
+
tide_linfitfiltpass.linfitfiltpass(
|
|
1688
2385
|
timepoints,
|
|
1689
2386
|
fmri_data[validlocs, :],
|
|
1690
2387
|
threshval,
|
|
@@ -1696,12 +2393,15 @@ def happy_main(argparsingfunc):
|
|
|
1696
2393
|
fitNorm,
|
|
1697
2394
|
datatoremove[validlocs, :],
|
|
1698
2395
|
filtereddata[validlocs, :],
|
|
1699
|
-
|
|
2396
|
+
chunksize=10,
|
|
1700
2397
|
procbyvoxel=False,
|
|
1701
2398
|
nprocs=args.nprocs,
|
|
1702
2399
|
)
|
|
1703
|
-
|
|
1704
|
-
|
|
2400
|
+
tide_util.enablemkl(args.mklthreads)
|
|
2401
|
+
datatoremove[validlocs, :] = np.multiply(cardiacnoise[validlocs, :], fitcoffs[None, :])
|
|
2402
|
+
print(f"{datatoremove.shape=}, {np.min(datatoremove)=}, {np.max(datatoremove)=}")
|
|
2403
|
+
print(f"{cardiacnoise.shape=}, {np.min(cardiacnoise)=}, {np.max(cardiacnoise)=}")
|
|
2404
|
+
print(f"{fitcoffs.shape=}, {np.min(fitcoffs)=}, {np.max(fitcoffs)=}")
|
|
1705
2405
|
filtereddata = fmri_data - datatoremove
|
|
1706
2406
|
timings.append(
|
|
1707
2407
|
[
|
|
@@ -1711,40 +2411,42 @@ def happy_main(argparsingfunc):
|
|
|
1711
2411
|
"timepoints",
|
|
1712
2412
|
]
|
|
1713
2413
|
)
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
theheader,
|
|
1723
|
-
cardfiltresultfilename,
|
|
2414
|
+
|
|
2415
|
+
if args.dotemporalregression:
|
|
2416
|
+
regressiontype = "temporal"
|
|
2417
|
+
meanvals, meanvals_shm = tide_util.allocarray(
|
|
2418
|
+
(numspatiallocs),
|
|
2419
|
+
"float64",
|
|
2420
|
+
shared=infodict["sharedmem"],
|
|
2421
|
+
name=f"meanvals_{infodict['pid']}",
|
|
1724
2422
|
)
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
2423
|
+
rvals, rvals_shm = tide_util.allocarray(
|
|
2424
|
+
(numspatiallocs),
|
|
2425
|
+
"float64",
|
|
2426
|
+
shared=infodict["sharedmem"],
|
|
2427
|
+
name=f"rvals_{infodict['pid']}",
|
|
1729
2428
|
)
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
None,
|
|
1736
|
-
]
|
|
2429
|
+
r2vals, r2vals_shm = tide_util.allocarray(
|
|
2430
|
+
(numspatiallocs),
|
|
2431
|
+
"float64",
|
|
2432
|
+
shared=infodict["sharedmem"],
|
|
2433
|
+
name=f"r2vals_{infodict['pid']}",
|
|
1737
2434
|
)
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
fitNorm =
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2435
|
+
fitcoffs, fitcoffs_shm = tide_util.allocarray(
|
|
2436
|
+
(numspatiallocs),
|
|
2437
|
+
"float64",
|
|
2438
|
+
shared=infodict["sharedmem"],
|
|
2439
|
+
name=f"fitcoffs_{infodict['pid']}",
|
|
2440
|
+
)
|
|
2441
|
+
fitNorm, fitNorm_shm = tide_util.allocarray(
|
|
2442
|
+
(numspatiallocs),
|
|
2443
|
+
"float64",
|
|
2444
|
+
shared=infodict["sharedmem"],
|
|
2445
|
+
name=f"fitNorm_{infodict['pid']}",
|
|
2446
|
+
)
|
|
2447
|
+
print("Running temporal regression on", numvalidspatiallocs, "voxels")
|
|
2448
|
+
tide_util.disablemkl(args.nprocs)
|
|
2449
|
+
tide_linfitfiltpass.linfitfiltpass(
|
|
1748
2450
|
numvalidspatiallocs,
|
|
1749
2451
|
fmri_data[validlocs, :],
|
|
1750
2452
|
threshval,
|
|
@@ -1758,10 +2460,15 @@ def happy_main(argparsingfunc):
|
|
|
1758
2460
|
filtereddata[validlocs, :],
|
|
1759
2461
|
procbyvoxel=True,
|
|
1760
2462
|
nprocs=args.nprocs,
|
|
2463
|
+
debug=args.focaldebug,
|
|
1761
2464
|
)
|
|
2465
|
+
tide_util.enablemkl(args.mklthreads)
|
|
1762
2466
|
datatoremove[validlocs, :] = np.multiply(
|
|
1763
2467
|
cardiacnoise[validlocs, :], fitcoffs[validlocs, None]
|
|
1764
2468
|
)
|
|
2469
|
+
print(f"{datatoremove.shape=}, {np.min(datatoremove)=}, {np.max(datatoremove)=}")
|
|
2470
|
+
print(f"{cardiacnoise.shape=}, {np.min(cardiacnoise)=}, {np.max(cardiacnoise)=}")
|
|
2471
|
+
print(f"{fitcoffs.shape=}, {np.min(fitcoffs)=}, {np.max(fitcoffs)=}")
|
|
1765
2472
|
filtereddata[validlocs, :] = fmri_data[validlocs, :] - datatoremove[validlocs, :]
|
|
1766
2473
|
timings.append(
|
|
1767
2474
|
[
|
|
@@ -1771,49 +2478,92 @@ def happy_main(argparsingfunc):
|
|
|
1771
2478
|
"voxels",
|
|
1772
2479
|
]
|
|
1773
2480
|
)
|
|
1774
|
-
theheader =
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
2481
|
+
theheader = input_data.copyheader(numtimepoints=1)
|
|
2482
|
+
maplist = [
|
|
2483
|
+
(
|
|
2484
|
+
fitcoffs.reshape((xsize, ysize, numslices)),
|
|
2485
|
+
"cardfiltCoeffs",
|
|
2486
|
+
"map",
|
|
2487
|
+
None,
|
|
2488
|
+
"Coefficients for temporal cardiac noise regression",
|
|
2489
|
+
),
|
|
2490
|
+
(
|
|
2491
|
+
meanvals.reshape((xsize, ysize, numslices)),
|
|
2492
|
+
"cardfiltMean",
|
|
2493
|
+
"map",
|
|
2494
|
+
None,
|
|
2495
|
+
"Mean values after temporal cardiac noise regression",
|
|
2496
|
+
),
|
|
2497
|
+
(
|
|
2498
|
+
rvals.reshape((xsize, ysize, numslices)),
|
|
2499
|
+
"cardfiltR",
|
|
2500
|
+
"map",
|
|
2501
|
+
None,
|
|
2502
|
+
"R values for temporal cardiac noise regression",
|
|
2503
|
+
),
|
|
2504
|
+
]
|
|
2505
|
+
tide_io.savemaplist(
|
|
2506
|
+
outputroot,
|
|
2507
|
+
maplist,
|
|
2508
|
+
None,
|
|
2509
|
+
(xsize, ysize, numslices),
|
|
1786
2510
|
theheader,
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
tide_io.savetonifti(
|
|
1790
|
-
rvals.reshape((xsize, ysize, numslices)), theheader, cardfiltRfilename
|
|
2511
|
+
bidsdict,
|
|
2512
|
+
debug=args.debug,
|
|
1791
2513
|
)
|
|
1792
2514
|
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
2515
|
+
# now write out the filtered data
|
|
2516
|
+
theheader = input_data.copyheader()
|
|
2517
|
+
maplist = [
|
|
2518
|
+
(
|
|
1797
2519
|
filtereddata.reshape((xsize, ysize, numslices, timepoints)),
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
2520
|
+
"cardfiltResult",
|
|
2521
|
+
"bold",
|
|
2522
|
+
None,
|
|
2523
|
+
f"Cardiac filtered BOLD data after {regressiontype} regression",
|
|
2524
|
+
),
|
|
2525
|
+
(
|
|
1802
2526
|
datatoremove.reshape((xsize, ysize, numslices, timepoints)),
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
)
|
|
2527
|
+
"cardfiltRemoved",
|
|
2528
|
+
"bold",
|
|
2529
|
+
None,
|
|
2530
|
+
f"Cardiac noise removed with {regressiontype} regression",
|
|
2531
|
+
),
|
|
2532
|
+
]
|
|
2533
|
+
tide_io.savemaplist(
|
|
2534
|
+
outputroot,
|
|
2535
|
+
maplist,
|
|
2536
|
+
None,
|
|
2537
|
+
(xsize, ysize, numslices, timepoints),
|
|
2538
|
+
theheader,
|
|
2539
|
+
bidsdict,
|
|
2540
|
+
debug=args.debug,
|
|
2541
|
+
)
|
|
2542
|
+
timings.append(
|
|
2543
|
+
[
|
|
2544
|
+
f"Cardiac signal {regressiontype} regression files written",
|
|
2545
|
+
time.time(),
|
|
2546
|
+
None,
|
|
2547
|
+
None,
|
|
2548
|
+
]
|
|
2549
|
+
)
|
|
2550
|
+
|
|
2551
|
+
# clean up shared memory, if using
|
|
2552
|
+
if args.dotemporalregression or args.dospatialregression:
|
|
2553
|
+
if infodict["sharedmem"]:
|
|
2554
|
+
tide_util.cleanup_shm(filtereddata_shm)
|
|
2555
|
+
tide_util.cleanup_shm(datatoremove_shm)
|
|
2556
|
+
tide_util.cleanup_shm(meanvals_shm)
|
|
2557
|
+
tide_util.cleanup_shm(rvals_shm)
|
|
2558
|
+
tide_util.cleanup_shm(r2vals_shm)
|
|
2559
|
+
tide_util.cleanup_shm(fitcoffs_shm)
|
|
2560
|
+
tide_util.cleanup_shm(fitNorm_shm)
|
|
1814
2561
|
|
|
1815
2562
|
timings.append(["Done", time.time(), None, None])
|
|
1816
2563
|
|
|
2564
|
+
# save pyfftw wisdom
|
|
2565
|
+
tide_util.savewisdom(args.pyfftw_wisdom)
|
|
2566
|
+
|
|
1817
2567
|
# Process and save timing information
|
|
1818
2568
|
nodeline = "Processed on " + platform.node()
|
|
1819
2569
|
tide_util.proctiminginfo(
|
|
@@ -1821,3 +2571,15 @@ def happy_main(argparsingfunc):
|
|
|
1821
2571
|
)
|
|
1822
2572
|
|
|
1823
2573
|
tide_util.logmem("final")
|
|
2574
|
+
|
|
2575
|
+
# save the information file
|
|
2576
|
+
if args.saveinfoasjson:
|
|
2577
|
+
tide_io.writedicttojson(infodict, outputroot + "_desc-runinfo.json")
|
|
2578
|
+
else:
|
|
2579
|
+
tide_io.writedict(infodict, outputroot + "_info.txt")
|
|
2580
|
+
|
|
2581
|
+
# delete the canary file
|
|
2582
|
+
Path(f"{outputroot}_ISRUNNING.txt").unlink()
|
|
2583
|
+
|
|
2584
|
+
# create the finished file
|
|
2585
|
+
Path(f"{outputroot}_DONE.txt").touch()
|