#!/usr/bin/env python import sys, os, string import option_list, afni_util g_help_string = """ =========================================================================== Convert a set of 0/1 stim files into a set of stim_times files. Each input stim file can have a set of columns of stim classes, and multiple input files can be used. Each column of an input file is expected to have one row per TR, and a total of num_TRs * num_runs rows. The user must provide -files, -prefix, -nruns, -nt and -tr, where NT * NRUNS should equal (or be less than) the number of TR lines in each file. Note: Since the output times are LOCAL (one row per run) in the eyes of 3dDeconvolve, any file where the first stimulus is the only stimulus in that run will have '*' appended to that line, so 3dDeconvolve would treat it as a multi-run file. Sample stim_file with 3 stim classes over 7 TRs: 0 0 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 Corresponding stim_times files, assume TR = 2.5 seconds: stim.01.1D: 2.5 10 stim.02.1D: 5 7.5 stim.03.1D: 15 Options: -files file1.1D file2.1D ... : specify stim files -prefix PREFIX : output prefix for files -nruns NRUNS : number of runs -nt NT : number of TRs per run -tr TR : TR time, in seconds -offset OFFSET : add OFFSET to all output times -verb LEVEL : provide verbose output examples: 1. Given 3 stimulus classes, A, B and C, each with a single column file spanning 7 runs (with some number of TRs per run), create 3 stim_times files (stimes.01.1D, stimes.02.1D, stimes.02.1D) having the times, in seconds, of the stimuli, one run per row. make_stim_files -files stimA.1D stimB.1D stimC.1D \\ -prefix stimes -tr 2.5 -nruns 7 -nt 100 2. Same as 1, but suppose stim_all.1D has all 3 stim types (so 3 columns). make_stim_files -files stim_all.1D -prefix stimes -tr 2.5 \\ -nruns 7 -nt 100 3. Same as 2, but the stimuli were presented at the middle of the TR, so add 1.25 seconds to each stimulus time. make_stim_files -files stim_all.1D -prefix stimes -tr 2.5 \\ -nruns 7 -nt 100 -offset 1.25 4. An appropriate conversion of stim_files to stim_times for the example in AFNI_data2 (HowTo #5). make_stim_times.py -prefix stim_times -tr 1.0 -nruns 10 -nt 272 \\ -files misc_files/all_stims.1D - R Reynolds, Nov 17, 2006 =========================================================================== """ g_mst_history = """ make_stim_times.py history: 1.0 Dec 2006: initial release 1.1 Feb 02, 2007: - only print needed '*' (or two) for first run - added options -hist, -ver """ g_mst_version = "version 1.1, February 2, 2007" def get_opts(): global g_help_string okopts = option_list.OptionList('for input') okopts.add_opt('-help', 0, []) okopts.add_opt('-hist', 0, []) okopts.add_opt('-ver', 0, []) okopts.add_opt('-files', -1, [], req=1) okopts.add_opt('-prefix', 1, [], req=1) okopts.add_opt('-tr', 1, [], req=1) okopts.add_opt('-nt', 1, [], req=1) okopts.add_opt('-nruns', 1, [], req=1) okopts.add_opt('-offset', 1, []) okopts.add_opt('-verb', 1, []) okopts.trailers = 1 # if argv has only the program name, or user requests help, show it if len(sys.argv) <= 1 or '-help' in sys.argv: print g_help_string return # check for -ver and -hist, too if '-hist' in sys.argv: print g_mst_history return if '-ver' in sys.argv: print g_mst_version return opts = option_list.read_options(sys.argv, okopts) return opts def proc_mats(uopts): offset = 0.0 # offset for output times if uopts == None: return opt = uopts.find_opt('-verb') if opt: try: verb = int(opt.parlist[0]) except: print "** error: verb must be int, have '%s'" % opt.parlist[0] return else: verb = 0 opt = uopts.find_opt('-files') files = opt.parlist opt = uopts.find_opt('-nruns') nruns = int(opt.parlist[0]) opt = uopts.find_opt('-offset') if opt: try: offset = float(opt.parlist[0]) except: print "** error: offset must be float, have '%s'" % opt.parlist[0] return opt = uopts.find_opt('-prefix') prefix = opt.parlist[0] opt = uopts.find_opt('-tr') try: tr = float(opt.parlist[0]) except: print "** error: TR must be float, have '%s'" % opt.parlist[0] return opt = uopts.find_opt('-nt') try: nt = int(opt.parlist[0]) except: print "** error: -nt must be int, have '%s'" % opt.parlist[0] return if verb: print "-d nt = %d, nruns = %d, TR = %s" % (nt, nruns, str(tr)) newfile_index = 1 # index over output files for file in files: mat = afni_util.read_1D_file(file, -1, verb=verb) if not mat: print "read_1D_file failed for file: %s" % file return mat = afni_util.transpose(mat) if len(mat[0]) != nt * nruns: print 'warning: file %s has %d entries (expected %d)' % \ (file, len(mat[0]), nt*nruns) for row in mat: newp = "%s.%02d" % (prefix,newfile_index) newfile = afni_util.change_path_basename(file, newp, ".1D") if newfile == None: return fp = open(newfile, 'w') need_ast = 1 # '*' filler in case of 1 stim per run, max for run in range(nruns): rindex = run * nt # point to start of run if not 1 in row[rindex:rindex+nt]: # no stim in this run if run == 0: fp.write('* *\n') # first run gets 2 else: fp.write('*\n') continue time = 0 # in this run nstim = 0 # be sure we have more than 1 somewhere for lcol in range(nt): if row[rindex+lcol]: nstim += 1 fp.write('%s ' % str(time+offset)) time += tr if run == 1 and need_ast and nstim == 1: fp.write('*') # if first time has 1 stim, add '*' need_ast = 0 elif nstim > 1: need_ast = 0 # no worries fp.write('\n') fp.close() newfile_index += 1 if __name__ == "__main__": proc_mats(get_opts())