Attributes in the AFNI Dataset Header
=====================================
Each attribute is an array of values.  There are three kinds of attributes
allowed: float, int, and string (array of char).  Each attribute has a
name, which by convention is all caps.  All the attributes are read in
at once when a dataset .HEAD file is opened.  The software searches for
the attributes it wants, by name, when it needs them.  Attributes that
are not wanted by the programs are thus simply ignored.  For example,
the HISTORY_NOTE attribute is only used by functions in the thd_notes.c
source file.

--------------------
Format of Attributes
--------------------
The format of attributes is a little clunky and non-robust, but that's
the way it is for now.  The .HEAD file structure was "designed" in 1994,
and has not changed at all since then.  Here is an example of an int
attribute in the .HEAD file:

type = integer-attribute
name = ORIENT_SPECIFIC
count = 3
 3 5 1

The first line of the attribute is the "type =" line, which can take
values "integer-attribute", "float-attribute", or "string-attribute".

The second line is the "name =" line; the name that follows must not
contain any blanks.

The third line is the "count =" line; the value that follows is the
number of entries in the attribute array.

These 3 lines are read with the code below:
  char aname[THD_MAX_NAME] , atypestr[THD_MAX_NAME] ;
  int  acount ;
  fscanf( header_file ,
          " type = %s name = %s count = %d" ,
          atypestr , aname , &acount ) ;
Recall that a blank in a format matches any amount of whitespace in the
input stream; for example, "name =" and "name   =" are both acceptable
second lines in an attribute (as are a number of other bizarre things
that are too painful to elucidate).

Following the third line is the list of values for the attribute array.
For float and int attributes, these values are separated by blanks
(or other C "whitespace").  If the .HEAD file is generated by an AFNI
program, then a maximum of 5 values per line will be written.  However,
this is not required -- it is just there to make the .HEAD file easy
to edit manually.

For string attributes, the entire array of "count" characters follows
on the fourth line, right after a single opening quote ' character.
For example:

type = string-attribute
name = TYPESTRING
count = 15
'3DIM_HEAD_ANAT~

Note that the starting ' is not part of the attribute value and is not
included in the count.  Also note that ASCII NUL characters '\0' are
replaced with tilde ~ characters when the header is written.  (This is
to make it easy to edit the file manually).  They will be replaced with
NULs (not to be confused with NULL) when the attribute is read in.
If a string actually contains a tilde, then the tilde will be replaced
with an asterisk * when the attribute is written out.  However, asterisks
will NOT be replaced with tildes on input -- that is, there is no way
for an attribute string to contain a tilde.

Some of the attributes described below may contain more array entries
in the .HEAD file than are listed.  These entries are "reserves" for
future expansion.  In most cases, the expansions never happened.

---------------------------------------
Extracting Attributes in a Shell Script
---------------------------------------
Program 3dAttribute can be used to extract attributes from a dataset
.HEAD file.  For example
   3dAttribute TYPESTRING anat+orig
might produce (on stdout) the value "3DIM_HEAD_ANAT".  This could be
captured in a shell variable and used to make some decisions.  For
usage details, type the command
   3dAttribute -help

--------------------
Mandatory Attributes
--------------------
All these attributes must be present for a dataset to be recognized from
a .HEAD file.

DATASET_RANK = Two values that determine the dimensionality of the
(int)          dataset:
                [0] = Number of spatial dimensions (must be 3)
                [1] = Number of sub-bricks in the dataset
                      (in most programs, this is called "nvals")
               At one time I thought I might extend AFNI to support
               n-dimensional datasets, but as time went one, I decided
               to support the fourth dimension not by increasing the
               "rank" of a dataset, but by adding the time axis instead.
               Thus, the dataset rank is always set to 3.

DATASET_DIMENSIONS = Three values that determine the size of each
(int)                spatial axis of the dataset:
                      [0] = number of voxels along the x-axis (nx)
                      [1] = number of voxels along the y-axis (ny)
                      [2] = number of voxels along the z-axis (nz)
                     The voxel with 3-index (i,j,k) in a sub-brick
                     is located at position (i+j*nx+k*nx*ny), for
                     i=0..nx-1, j=0..ny-1, k=0..nz-1.  Each axis must
                     have at least 2 points!

TYPESTRING = One of "3DIM_HEAD_ANAT" or "3DIM_HEAD_FUNC" or
(string)            "3DIM_GEN_ANAT"  or "3DIM_GEN_FUNC".
             Determines if the dataset is of Anat or Func type (grayscale
             underlay or color overlay).  If Anat type, and if it is a
             _HEAD_ dataset in the +orig view, then Talairach markers
             might be attached to it (if it was created by to3d).

