#### calc 2D and 3D gradients of curv/val/phase ####
-------------------------------------------
funct: "Calc 2D/Flat Gradient Curv (left-click-GR)"
  compute_gradient <0=curv>
-------------------------------------------
funct: "Calc 2D/Flat Gradient RealVal (mid-click-GR)"
  compute_gradient <1=val>
-------------------------------------------
funct: "Calc 2D/Flat Gradient Phase (shift-mid-clk-GR)"
  compute_angles_vals_to_baks
  compute_gradient <2=phase-of-val/val2>
-------------------------------------------
funct: "Calc Surf Gradient Curv (ctrl-left-click-GR)"
  compute_surfgrad <0=curv>
-------------------------------------------
funct: "Calc Surf Gradient RealVal (ctrl-mid-click-GR)"
  compute_surfgrad <1=val>
-------------------------------------------
funct: "Calc Surf Gradient Phase (ctrl-shift-mid-clk-GR)"
  compute_angles_vals_to_baks
  compute_surfgrad <2=phase-of-val/val2>
-------------------------------------------
[like first 6, but single grad vecs avg'd by annot region]
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg Curv (no hotkey)"
  compute_gradient <0=curv>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg RealVal (no hotkey)"
  compute_gradient <1=val>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc 2D/Flat BrainRegAvg Grad Phase (no hotkey)"
  compute_angles_vals_to_baks
  compute_gradient <2=phase-of-val/val2>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg Curv (no hotkey)"
  compute_surfgrad <0=curv>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg RealVal (no hotkey)"
  compute_surfgrad <1=val>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Calc Surf BrainRegAvg Grad Phase (no hotkey)"
  compute_angles_vals_to_baks
  compute_surfgrad <2=phase-of-val/val2>
  compute_brainregion_avggrads
-------------------------------------------
funct: "Find Gradient Reversals (no hotkey)"
  find_grad_reversals
-------------------------------------------
[funct: compute_laplacian]
-------------------------------------------


The "GR" button on the "fs:" entry line computes
gradients on surface-loaded data.

N.B.: first 3 require first loading a 2D/flat patch
N.B.: second 3 require first loading 3D surface
N.B.: last 6 are like first, but avg'd by annot region
N.B.: R-click on "GR" to get convenient controls popup!
N.B.: 13th button req's 1st running one of the first 12

-------------------------------------------
Calculating the 2D gradient of 2D or 3D surface data
-------------------------------------------

A left-, middle-, or shift-middle-click on the
"GR" button uses "compute_gradient" to compute
the 2D gradient of the current data in curv, val,
or complex phase (val/val2), put the result in
the bottom of the stack (valbak,val2bak), and
then display it as a field of arrows.  This
doesn't disturb the data in the val/(val2)
fields.

By adding control (control-left, control-middle,
control-shift-middle), the local 2D gradient is
instead computed on an arbitrary 3D surface,
using "compute_surfgrad" (this function computes
gradients using unit vectors to neighboring
vertices).  N.B.: in sharply curved regions,
large gradient arrows on the 3D surface may be
truncated because they penetrate the surface.

An additional 6 options, available as buttons on
the popup available from a R-click on the "GR"
button, calculate the same 6 gradients but then
also vector-average them across each brain region
of the currently displayed annotation, resulting
in only one gradient vector per annotation
region.

For val, curv, and phase gradients, finite
differences are computed between the current and
neighboring vertices.  With phase, a circular
subtraction is used.

Because standard rotating wedge polar angle
mapping stimuli result in phases with opposite
signs in left and right hemispheres, by default,
$flipRHpolararrowsflag is ON, which causes a 180
deg flip of RH gradient arrows (to match the flip
in the standard polar angle color scales).
Gradient arrows are only flipped if:

  (1) complexvalflag is ON
  (2) hemi is "rh"
  (3) angle_cycles is *not* an integer (1.0, 2.0, ...)

Turning OFF $flipRHpolararrowsflag stops all
arrow flipping.

In both flat and 3D surface cases, gradients of
val or phase data are truncated to zero during
the calculation if:

  (1) $statmaskamp OFF:
      any data vertices used to calc gradients
      fall below $fthresh (complex amplitude in
      the case of phase data)

  (2) $statmaskamp ON:
      any vertices used to calc gradients have a
      .stat field that falls below $sfthresh

N.B.: To see the effect of changing $fthresh or
$sfthresh, you must re-run compute_gradient or
compute_surfgrad.

N.B.: The displayed gradient arrows may not refer
to the data currently displayed.  For example,
the gradient of *curvature* can be computed with
a val (or val/val2) overlay loaded.  Also, a
different val (or val/val2) overlay can be loaded
under the arrows computed for a previous val (or
val/val2) data set. Both of these scenarios could
be useful.

For real-valued data (curv or val) on a flat
surface, the tcl commands are:

  compute_gradient <0=curv,1=val>
  set gradvecbakflag 1
  redraw

or, for 2D gradients on a 3D surface:

  compute_surfgrad <0=curv,1=val>
  set gradvecbak3dflag 1
  redraw

For the gradient of the phase of complex-valued
data, the data must first be converted to
phase/amplitude with compute_angles_vals_to_baks.
The output of that function goes to the bottom of
complex stack (*.valbak,*.val2bak), and then
"compute_gradient 2" (2=phase) converts it to a
gradient in place.  For a flat surface, the tcl
commands are:

  compute_angles_vals_to_baks
  compute_gradient <2=phase>
  set gradvecbakflag 1
  redraw

or, for 2D gradients on a 3D surface:

  compute_angles_vals_to_baks
  compute_surfgrad <2=phase>
  set gradvecbak3dflag 1
  redraw

Finally, per-brainregion averages are computed
with:

   compute_brainregion_avggrads

and displayed for flat surfaces with:

  set reggradvecbakflag 1

and 3d surfaces with:

  set reggradvecbak3dflag 1

-------------------------------------------
Gradient vector display controls
-------------------------------------------

A R-click on the unlabeled tickbox to the left of
"fs:" (tksurfer middle left), brings up a
convienient popup for controlling and pruning
gradient (and fieldsign) arrows.

The displayed length of gradient arrows can be
scaled with $arrowscale, which is a fraction.
Alternatively, the length can be normalized with
$arrownormflag, in which case, $arrowscale will
be in units of mm.  These variables can be set on
the popup or by using the unlabeled tick box
($arrownormflag) and the unlabeld entry
($arrowscale) at the bottom of the phasecontour
box ("phc") (there since gradients are
perpendicular to isocontours).

To toggle visibility of gradient arrows on a flat
surface, use "gradvecbakflag" on the popup (or do
a middle-click on the checkbutton to the left of
"fs:", or set $gradvecbakflag to 0 or 1).

To toggle visibility of gradient arrows on a 3D
surface, use "gradvecbak3dflag" on the popup (or
do a control-middle-click on the same
checkbutton, or set $gradvecebak3dflag to 0 or
1).

The equivalent for per-brainregion average
gradients (displayed at the vertex closest to the
average 3D location for each region) are
"reggradvecbakflag" and "reggradvecbak3dflag"

To draw the arrowhead for the 3D gradient
vectors, the local tangent plane is approximated
by taking the cross product of the 3D gradient
vector and the local surface normal.

-------------------------------------------
Pruning gradient vectors
-------------------------------------------

Gradient calculations result in a very large
number of gradient arrows (one per vertex), which
will look cluttered (unless you strongly zoom in
on the surface).  A R-click on the unlabeled
tickbox to the left of "fs:" (middle left),
brings up a popup for controlling gradient (and
fieldsign) arrows.

There is a PRUNE ARROWS button at the bottom of
the popup.  The density of arrows is set by the
$gridsize parameter (in mm) on the popup.  The
"prunearrowsflag" toggles between pruning and no
pruning.  N.B.: click PRUNE ARROWS again after
$gridsize is adjusted to see effect.

The pruning works by only showing one arrow for
each specified-size grid cell (the one closest to
center of cell).  Since the actual vertex
location of the winning arrow is used, the grid
will be slightly irregular.  Try slight (+/-
0.1) adjustments for fine-tuning.

Also remember that *.val (or *.stat) thresholds
can be used to prune 'noise' arrows by setting
$fthresh (or $sfthresh if "mask" is ticked), and
then recalculating the gradient arrows.

N.B.: this process does not do any smoothing of
the gradient vectors (see next).

-------------------------------------------
Smoothing gradient vectors
-------------------------------------------

To smooth gradient vectors (e.g., before
pruning), use "Surface Smooth (gr)" on buttonbar
popup available from a R-click on the SMOOTH
button (or change to the larger F3 interface
(cmd/fn-F3) and use the extra "gr" option with
the SMOOTH button).

This can also be used to smooth any other
complex-valued data in the bottom of the data
stack (.valbak/.val2bak).

Note that if data (real or complex) itself has
been SMOOTH'd before calculating gradients, the
gradient arrows should already be smoothly
changing.

-------------------------------------------
Viewing gradient amplitude with standard color scales
-------------------------------------------

Since the 2D gradient is stored as x and y
components in the bottom of the stack (.valbak
and .val2bak), its amplitude can be displayed by
using the complex-valued heat scale ($colscale 1)
after first swapping the gradient to the top of
the complex stack with shift-middle-click "S/V".
The tcl commands are:

  swap_valval2_valbakval2bak
  set colscale 1
  redraw

N.B.: doesn't work with 3D gradient arrows on a
3D surface.

Alternatively, here is how to obtain a
real-valued overlay containing the gradient
amplitude (after the gradient has been computed):

  1) swap gradient to top of complex stack
  2) convert to phase/ampl (goes back to bottom)
  3) swap phase/ampl to the top
  4) swap val and valbak (ampl is second)
  5) unset display gradient vectors flag
  6) unset complexval flag
  7) adjust color scale

