#### 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
-------------------------------------------

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 like first, but avg'd by annot region
N.B.: R-click on "GR" to get convenient controls popup!

-------------------------------------------
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 and then
vector-average them across each brain region of
the currently displayed annotation, resulting in
one gradient vector per 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 gradient is stored as x and y
components in the bottom of the stack (valbak,
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

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.