SCENE_DATA = Three integer codes describing the dataset type
(int)         [0] = view type: 0=+orig, 1=+acpc, 2=+tlrc
              [1] = func type:
                    If dataset is Anat type, then this is one of the
                    following codes:
                      #define ANAT_SPGR_TYPE   0
                      #define ANAT_FSE_TYPE    1
                      #define ANAT_EPI_TYPE    2
                      #define ANAT_MRAN_TYPE   3
                      #define ANAT_CT_TYPE     4
                      #define ANAT_SPECT_TYPE  5
                      #define ANAT_PET_TYPE    6
                      #define ANAT_MRA_TYPE    7
                      #define ANAT_BMAP_TYPE   8
                      #define ANAT_DIFF_TYPE   9
                      #define ANAT_OMRI_TYPE   10
                      #define ANAT_BUCK_TYPE   11
                    At this time, Anat codes 0..10 are treated identically
                    by all AFNI programs.  Code 11 marks the dataset as a
                    "bucket" type, which is treated differently in the
                    display; the "Define Function" control panel will have a
                    chooser that allows you to specify which sub-brick from
                    the bucket should be used to make the underlay image.

                    If dataset is Func type, then this is one of the
                    following codes:
                      #define FUNC_FIM_TYPE   0  /* 1 value           */
                      #define FUNC_THR_TYPE   1  /* obsolete          */
                      #define FUNC_COR_TYPE   2  /* fico: correlation */
                      #define FUNC_TT_TYPE    3  /* fitt: t-statistic */
                      #define FUNC_FT_TYPE    4  /* fift: F-statistic */
                      #define FUNC_ZT_TYPE    5  /* fizt: z-score     */
                      #define FUNC_CT_TYPE    6  /* fict: Chi squared */
                      #define FUNC_BT_TYPE    7  /* fibt: Beta stat   */
                      #define FUNC_BN_TYPE    8  /* fibn: Binomial    */
                      #define FUNC_GT_TYPE    9  /* figt: Gamma       */
                      #define FUNC_PT_TYPE    10 /* fipt: Poisson     */
                      #define FUNC_BUCK_TYPE  11 /* fbuc: bucket      */
                    These types are defined more fully in README.func_types.

                    Unfortunately, the func type codes overlap for Func
                    and Anat datasets.  This means that one cannot tell
                    the contents of a dataset from a single attribute.
                    However, this bad design choice (from 1994) is now
                    enshrined in the .HEAD files of thousands of datasets,
                    so it will be hard to change.

              [2] = 0 or 1 or 2 or 3, corresponding to the TYPESTRING
                    values given above.  If this value does not match the
                    typestring value, then the dataset is malformed and
                    AFNI will reject it!

ORIENT_SPECIFIC = Three integer codes describing the spatial orientation
(int)             of the dataset axes; [0] for the x-axis, [1] for the
                  y-axis, and [2] for the z-axis.  The possible codes are:
                    #define ORI_R2L_TYPE  0  /* Right to Left         */
                    #define ORI_L2R_TYPE  1  /* Left to Right         */
                    #define ORI_P2A_TYPE  2  /* Posterior to Anterior */
                    #define ORI_A2P_TYPE  3  /* Anterior to Posterior */
                    #define ORI_I2S_TYPE  4  /* Inferior to Superior  */
                    #define ORI_S2I_TYPE  5  /* Superior to Inferior  */
                  Note that these codes must make sense (e.g., they can't
                  all be 4).  Only program to3d enforces this restriction,
                  but if you create a nonsensical dataset, then bad things
                  will happen at some point.

                  Spatial xyz-coordinates in AFNI are sometimes used in
                  dataset order, which refers to the order given here.
                  They are also sometimes used in Dicom order, in which
                  x=R-L, y=A-P, and z=I-S (R,A,I are < 0; L,P,S are > 0).
                  There are utility functions for converting dataset
                  ordered 3-vectors to and from Dicom ordered 3-vectors
                  -- see the functions in file thd_coords.c.  Distances
                  in AFNI are always encoded in millimeters.

ORIGIN = Three numbers giving the xyz-coordinates of the center of
(float)  the (0,0,0) voxel in the dataset.  The order of these numbers
         is the same as the order of the xyz-axes (cf. ORIENT_SPECIFIC).
         However, the AFNI convention is that R-L, A-P, and I-S are
         negative-to-positive.  Thus, if the y-axis is P-A (say), then
         the y-origin is likely to be positive (and the y-delta, below,
         would be negative).  These numbers are usually computed from
         the centering controls in to3d.

DELTA = Three numbers giving the (x,y,z) voxel sizes, in the same order
        as ORIENT_SPECIFIC.  That is, [0] = x-delta, [1] = y-delta, and
        [2] = z-delta.  These values may be negative; in the example
        above, where the y-axis is P-A, then y-delta would be negative.
        The center of the (i,j,k) voxel is located at xyz-coordinates
        ORIGIN[0]+i*DELTA[0], ORIGIN[1]+j*DELTA[1], ORIGIN[2]+k*DELTA[2]

---------------------------------
Time-Dependent Dataset Attributes
---------------------------------
These attributes are mandatory if the .HEAD file describes a 3D+time
dataset.

TAXIS_NUMS = [0] = Number of points in time (at present, must be equal
(int)              to nvals=DATASET_RANK[1], or AFNI programs will not
                   be happy; that is, each time point can only have
                   a single numerical value per voxel).
             [1] = Number of slices with time offsets.  If zero, then
                   no slice-dependent time offsets are present (all slices
                   are presumed to be acquired at the same time).  If
                   positive, specifies the number of values to read
                   from TAXIS_OFFSETS.  Normally, this would either be 0
                   or be equal to DATASET_DIMENSIONS[2].
             [2] = Units codes for TAXIS_FLOATS[1]; one of the following
                     #define UNITS_MSEC_TYPE  77001  /* don't ask me */
                     #define UNITS_SEC_TYPE   77002  /* where these */
                     #define UNITS_HZ_TYPE    77003  /* came from! */

