#### various smooth types, searchlight operations ####
-------------------------------------------
left-click SMOOTH button w/diff interface settings
      *or use*
explicit-name buttonbar buttons (same, uses steps setting)
-------------------------------------------
  "Surface Smooth (cv) - .curv (curv/sulc/area)"
    smooth_curv <steps>
  -------------------------
  "Surface Smooth (val) - .val(.val2), and .stat if there"
  [real]
    smooth_val <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val <steps>
    swap_val_val2
    smooth_val <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (s) - .stat field only"
    smooth_stat <steps>
  -------------------------
  "Surface Smooth  (w) - .val(.val2), distance-weighted"
  [real]
    smooth_val_weighted <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val_weighted <steps>
    swap_val_val2
    smooth_val_weighted <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (sp) - .val(.val2), sparse, fixed-val interp"
  [real]
    smooth_val_sparse <steps>
    smooth_stat <steps>
  [complex]
    swap_val_val2
    smooth_val_sparse <steps>
    swap_val_val2
    smooth_val_sparse <steps>
    smooth_stat <steps>
  -------------------------
  "Surface Smooth (cr) - .val(.val2), cmplex ang w/realamp"
    smooth_complexang_realamp <steps>
  -------------------------
  "Surface Smooth (gr) - .valbak(.val2bak) gradient arrows"
    swap_valval2_valbakval2bak
    swap_val_val2
    smooth_val <steps>
    swap_val_val2
    smooth_val <steps>
    swap_valval2_valbakval2bak
  -------------------------
  "Fill Annot/Label Holes, 1-Neigh (steps = annotholes)"
    fill_annot_holes
  -------------------------
  "Fill .val Field Holes, 1-Neigh Avg (steps = valholes)"
    fill_val_holes
  -------------------------
  "Fill Annot/Label Holes, AdjNeigh (=annotholes-neigh)"
    fill_annot_holes_neigh <neighord> <annotedfrac>
  -------------------------
  "Erode Edges of Annot/Label (steps = annoterode)"
    erode_annot
-------------------------------------------
"Searchlight Ops Control Popup (mid-click-SMOOTH)"
  searchlightop_val2stat <filltype> <criterion> <op>
-------------------------------------------
"No-overlap .stat Paintballs Popup (shift-mid-clk-SMOOTH)"
  neighop_val2stat <neighord> <criterion=3>
-------------------------------------------


Detailed Description of "SMOOTH" Button Actions

-------------------------------------------
funct (left-click):
  [various, depending on interface settings]
-------------------------------------------

The SMOOTH button runs requested number of steps
of surface-based smoothing (number of steps in
entry).

Select smoothing type using radio buttons at
right (radio button labels in quotes in left
column of table below).  If the data is complex,
both components are smoothed.

  "cv"  (curvature)     -- vertex[i].curv
  "val" (nearest nei)   -- vertex[i].val,{vertex[i].val2}
                                   and vertex[i].stat, if there
  "w"   (dist weight)    -- vertex[i].val,{vertex[i].val2}
  "sp"  (sparse)         -- vertex[i].val,{vertex[i].val2}

See the right click help of each radio button for
more details on each operation.  There are
additional SMOOTH radio buttons on the large F3
tksurfer interface:

  "vo" (valonly)        -- vertex[i].val,{vertex[i].val2}, not .stat
  "cr"  (complex/real) -- vertex[i].val,{vertex[i].val2}
  "s"  (stat)               -- vertex[i].stat only
  "gr"  (gradient)       -- vertex[i].valbak,{vertex[i].val2bak}

The convenient SMOOTH button tcl wrapper proc,
"smooth", can also be called from a user tcl
script.  It can call all the different types of
smooth functions and is a one-liner for smoothing
complex data:

  smooth <steps> <type>

where <steps> is one of:

  1) number of steps (e.g., "5")
  2) "valholes" (or "valueholes")
  3) "annotholes" (or "labelholes")
  4) "annoterode"

and <type> is one of:

  1) curv       (or sulc/area)
  2) val         (auto-detect real/complex, also stat if there)
  3) stat         (smooth just stat)
  4) weight    (auto-detect real/cmplx, dist- & num-weighted)
  5) sparse    (detect real/cmplx, only interp nodata vtxs)
  6) valonly   (auto-detect real/cmplx, don't smooth stat)
  7) cpxreal   (smooth complex angle and real amplitude)
  8) grad       (valbak/val2bak arrows gradient calc)

Omit <type> arg to tcl "smooth" function if
"<steps>" is set to "valholes", etc.

