#! /bin/sh
# (next line not seen by tcl) \
exec tclsh8.5 $0 ${1+"$@"}    # goto tcl8.5, wherever it is

### alternate 3rd line: but breaks standalone
#DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH exec tclsh $0 ${1+"$@"}  # goto my tcl

### runra: marty sereno -- run n recon-all's in bg, rotate new in when done
# 14/01/09 -- 01a: initial hack
# 14/01/10 -- 01b: cleanup, comment, bold start/stop msgs, ps uxww on Linux
# 14/10/20 -- 01c: save list of curr running subj names, use when one finishes
#N.B.: ctrl-C during test leaves tmpfile (don't bother w/TclX)

############################################################################
# 4 user-editable parms (don't change the variable names: e.g., sublist)
############################################################################
# list of subjects to reconstruct (recon-all will create these directories)
set sublist { \
 AMIELB ANNASH ANNSNI ARADAV AURRUS BENOHA CHAHAR CHALOC CHYHIL DAVRAU \
 ETHTIL FELPIC FLOHOC GEOSAN GRADEN HANMOR ISADES JACADD JOKHER JONTIL \
 JOSDAV LOLYOU NELCAM PHIKEL PHIPEL REBBRO RHITOM RHYHOL SALKRI VICKNO }

# dir outside SUBJECTS_DIR w/rawscan subject dirs in it w/same names as above
set rawdir /media/Data/Inverse/TessaData/MRI_RECON

# name of rawscan NIFTI files (currently req'd to be same for all)
set rawscan MPRAGE1.nii

# maximum number of background processes to run 
set maxprocs 6
############################################################################

### help
set log ./runra.[pid].log
set helpflag 1
set debugflag 0
if { [llength $argv] == 1 } {
  set arg [lindex $argv 0]
  if {$arg == "-test" || $arg == "-debug"} { set helpflag 0; set debugflag 1 }
  if {$arg == "-go"} { set helpflag 0 }
}
if {$helpflag} {
  puts ""
  puts "use: runra \[-go,-test\]"
  puts ""
  puts "  --cp script and edit 4 variables at top of it"
  puts "  --req's tclsh8.5 and MGH freesurfer setup (recon-all, etc on \$path)"
  puts "  --start/finish of each subj written to ./runra.<pid>.log"
  puts "  --option -test makes/runs small csh sleep script for demo"
  puts ""
  puts "  Example raw scan directories:"
  puts "    /tmp/rawdata/marty/MPRAGE1.nii"
  puts "    /tmp/rawdata/trevor/MPRAGE1.nii"
  puts "    /tmp/rawdata/tessa/MPRAGE1.nii"
  puts "  Resulting subject dirs:"
  puts "    \$SUBJECTS_DIR/marty"
  puts "    \$SUBJECTS_DIR/trevor"
  puts "    \$SUBJECTS_DIR/tessa"
  puts ""
  puts "  Current state of editable parms:"
  puts ""
  puts "   (1) sublist = $sublist"
  puts "   (2) rawdir = $rawdir"
  puts "   (3) rawscan = $rawscan"
  puts "   (4) maxprocs = $maxprocs"
  puts "                                                       version: 01c"
  exit
}

### internal
set chkinterval 15000   ;# 15sec
set prog recon-all
set tmpscript /tmp/TmpCshRunra.[pid]

### debug
if {$debugflag} {
  set prog $tmpscript
  set chkinterval 2000
  set sublist { marty paul trevor tessa joan }
  set maxprocs 3
  # make tmp script that takes some time to run
  set id [open $tmpscript w 0755]
  puts $id "#! /bin/csh -f"
  puts $id "set name = test"
  puts $id "if (\$#argv == 1) then"
  puts $id "  set name = \$argv\[1\]"
  puts $id "endif"
  puts $id "set i = 1"
  puts $id "while (\$i < 8)"
  puts $id "  sleep 2"
  puts $id "  echo \"from pid \$\$ for \$name\""
  puts $id "  @ i++"
  puts $id "end"
  puts $id "echo \"\$0 done\""
  close $id
}

### binary found on path (accepts "aliased to", new which: no resp to missing)
proc foundbywhich { somebinary } {
  catch {eval exec /usr/bin/which $somebinary} ret
  if { [string match "" $ret] || \
       [string match "*no $somebinary*" $ret] || \
       [string match "*child process exited abnormally*" $ret] } {
    return 0
  } else {
    return 1
  }
}