TAXIS_FLOATS = [0] = Time origin (in units given by TAXIS_NUMS[2]).
(float)              This is 0 in datasets created by to3d (at present).
               [1] = Time step (TR).
               [2] = Duration of acquisition.  This is 0 in datasets
                     created by to3d (at present)
               [3] = If TAXIS_NUMS[1] > 0, then this is the z-axis offset
                     for the slice-dependent time offsets.  This will
                     be equal to ORIGIN[2] in datasets created by to3d.c.
               [4] = If TAXIS_NUMS[1] > 0, then this is the z-axis step
                     for the slice-dependent time offsets.  This will
                     be equal to DELTA[2] in datasets created by to3d.c.

TAXIS_OFFSETS = If TAXIS_NUMS[1] > 0, then this array gives the time
(floats)        offsets of the slices defined by TAXIS_FLOATS[3..4].
                The time offset at
                  z = TAXIS_FLOATS[3] + k*TAXIS_FLOATS[4]
                is TAXIS_OFFSETS[k], for k=0..TAXIS_NUMS[1]-1.
                If TAXIS_NUMS[1] == 0, then this attribute is not used.

The functions in thd_timeof.c are used to compute the time for any given
voxel, taking into account the slice-dependent offsets.

---------------------------
Almost Mandatory Attributes
---------------------------
The following useful attributes are present in most AFNI datasets created
by AFNI package programs.  However, if they are not present, then the
function that assembles a dataset struct will get by.

IDCODE_STRING = 15 character string (plus NUL) giving a (hopefully)
(string)        unique identifier for the dataset, independent of the
                filename assigned by the user.  If this attribute is not
                present, the input routine will make one up for the
                dataset.  ID codes are used to provide links between
                datasets; see IDCODE_ANAT_PARENT for an example.
                (ID codes are generated in file thd_idcode.c.)

IDCODE_DATE = Maximum of 47 characters giving the creation date for
(string)      the dataset.  (Antedates the History Note, which contains
              the same information and more.)  Not used anywhere except
              in 3dinfo.

BYTEORDER_STRING = If this attribute is present, describes the byte-
(string)           ordering of the data in the .BRIK file.  Its value
                   must be one of the strings "LSB_FIRST" or "MSB_FIRST".
                   If this attribute is not present, AFNI will assume
                   that the brick is in the "native" order for the CPU
                   on which the program is running.  If this attribute
                   is present, and it is different from the native CPU
                   order, then short sub-bricks are 2-swapped (AB->BA)
                   and float or complex sub-bricks are 4-swapped
                   (ABCD->DCBA) when the .BRIK file is read into memory.

BRICK_STATS = There should be 2*nvals values here.  For the p-th
(float)       sub-brick, BRICK_STATS[2*p] is the minimum value stored
              in the brick, and BRICK_STATS[2*p+1] is the maximum value
              stored in the brick.  If the brick is scaled, then these
              values refer to the scaled values, NOT to the actual values
              stored in the .BRIK file.  Most AFNI programs create this
              attribute as they write the dataset to disk (e.g., by using
              the DSET_write macro, or by calling THD_load_statistics).
              The main function of this attribute is to provide the display
              of the dataset numerical ranges on the "Define Function"
              control panel.

