Index: trunk/tools/eam/itc.config/get.schema.sh
===================================================================
--- trunk/tools/eam/itc.config/get.schema.sh	(revision 42839)
+++ trunk/tools/eam/itc.config/get.schema.sh	(revision 42839)
@@ -0,0 +1,52 @@
+#!/bin/csh
+
+if ($#argv != 2) then
+   echo "USAGE: get.schema.sh (database) (password)"
+   exit 2
+endif
+
+which mariadb >& /dev/null
+@ has_mariadb = ($status == 0)
+
+which mysql >& /dev/null
+@ has_mysql = ($status == 0)
+
+set MYSQL = none
+if ($has_mariadb) then
+  set MYSQL = mariadb
+endif
+if (($has_mariadb == 0) && ($has_mysql)) then
+  set MYSQL = mysql
+endif
+
+echo "mysql is $MYSQL"
+
+set dbserver = ippdb05
+set dbuser = ippuser
+set dbname = $argv[1]
+set dbpass = $argv[2]
+
+# generate skycell entry (needed for xcsky and xccal queries)
+$MYSQL -h $dbserver -u $dbuser -p$dbpass $dbname <<EOF > tables.$dbname.txt
+  show tables
+EOF
+if ($status) then
+ echo "ERROR: failed in mysql load for $dbname"
+ exit 2
+ endif
+ 
+rm -f tables.$dbname.sql
+foreach f (`cat tables.$dbname.txt | awk '(NR > 1){print $1}'`)
+  echo "SHOW CREATE TABLE $f;" >> tables.$dbname.sql
+  echo -n "$f, "
+end
+echo ""
+
+# generate skycell entry (needed for xcsky and xccal queries)
+$MYSQL -N -h $dbserver -u $dbuser -p$dbpass $dbname < tables.$dbname.sql > create.$dbname.txt
+if ($status) then
+ echo "ERROR: failed in mysql load for $dbname"
+ exit 2
+ endif
+ 
+ 
Index: trunk/tools/eam/phosim/dvo.sh
===================================================================
--- trunk/tools/eam/phosim/dvo.sh	(revision 42839)
+++ trunk/tools/eam/phosim/dvo.sh	(revision 42839)
@@ -0,0 +1,310 @@
+
+macro load.Biprism.field.defocus
+
+  # 3 images:
+  # out/Biprism.focus.v3.01/Biprism.focus.v3.02_a_F02_f0_ch00_ch1_E000.fits : Mz = 2249.19
+  # out/Biprism.focus.v3.02/Biprism.focus.v3.03_a_F03_f0_ch00_ch1_E000.fits : Mz = 2249.24
+  # out/Biprism.focus.v3.03/Biprism.focus.v3.04_a_F04_f0_ch00_ch1_E000.fits : Mz = 2249.29
+
+  # rd i1 out/Biprism.focus.v3.02/Biprism.focus.v3.02_a_F02_f0_ch00_ch1_E000.fits
+  # rd i2 out/Biprism.focus.v3.03/Biprism.focus.v3.03_a_F03_f0_ch00_ch1_E000.fits
+  # rd i3 out/Biprism.focus.v3.04/Biprism.focus.v3.04_a_F04_f0_ch00_ch1_E000.fits
+
+  rd i1 out/Biprism.focus.v4.04/Biprism.focus.v4.04_a_F04_f0_ch00_ch1_E000.fits
+  rd i2 out/Biprism.focus.v4.05/Biprism.focus.v4.05_a_F05_f0_ch00_ch1_E000.fits
+  rd i3 out/Biprism.focus.v4.06/Biprism.focus.v4.06_a_F06_f0_ch00_ch1_E000.fits
+
+  for i 1 4
+    set li$i = log(i$i)
+  end
+end
+
+macro show.Biprism.field.defocus
+
+  dev -n tv
+  clear -s
+  section default -imtool none
+  resize {3*700+20} {3*400+20}
+
+  # focus.v4:
+  #  757 4144 -- -15 arcmin 
+  # 4244 4144
+  # 5642 4144 -- +6 arcmin (M2tilt moves images off FOV)
+
+  # focus.v3:
+  #  727 4143
+  # 4215 4143
+  # 7006 4143
+
+  section a00 0.000 0.000 0.333 0.333; section a00 -imtool none; tv li1 2.95 0.5; center  757 4144 6
+  section a10 0.333 0.000 0.333 0.333; section a10 -imtool none; tv li1 2.95 0.5; center 4244 4144 6
+  section a20 0.666 0.000 0.333 0.333; section a20 -imtool none; tv li1 2.95 0.5; center 5642 4144 6
+				   	     		    
+  section a01 0.000 0.333 0.333 0.333; section a01 -imtool none; tv li2 2.95 0.5; center  757 4144 6
+  section a11 0.333 0.333 0.333 0.333; section a11 -imtool none; tv li2 2.95 0.5; center 4244 4144 6
+  section a21 0.666 0.333 0.333 0.333; section a21 -imtool none; tv li2 2.95 0.5; center 5642 4144 6
+				   	     		    
+  section a02 0.000 0.666 0.333 0.333; section a02 -imtool none; tv li3 2.95 0.5; center  757 4144 6
+  section a12 0.333 0.666 0.333 0.333; section a12 -imtool none; tv li3 2.95 0.5; center 4244 4144 6
+  section a22 0.666 0.666 0.333 0.333; section a22 -imtool none; tv li3 2.95 0.5; center 5642 4144 6
+end
+
+macro load.LASF9.field.defocus
+
+  # 3 images:
+  # out/LASF9.focus.v3.v03/LASF9.focus.v3.v03_a_F03_f0_ch00_ch1_E000.fits : Mz = 2248.50
+  # out/LASF9.focus.v3.v04/LASF9.focus.v3.v04_a_F04_f0_ch00_ch1_E000.fits : Mz = 2248.55
+  # out/LASF9.focus.v3.v05/LASF9.focus.v3.v05_a_F05_f0_ch00_ch1_E000.fits : Mz = 2248.60
+
+  rd i1 out/LASF9.focus.v3.v03/LASF9.focus.v3.v03_a_F03_f0_ch00_ch1_E000.fits
+  rd i2 out/LASF9.focus.v3.v04/LASF9.focus.v3.v04_a_F04_f0_ch00_ch1_E000.fits
+  rd i3 out/LASF9.focus.v3.v05/LASF9.focus.v3.v05_a_F05_f0_ch00_ch1_E000.fits
+
+  for i 1 4
+    set li$i = log(i$i)
+  end
+end
+
+macro show.LASF9.field.defocus
+
+  dev -n tv
+  clear -s
+  section default -imtool none
+  resize {3*700+20} {3*400+20}
+
+  section a00 0.000 0.000 0.333 0.333; section a00 -imtool none; tv li1 2.95 0.5; center  665 4143 6
+  section a10 0.333 0.000 0.333 0.333; section a10 -imtool none; tv li1 2.95 0.5; center 4154 4143 6
+  section a20 0.666 0.000 0.333 0.333; section a20 -imtool none; tv li1 2.95 0.5; center 6947 4143 6
+				   	     		    
+  section a01 0.000 0.333 0.333 0.333; section a01 -imtool none; tv li2 2.95 0.5; center  665 4143 6
+  section a11 0.333 0.333 0.333 0.333; section a11 -imtool none; tv li2 2.95 0.5; center 4154 4143 6
+  section a21 0.666 0.333 0.333 0.333; section a21 -imtool none; tv li2 2.95 0.5; center 6947 4143 6
+				   	     		    
+  section a02 0.000 0.666 0.333 0.333; section a02 -imtool none; tv li3 2.95 0.5; center  665 4143 6
+  section a12 0.333 0.666 0.333 0.333; section a12 -imtool none; tv li3 2.95 0.5; center 4154 4143 6
+  section a22 0.666 0.666 0.333 0.333; section a22 -imtool none; tv li3 2.95 0.5; center 6947 4143 6
+end
+
+macro show.image
+  if ($0 != 2)
+    echo "USAGE: show.image (filename)"
+    break
+  end
+
+  dev -n sky
+  region 0 0 0.5
+  imbox -c blue -lw 2 $1
+
+  dev -n tv
+  rd im $1
+  tv im 900 500
+end
+
+macro make.filter
+  if ($0 != 4)
+    echo "USAGE: make.filter (output) (Wo) (dW)"
+    break
+  end
+
+  local Wmin Wmax
+  $Wmin = $2 - 0.5*$3
+  $Wmax = $2 + 0.5*$3
+
+  create w 0.2 1.0 0.001
+  set t = zero(w) + 1.0*((w > $Wmin) && (w < $Wmax))
+  set r = 1.0 - t
+  set a = zero(w)
+
+  write $1 a w t r
+end
+
+macro make.3band.filter
+  if ($0 != 2)
+    echo "USAGE: make.3band.filter (output)"
+    break
+  end
+
+  local Wmin Wmax
+  $W1min = 0.400
+  $W1max = 0.450
+  $W2min = 0.550
+  $W2max = 0.600
+  $W3min = 0.700
+  $W3max = 0.750
+
+  create w 0.2 1.0 0.001
+  set t = zero(w) + 1.0*((w > $W1min) && (w < $W1max)) + 1.0*((w > $W2min) && (w < $W2max)) + 1.0*((w > $W3min) && (w < $W3max))
+  set r = 1.0 - t
+  set a = zero(w)
+
+  write $1 a w t r
+end
+
+macro make.4band.filter
+  if ($0 != 2)
+    echo "USAGE: make.4band.filter (output)"
+    break
+  end
+
+  local Wmin Wmax
+  $W0min = 0.400
+  $W0max = 0.420
+  $W1min = 0.440
+  $W1max = 0.460
+  $W2min = 0.550
+  $W2max = 0.600
+  $W3min = 0.700
+  $W3max = 0.750
+
+  create w 0.2 1.0 0.001
+  set f0 = ((w > $W0min) && (w < $W0max))
+  set f1 = ((w > $W1min) && (w < $W1max))
+  set f2 = ((w > $W2min) && (w < $W2max))
+  set f3 = ((w > $W3min) && (w < $W3max))
+  set t = zero(w) + f0 + f1 + f2 + f3
+  set r = 1.0 - t
+  set a = zero(w)
+
+  write $1 a w t r
+end
+
+macro make.comb.filter
+  if ($0 != 2)
+    echo "USAGE: make.comb.filter (output)"
+    break
+  end
+
+  create w 0.2 1.01 0.0001
+
+  set t = zero(w)
+  for Wmin 0.30 1.01 0.10 -incl
+    set df = (w > $Wmin) && (w < $Wmin + 0.002)
+    set t = t + df
+  end
+  set r = 1.0 - t
+  set a = zero(w)
+
+  write $1 a w t r
+end
+
+macro get.comb
+ if ($0 != 2)
+  echo "USAGE: get.comb (dlambda)"
+  break
+ end
+
+ local dW
+ $dW = $1
+
+ # buffers are named i$dW 
+
+ $Fthresh = 15000
+
+ cut i$dW xc fc x 4070 4136 250 15
+
+ lim -n gr xc fc; clear; box; plot -x hist xc fc
+ line -c blue 4000 $Fthresh to 6000 $Fthresh
+
+ vpeaks fc xp_raw fp $Fthresh
+ set xp = xp_raw + xc[0]
+
+ plot -c red -pt ocir xp fp
+
+ set wp = 300 + $dW*ramp(xp) 
+
+ lim -n gw xp wp; clear; box; plot -pt cir -sz 2 -c red xp wp
+
+ # the first peak is the same wavelength for all
+ # there may be shifts, but all should have the same dispersion
+ set xp$dW = xp - xp[0]
+ set wp$dW = wp
+end
+
+macro get.disp
+
+  if (0)
+    get.comb 20
+    get.comb 50
+    get.comb 100
+  end
+
+  lim -n gw xp100 wp100; clear; box;
+  plot -pt cir -sz 2 -op 0.4 -c blue xp20 wp20
+  plot -pt cir -sz 2 -op 0.4 -c indigo xp50 wp50 
+  plot -pt cir -sz 2 -op 0.4 -c red xp100 wp100
+
+  subset xp20s = xp20 where (xp20 < 90)
+  subset wp20s = wp20 where (xp20 < 90)
+
+  subset xp50s = xp50 where (xp50 < 190)
+  subset wp50s = wp50 where (xp50 < 190)
+
+  delete -q xp_all wp_all
+  
+  concat xp20s xp_all
+  concat xp50s xp_all
+  concat xp100 xp_all
+
+  concat wp20s wp_all
+  concat wp50s wp_all
+  concat wp100 wp_all
+
+  plot -pt plus -c black -sz 2 xp_all wp_all
+
+  spline create disp xp_all wp_all
+  create xr 0 212
+  spline apply disp xr wr
+  plot -x line -c black xr wr
+
+  set wr_p = wr
+  set xr_p = xr
+  vroll wr_p
+  vroll xr_p
+  set dw = wr_p - wr
+  set dx = xr_p - xr
+  
+  set R = wr / (4 * dw / dx)
+end
+
+macro load.comb
+
+  rd i20 out/Biprism.comb.t1/Biprism.comb.t1_a_F05_f0_ch00_ch1_E000.fits
+  rd i50 out/Biprism.comb.t2/Biprism.comb.t2_a_F05_f0_ch00_ch1_E000.fits 
+  rd i100 out/Biprism.comb.t3/Biprism.comb.t3_a_F05_f0_ch00_ch1_E000.fits 
+
+  stat -q i20;   i20[4115][4139] = $MEDIAN
+  stat -q i50;   i50[4115][4139] = $MEDIAN
+  stat -q i100; i100[4115][4139] = $MEDIAN
+end
+
+# clean steps would be:
+# 300 -  400 :  20nm
+# 400 -  600 :  50nm
+# 600 - 1000 : 100nm
+
+macro make.newcomb.filter
+  if ($0 != 2)
+    echo "USAGE: make.newcomb.filter (output)"
+    break
+  end
+
+  create w 0.2 1.01 0.0001
+
+  set t = zero(w)
+  for Wmin 0.30 0.40 0.02 -incl
+    set df = (w > $Wmin) && (w < $Wmin + 0.002)
+    set t = t + df
+  end
+  for Wmin 0.45 0.65 0.05 -incl
+    set df = (w > $Wmin) && (w < $Wmin + 0.002)
+    set t = t + df
+  end
+  for Wmin 0.70 1.01 0.10 -incl
+    set df = (w > $Wmin) && (w < $Wmin + 0.002)
+    set t = t + df
+  end
+  set r = 1.0 - t
+  set a = zero(w)
+
+  write $1 a w t r
+end
Index: trunk/tools/eam/phosim/run.phosim
===================================================================
--- trunk/tools/eam/phosim/run.phosim	(revision 42839)
+++ trunk/tools/eam/phosim/run.phosim	(revision 42839)
@@ -0,0 +1,90 @@
+#!/bin/csh
+
+psconfig phosim
+
+set obsinst = instance-grid
+
+if ($#argv != 15) then
+  echo "USAGE: run.phosim (outdir) (obsid) (inst) (M2a-z) (L1a-z) (F2coat) (F2material) (F2aTilt) (F2bTilt) (F3coat) (F3material) (F3aTilt) (F3bTilt) (M2tip) (M2tilt)"
+  exit 2
+endif
+  
+set outdir = $1
+set obsid  = $2
+set instr  = $3
+
+set Mz     = $4
+set Lz     = $5
+
+set F2c    = $6	
+set F2m    = $7	
+set F2aT   = $8	
+set F2bT   = $9	
+set F3c    = $10
+set F3m    = $11
+set F3aT   = $12
+set F3bT   = $13
+set M2Tip  = $14
+set M2Tilt = $15
+
+if (-e $outdir) then
+  echo "ERROR: $outdir exists, exiting"
+  exit 2
+endif
+
+mkdir -p $outdir
+rsync -auv data/pan-base/ $outdir/
+
+set camdir = `basename $outdir`
+ln -s `pwd`/$outdir data/$camdir
+
+echo "obsid $obsid" >> $outdir/$obsinst
+
+rm -f $outdir/focalplanelayout.txt
+rm -f $outdir/segmentation.txt
+
+ln -s focalplanelayout.$instr.txt $outdir/focalplanelayout.txt
+ln -s segmentation.$instr.txt $outdir/segmentation.txt
+
+cat $outdir/optics_raw.txt | sed s/@Mz@/$Mz/ | sed s/@Lz@/$Lz/ | sed s/@F2coat@/$F2c/ | sed s/@F3coat@/$F3c/ | sed s/@F2mat@/$F2m/ | sed s/@F3mat@/$F3m/ > $outdir/optics_0.txt
+
+rm -f $outdir/perturbation.txt
+set dF2aT = `echo "($F2aT   > 0.00001) || ($F2aT   < -0.00001)" | bc`
+set dF2bT = `echo "($F2bT   > 0.00001) || ($F2bT   < -0.00001)" | bc`
+set dF3aT = `echo "($F3aT   > 0.00001) || ($F3aT   < -0.00001)" | bc`
+set dF3bT = `echo "($F3bT   > 0.00001) || ($F3bT   < -0.00001)" | bc`
+set dM2Tx = `echo "($M2Tip  > 0.00001) || ($M2Tip  < -0.00001)" | bc`
+set dM2Ty = `echo "($M2Tilt > 0.00001) || ($M2Tilt < -0.00001)" | bc`
+
+if ($dM2Tx) then
+  grep M2_tip $outdir/perturbation_raw.txt | sed s/@M2Tip@/$M2Tip/ >> $outdir/perturbation.txt
+endif
+if ($dM2Ty) then
+  grep M2_tilt $outdir/perturbation_raw.txt | sed s/@M2Tilt@/$M2Tilt/ >> $outdir/perturbation.txt
+endif
+if ($dF2aT) then
+  grep prism_F2a $outdir/perturbation_raw.txt | sed s/@F2aTilt@/$F2aT/ >> $outdir/perturbation.txt
+endif
+if ($dF2bT) then
+  grep prism_F2b $outdir/perturbation_raw.txt | sed s/@F2bTilt@/$F2bT/ >> $outdir/perturbation.txt
+endif
+if ($dF3aT) then
+  grep prism_F3a $outdir/perturbation_raw.txt | sed s/@F3aTilt@/$F3aT/ >> $outdir/perturbation.txt
+endif
+if ($dF3bT) then
+  grep prism_F3b $outdir/perturbation_raw.txt | sed s/@F3bTilt@/$F3bT/ >> $outdir/perturbation.txt
+endif
+
+echo $obsid $Mz $Lz $F2c $F2m $F2aT $F2bT $F3c $F3m $F3aT $F3bT > $outdir/params.txt
+
+if (0) then
+  echo ./phosim $outdir/$obsinst -c $outdir/noseeing -i $camdir -o $outdir > $outdir/phosim.log
+  ./phosim $outdir/$obsinst -c $outdir/noseeing -i $camdir -o $outdir >>& $outdir/phosim.log
+else 
+  echo ./phosim $outdir/$obsinst -c $outdir/quickbck-noseeing -i $camdir -o $outdir > $outdir/phosim.log
+  ./phosim $outdir/$obsinst -c $outdir/quickbck-noseeing -i $camdir -o $outdir >>& $outdir/phosim.log
+endif
+
+gunzip $outdir/*_a_*.gz
+rm $outdir/*_e_*.gz
+rm data/$camdir
Index: trunk/tools/eam/phosim/run.sequence.sh
===================================================================
--- trunk/tools/eam/phosim/run.sequence.sh	(revision 42839)
+++ trunk/tools/eam/phosim/run.sequence.sh	(revision 42839)
@@ -0,0 +1,372 @@
+#!/usr/bin/env mana
+
+$RUN_SCRIPT = focus.Biprism.v4
+
+# the M2 tilt sequence seems to be best for a tilt of 0.002 rad
+# now I want to scan the focus around that tilt
+macro focus.Biprism.v4
+
+ $tilt = 0.05
+ $M2tilt = 0.002
+
+ $dz = 0.01
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $i = 0
+ for noff -5 5 1 -incl
+    $Mz = $Mo + $noff*$dz
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Biprism.focus.v4.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid 8k $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0 0.0 $M2tilt
+    exec ./run.phosim $outdir $obsid 8k $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0 0.0 $M2tilt
+    $i ++
+  end
+end
+
+# difficult to judge the best focus
+# highest central core: 2249.24
+macro M2tilt.Biprism.v1
+
+ # prism wedge angle:
+ $tilt = 0.05
+
+ $dz = 0.05
+
+ # the best focus for the biprism is $Mo = 2249.24
+
+ # run a sequence with 0.5 mm of defocus:
+ $Mo = 2249.74
+ $dLM = 66.816
+
+ $i = 0
+ $dM2 = 0.001
+ for M2tilt 0.0 0.010 $dM2
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Biprism.M2tilt.v1.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid 8k $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0 0.0 $M2tilt 
+    exec ./run.phosim $outdir $obsid 8k $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0 0.0 $M2tilt
+    $i ++
+  end
+end
+
+# difficult to judge the best focus
+# highest central core: 2249.24
+macro focus.Biprism.v3
+
+ $tilt = 0.05
+
+ $dz = 0.05
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $i = 0
+ for noff -3 3 1 -incl
+    $Mz = $Mo + $noff*$dz
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Biprism.focus.v3.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro focus.LASF9.v3
+
+ $tilt = 0.02
+ $dz = 0.01
+ $Mo = 2248.60
+ $dLM = 66.816
+
+ $i = 31
+ for noff -4 5 1 -incl
+    $Mz = $Mo + $noff*$dz
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/LASF9.focus.v3.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.4band.txt LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.4band.txt LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro focus.LASF9.v2
+
+ $tilt = 0.05
+ $dz = 0.05
+ $Mo = 2248.5
+ $dLM = 66.816
+
+ for n 0 10
+    $Mz = $Mo + $n*$dz
+    $Lz = $dLM - $Mz
+
+    $i = $n + 20
+    sprintf outdir out/LASF9.focus.v2.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.4band.txt LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.4band.txt LASF9.txt $tilt 0.0
+  end
+end
+
+# best was: 2249.24
+macro disp.Biprism.v2
+
+ $tilt = 0.05
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $Mz = $Mo
+ $Lz = $dLM - $Mz
+
+ echo ./run.phosim out/Biprism.v2.4band.v00 F01 $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+ exec ./run.phosim out/Biprism.v2.4band.v00 F01 $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+end
+
+# difficult to judge the best focus
+# highest central core: 2249.24
+macro focus.Biprism.v2
+
+ $tilt = 0.05
+
+ $dz = 0.01
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $i = 30
+ for zoff -0.05 +0.05 $dz -incl
+    $Mz = $Mo + $zoff
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Biprism.focus.v2.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro tilt.Both.v2
+
+ $dt = 0.005
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $i = 0
+ for tilt 0.02 0.05 $dt -incl
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Both.tilt.v2.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+# best was: 2249.24
+macro disp.Biprism
+
+ $tilt = 0.02
+ $Mo = 2249.24
+ $dLM = 66.816
+
+ $Mz = $Mo
+ $Lz = $dLM - $Mz
+
+#echo ./run.phosim out/Biprism.3band F00 $Mz $Lz filt.3band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+#echo ./run.phosim out/Biprism.4band.v01 F01 $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+ echo ./run.phosim out/Biprism.4band.v02 F01 $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+ exec ./run.phosim out/Biprism.4band.v01 F01 $Mz $Lz filt.4band.txt BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+end
+
+# best was: 2249.24
+macro focus.Biprism
+
+ $tilt = 0.02
+
+ $dz = 0.01
+ $Mo = 2249.25
+ $dLM = 66.816
+
+ $i = 0
+ for zoff -0.05 +0.05 $dz -incl
+    $Mz = $Mo + $zoff
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Biprism.focus.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro tilt.Both
+
+ $dt = 0.005
+ $Mo = 2249.25
+ $dLM = 66.816
+
+ $i = 0
+ for tilt 0.0 0.02 $dt -incl
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/Both.tilt.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 $tilt none LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro focus.Both
+
+ $dz = 0.05
+ $Mo = 2249.2
+ $dLM = 66.816
+
+ $Noff = 5
+
+  for n {-$Noff} $Noff -incl
+    $Mz = $Mo + $n*$dz
+    $Lz = $dLM - $Mz
+
+    $i = $n + $Noff
+    sprintf outdir out/Both.focus.v2.%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 0.0 none LASF9.txt 0.0 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none BK7.txt 0.0 0.0 none LASF9.txt 0.0 0.0
+  end
+end
+
+macro tilt.LASF9.v2
+
+ $dt = 0.002
+ $Mo = 2248.6
+ $dLM = 66.816
+
+ $i = 0
+ for tilt 0.00 0.02 $dt -incl
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    # tilt the lower interface, what happens?
+    sprintf outdir out/LASF9.tilt.stars.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none LASF9.txt 0.0 $tilt
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none LASF9.txt 0.0 $tilt
+    $i ++
+  end
+end
+
+macro tilt.LASF9.v1
+
+ $dt = 0.005
+ $Mo = 2248.6
+ $dLM = 66.816
+
+ $i = 0
+ for tilt -0.02 0.02 $dt -incl
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    # tilt the lower interface, what happens?
+    sprintf outdir out/LASF9.tilt.F3b.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.750nm.txt LASF9.txt 0.0 $tilt
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.750nm.txt LASF9.txt 0.0 $tilt
+    $i ++
+  end
+end
+
+macro tilt.LASF9.v0
+
+ $dt = 0.005
+ $Mo = 2248.6
+ $dLM = 66.816
+
+ $i = 0
+ for tilt -0.02 0.02 $dt -incl
+    $Mz = $Mo
+    $Lz = $dLM - $Mz
+
+    # tilt the upper interface
+    sprintf outdir out/LASF9.tilt.F3a.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.750nm.txt LASF9.txt $tilt 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 filt.750nm.txt LASF9.txt $tilt 0.0
+    $i ++
+  end
+end
+
+macro focus.BK7
+
+ $dz = 0.1
+ $Mo = 2248.5
+ $dLM = 66.816
+
+ $Noff = 7
+
+  for n {-$Noff} $Noff -incl
+    $Mz = $Mo + $n*$dz
+    $Lz = $dLM - $Mz
+
+    $i = $n + $Noff
+    sprintf outdir out/BK7.focus.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none BK7.txt 0.0 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none BK7.txt 0.0 0.0
+  end
+end
+
+macro focus.LASF9
+
+ $dz = 0.1
+ $Mo = 2248.5
+ $dLM = 66.816
+
+ $Noff = 5
+
+  for n {-$Noff} $Noff -incl
+    $Mz = $Mo + $n*$dz
+    $Lz = $dLM - $Mz
+
+    $i = $n + $Noff
+    sprintf outdir out/LASF9.focus.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none LASF9.txt 0.0 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none LASF9.txt 0.0 0.0
+  end
+end
+
+macro focus.silica
+
+ $dz = 0.005
+ $Mo = 2248.2840
+ $dLM = 66.816
+
+  for i -3 3 -incl
+    $Mz = $Mo + $i*$dz
+    $Lz = $dLM - $Mz
+
+    sprintf outdir out/silica.focus.v%02d $i
+    sprintf obsid F%02d $i
+    echo ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none silica_dispersion.txt 0.0 0.0
+    exec ./run.phosim $outdir $obsid $Mz $Lz none air 0.0 0.0 none silica_dispersion.txt 0.0 0.0
+  end
+end
+
+if ($SCRIPT)
+  $RUN_SCRIPT  
+end
Index: trunk/tools/eam/xcstack.20231124/make.xcstack.sh
===================================================================
--- trunk/tools/eam/xcstack.20231124/make.xcstack.sh	(revision 42839)
+++ trunk/tools/eam/xcstack.20231124/make.xcstack.sh	(revision 42839)
@@ -0,0 +1,162 @@
+#!/bin/csh
+
+which mariadb >& /dev/null
+@ has_mariadb = ($status == 0)
+
+which mysql >& /dev/null
+@ has_mysql = ($status == 0)
+
+set MYSQL = none
+if ($has_mariadb) then
+  set MYSQL = mariadb
+endif
+if (($has_mariadb == 0) && ($has_mysql)) then
+  set MYSQL = mysql
+endif
+
+echo "mysql is $MYSQL"
+
+set dbserver = localhost
+set dbuser = ipp
+set dbpass = ipp
+
+# create 3 databases: two cameras and a xcamera
+# also need to create ippadmin entries to match these camera databases:
+$MYSQL -h $dbserver -u $dbuser -p$dbpass ippadmin <<EOF
+  delete from projects where projname = 'test_cam1';
+  delete from projects where projname = 'test_cam2';
+  delete from projects where projname = 'test_xcam';
+  insert into projects (projname) values ('test_cam1');
+  insert into projects (projname) values ('test_cam2');
+  insert into projects (projname) values ('test_xcam');
+  drop database if exists test_cam1;
+  drop database if exists test_cam2;
+  drop database if exists test_xcam;
+  create database test_cam1;
+  create database test_cam2;
+  create database test_xcam;
+EOF
+
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam1 < make.xcstack.sql
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam2 < make.xcstack.sql
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_xcam < make.xcstack.sql
+
+# insert data into the stack tables
+
+set mydir = `pwd`
+
+# three different stacks (one same filter & different skycell, one same skycell & different filter)
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam1 <<EOF
+  insert into warpRun (warp_id, state, workdir, label)              values (1, 'full', '$mydir/warps.sample.gpc1', 'Test.Label.Cam1');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (1, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc1/o5283g0266o.152638.wrp.1009477.skycell.2479.024');
+  insert into warpRun (warp_id, state, workdir, label)              values (2, 'full', '$mydir/warps.sample.gpc1', 'Test.Label.Cam1');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (2, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc1/o5283g0278o.152648.wrp.1009478.skycell.2479.024');
+  insert into warpRun (warp_id, state, workdir, label)              values (3, 'full', '$mydir/warps.sample.gpc1', 'Test.Label.Cam1');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (3, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc1/o5651g0398o.319286.wrp.1009479.skycell.2479.024');
+  insert into stackRun (stack_id, state, workdir, label, skycell_id, tess_id, filter) values (1, 'full', '$mydir', 'Test.Label.Cam1', 'skycell.2479.024', 'Fake.Tess', 'g');
+  insert into stackSumSkyfile (stack_id, path_base, good_frac, fault, quality) values (1, '$mydir/skycell.2479.024.ps1', 0.95, 0, 0);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 1);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 2);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 3);
+EOF
+
+# these stacks are each supposed to match the cam1 stacks above
+# three different stacks (one same filter & different skycell, one same skycell & different filter)
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam2 <<EOF
+  insert into warpRun (warp_id, state, workdir, label)              values (1, 'full', '$mydir/warps.sample.gpc2', 'Test.Label.Cam2');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (1, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc2/o60033h0313o.551799.wrp.493182.skycell.2479.024');
+  insert into warpRun (warp_id, state, workdir, label)              values (2, 'full', '$mydir/warps.sample.gpc2', 'Test.Label.Cam2');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (2, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc2/o60033h0338o.551824.wrp.493207.skycell.2479.024');
+  insert into warpRun (warp_id, state, workdir, label)              values (3, 'full', '$mydir/warps.sample.gpc2', 'Test.Label.Cam2');
+  insert into warpSkyfile (warp_id, skycell_id, tess_id, path_base) values (3, 'skycell.2479.024', 'Fake.Tess', '$mydir/warps.sample.gpc2/o60033h0363o.551849.wrp.493231.skycell.2479.024');
+  insert into stackRun (stack_id, state, workdir, label, skycell_id, tess_id, filter) values (1, 'full', '$mydir', 'Test.Label.Cam2', 'skycell.2479.024', 'Fake.Tess', 'g');
+  insert into stackSumSkyfile (stack_id, path_base, good_frac, fault, quality) values (1, '$mydir/skycell.2479.024.ps2', 0.95, 0, 0);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 1);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 2);
+  insert into stackInputSkyfile (stack_id, warp_id) values (1, 3);
+EOF
+
+# generate skycell entry (needed for xcsky and xccal queries)
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_xcam <<EOF
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, glong, glat, width, height) values ('Fake.Tess', 'skycell.2479.024', 200.412, 60.9857, 116.426, 55.7593, 0.433333, 0.438819);
+  insert into dbversion (schema_version) values ('0.1');
+EOF
+
+# define the xcameras:
+xcstacktool -dbname test_cam1 -addcamera -xcamera test_xcam
+xcstacktool -dbname test_cam2 -addcamera -xcamera test_xcam
+
+# define the xcameras:
+xcstacktool -dbname test_xcam -addcamera -xcamera test_cam1
+xcstacktool -dbname test_xcam -addcamera -xcamera test_cam2
+
+# define a xcstack:
+xcstacktool -dbname test_xcam -definebyquery -xcamera test_cam1 -set_workdir $mydir -set_label Test.xcstack
+xcstacktool -dbname test_xcam -addbyquery -xcamera test_cam2 -select_skycell_id skycell.2479.024 -select_instack_filter g -select_xcstack_filter g
+
+xcstacktool -dbname test_xcam -tosum > xcstack.md
+set stk_id = `grep xcstack_id xcstack.md | awk '{print $3}'`
+set workdir = `grep workdir xcstack.md | awk '{print $3}'`
+
+## run xcstack_skycell.pl or fake it
+if (0) then
+  # manually run xcstack : note the camera must match a real camera in ippconfig/system.conf
+  xcstack_skycell.pl --dbname test_xcam --xcstack_id $stk_id --outroot $workdir/test.xcs.v0 --run-state new --camera GPC1
+endif
+  # pretend to run xcstack
+  xcstacktool -dbname test_xcam -addsumskyfile -path_base $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.stk.1 -hostname elepaio -dtime_script 45.9999994374812 -xcstack_id $stk_id
+endif
+
+# if neither of the above are set, use pantasks to run xcstack
+xcskytool -dbname test_xcam -definebyquery -select_xcstack_id 1 -set_workdir $mydir/xcsky -set_label Test.xcsky
+
+xcskytool -dbname test_xcam -todo -label Test.xcsky
+
+xcskytool -dbname test_xcam -updaterun -label Test.xcsky -set_data_group foo -set_dist_group bar -set_note myNote
+
+xcskytool -dbname test_xcam -todo -label Test.xcsky > xcsky.md
+set sky_id = `grep xcsky_id xcsky.md | awk '{print $3}'`
+cat xcsky.md
+
+xcskytool -dbname test_xcam -inputs -xcsky_id $sky_id > xcsky.md
+set workdir = `grep workdir xcsky.md | awk '{print $3}'`
+cat xcsky.md
+
+## run xcsky.pl or fake it
+if (0) then
+  xcsky.pl --dbname test_xcam --xcsky_id $sky_id --outroot $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1 --camera GPC1
+else
+  xcskytool -dbname test_xcam -addresult -path_base $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1 -hostname foobar -dtime_script 30 -dtime_phot 28 -sources 100 -num_inputs 1 -good_frac 0.5 -xcsky_id $sky_id
+endif
+
+xcskytool -dbname test_xcam -result -xcsky_id $sky_id
+
+if (0) then
+  xcskytool -dbname test_xcam -updateresult -xcsky_id 1 -fault 1
+  xcskytool -dbname test_xcam -updaterun -xcsky_id 1 -set_state new
+  xcskytool -dbname test_xcam -revert -xcsky_id 1
+endif
+
+# NOTE: xccalRun inherits the label, data_group, dist_group, reduction from xcskyRun
+xcskytool -dbname test_xcam -definexccalrun -select_xcsky_id 1
+
+xcskytool -dbname test_xcam -pendingxccalrun -label Test.xcsky > xccal.md
+set cal_id = `grep xccal_id xccal.md | awk '{print $3}'`
+cat xccal.md
+
+## run xccal.pl or fake it
+if (0) then
+  echo xccal.pl --xccal_id 1 --xcstack_id 1 --outroot $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.cal.1 --path_base $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1 --camera GPC1 --dbname test_xcam
+       xccal.pl --xccal_id 1 --xcstack_id 1 --outroot $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.cal.1 --path_base $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1 --camera GPC1 --dbname test_xcam
+else
+  xcskytool -dbname test_xcam -addxccalresult -xccal_id 1 -path_base $workdir/Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.cal.1 -hostname foobaz -zpt_obs 25.0
+endif
+
+xcskytool -dbname test_xcam -xccalresult -xccal_id $cal_id
+
+if (0) then
+  xcskytool -dbname test_xcam -updatexccal    -xccal_id 1 -set_fault 1
+  xcskytool -dbname test_xcam -updatexccalrun -xccal_id 1 -set_state new
+  xcskytool -dbname test_xcam -revertxcal -xccal_id 1
+endif
+
Index: trunk/tools/eam/xcstack.20231124/make.xcstack.sql
===================================================================
--- trunk/tools/eam/xcstack.20231124/make.xcstack.sql	(revision 42839)
+++ trunk/tools/eam/xcstack.20231124/make.xcstack.sql	(revision 42839)
@@ -0,0 +1,425 @@
+
+-- input test tables do not have auto_increment keys or foreign key constraints
+
+CREATE TABLE dbversion (
+    schema_version VARCHAR(64),
+    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE skycell (
+    tess_id     VARCHAR(64),
+    skycell_id  VARCHAR(64),
+    radeg       float,
+    decdeg      float,
+    glong       float,
+    glat        float,
+    width       float,
+    height      float,
+    PRIMARY KEY (tess_id, skycell_id),
+    KEY(radeg),
+    KEY(decdeg),
+    KEY(glong),
+    KEY(glat)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+CREATE TABLE Label (
+    label       VARCHAR(64),
+    priority    INT,
+    active      TINYINT,
+    comment     VARCHAR(80),
+    PRIMARY KEY(label),
+    KEY(priority),
+    KEY(active)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE rawExp (
+    exp_id BIGINT,
+    exp_name VARCHAR(64),
+    camera VARCHAR(64),
+    filter VARCHAR(64)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE chipRun (
+    chip_id BIGINT,
+    exp_id BIGINT
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE camRun (
+    cam_id BIGINT,
+    chip_id BIGINT
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE fakeRun (
+    fake_id BIGINT,
+    cam_id BIGINT
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE warpRun (
+    warp_id BIGINT, 
+    fake_id BIGINT,
+    mode VARCHAR(64),
+    state VARCHAR(64),
+    workdir VARCHAR(255),
+    workdir_state VARCHAR(64),
+    label VARCHAR(64),
+    data_group VARCHAR(64),
+    dist_group VARCHAR(64),
+    dvodb VARCHAR(255),
+    tess_id VARCHAR(64),
+    reduction VARCHAR(64),
+    end_stage VARCHAR(64),
+    registered DATETIME,
+    magicked BIGINT,
+    software_ver VARCHAR(16),
+    maskfrac_npix FLOAT,
+    maskfrac_static FLOAT,
+    maskfrac_dynamic FLOAT,
+    maskfrac_magic FLOAT,
+    maskfrac_advisory FLOAT,
+    note VARCHAR(255),
+    PRIMARY KEY(warp_id),
+    KEY(warp_id),
+    KEY(fake_id),
+    KEY(mode),
+    KEY(state),
+    KEY(workdir_state),
+    KEY(label),
+    KEY(data_group),
+    KEY(dist_group),
+    KEY(end_stage)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE warpSkyCellMap (
+    warp_id BIGINT,
+    skycell_id VARCHAR(64),
+    tess_id VARCHAR(64),
+    class_id VARCHAR(64),
+    fault SMALLINT,
+    PRIMARY KEY(warp_id, skycell_id, tess_id, class_id),
+    KEY(fault)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE warpImfile (
+    warp_id BIGINT,
+    skycell_id VARCHAR(64),
+    warp_skyfile_id BIGINT,
+    PRIMARY KEY(warp_id, skycell_id),
+    KEY(warp_skyfile_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE warpSkyfile (
+    warp_id BIGINT,
+    skycell_id VARCHAR(64),
+    tess_id VARCHAR(64),
+    uri VARCHAR(255),
+    path_base VARCHAR(255),
+    data_state VARCHAR(64),
+    bg DOUBLE,
+    bg_stdev DOUBLE,
+    dtime_warp FLOAT,
+    dtime_script FLOAT,
+    hostname VARCHAR(64),
+    good_frac FLOAT,
+    xmin INT,
+    xmax INT,
+    ymin INT,
+    ymax INT,
+    quality SMALLINT NOT NULL DEFAULT 0,
+    fault SMALLINT,
+    magicked BIGINT,
+    software_ver VARCHAR(16),
+    maskfrac_npix INT,
+    maskfrac_static FLOAT,
+    maskfrac_dynamic FLOAT,
+    maskfrac_magic FLOAT,
+    maskfrac_advisory FLOAT,
+    background_model SMALLINT,
+    PRIMARY KEY(warp_id, skycell_id, tess_id),
+    KEY(good_frac),
+    KEY(fault),
+    KEY(quality),
+    KEY(data_state)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE stackRun (
+        stack_id BIGINT,
+        state VARCHAR(64),
+        workdir VARCHAR(255),
+        label VARCHAR(64),
+        data_group VARCHAR(64),
+        dist_group VARCHAR(64),
+        reduction VARCHAR(64),
+        dvodb VARCHAR(255),
+        registered DATETIME,
+        skycell_id VARCHAR(64),
+        tess_id VARCHAR(64),
+        filter VARCHAR(64),
+        software_ver VARCHAR(16),
+        note VARCHAR(255),
+        PRIMARY KEY(stack_id),
+        KEY(stack_id),
+        KEY(state),
+        KEY(skycell_id),
+        KEY(tess_id),
+        KEY(label),
+        KEY(data_group),
+        KEY(dist_group)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE stackInputSkyfile (
+        stack_id BIGINT,
+        warp_id BIGINT,
+        PRIMARY KEY(stack_id, warp_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE stackSumSkyfile (
+        stack_id BIGINT,
+        uri VARCHAR(255),
+        path_base VARCHAR(255),
+        bg DOUBLE,
+        bg_stdev DOUBLE,
+        dtime_stack FLOAT,
+        dtime_match_mean FLOAT,
+        dtime_match_stdev FLOAT,
+	dtime_convolve FLOAT,
+        dtime_initial FLOAT,
+        dtime_reject FLOAT,
+        dtime_final FLOAT,
+        dtime_phot FLOAT,
+        dtime_script FLOAT,
+        match_mean FLOAT,
+        match_stdev FLOAT,
+        match_rms FLOAT,
+        stamps_mean FLOAT,
+        stamps_stdev FLOAT,
+        stamps_min INT,
+        reject_images INT,
+        reject_pix_mean FLOAT,
+        reject_pix_stdev FLOAT,
+        sources INT,
+        hostname VARCHAR(64),
+        good_frac FLOAT,
+        mjd_obs DOUBLE,
+        fault SMALLINT,
+        software_ver VARCHAR(16),
+	background_model SMALLINT,
+        quality SMALLINT NOT NULL DEFAULT 0,
+        PRIMARY KEY(stack_id),
+        KEY(dtime_stack),
+        KEY(good_frac),
+        KEY(fault),
+        KEY(quality)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcstackRun (
+        xcstack_id BIGINT AUTO_INCREMENT,
+        state VARCHAR(64),
+        workdir VARCHAR(255),
+        label VARCHAR(64),
+        data_group VARCHAR(64),
+        dist_group VARCHAR(64),
+        reduction VARCHAR(64),
+        registered DATETIME,
+        skycell_id VARCHAR(64),
+        tess_id VARCHAR(64),
+        filter VARCHAR(64),
+        software_ver VARCHAR(16),
+        note VARCHAR(255),
+        PRIMARY KEY(xcstack_id),
+        KEY(xcstack_id),
+        KEY(state),
+        KEY(skycell_id),
+        KEY(tess_id),
+        KEY(label),
+        KEY(data_group),
+        KEY(dist_group)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcstackInputSkyfile (
+        xcstack_id BIGINT,
+        camera_id BIGINT,
+        stack_id BIGINT,
+        PRIMARY KEY(xcstack_id, camera_id, stack_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcstackSumSkyfile (
+        xcstack_id BIGINT,
+        path_base VARCHAR(255),
+        bg DOUBLE,
+        bg_stdev DOUBLE,
+        dtime_stack FLOAT,
+        dtime_script FLOAT,
+        hostname VARCHAR(64),
+        good_frac FLOAT,
+        fault SMALLINT,
+        software_ver VARCHAR(16),
+        quality SMALLINT NOT NULL DEFAULT 0,
+        PRIMARY KEY(xcstack_id),
+        KEY(dtime_stack),
+        KEY(good_frac),
+        KEY(fault),
+        KEY(quality)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcstackCamera (
+        camera_id BIGINT AUTO_INCREMENT,
+        camera VARCHAR(255),
+        PRIMARY KEY(camera_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- A static sky analysis set
+CREATE TABLE xcskyRun (
+      xcsky_id BIGINT AUTO_INCREMENT, -- unique identifier
+      state VARCHAR(64) NOT NULL,  -- state of run (new, full, etc.)
+      workdir VARCHAR(255) NOT NULL, -- working directory
+      label VARCHAR(64),             -- processing label
+      data_group VARCHAR(64),        -- group for data
+      dist_group VARCHAR(64),        -- group for distribution
+      reduction VARCHAR(64),         -- reduction class (for altering recipe)
+      note VARCHAR(255),             -- note
+      registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- time run was registered
+      PRIMARY KEY(xcsky_id),
+      KEY(state),
+      KEY(label),
+      KEY(data_group),
+      KEY(dist_group)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Inputs for static sky analysis
+CREATE TABLE xcskyInput (
+      xcsky_id BIGINT,             -- static sky identifier
+      xcstack_id BIGINT,          -- stack identifier
+      PRIMARY KEY(xcsky_id,xcstack_id),
+      KEY(xcstack_id),
+      FOREIGN KEY(xcsky_id) REFERENCES xcskyRun(xcsky_id),
+      FOREIGN KEY(xcstack_id) REFERENCES xcstackSumSkyfile(xcstack_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Result of static sky analysis
+CREATE TABLE xcskyResult (
+      xcsky_id BIGINT,             -- static sky identifier
+      path_base VARCHAR(255) NOT NULL, -- root name for outputs
+      dtime_phot FLOAT,                -- elapsed time for photometry
+      dtime_script FLOAT,              -- elapsed time for script
+      sources INT,                     -- number of sources
+      num_inputs INT,                  -- number of input images
+      hostname VARCHAR(64) NOT NULL,   -- host that executed script
+      good_frac FLOAT,                 -- good fraction of skycell
+      quality SMALLINT NOT NULL,       -- bad quality flag
+      fault SMALLINT NOT NULL,         -- fault code
+      PRIMARY KEY(xcsky_id),
+      KEY(good_frac),
+      KEY(fault),
+      KEY(quality),
+      FOREIGN KEY(xcsky_id) REFERENCES xcskyRun(xcsky_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xccalRun (
+      xccal_id BIGINT AUTO_INCREMENT, -- unique identifier
+      xcsky_id BIGINT,
+      xcstack_id BIGINT,
+      state VARCHAR(64) NOT NULL,  -- state of run (new, full, etc.)
+      workdir VARCHAR(255) NOT NULL, -- working directory
+      label VARCHAR(64),             -- processing label
+      data_group VARCHAR(64),        -- group for data
+      dist_group VARCHAR(64),        -- group for distribution
+      reduction VARCHAR(64),         -- reduction class (for altering recipe)
+      registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- time run was registered
+      note VARCHAR(255),             -- note
+      PRIMARY KEY(xccal_id),
+      KEY(state),
+      KEY(label),
+      KEY(data_group),
+      KEY(dist_group),
+      KEY(xcsky_id),
+      KEY(xcstack_id),
+      FOREIGN KEY(xcsky_id) REFERENCES xcskyRun(xcsky_id),
+      FOREIGN KEY(xcstack_id) REFERENCES xcstackRun(xcstack_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Result of sky calibration analysis
+CREATE TABLE xccalResult (
+      xccal_id BIGINT,
+      path_base VARCHAR(255) NOT NULL,
+      dtime_script FLOAT,
+      dtime_astrom FLOAT,
+      sigma_ra FLOAT,
+      sigma_dec FLOAT,
+      n_astrom INT,
+      n_detections INT,
+      n_extended INT,
+      n_forced INT,
+      zpt_obs FLOAT,
+      zpt_stdev FLOAT,
+      fwhm_major  FLOAT,
+      fwhm_minor  FLOAT,
+      quality SMALLINT NOT NULL,
+      hostname VARCHAR(64) NOT NULL,
+      software_ver VARCHAR(64),
+      fault SMALLINT NOT NULL,
+      PRIMARY KEY(xccal_id),
+      KEY(fault),
+      KEY(quality),
+      FOREIGN KEY(xccal_id) REFERENCES xccalRun(xccal_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcForceRun (
+    xcff_id         BIGINT NOT NULL AUTO_INCREMENT,
+    xccal_id        BIGINT,
+    sources_path_base VARCHAR(255),
+    state           VARCHAR(64),
+    workdir         VARCHAR(255),
+    label           VARCHAR(64),
+    skycell_id      VARCHAR(64),
+    tess_id         VARCHAR(64),
+    data_group      VARCHAR(64),
+    dist_group      VARCHAR(64),
+    note            VARCHAR(255),
+    reduction       VARCHAR(64),
+    registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- time run was registered
+    PRIMARY KEY(xcff_id),
+    KEY(state),
+    KEY(label),
+    KEY(data_group),
+    KEY(xccal_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcForceInput (
+    xcff_id              BIGINT,
+    warp_id              BIGINT,
+    camera_id            BIGINT,
+    PRIMARY KEY(xcff_id, warp_id),
+    FOREIGN KEY(xcff_id)   REFERENCES xcForceRun(xcff_id),
+    FOREIGN KEY(warp_id) REFERENCES warpRun(warp_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcForceResult (
+    xcff_id         BIGINT,
+    warp_id         BIGINT,
+    path_base       VARCHAR(255) NOT NULL,
+    dtime_script    FLOAT,
+    quality         SMALLINT NOT NULL,
+    hostname        VARCHAR(64) NOT NULL,
+    software_ver    VARCHAR(16),
+    fault           SMALLINT NOT NULL,
+    PRIMARY KEY(xcff_id, warp_id),
+    KEY(fault),
+    KEY(quality),
+    FOREIGN KEY(xcff_id) REFERENCES xcForceRun(xcff_id),
+    FOREIGN KEY(warp_id) REFERENCES warpRun(warp_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE xcForceSummary (
+    xcff_id         BIGINT,
+    path_base       VARCHAR(255) NOT NULL,
+    dtime_script    FLOAT,
+    quality         SMALLINT NOT NULL,
+    hostname        VARCHAR(64) NOT NULL,
+    software_ver    VARCHAR(16),
+    fault           SMALLINT NOT NULL,
+    PRIMARY KEY(xcff_id),
+    KEY(fault),
+    KEY(quality),
+    FOREIGN KEY(xcff_id) REFERENCES xcForceRun(xcff_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
Index: trunk/tools/eam/xcstack.20231124/make.xcstack.v1.sh
===================================================================
--- trunk/tools/eam/xcstack.20231124/make.xcstack.v1.sh	(revision 42839)
+++ trunk/tools/eam/xcstack.20231124/make.xcstack.v1.sh	(revision 42839)
@@ -0,0 +1,457 @@
+#!/bin/csh
+
+which mariadb >& /dev/null
+@ has_mariadb = ($status == 0)
+
+which mysql >& /dev/null
+@ has_mysql = ($status == 0)
+
+set MYSQL = none
+if ($has_mariadb) then
+  set MYSQL = mariadb
+endif
+if (($has_mariadb == 0) && ($has_mysql)) then
+  set MYSQL = mysql
+endif
+
+echo "mysql is $MYSQL"
+
+set dbserver = localhost
+set dbuser = ipp
+set dbpass = ipp
+
+echo "******** create databases ********"
+
+# create 3 databases: two cameras and a xcamera
+# also need to create ippadmin entries to match these camera databases:
+$MYSQL -h $dbserver -u $dbuser -p$dbpass ippadmin <<EOF
+  delete from projects where projname = 'test_cam1';
+  delete from projects where projname = 'test_cam2';
+  delete from projects where projname = 'test_xcam';
+  insert into projects (projname) values ('test_cam1');
+  insert into projects (projname) values ('test_cam2');
+  insert into projects (projname) values ('test_xcam');
+  drop database if exists test_cam1;
+  drop database if exists test_cam2;
+  drop database if exists test_xcam;
+  create database test_cam1;
+  create database test_cam2;
+  create database test_xcam;
+EOF
+
+pxadmin -dbname test_cam1 -create
+pxadmin -dbname test_cam2 -create
+pxadmin -dbname test_xcam -create
+
+exit 2
+
+#$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam1 < make.xcstack.sql
+#$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam2 < make.xcstack.sql
+#$MYSQL -h $dbserver -u $dbuser -p$dbpass test_xcam < make.xcstack.sql
+
+echo "******** add skycell info ********"
+
+# generate skycell entry (needed for xcsky and xccal queries)
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_xcam <<EOF
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.024', 200.4, 60.0, 0.433333, 0.438819);
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.025', 200.5, 60.0, 0.433333, 0.438819);
+  insert into dbversion (schema_version) values ('0.1');
+EOF
+if ($status) then
+ echo "ERROR: failed in mysql load for test_xcam"
+ exit 2
+ endif
+ 
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam1 <<EOF
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.024', 200.4, 60.0, 0.433333, 0.438819);
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.025', 200.5, 60.0, 0.433333, 0.438819);
+  insert into dbversion (schema_version) values ('0.1');
+EOF
+if ($status) then
+ echo "ERROR: failed in mysql load for test_cam1"
+ exit 2
+ endif
+
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_cam2 <<EOF
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.024', 200.4, 60.0, 0.433333, 0.438819);
+  insert into skycell (tess_id, skycell_id, radeg, decdeg, width, height) values ('Fake.Tess', 'skycell.2479.025', 200.5, 60.0, 0.433333, 0.438819);
+  insert into dbversion (schema_version) values ('0.1');
+EOF
+if ($status) then
+ echo "ERROR: failed in mysql load for test_cam2"
+ exit 2
+ endif
+
+# insert data into the stack tables
+
+set mydir = `pwd`
+
+# I need to generate a more complex dataset.  I can use the same image (or use fake image names)
+# I will generate Nw warps, Ns stacks make from groups of Ni warps, but with some duplicates (ie, same warps used
+# in multiple stacks).  for additional complexity, the number of warps used in each stack will not be the same
+# for each stack (to mimic, e.g., a new stack made with additional new warps)
+
+echo "******** add cam1 stacks and warps ********"
+
+# starting point for running indexes
+set warp_id = 1
+set stack_id = 1
+set nwarps_max = 5
+set nwarps_min = 3
+set cam = "cam1"
+
+rm -f test_$cam.sql
+echo "SET FOREIGN_KEY_CHECKS=0;" > test_$cam.sql
+
+set filters  = (g                r                g                )
+set skycells = (skycell.2479.024 skycell.2479.024 skycell.2479.025 )
+
+set ngroup = 1
+
+while ($ngroup <= $#filters)
+  set skycell = $skycells[$ngroup]
+  set filter  = $filters[$ngroup]
+  
+  @ warp_id_max = $warp_id + $nwarps_max - 1
+
+  # generate warps (two filters, two skycells)
+  while ($warp_id <= $warp_id_max) 
+    echo "insert into rawExp      (exp_id, exp_name, camera, filter, fault) values ($warp_id, 'name.$warp_id', 'test_$cam', '$filter', 0);" >> test_$cam.sql
+    echo "insert into chipRun     (exp_id, chip_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into camRun      (chip_id, cam_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into fakeRun     (cam_id, fake_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into warpRun     (warp_id, fake_id, tess_id, state, workdir, label) values ($warp_id, $warp_id, 'Fake.Tess', 'full', '$mydir/warps.$cam', 'label.$cam');" >> test_$cam.sql
+    echo "insert into warpSkyfile (warp_id, skycell_id, tess_id, quality, fault, good_frac, path_base, data_state) values ($warp_id, '$skycell', 'Fake.Tess', 0, 0, 0.8, '$mydir/warps.$cam/warp.$warp_id.$skycell', 'full');" >> test_$cam.sql
+    @ warp_id ++
+  end
+    
+  set nstack = 0
+
+  # generate stacks from nwarps_min inputs to nwarps_max input (e.g., 3, 4, 5, 6) 
+  while ($nstack < $nwarps_max - $nwarps_min + 1)
+    
+    echo "insert into stackRun (stack_id, state, workdir, label, skycell_id, tess_id, filter) values ($stack_id, 'full', '$mydir/stacks.$cam', 'label.$nstack.$cam', '$skycell', 'Fake.Tess', '$filter');" >> test_$cam.sql
+    echo "insert into stackSumSkyfile (stack_id, path_base, good_frac, fault, quality) values ($stack_id, '$mydir/stacks.$cam/stack.$stack_id.$skycell', 0.95, 0, 0);" >> test_$cam.sql
+    
+    @ warp_id_inp = ($nwarps_max * ($ngroup - 1) + 1)
+    @ warp_id_max = $warp_id_inp + $nstack + $nwarps_min - 1
+    while ($warp_id_inp <= $warp_id_max)
+      echo "insert into stackInputSkyfile (stack_id, warp_id) values ($stack_id, $warp_id_inp);" >> test_$cam.sql
+      @ warp_id_inp ++
+    end
+    @ nstack ++
+    @ stack_id ++
+  end
+
+  @ ngroup ++
+end
+
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_$cam < test_$cam.sql
+if ($status) then
+ echo "ERROR: failed in mysql inserts for test_cam1"
+ exit 2
+ endif
+
+echo "******** add cam2 stacks and warps ********"
+
+# starting point for running indexes
+set warp_id = 1
+set stack_id = 1
+set nwarps_max = 5
+set nwarps_min = 3
+set cam = "cam2"
+
+rm -f test_$cam.sql
+echo "SET FOREIGN_KEY_CHECKS=0;" > test_$cam.sql
+
+set filters  = (g                r                g                )
+set skycells = (skycell.2479.024 skycell.2479.024 skycell.2479.025 )
+
+set ngroup = 1
+
+while ($ngroup <= $#filters)
+  set skycell = $skycells[$ngroup]
+  set filter  = $filters[$ngroup]
+  
+  @ warp_id_max = $warp_id + $nwarps_max - 1
+
+  # generate warps (two filters, two skycells)
+  while ($warp_id <= $warp_id_max) 
+    echo "insert into rawExp      (exp_id, exp_name, camera, filter, fault) values ($warp_id, 'name.$warp_id', 'test_$cam', '$filter', 0);" >> test_$cam.sql
+    echo "insert into chipRun     (exp_id, chip_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into camRun      (chip_id, cam_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into fakeRun     (cam_id, fake_id) values ($warp_id, $warp_id);" >> test_$cam.sql
+    echo "insert into warpRun     (warp_id, fake_id, tess_id, state, workdir, label) values ($warp_id, $warp_id, 'Fake.Tess', 'full', '$mydir/warps.$cam', 'label.$cam');" >> test_$cam.sql
+    echo "insert into warpSkyfile (warp_id, skycell_id, tess_id, quality, fault, good_frac, path_base, data_state) values ($warp_id, '$skycell', 'Fake.Tess', 0, 0, 0.8, '$mydir/warps.$cam/warp.$warp_id.$skycell', 'full');" >> test_$cam.sql
+    @ warp_id ++
+  end
+    
+  set nstack = 0
+
+  # generate stacks from nwarps_min inputs to nwarps_max input (e.g., 3, 4, 5, 6) 
+  while ($nstack < $nwarps_max - $nwarps_min + 1)
+    
+    echo "insert into stackRun (stack_id, state, workdir, label, skycell_id, tess_id, filter) values ($stack_id, 'full', '$mydir/stacks.$cam', 'label.$nstack.$cam', '$skycell', 'Fake.Tess', '$filter');" >> test_$cam.sql
+    echo "insert into stackSumSkyfile (stack_id, path_base, good_frac, fault, quality) values ($stack_id, '$mydir/stacks.$cam/stack.$stack_id.$skycell', 0.95, 0, 0);" >> test_$cam.sql
+    
+    @ warp_id_inp = ($nwarps_max * ($ngroup - 1) + 1)
+    @ warp_id_max = $warp_id_inp + $nstack + $nwarps_min - 1
+    while ($warp_id_inp <= $warp_id_max)
+      echo "insert into stackInputSkyfile (stack_id, warp_id) values ($stack_id, $warp_id_inp);" >> test_$cam.sql
+      @ warp_id_inp ++
+    end
+    @ nstack ++
+    @ stack_id ++
+  end
+
+  @ ngroup ++
+end
+
+$MYSQL -h $dbserver -u $dbuser -p$dbpass test_$cam < test_$cam.sql
+
+#### xcstacktool tests
+
+echo "******** generate the camera db entries ********"
+
+# define the xcameras:
+xcstacktool -dbname test_cam1 -addcamera -xcamera test_xcam
+xcstacktool -dbname test_cam2 -addcamera -xcamera test_xcam
+
+# define the xcameras:
+xcstacktool -dbname test_xcam -addcamera -xcamera test_cam1
+xcstacktool -dbname test_xcam -addcamera -xcamera test_cam2
+
+# exit 2
+
+echo "******** xcstacktool steps ********"
+
+set nstack = 0
+while ($nstack < $nwarps_max - $nwarps_min + 1)
+  # define xcstacks by matching labels:
+  xcstacktool -dbname test_xcam -definebyquery -xcamera test_cam1 -set_workdir $mydir/xcstack -set_label Test.xcstk.$nstack -select_label label.$nstack.cam1
+
+  # we have to define the relationship between instack and xcstack filters, so both must be specified
+  xcstacktool -dbname test_xcam -addbyquery    -xcamera test_cam2 -select_instack_filter g -select_xcstack_filter g -select_instack_label label.$nstack.cam2 -select_xcstack_label Test.xcstk.$nstack
+  xcstacktool -dbname test_xcam -addbyquery  -xcamera test_cam2 -select_instack_filter r -select_xcstack_filter r -select_instack_label label.$nstack.cam2 -select_xcstack_label Test.xcstk.$nstack
+
+  @ nstack ++
+end
+
+# can restrict by skycell as well
+# xcstacktool -dbname test_xcam -addbyquery    -xcamera test_cam2 -select_skycell_id skycell.2479.024 -select_instack_filter g -select_xcstack_filter g -select_instack_label label.0.cam2
+
+# XXX shouldn't this require some restrictions?
+xcstacktool -dbname test_xcam -tosum > xcstack.md
+set stk_ids = (`grep xcstack_id xcstack.md | awk '{print $3}'`)
+set Tskycells = (`grep skycell_id xcstack.md | awk '{print $3}'`)
+set workdir = `grep workdir xcstack.md | awk '{print $3}' | head -n 1`
+mkdir -p $workdir
+
+# (pretend to) run xcstack
+set n = 1
+while ($n <= $#stk_ids)
+  # OUTROOT is defined in xcstack.pro based on workdir : "%s/%s/%s/%s.%s.stk.%s" $WORKDIR $TESS_ID $SKYCELL_ID $TESS_ID $SKYCELL_ID $XCSTACK_ID
+  if (0 && ($n == 1)) then
+    # manually run xcstack : note the camera must match a real camera in ippconfig/system.conf
+    mkdir -p $workdir/Fake.Tess/$Tskycells[$n]
+    echo xcstack_skycell.pl --dbname test_xcam --xcstack_id $stk_ids[$n] --outroot $workdir/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].stk.$stk_ids[$n] --run-state new --camera GPC1
+    xcstack_skycell.pl --dbname test_xcam --xcstack_id $stk_ids[$n] --outroot $workdir/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].stk.$stk_ids[$n] --run-state new --camera GPC1
+  else
+    xcstacktool -dbname test_xcam -addsumskyfile -path_base $workdir/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].stk.$stk_ids[$n] -hostname elepaio -dtime_script 45.9999994374812 -xcstack_id $stk_ids[$n]
+  endif
+  @ n++
+end
+
+echo "******** xcskytool steps (static sky) ********"
+
+#### xcskytool tests
+
+# do the first set as separate filters
+xcskytool -dbname test_xcam -definebyquery -set_workdir $mydir/xcsky -set_label Test.xcsky.0 -select_label Test.xcstk.0 -select_filter r
+xcskytool -dbname test_xcam -definebyquery -set_workdir $mydir/xcsky -set_label Test.xcsky.0 -select_label Test.xcstk.0 -select_filter g
+
+# do the second and third sets as multi-filters
+xcskytool -dbname test_xcam -definebyquery -set_workdir $mydir/xcsky -set_label Test.xcsky.1 -select_label Test.xcstk.1 -select_filter g -select_filter r
+xcskytool -dbname test_xcam -definebyquery -set_workdir $mydir/xcsky -set_label Test.xcsky.2 -select_label Test.xcstk.2 -select_filter g -select_filter r
+
+xcskytool -dbname test_xcam -todo -label Test.xcsky.0
+
+xcskytool -dbname test_xcam -updaterun -label Test.xcsky.0 -set_data_group foo -set_dist_group bar -set_note myNote
+
+## now I need to identify the entries and set fake results
+
+## inject results for (Test.xcsky.t0, Test.xcsky.t1, Test.xcsky.t2)
+
+foreach label (0 1 2)
+  xcskytool -dbname test_xcam -todo -label Test.xcsky.$label > xcsky.md
+  set sky_ids   = (`grep xcsky_id   xcsky.md | awk '{print $3}'`)
+  set Tskycells = (`grep skycell_id xcsky.md | awk '{print $3}'`)
+  set workdir   = (`grep workdir    xcsky.md | awk '{print $3}'`)
+  
+  ## (pretend to) run xcsky.pl
+  set n = 1
+  while ($n <= $#sky_ids)
+    # OUTROOT is defined in xcsky.pro based on workdir : "%s/%s/%s/%s.%s.sky.%s" $WORKDIR $TESS_ID $SKYCELL_ID $TESS_ID $SKYCELL_ID $SKY_ID
+    if (0 && ($n == 2)) then
+      mkdir -p $workdir[$n]/Fake.Tess/$Tskycells[$n]
+      echo xcsky.pl --dbname test_xcam --xcsky_id $sky_ids[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].sky.$sky_ids[$n] --camera GPC1
+      xcsky.pl --dbname test_xcam --xcsky_id $sky_ids[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].sky.$sky_ids[$n] --camera GPC1
+    else
+      xcskytool -dbname test_xcam -addresult -path_base $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].sky.$sky_ids[$n] -hostname elepaio -dtime_script 45 -dtime_phot 28 -sources 100 -num_inputs 1 -good_frac 0.5 -xcsky_id $sky_ids[$n]
+      xcskytool -dbname test_xcam -result -xcsky_id $sky_ids[$n]
+    endif
+    @ n++
+  end
+end
+
+# test the revert process:
+if (0) then
+  xcskytool -dbname test_xcam -updateresult -xcsky_id 1 -fault 1
+  xcskytool -dbname test_xcam -updaterun -xcsky_id 1 -set_state new
+  xcskytool -dbname test_xcam -revert -xcsky_id 1
+endif
+
+####### xccal
+
+echo "******** xcskytool steps (calibration) ********"
+
+# queue a single xcskyRun to xccalRun:
+# xcskytool -dbname test_xcam -definexccalrun -select_xcsky_id 1
+
+# queue all three labels
+foreach label (0 1 2)
+  # workdir is inherited from xcsky if not specified here
+  xcskytool -dbname test_xcam -definexccalrun -select_label Test.xcsky.$label -set_label Test.xccal.$label
+end 
+
+# mysql> select xccal_id, xcsky_id, xcstack_id, xccalRun.label as calLabel, xcskyRun.label as skyLabel, xcstackRun.label as stkLabel, xcstackRun.filter, xcskyResult.path_base, xcstackSumSkyfile.path_base from xccalRun join xcskyInput using (xcsky_id, xcstack_id) join xcskyRun using (xcsky_id) join xcskyResult using (xcsky_id) join xcstackRun using (xcstack_id) join xcstackSumSkyfile using (xcstack_id);
+# NOTE: xccalRun inherits the label, data_group, dist_group, reduction from xcskyRun
+
+foreach label (0 1 2)
+  xcskytool -dbname test_xcam -pendingxccalrun -label Test.xccal.$label > xccal.md
+  set cal_ids   = (`grep xccal_id   xccal.md | awk '{print $3}'`)
+  set stk_ids   = (`grep xcstack_id xccal.md | awk '{print $3}'`)
+  set Tskycells = (`grep skycell_id xccal.md | awk '{print $3}'`)
+  set workdir   = (`grep workdir    xccal.md | awk '{print $3}'`)
+  set pathbase  = (`grep path_base  xccal.md | awk '{print $3}'`)
+  
+  ## (pretend to) run xccal.pl
+  set n = 1
+  while ($n <= $#cal_ids)
+    # OUTROOT is defined in xccal.pro based on workdir : "%s/%s/%s/%s.%s.cal.%s" $WORKDIR $TESS_ID $SKYCELL_ID $TESS_ID $SKYCELL_ID $SKYCAL_ID  ****** TBD *****
+    # change 'cal' to 'xccal' here?
+    if (0 && ($n == 1)) then
+      mkdir -p $workdir[$n]/Fake.Tess/$Tskycells[$n]
+      echo xccal.pl --dbname test_xcam --xccal_id $cal_ids[$n] --xcstack_id $stk_ids[$n] --path_base $pathbase[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].cal.$cal_ids[$n] --camera GPC1
+           xccal.pl --dbname test_xcam --xccal_id $cal_ids[$n] --xcstack_id $stk_ids[$n] --path_base $pathbase[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].cal.$cal_ids[$n] --camera GPC1
+    else
+      xcskytool -dbname test_xcam -addxccalresult -path_base $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].cal.$cal_ids[$n] -hostname elepaio -zpt_obs 25.0 -xccal_id $cal_ids[$n]
+      xcskytool -dbname test_xcam -xccalresult -xccal_id $cal_ids[$n]
+    endif
+    @ n++
+  end
+end
+
+# test the revert process
+if (0) then
+  xcskytool -dbname test_xcam -updatexccal    -xccal_id 1 -set_fault 1
+  xcskytool -dbname test_xcam -updatexccalrun -xccal_id 1 -set_state new
+  xcskytool -dbname test_xcam -revertxcal -xccal_id 1
+endif
+
+####### xcfftool
+
+echo "******** xcfftool steps ********"
+
+foreach label (0 1 2)
+  xcfftool -dbname test_cam1 -definebyquery -select_xccal_label Test.xccal.$label -set_label Test.xcff.$label -set_workdir $mydir/xcff -xcamera test_xcam 
+  xcfftool -dbname test_cam2 -definebyquery -select_xccal_label Test.xccal.$label -set_label Test.xcff.$label -set_workdir $mydir/xcff -xcamera test_xcam 
+end
+
+xcfftool -dbname test_cam1 -updaterun -xcff_id 1 -set_note myNote
+ 
+foreach cam (cam1 cam2)
+  foreach label (0 1 2)
+    xcfftool -dbname test_$cam -todo -label Test.xcff.$label > xcff.todo.md
+    set xcff_ids   = (`grep xcff_id    	    xcff.todo.md | awk '{print $3}'`)
+    set xccal_ids  = (`grep xccal_id  	    xcff.todo.md | awk '{print $3}'`)
+    set warp_ids   = (`grep warp_id    	    xcff.todo.md | awk '{print $3}'`)
+    set Tskycells  = (`grep skycell_id 	    xcff.todo.md | awk '{print $3}'`)
+    set workdir    = (`grep workdir    	    xcff.todo.md | awk '{print $3}'`)
+    set warppaths  = (`grep warp_path_base    xcff.todo.md | awk '{print $3}'`)
+    set srcpaths   = (`grep sources_path_base xcff.todo.md | awk '{print $3}'`)
+
+    ## (pretend to) run xcff_warp.pl
+    set n = 1
+    while ($n <= $#xcff_ids)
+      # OUTROOT is defined in xcff.pro based on workdir : "%s/%s/%s/%s.%s.wrp.%s.xcff.%s" $WORKDIR $TESS_ID $SKYCELL_ID $TESS_ID $SKYCELL_ID $WARP_ID $FF_ID ***** TBD *****
+      # WORKDIR is needed to prevent collisions between (e.g.,) gpc1 and gpc2 jobs for the same skycell, or else add the camera to the output path
+      if (0 && ($xccal_ids[$n] == 1)) then
+        mkdir -p $workdir[$n]/Fake.Tess/$Tskycells[$n]
+        echo xcff_warp.pl --dbname test_$cam --xcff_id $xcff_ids[$n] --warp_id $warp_ids[$n] --skycell_id $Tskycells[$n] --warp_path_base $warppaths[$n] --sources_path_base $srcpaths[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].$cam.wrp.$warp_ids[$n].xcff.$xcff_ids[$n] --camera GPC1
+             xcff_warp.pl --dbname test_$cam --xcff_id $xcff_ids[$n] --warp_id $warp_ids[$n] --skycell_id $Tskycells[$n] --warp_path_base $warppaths[$n] --sources_path_base $srcpaths[$n] --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].$cam.wrp.$warp_ids[$n].xcff.$xcff_ids[$n] --camera GPC1
+      else
+        xcfftool -dbname test_$cam -addresult -xcff_id $xcff_ids[$n] -warp_id $warp_ids[$n] -path_base $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].$cam.wrp.$warp_ids[$n].xcff.$xcff_ids[$n] -hostname elepaio -quality 0 -fault 0
+        xcfftool -dbname test_$cam -result    -xcff_id $xcff_ids[$n]
+      endif
+      @ n++
+    end
+
+    # get a list of the unique xcff_ids 
+    set xcff_ids_u   = (`grep xcff_id xcff.todo.md | awk '{print $3}' | sort | uniq`)
+    
+    set n = 1
+    while ($n <= $#xcff_ids_u)
+      # get the workdir from above which matches this uniq xcff_ids:
+      set workdir_u = ""
+      set skycell_u = ""
+      set xccal_u = ""
+      set t = 1
+      while ($t <= $#xcff_ids)
+        if ($xcff_ids[$t] == $xcff_ids_u[$n]) then
+          set workdir_u = $workdir[$t]
+          set skycell_u = $Tskycells[$t]
+          set xccal_u = $xccal_ids[$t]
+          set xcff_u = $xcff_ids_u[$n]
+        endif
+        @ t++
+      end
+      if ($workdir_u == "") then
+        echo "ERROR: failed to find workdir for $xcff_ids_u[$n] from $workdir"
+        exit 2
+      endif
+
+      # OUTROOT is defined in xcff.pro based on workdir : "%s/%s/%s/%s.%s.xcff.%s" $WORKDIR $TESS_ID $SKYCELL_ID $TESS_ID $SKYCELL_ID $XCFF_ID **** TBD ***
+      ## (pretend to) run xcff_summary.pl
+      xcfftool -dbname test_$cam -toadvance -xcff_id $xcff_u
+    
+      if (1 && ($xccal_u == 1)) then
+        mkdir -p $workdir[$n]/Fake.Tess/$Tskycells[$n]
+        echo xcff_summary.pl --dbname test_$cam --xcff_id $xcff_u --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].$cam.xcff.$xcff_u --camera GPC1
+             xcff_summary.pl --dbname test_$cam --xcff_id $xcff_u --outroot $workdir[$n]/Fake.Tess/$Tskycells[$n]/Fake.Tess.$Tskycells[$n].$cam.xcff.$xcff_u --camera GPC1
+      else
+        xcfftool -dbname test_$cam -addsummary -xcff_id $xcff_u -path_base $workdir_u/Fake.Tess/$skycell_u/Fake.Tess.$skycell_u.$cam.xcff.$xcff_u -dtime_script 0.0 -quality 0 -fault 0 -hostname elepaio
+      endif
+      xcfftool -dbname test_$cam -summary    -xcff_id $xcff_u
+      @ n++
+    end
+  end
+
+  # test the revert process
+  if (0) then
+    xcfftool -dbname test_$cam -updateresult -xcff_id 1 -warp_id 6 -fault 1
+    xcfftool -dbname test_$cam -updateresult -xcff_id 1 -warp_id 7 -fault 1
+    xcfftool -dbname test_$cam -updateresult -xcff_id 1 -warp_id 8 -fault 1
+    xcfftool -dbname test_$cam -revert -xcff_id 1 -warp_id 6
+    xcfftool -dbname test_$cam -revert -xcff_id 1 -warp_id 7
+    xcfftool -dbname test_$cam -revert -xcff_id 1 -warp_id 8
+    xcfftool -dbname test_$cam -updatesummary -xcff_id 1 -fault 1
+    xcfftool -dbname test_$cam -revertsummary -xcff_id 1
+  endif
+
+end
+
+#  -exportrun      list summary results
+#  -importrun      list summary results
+
+exit 0
Index: trunk/tools/eam/xcstack.20231124/run.addstar.sh
===================================================================
--- trunk/tools/eam/xcstack.20231124/run.addstar.sh	(revision 42839)
+++ trunk/tools/eam/xcstack.20231124/run.addstar.sh	(revision 42839)
@@ -0,0 +1,7 @@
+#!/bin/csh -f
+
+# this works for the first warp from each camera, but fails for the
+# rest because they are all duplicates in reality
+foreach f ( xcff/Fake.Tess/skycell.2479.024/*.wrp.*.cmf )
+  addstar -D CATDIR catdir.t2 -D CAMERA gpc1 -accept-astrom $f
+end
Index: trunk/tools/eam/xcstack.20231124/run.xcstack.sh
===================================================================
--- trunk/tools/eam/xcstack.20231124/run.xcstack.sh	(revision 42839)
+++ trunk/tools/eam/xcstack.20231124/run.xcstack.sh	(revision 42839)
@@ -0,0 +1,105 @@
+#!/bin/csh
+
+# the cross-camera stack and photometry stages boil down to the following few commands:
+
+# stack the images:
+
+set inp = skycell.2479.024.ps1.ps2.input
+set out = Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.stk.1
+ 
+set options = ""
+set options = "$options -stats $out.stats"
+set options = "$options -recipe PPSTACK TEST1"
+set options = "$options -recipe PPSTATS STACKSTATS"
+set options = "$options -stack-type DEEP_STACK"
+
+# uncompressed output:
+set options = "$options -F PPSTACK.OUTPUT PPSTACK.OUTPUT.NOCOMP"
+set options = "$options -F PPSTACK.OUTPUT.VARIANCE PPSTACK.OUTPUT.VARIANCE.NOCOMP"
+set options = "$options -F PPSTACK.OUTPUT.EXPWT PPSTACK.OUTPUT.EXPWT.NOCOMP"
+set options = "$options -F PPSTACK.OUTPUT.EXP PPSTACK.OUTPUT.EXP.NOCOMP"
+set options = "$options -F PPSTACK.UNCONV PPSTACK.UNCONV.NOCOMP"
+set options = "$options -F PPSTACK.UNCONV.VARIANCE PPSTACK.UNCONV.VARIANCE.NOCOMP"
+set options = "$options -F PPSTACK.UNCONV.EXPWT PPSTACK.UNCONV.EXPWT.NOCOMP"
+set options = "$options -F PPSTACK.UNCONV.EXP PPSTACK.UNCONV.EXP.NOCOMP"
+
+# logflux output:
+# set options = "$options -R PPSTACK.OUTPUT          FITS.TYPE STK_UNIONS_COMP"
+# set options = "$options -R PPSTACK.OUTPUT.VARIANCE FITS.TYPE STK_UNIONS_COMP" 
+# set options = "$options -R PPSTACK.UNCONV          FITS.TYPE STK_UNIONS_COMP"
+# set options = "$options -R PPSTACK.UNCONV.VARIANCE FITS.TYPE STK_UNIONS_COMP"
+
+# deep-stack output
+# set options = "$options -R PPSTACK.OUTPUT.EXP FITS.TYPE EXP_UNIONS "
+# set options = "$options -R PPSTACK.UNCONV.EXP FITS.TYPE EXP_UNIONS "
+
+set options = "$options -threads 6"
+set options = "$options -dbname test_cam1"
+set options = "$options -image_id 1"
+set options = "$options -source_id 2"
+set options = "$options -dumpconfig $out.mdc"
+
+if (0) then
+  ppStack -input $inp $out $options
+endif
+
+# run psphot on the stack (static sky)
+
+set inp = skycell.2479.024.sky.input
+set out = Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1
+
+set options = ""
+set options = "$options -threads 6"
+set options = "$options -recipe PSPHOT STACKPHOT_SINGLE"
+set options = "$options -recipe PPSTACK STACKPHOT"
+set options = "$options -recipe PPSUB STACKPHOT"
+set options = "$options -dumpconfig $out.mdm"
+
+if (0) then
+  psphotStack -input $inp $out $options
+endif
+
+# run psastro on the output of psphot (static sky)
+
+set inp = Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.sky.1.stk.12.cmf
+set out = Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.cal.1
+
+set options = ""
+set options = "$options -recipe PSASTRO STATICSKY_CAL"
+set options = "$options -recipe PPSTATS SKYCALSTATS"
+
+set options = "$options -F PSASTRO.OUTPUT PSASTRO.OUTPUT.CMF"
+set options = "$options -stats $out.stats"
+set options = "$options -dumpconfig $out.mdc"
+
+if (0) then
+  echo psastro -file $inp $out $options
+       psastro -file $inp $out $options
+endif
+
+# run psphotFullForce
+
+set src = "Fake.Tess/skycell.2479.024/Fake.Tess.skycell.2479.024.cal.1"
+set wrp = "warps.sample.gpc1/o5283g0266o.152638.wrp.1009477.skycell.2479.024"
+set out = "force.sample.gpc1/o5283g0266o.152638.wrp.1009477.skycell.2479.024"
+
+set options = ""
+set options = "$options -force     $src.cff"
+set options = "$options -file      $wrp.fits"
+set options = "$options -mask      $wrp.mask.fits"
+set options = "$options -variance  $wrp.wt.fits"
+set options = "$options -psf       $wrp.psf"
+set options = "$options -threads 6"
+
+set options = "$options -recipe PSPHOT FULLFORCE_WARP"
+set options = "$options -F PSPHOT.OUTPUT PSPHOT.OUT.CMF.MEF"
+set options = "$options -F PSPHOT.BACKMDL PSPHOT.BACKMDL.MEF"
+set options = "$options -photcode-rule '{DETECTOR}.{FILTER.ID}.ForcedWarp'"
+
+set options = "$options -stats $out.stats"
+set options = "$options -dumpconfig $out.mdc"
+
+if (1) then
+  echo psphotFullForce $out $options
+       psphotFullForce $out $options
+endif