Here are example tcl commands:

  swap_valval2_valbakval2bak
  compute_angles_vals_to_baks   
  swap_valval2_valbakval2bak
  swap_val_val2
  set gradvecbakflag 0
  set gradvecbak3dflag 0
  set complexvalflag 0
  set colscale 6
  set overlayflag 1
  set fthresh 0.0
  set fmid 0.08
  set fslope 10.0
  redraw

This process can be done all at once by clicking
"GRAD ARROWS -> COLOR" button on the popup
available from a R-click on the unmarked tickbox
at the bottom of the phase contour panel (just to
right of "cpx" button), after a gradient has been
calculated.  Finally, to save the auto-calculated
gradient amplitude as a real valued-file:

  setfile val */scan1/gradamp-$hemi.w
  write_binary_values

-------------------------------------------
Gradients on re-cut patches
-------------------------------------------

Since the gradient is calculated using
neighboring vertex values, the gradient is
undefined for vertices on the boundary of a
re-cut label.

If you want to calculate gradient values for
vertices on the boundary, first dilate the patch
by one layer of vertices before calculating the
gradient:

  middle-click "er" tickbox (tickbox label -> "dl" for dilate)
  left-click a vertex inside the re-cut label
  click FILL

or simply recut the patch *after* the gradient
calculation.