BRICK_TYPES = There should be nvals=DATASET_RANK[1] values here.  For
(int)         the p-th sub-brick, BRICK_TYPES[p] is a code that tells
              the type of data stored in the .BRIK file for that
              sub-brick.  (Although it is possible to create a dataset
              that has varying sub-brick types, I do not recommend it.
              That is, I recommend that all BRICK_TYPE[p] values be
              the same.)  The legal types for AFNI datasets are
                0 = byte    (unsigned char; 1 byte)
                1 = short   (2 bytes, signed)
                3 = float   (4 bytes, assumed to be IEEE format)
                5 = complex (8 bytes: real+imaginary parts)
              Future versions of AFNI may support 2=int, 4=double, and
              6=rgb, or other extensions (but don't hold your breath).
              Relatively few AFNI programs support complex-valued
              datasets.  If this attribute is not present, then the
              sub-bricks will all be assumed to be shorts (which was
              the only datum type supported in AFNI 1.0).  The p-th
              sub-brick will have nx*ny*nz*sz bytes from the .BRIK file,
              where nx,ny,nz are from DATASET_DIMENSIONS and
              sz=sizeof(datum type).

BRICK_FLOAT_FACS = There should be nvals=DATASET_RANK[1] values here.  For
(float)            the p-th sub-brick, if f=BRICK_FLOAT_FACS[p] is positive,
                   then the values in the .BRIK should be scaled by f
                   to give their "true" values.  Normally, this would
                   only be used with byte or short types (to save disk
                   space), but it is legal to use f > 0 for float type
                   sub-bricks as well (although pointless and confusing).
                   If f==0, then the values are unscaled.  Possible uses
                   for f < 0 are reserved for the future.  If this
                   attribute is not present, then all brick factors are
                   taken to be 0 (i.e., no scaling).

BRICK_LABS = These are labels for the sub-bricks, and are used in the
(string)     choosers for sub-brick display when the dataset is a
             bucket type.  This attribute should contain nvals
             sub-strings, separated by NUL characters.  If this attribute
             is not present, then the input routine will make up some
             labels of the form "#0", "#1", etc.

BRICK_STATAUX = This stores auxiliary statistical information about
(float)         sub-bricks that contain statistical parameters.
                Each unit of this array contains the following
                  iv = sub-brick index  (0..nvals-1)
                  jv = statistical code (see below)
                  nv = number of parameters that follow (may be 0)
                  and then nv more numbers.
                That is, there are nv+3 numbers for each unit of this
                array, starting at location [0].  After the first
                unit is read out (from BRICK_STATAUX[0] up to
                BRICK_STATAUX[2+BRICK_STATAUX[2]]), then the next
                one starts immediately with the next value of iv.
                jv should be one of the 9 statistical types supported
                by AFNI, and described in README.func_types, and below:
           ------------- ----------------- ------------------------------
           Type Index=jv Distribution      Auxiliary Parameters [stataux]
           ------------- ----------------- ------------------------------
           FUNC_COR_TYPE Correlation Coeff # Samples, # Fit Param, # Orts
           FUNC_TT_TYPE  Student t         Degrees-of-Freedom (DOF)
           FUNC_FT_TYPE  F ratio           Numerator DOF, Denominator DOF
           FUNC_ZT_TYPE  Standard Normal   -- none --
           FUNC_CT_TYPE  Chi-Squared       DOF
           FUNC_BT_TYPE  Incomplete Beta   Parameters "a" and "b"
           FUNC_BN_TYPE  Binomial          # Trials, Probability per trial
           FUNC_GT_TYPE  Gamma             Shape, Scale
           FUNC_PT_TYPE  Poisson           Mean
                The main function of this attribute is to let the
                "Define Function" threshold slider show a p-value.
                This attribute also allows various other statistical
                calculations, such as the "-1zscore" option to 3dmerge.

STAT_AUX = The BRICK_STATAUX attribute allows you to attach statistical
(float)    distribution information to arbitrary sub-bricks of a bucket
           dataset.  The older STAT_AUX attribute is for the Func type
           datasets of the following types:
              fico = FUNC_COR_TYPE   fitt = FUNC_TT_TYPE
              fift = FUNC_FT_TYPE    fict = FUNC_CT_TYPE
              fibt = FUNC_BT_TYPE    fibn = FUNC_BN_TYPE
              figt = FUNC_GT_TYPE    fipt = FUNC_PT_TYPE
           These parameters apply to the second sub-brick (#1) of the
           dataset.  (Datasets of these types must have exactly 2
           sub-bricks.)  The number and definition of these parameters
           is the same as the BRICK_STATAUX cases, above.

----------------
Notes Attributes
----------------
Special characters in these strings are escaped.  For example, the
newline character is stored in the header as the two character
combination "\n", but will be displayed as a newline when the Notes
are printed (e.g., in 3dinfo).  The characters that are escaped are
    '\r'   '\n'   '\"'    '\t'   '\a'    '\v'    '\b'
     CR     LF     quote   TAB    BEL     VTAB    BS
For details, see function tross_Encode_String() in file thd_notes.c.

HISTORY_NOTE = A multi-line string giving the history of the dataset.
(string)       Can be read with 3dinfo, the Notes plugin, or 3dNotes.
               Written functions in thd_notes.c, including
                tross_Copy_History: copies dataset histories
                tross_Make_History: adds a history line from argc,argv

NOTES_COUNT = The number of auxiliary notes attached to the dataset
(int)         (from 0 to 999).

NOTE_NUMBER_001 = The first auxiliary note attached to the dataset.
(string)          Can be read/written with the Notes plugin, or 3dNotes.
                  (You have to guess what the attribute name for the
                  237th Note will be.)

-----------------------
Registration Attributes
-----------------------
Note that the MATVEC attributes are transformations of Dicom-ordered
coordinates, and so have to be permuted to transform dataset-ordered
xyz-coordinates.  The MATVEC attributes describe the transformation
of coordinates from input dataset to the output dataset in the form
   [xyz_out] = [mat] ([xyz_in]-[xyz_cen]) + [vec] + [xyz_cen]
where
   [mat]     is a 3x3 orthogonal matrix;
   [vec]     is a 3-vector;
   [xyz_in]  is the input vector;
   [xyz_cen] is the center of rotation (usually the center of the dataset);
   [xyz_out] is the output vector.
Dicom coordinate order is used for these matrices and vectors, which
means that they need to be permuted to dataset order for application.
For examples of how this is done, see 3drotate.c and 3dvolreg.c.

TAGALIGN_MATVEC = 12 numbers giving the 3x3 matrix and 3-vector of the
(float)           transformation derived in 3dTagalign.  The matrix-vector
                  are loaded from the following elements of the attribute:
                            [ 0 1  2 ]           [  3 ]
                    [mat] = [ 4 5  6 ]   [vec] = [  7 ]
                            [ 8 9 10 ]           [ 11 ]
                  This is used by 3drotate with the -matvec_dset option,
                  and is written by 3dTagalign.

VOLREG_MATVEC_xxxxxx = For sub-brick #xxxxxx (so a max of 999,999
(float)                sub-bricks can be used), this stores the 12 numbers
                       for the matrix-vector of the transformation from
                       3dvolreg.  This is used by the -rotparent options
                       of 3drotate and 3dvolreg, and is written into the
                       output dataset of 3dvolreg.  The value of xxxxxx
                       is printf("%06d",k) for k=0..VOLREG_ROTCOM_NUM-1.

VOLREG_ROTCOM_xxxxxx = The -rotate/-ashift options to 3drotate that are
(string)               equivalent to the above matrix-vector transformation.
                       It is not actually used anywhere, but is there for
                       reference.

VOLREG_CENTER_OLD = The xyz-coordinates (Dicom order) of the center of
(float)             the input dataset to 3dvolreg; this is written to
                    3dvolreg's output dataset, and is used by the
                    -rotparent options to 3dvolreg and 3drotate.

VOLREG_CENTER_BASE = The xyz-coordinates (Dicom order) of the center
                     of the base dataset to 3dvolreg; this is written
                     to 3dvolreg's output dataset, and is used by the
                     -rotparent options to 3dvolreg and 3drotate.

VOLREG_ROTPARENT_IDCODE = If a 3dvolreg run uses the -rotparent option,
(string)                  then this value in the header of the output
                          dataset tells which dataset was the rotparent.

VOLREG_ROTPARENT_NAME = The .HEAD filename of the -rotparent.
(string)

VOLREG_GRIDPARENT_IDCODE = Similar to the above, but for a 3dvolreg
(string)                   output dataset that was created using a
                           -gridparent option.

VOLREG_GRIDPARENT_NAME = The .HEAD filename of the -gridparent.
(string)

VOLREG_INPUT_IDCODE = In the 3dvolreg output dataset header, this
(string)              tells which dataset was the input to 3dvolreg.

VOLREG_INPUT_NAME = The .HEAD filename of the 3dvolreg input dataset.
(string)

VOLREG_BASE_IDCODE = In the 3dvolreg output dataset header, this
(string)             tells which dataset was the base for registration.

VOLREG_BASE_NAME = The .HEAD filename of the 3dvolreg base dataset.
(string)

VOLREG_ROTCOM_NUM = The single value in here tells how many sub-bricks
(int)               were registered by 3dvolreg.  (The only reason this
                    might be different than nvals is that someone might
                    later tack extra sub-bricks onto this dataset using
                    3dTcat.)  This is how many VOLREG_MATVEC_xxxxx and
                    VOLREG_ROTCOM_xxxxxx attributes are present in the
                    dataset.

------------------------
Miscellaneous Attributes
------------------------
IDCODE_ANAT_PARENT = ID code for the "anatomy parent" of this dataset
(string)             (if it has one).

TO3D_ZPAD = 3 integers specifying how much zero-padding to3d applied
(int)       when it created the dataset (x,y,z axes).  At this time,
            only the [2] component could be nonzero.  If this attribute
            is not present, then no zero-padding was done by to3d.

------------------
Warping Attributes
------------------
IDCODE_WARP_PARENT = ID code for the "warp parent" of this dataset
(string)             (if it has one).  This will normally be a dataset
                     in the +orig view, even for datasets transformed
                     from +acpc to +tlrc.  That is, the transformation
                     chain +orig to +acpc to +tlrc is symbolic; when
                     you transform a dataset from +acpc to +tlrc, AFNI
                     catenates that transformation onto the +orig to
                     +acpc transformation and stores the result, which
                     is the direct transformation from +orig to +tlrc.

WARP_TYPE = [0] = Integer code describing the type of warp:
(int)               #define WARP_AFFINE_TYPE        0
                    #define WARP_TALAIRACH_12_TYPE  1
            [1] = No longer used (was the resampling type, but that
                  is now set separately by the user).

WARP_DATA = Data that define the transformation from the warp parent
(float)     to the current dataset.  Each basic linear transformation
            (BLT) takes 30 numbers.  For WARP_AFFINE_TYPE, there is one
            BLT per warp; for WARP_TALAIRACH_12_TYPE, there are 12 BLTs
            per warp.  Thus, for WARP_AFFINE_TYPE there should be 30
            numbers in WARP_DATA, and for WARP_TALAIRACH_12_TYPE there
            should be 360 numbers.  (WARP_AFFINE_TYPE is used for the
            +orig to +acpc transformation; WARP_TALAIRACH_12_TYPE is
            used for the +orig to +tlrc transformation - duh.)

Each BLT is defined by a struct that contains two 3x3 matrices and four
3-vectors (2*3*3+4*3 = the 30 numbers).  These values are:

 [mfor] = 3x3 forward transformation matrix    [0..8]   } range of
 [mbac] = 3x3 backward transformation matrix   [9..17]  } indexes
 [bvec] = 3-vector for forward transformation  [18..20] } in the
 [svec] = 3-vector for backward transformation [21..23] } WARP_DATA
 [bot]  } two more 3-vectors that              [24..26] } BLT
 [top]  } are described below                  [27..29] } array