### check env, sublist, infiles
if {!$debugflag} {
  if ![foundbywhich $prog] {
    puts "runra: ### $prog not on \$path   ...quitting"
    exit
  }
  if ![info exists env(SUBJECTS_DIR)] {
    puts "runra: ### env variable SUBJECTS_DIR undefined (use setenv)"
    exit
  }
  set existing ""
  foreach sub $sublist {
    if [file exists $env(SUBJECTS_DIR)/$sub] {
      puts "runra: ### $sub already exists in $env(SUBJECTS_DIR)"
      set existing "$existing $sub"
    }
  }
  if {$existing != ""} { puts "runra: ###  ...quitting"; exit }
  set notfound 0
  foreach sub $sublist {
    if ![file exists $rawdir/$sub/$rawscan] {
      puts "runra: ### infile not found:"
      puts "  $rawdir/$sub/$rawscan\n"
      set notfound 1
    }
  }
  if {$notfound} {
    puts "\nrunra: ### one or more infiles missing   ...quitting\n"
    exit
  }
}

### wait confirm start
puts ""
puts "runra: subjects to recon:"
puts ""
foreach sub $sublist { puts "  $sub" }
puts ""
puts " => ctrl-D to go"
puts " => ctrl-C to quit"
set resp [read stdin]
puts ""
set msg "runra (tcl): starting: [exec date]"
puts $msg; exec echo $msg >> $log

### start up maxprocs
set subcnt [llength $sublist]
if {$subcnt < $maxprocs} { set maxprocs $subcnt }
for {set i 0} {$i < $maxprocs} {incr i} { set pids($i) -1 }
for {set i 0} {$i < $maxprocs} {incr i} { set subs($i) FINISHED }
set subnum 0
set i 0
for {set i 0} {$i < $maxprocs} {incr i} {
  set sub [lindex $sublist $subnum]
  ## run recon-all in bg
  set cmd "$prog -subjid $sub -all -i $rawdir/$sub/$rawscan &"
  if {$debugflag} { set cmd "$prog $sub &" }
  set pids($i) [eval exec $cmd]  ;# list curr running pids (cnt=$maxprocs)
  set subs($i) $sub              ;# parallel list of curr running subj names
  puts "\n###############################################################"
  set msg \
    "runra: start $prog in bg for subj [expr $subnum + 1]: $sub (pid=$pids($i))"
  puts $msg; exec echo $msg >> $log
  puts "###############################################################\n"
  incr subnum
}

### periodically check if any proc finishes, if subs left, start another
while {1} {
  for {set i 0} {$i < $maxprocs} {incr i} {
    set pid $pids($i)
    set psout -1
    if { $pid != -1 } {
      if { [exec uname] == "Darwin" } { ;# err to pipe: ps setuid/DYLD warning
        catch {set psout [exec ps uxww |& grep "$pid " | grep -v grep]}
      } elseif { [exec uname] == "Linux" } {
        catch {set psout [exec ps uxww |& grep "$pid " | grep -v grep]}
      } else {
        catch {set psout [exec ps af |& grep "$pid " | grep -v grep]} ;#oldsys5
      }
    }
    set pidnamerunning 0
    if [string match *${prog}* "$psout"] { set pidnamerunning 1 }
    if {!$pidnamerunning} { 
      if {"$pids($i)" != -1} {
        puts "\n##################################################"
        set msg "runra: subj: $subs($i) (pid=$pids($i))   ### FINISHED ###"
        puts $msg; exec echo $msg >> $log
        puts "##################################################\n"
      }
      set pids($i) -1
      if {$subnum < $subcnt} {
        set sub [lindex $sublist $subnum]
        ### run recon-all in bg
        set cmd "$prog -subjid $sub -all -i $rawdir/$sub/$rawscan &"
        if {$debugflag} { set cmd "$prog $sub &" }
        set pids($i) [eval exec $cmd]
        puts "\n###############################################################"
        set msg \
    "runra: start $prog in bg for subj [expr $subnum + 1]: $sub (pid=$pids($i))"
        puts $msg; exec echo $msg >> $log
        puts "###############################################################\n"
        incr subnum
      }
    }
  }
  # break if none left running
  set running 0
  for {set i 0} {$i < $maxprocs} {incr i} {
    if {$pids($i) != -1} { incr running }
  }
  if {!$running} { break }
  after $chkinterval   ;# wait for next check
}
if {$debugflag} { exec rm -f $tmpscript }
puts "\n###############################################################"
set msg "runra: done w/sublist: $sublist"
puts $msg; exec echo $msg >> $log
set msg "runra: finished: [exec date]"
puts $msg; exec echo $msg >> $log
puts "###############################################################\n"