-------------------------------------------
funct: "Find Gradient Reversals (no hotkey)"
  find_grad_reversals
-------------------------------------------

The 13th "Find Gradient Reversals" button makes a
popup, "FIND GRADIENT REVERSALS", which runs the
C/tcl function, find_gradient_reversals.  It
requires that a gradient (of curv, real-valued
.val, or complex-valued phase from .val and
.val2) has first been calculated and displayed
on a 2D or 3D surface using one of the first 12
buttons on the "GR" R-click popup.

For each vertex, the absolute angular difference
(lesser of CW and CCW angles) between the
gradient vector at the vertex and the gradient
vectors at each neighboring vertex are measured.
For each angular difference that exceeds
$mindiffphase, the .pval field for that vertex is
incremented by 1/n, where n is the number of
neighbors.  The permissive default value of
$mindiffphase is 0.1 (36deg) (0.5=180deg), which
can be increased to reduce noise in the reversal
detection.  Re-run FIND REVERSALS to see the
effect.

The calculated vertexwise .pval's are saved as a
wfile in the current scandir (or in the subject's
scripts dir for curv gradient reversals) as:

  gradrevprob_k-$hemi.w

The gradient reversals can be displayed in two
ways.  By default, $pvalborddotflag is ON
(ticked), which displays reversal vertices as
cyan dots (color adjustable in the the popup),
with a .pval threshold controlled by $dthresh
(default 0.3).  Turn this up to reduce the number
of dots displayed (i.e., require a higher pval).
This doesn't require re-running FIND REVERSALS
(use a <Return> in entry).

If real or complex-valued data is displayed,
reversal dots will be truncated if real .val or
complex amplitude of .val/.va2 are below
$fthresh.

If $pvalborddotflag is unticked, there will be a
popup offering to swap .pval into the .val field
and display it using colscale 11 (BRy).

-------------------------------------------
[funct: compute_laplacian]
-------------------------------------------

The buttons to run the compute_laplacian function
are currently hidden.  To expose, change the
tksurfer.tcl line:

  set includelaplacian 0

to the following:

  set includelaplacian 1

Or the function can be called from a tcl script.
The real-valued output is written to the .valbak
field.  To compute the laplacian of curv, val, or
phase angle, and view the output, do something
like this in a script:

  [load curv, real, or complex data]
  compute_laplacian <0=curv,1=val,2=phase>
  swap_valval2_valbakval2bak
  set overlayflag
  set complexvalflag 0
  set colscale 11
  set fslope 2.0
  set fmid 0.5     ;# curv: 0.002
  set fthresh 0.0
  redrawbutton