(the matrices are stored in row-major order; e.g.,
                [ 0 1 2 ]
       [mfor] = [ 3 4 5 ]
                [ 6 7 8 ] -- the indices of the [mfor] matrix).

The forward transformation is  [x_map] = [mfor] [x_in]  - [bvec];
The backward transformation is [x_in]  = [mbac] [x_map] - [svec]
(which implies [svec] = -[mbac] [bvec] and [mbac] = Inverse{[mfor]}).

The forward transformation is the transformation of Dicom order
coordinates from the warp parent dataset (usually in the +orig view)
to the warped dataset (usually +acpc or +tlrc).  The backward
transformation is just the inverse of the forward transformation, and
is stored for convenience (it could be recomputed from the forward
transformation whenever it was needed, but that would be too much
like work).  The identity BLT would be stored as these 30 numbers:
      1 0 0          }
      0 1 0          } [mfor] = I
      0 0 1          }
      1 0 0          }
      0 1 0          } [mbac] = I
      0 0 1          }
      0 0 0          } [bvec] = 0
      0 0 0          } [svec] = 0
      botx boty botz } these numbers are described below,
      topx topy topz } and depend on the application.

If the transformation is WARP_TALAIRACH_12_TYPE, then each BLT only
applies to a bounded region of 3-space.  The [bot] and [top] vectors
define the limits for each BLT, in the warped [x_map] coordinates.
These values are used in the function AFNI_transform_vector() to
compute the transformation of a 3-vector between +orig and +tlrc
coordinates.  For example, to compute the transformation from +tlrc
back to +orig of a vector [x_tlrc], the code must scan all 12
[bot]..[top] regions to see which BLT to use.  Similarly, to transform
[x_orig] from +orig to +tlrc, the vector must be transformed with
each BLT and then the result tested to see if it lies within the BLT's
[bot]..[top] region.  (If a lower bound is supposed to be -infinity,
then that element of [bot] is -9999; if an upper bound is supposed to
be +infinity, then that element of [top] is +9999 -- there is an
implicit assumption that AFNI won't be applied to species with heads
more than 10 meters in size.)

