changeset 1684:8c00fa0a8a63

New test files
author bert <bert>
date Tue, 02 Mar 2004 21:38:28 +0000
parents 5c5da1363212
children 9e209d8f160e
files libsrc2/test/Makefile libsrc2/test/convert-test.c libsrc2/test/datatype-test.c libsrc2/test/dimension-test.c libsrc2/test/full-test.c libsrc2/test/grpattr-test.c libsrc2/test/hyper-test.c libsrc2/test/label-test.c libsrc2/test/m2stats.c libsrc2/test/record-test.c libsrc2/test/slice-test.c libsrc2/test/valid-test.c libsrc2/test/volprops-test.c
diffstat 13 files changed, 2800 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/Makefile
@@ -0,0 +1,56 @@
+LIBS = -lminc2 -lminc -lnetcdf -lhdf5 -lm
+LDFLAGS = -L.. -L/localhome/bert/lib
+CPPFLAGS = -I.. -I/localhome/bert/include -g -Wall
+
+EXE=	convert-test \
+	datatype-test \
+	dimension-test \
+	full-test \
+	grpattr-test \
+	hyper-test \
+	label-test \
+	m2stats \
+	record-test \
+	slice-test \
+	valid-test \
+	volprops-test
+
+all: $(EXE)
+
+$(EXE): ../libminc2.a
+
+convert-test: convert-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+datatype-test: datatype-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+dimension-test: dimension-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+full-test: full-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+grpattr-test: grpattr-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+hyper-test: hyper-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+label-test: label-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+record-test: record-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+slice-test: slice-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+valid-test: valid-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+volprops-test: volprops-test.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
+
+m2stats: m2stats.o
+	$(CC) $(LDFLAGS) -Wall -g -o $@ $< $(LIBS)
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/convert-test.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+static int error_cnt = 0;
+
+int
+main(int argc, char **argv)
+{
+    int result;
+    double voxel[3];
+    double world[3];
+    double new_voxel[3];
+    unsigned long coords[3];
+    unsigned long count[3] = {1,1,1};
+    int i;
+    mihandle_t hvol;
+    double v1, v2;
+    double r1, r2;
+
+    if (argc != 5) {
+        TESTRPT("must specify a file name and position!", 0);
+        exit(-1);
+    }
+
+    result = miopen_volume(argv[1], MI2_OPEN_READ, &hvol);
+    if (result < 0) {
+        TESTRPT("miopen_volume error", result);
+    }
+
+    coords[0] = atof(argv[2]);
+    coords[1] = atof(argv[3]);
+    coords[2] = atof(argv[4]);
+
+    voxel[0] = coords[0];
+    voxel[1] = coords[1];
+    voxel[2] = coords[2];
+
+    miconvert_3D_voxel_to_world(hvol, voxel, world);
+
+    for (i = 0; i < 3; i++) {
+        printf("%.20g ", world[i]);
+    }
+    printf("\n");
+
+    miconvert_3D_world_to_voxel(hvol, world, new_voxel);
+    for (i = 0; i < 3; i++) {
+        printf("%.20g ", new_voxel[i]);
+    }
+    printf("\n");
+
+
+    /* Get a voxel value.
+     */
+    result = miget_voxel_value_hyperslab(hvol, MI_TYPE_DOUBLE,
+                                         coords, count, &v1);
+    if (result < 0) {
+        TESTRPT("miget_voxel_value_hyperslab error", result);
+    }
+
+    /* Convert from voxel to real.
+     */
+    result = miconvert_voxel_to_real(hvol, coords, 3, v1, &r1);
+    if (result < 0) {
+        TESTRPT("miconvert_voxel_to_real error", result);
+    }
+    printf("voxel %f => real %f\n", v1, r1);
+
+    /* Convert it back to voxel.
+     */
+    result = miconvert_real_to_voxel(hvol, coords, 3, r1, &v2);
+    if (result < 0) {
+        TESTRPT("miconvert_real_to_voxel error", result);
+    }
+    printf("real %f => voxel %f\n", r1, v2);
+
+    /* Compare to the value read via the ICV
+     */
+    result = miget_real_value(hvol, coords, 3, &r2);
+    if (result < 0) {
+        TESTRPT("miget_real_value error", result);
+    }
+    printf("real from ICV: %f\n", r2);
+    printf("\n");
+
+
+    if (v1 != v2) {
+        TESTRPT("Voxel value mismatch", 0);
+    }
+    if (r1 != r2) {
+        TESTRPT("Real value mismatch", 0);
+    }
+
+    result = miget_voxel_value(hvol, coords, 3, &v1);
+    if (result < 0) {
+        TESTRPT("miget_voxel_value error", result);
+    }
+
+    printf("voxel from mivarget1: %f\n", v1);
+
+    return (error_cnt);
+}
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/datatype-test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include "minc2.h"
+
+int
+main(int argc, char **argv)
+{
+    miclass_t myclass;
+    mitype_t mytype;
+    misize_t mysize;
+    char *myname;
+    mihandle_t volume;
+
+    /* Turn off automatic error reporting.
+     */
+    H5Eset_auto(NULL, NULL);
+
+    /* Check each file.
+     */
+    while (--argc > 0) {
+	
+	++argv;
+
+	if (micreate_volume(*argv, 0, NULL, 0, 0, NULL, &volume) < 0) {
+	    fprintf(stderr, "Error opening %s\n", *argv);
+	}
+	else {
+	    int i;
+	    /* Repeat many times to expose resource leakage problems, etc.
+	     */
+	    for (i = 0; i < 25000; i++) {
+		miget_data_type(volume, &mytype);
+		miget_data_type_size(volume, &mysize);
+		miget_data_class(volume, &myclass);
+		miget_space_name(volume, &myname);
+	    
+		mifree_name(myname);
+	    }
+
+	    miclose_volume(volume);
+
+	    printf("file: %s type %d size %ld class %d name %s\n", *argv,
+		   mytype, mysize, myclass, myname);
+	}
+
+    }
+    return (0);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/dimension-test.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+
+static int error_cnt = 0;
+
+#define CX 10
+#define CY 10
+#define CZ 6
+#define NDIMS 3
+
+int main(int argc, char **argv)
+{
+  mihandle_t vol;
+  int r;
+  midimhandle_t dimh, dimh1,dimh2; 
+  midimhandle_t dim[3];
+  mivolumeprops_t props;
+  double cosines[3];
+  double offsets[3];
+  double widths[3];
+  int n;
+  midimhandle_t dimens[3];
+  unsigned long coords[NDIMS];
+    unsigned long count[NDIMS];
+    int i,j,k;
+    struct test {
+        int r;
+        int g;
+        int b;
+    } voxel;
+    int result = 1;
+  /* Write data one voxel at a time. */
+    for (i = 0; i < NDIMS; i++) {
+        count[i] = 1;
+    }
+
+    r = minew_volume_props(&props);
+    r = miset_props_compression_type(props, MI_COMPRESS_ZLIB);
+    r = miset_props_zlib_compression(props, 3);
+     r = miset_props_multi_resolution(props, 1, 3);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  
+  r = micreate_dimension("xspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 10,&dimh);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  dim[0]=dimh;
+  
+  r = micreate_dimension("yspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 10,&dimh1);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  dim[1]=dimh1;
+  r = micreate_dimension("zspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 6,&dimh2);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  
+  dim[2]=dimh2;
+ 
+  r = micreate_volume("test_multi_h5.mnc", 3, dim, MI_TYPE_UINT, MI_CLASS_REAL,props,&vol);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+
+  r = micreate_volume_image(vol);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  
+  r = miget_volume_dimension_count(vol, MI_DIMCLASS_SPATIAL, MI_DIMATTR_ALL, &n);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  printf( " N is %d \n", n);
+
+  for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+            for (k = 0; k < CZ; k++) {
+                coords[0] = i;
+                coords[1] = j;
+                coords[2] = k;
+
+                voxel.r = i;
+                voxel.g = j;
+                voxel.b = k;
+                
+                result = miset_voxel_value_hyperslab(vol, MI_TYPE_UINT,
+						     coords, count, &voxel);
+                if (result < 0) {
+                    TESTRPT("Error writing voxel", result);
+                }
+            }
+        }
+    }
+
+  /* call miselect_resolution() 
+   */
+ 
+  r = miflush_from_resolution(vol, 3);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  r = miclose_volume(vol);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  
+  if (error_cnt != 0) {
+    fprintf(stderr, "%d error%s reported\n", 
+	    error_cnt, (error_cnt == 1) ? "" : "s");
+  }
+  else {
+    fprintf(stderr, "No errors\n");
+   
+  }
+  return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/full-test.c
@@ -0,0 +1,258 @@
+/* A test program to evaluate some of the MINC2 API's and features.
+ */
+#include <stdio.h>
+#include "minc2.h"
+
+#define ND 3
+#define CX 100
+#define CY 100
+#define CZ 100
+
+int test1(int do_real)
+{
+    int i, j, k;
+    int r;
+    mivolumeprops_t hprops;
+    midimhandle_t hdim[ND];
+    mihandle_t hvol;
+    double offsets[CX];
+    unsigned long coords[ND];
+
+    for (i = 0; i < CX; i++) {
+        offsets[i] = (double) i * (double) i;
+    }
+
+    r = minew_volume_props(&hprops);
+    if (r != 0) {
+        fprintf(stderr, "unexpected error\n");
+        return (1);
+    }
+
+    r = miset_props_compression_type(hprops, MI_COMPRESS_ZLIB);
+    if (r != 0) {
+        fprintf(stderr, "unexpected error\n");
+        return (1);
+    }
+
+    r = micreate_dimension("xspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_NOT_REGULARLY_SAMPLED, CX, &hdim[0]);
+    if (r != 0) {
+        fprintf(stderr, "unexpected error\n");
+        return (1);
+    }
+
+    r = miset_dimension_offsets(hdim[0], 100, 0, offsets);
+    if (r != 0) {
+        fprintf(stderr, "unexpected error\n");
+        return (1);
+    }
+
+    r = micreate_dimension("yspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CY, &hdim[1]);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = miset_dimension_start(hdim[1], -10.0);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = micreate_dimension("zspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CZ, &hdim[2]);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = miset_dimension_start(hdim[2], -20.0);
+    if (r != 0) {
+        fprintf(stderr, "error setting dimension start\n");
+        return (1);
+    }
+
+    r = miset_dimension_separation(hdim[2], 2.0);
+    if (r != 0) {
+        fprintf(stderr, "error setting dimension separation\n");
+        return (1);
+    }
+
+    r = micreate_volume("fulltest.mnc", 3, hdim, MI_TYPE_SHORT, MI_CLASS_REAL,
+                        hprops, &hvol);
+    if (r != 0) {
+        fprintf(stderr, "error creating volume\n");
+        return (1);
+    }
+
+    r = micreate_volume_image(hvol);
+    if (r != 0) {
+        fprintf(stderr, "error creating volume image\n");
+        return (1);
+    }
+
+    r = miset_volume_valid_range(hvol, 1000, -1000);
+    if (r != 0) {
+        fprintf(stderr, "error setting valid range\n");
+        return (1);
+    }
+
+    r = miset_volume_range(hvol, 5, -5);
+    if (r < 0) {
+        fprintf(stderr, "error setting volume range\n");
+        return (1);
+    }
+
+    for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+           for (k = 0; k < CZ; k++) {
+                coords[0] = i;
+                coords[1] = j;
+                coords[2] = k;
+
+                if (do_real) {
+                    r = miset_real_value(hvol, coords, ND, 1.0);
+                    if (r < 0) {
+                        return (1);
+                    }
+                }
+                else {
+                    r = miset_voxel_value(hvol, coords, ND, 200.0);
+                    if (r < 0) {
+                        return (1);
+                    }
+                }
+            }
+        }
+    }
+
+    r = mifree_volume_props(hprops);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = miclose_volume(hvol);
+    if (r < 0) {
+        return (1);
+    }
+
+    return (0);
+}
+
+int test2()
+{
+    midimhandle_t hdim[ND];
+    mihandle_t hvol;
+    int r;
+    int i,j,k;
+    unsigned long coords[ND];
+
+    r = micreate_dimension("xspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CX, &hdim[2]);
+    if (r != 0) {
+        return (1);
+    }
+
+    r = micreate_dimension("yspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CY, &hdim[1]);
+
+    if (r < 0) {
+        return (1);
+    }
+
+    r = miset_dimension_start(hdim[1], -10.0);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = micreate_dimension("zspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CZ, &hdim[0]);
+    if (r < 0) {
+        return (1);
+    }
+
+    r = miset_dimension_start(hdim[2], -20.0);
+    if (r < 0) {
+        fprintf(stderr, "error setting dimension start\n");
+        return (1);
+    }
+
+    r = miset_dimension_separation(hdim[2], 2.0);
+    if (r < 0) {
+        fprintf(stderr, "error setting dimension separation\n");
+        return (1);
+    }
+
+    r = micreate_volume("cmpltest.mnc", 3, hdim, MI_TYPE_FCOMPLEX, 
+                        MI_CLASS_COMPLEX,
+                        NULL, &hvol);
+    if (r != 0) {
+        fprintf(stderr, "error creating volume\n");
+        return (1);
+    }
+
+    r = micreate_volume_image(hvol);
+    if (r != 0) {
+        fprintf(stderr, "error creating volume image\n");
+        return (1);
+    }
+
+#if 0
+    r = miset_volume_valid_range(hvol, 1000, -1000);
+    if (r != 0) {
+        fprintf(stderr, "error setting valid range\n");
+    }
+
+    r = miset_volume_range(hvol, 5, -5);
+    if (r < 0) {
+        fprintf(stderr, "error setting volume range\n");
+    }
+#endif
+
+    for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+            for (k = 0; k < CZ; k++) {
+                coords[0] = i;
+                coords[1] = j;
+                coords[2] = k;
+            }
+        }
+    }
+
+    r = miclose_volume(hvol);
+    if (r < 0) {
+        return (1);
+    }
+
+    return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+    int errors;
+    int do_real = 0;
+
+    while (--argc > 0) {
+        char *argp = *++argv;
+        if (*argp == '-') {
+            argp++;
+            switch (*argp) {
+            case 'r':
+                do_real = 1;
+                break;
+            }
+        }
+    }
+
+    errors = 0;
+    errors += test1(do_real);
+    errors += test2();
+
+    if (errors == 0) {
+        printf("No errors\n");
+    }
+    else {
+        printf("%d error%s found\n", errors, (errors == 1) ? "" : "s");
+    }
+    return (errors);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/grpattr-test.c
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include <string.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+
+#define TESTARRAYSIZE 11
+
+static int error_cnt = 0;
+
+int main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    int r;
+    mitype_t data_type;
+    int length;
+    static double tstarr[TESTARRAYSIZE] = { 
+	1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10, 11.11
+    };
+    double dblarr[TESTARRAYSIZE];
+    float fltarr[TESTARRAYSIZE];
+    int intarr[TESTARRAYSIZE];
+    char valstr[128];
+
+    r = micreate_volume("tst-grpa.mnc", 0, NULL, MI_TYPE_UINT, 
+                        MI_CLASS_INT, NULL, &hvol);
+    if (r < 0) {
+	TESTRPT("Unable to create test file", r);
+	return (-1);
+    }
+
+    r = micreate_group(hvol, "/minc-2.0", "test1");
+    if (r < 0) {
+        TESTRPT("micreate_group failed", r);
+    }
+
+    r = micreate_group(hvol, "/minc-2.0", "test2");
+    if (r < 0) {
+        TESTRPT("micreate_group failed", r);
+    }
+
+    r = micreate_group(hvol, "/minc-2.0/test1", "stuff");
+    if (r < 0) {
+	TESTRPT("micreate_group failed", r);
+    }
+
+    r = micreate_group(hvol, "/minc-2.0/test1/stuff", "hello");
+    if (r < 0) {
+	TESTRPT("micreate_group failed", r);
+    }
+
+    r = miset_attr_values(hvol, MI_TYPE_STRING, "/minc-2.0/test1/stuff/hello", 
+			  "animal", 8, "fruitbat");
+    if (r < 0) {
+	TESTRPT("miset_attr_values failed", r);
+    }
+
+    r = miset_attr_values(hvol, MI_TYPE_STRING, "/minc-2.0/test1/stuff", 
+			  "objtype", 10, "automobile");
+    if (r < 0) {
+	TESTRPT("miset_attr_values failed", r);
+    }
+
+    r = miset_attr_values(hvol, MI_TYPE_DOUBLE, "/minc-2.0/test2", 
+			  "maxvals", TESTARRAYSIZE, tstarr);
+    if (r < 0) {
+	TESTRPT("miset_attr_values failed", r);
+    }
+
+    r = miget_attr_type(hvol, "/minc-2.0/test1/stuff/hello", "animal", 
+			&data_type);
+    if (r < 0) {
+	TESTRPT("miget_attr_type failed", r);
+    }
+
+    r = miget_attr_length(hvol, "/minc-2.0/test1/stuff/hello", "animal", 
+			  &length);
+    if (r < 0) {
+	TESTRPT("miget_attr_length failed", r);
+    }
+
+    if (data_type != MI_TYPE_STRING) {
+	TESTRPT("miget_attr_type failed", data_type);
+    }
+    if (length != 8) {
+	TESTRPT("miget_attr_length failed", length);
+    }
+
+    r = midelete_group(hvol, "/minc-2.0/test1/stuff", "goodbye");
+    if (r >= 0) {
+	TESTRPT("midelete_group failed", r);
+    }
+
+    r = midelete_group(hvol, "/minc-2.0/test1/stuff", "hello");
+    /* This should succeed.
+     */
+    if (r < 0) {
+	TESTRPT("midelete_group failed", r);
+    }
+
+    r = miget_attr_length(hvol, "/minc-2.0/test1/stuff/hello", "animal", 
+			  &length);
+    /* This should fail since we deleted the group.
+     */
+    if (r >= 0) {
+	TESTRPT("miget_attr_length failed", r);
+    }
+
+    r = miget_attr_values(hvol, MI_TYPE_DOUBLE, "/minc-2.0/test2", "maxvals", 
+			  TESTARRAYSIZE, dblarr);
+    if (r < 0) {
+	TESTRPT("miget_attr_values failed", r);
+    }
+
+    for (r = 0; r < TESTARRAYSIZE; r++) {
+	if (dblarr[r] != tstarr[r]) {
+	    TESTRPT("miget_attr_values mismatch", r);
+	}
+    }
+
+    /* Get the values again in float rather than double format.
+     */
+    r = miget_attr_values(hvol, MI_TYPE_FLOAT, "/minc-2.0/test2", "maxvals", 
+			  TESTARRAYSIZE, fltarr);
+    if (r < 0) {
+	TESTRPT("miget_attr_values failed", r);
+    }
+
+    for (r = 0; r < TESTARRAYSIZE; r++) {
+	if (fltarr[r] != (float) tstarr[r]) {
+	    TESTRPT("miget_attr_values mismatch", r);
+	    fprintf(stderr, "fltarr[%d] = %f, tstarr[%d] = %f\n",
+		    r, fltarr[r], r, tstarr[r]);
+	}
+    }
+
+    /* Get the values again in int rather than double format.
+     */
+    r = miget_attr_values(hvol, MI_TYPE_INT, "/minc-2.0/test2", "maxvals", 
+			  TESTARRAYSIZE, intarr);
+    if (r < 0) {
+	TESTRPT("miget_attr_values failed", r);
+    }
+
+    for (r = 0; r < TESTARRAYSIZE; r++) {
+	if (intarr[r] != (int) tstarr[r]) {
+	    TESTRPT("miget_attr_values mismatch", r);
+	    fprintf(stderr, "intarr[%d] = %d, tstarr[%d] = %d\n",
+		    r, intarr[r], r, (int) tstarr[r]);
+	}
+    }
+
+    r = miget_attr_values(hvol, MI_TYPE_STRING, "/minc-2.0/test1/stuff", 
+			  "objtype", 128, valstr);
+    if (r < 0) {
+	TESTRPT("miget_attr_values failed", r);
+    }
+
+    if (strcmp(valstr, "automobile") != 0) {
+	TESTRPT("miget_attr_values failed", 0);
+    }
+
+    r = miset_attr_values(hvol, MI_TYPE_STRING, "/minc-2.0/test1/stuff",
+			  "objtype", 8, "bicycle");
+
+    if (r < 0) {
+	TESTRPT("miset_attr_values failed on rewrite", r);
+    }
+
+    r = miget_attr_values(hvol, MI_TYPE_STRING, "/minc-2.0/test1/stuff", 
+			  "objtype", 128, valstr);
+    if (r < 0) {
+	TESTRPT("miget_attr_values failed", r);
+    }
+
+    if (strcmp(valstr, "bicycle") != 0) {
+	TESTRPT("miget_attr_values failed", 0);
+    }
+
+    miclose_volume(hvol);
+
+    if (error_cnt != 0) {
+	fprintf(stderr, "%d error%s reported\n", 
+		error_cnt, (error_cnt == 1) ? "" : "s");
+    }
+    else {
+	fprintf(stderr, "No errors\n");
+    }
+    return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/hyper-test.c
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include "minc2.h"
+
+#define NDIMS 3
+#define CX 11
+#define CY 10
+#define CZ 9
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+static int error_cnt = 0;
+
+int 
+main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    int result;
+    unsigned long start[NDIMS];
+    unsigned long count[NDIMS] = {CX,CY,CZ};
+    double dtemp[CX][CY][CZ];
+    unsigned short stemp[CX][CY][CZ];
+    unsigned char btemp[CX][CY][CZ];
+    unsigned short stmp2[CX][CY][CZ];
+    int i,j,k;
+    long imap[NDIMS];
+    long offset;
+    long sizes[NDIMS] = {CX,CY,CZ};
+    midimhandle_t hdims[NDIMS];
+    char *dimnames[] = {"xspace", "yspace", "zspace"};
+    
+    result = micreate_dimension("xspace", MI_DIMCLASS_SPATIAL, 
+                                MI_DIMATTR_REGULARLY_SAMPLED, CX, &hdims[0]);
+
+    result = micreate_dimension("yspace", MI_DIMCLASS_SPATIAL, 
+                                MI_DIMATTR_REGULARLY_SAMPLED, CY, &hdims[1]);
+
+    result = micreate_dimension("zspace", MI_DIMCLASS_SPATIAL, 
+                                MI_DIMATTR_REGULARLY_SAMPLED, CZ, &hdims[2]);
+
+    result = micreate_volume("tst-hyper.mnc", NDIMS, hdims, MI_TYPE_UINT, 
+                             MI_CLASS_REAL, NULL, &hvol);
+    if (result < 0) {
+        TESTRPT("Unable to create test volume", result);
+    }
+
+    result = miget_volume_dimensions(hvol, MI_DIMCLASS_ANY, MI_DIMATTR_ALL, 
+                                     MI_DIMORDER_FILE, NDIMS, hdims);
+    if (result < 0) {
+        TESTRPT("Unable to get volume dimensions", result);
+    }
+
+    micreate_volume_image(hvol);
+
+    start[0] = start[1] = start[2] = 0;
+    for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+            for (k = 0; k < CZ; k++) {
+                stemp[i][j][k] = (i*101)+(j*17)+(k);
+            }
+        }
+    }
+
+    result = miset_volume_valid_range(hvol, (CX*101)+(CY*17)+CZ, 0);
+    if (result < 0) {
+        TESTRPT("error setting valid range\n", result);
+    }
+
+    result = miset_volume_range(hvol, 1, -1);
+    if (result < 0) {
+        TESTRPT("error setting real range\n", result);
+    }
+
+    result = miset_voxel_value_hyperslab(hvol, MI_TYPE_SHORT, start, count, 
+                                         stemp);
+    if (result < 0) {
+        TESTRPT("unable to set hyperslab\n", result);
+    }
+    
+    miset_apparent_dimension_order_by_name(hvol, NDIMS, dimnames);
+
+    miset_dimension_apparent_voxel_order(hdims[2], MI_COUNTER_FILE_ORDER);
+
+
+    start[0] = start[1] = start[2] = 0;
+    result = miget_real_value_hyperslab(hvol, MI_TYPE_DOUBLE, start, count,
+                                        dtemp);
+        
+    printf("miget_real_value_hyperslab()\n");
+
+    if (result < 0) {
+        TESTRPT("oops\n", result);
+    }
+    else {
+        for (i = 0; i < CX; i++) {
+            for (j = 0; j < CY; j++) {
+                printf("[%d][%d]: ", i, j);
+                for (k = 0; k < CZ; k++) {
+                    printf("%f ", dtemp[i][j][k]);
+                }
+                printf("\n");
+            }
+        }
+    }
+
+    printf("miget_voxel_value_hyperslab()\n");
+
+    start[0] = start[1] = start[2] = 0;
+    i = miget_voxel_value_hyperslab(hvol, MI_TYPE_USHORT, start, count,
+                                    stemp);
+    if (i < 0) {
+        printf("oops\n");
+    }
+    else {
+        for (i = 0; i < CX; i++) {
+            for (j = 0; j < CY; j++) {
+                printf("[%d][%d]: ", i, j);
+                for (k = 0; k < CZ; k++) {
+                    printf("%u ", stemp[i][j][k]);
+                }
+                printf("\n");
+            }
+        }
+    }
+
+    printf("miget_hyperslab_normalized()\n");
+
+    i = miget_hyperslab_normalized(hvol, MI_TYPE_UBYTE, start, count,
+                                   0.0, 0.001, btemp);
+    if (i < 0) {
+        printf("oops\n");
+    }
+    else {
+        for (i = 0; i < CX; i++) {
+            for (j = 0; j < CY; j++) {
+                printf("[%d][%d]: ", i, j);
+                for (k = 0; k < CZ; k++) {
+                    printf("%u ", btemp[i][j][k]);
+                }
+                printf("\n");
+            }
+        }
+    }
+
+    i = miget_voxel_value_hyperslab(hvol, MI_TYPE_USHORT, start, count, stemp);
+    if (i < 0) {
+        printf("oops\n");
+    }
+    else {
+        for (i = 0; i < CX; i++) {
+            for (j = 0; j < CY; j++) {
+                for (k = 0; k < CZ; k++) {
+                    stemp[i][j][k] = stemp[i][j][k] ^ 0x55;
+                }
+            }
+        }
+    }
+    i = miset_voxel_value_hyperslab(hvol, MI_TYPE_USHORT, start, count, stemp);
+    if (i < 0) {
+        printf("oops\n");
+    }
+    else {
+        for (i = 0; i < CX; i++) {
+            for (j = 0; j < CY; j++) {
+                for (k = 0; k < CZ; k++) {
+                    stemp[i][j][k] = stemp[i][j][k] ^ 0x55;
+                }
+            }
+        }
+    }
+    i = miset_voxel_value_hyperslab(hvol, MI_TYPE_USHORT, start, count, stemp);
+    miclose_volume(hvol);
+    return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/label-test.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <string.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+
+static int error_cnt = 0;
+
+int
+main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    char *name;
+    int result;
+    int value;
+    midimhandle_t hdim[3];
+    unsigned long coords[3];
+
+    result = micreate_dimension("xspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, 10, &hdim[0]);
+
+    result = micreate_dimension("yspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, 10, &hdim[1]);
+
+    result = micreate_dimension("zspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, 6, &hdim[2]);
+
+    result = micreate_volume("tst-label.mnc", 3, hdim, MI_TYPE_UINT, 
+                             MI_CLASS_LABEL, NULL, &hvol);
+    if (result < 0) {
+	fprintf(stderr, "Unable to create test file %x\n", result);
+	return (-1);
+    }
+
+    /* Now test some stuff... */
+
+    midefine_label(hvol, 0, "Black");
+    midefine_label(hvol, 0xffffff, "White");
+    midefine_label(hvol, 0x808080, "Grey");
+    midefine_label(hvol, 0xff0000, "Red");
+    midefine_label(hvol, 0x00ff00, "Blue");
+    midefine_label(hvol, 0x0000ff, "Green");
+
+    result = miget_label_name(hvol, 0, &name);
+    if (result != MI_NOERROR) {
+	TESTRPT("Invalid return from miget_label_name", result);
+    }
+
+    if (strcmp(name, "Black") != 0) {
+	TESTRPT("Unexpected label for value 0", 0);
+    }
+    mifree_name(name);
+
+    result = miget_label_name(hvol, 0x00ff00, &name);
+    if (result != MI_NOERROR) {
+	TESTRPT("Invalid return from miget_label_name", result);
+    }
+
+    if (strcmp(name, "Blue") != 0) {
+	TESTRPT("Unexpected label for value 0", 0);
+    }
+    mifree_name(name);
+
+    result = miget_label_name(hvol, 1, &name);
+    if (result != MI_ERROR) {
+	TESTRPT("Invalid return from miget_label_name", result);
+    }
+
+
+    result = miget_label_value(hvol, "White", &value);
+    if (result != MI_NOERROR) {
+	TESTRPT("Invalid return from miget_label_value", result);
+    }
+
+    if (value != 0xffffff) {
+	TESTRPT("Unexpected value for label 'White'", 0);
+    }
+
+    result = miget_label_value(hvol, "Mauve", &value);
+    if (result != MI_ERROR) {
+	TESTRPT("Invalid return from miget_label_value", result);
+    }
+
+    micreate_volume_image(hvol);
+
+    coords[0] = 0;
+    coords[1] = 0;
+    coords[2] = 0;
+    miset_voxel_value(hvol, coords, 3, 0xffffff);
+    coords[2] = 2;
+    miset_voxel_value(hvol, coords, 3, 0x00ff00);
+
+    miclose_volume(hvol);
+
+    if (error_cnt != 0) {
+	fprintf(stderr, "%d error%s reported\n", 
+		error_cnt, (error_cnt == 1) ? "" : "s");
+    }
+    else {
+	fprintf(stderr, "No errors\n");
+    }
+    return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/m2stats.c
@@ -0,0 +1,1377 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#include <ParseArgv.h>
+#include "minc2.h"
+
+#ifndef TRUE
+#  define TRUE  1
+#  define FALSE 0
+#endif
+
+#define SQR(x)    ((x)*(x))
+#define WORLD_NDIMS 3
+#define DEFAULT_BOOLEAN (-1)
+#define BINS_DEFAULT 2000
+
+/* Double_Array structure */
+typedef struct {
+   int      numvalues;
+   double  *values;
+} Double_Array;
+
+/* Stats structure */
+typedef struct {
+   double   vol_range[2];
+   double   mask_range[2];
+   float   *histogram;
+   double   hvoxels;
+   double   vvoxels;
+   double   volume;
+   double   vol_per;
+   double   hist_per;
+   double   min;
+   double   max;
+   double   sum;
+   double   sum2;
+   double   mean;
+   double   variance;
+   double   stddev;
+   double   voxel_com_sum[WORLD_NDIMS];
+   double   voxel_com[WORLD_NDIMS];
+   double   world_com[WORLD_NDIMS];
+   double   median;
+   double   majority;
+   double   biModalT;
+   double   pct_T;
+   double   entropy;
+} Stats_Info;
+
+/* Function prototypes */
+void do_math(long coords[], long num_voxels,
+             int input_vector_length, double *input_data[]);
+void     do_stats(double value, long index[], Stats_Info * stats);
+void     print_result(char *title, double result);
+long     get_minc_nvoxels(mihandle_t hvol);
+double   get_minc_voxel_volume(mihandle_t hvol);
+int      get_minc_ndims(mihandle_t hvol);
+int get_minc_lengths(mihandle_t hvol, int *cx, int *cy, int *cz);
+
+void     find_minc_spatial_dims(mihandle_t hvol, int space_to_dim[], int dim_to_space[]);
+void     get_minc_voxel_to_world(mihandle_t hvol,
+                                 double voxel_to_world[WORLD_NDIMS + 1][WORLD_NDIMS + 1]);
+void     normalize_vector(double vector[]);
+void     transform_coord(double out_coord[],
+                         double transform[WORLD_NDIMS][WORLD_NDIMS + 1],
+                         double in_coord[]);
+void     print_com(Stats_Info * stats);
+int      get_double_list(char *dst, char *key, char *nextarg);
+void     verify_range_options(Double_Array * min, Double_Array * max,
+                              Double_Array * range, Double_Array * binvalue);
+void     init_stats(Stats_Info * stats, int hist_bins);
+void     free_stats(Stats_Info * stats);
+
+/* Argument variables */
+int      max_buffer_size_in_kb = 4 * 1024;
+
+static int verbose = FALSE;
+static int quiet = FALSE;
+static int clobber = FALSE;
+static int ignoreNaN = DEFAULT_BOOLEAN;
+static double fillvalue = -DBL_MAX;
+
+static int All = FALSE;
+static int Vol_Count = FALSE;
+static int Vol_Per = FALSE;
+static int Vol = FALSE;
+static int Min = FALSE;
+static int Max = FALSE;
+static int Sum = FALSE;
+static int Sum2 = FALSE;
+static int Mean = FALSE;
+static int Variance = FALSE;
+static int Stddev = FALSE;
+static int CoM = FALSE;
+static int World_Only = FALSE;
+
+static int Hist = FALSE;
+static int Hist_Count = FALSE;
+static int Hist_Per = FALSE;
+static int Median = FALSE;
+static int Majority = FALSE;
+static int BiModalT = FALSE;
+static int PctT = FALSE;
+static double pctT = 0.0;
+static int Entropy = FALSE;
+
+static Double_Array vol_min = { 0, NULL };
+static Double_Array vol_max = { 0, NULL };
+static Double_Array vol_range = { 0, NULL };
+static Double_Array vol_binvalue = { 0, NULL };
+static int num_ranges;
+
+char    *mask_file;
+static Double_Array mask_min = { 0, NULL };
+static Double_Array mask_max = { 0, NULL };
+static Double_Array mask_range = { 0, NULL };
+static Double_Array mask_binvalue = { 0, NULL };
+static int num_masks;
+
+char    *hist_file;
+static int hist_bins = BINS_DEFAULT;
+static double hist_sep;
+static double hist_range[2] = { -DBL_MAX, DBL_MAX };
+static int discrete_histogram = FALSE;
+static int integer_histogram = FALSE;
+static int max_bins = 10000;
+
+/* Global Variables to store info for stats */
+Stats_Info **stats_info = NULL;
+double   voxel_volume;
+double   nvoxels;
+int      space_to_dim[WORLD_NDIMS] = { -1, -1, -1 };
+int      dim_to_space[MI2_MAX_VAR_DIMS];
+int      file_ndims = 0;
+
+/* Argument table */
+ArgvInfo argTable[] = {
+   {NULL, ARGV_HELP, (char *)NULL, (char *)NULL, "General options:"},
+   {"-verbose", ARGV_CONSTANT, (char *)TRUE, (char *)&verbose,
+    "Print out extra information."},
+   {"-quiet", ARGV_CONSTANT, (char *)TRUE, (char *)&quiet,
+    "Print requested values only."},
+   {"-clobber", ARGV_CONSTANT, (char *)TRUE, (char *)&clobber,
+    "Clobber existing files."},
+   {"-noclobber", ARGV_CONSTANT, (char *)FALSE, (char *)&clobber,
+    "Do not clobber existing files (default)."},
+   {"-max_buffer_size_in_kb",
+    ARGV_INT, (char *)1, (char *)&max_buffer_size_in_kb,
+    "maximum size of internal buffers."},
+
+   {NULL, ARGV_HELP, (char *)NULL, (char *)NULL, "\nVoxel selection options:"},
+   {"-floor", ARGV_FUNC, (char *)get_double_list, (char *)&vol_min,
+    "Ignore voxels below this value (list)"},
+   {"-ceil", ARGV_FUNC, (char *)get_double_list, (char *)&vol_max,
+    "Ignore voxels above this value (list)"},
+   {"-range", ARGV_FUNC, (char *)get_double_list, (char *)&vol_range,
+    "Ignore voxels outside this range (list)"},
+   {"-binvalue", ARGV_FUNC, (char *)get_double_list, (char *)&vol_binvalue,
+    "Include voxels within 0.5 of this value (list)"},
+   {"-mask", ARGV_STRING, (char *)1, (char *)&mask_file,
+    "<mask.mnc> Use mask file for calculations."},
+   {"-mask_floor", ARGV_FUNC, (char *)get_double_list, (char *)&mask_min,
+    "Exclude mask voxels below this value (list)"},
+   {"-mask_ceil", ARGV_FUNC, (char *)get_double_list, (char *)&mask_max,
+    "Exclude mask voxels above this value (list)"},
+   {"-mask_range", ARGV_FUNC, (char *)get_double_list, (char *)&mask_range,
+    "Exclude voxels outside this range (list)"},
+   {"-mask_binvalue", ARGV_FUNC, (char *)get_double_list, (char *)&mask_binvalue,
+    "Include mask voxels within 0.5 of this value (list)"},
+   {"-ignore_nan", ARGV_CONSTANT, (char *)TRUE, (char *)&ignoreNaN,
+    "Exclude NaN values from stats (default)."},
+   {"-include_nan", ARGV_CONSTANT, (char *)FALSE, (char *)&ignoreNaN,
+    "Treat NaN values as zero."},
+   {"-replace_nan", ARGV_FLOAT, (char *)1, (char *)&fillvalue,
+    "Replace NaNs with specified value."},
+
+   {NULL, ARGV_HELP, (char *)NULL, (char *)NULL, "\nHistogram Options:"},
+   {"-histogram", ARGV_STRING, (char *)1, (char *)&hist_file,
+    "<hist_file> Compute histogram."},
+   {"-hist_bins", ARGV_INT, (char *)1, (char *)&hist_bins,
+    "<number> of bins in each histogram."},
+   {"-bins", ARGV_INT, (char *)1, (char *)&hist_bins,
+    "synonym for -hist_bins."},
+   {"-hist_floor", ARGV_FLOAT, (char *)1, (char *)&hist_range[0],
+    "Histogram floor value. (incl)"},
+   {"-hist_ceil", ARGV_FLOAT, (char *)1, (char *)&hist_range[1],
+    "Histogram ceiling value. (incl)"},
+   {"-hist_range", ARGV_FLOAT, (char *)2, (char *)&hist_range,
+    "Histogram floor and ceiling. (incl)"},
+   {"-discrete_histogram", ARGV_CONSTANT, (char *)TRUE, (char *)&discrete_histogram,
+    "Match histogram bins to data discretization"},
+   {"-integer_histogram", ARGV_CONSTANT, (char *)TRUE, (char *)&integer_histogram,
+    "Set histogram bins to unit width"},
+   {"-int_max_bins", ARGV_INT, (char *)1, (char *)&max_bins,
+    "Set maximum number of histogram bins for integer histograms"},
+
+   {NULL, ARGV_HELP, (char *)NULL, (char *)NULL, "\nStatistics (Printed in this order)"},
+   {"-all", ARGV_CONSTANT, (char *)TRUE, (char *)&All,
+    "all statistics (default)."},
+   {"-none", ARGV_CONSTANT, (char *)TRUE, (char *)&Vol_Count,
+    "synonym for -count. (from volume_stats)"},
+   {"-count", ARGV_CONSTANT, (char *)TRUE, (char *)&Vol_Count,
+    "# of voxels."},
+   {"-percent", ARGV_CONSTANT, (char *)TRUE, (char *)&Vol_Per,
+    "percentage of valid voxels."},
+   {"-volume", ARGV_CONSTANT, (char *)TRUE, (char *)&Vol,
+    "volume (in mm3)."},
+   {"-min", ARGV_CONSTANT, (char *)TRUE, (char *)&Min,
+    "minimum value."},
+   {"-max", ARGV_CONSTANT, (char *)TRUE, (char *)&Max,
+    "maximum value."},
+   {"-sum", ARGV_CONSTANT, (char *)TRUE, (char *)&Sum,
+    "sum."},
+   {"-sum2", ARGV_CONSTANT, (char *)TRUE, (char *)&Sum2,
+    "sum of squares."},
+   {"-mean", ARGV_CONSTANT, (char *)TRUE, (char *)&Mean,
+    "mean value."},
+   {"-variance", ARGV_CONSTANT, (char *)TRUE, (char *)&Variance,
+    "variance."},
+   {"-stddev", ARGV_CONSTANT, (char *)TRUE, (char *)&Stddev,
+    "standard deviation."},
+   {"-CoM", ARGV_CONSTANT, (char *)TRUE, (char *)&CoM,
+    "centre of mass of the volume."},
+   {"-com", ARGV_CONSTANT, (char *)TRUE, (char *)&CoM,
+    "centre of mass of the volume."},
+   {"-world_only", ARGV_CONSTANT, (char *)TRUE, (char *)&World_Only,
+    "print CoM in world coords only."},
+
+   {NULL, ARGV_HELP, (char *)NULL, (char *)NULL, "\nHistogram Dependant Statistics:"},
+   {"-hist_count", ARGV_CONSTANT, (char *)TRUE, (char *)&Hist_Count,
+    "# of voxels portrayed in Histogram."},
+   {"-hist_percent",
+    ARGV_CONSTANT, (char *)TRUE, (char *)&Hist_Per,
+    "percentage of histogram voxels."},
+   {"-median", ARGV_CONSTANT, (char *)TRUE, (char *)&Median,
+    "median value."},
+   {"-majority", ARGV_CONSTANT, (char *)TRUE, (char *)&Majority,
+    "most frequently occurring histogram bin."},
+   {"-biModalT", ARGV_CONSTANT, (char *)TRUE, (char *)&BiModalT,
+    "value separating a volume into 2 classes."},
+   {"-pctT", ARGV_FLOAT, (char *)1, (char *)&pctT,
+    "<%> threshold at the supplied % of data."},
+   {"-entropy", ARGV_CONSTANT, (char *)TRUE, (char *)&Entropy,
+    "entropy of the volume."},
+
+   {NULL, ARGV_HELP, NULL, NULL, ""},
+   {NULL, ARGV_END, NULL, NULL, NULL}
+};
+
+int main(int argc, char *argv[])
+{
+   char   **infiles;
+   int      nfiles;
+   mihandle_t hvol;
+   int      idim;
+   int      irange, imask;
+   double   real_range[2], valid_range[2];
+   mitype_t mitype;
+   double   voxel_to_world[WORLD_NDIMS + 1][WORLD_NDIMS + 1];
+   Stats_Info *stats;
+   FILE    *FP;
+   double   scale, voxmin, voxmax;
+   int x, y, z;
+   int cx, cy, cz;
+   double * buffer;
+
+   /* Get arguments */
+   if(ParseArgv(&argc, argv, argTable, 0) || (argc != 2)) {
+      (void)fprintf(stderr, "\nUsage: %s [options] <infile.mnc>\n", argv[0]);
+      (void)fprintf(stderr, "       %s -help\n\n", argv[0]);
+      exit(EXIT_FAILURE);
+   }
+   nfiles = argc - 1;
+   infiles = &argv[1];
+   infiles[1] = &mask_file[0];
+
+   if(infiles[1] != NULL) {
+      nfiles++;
+   }
+
+   /* Check for NaN options */
+   if(ignoreNaN == DEFAULT_BOOLEAN) {
+      ignoreNaN = (fillvalue != -DBL_MAX);
+   }
+   if(ignoreNaN && fillvalue == -DBL_MAX) {
+      fillvalue = 0.0;
+   }
+
+   /* Check range options: not over-specified and put values 
+      in vol_min/vol_max */
+   verify_range_options(&vol_min, &vol_max, &vol_range, &vol_binvalue);
+   num_ranges = vol_min.numvalues;
+
+   /* Check mask range options: not over-specified and put values 
+      in mask_min/mask_max */
+   verify_range_options(&mask_min, &mask_max, &mask_range, &mask_binvalue);
+   num_masks = mask_min.numvalues;
+
+   /* Check histogramming options */
+   if((discrete_histogram && integer_histogram) ||
+      ((discrete_histogram || integer_histogram) && (hist_bins != BINS_DEFAULT))) {
+      (void)fprintf(stderr,
+                    "Please specify only -discrete_histogram, -integer_histogram or -bins\n");
+      exit(EXIT_FAILURE);
+   }
+
+   /* init PctT boolean before checking */
+   if(pctT > 0.0) {
+      PctT = TRUE;
+      pctT /= 100;
+   }
+
+   /* if nothing selected, do everything */
+   if(!Vol_Count && !Vol_Per && !Vol && !Min && !Max && !Sum && !Sum2 &&
+      !Mean && !Variance && !Stddev && !Hist_Count && !Hist_Per &&
+      !Median && !Majority && !BiModalT && !PctT && !Entropy && !CoM) {
+      All = TRUE;
+      Hist = TRUE;
+   }
+
+   if((hist_file != NULL) || Hist_Count || Hist_Per ||
+      Median || Majority || BiModalT || PctT || Entropy) {
+      Hist = TRUE;
+   }
+   if(hist_bins <= 0)
+      Hist = FALSE;
+
+   /* do checking on arguments */
+   if(hist_bins < 1) {
+      (void)fprintf(stderr, "%s: Must have one or more bins for a histogram\n", argv[0]);
+      exit(EXIT_FAILURE);
+   }
+
+   if(access(infiles[0], F_OK) != 0) {
+      (void)fprintf(stderr, "%s: Couldn't find %s\n", argv[0], infiles[0]);
+      exit(EXIT_FAILURE);
+   }
+
+   if(infiles[1] != NULL && access(infiles[1], F_OK) != 0) {
+      (void)fprintf(stderr, "%s: Couldn't find mask file: %s\n", argv[0], infiles[1]);
+      exit(EXIT_FAILURE);
+   }
+
+   if(hist_file != NULL && !clobber && access(hist_file, F_OK) != -1) {
+      (void)fprintf(stderr, "%s: Histogram %s exists! (use -clobber to overwrite)\n",
+                    argv[0], hist_file);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Open the file to get some information */
+   if (miopen_volume(infiles[0], MI2_OPEN_READ, &hvol) < 0) {
+       fprintf(stderr, "Unable to open the input file\n");
+       exit(EXIT_FAILURE);
+   }
+
+   nvoxels = get_minc_nvoxels(hvol);
+   voxel_volume = get_minc_voxel_volume(hvol);
+   miget_data_type(hvol, &mitype);
+   miget_volume_real_range(hvol, real_range);
+   miget_volume_valid_range(hvol, &valid_range[1], &valid_range[0]);
+   file_ndims = get_minc_ndims(hvol);
+   find_minc_spatial_dims(hvol, space_to_dim, dim_to_space);
+   get_minc_voxel_to_world(hvol, voxel_to_world);
+
+   /* Check whether discrete histogramming makes sense - i.e. not
+      floating-point. Silently ignore the option if it does not make sense. */
+   if(mitype == MI_TYPE_FLOAT || mitype == MI_TYPE_DOUBLE) {
+      discrete_histogram = FALSE;
+   }
+
+   /* set up the histogram definition, if needed */
+   if(Hist) {
+      if(hist_range[0] == -DBL_MAX) {
+         if(vol_min.numvalues == 1 && vol_min.values[0] != -DBL_MAX)
+            hist_range[0] = vol_min.values[0];
+         else
+            hist_range[0] = real_range[0];
+      }
+
+      if(hist_range[1] == DBL_MAX) {
+         if(vol_max.numvalues == 1 && vol_max.values[0] != DBL_MAX)
+            hist_range[1] = vol_max.values[0];
+         else
+            hist_range[1] = real_range[1];
+      }
+
+      if(discrete_histogram) {
+
+         /* Convert histogram range to voxel values and round, then
+            convert back. */
+         scale = (real_range[1] == real_range[0]) ? 0.0 :
+            (valid_range[1] - valid_range[0]) / (real_range[1] - real_range[0]);
+         voxmin = rint((hist_range[0] - real_range[0]) * scale + valid_range[0]);
+         voxmax = rint((hist_range[1] - real_range[0]) * scale + valid_range[0]);
+         if(real_range[1] != real_range[0])
+            scale = 1.0 / scale;
+         hist_range[0] = (voxmin - valid_range[0]) * scale + real_range[0];
+         hist_range[1] = (voxmax - valid_range[0]) * scale + real_range[0];
+
+         /* Figure out number of bins and bin width */
+         hist_bins = voxmax - voxmin;
+         if(hist_bins <= 0) {
+            hist_sep = 1.0;
+            hist_bins = 0;
+         }
+         else {
+            hist_sep = (hist_range[1] - hist_range[0]) / hist_bins;
+         }
+
+         /* Shift the ends of the histogram down and up by half a bin
+            and add one to the number of bins */
+         hist_range[0] -= hist_sep / 2.0;
+         hist_range[1] += hist_sep / 2.0;
+         hist_bins++;
+      }
+      else if(integer_histogram) {
+
+         /* Add and subtract the 0.01 in order to ensure that a range that
+            is already properly specified stays that way. Ie. [-0.5,255.5]
+            does not change, regardless of the type of rounding done to .5 */
+         hist_range[0] = (int)rint(hist_range[0] + 0.01);
+         hist_range[1] = (int)rint(hist_range[1] - 0.01);
+         hist_bins = hist_range[1] - hist_range[0] + 1.0;
+         hist_range[0] -= 0.5;
+         hist_range[1] += 0.5;
+         hist_sep = 1.0;
+      }
+      else {
+         hist_sep = (hist_range[1] - hist_range[0]) / hist_bins;
+      }
+
+      if((discrete_histogram || integer_histogram) && (hist_bins > max_bins)) {
+         (void)fprintf(stderr,
+                       "Too many bins in histogram (%d) - please increase -max_bins if appropriate\n",
+                       hist_bins);
+         exit(EXIT_FAILURE);
+      }
+
+   }
+
+   /* Initialize the stats structure */
+   stats_info = malloc(num_ranges * sizeof(*stats_info));
+   for(irange = 0; irange < num_ranges; irange++) {
+      stats_info[irange] = malloc(num_masks * sizeof(**stats_info));
+      for(imask = 0; imask < num_masks; imask++) {
+         stats = &stats_info[irange][imask];
+         init_stats(stats, hist_bins);
+         stats->vol_range[0] = vol_min.values[irange];
+         stats->vol_range[1] = vol_max.values[irange];
+         stats->mask_range[0] = mask_min.values[imask];
+         stats->mask_range[1] = mask_max.values[imask];
+      }
+   }
+
+   get_minc_lengths(hvol, &cx, &cy, &cz);
+
+   buffer = malloc(sizeof(double) * cz * cy);
+
+   /* Do math */
+   for (x = 0; x < cx; x++) {
+       long coords[3];
+       long edges[3];
+       double *r[2];
+       double v;
+
+       coords[0] = x;
+       coords[1] = 0;
+       coords[2] = 0;
+       edges[0] = 1;
+       edges[1] = cy;
+       edges[2] = cz;
+
+       miget_real_value_hyperslab(hvol, MI_TYPE_DOUBLE, 
+                                  coords, edges, buffer);
+
+       for (y = 0; y < cy; y++) {
+           for (z = 0; z < cz; z++) {
+               coords[1] = y;
+               coords[2] = z;
+               v = buffer[(y * cy) + z];
+               r[0] = &v;
+               do_math(coords, 1, 1, r);
+           }
+       }
+   }
+
+   free(buffer);
+
+
+   /* Open the histogram file if it will be needed */
+   if(hist_file == NULL) {
+      FP = NULL;
+   }
+   else {
+      FP = fopen(hist_file, "w");
+      if(FP == NULL) {
+         perror("Error opening histogram file");
+         exit(EXIT_FAILURE);
+      }
+   }
+
+   /* Loop over ranges and masks, calculating results */
+   for(irange = 0; irange < num_ranges; irange++) {
+      for(imask = 0; imask < num_masks; imask++) {
+
+         stats = &stats_info[irange][imask];
+
+         stats->vol_per = stats->vvoxels / nvoxels * 100;
+         stats->hist_per = stats->hvoxels / nvoxels * 100;
+         stats->mean = (stats->vvoxels > 0) ? stats->sum / stats->vvoxels : 0.0;
+         stats->variance =
+            (stats->vvoxels > 1) ?
+            (stats->sum2 - SQR(stats->sum) / stats->vvoxels) / (stats->vvoxels - 1)
+            : 0.0;
+         stats->stddev = sqrt(stats->variance);
+         stats->volume = voxel_volume * stats->vvoxels;
+         for(idim = 0; idim < WORLD_NDIMS; idim++) {
+            if(stats->sum != 0.0)
+               stats->voxel_com[idim] = stats->voxel_com_sum[idim] / stats->sum;
+            else
+               stats->voxel_com[idim] = 0.0;
+         }
+         transform_coord(stats->world_com, voxel_to_world, stats->voxel_com);
+
+         /* Do the histogram calculations */
+         if(Hist) {
+            int      c;
+            float   *hist_centre;
+            float   *pdf;              /* probability density Function */
+            float   *cdf;              /* cumulative density Function  */
+
+            int      majority_bin = 0;
+            int      median_bin = 0;
+            int      pctt_bin = 0;
+            int      bimodalt_bin = 0;
+
+            /* BiModal Threshold variables */
+            double   zero_moment = 0.0;
+            double   first_moment = 0.0;
+            double   var = 0.0;
+            double   max_var = 0.0;
+
+            /* Allocate space for histograms */
+            hist_centre = malloc(hist_bins * sizeof(float));
+            memset(hist_centre, 0, hist_bins * sizeof(float));
+            pdf = malloc(hist_bins * sizeof(float));
+            memset(pdf, 0, hist_bins * sizeof(float));
+            cdf = malloc(hist_bins * sizeof(float));
+            memset(cdf, 0, hist_bins * sizeof(float));
+            if(hist_centre == NULL || pdf == NULL || cdf == NULL) {
+               (void)fprintf(stderr, "Memory allocation error\n");
+               exit(EXIT_FAILURE);
+            }
+
+            for(c = 0; c < hist_bins; c++) {
+               hist_centre[c] = (c * hist_sep) + hist_range[0] + (hist_sep / 2);
+
+               /* Probability and Cumulative density functions */
+               pdf[c] = (stats->hvoxels > 0) ? stats->histogram[c] / stats->hvoxels : 0.0;
+               cdf[c] = (c == 0) ? pdf[c] : cdf[c - 1] + pdf[c];
+
+               /* Majority */
+               if(stats->histogram[c] > stats->histogram[majority_bin]) {
+                  majority_bin = c;
+               }
+
+               /* Entropy */
+               if(stats->histogram[c] > 0.0) {
+                  stats->entropy -= pdf[c] * (log(pdf[c]) / log(2.0));
+               }
+
+               /* Histogram Median */
+               if(cdf[c] < 0.5) {
+                  median_bin = c;
+               }
+
+               /* BiModal Threshold */
+               if(c > 0) {
+                  zero_moment += pdf[c];
+                  first_moment += hist_centre[c] * pdf[c];
+
+                  var = SQR((stats->mean * zero_moment) - first_moment) /
+                     (zero_moment * (1 - zero_moment));
+
+                  if(var > max_var) {
+                     bimodalt_bin = c;
+                     max_var = var;
+                  }
+               }
+
+               /* pct Threshold */
+               if(cdf[c] < pctT) {
+                  pctt_bin = c;
+               }
+            }
+
+            /* median */
+            if(median_bin == 0) {
+               stats->median = 0.5 * pdf[median_bin] * hist_sep;
+            }
+            else {
+               stats->median = ((double)median_bin + (0.5 - cdf[median_bin])
+                                * pdf[median_bin + 1]) * hist_sep;
+            }
+            stats->median += hist_centre[0];
+
+            stats->majority = hist_centre[majority_bin];
+            stats->biModalT = hist_centre[bimodalt_bin];
+
+            /* pct Threshold */
+            if(pctt_bin == 0) {
+               stats->pct_T = pctT * pdf[pctt_bin] * hist_sep;
+            }
+            else {
+               stats->pct_T = ((double)pctt_bin + (pctT - cdf[pctt_bin])
+                               * pdf[pctt_bin + 1]) * hist_sep;
+            }
+
+            /* output the histogram */
+            if(hist_file != NULL) {
+
+               (void)fprintf(FP, "# histogram for: %s\n", infiles[0]);
+	       (void)fprintf(FP, "#  mask file:    %s\n", 
+			     (infiles[1] != NULL) ? infiles[1] : "(null)");
+               if(stats->vol_range[0] != -DBL_MAX || stats->vol_range[1] != DBL_MAX) {
+                  (void)fprintf(FP, "#  volume range: %g  %g\n", stats->vol_range[0],
+                                stats->vol_range[1]);
+               }
+               if(stats->mask_range[0] != -DBL_MAX || stats->mask_range[1] != DBL_MAX) {
+                  (void)fprintf(FP, "#  mask range:   %g  %g\n", stats->mask_range[0],
+                                stats->mask_range[1]);
+               }
+               (void)fprintf(FP, "#  domain:       %g  %g\n", hist_range[0],
+                             hist_range[1]);
+               (void)fprintf(FP, "#  entropy:      %g\n", stats->entropy);;
+               (void)fprintf(FP, "# bin centres                 counts\n");
+               for(c = 0; c < hist_bins; c++)
+                  (void)fprintf(FP, "  %-20.10g  %12g\n", hist_centre[c],
+                                stats->histogram[c]);
+               (void)fprintf(FP, "\n");
+            }
+
+            /* Free the space */
+            free(hist_centre);
+            free(pdf);
+            free(cdf);
+
+         }                             /* end histogram calculations */
+
+         /* Print range of data allowed */
+         if(verbose || (num_ranges > 1 && !quiet)) {
+            (void)fprintf(stdout, "Included Range:    %g   %g\n", stats->vol_range[0],
+                          stats->vol_range[1]);
+         }
+         if(verbose || (num_masks > 1 && !quiet)) {
+            (void)fprintf(stdout, "Mask Range:        %g   %g\n", stats->mask_range[0],
+                          stats->mask_range[1]);
+         }
+
+         /* Print warnings about ranges */
+         if(!quiet && real_range[0] != stats->min &&
+            stats->vol_range[0] == -DBL_MAX && stats->mask_range[0] == -DBL_MAX) {
+            (void)fprintf(stderr,
+                          "*** %s - reported min (%g) doesn't equal header (%g)\n",
+                          argv[0], stats->min, real_range[0]);
+         }
+         if(!quiet && real_range[1] != stats->max &&
+            stats->vol_range[1] == DBL_MAX && stats->mask_range[1] == DBL_MAX) {
+            (void)fprintf(stderr,
+                          "*** %s - reported max (%g) doesn't equal header (%g)\n",
+                          argv[0], stats->max, real_range[1]);
+         }
+
+         /* Output stats */
+         if(Hist) {
+            if(verbose) {
+               (void)fprintf(stdout, "Histogram Range:   %g\t%g\n", hist_range[0],
+                             hist_range[1]);
+               (void)fprintf(stdout, "Histogram bins:    %i  of Width (separation): %f\n",
+                             hist_bins, hist_sep);
+            }
+         }
+
+         if(All && !quiet) {
+            (void)fprintf(stdout, "File:              %s\n", infiles[0]);
+         }
+         if(All && !quiet) {
+            (void)fprintf(stdout, "Mask file:         %s\n", 
+			  (infiles[1] != NULL) ? infiles[1] : "(null)");
+         }
+         if(All && !quiet) {
+            print_result("Total voxels:      ", nvoxels);
+         }
+         if(All || Vol_Count) {
+            print_result("# voxels:          ", stats->vvoxels);
+         }
+         if(All || Vol_Per) {
+            print_result("% of total:        ", stats->vol_per);
+         }
+         if(All || Vol) {
+            print_result("Volume (mm3):      ", stats->volume);
+         }
+         if(All || Min) {
+            print_result("Min:               ", stats->min);
+         }
+         if(All || Max) {
+            print_result("Max:               ", stats->max);
+         }
+         if(All || Sum) {
+            print_result("Sum:               ", stats->sum);
+         }
+         if(All || Sum2) {
+            print_result("Sum^2:             ", stats->sum2);
+         }
+         if(All || Mean) {
+            print_result("Mean:              ", stats->mean);
+         }
+         if(All || Variance) {
+            print_result("Variance:          ", stats->variance);
+         }
+         if(All || Stddev) {
+            print_result("Stddev:            ", stats->stddev);
+         }
+         if(All || CoM) {
+            print_com(stats);
+         }
+
+         if(Hist) {
+            if(All && !quiet) {
+               (void)fprintf(stdout, "\nHistogram:         %s\n", hist_file);
+            }
+            if(All && !quiet) {
+               print_result("Total voxels:      ", nvoxels);
+            }
+            if(All || Hist_Count) {
+               print_result("# voxels:          ", stats->hvoxels);
+            }
+            if(All || Hist_Per) {
+               print_result("% of total:        ", stats->hist_per);
+            }
+            if(All || Median) {
+               print_result("Median:            ", stats->median);
+            }
+            if(All || Majority) {
+               print_result("Majority:          ", stats->majority);
+            }
+            if(All || BiModalT) {
+               print_result("BiModalT:          ", stats->biModalT);
+            }
+            if(All || PctT) {
+               char     str[100];
+
+               (void)sprintf(str, "PctT [%3d%%]:       ", (int)(pctT * 100));
+               print_result(str, stats->pct_T);
+            }
+            if(All || Entropy) {
+               print_result("Entropy :          ", stats->entropy);
+            }
+            if(!quiet) {
+               (void)fprintf(stdout, "\n");
+            }
+         }
+
+      }                                /* End of loop over masks */
+
+   }                                   /* End of loop over ranges */
+
+   /* Close the histogram file */
+   if(FP != NULL) {
+      (void)fclose(FP);
+   }
+
+   /* Free things up */
+   for(irange = 0; irange < num_ranges; irange++) {
+      for(imask = 0; imask < num_masks; imask++) {
+         free_stats(&stats_info[irange][imask]);
+      }
+      free(stats_info[irange]);
+   }
+   free(stats_info);
+
+   return EXIT_SUCCESS;
+}
+
+void do_math(long index[], long num_voxels,
+             int input_vector_length,
+             double *input_data[])
+{
+   long     ivox;
+   int      imask, irange;
+   double   mask_min, mask_max;
+   Stats_Info *stats;
+
+   /* Loop through the voxels - a bit of optimization in case we 
+      have a brain-dead compiler */
+   if(mask_file != NULL) {
+      for(irange = 0; irange < num_ranges; irange++) {
+         for(imask = 0; imask < num_masks; imask++) {
+            stats = &stats_info[irange][imask];
+            mask_min = stats->mask_range[0];
+            mask_max = stats->mask_range[1];
+            if(CoM || All) {
+               for(ivox = 0; ivox < num_voxels * input_vector_length; ivox++) {
+                  if((input_data[1][ivox] >= mask_min) &&
+                     (input_data[1][ivox] <= mask_max)) {
+                     do_stats(input_data[0][ivox], index, stats);
+                  }
+               }
+            }
+            else {
+               for(ivox = 0; ivox < num_voxels * input_vector_length; ivox++) {
+                  if((input_data[1][ivox] >= mask_min) &&
+                     (input_data[1][ivox] <= mask_max)) {
+                     do_stats(input_data[0][ivox], NULL, stats);
+                  }
+               }
+            }
+         }
+      }
+   }
+
+   else {
+      for(irange = 0; irange < num_ranges; irange++) {
+         stats = &stats_info[irange][0];
+         if(CoM || All) {
+            for(ivox = 0; ivox < num_voxels * input_vector_length; ivox++) {
+               do_stats(input_data[0][ivox], index, stats);
+            }
+         }
+         else {
+            for(ivox = 0; ivox < num_voxels * input_vector_length; ivox++) {
+               do_stats(input_data[0][ivox], NULL, stats);
+            }
+         }
+      }
+   }
+
+   return;
+}
+
+void do_stats(double value, long index[], Stats_Info * stats)
+{
+   int      idim;
+   int      hist_index, dim_index;
+
+   /* Check for NaNs */
+   if(value == -DBL_MAX) {
+      if(ignoreNaN)
+         value = fillvalue;
+      else
+         return;
+   }
+
+   /* Collect stats if we are within range */
+   if((value >= stats->vol_range[0]) && (value <= stats->vol_range[1])) {
+      stats->vvoxels++;
+      stats->sum += value;
+      stats->sum2 += SQR(value);
+
+      if(value < stats->min) {
+         stats->min = value;
+      }
+      if(value > stats->max) {
+         stats->max = value;
+      }
+
+      /* Get voxel index */
+      if(CoM || All) {
+         for(idim = 0; idim < WORLD_NDIMS; idim++) {
+            dim_index = space_to_dim[idim];
+            if(dim_index >= 0) {
+               stats->voxel_com_sum[idim] += value * index[dim_index];
+            }
+         }
+      }
+
+      if(Hist && (value >= hist_range[0]) && (value <= hist_range[1])) {
+         /*lower limit <= value < upper limit */
+         hist_index = (int)floor((value - hist_range[0]) / hist_sep);
+         if(hist_index >= hist_bins) {
+            hist_index = hist_bins - 1;
+         }
+         stats->histogram[hist_index]++;
+         stats->hvoxels++;
+      }
+   }
+}
+
+void print_result(char *title, double result)
+{
+   if(!quiet) {
+      (void)fprintf(stdout, "%s", title);
+   }
+   (void)fprintf(stdout, "%.10g\n", result);
+}
+
+/* Get the number of voxels in the file - this is the total number,
+   not just spatial dimensions */
+long get_minc_nvoxels(mihandle_t hvol)
+{
+    int n;
+
+    miget_volume_voxel_count(hvol, &n);
+    return n;
+}
+
+int get_minc_lengths(mihandle_t hvol, int *cx, int *cy, int *cz)
+{
+    midimhandle_t dims[MI2_MAX_VAR_DIMS];
+    int ndims;
+    int i;
+    char *name;
+    unsigned long length;
+
+    miget_volume_dimensions(hvol, MI_DIMCLASS_ANY, MI_DIMATTR_ALL, 0, 
+                            MI2_MAX_VAR_DIMS, dims);
+
+    miget_volume_dimension_count(hvol, MI_DIMCLASS_ANY, MI_DIMATTR_ALL,
+                                 &ndims);
+
+    for (i = 0; i < ndims; i++) {
+        miget_dimension_name(dims[i], &name);
+        miget_dimension_size(dims[i], &length);
+        if (!strcmp(name, "xspace")) {
+            *cx = (int) length;
+        }
+        else if (!strcmp(name, "yspace")) {
+            *cy = (int) length;
+        }
+        else if (!strcmp(name, "zspace")) {
+            *cz = (int) length;
+        }
+        mifree_name(name);
+    }
+    return (MI_NOERROR);
+}
+
+/* Get the volume of a spatial voxel */
+double get_minc_voxel_volume(mihandle_t hvol)
+{
+   int      idim, ndims;
+   double   volume, step;
+   midimhandle_t *hdim;
+
+   miget_volume_dimension_count(hvol, MI_DIMCLASS_SPATIAL,
+                                MI_DIMATTR_ALL, &ndims);
+
+   hdim = (midimhandle_t *) malloc(sizeof (midimhandle_t) * ndims);
+
+   if (hdim == NULL) {
+       return (0.0);
+   }
+
+   miget_volume_dimensions(hvol, MI_DIMCLASS_SPATIAL,
+                           MI_DIMATTR_ALL, 0, ndims, hdim);
+
+   
+   /* Loop over them to get the total spatial volume */
+   volume = 1.0;
+   for (idim = 0; idim < ndims; idim++) {
+      step = 1.0;
+
+      miget_dimension_separation(hdim[idim], 0, &step);
+
+      /* Make sure that it is positive and calculate the volume */
+      if(step < 0.0)
+         step = -step;
+      volume *= step;
+   }
+   free(hdim);
+   return volume;
+}
+
+/* Get the total number of image dimensions in a minc file */
+int get_minc_ndims(mihandle_t hvol)
+{
+    int ndims;
+    miget_volume_dimension_count(hvol, MI_DIMCLASS_ANY,
+                                 MI_DIMATTR_ALL, &ndims);
+    return ndims;
+}
+
+/* Get the mapping from spatial dimension - x, y, z - to file dimensions
+   and vice-versa. */
+void find_minc_spatial_dims(mihandle_t hvol, int space_to_dim[], int dim_to_space[])
+{
+   midimhandle_t dim[MI2_MAX_VAR_DIMS];
+   int      idim, ndims, world_index;
+   char     *dimname;
+
+   /* Set default values */
+   for(idim = 0; idim < 3; idim++)
+      space_to_dim[idim] = -1;
+   for(idim = 0; idim < MI2_MAX_VAR_DIMS; idim++)
+      dim_to_space[idim] = -1;
+
+   ndims = miget_volume_dimensions(hvol, MI_DIMCLASS_ANY, MI_DIMATTR_ALL, 0,
+                                   MI2_MAX_VAR_DIMS, dim);
+
+   /* Loop over them to find the spatial ones */
+   for(idim = 0; idim < ndims; idim++) {
+
+      /* Get the name and check that this is a spatial dimension 
+       */
+       miget_dimension_name(dim[idim], &dimname);
+      if((dimname[0] == '\0') || (strcmp(&dimname[1], "space") != 0)) {
+          mifree_name(dimname);
+          continue;
+      }
+
+      /* Look for the spatial dimensions */
+      switch (dimname[0]) {
+      case 'x':
+         world_index = 0;
+         break;
+      case 'y':
+         world_index = 1;
+         break;
+      case 'z':
+         world_index = 2;
+         break;
+      default:
+         world_index = 0;
+         break;
+      }
+      space_to_dim[world_index] = idim;
+      dim_to_space[idim] = world_index;
+      mifree_name(dimname);
+   }
+}
+
+/* Get the voxel to world transform (for column vectors) */
+void get_minc_voxel_to_world(mihandle_t hvol, 
+                             double voxel_to_world[WORLD_NDIMS + 1][WORLD_NDIMS + 1])
+{
+    extern void miget_voxel_to_world(mihandle_t hvol, double v2w[WORLD_NDIMS+1][WORLD_NDIMS+1]);
+    miget_voxel_to_world(hvol, voxel_to_world);
+}
+
+void normalize_vector(double vector[])
+{
+   int      idim;
+   double   magnitude;
+
+   magnitude = 0.0;
+   for(idim = 0; idim < WORLD_NDIMS; idim++) {
+      magnitude += (vector[idim] * vector[idim]);
+   }
+   magnitude = sqrt(magnitude);
+   if(magnitude > 0.0) {
+      for(idim = 0; idim < WORLD_NDIMS; idim++) {
+         vector[idim] /= magnitude;
+      }
+   }
+}
+
+/* Prints out centre of mass with correct file order */
+void print_com(Stats_Info * stats)
+{
+   char    *spatial_codes[WORLD_NDIMS] = { "x", "y", "z" }; /* In x,y,z order */
+   int      idim;
+   int      first;
+
+   /* Print out voxel coord info */
+   if(!World_Only) {
+      if(!quiet) {
+         (void)fprintf(stdout, "CoM_voxel(");
+         first = TRUE;
+         for(idim = 0; idim < MI2_MAX_VAR_DIMS; idim++) {
+            if(dim_to_space[idim] >= 0) {
+               if(first)
+                  first = FALSE;
+               else
+                  (void)fprintf(stdout, ",");
+               (void)fprintf(stdout, "%s", spatial_codes[dim_to_space[idim]]);
+            }
+         }
+         (void)fprintf(stdout, "):  ");
+      }
+      first = TRUE;
+      for(idim = 0; idim < MI2_MAX_VAR_DIMS; idim++) {
+         if(dim_to_space[idim] >= 0) {
+            if(first)
+               first = FALSE;
+            else
+               (void)fprintf(stdout, " ");
+            (void)fprintf(stdout, "%.10g", stats->voxel_com[dim_to_space[idim]]);
+         }
+      }
+      (void)fprintf(stdout, "\n");
+   }
+
+   /* Print out world coord info */
+   if(!quiet) {
+      (void)fprintf(stdout, "CoM_real(x,y,z):   ");
+   }
+   (void)fprintf(stdout, "%.10g %.10g %.10g\n",
+                 stats->world_com[0], stats->world_com[1], stats->world_com[2]);
+}
+
+/* Transforms a coordinate through a linear transform */
+void transform_coord(double out_coord[],
+                     double transform[WORLD_NDIMS][WORLD_NDIMS + 1], double in_coord[])
+{
+   int      idim, jdim;
+   double   homogeneous_coord[WORLD_NDIMS + 1];
+
+   for(idim = 0; idim < WORLD_NDIMS; idim++) {
+      homogeneous_coord[idim] = in_coord[idim];
+   }
+   homogeneous_coord[WORLD_NDIMS] = 1.0;
+
+   for(idim = 0; idim < WORLD_NDIMS; idim++) {
+      out_coord[idim] = 0.0;
+      for(jdim = 0; jdim < WORLD_NDIMS + 1; jdim++) {
+         out_coord[idim] += transform[idim][jdim] * homogeneous_coord[jdim];
+      }
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_double_list
+@INPUT      : dst - client data passed by ParseArgv
+              key - matching key in argv
+              nextarg - argument following key in argv
+@OUTPUT     : (none)
+@RETURNS    : TRUE since nextarg is used.
+@DESCRIPTION: Gets a list (array) of double values.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 8, 1995 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+int get_double_list(char *dst, char *key, char *nextarg)
+{
+#define VECTOR_SEPARATOR ','
+
+   int      num_elements;
+   int      num_alloc;
+   double  *double_list;
+   double   dvalue;
+   char    *cur, *end, *prev;
+   Double_Array *double_array;
+
+   /* Check for a following argument */
+   if(nextarg == NULL) {
+      (void)fprintf(stderr, "\"%s\" option requires an additional argument\n", key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Get pointers to array variables */
+   double_array = (Double_Array *) dst;
+
+   /* Set up pointers to end of string and first non-space character */
+   end = nextarg + strlen(nextarg);
+   cur = nextarg;
+   while(isspace(*cur))
+      cur++;
+   num_elements = 0;
+   num_alloc = 0;
+   double_list = NULL;
+
+   /* Loop through string looking for doubles */
+   while(cur != end) {
+
+      /* Get double */
+      prev = cur;
+      dvalue = strtod(prev, &cur);
+      if(cur == prev) {
+         (void)fprintf(stderr,
+                       "expected vector of doubles for \"%s\", but got \"%s\"\n",
+                       key, nextarg);
+         exit(EXIT_FAILURE);
+      }
+
+      /* Add the value to the list */
+      num_elements++;
+      if(num_elements > num_alloc) {
+         num_alloc += 20;
+         if(double_list == NULL) {
+            double_list = malloc(num_alloc * sizeof(*double_list));
+         }
+         else {
+            double_list = realloc(double_list, num_alloc * sizeof(*double_list));
+         }
+      }
+      double_list[num_elements - 1] = dvalue;
+
+      /* Skip any spaces */
+      while(isspace(*cur))
+         cur++;
+
+      /* Skip an optional comma */
+      if(*cur == VECTOR_SEPARATOR)
+         cur++;
+
+   }
+
+   /* Update the global variables */
+   double_array->numvalues = num_elements;
+   if(double_array->values != NULL) {
+      free(double_array->values);
+   }
+   double_array->values = double_list;
+
+   return TRUE;
+}
+
+/* Check range options and set appropriate values. At least one
+   value will be set up for min and max. */
+void verify_range_options(Double_Array * min, Double_Array * max,
+                          Double_Array * range, Double_Array * binvalue)
+{
+   int      overspecified = FALSE;
+   int      min_defaults, max_defaults;
+   int      num_values;
+   int      ivalue;
+
+   /* Check the min and max */
+   if(min->numvalues != 0 && max->numvalues != 0 && min->numvalues != max->numvalues) {
+      (void)fprintf(stderr, "Number of floor ceil values differs\n");
+      exit(EXIT_FAILURE);
+   }
+   num_values = min->numvalues;
+   if(num_values == 0)
+      num_values = max->numvalues;
+
+   /* Check for range */
+   if(range->numvalues > 0) {
+      if(num_values == 0)
+         num_values = range->numvalues / 2;
+      else
+         overspecified = TRUE;
+   }
+
+   /* Check for binvalue */
+   if(binvalue->numvalues > 0) {
+      if(num_values == 0)
+         num_values = binvalue->numvalues;
+      else
+         overspecified = TRUE;
+   }
+
+   /* Print an error if too many options have been given */
+   if(overspecified) {
+      (void)fprintf(stderr, "Set only one of floor/ceil, range or binvalue\n");
+      exit(EXIT_FAILURE);
+   }
+
+   /* Double-check that we got the sizes right */
+   if((min->numvalues > 0 && min->numvalues != num_values) ||
+      (max->numvalues > 0 && max->numvalues != num_values)) {
+      (void)fprintf(stderr, "Problem with range specification\n");
+      exit(EXIT_FAILURE);
+   }
+
+   /* Check if we are setting default values. Make sure that at least one
+      value is set */
+   if(num_values <= 0) {
+      num_values = 1;
+      min_defaults = max_defaults = TRUE;
+   }
+   else {
+      min_defaults = (min->numvalues == 0 && max->numvalues > 0);
+      max_defaults = (max->numvalues == 0 && min->numvalues > 0);
+   }
+
+   /* Allocate the space */
+   if(min->numvalues <= 0) {
+      min->numvalues = num_values;
+      min->values = malloc(num_values * sizeof(double));
+   }
+   if(max->numvalues <= 0) {
+      max->numvalues = num_values;
+      max->values = malloc(num_values * sizeof(double));
+   }
+   if(min->values == NULL || max->values == NULL) {
+      (void)fprintf(stderr, "Memory allocation error\n");
+      exit(EXIT_FAILURE);
+   }
+
+   /* Set defaults, if needed */
+   if(min_defaults) {
+      for(ivalue = 0; ivalue < num_values; ivalue++)
+         min->values[ivalue] = -DBL_MAX;
+   }
+   if(max_defaults) {
+      for(ivalue = 0; ivalue < num_values; ivalue++)
+         max->values[ivalue] = DBL_MAX;
+   }
+
+   /* Set min and max from range, if needed */
+   if(range->numvalues > 0) {
+
+      /* Check for odd number of values - they should be in pairs */
+      if((vol_range.numvalues % 2) != 0) {
+         (void)fprintf(stderr, "Specify range values in pairs (even number)\n");
+         exit(EXIT_FAILURE);
+      }
+
+      /* Loop over values */
+      for(ivalue = 0; ivalue * 2 + 1 < range->numvalues; ivalue++) {
+         min->values[ivalue] = range->values[ivalue * 2];
+         max->values[ivalue] = range->values[ivalue * 2 + 1];
+      }
+
+   }
+
+   /* Set min and max from binvalue, if needed */
+   if(binvalue->numvalues > 0) {
+      for(ivalue = 0; ivalue < binvalue->numvalues; ivalue++) {
+         min->values[ivalue] = binvalue->values[ivalue] - 0.5;
+         max->values[ivalue] = binvalue->values[ivalue] + 0.5;
+      }
+   }
+
+}
+
+/* Initialiaze a Stats_Info structure */
+void init_stats(Stats_Info * stats, int hist_bins)
+{
+   stats->vol_range[0] = -DBL_MAX;
+   stats->vol_range[1] = DBL_MAX;
+   stats->mask_range[0] = -DBL_MAX;
+   stats->mask_range[1] = DBL_MAX;
+   if(Hist && hist_bins > 0) {
+      stats->histogram = malloc(hist_bins * sizeof(float));
+      memset(stats->histogram, 0, hist_bins * sizeof(float));
+      if(stats->histogram == NULL) {
+         (void)fprintf(stderr, "Memory allocation error\n");
+         exit(EXIT_FAILURE);
+      }
+   }
+   else {
+      stats->histogram = NULL;
+   }
+   stats->hvoxels = 0.0;               /* number of voxels in histogram  */
+   stats->vvoxels = 0.0;               /* number of valid voxels         */
+   stats->volume = 0.0;
+   stats->vol_per = 0.0;
+   stats->hist_per = 0.0;
+   stats->min = DBL_MAX;
+   stats->max = -DBL_MAX;
+   stats->sum = 0.0;
+   stats->sum2 = 0.0;
+   stats->mean = 0.0;
+   stats->variance = 0.0;
+   stats->stddev = 0.0;
+   stats->voxel_com_sum[0] = 0.0;
+   stats->voxel_com_sum[1] = 0.0;
+   stats->voxel_com_sum[2] = 0.0;
+   stats->voxel_com[0] = 0.0;
+   stats->voxel_com[1] = 0.0;
+   stats->voxel_com[2] = 0.0;
+   stats->world_com[0] = 0.0;
+   stats->world_com[1] = 0.0;
+   stats->world_com[2] = 0.0;
+   stats->median = 0.0;
+   stats->majority = 0.0;
+   stats->biModalT = 0.0;
+   stats->pct_T = 0.0;
+   stats->entropy = 0.0;
+}
+
+/* Free things from a Stats_Info structure */
+void free_stats(Stats_Info * stats)
+{
+   if(stats->histogram != NULL)
+      free(stats->histogram);
+}
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/record-test.c
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+
+static int error_cnt = 0;
+
+#define CX 10
+#define CY 10
+#define CZ 6
+#define NDIMS 3
+
+int
+main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    char *name;
+    int result;
+    midimhandle_t hdim[NDIMS];
+    unsigned long coords[NDIMS];
+    unsigned long count[NDIMS];
+    int i,j,k;
+    struct test {
+        int r;
+        int g;
+        int b;
+    } voxel;
+
+    /* Write data one voxel at a time. */
+    for (i = 0; i < NDIMS; i++) {
+        count[i] = 1;
+    }
+
+    result = micreate_dimension("xspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CX, &hdim[0]);
+
+    result = micreate_dimension("yspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CY, &hdim[1]);
+
+    result = micreate_dimension("zspace", MI_DIMCLASS_SPATIAL, 
+                           MI_DIMATTR_REGULARLY_SAMPLED, CZ, &hdim[2]);
+
+    result = micreate_volume("tst-rec.mnc", NDIMS, hdim, MI_TYPE_UINT, 
+                             MI_CLASS_UNIFORM_RECORD, NULL, &hvol);
+    if (result < 0) {
+	TESTRPT("Unable to create test file", result);
+    }
+
+    result = miset_record_field_name(hvol, 0, "Red");
+    if (result < 0) {
+        TESTRPT("miset_record_field_name", result);
+    }
+    miset_record_field_name(hvol, 1, "Green");
+    miset_record_field_name(hvol, 2, "Blue");
+
+    miget_record_field_name(hvol, 1, &name);
+    if (strcmp(name, "Green") != 0) {
+	TESTRPT("Unexpected label for value 1", 0);
+    }
+    mifree_name(name);
+
+    miget_record_field_name(hvol, 0, &name);
+    if (strcmp(name, "Red") != 0) {
+	TESTRPT("Unexpected label for value 0", 0);
+    }
+    mifree_name(name);
+
+    miget_record_field_name(hvol, 2, &name);
+    if (strcmp(name, "Blue") != 0) {
+	TESTRPT("Unexpected label for value 2", 0);
+    }
+    mifree_name(name);
+
+    result = micreate_volume_image(hvol);
+    if (result < 0) {
+        TESTRPT("micreate_volume_image failed", result);
+    }
+
+    for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+            for (k = 0; k < CZ; k++) {
+                coords[0] = i;
+                coords[1] = j;
+                coords[2] = k;
+
+                voxel.r = i;
+                voxel.g = j;
+                voxel.b = k;
+                
+                result = miset_voxel_value_hyperslab(hvol, MI_TYPE_UNKNOWN,
+                                                     coords, count, &voxel);
+                if (result < 0) {
+                    TESTRPT("Error writing voxel", result);
+                }
+            }
+        }
+    }
+
+    for (i = 0; i < CX; i++) {
+        for (j = 0; j < CY; j++) {
+            for (k = 0; k < CZ; k++) {
+                coords[0] = i;
+                coords[1] = j;
+                coords[2] = k;
+
+                result = miget_voxel_value_hyperslab(hvol, MI_TYPE_UNKNOWN,
+                                                     coords, count, &voxel);
+                if (result < 0) {
+                    TESTRPT("Error reading voxel", result);
+                }
+                if (voxel.r != i || voxel.g != j || voxel.b != k) {
+                    TESTRPT("Data mismatch", 0);
+                }
+            }
+        }
+    }
+
+    miclose_volume(hvol);
+
+    if (error_cnt != 0) {
+	fprintf(stderr, "%d error%s reported\n", 
+		error_cnt, (error_cnt == 1) ? "" : "s");
+    }
+    else {
+	fprintf(stderr, "No errors\n");
+    }
+    return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/slice-test.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include "minc2.h"
+
+int
+main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    int r;
+    unsigned long coords[3];
+    double min, max;
+    int i;
+
+    while (--argc > 0) {
+	r = miopen_volume(*++argv, MI2_OPEN_READ, &hvol);
+	if (r < 0) {
+	    fprintf(stderr, "can't open %s, error %d\n", *argv, r);
+	}
+	else {
+	    for (i = 0; i < 10; i++) {
+		coords[0] = i;
+		coords[1] = rand();
+		coords[2] = rand();
+
+		r = miget_slice_min(hvol, coords, 3, &min);
+		if (r < 0) {
+		    fprintf(stderr, "error %d getting slice minimum\n", r);
+		}
+
+		r = miget_slice_max(hvol, coords, 3, &max);
+		if (r < 0) {
+		    fprintf(stderr, "error %d getting slice maximum\n", r);
+		}
+		printf("%d. min %f max %f\n", i, min, max);
+	    }
+	    miclose_volume(hvol);
+	}
+    }
+    return (0);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/valid-test.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+static int error_cnt = 0;
+
+int
+main(int argc, char **argv)
+{
+    mihandle_t hvol;
+    int r;
+    double min, max;
+    double orig_min, orig_max;
+
+    while (--argc > 0) {
+	r = miopen_volume(*++argv, MI2_OPEN_RDWR, &hvol);
+	if (r < 0) {
+	    TESTRPT("can't open input", r);
+            continue;
+	}
+
+        r = miget_volume_valid_min(hvol, &min);
+        if (r < 0) {
+            TESTRPT("error getting valid minimum", r);
+        }
+
+        r = miget_volume_valid_max(hvol, &max);
+        if (r < 0) {
+            TESTRPT("error getting valid maximum", r);
+        }
+            
+        r = miget_volume_valid_range(hvol, &max, &min);
+        if (r < 0) {
+            TESTRPT("error getting valid range", r);
+        }
+
+        printf("min %f max %f\n", min, max);
+        if (min > max) {
+            TESTRPT("error - min exceeds max!", 0);
+        }
+
+        orig_min = min;
+        orig_max = max;
+
+        /* Try some arbitrary manipulations */
+        max = orig_max + 100;
+        min = orig_min - 100;
+
+        r = miset_volume_valid_range(hvol, max, min);
+        if (r < 0) {
+            TESTRPT("error setting new volume range", 0);
+        }
+
+        r = miget_volume_valid_min(hvol, &min);
+        if (r != 0 || min != orig_min - 100) {
+            TESTRPT("error changing volume minimum", 0);
+        }
+
+        r = miget_volume_valid_max(hvol, &max);
+        if (max != orig_max + 100) {
+            TESTRPT("error changing volume maximum", 0);
+        }
+
+        r = miset_volume_valid_range(hvol, orig_max, orig_min);
+        if (r < 0) {
+            TESTRPT("error restoring volume range", r);
+        }
+
+        miclose_volume(hvol);
+    }
+    return (error_cnt);
+}
+
new file mode 100644
--- /dev/null
+++ b/libsrc2/test/volprops-test.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include "minc2.h"
+
+#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
+                                  "Error reported on line #%d, %s: %d\n", \
+                                  __LINE__, msg, val))
+
+static int error_cnt = 0;
+
+
+int main(int argc, char **argv)
+{
+  mihandle_t vol;
+  mivolumeprops_t  props;
+  int r;
+  micompression_t compression_type;
+  BOOLEAN enable_flag;
+  int zlib_level;
+  int depth;
+  int edge_lengths[MI2_MAX_VAR_DIMS];
+  int edge_count;
+  int i;
+
+  r = minew_volume_props(&props);
+
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  
+  r = miset_props_multi_resolution(props, 1 , 2);
+
+  if (r < 0) {
+    TESTRPT("failed", r);
+   }
+
+  r = miget_props_multi_resolution(props, &enable_flag, &depth);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  else {
+    printf("Multiresolution enabled: %d depth: %d \n", enable_flag, depth);
+  }
+
+  r = miset_props_compression_type(props, MI_COMPRESS_NONE);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  else {
+      printf("Set compression type to %d\n", MI_COMPRESS_NONE);
+  }
+
+  r = miget_props_compression_type(props,&compression_type);
+  if (r < 0 || compression_type != MI_COMPRESS_NONE) {
+    TESTRPT("failed", r);
+  }
+  else {
+    printf("Got compression type %d \n", compression_type);
+ }  
+
+  r = miset_props_zlib_compression(props,4);
+  if (r < 0) {
+    TESTRPT("failed", r);
+  }
+  else {
+    printf("Set zlib level to %d\n", 4);
+  }
+
+  r = miget_props_zlib_compression(props,&zlib_level);
+  if (r < 0 || zlib_level != 4) {
+    TESTRPT("failed", r);
+  }
+  else {
+    printf("Got zlib level %d \n", zlib_level);
+  }
+
+  mifree_volume_props(props);
+
+  while (--argc > 0) {
+      r = miopen_volume(*++argv, MI2_OPEN_RDWR, &vol);
+      if (r < 0) {
+	  TESTRPT("failed", r);
+      }
+      r = miget_volume_props(vol, &props);
+      if (r < 0) {
+	  TESTRPT("failed", r);
+      }
+      r = miget_props_blocking(props, &edge_count, edge_lengths, 
+			       MI2_MAX_VAR_DIMS);
+      if (r < 0) {
+	  TESTRPT("failed", r);
+      }
+      printf("edge_count %d\n", edge_count);
+      for (i = 0; i < edge_count; i++) {
+	  printf("  %d", edge_lengths[i]);
+      }
+      printf("\n");
+      mifree_volume_props(props);
+      miclose_volume(vol);
+  }
+
+ if (error_cnt != 0) {
+    fprintf(stderr, "%d error%s reported\n", 
+	    error_cnt, (error_cnt == 1) ? "" : "s");
+  }
+  else {
+    fprintf(stderr, "No errors\n");
+  }
+  return (error_cnt);
+}
+