A R-click (help) on the SMOOTH button brings up a
button bar with a button for each of these 12
different types of smoothing.  There are two
additional bottom buttons on the button bar for
'searchlight' and 'paintball' operations (see
below).


Real vs. Complex-Valued Smoothing

The SMOOTH button does the following with
complex-valued data and the default smoothing
function for it, smooth_val (assumes real in
already in .val and imaginary already in .val2):

  swap_val_val2
  smooth_val <steps>
  swap_val_val2
  smooth_val <steps>

Note that complex-valued smoothing (averaging 2D
vectors) will generally reduce the amplitude of
the resulting vector more than real-valued
smoothing of the amplitude by itself.  This is
because complex valued smoothing (vector
averaging) is affected by local phase
differences, which are often substantial with
retinotopic mapping data.

Thus, smoothing complex-valued mapping data and
thresholding it at a given amplitude will reveal
somewhat *less* activation than smoothing the
amplitude -- e.g., sqrt(F) -- as a real value,
and then using it to mask the smoothed but
unthresholded complex-valued data at the same
amplitude.

There is an alternate smoothing method for
complex-valued data on the larger F3 panel (or
via middle-click on the "val" button on the
standard F2 panel):

  "cr"  (complex/real)		-- vertex[i].val,vertex[i].val2

This uses the funct, smooth_complexang_realamp,
which averages the complex angle, but then
replaces the resulting amplitude with a
real-valued average of the complex amplitudes,
thus ignoring local phase differences.  On the
csurf View Functional Data panel, there is an
unmarked tickbox (default unticked) immediately
to the left of the smoothsteps entry that toggles
using this function (for complex data) instead of
smooth_val.

To use this function in a tcl script, simply load
real to .val, imaginary to .val2, and call the
function.

The SMOOTH button can also be used to smooth
arrows generated by calculating gradients (of
curv, val, or phase).  First change to the large
F3 panel, and then use the extra "gr" radio
button next to the SMOOTH button (near bottom of
long vertical panel):

  "gr"  (gradient)          -- vertex[i].valbak,vertex[i].val2bak


Alternate hole-filling and eroding operations

The SMOOTH button can instead run four different
hole-filling and eroding functions if the
following text is typed into the entry next to
SMOOTH (instead of a number):

  annotholes -> fill holes in D'd label/annot
  valholes   -> fill holes in R'd label *data*
  annotholes-neigh -> fill holes w/adj neighbors & criterion
  annoterode -> erode 1 vtx from D'd label/annot

The first three operations do *not* smooth or
change the .annotation or .val field of vertices
that were part of the original label.  In that
respect, they behave like SMOOTH with "sp"
(sparse).

The fourth operation erodes the current
annotation (that is, sets it to zero) of any
vertex that has a neighbor with a different
annotation value.  Note that this does not do a
FILL operation, so repeated applications may not
leave a connected label.

In tcl scripts, the following C/tcl functions can
be used:

  smooth_curv <steps>
  smooth_val <steps>
  smooth_stat <steps>
  smooth_val_sparse <steps>
  smooth_val_weighted <steps>
  smooth_complexang_realamp <steps>
  fill_annot_holes
  fill_val_holes
  fill_annot_holes_neigh
  erode_annot

See R-click help for the smooth steps entry for
more details.


Lock a subset of vertices to locally prevent smoothing

The "locklabel" tickbox (F3 panel, lower middle)
toggles whether smoothing is disabled at vertices
under a label (displayed using "D").

If the tickbox variable, $locklabelflag, is TRUE
(=1), any vertex data (curv, val, val2) at locked
vertices will not be touched by the following
functions:

  smooth_curv
  smooth_val
  smooth_complexang_realamp


-------------------------------------------
"Searchlight Ops Control Popup (mid-click-SMOOTH)"
  searchlightop_val2stat <filltype> <criterion> <op>
-------------------------------------------

When the SMOOTH button is middle-clicked, a popup
appears with two adjustable parameters to control
the searchlight ROI size, and a third parameter to
select one of three operations to compute using
the C/tcl function:

  searchlightop_val2stat <filltype:0-2> <criterion> <op:0-4>

The searchlight size is controlled by:

  fillneartype:
    0: nearest n neighbors
    1: nearest up to area
    2: nearest up to radius

  criterion:
    if fillneartype=0: number of vertices
    if fillneartype=1: area in mm^2
    if fillneartype=2: radius in mm