For the +orig to +acpc transformation (of WARP_AFFINE_TYPE), the [bot]
and [top] vectors store the bounding box of the transformed dataset.
However, this fact isn't used much (only when the new dataset is created
when the user presses the "Define Markers->Transform Data" button, which
is when the +acpc.HEAD file would be created).  If you were to manually
edit the +acpc.HEAD file and change [bot] and [top], nothing would happen.
This is not true for a +tlrc.HEAD file, since the [bot] and [top] vectors
actually mean something for WARP_TALAIRACH_12_TYPE.

----------------------------
Talairach Markers Attributes
----------------------------
These are used to define the transformations from +orig to +acpc
coordinates, and from +acpc to +tlrc.  If they are present, then opening
the "Define Markers" panel in AFNI will show a list of the markers and
let you edit their locations.  MARKSET_ALIGN (+orig to +acpc) markers are
attached to 3DIM_HEAD_ANAT +orig datasets created by to3d (if there is
no time axis).  An empty set of such markers can also be attached to such
datasets using the "-markers" option to 3drefit.  (The label and help
strings for the 2 types of marker sets are defined in 3ddata.h.)

MARKS_XYZ = 30 values giving the xyz-coordinates (Dicom order) of
(float)     the markers for this dataset.  (A maximum of 10 markers
            can be defined for a dataset.)  MARKS_XYZ[0] = x0,
            MARKS_XYZ[1] = y0, MARKS_XYZ[2] = z0, MARKS_XYZ[3] = x1,
            etc.  If a marker's xyz-coordinates are outside the
            bounding box of the dataset, it is considered not to
            be set.  For this purpose, the bounding box of the dataset
            extends to the edges of the outermost voxels (not just their
            centers).

MARKS_LAB = 200 characters giving the labels for the markers (20 chars
(string)    per marker, EXACTLY, including the NULs).  A marker whose
            string is empty (all NUL characters) will not be defined
            or shown by AFNI.

MARKS_HELP = 2560 characters giving the help strings for the markers
(string)     (256 chars per marker, EXACTLY, including the NULs).

MARKS_FLAGS = [0] = Type of markers; one of the following:
(int)                 #define MARKSET_ALIGN    1 /* +orig to +acpc */
                      #define MARKSET_BOUNDING 2 /* +acpc to +tlrc */
              [1] = This should always be 1 (it is an "action code",
                    but the only action ever defined was warping).

--------------------------------
Attributes for User-Defined Tags
--------------------------------
These tags defined and set by plug_tag.c; their original purpose was
to aid in 3D alignment by having the user mark homologous points that
would then be aligned with 3dTagalign.  This application has pretty
much been superseded with the advent of "3dvolreg -twopass" (but you
never know, do you?).

TAGSET_NUM = [0] = ntag = number of tags defined in the dataset (max=100)
(int)        [1] = nfper = number of floats stored per tag (should be 5)

TAGSET_FLOATS = ntag*nfper values; for tag #i:
(float)          [nfper*i+0] = x-coordinate (Dicom order)
                 [nfper*i+1] = y-coordinate (Dicom order)
                 [nfper*i+2] = z-coordinate (Dicom order)
                 [nfper*i+3] = tag numerical value
                 [nfper*i+4] = sub-brick index of tag (if >= 0),
                               or "not set" flag (if < 0)

TAGSET_LABELS = ntag sub-strings (separated by NULs) with the labels
(string)        for each tag.

-------------------------
Nearly Useless Attributes
-------------------------
These attributes are leftovers from the early days of AFNI, but never
became useful for anything.

LABEL_1 = A short label describing the dataset.
(string)

LABEL_2 = Another short label describing the dataset.
(string)

