1#!/usr/local/bin/python3.8 2 3# python3 status: compatible 4 5# system libraries 6import sys, os 7 8try: sys.path.extend(['.', '%s/abin' % os.getenv('HOME')]) 9except: pass 10 11# AFNI libraries 12from afnipy import option_list as OPT 13from afnipy import afni_util as UTIL 14from afnipy import lib_subjects as SUBJ 15from afnipy import lib_vars_object as VO 16from afnipy import lib_surf_clustsim as CLUST 17 18# ---------------------------------------------------------------------- 19# globals 20 21g_command_help = """ 22============================================================================= 23slow_surf_clustsim.py - generate a tcsh script to run clustsim on surface 24 25------------------------------------------ 26 27 examples: ~1~ 28 29 1. basic: give 3 required inputs, all else is default ~2~ 30 31 While a blur of 4.0 is the default, it is included for clarity. 32 33 slow_surf_clustsim.py -save_script surf.clustsim \\ 34 -uvar spec_file sb23_lh_141_std.spec \\ 35 -uvar surf_vol sb23_SurfVol_aligned+orig \\ 36 -uvar blur 4.0 \\ 37 -uvar vol_mask mask_3mm+orig \\ 38 39 40 2. more advanced, but still based on EPI analysis ~2~ 41 42 Specify p-values, blur size and number of iterations, along with the 43 script name and results directory, use 10000 iterations, instead of 44 the default 1000. 45 46 slow_surf_clustsim.py -save_script surf.clustsim \\ 47 -uvar spec_file sb23_lh_141_std.spec \\ 48 -uvar surf_vol sb23_SurfVol_aligned+orig \\ 49 -uvar vol_mask mask_3mm+orig \\ 50 -uvar pthr_list 0.05 0.01 0.002 0.001 0.0002 0.0001 \\ 51 -uvar blur 8.0 \\ 52 -uvar niter 10000 \\ 53 -save_script csim.10000 \\ 54 -uvar results_dir clust.results.10000 55 56 57 3. basic, but on the surface (so no vol_mask is provided) ~2~ 58 59 slow_surf_clustsim.py -save_script surf.sim.3 \\ 60 -on_surface yes \\ 61 -uvar blur 3.0 \\ 62 -uvar spec_file sb23_lh_141_std.spec \\ 63 -uvar surf_vol sb23_SurfVol_aligned+orig 64 65 One can also add a surface mask via '-uvar surf_mask smask_lh.gii'. 66 67 68 Note: it is appropriate to use a volume mask on the same grid as the data to 69 be analyzed, which is to say either the EPI grid (for functional 70 analysis) or perhaps the anatomical grid (for anatomical analysis, 71 such as of thickness measures). 72 73 Note: the niter values should match between this program and 74 quick.alpha.vals.py. 75 76------------------------------------------ 77 78 applying the results: ~1~ 79 80 The result of processing should be one z.max.* file for each uncorrected 81 p-value input to the program (or each default). These files contain the 82 maximum cluster sizes (in mm^2), per z-score/p-value, and are named using 83 the corresponding p-value, e.g. z.max.area.0.001 corresponds to p=0.001. 84 85 To get the cluster size required for some uncorrected p-value, run 86 quick.alpha.vals.py on the z.max.area file corresponding to the desired 87 p-value, and note the cluster area required for the chosen corrected p. 88 89 For example, running this: 90 91 quick.alpha.vals.py -niter 1000 z.max.area.0.001 92 93 might show that a minimum cluster size of 113 mm^2 would correspond to a 94 corrected p=0.05. 95 96 Use of -niter should match that from slow_surf_clustsim.py. 97 98------------------------------------------ 99 100 script outline: ~1~ 101 102 set control variables 103 create and enter results directory 104 convert p-value list (pthr_list) to z-scores (zthr_list) 105 create dummy time series of length itersize 106 for each iter ( iteration list ) 107 3dcalc: generate noise volume 108 3dVol2Surf: map noise to surface 109 SurfSmooth: blur to FWHM 110 for each index ( itersize list ) 111 for each zthr ( zthr_list ) 112 SurfClust: make clust file clust.out.$iter.$index.$zthr 113 extract lists of maximum areas 114 115------------------------------------------ 116 117 terminal options: ~1~ 118 119 -help : show this help 120 -hist : show module history 121 -show_default_cvars : list default control variables 122 -show_default_uvars : list default user variables 123 -show_valid_opts : list valid options 124 -ver : show current version 125 126 other options: ~1~ 127 -on_surface yes/no : if yes, start from noise on the surface 128 (so no volume data is involved) 129 -print_script : print script to terminal 130 -save_script FILE : save script to given file 131 -uvar value ... : set the user variable 132 (use -show_default_uvars to see user vars) 133 -verb LEVEL : set the verbosity level 134 135----------------------------------------------------------------------------- 136R Reynolds June 2011 137============================================================================= 138""" 139 140 141class MyInterface: 142 """interface class for MyLibrary (whatever that is) 143 144 This uses lib_1D.py as an example.""" 145 def __init__(self, verb=1): 146 # main variables 147 self.status = 0 # exit value 148 self.valid_opts = None 149 self.user_opts = None 150 151 # general variables 152 self.verb = verb 153 154 # initialize valid_opts 155 self.valid_opts = self.get_valid_opts() 156 157 def get_valid_opts(self): 158 vopts = OPT.OptionList('valid opts') 159 160 # short, terminal arguments 161 vopts.add_opt('-help', 0, [], helpstr='display program help') 162 vopts.add_opt('-hist', 0, [], helpstr='display the modification history') 163 vopts.add_opt('-show_default_cvars',0,[],helpstr='show default cvars') 164 vopts.add_opt('-show_default_uvars',0,[],helpstr='show default uvars') 165 vopts.add_opt('-show_valid_opts',0,[],helpstr='display all valid options') 166 vopts.add_opt('-ver', 0, [],helpstr='display the current version number') 167 168 vopts.add_opt('-cvar', -2, [], helpstr='set control variable') 169 vopts.add_opt('-uvar', -2, [], helpstr='set user variable to value') 170 171 # general options 172 vopts.add_opt('-on_surface', 1, [], 173 acplist=['yes', 'no'], 174 helpstr='work directly on the surface (yes/no)') 175 vopts.add_opt('-print_script', 0, [], 176 helpstr='print script to terminal window') 177 vopts.add_opt('-save_script', 1, [], 178 helpstr='write script to given file') 179 vopts.add_opt('-verb', 1, [],helpstr='set the verbose level (default=1)') 180 181 return vopts 182 183 def process_options(self): 184 185 argv = sys.argv 186 187 if len(argv) == 0: # non-gui out 188 print(g_command_help) 189 return 1 190 191 # process any optlist_ options 192 self.valid_opts.check_special_opts(argv) 193 194 # process terminal options without the option_list interface 195 # (so that errors are not reported) 196 197 # if no arguments are given, apply -help 198 if len(argv) <= 1 or '-help' in argv: 199 print(g_command_help) 200 return 1 201 202 if '-hist' in argv: 203 print(CLUST.g_history) 204 return 1 205 206 if '-show_default_cvars' in argv: 207 CLUST.g_ctrl_defs.show('') 208 return 1 209 210 if '-show_default_uvars' in argv: 211 CLUST.g_user_defs.show('') 212 return 1 213 214 if '-show_valid_opts' in argv: 215 self.valid_opts.show('', 1) 216 return 1 217 218 if '-ver' in argv: 219 print(CLUST.g_version) 220 return 1 221 222 # ============================================================ 223 # read options specified by the user 224 self.user_opts = OPT.read_options(argv, self.valid_opts) 225 uopts = self.user_opts # convenience variable 226 if not uopts: return -1 # error condition 227 228 # ------------------------------------------------------------ 229 # init subject options struct 230 231 self.cvars = VO.VarsObject('control vars from command line') 232 self.uvars = VO.VarsObject('user vars from command line') 233 234 val, err = uopts.get_type_opt(int, '-verb') 235 if val != None and not err: self.verb = val 236 237 SUBJ.set_var_str_from_def('cvars', 'verb', ['%d'%self.verb], self.cvars, 238 defs=CLUST.g_ctrl_defs) 239 240 # first process all setup options 241 errs = 0 242 for opt in uopts.olist: 243 # skip -verb (any terminal option should block getting here) 244 if opt.name == '-verb': continue 245 246 # and skip and post-setup options (print command, save, etc.) 247 elif opt.name == '-print_script': continue 248 elif opt.name == '-save_script': continue 249 250 # now go after "normal" options 251 252 elif opt.name == '-on_surface': 253 val, err = uopts.get_string_list('', opt=opt) 254 if val == None or err: return -1 255 if self.cvars.set_var_with_defs(opt.name[1:],val,CLUST.g_ctrl_defs, 256 as_type=1, oname='cvars', verb=self.verb) < 0: 257 errs += 1 258 continue 259 260 # cvar requires at least 2 parameters, name and value 261 elif opt.name == '-cvar': 262 val, err = uopts.get_string_list('', opt=opt) 263 if val == None or err: return -1 264 # go after verb, in particular 265 if val[0] == 'verb': 266 try: self.verb = int(val[1]) 267 except: 268 print("** failed to set 'verb' level") 269 errs += 1 270 continue 271 # and set it from the form name = [value_list] 272 if SUBJ.set_var_str_from_def('cvars', val[0], val[1:], self.cvars, 273 CLUST.g_ctrl_defs, verb=self.verb) < 0: 274 errs += 1 275 continue 276 277 # uvar requires at least 2 parameters, name and value 278 elif opt.name == '-uvar': 279 val, err = uopts.get_string_list('', opt=opt) 280 if val == None or err: return -1 281 # and set it from the form name = [value_list] 282 if SUBJ.set_var_str_from_def('uvars', val[0], val[1:], self.uvars, 283 CLUST.g_user_defs, verb=self.verb) < 0: 284 errs += 1 285 continue 286 287 else: 288 print('** unknown option %s' % opt.name) 289 errs += 1 290 291 if self.verb > 2: 292 print('-' * 75) 293 self.uvars.show('post-init uvars', name=0) 294 self.cvars.show('post-init cvars', name=0) 295 print('-' * 75) 296 297 if errs: return -1 298 else: return 0 # no error, and continue on return 299 300 def execute(self): 301 302 if not self.ready_for_action(): return 1 303 304 if self.verb > 1: print('-- processing...') 305 306 uopts = self.user_opts 307 308 if uopts.find_opt('-print_script'): self.print_script() 309 310 opt = uopts.find_opt('-save_script') 311 if opt != None: 312 val, err = uopts.get_string_opt('', opt=opt) 313 if val != None and not err: self.save_script(val) 314 315 return 0 316 317 def ready_for_action(self): 318 """perform any final tests before execution""" 319 320 ready = 1 321 322 return ready 323 324 def print_script(self): 325 """create script and print to terminal""" 326 327 ctest, cmd = self.get_script() 328 print(cmd) 329 330 def save_script(self, fname): 331 332 ctest, cmd = self.get_script() 333 if cmd == '': return 334 335 if ctest.write_script(fname): 336 print('** failed to write slow_surf_clustsim script to disk') 337 338 def get_script(self): 339 """return the SurfClust object and script 340 (print warnings and errors to screen)""" 341 342 ctest = CLUST.SurfClust(self.cvars, self.uvars, argv=sys.argv) 343 344 nwarn, wstr = ctest.get_warnings() 345 status, mesg = ctest.get_script() 346 347 if status: # only show errors 348 print('%s\nERRORS:\n\n%s\n' % (75*'*', mesg)) 349 cmd = '' 350 else: 351 if wstr: print('%s\n**** Warnings:\n\n%s\n%s\n' % (75*'-',wstr,75*'-')) 352 cmd = '### surf clust script:\n\n%s\n' % mesg 353 354 return ctest, cmd 355 356 def test(self, verb=3): 357 print('------------------------ initial tests -----------------------') 358 self.verb = verb 359 360 print('------------------------ reset files -----------------------') 361 362 print('------------------------ should fail -----------------------') 363 364 print('------------------------ more tests ------------------------') 365 366 return None 367 368def main(): 369 me = MyInterface() 370 if not me: return 1 371 if me.status: return me.status 372 373 rv = me.process_options() 374 if rv > 0: return 0 # terminal success 375 if rv < 0: return 1 # terminal failure 376 # else rv == 0, so continue 377 378 rv = me.execute() 379 if rv > 0: return 1 380 381 return me.status 382 383if __name__ == '__main__': 384 sys.exit(main()) 385 386 387