#!/usr/bin/env tcsh @global_parse `basename $0` "$*" ; if ($status) exit 0 # Nomenclature note. We have multiple spaces, with the following abbrevs: # + orig : original input dset space # + osh : shifted version of original dset (by @Align_Centers) # + aff : affine-aligned version of original dset (by align_epi_anat.py) # + base : 'template' space, and/or NL warped version of original dset # On a historical note, this script is derived from macaque_align.csh # and NMT_subject_align.csh, scripts distributed with the D99 macaque # and the NMT macaque template datasets and tools. # affine alignment of individual dataset to a template # handcrafted for macaque alignment originally - D99 and NMT templates # usage example: # @animal_warper -input macaque1+orig \ # -base ../NMT.nii.gz \ # -atlas ${atlas_dir}/D99_atlas_1.2a_al2NMT.nii.gz # see help section at end for options # derived from macaque_align.csh and NMT_align.csh, scripts distributed # with the D99 macaque and the NMT macaque template datasets and tools set progname = @animal_warper # --------------------- version history with changes ----------------------- # #set version = "1.00" # #set version = "1.02" ; set date = "Sep 3, 2019" # [PT] Adding in @chauffeur_afni commands for visualization # + snapshots commented out # + cp -> \cp, etc. # #set version = "1.1" ; set date = "Sep 3, 2019" # [PT] Make a "no skull" version of the orig dset # + another QC image: skull stripped area # #set version = "1.2" ; set date = "Sep 5, 2019" # [PT] change smoothing of SUMA stuff, preserve ROIs more # + trivial stuff: change spacing / break lines for readability (sorry!) # #set version = "1.3" ; set date = "Sep 6, 2019" # [PT] QC order rearranged a bit; change names; more useful focus (foci) # + QC to sep dir, called QC # #set version = "1.4" ; set date = "Sep 6, 2019" # [PT] output dset that is wrpd2std, and skullstrip it with template # -> this is what would be useful to pass to AP # #set version = "1.5" ; set date = "Sep 10, 2019" # [PT] unifize skullstripped template in standard template space # + describe QC images in help file, for reference # + remove __tmp* dset-- hadn't noticed COMPRESSOR was ON # #set version = "1.6" ; set date = "Sep 11, 2019" # [DRG] remove temporary datasets with option to keep temporary datasets # + identify important output # + some help updates # #set version = "1.7" ; set date = "Sep 24, 2019" # [DRG] fullpath for input datasets determined even if specified as ., .., ~ # #set version = "1.71" ; set date = "Oct 3, 2019" # [PT] Adjust 3dNotes to include @animal_warper name # + this goes with adjusting gen_ss_review_table.py so it recognizes # and reads in the template name # + make $animal_outs almost lined up? # #set version = "1.72" ; set date = "Oct 7, 2019" # [PT] $animal_outs descriptors more consistent # + add in prog version numbers to animal_outs scripts # + goes with change in afni.c to have simpler AFNI version # number/package # + help now exits with 0 # #set version = "1.73" ; set date = "Jan 14, 2020" # [PT] update text output in @animal_outs a bit # #set version = "1.74" ; set date = "Feb 14, 2020" # [DRG] dset_followers to allow for similar space datasets to follow # into template space. Uses Align_Centers 1D dataset for initial # shifts #set version = "1.75" ; set date = "Feb 26, 2020" # [DRG] roidset_followers to allow for similar space datasets to follow # into template space with nearest neighbor interpolation # +modal smoothing. #set version = "1.76" ; set date = "Mar 22, 2020" # [DRG] fixed stupid bug, space in feature_size option for aea.py #set version = "1.77" ; set date = "Mar 26, 2020" # [DRG] changed center shift defaults and help for dealing with shifts # concatenating shift with affine alignment by default option # #set version = "1.78" ; set date = "Mar 29, 2020" # [BTJ] added template mask-based brainmasking # maxlev defaults to 9 for some increase in speed # #set version = "1.8" ; set date = "Apr 27, 2020" # [PT] add help file example of integrating with afni_proc.py # + particularly important now to get correct aff12 mat # #set version = "1.81" ; set date = "May 14, 2020" # [PT] change spacing and printing for ease of reading # + remove '-segmentation' opt, which didn't appear to do anything # + clean up comments # + introduce 'adjunct_simplify_cost.py' to get rid of +ZZ, +zz and + # #set version = "1.82" ; set date = "May 14, 2020" # [PT] more readability changes # #set version = "1.83" ; set date = "May 14, 2020" # [PT] more readability changes # #set version = "1.9" ; set date = "May 14, 2020" # [PT] make '-atlas ..' accept a list of dsets # + new opt "-atlas_followers .." to have same behavior as '-atlas ..' # #set version = "1.91" ; set date = "May 15, 2020" # [PT] continuing lots of updates, rearrangements, labelings # #set version = "1.92" ; set date = "May 15, 2020" # [PT] shifts done more similarly # + surfacizing # #set version = "1.93" ; set date = "May 15, 2020" # [PT] changing the way output atlas names and template abbrevs are done # + simplify help parsing for reporting missing params for opts # #set version = "1.94" ; set date = "May 16, 2020" # [PT] simplify what to do with existing animal_outs.txt: # + just make copy/backup # #set version = "1.95" ; set date = "May 16, 2020" # [PT] base2osh, osh2base nomenclature # + backup notice of prior/backup animal_outs.txt # + reordered calcs, so animal_outs is more logically ordered, too # + for each follower, now there is an optional abbrev list # + update 3dUnifize to be more like @SSwarper's # #set version = "1.96" ; set date = "May 17, 2020" # [PT] finally doing abbrevs # + abbrevs will be lists, and treated analogously for all # followers, to hopefully make code logic easier, by being # consistent and sorted out in a single place. HOPEFULLY. # #set version = "1.97" ; set date = "May 17, 2020" # [PT] use more consistent naming, bc otherwise 'template' and 'dset' # refer to many things-- both the required inputs, as well as # follower types # + all '-base BASE' references -> "${base_dset}" # + all '-input DSET' references -> "${src_dset0}" original/uncopied # "${src_dset}" copied into outdir # + all shifted src references -> "${srcsh_dset}" # + as observable from above got rid of renaming of: # set dset = ${dset}_shft # - as part of this, don't need separate 'finalmaster' anymore # #set version = "1.97" ; set date = "May 17, 2020" # [PT] do*.tcsh script to open surfaces in SUMA # + fix cleanup 'rm ..' commands # #set version = "1.98" ; set date = "May 17, 2020" # [PT] completed testing with multiple inputs/etc. # + updated help file # #set version = "1.99" ; set date = "May 18, 2020" # [PT] create skullstripped+unifized dset in orig space # #set version = "2.0" ; set date = "May 18, 2020" # [PT] final adjustments # #set version = "2.01" ; set date = "May 19, 2020" # [PT] use NSU in do_view_${surf_dir}.tcsh # #set version = "2.1" ; set date = "May 19, 2020" # [PT] new adjunct* functionality: create table of ROI info # + done using: adjunct_aw_tableize_roi_info.py # - someday, might make this program more 'standalone' with real opts # #set version = "2.11" ; set date = "May 21, 2020" # [PT] report mode_smooth_size in report*1D file # #set version = "2.2" ; set date = "May 30, 2020" # [PT] # + modal smoothing with replacement, now default; is new opt to turn off # + now, for multibrick ATL|SEG dsets, each subbrick will be snapshotted # for QC dir # #set version = "2.21" ; set date = "May 30, 2020" # [PT] # + change how input_abbrev gets applied-- will apply to copying # and earliest transformed input/src dsets now, for # simplicity/ease of reading if user is defining an inp abbr # #set version = "2.3" ; set date = "May 31, 2020" # [PT] 2 bug fixes # + one in defining ${src_prefix} (reorder to not have error) # + one in passing along labels/atlases from SEG|atlas dsets # #set version = "2.4" ; set date = "Jul 10, 2020" # [DRG] # + changed default mode_smooth_size to 1 voxel # #set version = "2.41" ; set date = "Aug 26, 2020" # [PT] fix location of jump-to-help when no args are input # + was getting error message, because ${outdir} needed to be def # #set version = "2.5" ; set date = "Aug 26, 2020" # [PT] add opts to turn @Align_Centers OFF or to use # "-cm", etc. # #set version = "2.51" ; set date = "Aug 27, 2020" # [PT] put specific space name for *base2osh* and *osh2base* dsets # #set version = "2.6" ; set date = "Aug 27, 2020" # [PT] put in 2nd shift-- well, it is a rearrangement: we combine the # @Align_Centers shift with the translation part of 3dAllineate # + and debugged a bit-- seems to run fine now # + NOTE: the shifts from @Align_Centers now go with the "*_pshft*" # files, and the "full" shift from combining the @Align_Center # work with the translation from align_epi_anat.py are the # "*_shft*" datasets, so there should be full continuity with the # help files and with the reported afni_proc.py usage. # #set version = "2.7" ; set date = "Oct 16, 2020" # [PT] instead of early 3dcalc of src_dset0 to start things off, use # 3dresample there; with the concatenation of translations # (pshft+shft), we want to have (x,y,z) ordering of coords for the src # dset, and this ensures it. Otherwise, get badness of something with # orient RSP, AIL, etc. is entered. # #set version = "2.8" ; set date = "Oct 16, 2020" # [PT] add status checks around, to stop in case of intermediate # failure # #set version = "2.9" ; set date = "Oct 16, 2020" # [PT] Phase I of restructuring output and simplifying output dir # + reports*.1D -> QC/ # + surface_* -> surfaces/ # + do_view*.tcsh -> surfaces/ # + animal_outs*txt is updated accordingly # ---> many thanks to B Jung for guidance+suggestions on this! # #set version = "2.91" ; set date = "Oct 16, 2020" # [PT] Phase II of restructuring output and simplifying output dir # + runs through "affine" part at the moment-- need to keep # adjusting files afterward to continue consistency # ---> many thanks to B Jung for guidance+suggestions on this! # #set version = "2.92" ; set date = "Oct 19, 2020" # [PT] Phase III of restructuring output and simplifying output dir # ---> STILL many thanks to B Jung for guidance+suggestions on this! # #set version = "2.93" ; set date = "Oct 19, 2020" # [PT] verifying/testing in Mac demos # #set version = "3.0" ; set date = "Oct 19, 2020" # [PT] updating help file -- more useful? # #set version = "3.01" ; set date = "Oct 19, 2020" # [PT] new "pre"-QC: check src-base overlap: @djunct_overlap_check # #set version = "3.1" ; set date = "Dec 22, 2020" # [PT] new feature size default: 0.5 (old default: empty) # #set version = "3.2" ; set date = "Feb 3, 2021" # [PT] add snapshot of aff, intermed qc # + pass along set echo to at least some subscript(s) # #set version = "3.3" ; set date = "Feb 25, 2021" # [PT] the rigid, rigid_equiv and affine align_types now go all the # way through the full processing, warping dsets, etc. This # functionality changed for Adam Messinger. # + NL alignment is unchanged # + record align_type in animal_outs.txt # + fixed bug in 3drefitting a 'dset_follower' as if it were int-valued # #set version = "3.31" ; set date = "Mar 1, 2021" # [PT] fix location of affine align init*jpg # #set version = "3.32" ; set date = "Apr 6, 2021" # [something lost in the mists of time. or github] # #set version = "3.33" ; set date = "May 17, 2021" # [DRG] fix oneline output for rigid_equiv matrix # #set version = "3.34" ; set date = "May 20, 2021" # [PT] update help examples and citations # + add in more init_qc* images to track progress @djunct_overlap_check # + change dset used to mask warp2std_ns dset---thanks, A Messinger! # + dump out a log_cmd.txt file immediately, in case of crash # #set version = "3.35" ; set date = "May 21, 2021" # [PT] new animal_ints file (guide to intermediate files, sep from main one) # - gets made in ${imed} dir # + myriad small description changes in animal_outs, to simplify or # clarify (ha, right!) # #set version = "3.36" ; set date = "May 21, 2021" # [PT] update init_qc* filenames, simplify, and put help desc # + ... and fix output location # + use log to record time info of start/stop # #set version = "3.37" ; set date = "May 24, 2021" # [PT] lower opacity in overlap check # #set version = "3.38" ; set date = "July 9, 2021" # [PT] Couple useful things: # + new '-aff_move_opt ..' opt: control affine align behavior # - necessary if coords are good and there is a lot of non-brain # in FOV # - NB: all aff output dsets will be on BASE grid, too. # + fix bug: if no followers used, no 'surfaces/' dir was created # for orig surface brain. Now OK. # #set version = "3.39"; set rev_dat = "Sep 27, 2021" # + [PT] chauffeur label_size 3 -> 4, bc imseq.c shifted all sizes # down one level # #set version = "3.40"; set rev_dat = "Oct 21, 2021" # + [PT] help examples were missing "-outdir .." arg. Now provided # #set version = "3.41"; set rev_dat = "Oct 23, 2021" # + [PT] make ROI_glasbey_2048 the colorbar for @chauffeur_afni # ROI images # + CHARM requires something >256, and other ones will, too # #set version = "3.5"; set rev_dat = "Oct 24, 2021" # + [PT] improve QC outputs # - use @djunct_edgy_olay to show alignment quality for qc_0{0,1}* # - improve/simplify/separate naming structure of QC images # - remove unnecessary pbar output for mask olay # - add src_abbrev to output QC names, if present, kind of like # having ${subj} (which we don't have available as input) # - make variable names for QC prefixes at top, so the help # automatically reflects them # - make glasbey_ROIs a bit more opaque (hard to see otherwise) # #set version = "3.51"; set rev_dat = "Oct 24, 2021" # + [PT] fix some chauffeur ranges # + change Urad in 3dUnifize to 14, from 30 (latter seems # waaaay too large for most animal dsets?) # #set version = "3.52"; set rev_dat = "Oct 27, 2021" # + [PT] fix desc of opt name "-qw_opts" in help to what it actually is: # "-extra_qw_opts". Thanks, C Garin. # #set version = "3.6"; set rev_dat = "Dec 1, 2022" # + [PT] new opt '-init_scale ..' for pre-scaling input anatomical if # it is much smaller/larger than the template (applied in AEA) # #set version = "3.61"; set rev_dat = "Dec 2, 2022" # + [PT] add QC image when using '-init_scale ..' # set version = "4.00"; set rev_dat = "Aug 6, 2024" # + [PT, DRG] fix application of shift shifting. # # -------------------------------------------------------------------- # -------------------------------------------------------------------- setenv AFNI_COMPRESSOR GZIP set here = "${PWD}" set src_dset0 = "" # actual input set src_dset = "" # copied src in outdir; used in proc set base_dset = "" set src_abbrev = "" set src_add = "" set base_abbrev = "" set USE_KNOWN_BASE_ABBREV = 0 # will use ${all_known_template_abbrev} set outdir = "aw_results" set imed = "intermediate" # intermed files; ~purgeable set center_out = "native" set brainmask = "" set cost = "" set maxlev = "09" set make_orig_surfaces = "1" set align_type = "all" set ok_to_exist = "0" set extra_qw_opts = "" set aff_move = "-giant_move" # one-to-one correspondence between followers and abbrevs set atlas_followers = () ; set atlas_abbrevs = () set template_followers = () ; set template_abbrevs = () set seg_followers = () ; set seg_abbrevs = () set dset_followers = () ; set dset_abbrevs = () set roidset_followers = () ; set roidset_abbrevs = () # these start in base space set USE_KNOWN_ATLAS_ABBREV = 0 set all_known_atlas_abbrev = ( "D99" "CHARM" ) set USE_KNOWN_TEMPLATE_ABBREV = 0 set all_known_template_abbrev = ( "NMT" ) set USE_KNOWN_SEG_ABBREV = 0 set all_known_seg_abbrev = ( ) # these start in input dset space set USE_KNOWN_ROIDSET_ABBREV = 0 set all_known_roidset_abbrev = ( ) set USE_KNOWN_DSET_ABBREV = 0 set all_known_dset_abbrev = ( ) set DO_ALIGN_CENTERS = 1 set align_centers_meth = "-grid" set DO_INIT_SCALE = 0 # [PT: Dec 1, 2022] overcome size mismatch set init_scale = 1.0 set opt_init_scale = "" set feature_size = "0.5" # [PT: Dec 22, 2020] new default set feature_option = "-feature_size $feature_size" set modesmooth = "1" # 1 voxel modal smoothing set DO_MODE_SMOO_W_REP = 1 # use modal smoothing with rep (def) set supersize = "" set keep_temp = "" set animal_outs = "animal_outs.txt" # recreated, even with exist set animal_ints = "${imed}/guide_to_ints.txt" # guide to intermediate set backup_ao = "" set DO_ECHO = "" # put all QC/ image prefixes here, so we refer more easily to them in help set iqc00 = init_qc_00.input+base set iqc01 = init_qc_01.input_sh+base set iqc01b = init_qc_01.input_sh_scale+base # if init scaling is used set iqc02 = init_qc_02.input_aff+base set iqc03 = init_qc_03.input_NL+base set qc00 = qc_00.wrpd_input+base set qc01 = qc_01.input+wrpd_base set qc02 = qc_02.input+mask set qc03 = qc_03.input+wrpd # ------------------------ process user options -------------------------- # [PT: Oct 7, 2019] changed condition from ("$#" < "2"), so that args # get parsed and we can still get at script version number # [PT: Aug 26, 2020] moved this here, because it needs to be after # ${outdir} is defined, or an error is caused when trying to show help if ("$#" < "1") then goto HELP endif set ac = 1 while ($ac <= $#argv) if ("$argv[$ac]" == "-help" || "$argv[$ac]" == "-h") then goto HELP else if ("$argv[$ac]" == "-ver") then echo $version exit 0 # ------------------- else if ( "$argv[$ac]" == "-echo" ) then set echo set DO_ECHO = "-echo" else if ("$argv[$ac]" == "-input") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set src_dset0 = $argv[$ac] # User can specify simpler name for this dset for output fnames else if ("$argv[$ac]" == "-input_abbrev") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set src_abbrev = $argv[$ac] else if ("$argv[$ac]" == "-base") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set base_dset = $argv[$ac] # User can specify simpler name for this dset for output fnames else if ("$argv[$ac]" == "-base_abbrev") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set base_abbrev = $argv[$ac] else if ("$argv[$ac]" == "-outdir") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set outdir = $argv[$ac] else if ("$argv[$ac]" == "-cost") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set cost = $argv[$ac] #### [PT: May 17, 2020] remove for '-abbrev_base'-- matches other #### input names/opts better #else if ("$argv[$ac]" == "-template_prefix") then # set this_opt = "$argv[$ac]" # @ ac ++ # if ( $ac > $#argv ) then # echo "** missing parameter for option '${this_opt}'" # exit 1 # endif # set templatename = $argv[$ac] else if ("$argv[$ac]" == "-use_known_abbrev_base") then set USE_KNOWN_BASE_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_atlas") then set USE_KNOWN_ATLAS_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_template") then set USE_KNOWN_TEMPLATE_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_seg") then set USE_KNOWN_SEG_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_dset") then set USE_KNOWN_DSET_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_roidset") then set USE_KNOWN_ROIDSET_ABBREV = 1 else if ("$argv[$ac]" == "-use_known_abbrev_ALL") then set USE_KNOWN_BASE_ABBREV = 1 set USE_KNOWN_ATLAS_ABBREV = 1 set USE_KNOWN_TEMPLATE_ABBREV = 1 set USE_KNOWN_SEG_ABBREV = 1 set USE_KNOWN_DSET_ABBREV = 1 set USE_KNOWN_ROIDSET_ABBREV = 1 else if ("$argv[$ac]" == "-align_centers_meth") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set ac_opt = "$argv[$ac]" if ( "${ac_opt}" == "OFF" ) then set DO_ALIGN_CENTERS = 0 else set align_centers_meth = "-${ac_opt}" if ( "${ac_opt}" == "shift_xform" || \ "${ac_opt}" == "shift_xform_inv" ) then @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" echo " because you need another arg after '${ac_opt}'" exit 1 endif set align_centers_meth = "${align_centers_meth} $argv[$ac]" endif endif # [PT: July 8, 2021] be able to control main affine opts for move else if ("$argv[$ac]" == "-aff_move_opt") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set aaa = "$argv[$ac]" if ( "${aaa}" == "OFF" ) then set aff_move = "" else set aff_move = "-${aaa}" endif else if ("$argv[$ac]" == "-skullstrip") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set brainmask = $argv[$ac] else if ("$argv[$ac]" == "-maxlev") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set maxlev = $argv[$ac] else if ("$argv[$ac]" == "-init_scale") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set init_scale = $argv[$ac] set DO_INIT_SCALE = 1 else if ("$argv[$ac]" == "-align_type") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set align_type = $argv[$ac] if (( "$align_type" == "all" ) || \ ( "$align_type" == "rigid" ) || \ ( "$align_type" == "rigid_equiv" ) || \ ( "$align_type" == "affine" )) then echo "align_type set to $align_type" else echo "align_type $align_type is not a valid choice" exit 1 endif else if ("$argv[$ac]" == "-extra_qw_opts") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set extra_qw_opts = ($extra_qw_opts $argv[$ac] ) echo "extra_qw_opts is set to "$extra_qw_opts else if ("$argv[$ac]" == "-center_out") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set center_out = "$argv[$ac]" if (( "${center_out}" == "native") || \ ( "${center_out}" == "center_shift")) then echo "++ The center_out is set to: $center_out" else echo "** ERROR: center_out '$center_out' is not a valid choice" echo " please choose native or center_shift" exit 1 endif else if ("$argv[$ac]" == "-ok_to_exist") then set ok_to_exist = "1" else if ("$argv[$ac]" == "-no_surfaces") then set make_orig_surfaces = "0" # [PT: May 14, 2020] else if ( ("$argv[$ac]" == "-atlas") || \ ("$argv[$ac]" == "-atlas_followers") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) # go until an option starting with a hyphen appears set poss_dset = `echo $argv[$ac] | grep -- "^-"` # if hyphenated, grep returns same arg -> are at new opt if ("$argv[$ac]" == "$poss_dset") then break # not a hyphen leading option, should be dataset else set atlfollow = $argv[$ac] # is the dataset somewhere else or current directory set atlfollow = `@FindAfniDsetPath -append_file \ -full_path $atlfollow` # add the dataset to the segmentation follower list set atlas_followers = ($atlas_followers $atlfollow) endif @ ac ++ end if ( $#atlas_followers == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ( ("$argv[$ac]" == "-atlas_abbrevs") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) set poss_dset = `echo $argv[$ac] | grep -- "^-"` if ("$argv[$ac]" == "$poss_dset") then break else set atlas_abbrevs = ( $atlas_abbrevs "$argv[$ac]" ) endif @ ac ++ end if ( $#atlas_abbrevs == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ("$argv[$ac]" == "-template_followers") then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) # go until an option starting with a hyphen appears set poss_dset = `echo $argv[$ac] | grep -- "^-"` # if hyphenated, grep returns same arg -> are at new opt if ("$argv[$ac]" == "$poss_dset") then break # not a hyphen leading option, should be dataset else set tempfollow = $argv[$ac] # is the dataset somewhere else or current directory set tempfollow = `@FindAfniDsetPath -append_file \ -full_path $tempfollow` # add the dataset to the template follower list set template_followers = ($template_followers $tempfollow) endif @ ac ++ end if ( "$#template_followers" == "0" ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ( ("$argv[$ac]" == "-template_abbrevs") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) set poss_dset = `echo $argv[$ac] | grep -- "^-"` if ("$argv[$ac]" == "$poss_dset") then break else set template_abbrevs = ( $template_abbrevs "$argv[$ac]" ) endif @ ac ++ end if ( $#template_abbrevs == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ("$argv[$ac]" == "-seg_followers") then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) # go until an option starting with a hyphen appears set poss_dset = `echo $argv[$ac] | grep -- "^-"` # if hyphenated, grep returns same arg -> are at new opt if ("$argv[$ac]" == "$poss_dset") then break # not a hyphen leading option, should be dataset else set segfollow = $argv[$ac] # is the dataset somewhere else or current directory set segfollow = `@FindAfniDsetPath -append_file \ -full_path $segfollow` # add the dataset to the segmentation follower list set seg_followers = ($seg_followers $segfollow) endif @ ac ++ end if ( $#seg_followers == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ( ("$argv[$ac]" == "-seg_abbrevs") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) set poss_dset = `echo $argv[$ac] | grep -- "^-"` if ("$argv[$ac]" == "$poss_dset") then break else set seg_abbrevs = ( $seg_abbrevs "$argv[$ac]" ) endif @ ac ++ end if ( $#seg_abbrevs == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ("$argv[$ac]" == "-dset_followers") then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) # go until an option starting with a hyphen appears set poss_dset = `echo $argv[$ac] | grep -- "^-"` # if hyphenated, grep returns same arg -> are at new opt if ("$argv[$ac]" == "$poss_dset") then break # not a hyphen leading option, should be dataset else set dsetfollow = $argv[$ac] # is the dataset somewhere else or current directory set dsetfollow = `@FindAfniDsetPath -append_file \ -full_path $dsetfollow` # add the dataset to the template follower list set dset_followers = ($dset_followers $dsetfollow) endif @ ac ++ end if ( "$#dset_followers" == "0" ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ( ("$argv[$ac]" == "-dset_abbrevs") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) set poss_dset = `echo $argv[$ac] | grep -- "^-"` if ("$argv[$ac]" == "$poss_dset") then break else set dset_abbrevs = ( $dset_abbrevs "$argv[$ac]" ) endif @ ac ++ end if ( $#dset_abbrevs == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ("$argv[$ac]" == "-roidset_followers") then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) # go until an option starting with a hyphen appears set poss_dset = `echo $argv[$ac] | grep -- "^-"` # if hyphenated, grep returns same arg -> are at new opt if ("$argv[$ac]" == "$poss_dset") then break # not a hyphen leading option, should be dataset else set dsetfollow = $argv[$ac] # is the dataset somewhere else or current directory set dsetfollow = `@FindAfniDsetPath -append_file \ -full_path $dsetfollow` # add the dataset to the template follower list set roidset_followers = ($roidset_followers $dsetfollow) endif @ ac ++ end if ( "$#roidset_followers" == "0" ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ( ("$argv[$ac]" == "-roidset_abbrevs") ) then set this_opt = "$argv[$ac]" @ ac ++ while ($ac <= $#argv) set poss_dset = `echo $argv[$ac] | grep -- "^-"` if ("$argv[$ac]" == "$poss_dset") then break else set roidset_abbrevs = ( $roidset_abbrevs "$argv[$ac]" ) endif @ ac ++ end if ( $#roidset_abbrevs == 0 ) then echo "** missing dataset for option '${this_opt}'" exit 1 endif @ ac -- else if ("$argv[$ac]" == "-feature_size") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set feature_size = $argv[$ac] set feature_option = "-feature_size $feature_size" else if ("$argv[$ac]" == "-mode_smooth_size") then set this_opt = "$argv[$ac]" @ ac ++ if ( $ac > $#argv ) then echo "** missing parameter for option '${this_opt}'" exit 1 endif set modesmooth = $argv[$ac] set modesmooth = `ccalc -int -expr "$modesmooth"` if ("$status" != "0") then echo "mode_smooth_size set to $argv[$ac] is not valid" echo "Please use a number to specify how many voxels" exit 1 endif # [PT: May 30, 2020] turn off replacement of lost ROIs in modal smooth else if ("$argv[$ac]" == "-mode_smooth_replacement_off") then set DO_MODE_SMOO_W_REP = 0 else if ("$argv[$ac]" == "-supersize") then set supersize = "-supersize" else if ("$argv[$ac]" == "-keep_temp") then set keep_temp = "1" # ---------- fin ------------------ else echo "** unknown option $argv[$ac]" exit 1 endif @ ac ++ end # =========================================================================== # =========================================================================== echo "++ Start @animal_warper, ver = ${version}" set thedate = `date +%Y_%m_%d_%H_%M_%S` set start_d = `date +%Y-%m-%d` set start_H = `date +%H` set start_M = `date +%M` set start_S = `date +%S` set start_VAL = "${start_d} ${start_H}:${start_M}:${start_S}" # ------------------------- check for required inputs if ("${src_dset0}" == "") then echo "No input dataset provided" exit 1 endif if ("${base_dset}" == "") then echo "No base template dataset provided" exit 1 endif # [PT: Oct 24, 2021] if a src abbrev is used, add it to the QC image # names, so we can tell who is who more easily when looking at a lot # of them. if ( "${src_abbrev}" != "" ) then set src_add = ".${src_abbrev}" endif # ------------------------ define final 'orig' space # is it *really* the orig, or the osh (orig-shifted)? if ( "${center_out}" == "native" ) then set orig_fin = "orig" else if ( "${center_out}" == "center_shift" ) then set orig_fin = "orig-shft" else echo "** ERROR: Unrecognized center_out value: ${center_out}" exit 1 endif # ------------------------- make OUTDIR + QC dir # We don't allow output directory to be $PWD -- must be a subdir; too # complicated with copying fnames \mkdir -p "${outdir}" cd "${outdir}" if ( "${PWD}" == "${here}" ) then echo "** ERROR: Output directory cannot be same current working dir." echo " Please specify new output directory" exit 1 endif cd - \mkdir -p ${outdir}/QC \mkdir -p ${outdir}/${imed} # ----------------------- INFO for animal_outs set afni_pack = `afni -package` set afni_vnum = `afni -vnum` set aw_ver = `@animal_warper -ver` # so that if there is a crash, there is a record of what was run echo "# AFNI pack : ${afni_pack}" > ${outdir}/log_cmd.txt echo "# AFNI ver : ${afni_vnum}" >> ${outdir}/log_cmd.txt echo "# AW ver : ${aw_ver}" >> ${outdir}/log_cmd.txt echo "# Command :" >> ${outdir}/log_cmd.txt echo "@animal_warper $argv" >> ${outdir}/log_cmd.txt echo "" >> ${outdir}/log_cmd.txt echo "# start : ${start_VAL}" >> ${outdir}/log_cmd.txt # -------------------------- set alignment COSTS if ($cost == "") then set cost = "lpa+ZZ" set nlcost = "" else # NL warps do not support +ZZ costs, so just use similar cost set nlcost = `adjunct_simplify_cost.py ${cost}` endif # user set cost function if ( "${nlcost}" != "" ) then set nlcostoption = "-$nlcost" else # using default cost in 3dQwarp set nlcostoption = "" endif # ------------------------- earliest QC: check overlap set opref = QC/${iqc00}${src_add} @djunct_overlap_check \ -ulay "${src_dset0}" \ -olay "${base_dset}" \ -opacity 3 \ -prefix ${outdir}/${opref} # ------------------------- setup input SRC dset # input datasets may not be +orig # so match input view equivalent even for NIFTI set origview = `3dinfo -av_space "${src_dset0}" |tr -d +` # unused set origspace = `3dinfo -space "${src_dset0}"` set src_prefix = `3dinfo -prefix_noext "${src_dset0}"` if ( "${src_abbrev}" == "" ) then set src_abbrev = "${src_prefix}" endif set src_dset = ${src_abbrev}.nii.gz # cp of orig inp, used to proc # all the *p*reliminary shifted forms set srcsh_prefix = ${src_abbrev}_pshft # NOTE this name change set srcsh_dset = ${srcsh_prefix}.nii.gz # ... redefine $dset set srcsh_shft = ${srcsh_prefix}.1D # for convenience set srcsh_shft_inv = ${srcsh_prefix}_inv.1D # [PT: Aug 27, 2020] this will be the combined @Align_Centers shift # with the translation part of 3dAllineate set srcsh2_prefix = ${src_abbrev}_shft # NOTE this name change set srcsh2_dset = ${srcsh2_prefix}.nii.gz # ... redefine $dset set srcsh2_shft = ${srcsh2_prefix}.1D # for convenience set srcsh2_shft_inv = ${srcsh2_prefix}_inv.1D if (($ok_to_exist == 1) && \ (-f "${outdir}/${src_dset}" )) then echo "++ Reusing input copy: ${outdir}/${src_dset}" else # in case use uses subbrick selection on $dset, copy this way ### [PT: Oct 16, 2020] this 3dresample replaces a previous 3dcalc ### to copy src_dset: with the pshft and concatenation of ### translations, we want to have the the src dataset have good ### (x,y,z) ordering of coords. 3dresample -overwrite \ -input "${src_dset0}" \ -orient RAI \ -prefix "${outdir}/${src_dset}" if ( ${status} ) then echo "** ERROR: program failed (cp src)" exit 1 endif endif # -------------------- setup BASE dset # is the dataset somewhere else or current directory set base_dset = `@FindAfniDsetPath -full_path -append_file "${base_dset}"` set base_space = `3dinfo -space "${base_dset}"` set base_view = `3dinfo -av_space "${base_dset}"` set tbase = `basename ${base_dset}` # can also refer to base in OUTDIR # Figure out short name for base to insert into output files if ( "${base_abbrev}" != "" ) then echo "++ Using user's base abbrev: ${base_abbrev}" else # default will be `3dinfo -space ..` of base_dset set base_abbrev = ${base_space} echo "++ Making 'base' abbrev:" echo " ... ${base_abbrev}" if ( ${USE_KNOWN_BASE_ABBREV} ) then # go through our list of known *template* abbrevs foreach aa ( ${all_known_template_abbrev} ) set gcount = `echo "${base_abbrev}" | grep -c "${aa}"` if ( "${gcount}" != "0" ) then set base_abbrev = "${aa}" break endif end endif # special case, if base_dset is in orig space; clarify *whose* # ORIG space; probably a rare occurrence if ( "${base_abbrev}" == "ORIG" ) then set base_abbrev = "BASEORIG" endif printf " --> ${base_abbrev}\n" endif if (($ok_to_exist == 1) && \ (-f ${outdir}/`basename "${base_dset}"`)) then echo "++ Reusing ${outdir}/${base_dset}" else # NB: in code below, instances of ${base_dset} still refer to the # original, uncopied dset (bc it has full path); this is just for # checking alignments; probably better to still have code refer to # original ${base_dset}, for gen_ss_review.py to get info via # afni_proc.py-generated script 3dcopy "${base_dset}" ${outdir}/ if ( ${status} ) then echo "** ERROR: program failed (copy base)" exit 1 endif endif # ------------------ copy atlas followers if ( ${#atlas_followers} != 0 ) then foreach ff ( ${atlas_followers} ) if ( ($ok_to_exist == 1) && \ (-f ${outdir}/`basename "${ff}"`) ) then echo "++ Reusing ${outdir}/${ff}" else # Use 3dcopy here to tables/atlas_points/subbrick labels wd # copy over 3dcopy "${ff}" ${outdir}/ if ( ${status} ) then echo "** ERROR: program failed (copy atlas foll)" exit 1 endif endif end endif # ----- SHOULD ALL FOLLOWERS BE COPIED HERE AS WELL ??? # ------------------------- setup BRAINMASK # [BTJ: Mar 29, 2020] template mask-based brainmasking code if ("${brainmask}" != "") then # is the dataset somewhere else or current directory set brainmask = `@FindAfniDsetPath -full_path -append_file "${brainmask}"` if ( ($ok_to_exist == 1) && \ (-f ${outdir}/`basename "$brainmask"`) ) then echo "++ Reusing ${outdir}/$brainmask" else 3dcopy "${brainmask}" ${outdir}/ endif # Need to specify a mask to use for 'base' dset for reports set base_mask_for_reps = "${brainmask}" else # If no brainmask is input, then the base dset itself is applied as # the mask set base_mask_for_reps = "${base_dset}" endif # ------------------ check/make abbrevs (for all followers) # Here, we check that the number of user-entered abbrevs is # appropriate (either 0 or same nonzero number of atlas followers). # The we also see if we recognize an atlas, based on file name, and if # so take that shorter piece as an abbreviation; # We now treat all followers in a similar manner, so have some generic # variables defined that are sent to/returned from a 'function' with # goto. Each chunk here is created by replacing "atlas" with the # follower type. (In emacs, case is matched with this manner of # find/replace.) # ATLAS if ( ${#atlas_followers} ) then set generic_followers = ( ${atlas_followers} ) set generic_abbrevs = ( ${atlas_abbrevs} ) set all_known_generic_abbrev = ( ${all_known_atlas_abbrev} ) set foll_type = "atlas" set USE_KNOWN_GENERIC_ABBREV = ${USE_KNOWN_ATLAS_ABBREV} goto ABBREV_CREATION_START ABBREV_CREATION_END_ATLAS: set atlas_abbrevs = ( ${generic_abbrevs} ) endif # TEMPLATE if ( ${#template_followers} ) then set generic_followers = ( ${template_followers} ) set generic_abbrevs = ( ${template_abbrevs} ) set all_known_generic_abbrev = ( ${all_known_template_abbrev} ) set foll_type = "template" set USE_KNOWN_GENERIC_ABBREV = ${USE_KNOWN_TEMPLATE_ABBREV} goto ABBREV_CREATION_START ABBREV_CREATION_END_TEMPLATE: set template_abbrevs = ( ${generic_abbrevs} ) endif # SEG if ( ${#seg_followers} ) then set generic_followers = ( ${seg_followers} ) set generic_abbrevs = ( ${seg_abbrevs} ) set all_known_generic_abbrev = ( ${all_known_seg_abbrev} ) set foll_type = "seg" set USE_KNOWN_GENERIC_ABBREV = ${USE_KNOWN_SEG_ABBREV} goto ABBREV_CREATION_START ABBREV_CREATION_END_SEG: set seg_abbrevs = ( ${generic_abbrevs} ) endif # DSET if ( ${#dset_followers} ) then set generic_followers = ( ${dset_followers} ) set generic_abbrevs = ( ${dset_abbrevs} ) set all_known_generic_abbrev = ( ${all_known_dset_abbrev} ) set foll_type = "dset" set USE_KNOWN_GENERIC_ABBREV = ${USE_KNOWN_DSET_ABBREV} goto ABBREV_CREATION_START ABBREV_CREATION_END_DSET: set dset_abbrevs = ( ${generic_abbrevs} ) endif # ROIDSET if ( ${#roidset_followers} ) then set generic_followers = ( ${roidset_followers} ) set generic_abbrevs = ( ${roidset_abbrevs} ) set all_known_generic_abbrev = ( ${all_known_roidset_abbrev} ) set foll_type = "roidset" set USE_KNOWN_GENERIC_ABBREV = ${USE_KNOWN_ROIDSET_ABBREV} goto ABBREV_CREATION_START ABBREV_CREATION_END_ROIDSET: set roidset_abbrevs = ( ${generic_abbrevs} ) endif # --------- END of abbrev name generation for all followers # ----------------------- setup autowarp dir set awpy_dir = awpy_${srcsh_prefix} # ------------------------------------------------------------------------ # --------------------- move to odir, then start proc -------------------- cd ${outdir} # ----------------------- MAKE animal_outs ------------------------------- # If animal_outs text file already exists, mv it (for backup) and then # make a new one if ( ($ok_to_exist == 1) && \ (-f ${animal_outs}) ) then set backup_ao = ${animal_outs:gas/.txt//}_mvd_${thedate}.txt \mv ${animal_outs} ${backup_ao} if ( ${status} ) then echo "** ERROR: program failed (cp backup rep)" exit 1 endif echo "++ Moved old ${animal_outs} to: ${backup_ao}" endif if ( ($ok_to_exist == 1) && \ (-f ${animal_ints}) ) then set backup_ao2 = ${animal_ints:gas/.txt//}_mvd_${thedate}.txt \mv ${animal_ints} ${backup_ao2} echo "++ Moved old ${animal_ints} to: ${backup_ao2}" endif # Set up main and intermediate output text file with file descriptions echo "# List of inputs and outputs from @animal_warper" > ${animal_outs} echo "" >> ${animal_outs} echo "# List of @animal_warper files in ${imed} directory" > ${animal_ints} echo "" >> ${animal_ints} printf "%-37s : %s\n" \ "AFNI package" \ "${afni_pack}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "AFNI version number" \ "${afni_vnum}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "@animal_warper ver" \ "${version}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "List of main outputs (this file)" \ "${animal_outs}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "List of intermediate files" \ "${animal_ints}" \ >> ${animal_outs} if ( "${backup_ao}" != "" ) then printf "%-37s : %s\n" \ "Rerun notice, see backup info" \ "${backup_ao}" \ >> ${animal_outs} endif echo "" >> ${animal_outs} printf "%-37s : %s\n" \ "Input dset (orig)" \ "${src_dset}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Base dset (templ)" \ "${tbase}" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Base space" \ "${base_space}" \ >> ${animal_outs} set dlist = "" foreach ff ( ${atlas_followers} ) # use basename of each atlas, bc full path can be long; full # command is echoed at bottom of animal_outs, anyways set bb = `basename "${ff}"` if ( "${dlist}" == "" ) then set dlist = "${bb}" else set dlist = "${dlist}, ${bb}" endif end printf "%-37s : %s\n" \ "Atlas dsets" \ "${dlist}" \ >> ${animal_outs} # Record the final 'orig' space (shifted or original) printf "%-37s : %s\n" \ "Input dset center_out" \ "${center_out}" \ >> ${animal_outs} if ( "$align_type" == "all" ) then set al_meth = "all (= nonlinear)" else set al_meth = "$align_type" endif # Record the type of alignment printf "%-37s : %s\n" \ "Alignment type" \ "${al_meth}" \ >> ${animal_outs} echo "" >> ${animal_outs} # ----------------------------------------------------------------------- # -------------------- estimate center-align shift ---------------------- # put the center of the dataset on top of the center of the template if ( ($ok_to_exist == "1") && \ (-f ${srcsh_dset}) ) then echo "++ Reusing center aligned ${srcsh_dset}" else if ( ${DO_ALIGN_CENTERS} ) then @Align_Centers -overwrite \ ${align_centers_meth} \ -prefix "${imed}/${srcsh_dset}" \ -base "${base_dset}" \ -dset "${src_dset}" if ( ${status} ) then echo "** ERROR: program failed (align centers)" exit 1 endif # Do this because @Align Centers doesn't put *_shft.1D in same # place as its "-prefix .." path tells it to. \mv ${srcsh_shft} \ ${imed}/${srcsh_shft} else echo "++ Well, actually just COPYING dset as the center-alignment..." 3dcopy -overwrite \ "${src_dset}" \ "${imed}/${srcsh_dset}" if ( ${status} ) then echo "** ERROR: program failed (align centers, cp)" exit 1 endif echo " ... and making an identity 'shift'" echo "1 0 0 0 0 1 0 0 0 0 1 0" > ${imed}/${srcsh_shft} endif endif # *** After this point, the following files exist: # ${srcsh_dset} = src dset that has been shifted # ${srcsh_shft} = text file of the shift itself # Inverse translation (should just be negation of translation column). if ( ($ok_to_exist == "1") && \ (-f ${imed}/${srcsh_shft_inv}) ) then echo "++ Reusing center aligned ${srcsh_shft_inv}" else cat_matvec \ ${imed}/${srcsh_shft} -I \ > ${imed}/${srcsh_shft_inv} if ( ${status} ) then echo "** ERROR: program failed (al cent inv)" exit 1 endif endif printf "%-37s : %s\n" \ "Dset, pre-shifted to base" \ "${srcsh_dset}" \ >> ${animal_ints} # [PT] newer check about overlap, and show some progress set opref = QC/${iqc01}${src_add} @djunct_overlap_check \ -ulay "${imed}/${srcsh_dset}" \ -olay "${base_dset}" \ -opacity 3 \ -prefix ${opref} # ------------------------- estimate aff mat ------------------------- # Using input/src dset as dset2 and the base as dset1 (the base and # source are treated differently by align_epi_anats resampling and by # 3dAllineate) if ( "$align_type" == "rigid" ) then set rigidopt = "-rigid_body" else set rigidopt = "" endif if ( ( $ok_to_exist == "1" ) && \ (-f ${imed}/${srcsh_prefix}_al2std_mat.aff12.1D) ) then echo "++ Reusing affine transformation matrix" else #set aaa = ( -giant_move ) if ( $DO_INIT_SCALE ) then echo "++ Make pre_matrix for initial scale: ${init_scale}" set premat_fname = "${imed}/aea_pre_matrix.1D" set opt_init_scale = "-pre_matrix ${premat_fname}" cat < "${premat_fname}" ${init_scale} 0.0 0.0 0.0 0.0 ${init_scale} 0.0 0.0 0.0 0.0 ${init_scale} 0.0 EOF # just for QC image-generating purposes 3dAllineate \ -overwrite \ -1Dmatrix_apply "${premat_fname}" \ -input "${imed}/${srcsh_dset}" \ -prefix "${imed}/__tmp_INIT_SCALE.nii.gz" set opref = QC/${iqc01b}${src_add} @djunct_overlap_check \ -ulay "${imed}/__tmp_INIT_SCALE.nii.gz" \ -olay "${base_dset}" \ -opacity 3 \ -prefix ${opref} if ( "${keep_temp}" != "1") then \rm -rf "${imed}/__tmp_INIT_SCALE.nii.gz" endif endif # outputs a BRIK/HEAD file # [PT: July 8, 2021] allow '-giant_move' to be switched to other opts # [PT: July 9, 2021] ... and adding "-master_dset2 BASE" for stability # across now-larger range of $aff_move options. align_epi_anat.py -overwrite \ -output_dir "${imed}" \ -dset2 "${imed}/${srcsh_dset}" \ -dset1 "${base_dset}" \ -dset2to1 \ -suffix _al2std \ -dset1_strip None \ -dset2_strip None \ -cost $cost $rigidopt $feature_option $supersize ${aff_move} \ -master_dset2 BASE ${opt_init_scale} if ( ${status} ) then echo "** ERROR: program failed (AEA)" exit 1 endif # convert the affine aligned output to NIFTI 3dAFNItoNIFTI \ -prefix ${imed}/${srcsh_prefix}_al2std.nii.gz \ ${imed}/${srcsh_prefix}_al2std${base_view} if ( ${status} ) then echo "** ERROR: program failed (afni2nii)" exit 1 endif \rm ${imed}/${srcsh_prefix}_al2std${base_view}.* endif # re-partition the translation part of aff alignment with the shift # from @Align_Centers if ( ( $ok_to_exist == "1" ) && \ (-f ${imed}/${srcsh2_dset} ) ) then echo "++ Reusing re-partitioned shift" else # extract the translation part and output it set mat0 = `cat_matvec -ONELINE \ "${imed}/${srcsh_prefix}_al2std_mat.aff12.1D"` echo "1 0 0 ${mat0[4]} 0 1 0 ${mat0[8]} 0 0 1 ${mat0[12]}" > \ "${imed}/${srcsh_prefix}_al2std_mat_TR.aff12.1D" # ... and calc its inverse cat_matvec -ONELINE \ "${imed}/${srcsh_prefix}_al2std_mat_TR.aff12.1D" -I \ > "${imed}/${srcsh_prefix}_al2std_mat_TR_INV.aff12.1D" # this is needed for shifting the origin, below set inv_transl = `cat "${imed}/${srcsh_prefix}_al2std_mat_TR_INV.aff12.1D"` # create the new full shift cat_matvec -ONELINE \ ${imed}/${srcsh_shft} \ "${imed}/${srcsh_prefix}_al2std_mat_TR.aff12.1D" \ > ${imed}/${srcsh2_shft} # ... and inverse shift cat_matvec -ONELINE \ ${imed}/${srcsh2_shft} -I \ > ${imed}/${srcsh2_shft_inv} if ( ${status} ) then echo "** ERROR: program failed (cat_matvec inv)" exit 1 endif # THIS is the aff matrix that goes from shft2 to template space, # and what we should use later; it should have NO translation # component # [PT, DRG: Aug 5, 2024] fix how this is done, so that # after this is applied, the *_pshft_al2std.nii.gz will # be essentially the same as *_shft_aff.nii.gz (just in # ORIG and TLRC views, and on diff grids) cat_matvec -ONELINE \ "${imed}/${srcsh_prefix}_al2std_mat.aff12.1D" \ "${imed}/${srcsh_prefix}_al2std_mat_TR_INV.aff12.1D" \ > "${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D" # Finally, make the new shifted dset; that should overlap # well with base_dset 3dcopy \ -overwrite \ ${imed}/${srcsh_dset} \ ${imed}/${srcsh2_dset} 3drefit \ -dxorigin ${inv_transl[4]} \ -dyorigin ${inv_transl[8]} \ -dzorigin ${inv_transl[12]} \ ${imed}/${srcsh2_dset} if ( ${status} ) then echo "** ERROR: program failed (combine shifts)" exit 1 endif # *** From this point onward, the shft2 space is the more important # jumping point between the original native space and the # base/template space*** endif printf "%-37s : %s\n" \ "Dset, 2nd-shifted to base" \ "${srcsh2_dset}" \ >> ${animal_ints} echo "" >> ${animal_ints} printf "%-37s : %s\n" \ "Input, aff-xformed to base (orig res)" \ "${srcsh_prefix}_al2std.nii.gz" \ >> ${animal_ints} printf "%-37s : %s\n" \ "Matrix, aff xform (shft2 to base)" \ "${srcsh2_prefix}_al2std_mat.aff12.1D" \ >> ${animal_ints} if ( "$align_type" == "rigid_equiv" ) then set affmat = ${srcsh2_prefix}_al2std_mat_rigid.aff12.1D cat_matvec -ONELINE \ ${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D -P \ > ${imed}/${affmat} if ( ${status} ) then echo "** ERROR: program failed (cat_matvec, affmat)" exit 1 endif printf "%-37s : %s\n" \ "Matrix, rigid equiv xform" \ "${affmat}" \ >> ${animal_ints} else set affmat = ${srcsh2_prefix}_al2std_mat.aff12.1D endif ## put affine aligned data on template grid # similar to al2std dataset but with exactly same grid as the template if (($ok_to_exist == "1") && \ (-f ${imed}/${srcsh2_prefix}_aff.nii.gz)) then echo "++ Reusing affine transformed dataset" else 3dAllineate -overwrite \ -1Dmatrix_apply ${imed}/${affmat} \ -prefix ${imed}/${srcsh2_prefix}_aff.nii.gz \ -base "${base_dset}" \ -master BASE \ -source "${imed}/${srcsh2_dset}" if ( ${status} ) then echo "** ERROR: program failed (3dAllineate)" exit 1 endif set opref = QC/${iqc02}${src_add} @djunct_overlap_check \ -ulay "${imed}/${srcsh2_prefix}_aff.nii.gz" \ -olay "${base_dset}" \ -opacity 3 \ -prefix ${opref} endif printf "%-37s : %s\n" \ "Input, aff-xformed to base" \ "${srcsh2_prefix}_aff.nii.gz" \ >> ${animal_ints} echo "" >> ${animal_ints} # ---------------------- make inv and composite aff mats ---------------- # Note on combining shft2 and affine 1D files for composite linear # transformation to template space: combining shift is dangerous! The # transformation distance can be very large, and 3dNwarpApply will # create a high resolution space that will likely eat up large amounts # of memory. Proceed with caution (well, the user needs dsets that # aren't *too* far apart). # Compute the inverse of the affine alignment transformation - all 12 # numbers; creates 'template -> shifted input space' aff xform cat_matvec \ -ONELINE \ ${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D -I \ >! ${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D # full affine part, template to unshifted org space: don't want this # to be large (see note above); creates 'original input -> template # space' aff xform cat_matvec \ -ONELINE \ ${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D \ ${imed}/${srcsh2_shft} \ > ${src_abbrev}_composite_linear_to_template.1D #Now create the inverse composite warp from template to subject space; # creates 'template spac -> original input' aff xform cat_matvec -ONELINE \ ${imed}/${srcsh2_shft_inv} \ ${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D \ > ${src_abbrev}_composite_linear_to_template_inv.1D if ( ${status} ) then echo "** ERROR: program failed (inv comp)" exit 1 endif printf "%-37s : %s\n" \ "Matrix, full aff xform (for AP)" \ "${src_abbrev}_composite_linear_to_template.1D" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Matrix, full aff xform, inv" \ "${src_abbrev}_composite_linear_to_template_inv.1D" \ >> ${animal_outs} # ---------------------- end aff; can go to NL ---------------------------- #### no longer the case! # ## if nonlinear alignment is not requested, then exit #if ( "$align_type" != "all" ) then # echo "" # echo "++ Finished aligning with only ${align_type} alignment" # echo "" # if ( "$align_type" == "rigid" ) then # echo "++ This 'rigid' alignment method requires restarting" # echo " the alignment for other types of alignment" # else # echo "++ You may restart for other types of alignment with" # echo " a different align_type and -ok_to_exist" # endif # goto FINISH_OUTS #endif if ( "$align_type" != "all" ) then echo "++ With align_type = '$align_type', we jump ahead." goto JUMP_RIGID endif # ------------------------ MAKE_WARP aff2base, base2aff -------------------- # -------------------------------------------------------------------------- # Note about the warping here: # # affinely align to template (could let auto_warp.py hande this, but # AUTO_CENTER option might be needed) # @auto_tlrc -base $base -input $dset -no_ss -init_xform AUTO_CENTER # # NB: Now skipping cheap skullstripping: # It didn't work for macaques with very different size brains. V1 # got cut off probably could work with dilated mask "cheap" # skullstripping with affine registered dataset the macaque brains # are similar enough that the affine seems to be sufficient here for # skullstripping # 3dcalc -a ${src_prefix}_aff+tlrc. -b $base -expr 'a*step(b)' \ # -prefix ${src_prefix}_aff_ns -overwrite # # nonlinear alignment of affine skullstripped dataset to template # by default,the warp and the warped dataset are computed # by using "-qw_opts ", one could save the inverse warp and do extra padding # with -qw_opts '-iwarp -expad 30' # change qw_opts to remove max_lev 2 for final # -------------------------------------------------------------------------- # No $ok_to_exist on this dir: the outputs that are extracted from it # are checked, instead. Gets purged, below, at end of running. \rm -rf ${awpy_dir} if ( ($ok_to_exist == "1") && \ (-f ${srcsh2_prefix}_WARP.nii.gz) ) then echo "++ Reusing nonlinear WARP dataset" else # nonlinear warping via auto_warp script auto_warp.py -overwrite \ -base "${base_dset}" \ -affine_input_xmat ID \ -qworkhard 0 2 \ -input ${imed}/${srcsh2_prefix}_aff.nii.gz \ -output_dir ${awpy_dir} \ -qw_opts -iwarp -maxlev ${maxlev} ${nlcostoption} \ $extra_qw_opts if ( ${status} ) then echo "** ERROR: program failed (autowarp)" exit 1 endif # the awpy has the result dataset, copy the warped data, the warp, # inverse warp don't copy the warped dataset - combine the # transformations instead below # THIS is a major output # from orig+shft2+aff -> base 3dcopy -overwrite \ ${awpy_dir}/anat.*.qw_WARP.nii* \ ${srcsh2_prefix}_WARP.nii.gz # from base -> orig+shft2+aff 3dcopy -overwrite \ ${awpy_dir}/anat.*.qw_WARPINV.nii* \ ${srcsh2_prefix}_WARPINV.nii.gz if ( ${status} ) then echo "** ERROR: program failed (autowarp cp)" exit 1 endif endif # THIS is what should be given to afni_proc.py printf "%-37s : %s\n" \ "NL warp, aff2base (for AP)" \ "${srcsh2_prefix}_WARP.nii.gz" \ >> ${animal_outs} printf "%-37s : %s\n" \ "NL warp, base2aff" \ "${srcsh2_prefix}_WARPINV.nii.gz" \ >> ${animal_outs} # ----------------------------------------------------------------------- # ------------------------ MAKE_WARP osh2base -------------------------- # This is the aff+WARP dset used within @animal_warper, so we don't # have to keep recalculate it below. THIS IS NOT what is applied to # afni_proc.py. if ( ($ok_to_exist == "1") && \ (-f "${imed}/${srcsh2_prefix}_osh2base_WARP.nii.gz" ) ) then echo "++ Reusing osh2base_WARP dataset" else # warp from orig+shft2 -> base 3dNwarpCat -echo_edu \ -warp1 "${srcsh2_prefix}_WARP.nii.gz" \ -warp2 "${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D" \ -prefix "${imed}/${srcsh2_prefix}_osh2base_WARP.nii.gz" if ( ${status} ) then echo "** ERROR: program failed (3dNwarpCat, osh2base)" exit 1 endif endif printf "%-37s : %s\n" \ "NL warp, osh2base (internal use)" \ "${srcsh2_prefix}_osh2base_WARP.nii.gz" \ >> ${animal_ints} # ------------------------- MAKE_WARP base2osh ------------------------ # Since this warp will get applied at least once (and probably more # often, create it and then apply it. Thus, THIS is the warp to apply # for all template -> original/native space transforms if ( ($ok_to_exist == "1") && \ (-f "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" ) ) then echo "++ Reusing base2osh_WARP dataset" else # warp from base -> orig+shft2 # [PT: Aug 27, 2020] get name of specific space (otherwise will # just be generic "TLRC)" set space = `3dinfo -space "${srcsh2_prefix}_WARPINV.nii.gz"` 3dNwarpCat -echo_edu \ -warp1 "${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D" \ -warp2 "${srcsh2_prefix}_WARPINV.nii.gz" \ -space "${space}" \ -prefix "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" if ( ${status} ) then echo "** ERROR: program failed (3dNwarpCat, base2osh)" exit 1 endif endif printf "%-37s : %s\n" \ "NL warp, base2osh (internal use)" \ "${srcsh2_prefix}_base2osh_WARP.nii.gz" \ >> ${animal_ints} JUMP_RIGID: # ----------------------------------------------------------------------- # --------------------- APPLY_WARP osh2base: input dset ----------------- # NB: when *applying* warps to bring data into standard space, in this # case the input template is in the shifted location: that is why the # warp is only aff+WARP, and not oshft2+aff+WARP. if ( ($ok_to_exist == "1") && \ (-f ${src_abbrev}_warp2std.nii.gz) && \ (-f ${src_abbrev}_warp2std_nsu.nii.gz) ) then echo "++ Reusing warped input dataset and its unifized version" else if ( "$align_type" == "all" ) then # [DRG: 07 Nov 2016] combine nonlinear and affine warps for dataset # warped to standard template space 3dNwarpApply -overwrite \ -prefix "${src_abbrev}_warp2std.nii.gz" \ -nwarp "${imed}/${srcsh2_prefix}_osh2base_WARP.nii.gz" \ -source "${imed}/${srcsh2_dset}" \ -master "${base_dset}" if ( ${status} ) then echo "** ERROR: program failed (3dNwarpApply, osh2base)" exit 1 endif else 3dAllineate -overwrite \ -prefix "${src_abbrev}_warp2std.nii.gz" \ -1Dmatrix_apply "${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D" \ -source "${imed}/${srcsh2_dset}" \ -master "${base_dset}" if ( ${status} ) then echo "** ERROR: program failed ($align_type 3dAllineate, osh2base)" exit 1 endif endif set opref = QC/${iqc03}${src_add} @djunct_overlap_check \ -ulay "${src_abbrev}_warp2std.nii.gz" \ -olay "${base_dset}" \ -opacity 3 \ -prefix ${opref} # make masked version of orig dset in template space, using the # template itself. # [PT: Feb 25, 2021] not sure how much sense this makes with rigid aligns, # but will leave it in for user to decide about utility # [PT: May 20, 2021] switch what dset is used to mask the data that # has now been warped to standard space: should be either input # mask, or masking of template dset---thanks to A Messinger for pointing # this out 3dcalc -overwrite \ -a "${src_abbrev}_warp2std.nii.gz" \ #-b "${base_dset}" \ -b "${base_mask_for_reps}" \ -expr 'a*step(b)' \ -prefix "${src_abbrev}_warp2std_ns.nii.gz" if ( ${status} ) then echo "** ERROR: program failed (3dcalc, osh2base)" exit 1 endif # nicer version for viewing in template space: this will be passed # along to AP to be ulay at times echo "++ Unifizing input dset in template space" 3dUnifize -overwrite \ -GM \ -clfrac 0.4 \ -Urad 14 \ -input ${src_abbrev}_warp2std_ns.nii.gz \ -prefix ${src_abbrev}_warp2std_nsu.nii.gz if ( ${status} ) then echo "** ERROR: program failed (3dUnifize, osh2base)" exit 1 endif # ... and put a note in its history, so that # gen_ss_review_scripts.py knows the name of the template 3dNotes \ -h "@animal_warper aligned this dset to standard space: -base ${base_dset}" \ ${src_abbrev}_warp2std_nsu.nii.gz # Image : [ulay] orig dset, warped to template # [olay] edges of template # This is in template space, so use the template (which has no # skull) as a refbox set olay = "${base_dset}" set ulay = "${src_abbrev}_warp2std.nii.gz" set opref = QC/${qc00}${src_add} @djunct_edgy_align_check \ -olay ${olay} \ -box_focus_slices ${olay} \ -ulay ${ulay} \ -prefix ${opref} \ -save_ftype PNG \ -montx 5 -monty 3 \ -montgap 1 \ -montcolor 'black' endif # maybe change names? these sound like warp dsets, but they are # actually dsets that *have* been warped echo "" >> ${animal_outs} printf "%-37s : %s\n" \ "Input in templ" \ "${src_abbrev}_warp2std.nii.gz" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Input in templ, no skull" \ "${src_abbrev}_warp2std_ns.nii.gz" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Input in templ, no skull, unifized" \ "${src_abbrev}_warp2std_nsu.nii.gz" \ >> ${animal_outs} # ------------ APPLY_WARP osh2base: DSET, ROIDSET followers ----------- # Use just one loop through all float- and int-valued dsets that are # in the orig space, so the code isn't duplicated. Use a matched list # of interp values to tell which is which, when we need differences. # Note: the followers will first be shifted here with @Align_centers, # and then the aff+WARP matrix will be applied to them; this is yet # again different than applying shft+aff+WARP. The reason for this is # the potential for giant memory usage if the shift part is large, as # the final NL warp dset might be ginormous. set all_follow = ( ) set all_abbrev = ( ) set all_interp = ( ) foreach ii ( `seq 1 1 ${#dset_followers}` ) set all_follow = ( ${all_follow} "${dset_followers[$ii]}" ) set all_abbrev = ( ${all_abbrev} "${dset_abbrevs[$ii]}" ) set all_interp = ( ${all_interp} wsinc5 ) end foreach ii ( `seq 1 1 ${#roidset_followers}` ) set all_follow = ( ${all_follow} "${roidset_followers[$ii]}" ) set all_abbrev = ( ${all_abbrev} "${roidset_abbrevs[$ii]}" ) set all_interp = ( ${all_interp} NN ) end # applying warps to followers - other datasets that start in same # space, ~grid. move each the same way as the data - align centers, # apply affine, nonlinear warp. foreach ii ( `seq 1 1 ${#all_follow}` ) set followset = "${all_follow[$ii]}" set follow_abbrev = "${all_abbrev[$ii]}" set follow_interp = "${all_interp[$ii]}" # the main output set follow_in_std = ${follow_abbrev}_warp2std.nii.gz # ... but if followset is int value AND is modally smoothed, then # save the pre-modally smoothed version under this name: set follow_in_std_pre = ${follow_abbrev}_w2s_PRE.nii.gz # first check if output exists if ( ($ok_to_exist == "1") && \ (-f ${follow_in_std}) ) then echo "++ Reusing nonlinear transformed follower dataset:" echo " ${follow_in_std}" else # copy dataset to temporary one - reused by multiple dset followers \rm -f tempfollow.nii.gz 3dcopy "${followset}" tempfollow.nii.gz # Move center of follower with same 1D shift as original dataset. # Funny that the opt has '_inv', but that appears to be correct! @Align_Centers -overwrite \ -no_cp \ -base "${base_dset}" \ -dset tempfollow.nii.gz \ -shift_xform_inv ${imed}/${srcsh2_shft} if ( "$align_type" == "all" ) then # apply NL warp 3dNwarpApply -overwrite \ -ainterp ${follow_interp} \ -prefix ${follow_in_std} \ -nwarp "${imed}/${srcsh2_prefix}_osh2base_WARP.nii.gz" \ -source tempfollow.nii.gz \ -master "${base_dset}" if ( ${status} ) then echo "** ERROR: program failed (follower data, 1)" exit 1 endif else 3dAllineate -overwrite \ -final ${follow_interp} \ -prefix ${follow_in_std} \ -1Dmatrix_apply "${imed}/${srcsh2_prefix}_al2std_mat.aff12.1D" \ -source tempfollow.nii.gz \ -master "${base_dset}" if ( ${status} ) then echo "** ERROR: program failed ($align_type follower data, 1)" exit 1 endif endif if ( "${follow_interp}" == "NN" ) then # keep propagating labels/atlases 3drefit -copytables "${followset}" ${follow_in_std} 3drefit -cmap INT_CMAP ${follow_in_std} echo "++ Created follower ROI dset: ${follow_in_std}" if ( "${modesmooth}" != "0") then # save the unsmoothed version as a backup 3dcopy -overwrite \ ${follow_in_std} \ ${imed}/${follow_in_std_pre} if ( ${DO_MODE_SMOO_W_REP} ) then # Modal smoothing *with* replacement; output has # INT_CMAP and tables copied @djunct_modal_smoothing_with_rep \ -overwrite ${DO_ECHO} \ -input ${imed}/${follow_in_std_pre} \ -prefix ${follow_in_std} \ -modesmooth $modesmooth else # Standard modal smoothing (*no* replacement) 3dLocalstat -overwrite \ -stat mode \ -nbhd "SPHERE(-${modesmooth})" \ -prefix ${follow_in_std} \ ${imed}/${follow_in_std_pre} # make these show up in AFNI as labeled ROI or atlas datasets 3drefit -copytables ${followset} ${follow_in_std} 3drefit -cmap INT_CMAP ${follow_in_std} if ( ${status} ) then echo "** ERROR: program failed (foll data, 2: ${followset})" exit 1 endif endif endif echo " ... and finished processing it" else if ( "${follow_interp}" == "wsinc5" ) then echo "++ Created follower dset: ${follow_in_std}" else echo "** ERROR: how is the interp value: ${follow_interp}?" exit 1 endif endif # final part, for text file info if ( "${follow_interp}" == "NN" ) then printf "%-37s : %s\n" \ "Follower ROI dset, warped to base" \ "${follow_in_std}" \ >> ${animal_outs} else if ( "${follow_interp}" == "wsinc5" ) then printf "%-37s : %s\n" \ "Follower dset, warped to base" \ "${follow_in_std}" \ >> ${animal_outs} else echo "** ERROR: how is the interp value: ${follow_interp}?" exit 1 endif end # ------------------------------------------------------------------------- # ------------------ pre-APPLY_WARP base2orig|base2osh -------------------- # Now handle the inverse transformed data - template and atlases to # native space. # ---------------------------- useful vars -------------------------------- set t_in_o_prefix = ${base_abbrev}_in_${src_abbrev} set templ_in_orig = ${t_in_o_prefix}.nii.gz set templ_in_origA = ${t_in_o_prefix}_aniso.nii.gz set templ_in_origAC = ${t_in_o_prefix}_aniso_clust.nii.gz set templ_in_origG = ${t_in_o_prefix}.gii # ---------------- APPLY_WARP base2orig|base2osh: BASE dset ---------------- # apply base2osh warp (and osh2orig shft vec, by default) if ( ($ok_to_exist == "1") && \ (-f ${templ_in_orig} ) ) then echo "++ Reusing template transformed to native space dataset" else if ( "$align_type" == "all" ) then # warp to orig+shft space 3dNwarpApply -overwrite \ -ainterp wsinc5 \ -nwarp "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" \ -source "${base_dset}" \ -master ${imed}/${srcsh2_dset} \ -prefix ${templ_in_orig} if ( ${status} ) then echo "** ERROR: program failed (3dNwarpApply, base2osh, 1)" exit 1 endif else 3dAllineate -overwrite \ -final wsinc5 \ -1Dmatrix_apply "${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D" \ -source "${base_dset}" \ -master ${imed}/${srcsh2_dset} \ -prefix ${templ_in_orig} if ( ${status} ) then echo "** ERROR: program failed ($align_type 3dAllineate, base2osh, 1)" exit 1 endif endif # put back in non-shifted version (really native space); default if (${center_out} == "native") then # Move center of dset with the INV of the original shift. Funny # that the opt has '_inv', but this appears to be correct! @Align_Centers -overwrite \ -no_cp \ -base ${src_dset} \ -dset ${templ_in_orig} \ -shift_xform_inv ${imed}/${srcsh2_shft_inv} if ( ${status} ) then echo "** ERROR: program failed (base2osh 2)" exit 1 endif endif # Return original dataset view (to view in AFNI) 3drefit -space ${origspace} ${templ_in_orig} # Note: image made below, after skull-stripping applied to make # focus mask. endif # --------------- APPLY_WARP base2orig|base2osh: BRAINMASK --------------- # apply base2osh warp (and osh2orig shft vec, by default); or, created # a brain mask if ( ($ok_to_exist == "1") && \ (-f ${src_abbrev}_ns.nii.gz) && \ (-f ${src_abbrev}_mask.nii.gz) ) then echo "++ Reusing masked original/input dset" else # [BTJ: Mar 29, 2020] template mask-based brainmasking code if (${brainmask} != "") then if ( ($ok_to_exist == "1") && \ (-f ${src_abbrev}_mask.nii.gz) ) then echo "++ Reusing template transformed to native space dataset" else if ( "$align_type" == "all" ) then # warp to orig+shft space 3dNwarpApply -overwrite \ -ainterp NN \ -short \ -nwarp "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" \ -source ${brainmask} \ -master ${imed}/${srcsh2_dset} \ -prefix ${src_abbrev}_mask.nii.gz if ( ${status} ) then echo "** ERROR: program failed (base2osh, brainmask)" exit 1 endif else set amat = "${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D" 3dAllineate -overwrite \ -final NN \ -1Dmatrix_apply "${amat}" \ -source ${brainmask} \ -master ${imed}/${srcsh2_dset} \ -prefix ${src_abbrev}_mask.nii.gz if ( ${status} ) then echo "** ERROR: program failed ($align_type 3dAllineate base2osh, brainmask)" exit 1 endif endif # put back in non-shifted version (really native space); # default if (${center_out} == "native") then # put back in non-shifted version (really native space) @Align_Centers \ -no_cp \ -base ${src_dset} \ -dset ${src_abbrev}_mask.nii.gz \ -shift_xform_inv ${imed}/${srcsh2_shft_inv} if ( ${status} ) then echo "** ERROR: program failed (base2osh, brainmask 2)" exit 1 endif endif # Return original dataset view (to view in AFNI) 3drefit -space ${origspace} ${src_abbrev}_mask.nii.gz endif else 3dcalc \ -a ${templ_in_orig} \ -b ${src_abbrev}.nii.gz \ -expr 'step(a)*b' \ -prefix ${imed}/__tmp_orig_mskd.nii.gz \ -overwrite if ( ${status} ) then echo "** ERROR: program failed (base2osh, brainmask, B1)" exit 1 endif # smoothify mask with in/out dilations; slightly pad: this is our # new anat mask. 3dmask_tool \ -dilate_inputs -2 3 \ -inputs ${imed}/__tmp_orig_mskd.nii.gz \ -prefix ${src_abbrev}_mask.nii.gz \ -overwrite if ( ${status} ) then echo "** ERROR: program failed (base2osh, brainmask, B2)" exit 1 endif endif 3dcalc \ -a ${src_abbrev}.nii.gz \ -b ${src_abbrev}_mask.nii.gz \ -expr 'a*step(b)' \ -prefix ${src_abbrev}_ns.nii.gz \ -overwrite if ( ${status} ) then echo "** ERROR: program failed (base2osh brainmask 4)" exit 1 endif # Image : [ulay] orig dset; [olay] edges of warped template set olay = "${templ_in_orig}" set ulay = "${src_abbrev}.nii.gz" set focus = "${src_abbrev}_mask.nii.gz" set opref = QC/${qc01}${src_add} @djunct_edgy_align_check \ -olay ${olay} \ -box_focus_slices ${focus} \ -ulay ${ulay} \ -prefix ${opref} \ -save_ftype PNG \ -montx 5 -monty 3 \ -montgap 1 \ -montcolor 'black' # Image : [ulay] orig dset [olay] mask of orig dset set ulay = ${src_abbrev}.nii.gz set olay = ${src_abbrev}_mask.nii.gz set focus = ${olay} set opref = QC/${qc02}${src_add} @chauffeur_afni \ -ulay "${ulay}" \ -ulay_range_nz 0% 98% \ -set_subbricks 0 0 0 \ -olay "${olay}" \ -box_focus_slices "${focus}" \ -cbar RedBlueGreen \ -montgap 1 \ -montcolor 'black' \ -pbar_posonly \ #-pbar_saveim ${opref} \ -prefix ${opref} \ -opacity 3 \ -montx 5 -monty 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 # clean up a bit \rm -f ${imed}/__tmp_orig_mskd.nii.gz endif # [PT: Jan 14, 2020] add these to the output text printf "%-37s : %s\n" \ "Mask of input" \ "${src_abbrev}_mask.nii.gz" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Input (orig), no skull" \ "${src_abbrev}_ns.nii.gz" \ >> ${animal_outs} # Make unifized form of original (skullstripped) dset if ( ($ok_to_exist == "1") && \ (-f ${src_abbrev}_nsu.nii.gz) ) then echo "++ Reusing skullstripped+unifized original/input dset" else echo "++ Unifizing input dset in input/source space" 3dUnifize -overwrite \ -GM \ -clfrac 0.4 \ -Urad 14 \ -input ${src_abbrev}_ns.nii.gz \ -prefix ${src_abbrev}_nsu.nii.gz if ( ${status} ) then echo "** ERROR: program failed (nsu)" exit 1 endif endif printf "%-37s : %s\n" \ "Input (orig), no skull, unifized" \ "${src_abbrev}_nsu.nii.gz" \ >> ${animal_outs} echo "" >> ${animal_outs} # -------- APPLY_WARP base2orig|base2osh: TEMPLATE followers (floats) ------ # apply base2osh warp (and osh2orig shft vec, by default) foreach ii ( `seq 1 1 ${#template_followers}` ) set template_dset = "${template_followers[$ii]}" set template_prefix = "${template_abbrevs[$ii]}" set template_in_orig = ${template_prefix}_in_${src_abbrev}.nii.gz if ( ($ok_to_exist == "1") && \ (-f ${template_in_orig} ) ) then echo "++ Reusing template transformed to native space dataset:" echo " ${template_in_orig}" else if ( "$align_type" == "all" ) then # warp to orig+shft space 3dNwarpApply -overwrite \ -short \ -ainterp wsinc5 \ -nwarp "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" \ -source ${template_dset} \ -master ${imed}/${srcsh2_dset} \ -prefix ${template_in_orig} if ( ${status} ) then echo "** ERROR: program failed (base2osh templ foll, ${template_dset})" exit 1 endif else set amat = "${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D" 3dAllineate -overwrite \ -final wsinc5 \ -1Dmatrix_apply "${amat}" \ -source ${template_dset} \ -master ${imed}/${srcsh2_dset} \ -prefix ${template_in_orig} if ( ${status} ) then echo "** ERROR: program failed ($align_type base2osh templ foll, ${template_dset})" exit 1 endif endif # put back in non-shifted version (really native space) if (${center_out} == "native") then @Align_Centers \ -no_cp \ -base ${src_dset} \ -dset ${template_in_orig} \ -shift_xform_inv ${imed}/${srcsh2_shft_inv} endif # Return original dataset view (to view in AFNI) 3drefit -space ${origspace} ${template_in_orig} endif printf "%-37s : %s\n" \ "Template follower in ${orig_fin}" \ "${template_in_orig}" \ >> ${animal_outs} end # ---------------------------------------------------------------------- # Old Note (var names may be out of date): # # this only warps back to the affine warped space (~ in template space) # 3dNwarpApply -ainterp NN -short -overwrite -nwarp \ # ${src_prefix}_WARPINV.nii.gz -overwrite \ # -source $segset -master ${src_prefix}_aff.nii.gz \ # -prefix ${segname}_in_${src_abbrev}.nii.gz # moves data to orig space - but introduces second interpolation # on nearest neighbor ROI data, this can make for odd artifacts # 3dAllineate -source ${segname}_in_${src_abbrev}.nii.gz \ # -base ${src_abbrev}.nii.gz \ # -final NN \ # -1Dmatrix_apply ${src_abbrev}_composite_linear_to_template_inv.1D \ # -prefix ${segname}_in_${src_abbrev}.nii.gz # deletes the segmentation in affine warped space # ---------------------------------------------------------------------- # -------- APPLY_WARP base2orig|base2osh: ATL, SEG followers (int) ------ # apply base2osh warp (and osh2orig shft vec, by default) # Loop over all atl and seg dsets that were entered; most of what # happens is similar; only difference is that the ATL dsets will get # isosurfaces generated set all_tfollow = ( ) set all_tabbrev = ( ) set all_ttypes = ( ) foreach ii ( `seq 1 1 ${#atlas_followers}` ) set all_tfollow = ( ${all_tfollow} "${atlas_followers[$ii]}" ) set all_tabbrev = ( ${all_tabbrev} "${atlas_abbrevs[$ii]}" ) set all_ttypes = ( ${all_ttypes} "ATL" ) end foreach ii ( `seq 1 1 ${#seg_followers}` ) set all_tfollow = ( ${all_tfollow} "${seg_followers[$ii]}" ) set all_tabbrev = ( ${all_tabbrev} "${seg_abbrevs[$ii]}" ) set all_ttypes = ( ${all_ttypes} "SEG" ) end foreach ii ( `seq 1 1 ${#all_tfollow}` ) set iii = `printf "%02d" $ii` set segm_dset = "${all_tfollow[$ii]}" set segm_prefix = "${all_tabbrev[$ii]}" set segm_type = "${all_ttypes[$ii]}" # the main output set segm_in_orig = "${segm_prefix}_in_${src_abbrev}.nii.gz" # ... but if followset is int value AND is modally smoothed, then # save the pre-modally smoothed version under this name: set segm_in_orig_pre = "${segm_prefix}_in_${src_abbrev}_PRE.nii.gz" if ( ( $ok_to_exist == "1" ) && \ ( -f ${segm_in_orig} ) ) then echo "++ Reusing ${segm_type} in native space: ${segm_in_orig}" else if ( "$align_type" == "all" ) then # warp to orig+shft space 3dNwarpApply -overwrite \ -ainterp NN \ -short \ -nwarp "${imed}/${srcsh2_prefix}_base2osh_WARP.nii.gz" \ -source ${segm_dset} \ -master ${imed}/${srcsh2_dset} \ -prefix ${segm_in_orig} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll)" echo " ... for dset: ${segm_dset}" exit 1 endif else set amat = "${imed}/${srcsh2_prefix}_inv_al2std_mat.aff12.1D" 3dAllineate -overwrite \ -final NN \ -1Dmatrix_apply "${amat}" \ -source ${segm_dset} \ -master ${imed}/${srcsh2_dset} \ -prefix ${segm_in_orig} if ( ${status} ) then echo "** ERROR: program failed ($align_type base2osh atl/seg foll)" echo " ... for dset: ${segm_dset}" exit 1 endif endif # put back in non-shifted version (really native space) if ($center_out == "native") then @Align_Centers \ -no_cp \ -base ${src_dset} \ -dset ${segm_in_orig} \ -shift_xform_inv ${imed}/${srcsh2_shft_inv} endif # change the datum type to byte to save space if values # range from 0 to 255 this step also gets removes the shift # transform information in the header overwriting original # dataset just created set segminmax = `3dBrickStat \ -min -max -slow \ ${segm_in_orig}` if ( (${segminmax[2]} <= 255) && \ (${segminmax[1]} >= 0) ) then 3dcalc -overwrite \ -a ${segm_in_orig} \ -expr a \ -datum byte \ -nscale \ -prefix ${segm_in_orig} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, calc)" echo " ... for dset: ${segm_dset}" exit 1 endif endif # keep propagating labels/atlases 3drefit -copytables "${segm_dset}" ${segm_in_orig} 3drefit -cmap INT_CMAP ${segm_in_orig} # modal smoothing if ( "${modesmooth}" != "0") then # save the unsmoothed version as a backup 3dcopy -overwrite \ ${segm_in_orig} \ ${imed}/${segm_in_orig_pre} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, cp)" echo " ... for dset: ${segm_dset}" exit 1 endif \rm ${segm_in_orig} # this extra step done here to make sure the space is # correct (should be, from 3dNwarp*?) 3drefit \ -space ${origspace} \ ${imed}/${segm_in_orig_pre} if ( ${DO_MODE_SMOO_W_REP} ) then # Modal smoothing *with* replacement; output has # INT_CMAP and tables copied @djunct_modal_smoothing_with_rep \ -overwrite ${DO_ECHO} \ -input ${imed}/${segm_in_orig_pre} \ -prefix ${segm_in_orig} \ -modesmooth ${modesmooth} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, @dj)" echo " ... for dset: ${segm_dset}" exit 1 endif else # Standard modal smoothing (*no* replacement) 3dLocalstat -overwrite \ -stat mode \ -nbhd "SPHERE(-${modesmooth})" \ -prefix ${segm_in_orig} \ ${imed}/${segm_in_orig_pre} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, loc)" echo " ... for dset: ${segm_dset}" exit 1 endif # make these show up in AFNI as labeled ROI or atlas datasets 3drefit \ -cmap INT_CMAP \ ${segm_in_orig} 3drefit \ -copytables ${segm_dset} \ ${segm_in_orig} if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, refit)" echo " ... for dset: ${segm_dset}" exit 1 endif endif endif # Image : [ulay] edge enhanced orig dset; # [olay] atlas warped to orig space set ulay = "${src_abbrev}.nii.gz" set olay = "${segm_in_orig}" set focus = ${src_abbrev}_mask.nii.gz set nvi = `3dinfo -nvi "${olay}"` if ( "${nvi}" == "0" ) then set opref = QC/${qc03}_${segm_type}_${segm_prefix}${src_add} @chauffeur_afni \ -ulay "${ulay}" \ -edge_enhance_ulay 0.5 \ -set_subbricks 0 0 0 \ -olay "${olay}" \ -box_focus_slices "${focus}" \ -montgap 1 \ -montcolor 'black' \ -XXXnpane 2048 \ -func_range 2048 \ -cbar ROI_glasbey_2048 \ -pbar_posonly \ -pbar_saveim "${opref}" \ -prefix "${opref}" \ -opacity 5 \ -montx 5 -monty 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 else foreach nn ( `seq 0 1 ${nvi}` ) set nnn = `printf %02d ${nn}` set opref = QC/${qc03}_${segm_type}_${segm_prefix}_${nnn} set opref = ${opref}${src_add} @chauffeur_afni \ -ulay "${ulay}" \ -edge_enhance_ulay 0.5 \ -set_subbricks 0 ${nn} ${nn} \ -olay "${olay}" \ -box_focus_slices "${focus}" \ -montgap 1 \ -montcolor 'black' \ -XXXnpane 2048 \ -func_range 2048 \ -cbar ROI_glasbey_2048 \ -pbar_posonly \ -pbar_saveim "${opref}" \ -prefix "${opref}" \ -opacity 5 \ -montx 5 -monty 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 end endif endif if ( "${segm_type}" == "SEG" ) then printf "%-37s : %s\n" \ "Seg follower in ${orig_fin}" \ "${segm_in_orig}" \ >> ${animal_outs} else if ( "${segm_type}" == "ATL" ) then printf "%-37s : %s\n" \ "Atlas follower in ${orig_fin}" \ "${segm_in_orig}" \ >> ${animal_outs} endif # ---------------- report info on atl/seg vols -------------------- if ( -f ${segm_in_orig} ) then # each atl dset could have multiple subbricks, like the # CHARM atlas for macaques set nvi = `3dinfo \ -nvi \ ${segm_in_orig}` foreach nn ( `seq 0 1 ${nvi}` ) set report = QC/report_${segm_prefix}.1D set surf_dir = surfaces_${segm_prefix} if ( ${nvi} > 0 ) then set nnn = `printf %02d ${nn}` set surf_dir = ${surf_dir}_${nnn} set report = QC/report_${segm_prefix}_${nnn}.1D endif set surf_path = surfaces/${surf_dir} # reports on sizes of ROIs *after* warping, relative to # those values *before* warping adjunct_aw_tableize_roi_info.py \ "${report}" \ "${segm_in_orig}[${nn}]" \ "${src_abbrev}_mask.nii.gz" \ "${segm_dset}[${nn}]" \ "${base_mask_for_reps}" \ "${modesmooth}" # ------- isosurfs in native space: only for ATLAS followers if ( ${status} ) then echo "** ERROR: program failed (base2osh atl/seg foll, table)" echo " ... for dset: ${segm_in_orig}" exit 1 endif if ( ( $make_orig_surfaces == "1" ) && \ ( -f ${segm_in_orig} ) ) then \rm -rf ${surf_path} \mkdir -p ${surf_path} cd ${surf_path} IsoSurface \ -isorois+dsets \ -o native.gii \ -input ../../${segm_in_orig}"[$nn]" \ -noxform \ -Tsmooth 0.01 6 cd - # [PT: Oct 16, 2020] put in SEG/ATL separately if ( "${segm_type}" == "SEG" ) then printf "%-37s : %s\n" \ "Seg follower surfs in ${orig_fin}" \ "${surf_path}" \ >> ${animal_outs} else if ( "${segm_type}" == "ATL" ) then printf "%-37s : %s\n" \ "Atlas follower surfs in ${orig_fin}" \ "${surf_path}" \ >> ${animal_outs} endif # a script to view all surfs together set oscript = surfaces/do_view_${surf_dir}.tcsh printf "" > ${oscript} cat <> ${oscript} #!/usr/bin/env tcsh # All files are defined here relative to the "surfaces/" directory # that originally contained this script. This can be adapted to other # cases, by adjusting the two variables defined at the top of the # script. set bkgd_vol = "../${src_abbrev}_nsu.nii.gz" set surf_dir = ${surf_dir} suma \ -onestate \ -i \${surf_dir}/native*.gii \ -vol "\${bkgd_vol}" & EOF chmod 755 ${oscript} endif end endif end # --------------- TEMPLATE SURFACE: in native space ------------------- if ( $make_orig_surfaces == "1" ) then # [PT: July 9, 2021] this needed in case no followers above used \mkdir -p surfaces # "carve" out template surface in native space instead to use # as representative surface using anisotropic smoothing could # use skullstripped original instead if ( ($ok_to_exist == "1") && \ (-f ${imed}/${templ_in_origA} ) ) then echo "++ Reusing anisotropically smoothed template" echo " in native space dataset" else 3danisosmooth -overwrite \ -prefix ${imed}/${templ_in_origA} \ -automask \ -3D \ -iters 6 \ -matchorig \ ${templ_in_orig} if ( ${status} ) then echo "** WARNING: program failed (templ surf, anisosmoo)" endif endif # also remove any small clusters for surface generation # (threshold here is specific so may need tweaking) set baseperc = 15 set basestats = `3dBrickStat \ -percentile $baseperc 1 $baseperc \ -non-zero \ ${imed}/${templ_in_origA}` if ( ${status} ) then echo "** WARNING: program failed (templ surf, brickstat)" endif set basethresh = $basestats[2] # non-zero count not right with percentile, so doing it # separately here set basestats2 = `3dBrickStat \ -max -count -non-zero \ ${imed}/${templ_in_origA}` set basemax = $basestats2[1] set minbrainvolume = `ccalc -int "${basestats2[2]}*0.5"` if ( ($ok_to_exist == "1") && \ (-f ${imed}/${templ_in_origAC} )) then echo "++ Reusing anisotropically smoothed and clustered template" echo " in native space dataset" else 3dClusterize \ -idat 0 -ithr 0 \ -1sided RIGHT_TAIL ${basethresh} \ -pref_dat ${imed}/${templ_in_origAC} \ -inset ${imed}/${templ_in_origA} \ -NN 2 \ -clust_nvox ${minbrainvolume} if ( ${status} ) then echo "** WARNING: program failed (templ surf, clust)" endif endif if ( ($ok_to_exist == "1") && \ (-f surfaces/${templ_in_origG} ) ) then echo "++ Reusing template in native space surface dataset" else IsoSurface -overwrite \ -isorange ${basethresh} ${basemax} \ -input ${imed}/${templ_in_origAC} \ -o surfaces/${templ_in_origG} \ -noxform \ -Tsmooth 0.01 6 if ( ${status} ) then echo "** WARNING: program failed (templ surf, isosurf)" endif endif printf "%-37s : %s\n" \ "Templ surf in ${orig_fin}" \ "surfaces/${templ_in_origG}" \ >> ${animal_outs} # move in to surfaces/ subdir for this step! cd surfaces # a script to view all surfs together set oscript = do_view_isosurf_${t_in_o_prefix}.tcsh printf "" > ${oscript} cat <> ${oscript} #!/usr/bin/env tcsh set bkgd_vol = "../${src_dset}" set dset_gii = "${templ_in_origG}" suma \ -onestate \ -i \${dset_gii} \ -vol \${bkgd_vol} & EOF chmod 755 ${oscript} cd - endif # ------------------------------ Clean up ---------------------------- # get rid of temporary warped datasets if ( "${keep_temp}" != "1") then \rm -rf "${awpy_dir}/" \rm -f `\ls __tmp*` \rm -f tempfollow.nii* echo "++ Done cleaning up." endif # --------------------------- Finish and exit ---------------------------- # finish outputs and exit gracefully: normal exit for default proc goto FINISH_OUTS # ------------------------------------------------------------------------- # Old Note (out of date variables....) # # zeropad the warp if segmentation doesn't cover the brain, and # reapply the warp: # 3dZeropad -S 50 -prefix ${src_prefix}_zp_WARP.nii.gz \ # ${src_prefix}_WARP.nii.gz # 3dNwarpApply -interp NN \ # -nwarp "${src_prefix}_inv.aff12.1D INV(${src_prefix}_zp_WARP.nii.gz)" \ # -source $segset -master $dset -prefix ${src_prefix}_seg_zp # 3drefit -cmap INT_CMAP ${src_prefix}_seg_zp${origview} # 3drefit -copytables $segset ${src_prefix}_seg_zp${origview} # --------------------------------------------------------------------------- HELP: cat << SCRIPT_HELP_STRING Overview ~1~ This is a script to: + align a subject structural dataset to a template + save the warp + inverse warps, for any future mapping + apply the warps to "follower" datasets in either space (e.g., atlases, segmentations, masks, or other anatomicals) to map those dsets to the other space - one common use: send a template atlas to native space + estimate surfaces of ROIs (with scripts also made to simplify viewing) + make automatic QC images to show the outputs, for quick evaluation This @animal_warper (AW) program uses basic AFNI commands to compute affine and nonlinear alignments. The program works by first aligning centers of the subject to that of the template. Affine and nonlinear alignment follow. The inverse warp is computed to bring the template and atlas segmentation into the center-shifted grid. Skullstripping is provided by masking with the template. Finally, the grids are adjusted back to the original center. Surfaces are made for all the atlas regions and for a transformed copy of the template dataset. Throughout this help file and output text files, note that the following terminology applies: AP = afni_proc.py AW = @animal_warper xform = transform NL = nonlinear aff = affine orig = 'original' (or native) subject data and/or space base = template and/or template space osh = original subject data/space shifted to base pshft = pre-shift (simple center of mass shift) to base shft = 'full' shift (includes aff align) to base warp2std = a dset now warped to standard/template space (from original) Usage Example ~1~ animal_warper \ -input macaque1+orig \ -base ../NMT.nii.gz \ -atlas atlas_dir/D99_atlas_1.2a_al2NMT.nii.gz \ -outdir aligned_data Note only the input dset and template_dset are *required*. If no "-atlas .." dset is given, then only the alignment steps are performed. Note also that you might want to include the "-ok_to_exist" flag, in case you need to restart the command at some point, and want to make use of previously created datasets (to save time). Options ~1~ -input input_dset :required input dataset to align to base template (what is called the 'source' in other AFNI alignment programs). -base base_dset :required dataset. Can be given with a normal path-specification, or by just being somewhere that @FindAfniDsetPath can find it. Note, this volume will also be used to try to skullstrip in the input dset (unless an explicit '-brainmask ..' dset is input; see that option below). -template_prefix TP :*no longer an option*. See/use '-base_abbrev', below. -outdir outputdir :create new directory and do all processing there. Minor note: '.' is not allowed; that is, you must choose a new directory. NB: the input, base and any atlas followers get copied into that directory (def = '${outdir}') -skullstrip brainmask :one can provide a brainmask that is in the base template space. This brainmask will be warped back to native space and used to skullstrip the original volume. This dataset should share exactly the same grid as the base template dataset. (If this opt isn't used to provide a brainmask, then the '-base ..' volume itself will be used to do so.) -atlas ATL1 ATL2 ATL3 ... -atlas_followers ATL1 ATL2 ATL3 ... :either of these option flags does the exact same thing-- one or more atlas (int-valued) dsets in the *base* volume space can be provided, and each will be mapped to the input dset's native space. Atlas labeling will be preserved. Additionally, isosurfaces of each that can be viewed in SUMA will be created. Atlas locations can be given with a normal path-specification, or by just being somewhere that @FindAfniDsetPath can find it. -seg_followers S1 S2 S3 ... :one or more (int-valued) dsets in the *base* volume space can be provided, and each will be mapped to the input dset's native space. Must share the same grid of the base dataset. Atlas labeling will be preserved. different than the atlas_followers above (no surfaces generated for these). -template_followers T1 T2 T3 ... :one or more dsets in the *base* volume space can be provided, and each will be mapped to the input dset's native space. Not required to be int-valued here. -dset_followers D1 D2 D3 ... :one or more dsets in the *input* volume space can be provided, and each will be mapped to the base dset's template space. Not required to be int-valued here. -roidset_followers dset1 dset2 ... :one or more (int-valued) dsets in the *input* volume space can be provided, and each will be mapped to the base dset's template space. -input_abbrev INP_ABBR :when a dset DSET is warped to a space, it will like DSET_in_SOMETHING.nii.gz. If that SOMETHING is the input dset space, then you can specify that label/abbreviation here. The INP_ABBR is also used for some files as SOMETHING_*. Default naming will be to use the prefix of the input dset, such as would come from: 3dinfo -prefix_noext INPUT_DSET Created file names can be quite long due to this, so an INP_ABBR might be useful. -base_abbrev BASE_ABBR :used just like the '-input_abbrev ..' value above, but for the base dset. Default here is to use the space information from a dset, namely: 3dinfo -space BASE_DSET See also the '-use_known_abbrev_*' options for being able to let this program try to recognize a commonly known dset from its name. -atlas_abbrevs AA1 AA2 AA3 ... :used just like the '-input_abbrev ..' value above, but for the atlas follower dsets. NB: you either need to have the same number of atlas abbreviations as input atlas followers, or none. Default abbreviation is: 3dinfo -prefix_noext ATLAS_DSET See also the '-use_known_abbrev_*' options for being able to let this program try to recognize a commonly known dset from its name. -template_abbrevs TA1 TA2 TA3 ... :used just like the '-atlas_abbrevs ..' opt above, but for the template follower dsets. Default abbreviation is: 3dinfo -prefix_noext TEMPLATE_DSET Has the same 'known' list as the base abbrevs, so make sure you don't run into having two files share the same abbrev! -seg_abbrevs SA1 SA2 SA3 ... :used just like the '-atlas_abbrevs ..' opt above, but for the seg follower dsets. Default abbreviation is: 3dinfo -prefix_noext SEG_DSET Has no 'known' abbrevs. -dset_abbrevs DA1 DA2 DA3 ... :used just like the '-atlas_abbrevs ..' opt above, but for the dset follower dsets. Default abbreviation is: 3dinfo -prefix_noext DSET_DSET Has no 'known' abbrevs. -roidset_abbrevs RA1 RA2 RA3 ... :used just like the '-atlas_abbrevs ..' opt above, but for the dset follower dsets. Default abbreviation is: 3dinfo -prefix_noext ROIDSET_DSET Has no 'known' abbrevs. -use_known_abbrev_base :try to 'guess' an appropriate abbreviation for a base dset as processing proceeds, for naming created dsets. Shares same list of knowns as the 'template' followers. -use_known_abbrev_atlas :try to 'guess' an appropriate abbreviation for an atlas dset as processing proceeds, for naming created dsets. -use_known_abbrev_template :try to 'guess' an appropriate abbreviation for a template follower dset as processing proceeds, for naming created dsets. Shares same list of knowns as the 'base'. -use_known_abbrev_ALL :like using all the other '-use_known_abbrev*' opts. -align_centers_meth ACM :By default, an early step here is to use "Align_Centers -grid .." to start the alignment (align centers of grids). If you want to, you can enter any of the "Center options" that @Align_Centers permits by using the given option in place of "ACM" *without* the preceding minus (e.g. a useful one might be: cm). You can also provide the keyword "OFF" as an argument, and then @Align_Centers won't be run at all (the dset is just copied at that step), which is useful if you have already centered your dataset nicely. -aff_move_opt AMO :by default, '-giant_move' is used in the affine alignment step (via align_epi_anat.py). With this option, you can change the movement type to be any of the values allowed by align_epi_anat.py--- note that you should *not* include the hyphen from the align_epi_anat.py option name, and if the option takes two terms, then you should put it in quotes, such as: "cmass cmass" (default: "giant_move"). A special value of "OFF" means that none of these extra movement options is included (e.g., your input dset overlaps the base VERY well already). -cost xxx :choose a cost function for affine and nonlinear alignment. The same or similar cost function will be used for both alignments. The cost functions are listed in the help for 3dAllineate and 3dQwarp. Cost functions, like lpa+ZZ for 3dAllineate, are not available in 3dQwarp, so the "+ZZ" part would removed from the NL part of warping (i.e., lpa would then be used for 3dQwarp's NL warping cost function). The default cost function is lpa+ZZ for affine warping (via align_epi_anat.py and 3dAllineate) and a clipped Pearson correlation for nonlinear warping (via auto_warp.py and 3dQwarp) -maxlev nn :maximum level for nonlinear warping. Determines final neighborhood 'patch' size that is matched+refined. Allowed values are: 0 <= nn <= 11 See 3dQwarp help for information on maxlev. Use smaller values for faster performance and testing. Increase up to 11 for finer warping. (def = ${maxlev}) -no_surfaces :do not make surfaces for atlas regions in native space. Default is to create a surface directory with surfaces of each region in native space. -feature_size mm :set size in mm for affine alignment. Use about 0.1 for mouse, 0.5 for macaque or rat. (def: 0.5) -supersize :allow for up to 50% size difference between subject and template -init_scale IS :useful if the input dset is much larger or smaller than the reference template. 'IS' is the approximate length ratio of the input to the template. So, if you align a baby shark (doo doo, doo doo doo doo) brain to an adult shark template brain, you might use this option with a value of 0.75, for example. -mode_smooth_size n :modal smoothing kernel size in voxels (not mm) This determines the size of a spatial regularization neighborhood for both ROI followers and segmentation datasets. Voxel values are replaced with the mode (most common value) in the spherical neighborhood. The default uses a 1 voxel radius. Use higher values depending on the irregularities of the edges of the regions and ROI Turn off by setting this to 0 -mode_smooth_replacement_off :the current default behavior for modal smoothing is to do both 1) modal smoothing (with 3dLocalstat) and then 2) check if any ROIs got lost in that process, and 3) if ROIs got lost, put them back in (those specific ones won't be smoothed, just re-placed). Using this opt will mean that steps #2 and #3 do NOT happen -- you just get plain modal smoothing without replacement. -center_out CO :center native-space output to native original space or to center-shifted space over the center of template. Allowed values of CO are 'native' (def, leaves center at original location) and 'center_shift' (shift the input toward base, and calculate all other warps and outputs to/from there). ****Note using the center_out native data transformations might require extra care. 3dNmatrix_apply may require vast amounts of memory if the center of the original dataset is far from the center of the template dataset, usually around an xyz coordinate of 0,0,0. If datasets are far from a center around 0,0,0, then consider using 3drefit -oblique_recenter 3drefit -oblique_recenter_raw or a preprocessing center alignment for all the native space datasets @Align_Centers -base template -dset mydset \ -child dset2 dset3 ... -align_type AT :provide alignment only to specified level, of which your choices are: rigid - align using rotation and translation rigid_equiv - compute alignment with full affine but apply only the rigid parameters. This is usually preferred over the rigid body alignment because it handles different sizes better. The purpose here is to put data into approximately the same position as the template (AC-PC, axialized, ...) affine - full affine, 12 parameters rotation, translation, shearing and scaling all - go through affine and nonlinear warps (default) In each case the full script runs. However, note that the detail of alignment (and quality of masking) from less-than-nonlinear warps will necessarily be more approximate. -extra_qw_opts "EQO" :specify other options to add on to the existing options for 3dQwarp either as a group of options in quotes as in "-nopenalty -workhard 0:3" or by repeated use of this option. 3dQwarp is called indirectly using auto_warp.py. -keep_temp :keep temporary files including awpy directory (from auto_warp.py) and other intermediate datasets -ver :display program version -ok_to_exist :reuse and do not overwrite existing datasets. This option is used for faster restarts or with limited alignment options -echo :copy all commands being run into the terminal (like running 'tcsh -x ...') Outputs (we got plenty of 'em!) ~1~ @animal_warper provides multiple outputs to assist in registering your anatomicals and associated MRI data to the template. Below, INP refers to the abbreviation used to refer to the "-input .." subject dset, and TEM to that of the "-base .." template (typically in some standard space). Main datasets ~2~ The following are all contained in the main output directory ("-outdir ..") + Text file "dictionary" reference of outputs o animal_outs.txt - guide to data in main dir and subdirs; contains version number and history of command run + Subject scans in native space of input o INP.nii.gz - copy of original input o INP_ns.nii.gz - same as above, but "no skull" (ns) version o INP_nsu.nii.gz - same as above, but also unifized (brightness) o INP_mask.nii.gz - mask of input (should match "ns" version) o DSET_FOLL - copy(s) of "-dset_followers .." (not abbrev) o ROIDSET_FOLL - copy(s) of "-roidset_followers .." (not abbrev) + Template scans in native space of input o TEM_in_INP.nii.gz - template aligned to input + Template followers (e.g., atlas ATL, segmentation SEG) in native space of input; could be several of each, each with own abbreviation o ATL_in_INP.nii.gz - "-atlas_followers .." aligned to input o SEG_in_INP.nii.gz - "-seg_followers .." aligned to input + Template dsets and followers in template space o TEMPLATE - copy of "-template .." (not abbrev) o TEMPLATE_MASK - copy of "-skullstrip .." mask (not abbrev) o ATL_FOLL - copy(s) of "-atlas_followers .." (not abbrev) o SEG_FOLL - copy(s) of "-seg_followers .." (not abbrev) o TEMPLATE_FOLL - copy of "-template_followers .." (not abbrev) + Subject scans mapped to the template o INP_warp2std.nii.gz - input dset nonlinearly warped to TEM o INP_warp2std_ns.nii.gz - same as above, but "no skull" version o INP_warp2std_nsu.nii.gz - same as above, but also unifized (brightness) + Alignment data (INP->TEM) o INP_composite_linear_to_template.1D - matrix, full affine part o INP_shft_WARP.nii.gz - NL warp part (TEM grid) + Alignment data (TEM->INP) o INP_composite_linear_to_template_inv.1D - matrix, full affine part o INP_shft_WARPINV.nii.gz - NL part of warp (TEM grid) QC info ~2~ The following are all contained in the "QC/" subdirectory. The following quality control (QC) images are automatically generated during processing, to help with speedy checking of processing. In each case, there are three sets of PNG montages (one for sag, cor and axi views) and a copy of the colorbar used (same prefix as file name, *.jpg). Additionally, there is also a *.txt file of ranges of values related to the ulay and olay, which might be useful for QC or figure-generation. + ${iqc00}*.jpg, [init_qc_00_*_DEOB*] [ulay] input source dset, original location [olay] base dset o single image montage to check initial overlap of source and base, ignoring any obliquity that might be present (i.e., the way AFNI GUI does by default, and also how alignment starts) o if initial overlap is not strong, alignment can fail or produce weirdness o *if* either dset has obliquity, then an image of both after deobliquing with 3dWarp is created (*DEOB.jpg), and a text file about obliquity is also created (*DEOB.txt). + ${iqc01}*.jpg [ulay] input source dset, center-shifted location [olay] base dset + ${iqc01b}*.jpg (only created if using '-init_scale ..') [ulay] same as previous ulay, but with init_scale value applied [olay] base dset + ${iqc02}*.jpg [ulay] input source dset, affine-aligned to base [olay] base dset + ${iqc03}*.jpg [ulay] input source dset, NL-aligned to base [olay] base dset + ${qc00}* (in base space) [ulay] edges of the base dset [olay] warped input dset + ${qc01}* (in input space) [ulay] edges of the (warped) base dset [olay] original input dset + ${qc02}* (in input space) [ulay] input dset [olay] estimated (or input) mask, showing skullstripping + ${qc03}_{ATL,SEG}* (in input space) [ulay] 'edge enhanced' original input dset [olay] warped atlas or seg dset o NB: if the olay dset has >1 subbrick, each will be snapshotted separately, because I heard the baying of the crowds for such. Additionally, if follower datasets are used (e.g., mapping atlases from template to subject space), then report*1D text files are also output, detailing information about ROIs before and after mapping. + report_{ATL,SEG}*.1D o this text file includes both absolute and relative volumes, as well as ratios of volumes. Additionally, one can see if any ROIs got lost in the mapping process (e.g., were too small or narrow, got squeezed too much or fell outside the mask). o this text file can be viewed in a regular text editor and also used for calculations with AFNI programs o each report calculated separately for each subbrick of an input ATL or SEG Surfaces generated ~2~ (Unless you turn off surface estimate) there will be a "surfaces/" directory with full sets of ROI surfaces calculated from the '-atlas_follower ..' and '-seg_follower ..' dsets. + surfaces_{ATL,SEG}*/ o full set of surfaces of each region in the respective dset o if the atlas has >1 subbrick (e.g., the CHARM), then each subbrick will have its own subdir + do_view_surfaces_{ATL,SEG}*.tcsh o automatically generated script to view the contents of each surfaces_{ATL,SEG}*/ directory in SUMA + TEM_in_INP.gii o slightly polished surface of the warped template in input space + do_view_isosurf_TEM_in_INP.tcsh o automatically generated script to view TEM_in_INP.gii in SUMA Intermediate results directory ~2~ There is an "intermediate/" directory with lots of intermediate warps, affine transforms and datasets. *If* you are supremely confident about your outputs, you can remove this directory to save space. **But** you should probably only do so if you really need to, because invariably once you delete it you will need to check something from it. That's just life. This directory is useful to keep around for asking questions, checking alignment (esp. checking if something went wrong), potentially debugging (not my fault!), etc. Comments ~2~ All atlas_points and labeltables on all input dsets should be passed along to their warped versions, preserving those useful functionalities and information. Integrating AW with afni_proc.py (AP) ~1~ Let's say that you plan to run AW as a prelude to processing FMRI data with AP (a good idea, by the way!). This might be an example AW command (written with variables in ye olde 'tcsh' style): set anat_subj = sub-001_anat.nii.gz # input anat set refvol = NMT_*_SS.nii.gz # ref: template set refatl = CHARM*.nii.gz # ref: atlas set odir_aw = dir_aw/sub-001 # output dir @animal_warper \ -input \${anat_subj} \ -base \${refvol} \ -atlas \${refatl} \ -outdir \${odir_aw} \ -ok_to_exist If you are mapping your FMRI data to standard space and using the "tlrc" block in your AP command, then there are probably 4 main outputs from there that you would then put into every successive AP command, as well as using the same "refvol" and noting that your anatomical dset has already been skullstripped. We highlight these in the following AP skeleton command (where the '...' means some other entries/options would likely be included; order doesn't matter for the AP command, but we are following the style in which most afni_proc.py help examples are written): | # root of AW output dsets | set anat_base = \`3dinfo -prefix_noext \${anat_subj}\` | | afni_proc.py \ | ... \ | -blocks ... align tlrc volreg ... \ | ... \ | -copy_anat \${odir_aw}/\${anat_base}_ns.nii.gz \ | -anat_has_skull no \ | ... \ | -tlrc_base \${refvol} \ | -tlrc_NL_warp \ | -tlrc_NL_warped_dsets \ | \${odir_aw}/\${anat_base}_warp2std_nsu.nii.gz \ | \${odir_aw}/\${anat_base}_composite_linear_to_template.1D \ | \${odir_aw}/\${anat_base}_shft_WARP.nii.gz \ | ... In the preceding, please note the naming conventions in the *.1D affine matrix and *WARP.nii.gz nonlinear warp dset which are provided to the '-tlrc_NL_warped_dsets ..' option. Examples ~1~ 1) Align a subject anatomical to the NMT template. Use some 'follower' datasets that are defined in the template space, so that they will be warped to subject space (there are other followers that can start in the native space and be warped to the standard space, too). Use abbreviations with the followers to simplify life: @animal_warper \ -input \${dir_anat}/anat-sub-000.nii.gz \ -input_abbrev \${subj}_anat \ -base \${dir_ref}/NMT_*_SS.nii.gz \ -base_abbrev NMT2 \ -atlas_followers \${dir_ref}/CHARM_*.nii.gz \ -atlas_abbrevs CHARM \ -seg_followers \${dir_ref}/NMT_*_segmentation.nii.gz \ -seg_abbrevs SEG \ -skullstrip \${dir_ref}/NMT_*_brainmask.nii.gz \ -outdir odir_aw \ -ok_to_exist 2) Just like the previous example, but include more followers and abbrevs: @animal_warper \ -input \${dir_anat}/anat-sub-000.nii.gz \ -input_abbrev \${subj}_anat \ -base \${dir_ref}/NMT_*_SS.nii.gz \ -base_abbrev NMT2 \ -atlas_followers \${dir_ref}/CHARM_*.nii.gz \ \${dir_ref}/D99_*.nii.gz \ -atlas_abbrevs CHARM D99 \ -seg_followers \${dir_ref}/NMT_*_segmentation.nii.gz \ -seg_abbrevs SEG \ -skullstrip \${dir_ref}/NMT_*_brainmask.nii.gz \ -outdir odir_aw \ -ok_to_exist 3) Just like the previous example, but include followers (dset and roidset) from subject space: @animal_warper \ -input \${dir_anat}/anat-sub-000.nii.gz \ -input_abbrev \${subj}_anat \ -base \${dir_ref}/NMT_*_SS.nii.gz \ -base_abbrev NMT2 \ -atlas_followers \${dir_ref}/CHARM_*.nii.gz \ \${dir_ref}/D99_*.nii.gz \ -atlas_abbrevs CHARM D99 \ -seg_followers \${dir_ref}/NMT_*_segmentation.nii.gz \ -seg_abbrevs SEG \ -skullstrip \${dir_ref}/NMT_*_brainmask.nii.gz \ -dset_followers \${dir_anat}/anat-t2w-sub-000.nii.gz \ -dset_abbrevs T2W \ -roidset_followers \${dir_anat}/parcels-sub-000.nii.gz \ -roidset_abbrevs ROIS \ -outdir odir_aw \ -ok_to_exist Demos, Tutorials and Online Docs ~1~ + See the MACAQUE_DEMO_* demos for examples in using the program, as well as integrating its outputs with afni_proc.py. To download the demos for task-based FMRI and resting state FMRI analysis, respectively: @Install_MACAQUE_DEMO @Install_MACAQUE_DEMO_REST ... with accompanying webpages here: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/nonhuman/macaque_demos/main_toc.html + For (growing) documentation on non-human dataset processing in AFNI, see: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/nonhuman/main_toc.html + For information on accompanying templates and atlases in the animal kingdon (such as NMT, CHARM and SARM), as well as how to download them, please see here: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/nonhuman/macaque_tempatl/main_toc.html References ~1~ If you use this program and/or the NMTv2, CHARM or ARM in your work, please cite the following: + Jung B, Taylor PA, Seidlitz PA, Sponheim C, Perkins P, Ungerleider LG, Glen DR, Messinger A (2021). A Comprehensive Macaque FMRI Pipeline and Hierarchical Atlas. NeuroImage 235:117997. https://doi.org/10.1016/j.neuroimage.2021.117997 https://www.biorxiv.org/content/10.1101/2020.08.05.237818v1 + Saad ZS, Glen DR, Chen G, Beauchamp MS, Desai R, Cox RW (2009). A new method for improving functional-to-structural MRI alignment using local Pearson correlation. Neuroimage 44 839–848. doi: 10.1016/j.neuroimage.2008.09.037 https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2649831/ If you use the SARM or ARM atlas, please cite the following: R. Hartig, D. Glen, B. Jung, N.K. Logothetis, G. Paxinos, E.A. Garza-Villarreal, A. Messinger, H. Evrard (2021). The Subcortical Atlas of the Rhesus Macaque (SARM) for Neuroimaging. NeuroImage 235:117996. https://doi.org/10.1016/j.neuroimage.2021.117996. If you use the D99 atlas (warped to the NMT v2 in this repository), please cite the following: C. Reveley, A. Gruslys, F.Q. Ye, D. Glen, J. Samaha, B.E. Russ, Z. Saad, A.K. Seth, D.A. Leopold, K.S. Saleem (2017). Three-Dimensional Digital Template Atlas of the Macaque Brain. Cereb. Cortex 27:4463-4477. https://doi.org/10.1093/cercor/bhw248. This program has been written (and rewritten!) by D Glen and PA Taylor (SSCC, NIMH, NIH, USA), with many helpful contributions and suggestions from B Jung and A Messinger. SCRIPT_HELP_STRING exit 0 # --------------------------------------- FINISH_OUTS: set stop_d = `date +%Y-%m-%d` set stop_H = `date +%H` set stop_M = `date +%M` set stop_S = `date +%S` set stop_VAL = "${stop_d} ${stop_H}:${stop_M}:${stop_S}" echo "# finish : ${stop_VAL}" >> log_cmd.txt echo "" >> ${animal_outs} printf "%-37s : %s\n" \ "QC directory of images" \ "QC/" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Info on atl/seg followers" \ "QC/report_*.1D" \ >> ${animal_outs} printf "%-37s : %s\n" \ "Scripts to view surfaces" \ "surfaces/do*.tcsh" \ >> ${animal_outs} echo "" >> ${animal_outs} echo "Command : @animal_warper $argv" >> ${animal_outs} echo "" echo "Highlights of the output" echo "------------------------" # show list of outputs cat ${animal_outs} echo "" echo "-------------------------" echo "" echo "++ To check the output, go to:" echo " cd ${outdir}" echo "" exit 0 # ------------------------------------------------------------------------- # "functions" ABBREV_CREATION_START: if ( ${#generic_followers} ) then # user enters ALL abbrevs or NONE. if ( ${#generic_abbrevs} == ${#generic_followers} ) then echo "++ Using user-entered list of ${foll_type}_follower abbrevs" else if ( ${#generic_abbrevs} == 0 ) then echo "++ Making list of '${foll_type}_follower' abbrevs:" foreach ff ( ${generic_followers} ) set ff_name = `3dinfo -prefix_noext "${ff}"` printf " ... ${ff_name}" if ( ${USE_KNOWN_GENERIC_ABBREV} ) then # go through our list of knowns foreach aa ( ${all_known_generic_abbrev} ) set gcount = `echo "${ff_name}" | grep -c "${aa}"` if ( "${gcount}" != "0" ) then set ff_name = "${aa}" break endif end endif printf " --> ${ff_name}\n" set generic_abbrevs = ( ${generic_abbrevs} "${ff_name}" ) end else echo "** ERROR:" echo " The number of ${foll_type}_follower" echo " abbrevs (${#generic_abbrevs}) must be 0 or match the" echo " number of ${foll_type}_followers (${#generic_followers})" exit 1 endif endif if ( "${foll_type}" == "atlas" ) then goto ABBREV_CREATION_END_ATLAS else if ( "${foll_type}" == "template" ) then goto ABBREV_CREATION_END_TEMPLATE else if ( "${foll_type}" == "seg" ) then goto ABBREV_CREATION_END_SEG else if ( "${foll_type}" == "dset" ) then goto ABBREV_CREATION_END_DSET else if ( "${foll_type}" == "roidset" ) then goto ABBREV_CREATION_END_ROIDSET else echo "** Someone forgot to code a new type here" exit 1 endif