DATASET_NAME = A longer name describing the dataset contents.
(string)

DATASET_KEYWORDS = List of keywords for this dataset.  By convention,
(string)           keywords are separated by " ; ".  (However, no
                   program at this time uses the keywords or this
                   convention!)

BRICK_KEYWORDS = List of keywords for each sub-brick of the dataset.
(string)         Should contain nvals sub-strings (separated by NULs).
                 Again, by convention, separate keywords for the same
                 sub-brick would be separated by " ; " within the
                 sub-brick's keyword string.

--------------------------
Programming Considerations
--------------------------
When a new dataset is created, it is usually made with one of the library
functions EDIT_empty_copy() or EDIT_full_copy().  These make a copy of a
dataset struct in memory.  They do NOT preserve attributes.  Various struct
elements will be translated to attributes when the dataset is written to
disk (see thd_writedset.c), but other attributes in the "parent" dataset
are not automatically copied.  This means that if you attach some extra
information to a dataset in a plugin using an attribute, say, and write
it out using the DSET_write_header() macro, that information will not be
preserved in "descendants" of that dataset.  For example, if you did
  3dcalc -a old+orig -expr "a" -prefix new
then any plugin-defined attributes attached to old+orig.HEAD will not be
reproduced in new+orig.HEAD.  (In fact, this would be a good way to see
exactly what attributes are generated by AFNI.)

==============================================================================
                  Accessing Dataset Elements in a C Program 
==============================================================================
Suppose you know the name of a dataset, and want to read some information
about it in your C program.  Parsing the dataset .HEAD file, as described
above, would be tedious and subject to change.  The "libmri.a" library
(header file "mrilib.h") compiled with AFNI has functions that will do
this stuff for you.  The code to open a dataset file, read all its header
information, and return an "empty" (unpopulated with volumetric data)
dataset is like so:

   THD_3dim_dataset *dset ;
   dset = THD_open_dataset( "fred+orig.HEAD" ) ;
   if( dset == NULL ){ fprintf(stderr,"My bad.\n"); exit(1); }

At this point, "dset" points to the complicated and ever-growing struct
type that comprises an AFNI dataset (defined in "3ddata.h", which is
included by "mrilib.h").  Rather than access the elements of this struct
yourself, there is a large number of macros to do this for you.  Some of
these are documented below.

Macros to Query the Status of a Dataset
---------------------------------------
These macros return 1 if the dataset satisfies some condition, and return
0 if it doesn't.  Here, the input "ds" is of type "THD_3dim_dataset *":

DSET_ONDISK(ds)      returns 1 if the dataset actually has data on disk
DSET_IS_BRIK(ds)     returns 1 if the dataset actually has a .BRIK file
DSET_IS_MINC(ds)     returns 1 if the dataset is from a MINC file
ISFUNC(ds)           returns 1 if the dataset is a functional type
ISANAT(ds)           returns 1 if the dataset is an anatomical type
ISFUNCBUCKET(ds)     returns 1 if the dataset is a functional bucket
ISANATBUCKET(ds)     returns 1 if the dataset is an anatomical bucket
ISBUCKET(ds)         returns 1 if the dataset is either type of bucket
DSET_COMPRESSED(ds)  returns 1 if the dataset .BRIK file is compressed
DSET_LOADED(ds)      returns 1 if the dataset .BRIK file has been loaded
                     into memory via macro DSET_load()

Macros to Query Information About Dataset Geometry
--------------------------------------------------
DSET_NVALS(ds)  returns the number of sub-bricks in the dataset
DSET_NVOX(ds)   returns the number of voxels in one sub-brick
DSET_NX(ds)     returns the x-axis grid array dimension
DSET_NY(ds)     returns the y-axis grid array dimension
DSET_NZ(ds)     returns the z-axis grid array dimension
DSET_DX(ds)     returns the x-axis grid spacing (in mm)
DSET_DY(ds)     returns the y-axis grid spacing (in mm)
DSET_DZ(ds)     returns the z-axis grid spacing (in mm)
DSET_XORG(ds)   returns the x-axis grid origin (in mm)
DSET_YORG(ds)   returns the y-axis grid origin (in mm)
DSET_ZORG(ds)   returns the z-axis grid origin (in mm)

Along the x-axis, voxel index #i is at x = DSET_XORG(ds)+i*DSET_DX(ds),
for i = 0 .. DSET_NX(ds)-1.  Similar remarks apply to the y- and z-axes.
Note that DSET_DX(ds) (etc.) may be negative.

DSET_CUBICAL(ds) returns 1 if the dataset voxels are cubical,
                 returns 0 if they are not

The following macros may be useful for converting from 1D indexes (q)
into the sub-brick arrays to 3D spatially relevant indexes (i,j,k):

DSET_index_to_ix(ds,q) returns the value of i that corresponds to q
DSET_index_to_jy(ds,q) returns the value of j that corresponds to q
DSET_index_to_kz(ds,q) returns the value of k that corresponds to q

DSET_ixyz_to_index(ds,i,j,k) returns the q that corresponds to (i,j,k)

Macros to Query Information about the Dataset Time Axis
-------------------------------------------------------
DSET_TIMESTEP(ds)  returns the TR; if 0 is returned, there is no time axis
DSET_NUM_TIMES(ds) returns the number of points along the time axis;
                   if 1 is returned, there is no time axis