There are five currently available searchlight
operations:

    op=0: average .val in each ROI => .stat
    op=1: count int IDs in each ROI => ,stat
    op=2: get variance after subtr currID from neighID's
    op=3: [not available: use neighop_val2stat]
    op=4: sum .val in each ROI => .stat

There are two additional options for controlling
whether 'representative vertices' are used in
each spotlight:

  searchlightuniqflag (req's load/samp/uniq 3D BRIK)
  numafteruniqflag

See "Use Representative Vertices" in the R-click
help for the "X" button on the "label:" line for
more details on how to use these two bottom
ticks.

N.B.: op=3 (non-overlapping patches to int ids in
.stat) is currently only available when using
the alternate function, neighop_val2stat (as
opposed to searchlightop_val2stat) in a tcl
script.  The neighop_val2stat function constructs
ROIs around each vertex by neighbor order (1-6).

Input Data

The input is the full-brain vertexwise data
currently loaded into the .val field.  The .val
field can be loaded using "R" on either the
"val:" or "label:" lines.

Output

The result, computed for searchlight ROIs across
the entire hemisphere, is put into the (invisible)
.stat field of each vertex.  To make the result
visible, use "S/V" to swap the .stat and .val
fields, and adjust the $colscale, $fslope, and
$fmid.

Searchlight operations

The first operation (optype=0) is a boxcar
average (N.B.: useful for very large kernels but
much slower than nearest neighbor smoothing for
small kernels).

The second and third operations are currently
designed for positive, ordered, integer cluster
IDs (negative vertex data is ignored).

The second operation (optype=1) counts the number
of different cluster IDs in each searchlight.

The third operation (optype=2) calculates the
variance of cluster IDs after first subtracting
off the cluster ID of the searchlight center.

The fourth operation (optype=3) paint
non-overlapping IDs (used for cerebellar patches
simulation).  N.B.: this currently only works
with the parallel function, neighop_val2stat, not
searchlightop_val2stat.

The fifth operation (optype=4) simply sums
.val for each searchlight ROI.

This function is multi-threaded (8 threads) and
takes about 9 min to finish on a standard
cortical hemiphere surface on a 4-core i7 (the
processor fans will increase their speed).

Example script

An example tcl script for loading data, running
the function, displaying and saving the results,
and subtracting the results from two different
data sets (using the C/tcl function,
subtr_valbak_from_val), is here:

  $CSURF_DIR/lib/tcl/zz-examples/searchlightdiff.tcl

That script expects two full-brain labels
containing positive integer cluster IDs ordered
by similarity, and displays differences in
cluster counts or cluster variance between
two different clusterings.


-------------------------------------------
"NonOverlap .stat Paintballs Popup (shift-mid-clk SMOOTH)"
  neighop_val2stat <neighorder:1-5> <operation=3>
-------------------------------------------

[not exactly smoothing but a local operation!]

A shift-middle click on the SMOOTH button brings
up a popup to provide interface support to run
the C/tcl function, neighop_val2stat (with
operation=3), for generating generating
'paintball' label/annots.  This function
generates a set of non-overlapping
label/annotation regions, whose size is specified
by vertex neighbor order (1=justneighbors,
2=neighbors-of-neighbors, etc).

The special operation=3 here is the only one that
ignores the .val field while writing to the .stat
field (the other operations for neighop_val2stat
are parallel to the operations in
searchlightop_val2stat).

Here are the neighbor counts for the fsaverage
surfaces:

    1-neighbors: 7
    2-neighbors: 19
    3-neighbors: 37
    4-neighbors: 61
    5-neighbors: 91
    6-neighbors: 127

When neighop_val2stat is run with operation=3, it
generates the non-overlapping regions as
sequentially-numbered, integer values in the
.stat field.

There will be small unlabeled regions in between
each non-overlapping, approximately circular
patch.  To fill these in, click the GROW STAT
IDNUMS button (C/tcl function grow_stat_idnums).
This selects a shuffled vertex and then, if it is
empty, adds it to an existing region if any of
its neighbors already have an idnum in the .stat
field.

The .stat idnum regions can then be turned into
an MGH annotation in order to use these regions
for further analysis.  This was originally
written to display the size of hypothetical
granule cell patches in the cerebellar cortex :-}
The regions are given random (non-overlapping)
colors in the output MGH annot file.

To see or use the result:

(1) save the .stat regions to a randcol annot file:
     --R-click "label:" line "W" to get popup
     --choose output file name in "label:" entry
     --"Write StatIds to RandCol MGH Annot" button

(2) display/use resulting annot file:
     --use "label:" line "D" button

