#!/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())
syntax highlighted by Code2HTML, v. 0.9.1