Macros to Query Information About Dataset Sub-Brick Contents
------------------------------------------------------------
DSET_BRICK_TYPE(ds,i) returns a code indicating the type of data stored
                      in the i-th sub-brick of the dataset; the type
                      codes are defined in "mrilib.h" (e.g., MRI_short)

DSET_BRICK_FACTOR(ds,i) returns the float scale factor for the data in
                        the i-th sub-brick of the dataset; if 0.0 is
                        returned, then don't scale this data, otherwise
                        each value should be scaled by this factor before
                        being used

DSET_BRICK_BYTES(ds,i) returns the number of bytes used to store the
                       data in the i-th sub-brick of the dataset

DSET_BRICK_LABEL(ds,i) returns a pointer to the string label for the
                       i-th sub-brick of the dataset

DSET_BRICK_STATCODE(ds,i) returns an integer code for the type of statistic
                          stored in the i-th sub-brick of the dataset
                          (e.g., FUNC_FT_TYPE for an F-test statistic);
                          returns -1 if this isn't a statistic sub-brick

DSET_BRICK_STATAUX(ds,i) returns a pointer to a float array holding the
                         auxiliary statistical parameters for the i-th
                         sub-brick of the dataset; returns NULL if this
                         isn't a statistic sub-brick

DSET_BRICK_STATPAR(ds,i,j) returns the float value of the j-th auxiliary
                           statistical parameter of the i-th sub-brick of
                           the dataset; returns 0.0 if this isn't a
                           statistic sub-brick

DSET_BRICK_ARRAY(ds,i) returns a pointer to the data array for the i-th
                       sub-brick of the dataset; returns NULL if the
                       dataset .BRIK wasn't loaded into memory yet
                       via the macro DSET_load()

Macros to Query Information about Dataset Filenames (etc.)
----------------------------------------------------------
DSET_PREFIX(ds)       returns a pointer to the dataset's prefix string
DSET_FILECODE(ds)     returns a pointer to the dataset's prefix+view string
DSET_HEADNAME(ds)     returns a pointer to the dataset's .HEAD filename string
DSET_BRIKNAME(ds)     returns a pointer to the dataset's .BRIK filename string
DSET_DIRNAME(ds)      returns a pointer to the dataset's directory name string
DSET_IDCODE(ds)->str  returns a pointer to the dataset's unique ID code string
DSET_IDCODE(ds)->date returns a pointer to the dataset's date of creation
EQUIV_DSETS(ds1,ds2)  returns 1 if the two datasets have same ID code string

Macros to Do Something with the Dataset
---------------------------------------
DSET_load(ds)    reads the dataset .BRIK file into memory (if it is already
                 loaded, it does nothing)

DSET_unload(ds)  purges the dataset sub-brick arrays from memory (but the
                 dataset struct itself is there, ready to be reloaded)

DSET_delete(ds)  purges the dataset sub-brick arrays from memory, then
                 destroys the dataset struct itself as well

DSET_mallocize(ds) forces the memory for the dataset to be allocated with
                   malloc(), rather than possibly allowing mmap(); this
                   macro should be used before DSET_load(); you CANNOT write
                   into a mmap()-ed dataset's arrays, so if you are altering
                   a dataset in-place, it must be mallocize-d!

DSET_write(ds)   writes a dataset (.HEAD and .BRIK) to disk; AFNI can't write
                 MINC formatted datasets to disk, so don't try

Important Dataset Fields without Macros
---------------------------------------
ds->daxes->xxorient  gives the orientation of the x-axis in space; this will
                     be one of the following int codes:
                       #define ORI_R2L_TYPE  0  /* Right-to-Left */
                       #define ORI_L2R_TYPE  1  /* Left-to-Right */
                       #define ORI_P2A_TYPE  2  /* Posterior-to-Anterior */
                       #define ORI_A2P_TYPE  3  /* Anterior-to-Posterior */
                       #define ORI_I2S_TYPE  4  /* Inferior-to-Superior */
                       #define ORI_S2I_TYPE  5  /* Superior-to-Inferior */

ds->daxes->yyorient  gives the orientation of the y-axis in space
ds->daxes->zzorient  gives the orientation of the z-axis in space

Functions to Access Attributes
------------------------------
Most attributes are loaded into dataset struct fields when a dataset is
opened with THD_open_dataset().  To access the attributes directly, you
can use the following functions:

ATR_float  *afl = THD_find_float_atr ( dset->dblk , "attribute_name" ) ;
ATR_int    *ain = THD_find_int_atr   ( dset->dblk , "attribute_name" ) ;
ATR_string *ast = THD_find_string_atr( dset->dblk , "attribute_name" ) ;

The ATR_ structs are typedef-ed in 3ddata.h (included by mrilib.h).
Cut directly from the living code:

typedef struct {
      int     type ;  /*!< should be ATR_FLOAT_TYPE */
      char *  name ;  /*!< name of attribute, read from HEAD file */
      int     nfl ;   /*!< number of floats stored here */
      float * fl ;    /*!< array of floats stored here */
} ATR_float ;

You can access the attribute values with afl->fl[i], for i=0..atr->nfl-1.
This functionality is used in 3dvolreg.c, for example, to access the
attributes whose name start with "VOLREG_".

====================================
Robert W Cox, PhD
National Institute of Mental Health
====================================
