TestXmdf.cpp

TestXmdf.cpp provides C++ code examples for many XMDF APIs.
// This file has functions that can be used to test reading and writing of
// datasets using HDF5.  This code is intended to be used as tests for the
// XMDF library as well as sample code for distribution.

#include "stdafx.h"
#include <Xmdf.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include "TestDatasets.h"

#define    DATASETS_LOCATION "Datasets"
#define    SCALAR_A_LOCATION "Scalars/ScalarA"
#define    SCALAR_B_LOCATION "Scalars/ScalarB"
#define    VECTOR2D_A_LOCATION "Vectors/Vector2D_A"
#define    VECTOR2D_B_LOCATION "Vectors/Vector2D_B"

void tdiDatasetArray (double a_dMin, double a_dMax, int a_nCycle, 
                     int a_SeedMultiplier, int a_nValues, float *a_Array);
double tdiRandomNumberInRange (double a_dMin, double a_dMax, int a_nSeed);
int tdiReadScalar (xid a_xScalarId, FILE *a_fp);
int tdiReadVector (xid a_xVectorId, FILE *a_fp);

// ---------------------------------------------------------------------------
// FUNCTION  tdEditScalarAValues
// PURPOSE   
// NOTES     
// ---------------------------------------------------------------------------
int tdEditScalarAValues (LPCSTR a_Filename, int a_Compression)
{
  int nStatus = NONE;
  xid xFileId = 0, xScalarId = 0;
  const char * DATASET_PATH = "Datasets/Scalars/ScalarA";

  nStatus = tdWriteScalarA(a_Filename, a_Compression);
  if (nStatus < 0) {
    return nStatus;
  }
    // open the file and edit the values
  
  nStatus = xfOpenFile(a_Filename, &xFileId, XFALSE);
  if (nStatus < 0) {
    return -1;
  }

  nStatus = xfOpenGroup(xFileId, DATASET_PATH, &xScalarId);
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1; 
  }
  
    // Edit values in timestep 1, make index 1 = 4, index 5 = 40,
    // and index 10 = 400
  int editTimestep = 1;
  const int editNumValues = 3;
  int indices[editNumValues];
  indices[0] = 1;
  indices[1] = 5;
  indices[2] = 10;
  float new_values[editNumValues];
  new_values[0] = 4.0;
  new_values[1] = 40.0;
  new_values[2] = 400.0;

  nStatus = xfChangeScalarValuesTimestepFloat(xScalarId, editTimestep, editNumValues,
                               indices, new_values);
  if (nStatus < 0) {
    xfCloseGroup(xScalarId);
    xfCloseFile(xFileId);
    return -1; 
  }

    // Edit values in timestep 2, make index 2 = 6, index 3 = 60, and 
    // index 9 = 600
  editTimestep = 2;
  indices[0] = 2;
  indices[1] = 3;
  indices[2] = 9;
  new_values[0] = -6.0;
  new_values[1] = 60.0;
  new_values[2] = 6000.0;

  nStatus = xfChangeScalarValuesTimestepFloat(xScalarId, editTimestep, editNumValues,
                               indices, new_values);
  if (nStatus < 0) {
    xfCloseGroup(xScalarId);
    xfCloseFile(xFileId);
    return -1; 
  }

  xfCloseGroup(xScalarId);
  xfCloseFile(xFileId);

  return nStatus;
} // tdEditScalarAValues
// --------------------------------------------------------------------------
// FUNCTION tdReadDatasets
// PURPOSE  Read a dataset group from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int tdReadDatasets (xid a_xGroupId, FILE *a_fp)
{
  int   nPaths=0, nMaxPathLength=0, nMultiDatasets=0;
  char *Paths = NULL, *IndividualPath = NULL;
  int   nStatus, i, j;
  xid   xScalarId = NONE, xVectorId = NONE, xMultiId = NONE;

  // Look for scalar datasets
  nStatus = xfGetScalarDatasetsInfo(a_xGroupId, &nPaths, &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nPaths*nMaxPathLength*sizeof(char));
    xfGetScalarDatasetPaths(a_xGroupId, nPaths, nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    return -1;
  }
  
  // Output number and paths to scalar datasets
  fprintf(a_fp, "Number of Scalars %d\n", nPaths);
  for (i = 0; i < nPaths; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];
    fprintf(a_fp, "Reading scalar: %s\n", IndividualPath);
   
    nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xScalarId);
    if (nStatus < 0) {
      return -1; 
    }

    nStatus = tdiReadScalar(xScalarId, a_fp);
    xfCloseGroup(xScalarId);
    if (nStatus < 0) {
      printf("Error reading scalar dataset.");
      return -1;
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  // Look for vector datasets
  nStatus = xfGetVectorDatasetsInfo(a_xGroupId, &nPaths, &nMaxPathLength);
  if (nStatus >= 0 && nPaths > 0) {
    Paths = (char *)malloc(nPaths*nMaxPathLength*sizeof(char));
    xfGetVectorDatasetPaths(a_xGroupId, nPaths, nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    return -1;
  }


  // Output number and paths to scalar datasets
  fprintf(a_fp, "Number of Vectors %d\n", nPaths);
  for (i = 0; i < nPaths; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];
    fprintf(a_fp, "Reading Vector: %s\n", IndividualPath);
   
    nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xVectorId);
    if (nStatus < 0) {
      return -1; 
    }

    nStatus = tdiReadVector(xVectorId, a_fp);
    xfCloseGroup(xVectorId);
    if (nStatus < 0) {
      printf("Error reading vector dataset.");
      return -1;
    }
  }

  // find multidataset folders
  nStatus = xfGetGroupPathsSizeForMultiDatasets(a_xGroupId, &nMultiDatasets,
                                                      &nMaxPathLength);
  if (nStatus >= 0 && nMultiDatasets > 0) {
    Paths = (char *)malloc(nMultiDatasets*nMaxPathLength*sizeof(char));
    nStatus = xfGetAllGroupPathsForMultiDatasets(a_xGroupId, nMultiDatasets, 
                                                 nMaxPathLength, Paths);
    if (nStatus < 0) {
      return -1;
    }

  // Output number and paths to multidatasets
    fprintf(a_fp, "Number of Multidatasets: %d\n", nMultiDatasets);
    for (i=0; i<nMultiDatasets; i++) {
      IndividualPath = "";
      for (j=0; j<nMaxPathLength-1; j++) {
        IndividualPath = &Paths[i*nMaxPathLength];
      }
      fprintf(a_fp, "Reading multidataset: %s\n", IndividualPath);
      nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xMultiId);
      if (nStatus < 0) {
            return -1;
      }

      nStatus = tdReadDatasets(xMultiId, a_fp);
      nStatus = xfCloseGroup(xMultiId);
      if (nStatus < 0) {
        printf("Error reading multidatasets.");
            return -1;
      }
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  return 1;
} // tdReadDatasets
// --------------------------------------------------------------------------
// FUNCTION tdReadActivityScalarAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int tdReadActivityScalarAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xScalarAId = NONE;
  int     nTimesteps;
  xmbool  *bActive;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, SCALAR_A_LOCATION, &xScalarAId);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xScalarAId, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  bActive = new xmbool[nTimesteps];
  status = xfReadActivityValuesAtIndex(xScalarAId, a_Index, 1, nTimesteps,
                                       bActive);

  // output the data
  printf("\nReading activity for scalar A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%d ", bActive[i]);
  }
  printf("\n");

  delete [] bActive;

  return status;
} // tdReadActivityScalarAtIndex
// --------------------------------------------------------------------------
// FUNCTION tdReadScalarAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int tdReadScalarAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xScalarAId = NONE;
  int     nTimesteps;
  float  *fValues;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, SCALAR_A_LOCATION, &xScalarAId);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xScalarAId, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  fValues = new float[nTimesteps];
  status = xfReadScalarValuesAtIndex(xScalarAId, a_Index, 1, nTimesteps,
                                     fValues);

  // output the data
  printf("\nReading scalar A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%f ", fValues[i]);
  }
  printf("\n");

  delete [] fValues;

  return status;
} // tdReadScalarAtIndex
// ---------------------------------------------------------------------------
// FUNCTION  tdReadScalarAIndices
// PURPOSE   
// NOTES     
// ---------------------------------------------------------------------------
int tdReadScalarAIndices (LPCSTR a_Filename, int a_nIndices, int *a_indices)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xScalarAId = NONE;
  int     nTimesteps;
  float  *fValues;
  int     nValues = 0;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, SCALAR_A_LOCATION, &xScalarAId);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xScalarAId, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  nValues = nTimesteps*a_nIndices;
  fValues = new float[nValues];
  status = xfReadScalarValuesAtIndicesFloat(xScalarAId, a_nIndices, a_indices, 1,
                                            nTimesteps, fValues);

  // output the data
  printf("\nReading scalar A indices\n");
  int id = 0;
  for (int i = 0; i < nTimesteps; i++) {
    printf("Timestep: %d\n", i+1);
    for (int j = 0; j < a_nIndices; j++) {
      printf("index: %d  value: %f \n", a_indices[j], fValues[id]);
      id++;
    }
  }
  printf("\n");

  delete [] fValues;

  return status;
} // tdReadScalarAIndices
// --------------------------------------------------------------------------
// FUNCTION tdWriteScalarA
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int tdWriteScalarA (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xScalarAId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, iHpgnZone;
  double   dJulianReftime;
  int      nErrors = 0, i = 0;
  char     **Errors = NULL;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group where we will put all the datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarAId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    fValues[0] = (float)dTime;
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
    }

    // write the dataset array values
    status = xfWriteScalarTimestep(xScalarAId, dTime, nValues, fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xScalarAId, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }
  }

  // Write Coordinate file - for ScalarA, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // set HPGN Zone for test
  iHpgnZone = 29;      // Utah

    // Write Coordinate Information to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xScalarAId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // tdWriteScalarA

// --------------------------------------------------------------------------
// FUNCTION tdWriteScalarAPieces
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests writing scalar datasets in parts
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int tdWriteScalarAPieces (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xScalarAId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, iHpgnZone;
  double   dJulianReftime;
  int      nErrors = 0, i = 0;
  char     **Errors = NULL;
  const int numValuesPerWrite = 2;
  float     minvalue, maxvalue;
  hsize_t       timestepId;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group where we will put all the datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarAId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    float minvalue =  9999.9;
    float maxvalue = -9999.9;

    fValues[0] = (float)dTime;
    minvalue = maxvalue = fValues[0];
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
      minvalue = min(minvalue, fValues[i]);
      maxvalue = max(maxvalue, fValues[i]);
    }

      // we will write the values as pairs
    status = xfInitializeScalarTimestep(xScalarAId, dTime, nValues, minvalue,
                                        maxvalue, &timestepId);
    if (status < 0) {
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }

    for (i = 0; i < nValues; i += numValuesPerWrite) {
      status = xfWriteScalarTimestepPortion(xScalarAId, timestepId,
                                           numValuesPerWrite, i+1, &fValues[i]);
    }

    if (status >= 0) {
      // write activity array
      xfInitializeActivityTimestep(xScalarAId, nActive, &timestepId); 

      for (i = 0; i < nActive; i += 2) {
        status = xfWriteActivityTimestepPortion(xScalarAId, timestepId, 2,
                   i+1, &bActivity[i]);
      }
    }
    if (status < 0) {
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }
  }

  // Write Coordinate file - for ScalarA, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return -1;
  }

    // set HPGN Zone for test
  iHpgnZone = 29;      // Utah

    // Write Coordinate Information to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xScalarAId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // tdWriteScalarAPieces

// --------------------------------------------------------------------------
// FUNCTION tdWriteScalarAPiecesAltMinMax
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests writing scalar datasets in parts
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int tdWriteScalarAPiecesAltMinMax (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xScalarAId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, iHpgnZone;
  double   dJulianReftime;
  int      nErrors = 0, i = 0;
  char     **Errors = NULL;
  const int numValuesPerWrite = 2;
  float     minvalue, maxvalue;
  hsize_t       timestepId;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group where we will put all the datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarAId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    float minvalue =  9999.9;
    float maxvalue = -9999.9;

    fValues[0] = (float)dTime;
    minvalue = maxvalue = fValues[0];
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
      minvalue = min(minvalue, fValues[i]);
      maxvalue = max(maxvalue, fValues[i]);
    }

      // we will write the values as pairs
    status = xfInitializeScalarTimestep(xScalarAId, dTime, nValues, minvalue,
                                        maxvalue, &timestepId);
    if (status < 0) {
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }

    for (i = 0; i < nValues; i += numValuesPerWrite) {
      status = xfWriteScalarTimestepPortion(xScalarAId, timestepId,
                                           numValuesPerWrite, i+1, &fValues[i]);
    }

      // Set the min to 0.1111*timestepId
      // Set the max to 1111*timestepId
    minvalue = 0.1111*(float)timestepId;
    maxvalue = 1111*(float)timestepId;
    status = xfSetDatasetTimestepMinMax(xScalarAId, timestepId,
                                        minvalue, maxvalue);

    if (status >= 0) {
      // write activity array
      xfInitializeActivityTimestep(xScalarAId, nActive, &timestepId); 

      for (i = 0; i < nActive; i += 2) {
        status = xfWriteActivityTimestepPortion(xScalarAId, timestepId, 2,
                   i+1, &bActivity[i]);
      }
    }
    if (status < 0) {
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }
  }

  // Write Coordinate file - for ScalarA, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return -1;
  }

    // set HPGN Zone for test
  iHpgnZone = 29;      // Utah

    // Write Coordinate Information to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xScalarAId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // tdWriteScalarAPiecesAltMinMax

// --------------------------------------------------------------------------
// FUNCTION tdWriteScalarB
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int tdWriteScalarB (LPCSTR a_Filename, int a_Compression, int a_Overwrite)
{
  xid      xFileId, xDsetsId, xScalarBId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0, dJulianReftime;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, nErrors = 0, i = 0;
  char     **Errors = NULL;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  if (a_Overwrite) {
      // open the already-existing file
    status = xfOpenFile(a_Filename, &xFileId, XFALSE);
    if (status < 0) {
      return -1;
    }
      // open the group where we have all the datasets 
    status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }
  else {
      // create the file
    status = xfCreateFile(a_Filename, &xFileId, XTRUE);
    if (status < 0) {
      return -1;
    }
      // create the group where we will put all the datasets 
    status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create/Overwrite the scalar B dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_B_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarBId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return -1;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarBId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarBId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  if (!a_Overwrite) {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 0.5 hour timestep
      dTime = (iTimestep + 1) * 0.5;

      fValues[0] = (float)dTime;
      for (i = 1; i < nValues; i++) {
        fValues[i] = float(fValues[i-1]*2.5);
      }

      // write the dataset array values
      status = xfWriteScalarTimestep(xScalarBId, dTime, nValues, fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xScalarBId, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xScalarBId);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }
  else {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 1.5 hour timestep
      dTime = (iTimestep + 1) * 1.5;

      fValues[0] = (float)dTime;
      for (i = 1; i < nValues; i++) {
        fValues[i] = float(fValues[i-1]*1.5);
      }

      // write the dataset array values
      status = xfWriteScalarTimestep(xScalarBId, dTime, nValues, fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xScalarBId, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xScalarBId);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }

  if (!a_Overwrite) {
    // Write Coordinate file
    status = xfCreateCoordinateGroup(xFileId, &xCoordId);
    if (status <= 0) {
      xfCloseGroup(xScalarBId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
      return -1;
    }

    // For ScalarB, we will set the coordinate system
    // to be UTM, with UTM Zone settings written to the file.
      // Write Coord Info to file
    xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
    xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

    xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
    xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

      // write additional information - we'll use the max value for this test
    xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

    xfCloseGroup(xCoordId);
    xCoordId = 0;
  }

  // close the dataset
  xfCloseGroup(xScalarBId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // tdWriteScalarB
// --------------------------------------------------------------------------
// FUNCTION tdWriteCoordsToMulti
// PURPOSE  Write coordinate system to a multidataset file
// NOTES
// --------------------------------------------------------------------------
int tdWriteCoordsToMulti (xid a_xFileId)
{
  xid   xCoordId = NONE;
  int   status;

  // Write Coordinate file - for Multidatasets, we will set the coordinate system
  //   to be UTM, with UTM Zone settings written to the file.
  status = xfCreateCoordinateGroup(a_xFileId, &xCoordId);
  if (status <= 0) {
    return -1;
  }

   // Write Coord Info to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information - we'll use the max value for this test
  xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  return XTRUE;
} // tdWriteCoordsToMulti
// --------------------------------------------------------------------------
// FUNCTION tdWriteScalarAToMulti
// PURPOSE  Write scalar Dataset to a multidataset
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int tdWriteScalarAToMulti (xid a_GroupId)
{
  xid      xScalarAId;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status;
  double   dJulianReftime;
  int      i = 0;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(a_GroupId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, NONE,
                                 &xScalarAId);
  
  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    fValues[0] = (float)dTime;
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
    }

    // write the dataset array values
    status = xfWriteScalarTimestep(xScalarAId, dTime, nValues, fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xScalarAId, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xScalarAId);
    }
  }

  // close the dataset
  xfCloseGroup(xScalarAId);

  return FALSE;
} // tdWriteScalarAToMulti
// --------------------------------------------------------------------------
// FUNCTION tdReadVector2DAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int tdReadVector2DAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xVector2DA = NONE;
  int     nTimesteps;
  float  *fValues;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, VECTOR2D_A_LOCATION, &xVector2DA);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xVector2DA, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  fValues = new float[nTimesteps*2];
  status = xfReadVectorValuesAtIndex(xVector2DA, a_Index, 1, nTimesteps, 2,
                                     fValues);

  // output the data
  printf("\nReading vector 2D A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%f %f \n", fValues[i*2], fValues[i*2 + 1]);
  }
  printf("\n");

  delete [] fValues;

  return status;
} // tdReadVector2DAIndex
// --------------------------------------------------------------------------
// FUNCTION tdWriteVector2D_A
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int tdWriteVector2D_A (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xVectorA, xCoordId = NONE;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;
  int      iHpgnZone;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store all datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Create the scalar A dataset group
  status = xfCreateVectorDataset(xDsetsId, VECTOR2D_A_LOCATION, "ft/s",
               TS_SECONDS, a_Compression, &xVectorA);
  if (status < 0) {
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    for (i = 0; i < nValues; i++) {
      for (j = 0; j < nComponents; j++) {
        fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
      }
    }
//    // generate values array using random numbers between dMin and dMax
//    tdiDatasetArray(dMin, dMax, iTimestep + 1, nSeedMultiplier,
//                    nValues*nComponents, fValues);

    // write the dataset array values
    status = xfWriteVectorTimestep(xVectorA, dTime, nValues, nComponents,
                                   fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xVectorA, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xVectorA);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }
  }

  // Write Coordinate file - for Vector2D_A, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xVectorA);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // set HPGN info for test
  iHpgnZone = 29;      // Utah

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xVectorA);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return FALSE;
} // tdWriteVector2D_A
// --------------------------------------------------------------------------
// FUNCTION tdWriteVector2D_A_Pieces
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int tdWriteVector2D_A_Pieces (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xVectorA, xCoordId = NONE;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
  int      i, j, status;
  int      iHpgnZone;
  hsize_t timestepId = 0;
  int nValuesToWrite = 2;
  int nComponentsToWrite = 2;
  int startIndex = 1;
  int startComponent = 1;
  float   minvalue, maxvalue;
  float   mag;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store all datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Create the scalar A dataset group
  status = xfCreateVectorDataset(xDsetsId, VECTOR2D_A_LOCATION, "ft/s",
               TS_SECONDS, a_Compression, &xVectorA);
  if (status < 0) {
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    for (i = 0; i < nValues; i++) {
      for (j = 0; j < nComponents; j++) {
        fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
      }
    }

    minvalue = MAX_FLOAT;
    maxvalue = 0.0;
    for (i = 0; i < nValues; i++) {
      mag = 0.0;
      for (j = 0; j < nComponents; j++) {
        mag += pow((double)fValues[i*nComponents + j], 2.0);
      }
      mag = sqrt(mag);
      minvalue = min(minvalue, mag);
      maxvalue = max(maxvalue, mag);
    }

    // write the dataset array values
    status = xfInitializeVectorTimestep(xVectorA, dTime, nValues, nComponents,
               minvalue, maxvalue, &timestepId);

      // write both components at once
    nValuesToWrite = 2;
    nComponentsToWrite = 2;
    startIndex = 1;
    startComponent = 1;
    for (int i = 0; i < nValues; i+=2) {
      status = xfWriteVectorTimestepPortion(xVectorA, timestepId,
                 nValuesToWrite, nComponentsToWrite, i + 1, startComponent,
                 &fValues[2*i]);
    }

    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xVectorA, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xVectorA);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }
  }

  // Write Coordinate file - for Vector2D_A, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xVectorA);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return -1;
  }

    // set HPGN info for test
  iHpgnZone = 29;      // Utah

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xVectorA);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return FALSE;
} // tdWriteVector2D_A_Pieces
// --------------------------------------------------------------------------
// FUNCTION tdWriteVector2D_B
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int tdWriteVector2D_B (LPCSTR a_Filename, int a_Compression, int a_Overwrite)
{
  xid      xFileId, xDsetsId, xVectorB, xCoordId = NONE;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  if (a_Overwrite) {
      //open the already-existing file
    status = xfOpenFile(a_Filename, &xFileId, XFALSE);
    if (status < 0) {
      return -1;
    }
      // open the group where we have all the datasets
    status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }
  else {
      // create the file
    status = xfCreateFile(a_Filename, &xFileId, XTRUE);
    if (status < 0) {
      return FALSE;
    }
      // create the group to store all datasets 
    status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return FALSE;
    }
  }

  // Create the Vector B dataset group
  status = xfCreateVectorDataset(xDsetsId, VECTOR2D_B_LOCATION, "ft/s",
               TS_SECONDS, a_Compression, &xVectorB);
  if (status < 0) {
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  if (!a_Overwrite) {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 0.5 hour timestep
      dTime = (iTimestep + 1) * 0.5;

      for (i = 0; i < nValues; i++) {
        for (j = 0; j < nComponents; j++) {
          fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
        }
      }

      // write the dataset array values
      status = xfWriteVectorTimestep(xVectorB, dTime, nValues, nComponents,
                                     fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xVectorB, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xVectorB);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }
  else {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 1.5 hour timestep
      dTime = (iTimestep + 1) * 1.5;

      for (i = 0; i < nValues; i++) {
        for (j = 0; j < nComponents; j++) {
          fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
        }
      }

      // write the dataset array values
      status = xfWriteVectorTimestep(xVectorB, dTime, nValues, nComponents,
                                     fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xVectorB, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xVectorB);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }

  // Write Coordinate file - for ScalarB, we will set the coordinate system
  //   to be UTM, with UTM Zone settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xVectorB);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // write the coordinate data to the file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information - we'll use the max UTM zone for the test
  xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xVectorB);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // tdWriteVector2D_B
// --------------------------------------------------------------------------
// FUNCTION tdWriteVector2DAToMulti
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int tdWriteVector2DAToMulti (xid a_GroupId)
{
  xid      xVectorA;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  // Create the scalar A dataset group
  status = xfCreateVectorDataset(a_GroupId, VECTOR2D_A_LOCATION, "ft/s",
               TS_SECONDS, NONE, &xVectorA);
  if (status < 0) {
    return FALSE;
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    for (i = 0; i < nValues; i++) {
      for (j = 0; j < nComponents; j++) {
        fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
      }
    }
//    // generate values array using random numbers between dMin and dMax
//    tdiDatasetArray(dMin, dMax, iTimestep + 1, nSeedMultiplier,
//                    nValues*nComponents, fValues);

    // write the dataset array values
    status = xfWriteVectorTimestep(xVectorA, dTime, nValues, nComponents,
                                   fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xVectorA, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xVectorA);
    }
  }

  // close the dataset
  xfCloseGroup(xVectorA);

  return FALSE;
} // tdWriteVector2DAToMulti
// --------------------------------------------------------------------------
// FUNCTION tdiRandomNumberInRange
// PURPOSE  generate Psuedo Random numbers.  We use the same seeds every
//          time so we end up with consistent values for testing purposes.
// --------------------------------------------------------------------------
double tdiRandomNumberInRange (double a_dMin, double a_dMax, int a_nSeed)
{
  int nRandom;
  double dValue;

  srand(a_nSeed);
  nRandom = rand();

  dValue = a_dMin + ((double)(nRandom)*(a_dMax - a_dMin))/RAND_MAX;

  return dValue;
} // tdiRandomNumberInRange
// --------------------------------------------------------------------------
// FUNCTION tdDatasetArray
// PURPOSE  Get dataset data to use in a dataset
// NOTES    Generates random numbers between a range to fill in the array
// --------------------------------------------------------------------------
void tdiDatasetArray (double a_dMin, double a_dMax, int a_nCycle, 
                     int a_SeedMultiplier, int a_nValues, float *a_Array)
{
  int       i, nSeedBase;

  for (i = 0; i < a_nValues; i++) {
    nSeedBase = a_nCycle*a_nValues + i;
    a_Array[i] = (float)tdiRandomNumberInRange(a_dMin, a_dMax, 
                                              nSeedBase*a_SeedMultiplier);
  }
} // tdDatasetArray
// --------------------------------------------------------------------------
// FUNCTION tdiReadScalar
// PURPOSE  Read a scalar from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int tdiReadScalar (xid a_xScalarId, FILE *a_fp)
{
  int    nTimes = NONE, nValues = NONE, nActive = NONE;
  int    nStatus = TRUE, iTime, iVal, iActive;
  char   TimeUnits[100], Units[100];
  double *Times = NULL;
  float  *Values = NULL, *Mins = NULL, *Maxs = NULL;
  xmbool  *Active = NULL;
  xmbool  bUseReftime;
  double Reftime;

  // read the time units
  nStatus = xfGetDatasetTimeUnits(a_xScalarId, TimeUnits);
  if (nStatus < 0) {
    return nStatus;
  }
  fprintf(a_fp, "Time units: %s\n", TimeUnits);

  // see if we are using a reftime
  nStatus = xfUseDatasetReftime(a_xScalarId, &bUseReftime);
  if (nStatus < 0) {
    return nStatus;
  }
  if (bUseReftime) {
    nStatus = xfReadDatasetReftime(a_xScalarId, &Reftime);
    if (nStatus < 0) {
      return nStatus;
    }
    fprintf(a_fp, "Reftime: %f\n", Reftime);
  }

  // read the units
  nStatus = xfGetDatasetUnits(a_xScalarId, Units);
  if (nStatus < 0) { 
    return nStatus;
  }
  fprintf(a_fp, "units: %s\n", Units);

  // read in the number of values and number of active values
  nStatus = xfGetDatasetNumVals(a_xScalarId, &nValues);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetNumActive(a_xScalarId, &nActive);
  }
  if (nStatus < 0) {
    return nStatus;
  }

  if (nValues <= 0) {
    printf("No data to read in.");
    return -1;
  }

  // read in the number of times
  nStatus = xfGetDatasetNumTimes(a_xScalarId, &nTimes);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the individual time values
  Times = (double *)malloc(nTimes*sizeof(double));
  if (Times == NULL) {
    printf("Out of memory");
    return -1;
  }
  nStatus = xfGetDatasetTimes(a_xScalarId, nTimes, Times);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the minimum and maximum values
  Mins = (float *)malloc(nTimes*sizeof(float));
  Maxs = (float *)malloc(nTimes*sizeof(float));
  if (Mins == NULL || Maxs == NULL) {
    free(Times);
    printf("Out of memory");
    return -1;
  }

  nStatus = xfGetDatasetMins(a_xScalarId, nTimes, Mins);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetMaxs(a_xScalarId, nTimes, Maxs);
  }
  if (nStatus < 0) {
    free(Times);
    free(Mins);
    free(Maxs);
    return nStatus;
  }

  Values = (float *)malloc(nValues*sizeof(float));
  if (nActive > 0) {
    Active = (xmbool *)malloc(nActive*sizeof(xmbool));
  }

  fprintf(a_fp, "Number Timesteps: %d\n", nTimes);
  fprintf(a_fp, "Number Values: %d\n", nValues);
  fprintf(a_fp, "Number Active: %d\n", nActive);

  // loop through the timesteps, read the values and active values and write
  // them to the text file
  for (iTime = 0; iTime < nTimes; iTime++) {
      // indices should be 1 based
    nStatus = xfReadScalarValuesTimestep(a_xScalarId, iTime + 1,
                                         nValues, Values);
    if (nStatus >= 0 && nActive > 0) {
        // indices should be 1 based
      nStatus = xfReadActivityTimestep(a_xScalarId, iTime + 1, nActive, Active);
    }

    // Write the time, min, max, values and active values to the text output
    // file.
    fprintf(a_fp, "\nTimestep at  %6.3lf\nMin: %6.3lf\nMax: %6.3lf\n", 
                  Times[iTime], Mins[iTime], Maxs[iTime]);

    fprintf(a_fp, "Values:\n");
    // print 5 values per line
    for (iVal = 0; iVal < nValues; iVal++) {
      fprintf(a_fp, "%6.3f ", Values[iVal]);
      if ((iVal + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n");

    fprintf(a_fp, "Activity:\n");
    // print 5 values per line
    for (iActive = 0; iActive < nActive; iActive++) {
      fprintf(a_fp, "%4d ", (int)Active[iActive]);
      if ((iActive + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n\n");
  }

  if (Times) {
    free(Times);
    Times = NULL;
  }
  
  if (Mins) {
    free(Mins);
    Mins = NULL;
  }

  if (Maxs) {
    free(Maxs);
    Maxs = NULL;
  }

  if (Values) {
    free(Values);
    Values = NULL;
  }

  if (Active) {
    free(Active);
    Active = NULL;
  }

  return TRUE;
} // tdiReadScalar
// --------------------------------------------------------------------------
// FUNCTION tdiReadVector
// PURPOSE  Read a vector from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int tdiReadVector (xid a_xVectorId, FILE *a_fp)
{
  int    nTimes = NONE, nValues = NONE, nComponents = NONE, nActive = NONE;
  int    nStatus = TRUE, iTime, iVal, iActive;
  char   TimeUnits[100];
  double *Times = NULL;
  float  *Values = NULL, *Mins = NULL, *Maxs = NULL;
  xmbool  *Active = NULL;
  xmbool  bUseReftime;
  double Reftime;

  // read the time units
  nStatus = xfGetDatasetTimeUnits(a_xVectorId, TimeUnits);
  if (nStatus < 0) {
    return nStatus;
  }
  fprintf(a_fp, "Time units: %s\n", TimeUnits);

  // see if we are using a reftime
  nStatus = xfUseDatasetReftime(a_xVectorId, &bUseReftime);
  if (nStatus < 0) {
    return nStatus;
  }
  if (bUseReftime) {
    nStatus = xfReadDatasetReftime(a_xVectorId, &Reftime);
    if (nStatus < 0) {
      return nStatus;
    }
    fprintf(a_fp, "Reftime: %f", Reftime);
  }

  // read in the number of values and number of active values
  nStatus = xfGetDatasetNumVals(a_xVectorId, &nValues);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetVecNumComponents(a_xVectorId, &nComponents);
    if (nStatus >= 0) {
      nStatus = xfGetDatasetNumActive(a_xVectorId, &nActive);
    }
  }
  if (nStatus < 0) {
    return nStatus;
  }

  if (nValues <= 0) {
    printf("No data to read in.");
    return -1;
  }

  // read in the number of times
  nStatus = xfGetDatasetNumTimes(a_xVectorId, &nTimes);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the individual time values
  Times = (double *)malloc(nTimes*sizeof(double));
  if (Times == NULL) {
    printf("Out of memory");
    return -1;
  }
  nStatus = xfGetDatasetTimes(a_xVectorId, nTimes, Times);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the minimum and maximum values
  Mins = (float *)malloc(nTimes*sizeof(float));
  Maxs = (float *)malloc(nTimes*sizeof(float));
  if (Mins == NULL || Maxs == NULL) {
    free(Times);
    printf("Out of memory");
    return -1;
  }

  nStatus = xfGetDatasetMins(a_xVectorId, nTimes, Mins);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetMaxs(a_xVectorId, nTimes, Maxs);
  }
  if (nStatus < 0) {
    free(Times);
    free(Mins);
    free(Maxs);
    return nStatus;
  }

  Values = (float *)malloc(nValues*nComponents*sizeof(float));
  if (nActive > 0) {
    Active = (xmbool *)malloc(nActive*sizeof(xmbool));
  }

  fprintf(a_fp, "Number Timesteps: %d\n", nTimes);
  fprintf(a_fp, "Number Values: %d\n", nValues);
  fprintf(a_fp, "Number Components: %d\n", nComponents);
  fprintf(a_fp, "Number Active: %d\n", nActive);

  // loop through the timesteps, read the values and active values and write
  // them to the text file
  for (iTime = 0; iTime < nTimes; iTime++) {
    nStatus = xfReadVectorValuesTimestep(a_xVectorId, iTime + 1,
                                         nValues, nComponents, Values);
    if (nStatus >= 0 && nActive > 0) {
      nStatus = xfReadActivityTimestep(a_xVectorId, iTime + 1, nActive, Active);
    }

    // Write the time, min, max, values and active values to the text output
    // file.
    fprintf(a_fp, "\nTimestep at  %6.3lf\nMin: %6.3lf\nMax: %6.3lf\n", 
                  Times[iTime], Mins[iTime], Maxs[iTime]);

    fprintf(a_fp, "Values:\n");
    // print a set of vector values per line
    for (iVal = 0; iVal < nValues; iVal++) {
      fprintf(a_fp, "%6.3f %6.3f\n", Values[iVal*nComponents], 
                                     Values[(iVal*nComponents) + 1]);
    }
    fprintf(a_fp, "\n");

    fprintf(a_fp, "Activity:\n");
    // print 5 values per line
    for (iActive = 0; iActive < nActive; iActive++) {
      fprintf(a_fp, "%4d ", (int)Active[iActive]);
      if ((iActive + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n\n");
  }

  if (Times) {
    free(Times);
    Times = NULL;
  }
  
  if (Mins) {
    free(Mins);
    Mins = NULL;
  }

  if (Maxs) {
    free(Maxs);
    Maxs = NULL;
  }

  if (Values) {
    free(Values);
    Values = NULL;
  }

  if (Active) {
    free(Active);
    Active = NULL;
  }

  return TRUE;
} // tdiReadVector
TestDatasets.cpp tests datasets
#include "stdafx.h"
#include <Xmdf.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include "TestGeomPaths.h"

/* tmReadTestPaths */
int tmReadTestPaths(LPCSTR Filename, LPCSTR OutFilename)
{
  int         nGroups, nMaxPathLength, nDims, nPaths, nTimes, i, j;
  int         PathIndices[2];
  char       *Paths = NULL, *IndividualPath = NULL;
  double     *times, *locs, NullVal = 0;
  xid         xFileId = NONE, xGroupId = NONE;
  int         nStatus;
  FILE       *fp = NULL;

  // open the XMDF file 
  nStatus = xfOpenFile(Filename, &xFileId, TRUE);
  if (nStatus < 0) {
    printf("Unable to open XMDF file tmReadTestPaths.");
    return nStatus;
  }

  // open the Output file 
  fp = fopen(OutFilename, "w");
  if (fp == NULL) {
    printf("Unable to open output file tmReadTestPaths.");
    return nStatus;
  }

  // find the geomotric path groups
  // Get the number and paths of datasets in the file.
  nStatus = xfGetGroupPathsSizeForGeomPaths(xFileId, &nGroups,
                                                    &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nMaxPathLength*nGroups*sizeof(char));
    nStatus = xfGetGroupPathsForGeomPaths(xFileId, nGroups, 
                                         nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }
  // Report the number and paths to individual geom paths groups in the file.
  fprintf(fp, "Number of geometric paths in file: %d\n", nGroups);
  fprintf(fp, "Paths:\n");
  for (i = 0; i < nGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    fprintf(fp, "  %s\n", IndividualPath);
  }
  fprintf(fp, "\n");

  // Open each geometric path group
  for (i = 0; i < nGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    
    fprintf(fp, "Reading geom paths in group: %s\n", IndividualPath);
    nStatus = xfOpenGroup(xFileId, IndividualPath, &xGroupId);
    if (nStatus >= 0) {
      // read the dimensionality of the paths
      nStatus = xfGetPathDimensionality(xGroupId, &nDims);
      if (nStatus >= 0) {
        fprintf(fp, "Group dimensionality: %d\n", nDims);
        // read the number of paths
        nStatus = xfGetNumberOfPaths(xGroupId, &nPaths);
        if (nStatus >= 0) {
          fprintf(fp, "Number of paths in group: %d\n", nPaths);
          // read the number of timesteps
          nStatus = xfGetNumberOfTimes(xGroupId, &nTimes);
          if (nStatus >= 0) {
            fprintf(fp, "Number of timesteps in group: %d\n", nTimes);
            // allocate times array
            times = (double *)malloc(nTimes*sizeof(double));
            if (times != NULL) {
              nStatus = xfGetPathTimesArray(xGroupId, nTimes, times);
              if (nStatus >= 0) {
                    // get space for the data location values
                locs = (double *)malloc(nPaths*nDims*sizeof(double));
                if (locs != NULL) {
                  // read null value 
                  nStatus = xfGetPathNullVal(xGroupId, &NullVal);
                  if (nStatus >= 0) {
                    fprintf(fp, "Null value: %lf\n", NullVal);
                    for (i=0; i<nTimes; ++i) {
                      fprintf(fp, "Timestep: %lf\n", times[i]);
                      // read the data for this timestep
                      nStatus = xfReadPathLocationsAtTime(xGroupId, i+1,
                                1, nPaths, locs);
                      if (nStatus >= 0) {
                        // write  the data for this timestep
                        fprintf(fp, "  X        Y");
                        if (nDims == 3) {
                          fprintf(fp, "       Z");
                        }
                        fprintf(fp, "\n");
                        for (j=0; j<nPaths; ++j) {
                          if (locs[j*nDims] == NullVal) {
                            fprintf(fp, "Particle not active yet\n");
                          }
                          else {
                            fprintf(fp, "%lf %lf", locs[j*nDims],
                                    locs[j*nDims+1]);
                            if (nDims == 3) {
                              fprintf(fp, " %lf", locs[j*nDims+2]);
                            }
                            fprintf(fp, "\n");
                          }
                        } // Loop through the points
                      }
                    } // Loop through timesteps
                  }
                  free(locs);
                }
                    // get space for the data location values - 1 particle 
                    // all times
                locs = (double *)malloc(nTimes*nDims*sizeof(double));
                if (locs != NULL) {
                  for (i=0; i<nPaths; ++i) {
                    // read the values for this particle for all timesteps
                    nStatus = xfReadPathLocationsForParticle(xGroupId, i+1, 
                                   1, nTimes, locs);
                    if (nStatus >= 0) {
                        // write  the data for this path
                      fprintf(fp, "Time       X        Y");
                      if (nDims == 3) {
                        fprintf(fp, "        Z");
                      }
                      fprintf(fp, "\n");
                      for (j=0; j<nTimes; ++j) {
                        if (locs[j*nDims] != NullVal) {
                          fprintf(fp, "%lf %lf %lf", times[j], locs[j*nDims],
                                  locs[j*nDims+1]);
                          if (nDims == 3) {
                            fprintf(fp, " %lf", locs[j*nDims+2]);
                          }
                          fprintf(fp, "\n");
                        }
                      } // Loop through the times
                    }
                  } // Loop through the paths
                  free(locs);
                }
                    // get space for the data location values - 2 particle 
                    // all times
                locs = (double *)malloc(nTimes*nDims*2*sizeof(double));
                if (locs != NULL) {
                  PathIndices[0] = 1;
                  PathIndices[1] = nPaths;                
                  nStatus = xfReadPathLocationsForParticles(xGroupId, 2,
                              PathIndices, 1, nTimes, locs);
                  if (nStatus >= 0) {
                      // write  the data for these 2 paths
                    if (nDims == 3) {
                      fprintf(fp, "Timestep       X1        Y1        Z1        Xn        Yn        Zn\n");
                    }
                    else {
                      fprintf(fp, "Timestep       X1        Y1        Xn        Yn\n");
                    }
                    for (j=0; j<nTimes; ++j) {
                      if (nDims == 3) {
                        fprintf(fp, "%lf %lf %lf %lf %lf %lf %lf\n", times[j],
                             locs[j*2*nDims], locs[j*2*nDims+1],
                             locs[j*2*nDims+2], locs[j*2*nDims+3],
                             locs[j*2*nDims+4], locs[j*2*nDims+5]);
                      }
                      else {
                        fprintf(fp, "%lf %lf %lf %lf %lf\n", times[j],
                             locs[j*2*nDims], locs[j*2*nDims+1],
                             locs[j*2*nDims+2], locs[j*2*nDims+3]);
                      }
                    } // Loop through the times
                  }
                  free(locs);
                }
              }
              free(times);
            }
          }
        }
      }
      xfCloseGroup(xGroupId);
    }
    if (nStatus < 0) {
      printf("Error reading geometric paths..\n");
    }
  }
    // free the paths
  if (Paths) {
    free(Paths);
    Paths = NULL;
  }
    // close the files
  fclose(fp);
  xfCloseFile(xFileId);
  return nStatus;
} /* tmReadTestPaths */

/* tmWriteTestPaths */
int tmWriteTestPaths(LPCSTR Filename, int Compression)
{
  int         nPaths = 0;
  double      pLocs[6];
  float       pSpeeds[2], NullVal = (float)-99999.9;
  xid         xFileId = NONE, xPathGroupId = NONE, xSpeedId = NONE,
              xPropGroupId = NONE;
  int         status;

  /* create the file */
  status = xfCreateFile(Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  /* create the group to store the particle paths */
  status = xfCreateGeometricPathGroup(xFileId, "particles",
               "abcdefglasdfjoaieur", Compression,
               &xPathGroupId, -99999.9);
  if (status < 0) {
    return FALSE;
  }

  /* create the data set to store the speed */
  status = xfCreateScalarDatasetExtendable(xPathGroupId, "Vmag", "m/s",
             TS_SECONDS, NullVal, Compression, &xSpeedId);
  if (status < 0) {
    return -1;
  }

  if (xfCreatePropertyGroup(xSpeedId, &xPropGroupId) < 0) {
    xfCloseGroup(xSpeedId);
    return -1;
  }
  xfWritePropertyFloat(xPropGroupId, PROP_NULL_VALUE, 1, &NullVal, -1);
  xfCloseGroup(xPropGroupId);

  // Setup the arrays for the path group at timestep 0 
    // particle location at the first timestep
  nPaths = 1;
  pLocs[0] = 1.0; pLocs[1] = 2.0; pLocs[2] = 3.0;
  
    // store the particles for the first timestep
  status = xfWriteParticleTimestep(xPathGroupId, 3, 0.0, nPaths, pLocs);
  if (status < 0) {
    return FALSE;
  }
    // set up and store the speed at timestep 0
  pSpeeds[0] = (float)(1.1);
  status = xfWriteScalarTimestep(xSpeedId, 0.0, 1, pSpeeds); 
  if (status < 0) {
    return FALSE;
  }

  // Setup the arrays for the path group at timestep 1 
    // particle location at the first timestep
  pLocs[0] = 4.0; pLocs[1] = 5.0; pLocs[2] = 6.0;
  
    // store the particles for the first timestep
  status = xfWriteParticleTimestep(xPathGroupId, 3, 1.0, nPaths, pLocs);
  if (status < 0) {
    return FALSE;
  }
  
    // set up and store the speed at timestep 1
  pSpeeds[0] = (float)(1.2);
  status = xfWriteScalarTimestep(xSpeedId, 1.0, 1, pSpeeds); 
  if (status < 0) {
    return FALSE;
  }

  // Setup the arrays for the path group at timestep 2-add a particle
    // particle location at the first timestep
  nPaths = 2;
  pLocs[0] = 7.0;  pLocs[1] = 8.0;  pLocs[2] = 9.0;
  pLocs[3] = -1.0; pLocs[4] = -2.0; pLocs[5] = -3.0;
  
    // store the particles for the timestep 2
  status = xfWriteParticleTimestep(xPathGroupId, 3, 2.0, nPaths, pLocs);
  if (status < 0) {
    return FALSE;
  }

    // extend the data set for speed
  status = xfExtendScalarDataset(xSpeedId, 2);
  if (status < 0) {
    return FALSE;
  }

    // set up and store the speed at timestep 2
  pSpeeds[0] = (float)1.3;
  pSpeeds[1] = (float)2.1;
  status = xfWriteScalarTimestep(xSpeedId, 2.0, 2, pSpeeds); 
  if (status < 0) {
    return FALSE;
  }

  // Setup the arrays for the path group at timestep 3-inactive particle(static)
    // particle location at the first timestep
  pLocs[0] = 7.0;  pLocs[1] = 8.0;  pLocs[2] = 9.0;
  pLocs[3] = -4.0; pLocs[4] = -5.0; pLocs[5] = -6.0;
  
    // store the particles for timestep 3
  status = xfWriteParticleTimestep(xPathGroupId, 3, 3.0, nPaths, pLocs);
  if (status < 0) {
    return FALSE;
  }

    // set up and store the speed at timestep 3
  pSpeeds[0] = NullVal;
  pSpeeds[1] = (float)2.2;
  status = xfWriteScalarTimestep(xSpeedId, 3.0, 2, pSpeeds); 
  if (status < 0) {
    return FALSE;
  }

  // close the resources
  xfCloseGroup(xSpeedId);
  xfCloseGroup(xPathGroupId);
  xfCloseFile(xFileId);

  return TRUE;
}
TestGeomPaths.cpp tests geometry paths
#include "stdafx.h"
#include <Xmdf.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define GRID_CART2D_GROUP_NAME "Grid Cart2D Group"
#define GRID_CURV2D_GROUP_NAME "Grid Curv2D Group"
#define GRID_CART3D_GROUP_NAME "Grid Cart3D Group"
// ---------------------------------------------------------------------------
// FUNCTION  tgReadGrid
// PURPOSE   Read a grid and write data to a text file
// NOTES     
// ---------------------------------------------------------------------------
int tgReadGrid (xid a_Id, FILE *a_Outfile)
{
  int      nGridType = 0, nExtrudeType = 0, nDims = 0, nCellsI = 0, nCellsJ = 0;
  int      nCellsK = 0, nLayers = 0, nOrientation = 0, nValsI = 0, nValsJ = 0;
  int      nValsK = 0, nExtrudeVals = 0, nCompOrigin = 1, nUDir = 1;
  char     strGridType[256], strExtrudeType[256];
  xmbool    bDefined = XFALSE;
  double   dOrigin[3], dBearing = 0.0, dDip = 0.0, dRoll =0.0;
  double  *dExtrudeVals = NULL, *dCoordI = NULL, *dCoordJ = NULL;
  double  *dCoordK = NULL;
  int      i = 0, error = 1;

  // Grid type
  error = xfGetGridType(a_Id, &nGridType);
  if (error < 0) {
    return error;
  }
  switch (nGridType) {
    case GRID_TYPE_CARTESIAN:
      strcpy(strGridType, "Cartesian");
      break;
    case GRID_TYPE_CURVILINEAR:
      strcpy(strGridType, "Curvilinear");
      break;
    case GRID_TYPE_CARTESIAN_EXTRUDED:
      strcpy(strGridType, "Cartesian extruded");
      break;
    case GRID_TYPE_CURVILINEAR_EXTRUDED:
      strcpy(strGridType, "Curvilinear extruded");
      break;
    default:
      printf("Invalid grid type.");
      return -1;
      break;
  }
  fprintf(a_Outfile, "The grid type is: %s\n", strGridType);

  // Number of dimensions
  error = xfGetNumberOfDimensions(a_Id, &nDims);
  if (error < 0) {
    return error;
  }
  if (nDims == 2) {
    fprintf(a_Outfile, "The grid is two-dimensional\n");
  }
  else if (nDims == 3) {
    fprintf(a_Outfile, "The grid is three-dimensional\n");
  }
  else {
    printf("The grid dimensions are invalid.");
    return -1;
  }

  // Extrusion type if applicable
  if (nGridType == GRID_TYPE_CARTESIAN_EXTRUDED ||
      nGridType == GRID_TYPE_CURVILINEAR_EXTRUDED) {
    error = xfGetExtrusionType(a_Id, &nExtrudeType);
    if (error < 0) {
      return error;
    }
    switch(nExtrudeType) {
      case EXTRUDE_SIGMA:
        strcpy(strExtrudeType, "Sigma stretch");
        break;
      case EXTRUDE_CARTESIAN:
        strcpy(strExtrudeType, "Cartesian");
        break;
      case EXTRUDE_CURV_AT_CORNERS:
        strcpy(strExtrudeType, "Curvilinear at Corners");
        break;
      case EXTRUDE_CURV_AT_CELLS:
        strcpy(strExtrudeType, "Curvilinear at Cells");
        break;
    }
    fprintf(a_Outfile, "The grid is extruding using: %s\n", strExtrudeType);
  }

  // Origin
  error = xfOriginDefined(a_Id, &bDefined);
  if (error < 0) {
    return error;
  }
  if (bDefined) {
    error = xfGetOrigin(a_Id, &dOrigin[0], &dOrigin[1], &dOrigin[2]);
    if (error < 0) {
      return error;
    }
    fprintf(a_Outfile, "The grid origin is %lf %lf %lf\n", dOrigin[0], 
                       dOrigin[1], dOrigin[2]);
  }
  
  // Orientation
  error = xfGetOrientation(a_Id, &nOrientation);
  if (error < 0) {
    return error;
  }
  if (nOrientation == ORIENTATION_RIGHT_HAND) {
    fprintf(a_Outfile, "The grid has a right hand orientation\n");
  }
  else if (nOrientation == ORIENTATION_LEFT_HAND) {
    fprintf(a_Outfile, "The grid has a left hand orientation\n");
  }
  else {
    printf("Invalid grid orientation.");
    return -1;
  }

  // Bearing
  error = xfBearingDefined(a_Id, &bDefined);
  if (error < 0) {
    return error;
  }
  if (bDefined) {
    error = xfGetBearing(a_Id, &dBearing);
    if (error < 0) {
      return error;
    }
    fprintf(a_Outfile, "The grid bearing is %lf\n", dBearing);
  }

  // Dip
  error = xfDipDefined(a_Id, &bDefined);
  if (error < 0) {
    return error;
  }
  if (bDefined) {
    error = xfGetDip(a_Id, &dDip);
    if (error < 0) {
      return error;
    }
    fprintf(a_Outfile, "The grid Dip is %lf\n", dDip);
  }

  if (nDims == 3) {
    // Roll
    error = xfRollDefined(a_Id, &bDefined);
    if (error < 0) {
      return error;
    }
    if (bDefined) {
      error = xfGetRoll(a_Id, &dRoll);
      if (error < 0) {
        return error;
      }
      fprintf(a_Outfile, "The grid Roll is %lf\n", dRoll);
    }
  }
  // Computational origin
  error = xfComputationalOriginDefined(a_Id, &bDefined);
  if (error < 0) {
    return error;
  }
  if (bDefined) {
    error = xfGetComputationalOrigin(a_Id, &nCompOrigin);
    if (error < 0) {
      return error;
    }
    fprintf(a_Outfile, "The grid Computational Origin is %d\n", nCompOrigin);
  }
  else {
    fprintf(a_Outfile, "The grid Computational Origin is not defined\n");
  }


  // U Direction
  error = xfGetUDirectionDefined(a_Id, &bDefined);
  if (error < 0) {
    return error;
  }
  if (bDefined) {
    error = xfGetUDirection(a_Id, &nUDir);
    if (error < 0) {
      return error;
    }
    fprintf(a_Outfile, "The grid U Direction is %d\n", nUDir);
  }
  else {
    fprintf(a_Outfile, "The grid U Direction is not defined\n");
  }


  // number of cells in each direction
  error = xfGetNumberCellsInI(a_Id, &nCellsI);
  if (error >= 0) {
    error = xfGetNumberCellsInJ(a_Id, &nCellsJ);
    if (error >= 0 && nDims == 3) { 
      error = xfGetNumberCellsInK(a_Id, &nCellsK);
    }
  }
  if (error < 0) {
    return error;
  }
  fprintf(a_Outfile, "Number of cells in I %d\n", nCellsI);
  fprintf(a_Outfile, "Number of cells in J %d\n", nCellsJ);
  if (nDims == 3) {
    fprintf(a_Outfile, "Number of cells in K %d\n", nCellsK);
  }

  // Grid coordinates
  switch (nGridType) {
    case GRID_TYPE_CARTESIAN:
    case GRID_TYPE_CARTESIAN_EXTRUDED:
      nValsI = nCellsI;
      nValsJ = nCellsJ;
      if (nDims == 3) {
        nValsK = nCellsK;
      }
      break;
    case GRID_TYPE_CURVILINEAR:
    case GRID_TYPE_CURVILINEAR_EXTRUDED:
      if (nDims == 3) {
        // three dimensions
        nValsI = nValsJ = nValsK = (nCellsI + 1) * (nCellsJ + 1) *(nCellsK + 1);
      }
      else {
        // two dimensions
        nValsI = nValsJ = (nCellsI + 1) * (nCellsJ + 1);
      }
      break;
    default:
      printf("Invalid grid type.");
      return -1;
      break;
  }

  dCoordI = new double[nValsI];
  dCoordJ = new double[nValsJ];
  if (nDims == 3) {
    dCoordK = new double[nValsK];
  }

  error = xfGetGridCoordsI(a_Id, nValsI, dCoordI);
  if (error >= 0) {
    error = xfGetGridCoordsJ(a_Id, nValsJ, dCoordJ);
    if (error >= 0 && nDims == 3) {
      error = xfGetGridCoordsK(a_Id, nValsK, dCoordK);
    }
  }
  if (error < 0) {
    printf("Error reading coordinates.\n");
    return -1;
  }

  fprintf(a_Outfile, "The Coordinates in direction I:\n");
  for (i = 0; i < nValsI; i++) {
    if ((i + 1) % 5 == 0) {
      fprintf(a_Outfile, "\n");
    }
    fprintf(a_Outfile, "%lf ", dCoordI[i]);
  }
  fprintf(a_Outfile, "\n");

  fprintf(a_Outfile, "The Coordinates in direction J:\n");
  for (i = 0; i < nValsJ; i++) {
    if ((i + 1) % 5 == 0) {
      fprintf(a_Outfile, "\n");
    }
    fprintf(a_Outfile, "%lf ", dCoordJ[i]);
  }
  fprintf(a_Outfile, "\n");

  if (nDims == 3) {
    fprintf(a_Outfile, "The Coordinates in direction K:\n");
    for (i = 0; i < nValsK; i++) {
      if ((i + 1) % 5 == 0) {
        fprintf(a_Outfile, "\n");
      }
      fprintf(a_Outfile, "%lf ", dCoordK[i]);
    }
  }
  fprintf(a_Outfile, "\n");

  if (dCoordI) {
    delete dCoordI;
  }
  if (dCoordJ) {
    delete dCoordJ;
  }
  if (dCoordK) {
    delete dCoordK;
  }

  // Extrude data
  if (nGridType == GRID_TYPE_CARTESIAN_EXTRUDED ||
      nGridType == GRID_TYPE_CURVILINEAR_EXTRUDED) {
    error = xfGetExtrudeNumLayers(a_Id, &nLayers);
    if (error < 0) {
      return error;
    }

    switch(nExtrudeType) {
      case EXTRUDE_SIGMA:
        nExtrudeVals = nLayers;
        break;

      case EXTRUDE_CURV_AT_CORNERS:
        nExtrudeVals = (nCellsI + 1) * (nCellsJ + 1) * nLayers;
        break;
      
      case EXTRUDE_CURV_AT_CELLS:
        nExtrudeVals = nCellsI * nCellsJ * nLayers;
        break;
    }
    dExtrudeVals = new double[nExtrudeVals];

    error = xfGetExtrudeValues(a_Id, nExtrudeVals, dExtrudeVals);
    if (error < 0) {
      return error;
    }

    printf("The extrude values are:\n");
    for (i = 0; i < nExtrudeVals; i++) {
      if ((i + 1) % 5 == 0) {
        fprintf(a_Outfile, "\n");
      }
      fprintf(a_Outfile, "%lf ", dExtrudeVals[i]);
    }

    if (dExtrudeVals) {
      delete dExtrudeVals;
    }
  }

  return error;
} // tgReadGrid
//////////////////////////////////////////////////////////////////////////////
// FUNCTION   tgWriteTestGridCart2D
// PURPOSE    Write a file that contains data for a 2D Cartesian Grid
// NOTES      A picture of the grid is in the file (TestGridCart2D.gif)
//            returns TRUE on success and FALSE on failure
//////////////////////////////////////////////////////////////////////////////
int tgWriteTestGridCart2D(LPCSTR Filename, int Compression)
{
  int         nDimensions = 2;
  int         nCellsI = 5, nCellsJ = 5;
  int         nGridType = GRID_TYPE_CARTESIAN;
  int         nCompOrigin = 4, nUDir = -2;
  double      dOriginX = 10.0, dOriginY = 10.0, dOriginZ = 0.0;
  int         nOrientation = ORIENTATION_RIGHT_HAND;
  double      dBearing = 45.0;
  double      PlanesI[5], PlanesJ[5];
  int         i, j, iSpcZone;
  xid         xFileId = NONE, xGridId = NONE, xCoordId = NONE;
  int         status;

  // Fill in the grid plane data with a constant size of 30
  for (i = 1; i <= nCellsI; i++) {
    PlanesI[i - 1] = (double)i*30.0;
  }
  for (j = 1; j <= nCellsJ; j++) {
    PlanesJ[j - 1] = (double)j*30.0;
  }
  
  // create the file
  status = xfCreateFile(Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store the grid
  status = xfCreateGroupForGrid(xFileId, GRID_CART2D_GROUP_NAME, &xGridId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid information to the file
  if (xfSetGridType(xGridId, nGridType) < 0 ||
      xfSetNumberOfDimensions(xGridId, nDimensions) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // set origin and orientation
  if (xfSetOrigin(xGridId, dOriginX, dOriginY, dOriginZ) < 0 ||
      xfSetOrientation(xGridId, nOrientation) < 0 ) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }
 
  // Set bearing
  if (xfSetBearing(xGridId, dBearing) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set computational origin
  if (xfSetComputationalOrigin(xGridId, nCompOrigin) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set u direction
  if (xfSetUDirection(xGridId, nUDir) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid geometry to the file
  // Set the number of cells in each direction
  if (xfSetNumberCellsInI(xGridId, nCellsI) < 0 ||
      xfSetNumberCellsInJ(xGridId, nCellsJ) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set the grid plane locations
  if (xfSetGridCoordsI(xGridId, nCellsI, PlanesI) < 0 ||
      xfSetGridCoordsJ(xGridId, nCellsJ, PlanesJ) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write Coordinate file - for GridCart2D, we will set the coordinate system
  //   to be State Plane NAD27.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
        return -1;
  }

  iSpcZone = 3601; // Oregon North

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_STATE_PLANE_NAD27);
  xfSetHorizUnits(xCoordId, COORD_UNITS_US_FEET);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_US_FEET);

    // write additional information
  xfSetSPCZone(xCoordId, iSpcZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // release memory
  xfCloseGroup(xGridId);
  xfCloseFile(xFileId);
  return TRUE;
} // tgWriteTestGridCart2D
//////////////////////////////////////////////////////////////////////////////
// FUNCTION   tgWriteTestGridCurv2D
// PURPOSE    Write a file that contains data for a 2D Curvilinear Grid
// NOTES      A picture of the grid is TestGridCurv2D.gif
//            returns TRUE on success and FALSE on failure
//////////////////////////////////////////////////////////////////////////////
int tgWriteTestGridCurv2D(LPCSTR Filename, int Compression)
{
  int         nDimensions = 2;
  int         nCompOrigin = 1, nUDir = 1;
  int         nCellsI = 2, nCellsJ = 3;
  int         nCells = nCellsI*nCellsJ;
  int         nCorners = (nCellsI + 1)*(nCellsJ + 1);
  int         nGridType = GRID_TYPE_CURVILINEAR, i;
  double      xVals[16], yVals[16]; // 16 is the number of corners
  double      dCppLat, dCppLon;
  xid         xFileId = NONE, xGridId = NONE, xPropId = NONE,
              xDatasetsId = NONE, xScalarId = NONE, xCoordId = NONE;
  double      dNullValue = -999.0;
  int         nOrientation = ORIENTATION_RIGHT_HAND;
  float       fDsetCellVals[6]; // for cell-centered dataset
  float       fDsetCornerVals[12]; // for corner-centered dataset
  xmbool       bDsetCellActive[6];
  xmbool       bDsetCornerActive[12];
  int         status;

  // There is no cell in the top right corner so we have a NullValue for
  // the top right corner

  // xValues row by row
  xVals[0] = 0.0; xVals[1] = 7.5; xVals[2] = 15.0;
  xVals[3] = 2.5; xVals[4] = 10.0; xVals[5] = 17.5;
  xVals[6] = 3.5; xVals[7] = 11.0; xVals[8] = 18.5;
  xVals[9] = 0.0; xVals[10] = 7.5; xVals[11] = dNullValue;

  // yValues row by row
  yVals[0] = 0.0; yVals[1] = 0.0; yVals[2] = 0.0;
  yVals[3] = 10.0; yVals[4] = 10.0; yVals[5] = 10.0;
  yVals[6] = 20.0; yVals[7] = 20.0; yVals[8] = 20.0;
  yVals[9] = 30.0; yVals[10] = 30.0; yVals[11] = dNullValue;

  // cell centered velocity dataset values
  fDsetCellVals[0] = (float)2.1; fDsetCellVals[1] = (float)2.0;
  fDsetCellVals[2] = (float)1.9; fDsetCellVals[3] = (float)2.3;
  fDsetCellVals[4] = (float)2.5; fDsetCellVals[5] = (float)dNullValue;
  // all are active except the last value
  for (i = 0; i < nCells; i++) {
    bDsetCellActive[i] = XTRUE;
  }
  bDsetCellActive[nCells - 1] = XFALSE;

  // corner centered elevation dataset values
  fDsetCornerVals[0] = (float)1.0; fDsetCornerVals[1] = (float)0.8; 
  fDsetCornerVals[2] = (float)1.2;
  fDsetCornerVals[3] = (float)1.4; fDsetCornerVals[4] = (float)1.8;
  fDsetCornerVals[5] = (float)2.2;
  fDsetCornerVals[6] = (float)1.8; fDsetCornerVals[7] = (float)1.4;
  fDsetCornerVals[8] = (float)2.0;
  fDsetCornerVals[9] = (float)1.0; fDsetCornerVals[10] = (float)1.8;
  fDsetCornerVals[11] = (float)2.2;
  // all are active except the last value
  for (i = 0; i < nCorners; i++) {
    bDsetCornerActive[i] = XTRUE;
  }
  bDsetCornerActive[nCorners - 1] = XFALSE;

  // create the file
  status = xfCreateFile(Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store the grid
  status = xfCreateGroupForGrid(xFileId, GRID_CURV2D_GROUP_NAME, &xGridId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid information to the file
  if (xfSetGridType(xGridId, nGridType) < 0 ||
      xfSetNumberOfDimensions(xGridId, nDimensions) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // set orientation
  if (xfSetOrientation(xGridId, nOrientation) < 0 ) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set computational origin
  if (xfSetComputationalOrigin(xGridId, nCompOrigin) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set u direction
  if (xfSetUDirection(xGridId, nUDir) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid geometry to the file
  // Set the number of cells in each direction
  if (xfSetNumberCellsInI(xGridId, nCellsI) < 0 ||
      xfSetNumberCellsInJ(xGridId, nCellsJ) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set a NullValue.  This is used to identify locations in the grid that are
  // not being used.  In our case no geometry is defined for the top right
  // corner.
  if (xfCreateGridPropertyGroup(xGridId, &xPropId) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  if (xfWritePropertyDouble(xPropId, PROP_NULL_VALUE, 1, &dNullValue, NONE) < 0){
    xfCloseGroup(xPropId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }
  xfCloseGroup(xPropId);

  // Set the grid plane locations
  if (xfSetGridCoordsI(xGridId, nCorners, xVals) < 0 ||
      xfSetGridCoordsJ(xGridId, nCorners, yVals) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Create the datasets group
  if (xfCreateGenericGroup(xGridId, "Datasets", &xDatasetsId) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Create the cell-centered dataset
  if (xfCreateScalarDataset(xDatasetsId, "Velocity Mag",  "ft/s", TS_MINUTES,
                            Compression, &xScalarId) < 0) {
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // specify that the dataset is cell-centered
  if (xfScalarDataLocation(xScalarId, GRID_LOC_CENTER) < 0) {
    xfCloseGroup(xScalarId);
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the data
  if (xfWriteScalarTimestep(xScalarId, 0.0, nCells, fDsetCellVals) < 0 ||
      xfWriteActivityTimestep(xScalarId, nCells, bDsetCellActive) < 0) {
    xfCloseGroup(xScalarId);
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // close the cell-centered dataset
  xfCloseGroup(xScalarId);

  // Create the corner-centered dataset
  if (xfCreateScalarDataset(xDatasetsId, "elevation",  "ft", TS_MINUTES,
                            Compression, &xScalarId) < 0) {
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // specify that the dataset is corner-centered
  if (xfScalarDataLocation(xScalarId, GRID_LOC_CORNER) < 0) {
    xfCloseGroup(xScalarId);
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the data
  if (xfWriteScalarTimestep(xScalarId, 0.0, nCorners, fDsetCornerVals) < 0 ||
      xfWriteActivityTimestep(xScalarId, nCorners, bDsetCornerActive) < 0){
    xfCloseGroup(xScalarId);
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write Coordinate file - for GridCurv2D, we will set the coordinate system
  //   to be CPP, with CPP Latitude and CPP Longitude settings written 
  //   to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xScalarId);
    xfCloseGroup(xDatasetsId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
          return -1;
  }

  dCppLat = 56.0;   // Made-up value
  dCppLon = 23.0;   // Made-up value

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_CPP);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetCPPLat(xCoordId, dCppLat);
  xfSetCPPLon(xCoordId, dCppLon);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // release memory
  xfCloseGroup(xScalarId);
  xfCloseGroup(xDatasetsId);
  xfCloseGroup(xGridId);
  xfCloseFile(xFileId);
  return TRUE;
} // tgWriteTestGridCurv2D
//////////////////////////////////////////////////////////////////////////////
// FUNCTION   tgWriteTestGridCart3D
// PURPOSE    Write a file that contains data for a 2D Cartesian Grid
// NOTES      A picture of the grid is in the file (TestGridCart2D.gif)
//            returns TRUE on success and FALSE on failure
//////////////////////////////////////////////////////////////////////////////
int tgWriteTestGridCart3D(LPCSTR Filename, int Compression)
{
  int         nDimensions = 3;
  int         nCompOrigin = 8, nUDir = -2;
  int         nCellsI = 5, nCellsJ = 5, nCellsK = 3;
  int         nGridType = GRID_TYPE_CARTESIAN;
  double      dOriginX = 10.0, dOriginY = 10.0, dOriginZ = 0.0;
  int         nOrientation = ORIENTATION_RIGHT_HAND;
  double      dBearing = 45.0, dDip = 0.0, dRoll = 0.0;
  double      PlanesI[5], PlanesJ[5], PlanesK[3];
  int         i, j, status, iSpcZone;
  xid         xFileId = NONE, xGridId = NONE;
  xid         xPropId = NONE, xCoordId = NONE;
  int         nCells = nCellsI * nCellsJ * nCellsK;
  int         Active[75];

  // Fill in the grid plane data with a constant size of 30
  for (i = 1; i <= nCellsI; i++) {
    PlanesI[i - 1] = (double)i*30.0;
  }
  for (j = 1; j <= nCellsJ; j++) {
    PlanesJ[j - 1] = (double)j*30.0;
  }
  for (j = 1; j <= nCellsK; j++) {
    PlanesK[j - 1] = (double)j*30.0;
  }

  // fill in the activity array
  // default array to active
  for (i = 0; i < nCells; i++) {
    Active[i] = (int)XTRUE;
  }

  // two cells are inactive (identified by array index)
  // i = 0, j = 0, k = 0  and i = 4, j = 4, k = 0
  Active[0] = (int)XFALSE;
  Active[4*nCellsJ*nCellsK+4*nCellsK] = (int)XFALSE;

  // create the file
  if (xfCreateFile(Filename, &xFileId, XTRUE) < 0) {
    return FALSE;
  }

  // create the group to store the grid
  if (xfCreateGroupForGrid(xFileId, GRID_CART3D_GROUP_NAME, &xGridId) < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid information to the file
  if (xfSetGridType(xGridId, nGridType) < 0 ||
      xfSetNumberOfDimensions(xGridId, nDimensions) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // set origin and orientation
  if (xfSetOrigin(xGridId, dOriginX, dOriginY, dOriginZ) < 0 ||
      xfSetOrientation(xGridId, nOrientation) < 0 ) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }
 
  // Set bearing, dip and roll
  if (xfSetBearing(xGridId, dBearing) < 0 ||
      xfSetDip(xGridId, dDip) < 0 ||
      xfSetRoll(xGridId, dRoll) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set computational origin
  if (xfSetComputationalOrigin(xGridId, nCompOrigin) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set u direction
  if (xfSetUDirection(xGridId, nUDir) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the grid geometry to the file
  // Set the number of cells in each direction
  if (xfSetNumberCellsInI(xGridId, nCellsI) < 0 ||
      xfSetNumberCellsInJ(xGridId, nCellsJ) < 0 ||
      xfSetNumberCellsInK(xGridId, nCellsK) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Set the grid plane locations
  if (xfSetGridCoordsI(xGridId, nCellsI, PlanesI) < 0 ||
      xfSetGridCoordsJ(xGridId, nCellsJ, PlanesJ) < 0 ||
      xfSetGridCoordsK(xGridId, nCellsK, PlanesK) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Write the activity array
  if (xfCreateGridCellPropertyGroup(xGridId, &xPropId) < 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  if (xfWritePropertyInt(xPropId, PROP_ACTIVITY, nCells, Active, 
                         Compression) < 0) {
    xfCloseGroup(xPropId);
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
    return FALSE;
  }
  xfCloseGroup(xPropId);

  // Write Coordinate file - for GridCart3D, we will set the coordinate system
  //   to be State Plane NAD27.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xGridId);
    xfCloseFile(xFileId);
          return -1;
  }

  iSpcZone = 3601; // Oregon North

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_STATE_PLANE_NAD27);
  xfSetHorizUnits(xCoordId, COORD_UNITS_US_FEET);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_US_FEET);

    // write additional information
  xfSetSPCZone(xCoordId, iSpcZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // release memory
  xfCloseGroup(xGridId);
  xfCloseFile(xFileId);
  return TRUE;
} // tgWriteTestGridCart3D
TestGrid.cpp tests grids
#include "stdafx.h"
#include <Xmdf.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define MESH_A_GROUP_NAME "MeshA Group"
#define MESH_B_GROUP_NAME "MeshB Group"
// ---------------------------------------------------------------------------
// FUNCTION  tmReadMesh
// PURPOSE   
// NOTES     
// ---------------------------------------------------------------------------
int tmReadMesh (xid xGroupId, FILE *a_OutFile)
{
  int    nElems = 0, nNodes = 0, nNodesPerElem = 0, nElemType, nNodeId;
  xmbool  bElementsOneType;
  int    status;
  int   *ElemTypes = NULL;
  int    i, j, StrType, UIntType, IntType, DblType, FloatType;
  int   *NodesInElem = NULL;
  double *XNodeLocs, *YNodeLocs, *ZNodeLocs;
  xid     xPropGrpId;

  // Get the number of elements, nodes, and Maximum number of nodes per element
  status = xfGetNumberOfElements(xGroupId, &nElems);
  if (status >= 0) {
    status = xfGetNumberOfNodes(xGroupId, &nNodes);
    if (status >= 0) {
      status = xfGetMaxNodesInElem(xGroupId, &nNodesPerElem);
    }
  }
  if (status < 0) {
    return -1;
  }

  // Do Element information first
  fprintf(a_OutFile, "Number of Elements: %d\n", nElems);

  // Element types
  status = xfAreAllElemsSameType(xGroupId, &bElementsOneType);
  if (status < 0) {
    return -1;
  }

  if (bElementsOneType == (xmbool)XTRUE) {
    status = xfReadElemTypesSingleValue(xGroupId, &nElemType);
    fprintf(a_OutFile, "All elements are type %d\n", nElemType);
  }
  else {
    ElemTypes = new int[nElems];
    if (ElemTypes == NULL) {
      printf("Memory Error");
      return -1;
    }
    status = xfReadElemTypes(xGroupId, nElems, ElemTypes);
    if (status < 0) {
      return -1;
    }
    fprintf(a_OutFile, "Element Types:\n");
    for (i = 0; i < nElems; i++) {
      fprintf(a_OutFile, "Elem %d, Type %d\n", i+1, ElemTypes[i]);
    }
    delete ElemTypes;
    ElemTypes = NULL;
  }

  // Nodes in each element
  NodesInElem  = new int[nElems*nNodesPerElem];
  xfReadElemNodeIds(xGroupId, nElems, nNodesPerElem, NodesInElem);
  for (i = 0; i < nElems; i++) {
    fprintf(a_OutFile, "Elem: %4d - ", i+1);
    for (j = 0; j < nNodesPerElem; j++) {
      nNodeId = NodesInElem[i*nNodesPerElem + j];
      if (nNodeId > 0) { // -1 is for unused array locations
        fprintf(a_OutFile, "%d ", nNodeId);
      }
    }
    fprintf(a_OutFile, "\n");
  }
  delete NodesInElem;
  NodesInElem = NULL;

  // NodeLocations
  XNodeLocs = new double[nNodes];
  YNodeLocs = new double[nNodes];
  ZNodeLocs = new double[nNodes];
  if (XNodeLocs == NULL || YNodeLocs == NULL || ZNodeLocs == NULL) {
    if (XNodeLocs != NULL) {
      delete XNodeLocs;
      XNodeLocs = NULL;
    }
    if (YNodeLocs != NULL) {
      delete YNodeLocs;
      YNodeLocs = NULL;
    }
    if (ZNodeLocs != NULL) {
      delete ZNodeLocs;
      ZNodeLocs = NULL;
    }
    printf("Memory Error!");
    return -1;
  }

  status = xfReadXNodeLocations(xGroupId, nNodes, XNodeLocs);
  if (status >= 0) {
    status = xfReadYNodeLocations(xGroupId, nNodes, YNodeLocs);
    if (status >= 0) {
      status = xfReadZNodeLocations(xGroupId, nNodes, ZNodeLocs);
    }
    else {
      return -1;
    }
  }
  else {
    return -1;
  }

  fprintf(a_OutFile, "Node Locations:\n");
  for (i = 0; i < nNodes; i++) {
    fprintf(a_OutFile, "Node: %d Location: %lf %lf %lf\n", i + 1, XNodeLocs[i],
                        YNodeLocs[i], ZNodeLocs[i]);
  }

  // Open the property group
  status = xfOpenGroup(xGroupId, "PROPERTIES", &xPropGrpId);
  if (status < 0) {
    fprintf(a_OutFile, "\n");
    fprintf(a_OutFile, "Properties Group not found\n");
    fprintf(a_OutFile, "\n");
    return -1; 
  }

  // Get the Property Types
  status = xfGetPropertyType(xPropGrpId, "String", &StrType);
  status = xfGetPropertyType(xPropGrpId, "UInt", &UIntType);
  status = xfGetPropertyType(xPropGrpId, "Int", &IntType);
  status = xfGetPropertyType(xPropGrpId, "Double", &DblType);
  status = xfGetPropertyType(xPropGrpId, "Float", &FloatType);

    // Property Types:
  fprintf(a_OutFile, "\n");
  if (StrType == XF_TYPE_STRING) {
    fprintf(a_OutFile, "String Property Type Read Correctly\n");
  }
  else {
    fprintf(a_OutFile, "Error in Getting String Property Type\n");
  }
  if (UIntType == XF_TYPE_UINT) {
    fprintf(a_OutFile, "Unsigned Integer Property Type Read Correctly\n");
  }
  else {
    fprintf(a_OutFile, "Error in Getting Unsigned Integer Property Type\n");
  }
  if (IntType == XF_TYPE_INT) {
    fprintf(a_OutFile, "Integer Property Type Read Correctly\n");
  }
  else {
    fprintf(a_OutFile, "Error in Getting Integer Property Type\n");
  }
  if (DblType == XF_TYPE_DOUBLE) {
    fprintf(a_OutFile, "Double Property Type Read Correctly\n");
  }
  else {
    fprintf(a_OutFile, "Error in Getting Double Property Type\n");
  }
  if (FloatType == XF_TYPE_FLOAT) {
    fprintf(a_OutFile, "Float Property Type Read Correctly\n");
  }
  else {
    fprintf(a_OutFile, "Error in Getting Float Property Type\n");
  }
  fprintf(a_OutFile, "\n");

  if (XNodeLocs) {
    delete XNodeLocs;
  }
  if (YNodeLocs) {
    delete YNodeLocs;
  }
  if (ZNodeLocs) {
    delete ZNodeLocs;
  }

  return TRUE;
} // tmReadMesh
//////////////////////////////////////////////////////////////////////////////
// FUNCTION   tmWriteTestMeshA
// PURPOSE    Write a file that contains data for an all tri mesh
// NOTES      A picture of the mesh is in the file (TestMeshA.gif)
//            returns TRUE on success and FALSE on failure
//////////////////////////////////////////////////////////////////////////////
int tmWriteTestMeshA(LPCSTR Filename, int Compression)
{
  int         nElements = 3, nNodes = 5;
  xid         xFileId = NONE, xMeshId = NONE;
  xid         xPropGrpId = NONE, xCoordId = NONE;
  double      dNodeLocsX[5], dNodeLocsY[5], dNodeLocsZ[5];
  int         iElementNodes[3][3]; // numelements, max elems per node
  int         status, propint, iEllipse;
  char          *propstring;
  unsigned int  propuint;
  double        propdouble, dMajorR, dMinorR;
  float         propfloat;

  // Setup the arrays for the mesh data
    // nodes
  dNodeLocsX[0] = 0.0; dNodeLocsY[0] = 5.0; dNodeLocsZ[0] = 0.0;
  dNodeLocsX[1] = 5.0; dNodeLocsY[1] = 5.0; dNodeLocsZ[1] = 0.0;
  dNodeLocsX[2] = 0.0; dNodeLocsY[2] = 0.0; dNodeLocsZ[2] = 0.0;
  dNodeLocsX[3] = 5.0; dNodeLocsY[3] = 0.0; dNodeLocsZ[3] = 0.0;
  dNodeLocsX[4] = 7.5; dNodeLocsY[4] = 2.5; dNodeLocsZ[4] = 0.0;
  
    // nodes for each element
    // must be counter-clockwize
  iElementNodes[0][0] = 1; iElementNodes[0][1] = 3; iElementNodes[0][2] = 2;
  iElementNodes[1][0] = 2; iElementNodes[1][1] = 3; iElementNodes[1][2] = 4;
  iElementNodes[2][0] = 5; iElementNodes[2][1] = 2; iElementNodes[2][2] = 4;

  // create the file
  status = xfCreateFile(Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store the mesh
  status = xfCreateGroupForMesh(xFileId, MESH_A_GROUP_NAME, &xMeshId);
  if (status < 0) {
    return FALSE;
  }

  // Element types - all are linear triangles
  status = xfSetAllElemsSameType(xMeshId, EL_TYPE_TRI_LINEAR);
  if (status < 0) {
    return FALSE;
  }

  // node information
  status = xfSetNumberOfNodes(xMeshId, nNodes);
  if (status < 0) {
    return FALSE;
  }

  status = xfWriteXNodeLocations(xMeshId, nNodes, dNodeLocsX, Compression);
  if (status < 0) {
    return FALSE;
  }
  status = xfWriteYNodeLocations(xMeshId, nNodes, dNodeLocsY);
  if (status < 0) {
    return FALSE;
  }
  status = xfWriteZNodeLocations(xMeshId, nNodes, dNodeLocsZ);
  if (status < 0) {
    return FALSE;
  }

  // element information
  status = xfSetNumberOfElements(xMeshId, nElements);
  if (status < 0) {
    return FALSE;
  }
 
  // Write the node array ids for the nodes in each element
  status = xfWriteElemNodeIds(xMeshId, nElements, 3, &iElementNodes[0][0],
                              Compression);
  if (status < 0) {
    return FALSE;
  }

  // Write the property file
  status = xfCreateMeshPropertyGroup(xMeshId, &xPropGrpId);
  if (status < 0) {
    xfCloseGroup(xFileId);
    return FALSE;
  }
  propstring = "Property String";
  propuint = 5;
  propint = -5;
  propdouble = 5.6789012345;
  propfloat = (float)5.6789;

  status = xfWritePropertyString(xPropGrpId, "String", 1, 
                                 strlen(propstring), propstring);
  status = xfWritePropertyUnsignedInt(xPropGrpId, "UInt", 1, &propuint, NONE);
  status = xfWritePropertyInt(xPropGrpId, "Int", 1, &propint, NONE);
  status = xfWritePropertyDouble(xPropGrpId, "Double", 1, &propdouble, NONE);
  status = xfWritePropertyFloat(xPropGrpId, "Float", 1, &propfloat, NONE);

  // Write Coordinate file - for MeshA, we will set the coordinate system to be
  //   Geogrpahic, with Latitude, Longitude, and user-defined ellipsoid settings
  //   written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xPropGrpId);
    xfCloseGroup(xMeshId);
    xfCloseFile(xFileId);
    return -1;
  }

    // set coordinate values
  iEllipse = 32;   // User defined
  dMajorR = 45.0;    // Made up
  dMinorR = 32.0;    // Made up

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC);
  xfSetHorizUnits(xCoordId, COORD_UNITS_US_FEET);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_US_FEET);

    // write additional information
  xfSetEllipse(xCoordId, iEllipse);
  xfSetLat(xCoordId, LATITUDE_NORTH);
  xfSetLon(xCoordId, LONGITUDE_EAST);
  xfSetMajorR(xCoordId, dMajorR);
  xfSetMinorR(xCoordId, dMinorR);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the resources
  xfCloseGroup(xPropGrpId);
  xfCloseGroup(xMeshId);
  xfCloseFile(xFileId);

  return TRUE;
} // tmWriteTestMeshA
//////////////////////////////////////////////////////////////////////////////
// FUNCTION   tmWriteTestMeshB
// PURPOSE    Write a file that contains data for an mixed quad/tri linear mesh
// NOTES      A picture of the mesh is in the file (TestMeshB.gif)
//            returns TRUE on success and FALSE on failure
//////////////////////////////////////////////////////////////////////////////
int tmWriteTestMeshB(LPCSTR Filename, int Compression)
{
  int         nElements = 2, nNodes = 5, nMaxNodePerElem = 4;
  xid         xFileId = NONE, xMeshId = NONE;
  xid         xPropGrpId = NONE, xCoordId = NONE;
  double      dNodeLocsX[5], dNodeLocsY[5], dNodeLocsZ[5];
  int         iElementNodes[2][4]; // numelements, max nodes per elem
  int         iElementTypes[2];
  int         status, propint, iEllipse;
  char          *propstring;
  unsigned int  propuint;
  double        propdouble;
  float         propfloat;

  // Setup the arrays for the mesh data
    // nodes
  dNodeLocsX[0] = 0.0; dNodeLocsY[0] = 5.0; dNodeLocsZ[0] = 0.0;
  dNodeLocsX[1] = 5.0; dNodeLocsY[1] = 5.0; dNodeLocsZ[1] = 0.0;
  dNodeLocsX[2] = 0.0; dNodeLocsY[2] = 0.0; dNodeLocsZ[2] = 0.0;
  dNodeLocsX[3] = 5.0; dNodeLocsY[3] = 0.0; dNodeLocsZ[3] = 0.0;
  dNodeLocsX[4] = 7.5; dNodeLocsY[4] = 2.5; dNodeLocsZ[4] = 0.0;
  
    // nodes for each element
    // must be counter-clockwize
  iElementNodes[0][0] = 1; iElementNodes[0][1] = 3; iElementNodes[0][2] = 4;
  iElementNodes[0][3] = 2;
  iElementNodes[1][0] = 2; iElementNodes[1][1] = 4; iElementNodes[1][2] = 5;
  iElementNodes[1][3] = NONE;

  iElementTypes[0] = EL_TYPE_QUADRILATERAL_LINEAR;
  iElementTypes[1] = EL_TYPE_TRI_LINEAR;

  // create the file
  status = xfCreateFile(Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store the mesh
  status = xfCreateGroupForMesh(xFileId, MESH_B_GROUP_NAME, &xMeshId);
  if (status < 0) {
    return FALSE;
  }

  // node information
  status = xfSetNumberOfNodes(xMeshId, nNodes);
  if (status < 0) {
    return FALSE;
  }

  status = xfWriteXNodeLocations(xMeshId, nNodes, dNodeLocsX, Compression);
  if (status < 0) {
    return FALSE;
  }
  status = xfWriteYNodeLocations(xMeshId, nNodes, dNodeLocsY);
  if (status < 0) {
    return FALSE;
  }
  status = xfWriteZNodeLocations(xMeshId, nNodes, dNodeLocsZ);
  if (status < 0) {
    return FALSE;
  }

  // element information
  status = xfSetNumberOfElements(xMeshId, nElements);
  if (status < 0) {
    return FALSE;
  }

  // Element types
  status = xfWriteElemTypes(xMeshId, nElements, iElementTypes, Compression);
  if (status < 0) {
    return FALSE;
  }
 
  // Write the node array ids for the nodes in each element
  status = xfWriteElemNodeIds(xMeshId, nElements, nMaxNodePerElem,
                              &iElementNodes[0][0], Compression);
  if (status < 0) {
    return FALSE;
  }

  // Write the property file
  status = xfCreateMeshPropertyGroup(xMeshId, &xPropGrpId);
  if (status < 0) {
    xfCloseGroup(xFileId);
    return FALSE;
  }
  propstring = "String Property";
  propuint = 2;
  propint = -2;
  propdouble = 2.3456789012;
  propfloat = (float)2.3456;

  status = xfWritePropertyString(xPropGrpId, "String", 1, 
                                 strlen(propstring), propstring);
  status = xfWritePropertyUnsignedInt(xPropGrpId, "UInt", 1, &propuint, NONE);
  status = xfWritePropertyInt(xPropGrpId, "Int", 1, &propint, NONE);
  status = xfWritePropertyDouble(xPropGrpId, "Double", 1, &propdouble, NONE);
  status = xfWritePropertyFloat(xPropGrpId, "Float", 1, &propfloat, NONE);

  // Write Coordinate file - for MeshB, we will set the coordinate system to be
  //   Geogrpahic, with Latitude, Longitude, and standard ellipsoid settings
  //   written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xPropGrpId);
          xfCloseGroup(xMeshId);
          xfCloseFile(xFileId);
          return -1;
  }

    // set coordinate values
  iEllipse = 21;   // International 1924

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

  xfSetVertDatum(xCoordId, VERT_DATUM_NGVD_88);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetEllipse(xCoordId, iEllipse);
  xfSetLat(xCoordId, LATITUDE_SOUTH);
  xfSetLon(xCoordId, LONGITUDE_WEST);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the resources
  xfCloseGroup(xPropGrpId);
  xfCloseGroup(xMeshId);
  xfCloseFile(xFileId);

  return TRUE;
} // tmWriteTestMeshB
TestMesh.cpp tests meshes
// This file has functions that can be used to test reading and writing of
// timesteps using HDF5.  This code is intended to be used as tests for the
// XMDF library as well as sample code for distribution.

// Untested XMDF functions used for timesteps:
// xfGetDatasetMinsDouble
// xfGetDatasetMaxsDouble
// xfReadScalarValuesTimestepInt
// xfReadVectorValuesAtIndexDouble

// All XMDF functions used for timesteps:
// xfGetDatasetTimes
// xfGetDatasetMins
// xfGetDatasetMaxs
// xfGetDatasetMinsFloat
// xfGetDatasetMaxsFloat
// xfGetDatasetMinsDouble
// xfGetDatasetMaxsDouble
// xfReadActivityTimestep
// xfReadActivityValuesAtIndex
// xfReadScalarValuesTimestep
// xfReadScalarValuesTimestepFloat
// xfReadScalarValuesTimestepFloatPortion
// xfReadScalarValuesTimestepDouble
// xfReadScalarValuesTimestepDoublePortion
// xfReadScalarValuesTimestepInt
// xfReadScalarValuesAtIndex
// xfReadScalarValuesAtIndexFloat
// xfReadScalarValuesAtIndexDouble
// xfReadScalarValuesAtIndices
// xfReadScalarValuesAtIndicesFloat
// xfReadVectorValuesTimestep
// xfReadVectorValuesTimestepFloat
// xfReadVectorValuesTimestepFloatPortion
// xfReadVectorValuesTimestepDouble
// xfReadVectorValuesTimestepDoublePortion


#include "stdafx.h"
#include <Xmdf.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define    DATASETS_LOCATION "Datasets"
#define    SCALAR_A_LOCATION "Scalars/ScalarA"
#define    SCALAR_B_LOCATION "Scalars/ScalarB"
#define    VECTOR2D_A_LOCATION "Vectors/Vector2D_A"
#define    VECTOR2D_B_LOCATION "Vectors/Vector2D_B"

void ttiDatasetArray (double a_dMin, double a_dMax, int a_nCycle, 
                     int a_SeedMultiplier, int a_nValues, float *a_Array);
double ttiRandomNumberInRange (double a_dMin, double a_dMax, int a_nSeed);
int ttiReadScalar (xid a_xScalarId, FILE *a_fp);
int ttiReadVector (xid a_xVectorId, FILE *a_fp);
int ttiTestNumTimes( xid a_DatasetId, int a_Itimestep );

// --------------------------------------------------------------------------
// FUNCTION ttReadDatasets
// PURPOSE  Read a dataset group from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int ttReadDatasets (xid a_xGroupId, FILE *a_fp)
{
  int   nPaths=0, nMaxPathLength=0, nMultiDatasets=0;
  char *Paths = NULL, *IndividualPath = NULL;
  int   nStatus, i, j;
  xid   xScalarId = NONE, xVectorId = NONE, xMultiId = NONE;

  // Look for scalar datasets
  nStatus = xfGetScalarDatasetsInfo(a_xGroupId, &nPaths, &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nPaths*nMaxPathLength*sizeof(char));
    xfGetScalarDatasetPaths(a_xGroupId, nPaths, nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    return -1;
  }
  
  // Output number and paths to scalar datasets
  fprintf(a_fp, "Number of Scalars %d\n", nPaths);
  for (i = 0; i < nPaths; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];
    fprintf(a_fp, "Reading scalar: %s\n", IndividualPath);
   
    nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xScalarId);
    if (nStatus < 0) {
      return -1; 
    }

    nStatus = ttiReadScalar(xScalarId, a_fp);
    xfCloseGroup(xScalarId);
    if (nStatus < 0) {
      printf("%d: ERROR reading scalar dataset.\n", __LINE__);
      return -1;
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  // Look for vector datasets
  nStatus = xfGetVectorDatasetsInfo(a_xGroupId, &nPaths, &nMaxPathLength);
  if (nStatus >= 0 && nPaths > 0) {
    Paths = (char *)malloc(nPaths*nMaxPathLength*sizeof(char));
    xfGetVectorDatasetPaths(a_xGroupId, nPaths, nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    return -1;
  }


  // Output number and paths to scalar datasets
  fprintf(a_fp, "Number of Vectors %d\n", nPaths);
  for (i = 0; i < nPaths; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];
    fprintf(a_fp, "Reading Vector: %s\n", IndividualPath);
   
    nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xVectorId);
    if (nStatus < 0) {
      return -1; 
    }

    nStatus = ttiReadVector(xVectorId, a_fp);
    xfCloseGroup(xVectorId);
    if (nStatus < 0) {
      printf("%d: ERROR reading vector dataset.\n", __LINE__);
      return -1;
    }
  }

  // find multidataset folders
  nStatus = xfGetGroupPathsSizeForMultiDatasets(a_xGroupId, &nMultiDatasets,
                                                      &nMaxPathLength);
  if (nStatus >= 0 && nMultiDatasets > 0) {
    Paths = (char *)malloc(nMultiDatasets*nMaxPathLength*sizeof(char));
    nStatus = xfGetAllGroupPathsForMultiDatasets(a_xGroupId, nMultiDatasets, 
                                                 nMaxPathLength, Paths);
    if (nStatus < 0) {
      return -1;
    }

  // Output number and paths to multidatasets
    fprintf(a_fp, "Number of Multidatasets: %d\n", nMultiDatasets);
    for (i=0; i<nMultiDatasets; i++) {
      IndividualPath = "";
      for (j=0; j<nMaxPathLength-1; j++) {
        IndividualPath = &Paths[i*nMaxPathLength];
      }
      fprintf(a_fp, "Reading multidataset: %s\n", IndividualPath);
      nStatus = xfOpenGroup(a_xGroupId, IndividualPath, &xMultiId);
      if (nStatus < 0) {
            return -1;
      }

      nStatus = ttReadDatasets(xMultiId, a_fp);
      nStatus = xfCloseGroup(xMultiId);
      if (nStatus < 0) {
        printf("%d: ERROR reading multidatasets.\n", __LINE__);
            return -1;
      }
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  return 1;
} // ttReadDatasets
// --------------------------------------------------------------------------
// FUNCTION ttReadActivityScalarAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int ttReadActivityScalarAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xScalarAId = NONE;
  int     nTimesteps;
  xmbool  *bActive;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, SCALAR_A_LOCATION, &xScalarAId);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xScalarAId, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  bActive = new xmbool[nTimesteps];
  status = xfReadActivityValuesAtIndex(xScalarAId, a_Index, 1, nTimesteps,
                                       bActive);

  // output the data
  printf("\nReading activity for scalar A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%d ", bActive[i]);
  }
  printf("\n");

  delete [] bActive;

  return status;
} // ttReadActivityScalarAtIndex
// --------------------------------------------------------------------------
// FUNCTION ttReadScalarAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int ttReadScalarAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xScalarAId = NONE;
  int     nTimesteps;
  float  *fValues;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, SCALAR_A_LOCATION, &xScalarAId);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xScalarAId, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  fValues = new float[nTimesteps];
  status = xfReadScalarValuesAtIndex(xScalarAId, a_Index, 1, nTimesteps,
                                     fValues);

  // output the data
  printf("\nReading scalar A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%f ", fValues[i]);
  }
  printf("\n");

  delete [] fValues;

  return status;
} // ttReadScalarAtIndex
// --------------------------------------------------------------------------
// FUNCTION ttWriteScalarA
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int ttWriteScalarA (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xScalarAId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, iHpgnZone;
  double   dJulianReftime;
  int      nErrors = 0, i = 0;
  char     **Errors = NULL;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group where we will put all the datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarAId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    fValues[0] = (float)dTime;
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
    }

    // write the dataset array values
    status = xfWriteScalarTimestep(xScalarAId, dTime, nValues, fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xScalarAId, nActive, bActivity);
      if (status < 0) {
        printf( "%d: ERROR writing activity timestep: %d\n",
               __LINE__, status );
      }
    }
    if (status < 0) {
      printf( "%d: ERROR writing scalar timestep.\n", __LINE__ );
      xfCloseGroup(xScalarAId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }

    status = ttiTestNumTimes( xScalarAId, iTimestep );
  }

  // Write Coordinate file - for ScalarA, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xScalarAId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // set HPGN Zone for test
  iHpgnZone = 29;      // Utah

    // Write Coordinate Information to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xScalarAId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return FALSE;
} // ttWriteScalarA

// --------------------------------------------------------------------------
// FUNCTION ttWriteScalarB
// PURPOSE  Write scalar Dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int ttWriteScalarB (LPCSTR a_Filename, int a_Compression, int a_Overwrite)
{
  xid      xFileId, xDsetsId, xScalarBId, xCoordId = NONE;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0, dJulianReftime;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status, nErrors = 0, i = 0;
  char     **Errors = NULL;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  if (a_Overwrite) {
      // open the already-existing file
    status = xfOpenFile(a_Filename, &xFileId, XFALSE);
    if (status < 0) {
      return -1;
    }
      // open the group where we have all the datasets 
    status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }
  else {
      // create the file
    status = xfCreateFile(a_Filename, &xFileId, XTRUE);
    if (status < 0) {
      return -1;
    }
      // create the group where we will put all the datasets 
    status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }

  // uncomment next line to test error handling function
  // xfCloseGroup(xDsetsId);

  // Create/Overwrite the scalar B dataset group
  status = xfCreateScalarDataset(xDsetsId, SCALAR_B_LOCATION,
                                 "mg/L", TS_HOURS, a_Compression,
                                 &xScalarBId);
  if (status < 0) {
    // print the error stack
    xfGetNumErrorMessages(&nErrors);
    if (nErrors > 0) {
      Errors = new char*[nErrors];
      for (i = 0; i < nErrors; i++) {
        Errors[i] = new char[XF_MAX_ERROR_MSG_SIZE];
      }
      status = xfGetErrorMessages(nErrors, Errors);
      if (status > 0) {
        for (i = 0; i < nErrors; i++) {
          printf("%s\n", Errors[i]);
        }
      }
      for (i = 0; i < nErrors; i++) {
        delete Errors[i];
      }
      delete Errors;
    }

    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return -1;
  }

  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarBId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarBId);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
  }

  if (!a_Overwrite) {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 0.5 hour timestep
      dTime = (iTimestep + 1) * 0.5;

      fValues[0] = (float)dTime;
      for (i = 1; i < nValues; i++) {
        fValues[i] = float(fValues[i-1]*2.5);
      }

      // write the dataset array values
      status = xfWriteScalarTimestep(xScalarBId, dTime, nValues, fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xScalarBId, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xScalarBId);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }
  else {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 1.5 hour timestep
      dTime = (iTimestep + 1) * 1.5;

      fValues[0] = (float)dTime;
      for (i = 1; i < nValues; i++) {
        fValues[i] = float(fValues[i-1]*1.5);
      }

      // write the dataset array values
      status = xfWriteScalarTimestep(xScalarBId, dTime, nValues, fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xScalarBId, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xScalarBId);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }

  if (!a_Overwrite) {
    // Write Coordinate file
    status = xfCreateCoordinateGroup(xFileId, &xCoordId);
    if (status <= 0) {
      xfCloseGroup(xScalarBId);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
      return -1;
    }

    // For ScalarB, we will set the coordinate system
    // to be UTM, with UTM Zone settings written to the file.
      // Write Coord Info to file
    xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
    xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

    xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
    xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

      // write additional information - we'll use the max value for this test
    xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

    xfCloseGroup(xCoordId);
    xCoordId = 0;
  }

  // close the dataset
  xfCloseGroup(xScalarBId);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // ttWriteScalarB
// --------------------------------------------------------------------------
// FUNCTION ttWriteCoordsToMulti
// PURPOSE  Write coordinate system to a multidataset file
// NOTES
// --------------------------------------------------------------------------
int ttWriteCoordsToMulti (xid a_xFileId)
{
  xid   xCoordId = NONE;
  int   status;

  // Write Coordinate file - for Multidatasets, we will set the coordinate system
  //   to be UTM, with UTM Zone settings written to the file.
  status = xfCreateCoordinateGroup(a_xFileId, &xCoordId);
  if (status <= 0) {
    return -1;
  }

   // Write Coord Info to file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);

  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information - we'll use the max value for this test
  xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  return XTRUE;
} // ttWriteCoordsToMulti
// --------------------------------------------------------------------------
// FUNCTION ttWriteScalarAToMulti
// PURPOSE  Write scalar Dataset to a multidataset
// NOTES    This tests dynamic data sets, and activity
//          This dataset is dynamic concentrations (mg/L) with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
//          reads/writes a reference time in julian days
// --------------------------------------------------------------------------
int ttWriteScalarAToMulti (xid a_GroupId)
{
  xid      xScalarAId;
  int      nValues = 10, nTimes = 3, nActive = 8;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[10]; // nValues
  xmbool    bActivity[10]; // activity
  int      status;
  double   dJulianReftime;
  int      i = 0;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    bActivity[iActive] = XTRUE;
  }
  bActivity[5] = XFALSE;

  // Create the scalar A dataset group
  status = xfCreateScalarDataset(a_GroupId, SCALAR_A_LOCATION,
                                 "mg/L", TS_HOURS, NONE,
                                 &xScalarAId);
  
  // Add in a reftime.  This is a julian day for:
  // noon July 1, 2003
  dJulianReftime = 2452822.0;
  status = xfDatasetReftime(xScalarAId, dJulianReftime);
  if (status < 0) {
    xfCloseGroup(xScalarAId);
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    fValues[0] = (float)dTime;
    for (i = 1; i < nValues; i++) {
      fValues[i] = float(fValues[i-1]*2.5);
    }

    // write the dataset array values
    status = xfWriteScalarTimestep(xScalarAId, dTime, nValues, fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xScalarAId, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xScalarAId);
    }

    status = ttiTestNumTimes( xScalarAId, iTimestep );
  }

  // close the dataset
  xfCloseGroup(xScalarAId);

  return FALSE;
} // ttWriteScalarAToMulti
// --------------------------------------------------------------------------
// FUNCTION ttReadVector2DAIndex
// PURPOSE  Read all timestep values for a particular index
// NOTES    
// --------------------------------------------------------------------------
int ttReadVector2DAIndex (LPCSTR a_Filename, int a_Index)
{
  int     status;
  xid     xFileId = NONE, xDsetsId = NONE, xVector2DA = NONE;
  int     nTimesteps;
  float  *fValues;

  // open the file
  status = xfOpenFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // open the dataset group
  status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status >= 0) {
    status = xfOpenGroup(xDsetsId, VECTOR2D_A_LOCATION, &xVector2DA);
  }
  if (status < 0) {
    return status;
  }

  // Find out the number of timesteps in the file
  status = xfGetDatasetNumTimes(xVector2DA, &nTimesteps);
  if (status < 0) {
    return status;
  }
  if (nTimesteps < 1) {
    return -1;
  }

  // Read the values for the index
  fValues = new float[nTimesteps*2];
  status = xfReadVectorValuesAtIndex(xVector2DA, a_Index, 1, nTimesteps, 2,
                                     fValues);

  // output the data
  printf("\nReading vector 2D A slice at index: %d\n", a_Index);
  for (int i = 0; i < nTimesteps; i++) {
    printf("%f %f \n", fValues[i*2], fValues[i*2 + 1]);
  }
  printf("\n");

  delete [] fValues;

  return status;
} // ttReadVector2DAIndex
// --------------------------------------------------------------------------
// FUNCTION ttWriteVector2D_A
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int ttWriteVector2D_A (LPCSTR a_Filename, int a_Compression)
{
  xid      xFileId, xDsetsId, xVectorA, xCoordId = NONE;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;
  int      iHpgnZone;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  // create the file
  status = xfCreateFile(a_Filename, &xFileId, XTRUE);
  if (status < 0) {
    return FALSE;
  }

  // create the group to store all datasets 
  status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
  if (status < 0) {
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Create the scalar A dataset group
  status = xfCreateVectorDataset(xDsetsId, VECTOR2D_A_LOCATION, "ft/s",
               TS_SECONDS, a_Compression, &xVectorA);
  if (status < 0) {
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    for (i = 0; i < nValues; i++) {
      for (j = 0; j < nComponents; j++) {
        fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
      }
    }
//    // generate values array using random numbers between dMin and dMax
//    ttiDatasetArray(dMin, dMax, iTimestep + 1, nSeedMultiplier,
//                    nValues*nComponents, fValues);

    // write the dataset array values
    status = xfWriteVectorTimestep(xVectorA, dTime, nValues, nComponents,
                                   fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xVectorA, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xVectorA);
      xfCloseGroup(xDsetsId);
      xfCloseFile(xFileId);
    }

    status = ttiTestNumTimes( xVectorA, iTimestep );
  }

  // Write Coordinate file - for Vector2D_A, we will set the coordinate system
  //   to be Geographic HPGN, with HPGN settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xVectorA);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // set HPGN info for test
  iHpgnZone = 29;      // Utah

  xfSetHorizDatum(xCoordId, HORIZ_DATUM_GEOGRAPHIC_HPGN);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information
  xfSetHPGNArea(xCoordId, iHpgnZone);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xVectorA);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return FALSE;
} // ttWriteVector2D_A
// --------------------------------------------------------------------------
// FUNCTION ttWriteVector2D_B
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int ttWriteVector2D_B (LPCSTR a_Filename, int a_Compression, int a_Overwrite)
{
  xid      xFileId, xDsetsId, xVectorB, xCoordId = NONE;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  if (a_Overwrite) {
      //open the already-existing file
    status = xfOpenFile(a_Filename, &xFileId, XFALSE);
    if (status < 0) {
      return -1;
    }
      // open the group where we have all the datasets
    status = xfOpenGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return -1;
    }
  }
  else {
      // create the file
    status = xfCreateFile(a_Filename, &xFileId, XTRUE);
    if (status < 0) {
      return FALSE;
    }
      // create the group to store all datasets 
    status = xfCreateGenericGroup(xFileId, DATASETS_LOCATION, &xDsetsId);
    if (status < 0) {
      xfCloseFile(xFileId);
      return FALSE;
    }
  }

  // Create the Vector B dataset group
  status = xfCreateVectorDataset(xDsetsId, VECTOR2D_B_LOCATION, "ft/s",
               TS_SECONDS, a_Compression, &xVectorB);
  if (status < 0) {
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
    return FALSE;
  }

  if (!a_Overwrite) {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 0.5 hour timestep
      dTime = (iTimestep + 1) * 0.5;

      for (i = 0; i < nValues; i++) {
        for (j = 0; j < nComponents; j++) {
          fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
        }
      }

      // write the dataset array values
      status = xfWriteVectorTimestep(xVectorB, dTime, nValues, nComponents,
                                     fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xVectorB, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xVectorB);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }
  else {
    // Loop through timesteps adding them to the file
    for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
      // We will have an 1.5 hour timestep
      dTime = (iTimestep + 1) * 1.5;

      for (i = 0; i < nValues; i++) {
        for (j = 0; j < nComponents; j++) {
          fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
        }
      }

      // write the dataset array values
      status = xfWriteVectorTimestep(xVectorB, dTime, nValues, nComponents,
                                     fValues);
      if (status >= 0) {
        // write activity array
        xfWriteActivityTimestep(xVectorB, nActive, bActivity);
      }
      if (status < 0) {
        xfCloseGroup(xVectorB);
        xfCloseGroup(xDsetsId);
        xfCloseFile(xFileId);
      }
    }
  }

  // Write Coordinate file - for ScalarB, we will set the coordinate system
  //   to be UTM, with UTM Zone settings written to the file.
  status = xfCreateCoordinateGroup(xFileId, &xCoordId);
  if (status <= 0) {
    xfCloseGroup(xVectorB);
    xfCloseGroup(xDsetsId);
    xfCloseFile(xFileId);
        return -1;
  }

    // write the coordinate data to the file
  xfSetHorizDatum(xCoordId, HORIZ_DATUM_UTM);
  xfSetHorizUnits(xCoordId, COORD_UNITS_METERS);
  xfSetVertDatum(xCoordId, VERT_DATUM_LOCAL);
  xfSetVertUnits(xCoordId, COORD_UNITS_METERS);

    // write additional information - we'll use the max UTM zone for the test
  xfSetUTMZone(xCoordId, UTM_ZONE_MAX);

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  // close the dataset
  xfCloseGroup(xVectorB);
  xfCloseGroup(xDsetsId);
  xfCloseFile(xFileId);

  return 1;
} // ttWriteVector2D_B
// --------------------------------------------------------------------------
// FUNCTION ttWriteVector2DAToMulti
// PURPOSE  Write 2D vector dataset to an HDF5 File
// NOTES    This tests dynamic data sets, and activity
//          Add reftime when it is completed
//          This dataset is dynamic water velocities with output times
//          in minutes.
//          Dataset is for a mesh and so nActive is the number of elements
//          which is not the same as the nValues which would be number of nodes
// --------------------------------------------------------------------------
int ttWriteVector2DAToMulti (xid a_GroupId)
{
  xid      xVectorA;
  int      nTimes = 6, nValues = 100, nComponents = 2, nActive = 75;
  double   dTime = 0.0;
  int      iTimestep, iActive;
  float    fValues[100*2]; // nValues*nComponents
  xmbool    bActivity[75]; // activity
//  double   dMin = 0.5, dMax = 3.5;
//  int      nSeedMultiplier = 138592;
  int      i, j, status;

  // 5th item in data set is always inactive, others active
  for (iActive = 0; iActive < nActive; iActive++) {
    if (iActive % 3 == 0) {
      bActivity[iActive] = XFALSE;
    }
    else {
      bActivity[iActive] = XTRUE;
    }
  }

  // Create the scalar A dataset group
  status = xfCreateVectorDataset(a_GroupId, VECTOR2D_A_LOCATION, "ft/s",
               TS_SECONDS, NONE, &xVectorA);
  if (status < 0) {
    return FALSE;
  }

  // Loop through timesteps adding them to the file
  for (iTimestep = 0; iTimestep < nTimes; iTimestep++) {
    // We will have an 0.5 hour timestep
    dTime = (iTimestep + 1) * 0.5;

    for (i = 0; i < nValues; i++) {
      for (j = 0; j < nComponents; j++) {
        fValues[i*nComponents + j] = (float)(((i)*nComponents + (j+1))*dTime);
      }
    }
//    // generate values array using random numbers between dMin and dMax
//    ttiDatasetArray(dMin, dMax, iTimestep + 1, nSeedMultiplier,
//                    nValues*nComponents, fValues);

    // write the dataset array values
    status = xfWriteVectorTimestep(xVectorA, dTime, nValues, nComponents,
                                   fValues);
    if (status >= 0) {
      // write activity array
      xfWriteActivityTimestep(xVectorA, nActive, bActivity);
    }
    if (status < 0) {
      xfCloseGroup(xVectorA);
    }

    status = ttiTestNumTimes( xVectorA, iTimestep );
  }

  // close the dataset
  xfCloseGroup(xVectorA);

  return FALSE;
} // ttWriteVector2DAToMulti
// --------------------------------------------------------------------------
// FUNCTION ttiRandomNumberInRange
// PURPOSE  generate Psuedo Random numbers.  We use the same seeds every
//          time so we end up with consistent values for testing purposes.
// --------------------------------------------------------------------------
double ttiRandomNumberInRange (double a_dMin, double a_dMax, int a_nSeed)
{
  int nRandom;
  double dValue;

  srand(a_nSeed);
  nRandom = rand();

  dValue = a_dMin + ((double)(nRandom)*(a_dMax - a_dMin))/RAND_MAX;

  return dValue;
} // ttiRandomNumberInRange
// --------------------------------------------------------------------------
// FUNCTION ttDatasetArray
// PURPOSE  Get dataset data to use in a dataset
// NOTES    Generates random numbers between a range to fill in the array
// --------------------------------------------------------------------------
void ttiDatasetArray (double a_dMin, double a_dMax, int a_nCycle, 
                     int a_SeedMultiplier, int a_nValues, float *a_Array)
{
  int       i, nSeedBase;

  for (i = 0; i < a_nValues; i++) {
    nSeedBase = a_nCycle*a_nValues + i;
    a_Array[i] = (float)ttiRandomNumberInRange(a_dMin, a_dMax, 
                                              nSeedBase*a_SeedMultiplier);
  }
} // ttDatasetArray
// --------------------------------------------------------------------------
// FUNCTION ttiReadScalar
// PURPOSE  Read a scalar from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int ttiReadScalar (xid a_xScalarId, FILE *a_fp)
{
  int    nTimes = NONE, nValues = NONE, nActive = NONE;
  int    nStatus = TRUE, iTime, iVal, iActive;
  char   TimeUnits[100], Units[100];
  double *Times = NULL;
  float  *Values = NULL, *Mins = NULL, *Maxs = NULL;
  xmbool  *Active = NULL;
  xmbool  bUseReftime;
  double Reftime;

  // read the time units
  nStatus = xfGetDatasetTimeUnits(a_xScalarId, TimeUnits);
  if (nStatus < 0) {
    return nStatus;
  }
  fprintf(a_fp, "Time units: %s\n", TimeUnits);

  // see if we are using a reftime
  nStatus = xfUseDatasetReftime(a_xScalarId, &bUseReftime);
  if (nStatus < 0) {
    return nStatus;
  }
  if (bUseReftime) {
    nStatus = xfReadDatasetReftime(a_xScalarId, &Reftime);
    if (nStatus < 0) {
      return nStatus;
    }
    fprintf(a_fp, "Reftime: %f\n", Reftime);
  }

  // read the units
  nStatus = xfGetDatasetUnits(a_xScalarId, Units);
  if (nStatus < 0) { 
    return nStatus;
  }
  fprintf(a_fp, "units: %s\n", Units);

  // read in the number of values and number of active values
  nStatus = xfGetDatasetNumVals(a_xScalarId, &nValues);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetNumActive(a_xScalarId, &nActive);
  }
  if (nStatus < 0) {
    return nStatus;
  }

  if (nValues <= 0) {
    printf("No data to read in.");
    return -1;
  }

  // read in the number of times
  nStatus = xfGetDatasetNumTimes(a_xScalarId, &nTimes);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the individual time values
  Times = (double *)malloc(nTimes*sizeof(double));
  if (Times == NULL) {
    printf("Out of memory");
    return -1;
  }
  nStatus = xfGetDatasetTimes(a_xScalarId, nTimes, Times);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the minimum and maximum values
  Mins = (float *)malloc(nTimes*sizeof(float));
  Maxs = (float *)malloc(nTimes*sizeof(float));
  if (Mins == NULL || Maxs == NULL) {
    free(Times);
    printf("Out of memory");
    return -1;
  }

  nStatus = xfGetDatasetMins(a_xScalarId, nTimes, Mins);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetMaxs(a_xScalarId, nTimes, Maxs);
  }
  if (nStatus < 0) {
    free(Times);
    free(Mins);
    free(Maxs);
    return nStatus;
  }

  Values = (float *)malloc(nValues*sizeof(float));
  if (nActive > 0) {
    Active = (xmbool *)malloc(nActive*sizeof(xmbool));
  }

  fprintf(a_fp, "Number Timesteps: %d\n", nTimes);
  fprintf(a_fp, "Number Values: %d\n", nValues);
  fprintf(a_fp, "Number Active: %d\n", nActive);

  // loop through the timesteps, read the values and active values and write
  // them to the text file
  for (iTime = 0; iTime < nTimes; iTime++) {
      // indices should be 1 based
    nStatus = xfReadScalarValuesTimestep(a_xScalarId, iTime + 1,
                                         nValues, Values);
    if (nStatus >= 0 && nActive > 0) {
        // indices should be 1 based
      nStatus = xfReadActivityTimestep(a_xScalarId, iTime + 1, nActive, Active);
    }

    // Write the time, min, max, values and active values to the text output
    // file.
    fprintf(a_fp, "\nTimestep at  %6.3lf\nMin: %6.3lf\nMax: %6.3lf\n", 
                  Times[iTime], Mins[iTime], Maxs[iTime]);

    fprintf(a_fp, "Values:\n");
    // print 5 values per line
    for (iVal = 0; iVal < nValues; iVal++) {
      fprintf(a_fp, "%6.3f ", Values[iVal]);
      if ((iVal + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n");

    fprintf(a_fp, "Activity:\n");
    // print 5 values per line
    for (iActive = 0; iActive < nActive; iActive++) {
      fprintf(a_fp, "%4d ", (int)Active[iActive]);
      if ((iActive + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n\n");
  }

  if (Times) {
    free(Times);
    Times = NULL;
  }
  
  if (Mins) {
    free(Mins);
    Mins = NULL;
  }

  if (Maxs) {
    free(Maxs);
    Maxs = NULL;
  }

  if (Values) {
    free(Values);
    Values = NULL;
  }

  if (Active) {
    free(Active);
    Active = NULL;
  }

  return TRUE;
} // ttiReadScalar
// --------------------------------------------------------------------------
// FUNCTION ttiReadVector
// PURPOSE  Read a vector from an XMDF file and output information to
//          to a text file
// NOTES    
// --------------------------------------------------------------------------
int ttiReadVector (xid a_xVectorId, FILE *a_fp)
{
  int    nTimes = NONE, nValues = NONE, nComponents = NONE, nActive = NONE;
  int    nStatus = TRUE, iTime, iVal, iActive;
  char   TimeUnits[100];
  double *Times = NULL;
  float  *Values = NULL, *Mins = NULL, *Maxs = NULL;
  xmbool  *Active = NULL;
  xmbool  bUseReftime;
  double Reftime;

  // read the time units
  nStatus = xfGetDatasetTimeUnits(a_xVectorId, TimeUnits);
  if (nStatus < 0) {
    return nStatus;
  }
  fprintf(a_fp, "Time units: %s\n", TimeUnits);

  // see if we are using a reftime
  nStatus = xfUseDatasetReftime(a_xVectorId, &bUseReftime);
  if (nStatus < 0) {
    return nStatus;
  }
  if (bUseReftime) {
    nStatus = xfReadDatasetReftime(a_xVectorId, &Reftime);
    if (nStatus < 0) {
      return nStatus;
    }
    fprintf(a_fp, "Reftime: %f", Reftime);
  }

  // read in the number of values and number of active values
  nStatus = xfGetDatasetNumVals(a_xVectorId, &nValues);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetVecNumComponents(a_xVectorId, &nComponents);
    if (nStatus >= 0) {
      nStatus = xfGetDatasetNumActive(a_xVectorId, &nActive);
    }
  }
  if (nStatus < 0) {
    return nStatus;
  }

  if (nValues <= 0) {
    printf("No data to read in.");
    return -1;
  }

  // read in the number of times
  nStatus = xfGetDatasetNumTimes(a_xVectorId, &nTimes);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the individual time values
  Times = (double *)malloc(nTimes*sizeof(double));
  if (Times == NULL) {
    printf("Out of memory");
    return -1;
  }
  nStatus = xfGetDatasetTimes(a_xVectorId, nTimes, Times);
  if (nStatus < 0) {
    return nStatus;
  }

  // Read in the minimum and maximum values
  Mins = (float *)malloc(nTimes*sizeof(float));
  Maxs = (float *)malloc(nTimes*sizeof(float));
  if (Mins == NULL || Maxs == NULL) {
    free(Times);
    printf("Out of memory");
    return -1;
  }

  nStatus = xfGetDatasetMins(a_xVectorId, nTimes, Mins);
  if (nStatus >= 0) {
    nStatus = xfGetDatasetMaxs(a_xVectorId, nTimes, Maxs);
  }
  if (nStatus < 0) {
    free(Times);
    free(Mins);
    free(Maxs);
    return nStatus;
  }

  Values = (float *)malloc(nValues*nComponents*sizeof(float));
  if (nActive > 0) {
    Active = (xmbool *)malloc(nActive*sizeof(xmbool));
  }

  fprintf(a_fp, "Number Timesteps: %d\n", nTimes);
  fprintf(a_fp, "Number Values: %d\n", nValues);
  fprintf(a_fp, "Number Components: %d\n", nComponents);
  fprintf(a_fp, "Number Active: %d\n", nActive);

  // loop through the timesteps, read the values and active values and write
  // them to the text file
  for (iTime = 0; iTime < nTimes; iTime++) {
    nStatus = xfReadVectorValuesTimestep(a_xVectorId, iTime + 1,
                                         nValues, nComponents, Values);
    if (nStatus >= 0 && nActive > 0) {
      nStatus = xfReadActivityTimestep(a_xVectorId, iTime + 1, nActive, Active);
    }

    // Write the time, min, max, values and active values to the text output
    // file.
    fprintf(a_fp, "\nTimestep at  %6.3lf\nMin: %6.3lf\nMax: %6.3lf\n", 
                  Times[iTime], Mins[iTime], Maxs[iTime]);

    fprintf(a_fp, "Values:\n");
    // print a set of vector values per line
    for (iVal = 0; iVal < nValues; iVal++) {
      fprintf(a_fp, "%6.3f %6.3f\n", Values[iVal*nComponents], 
                                     Values[(iVal*nComponents) + 1]);
    }
    fprintf(a_fp, "\n");

    fprintf(a_fp, "Activity:\n");
    // print 5 values per line
    for (iActive = 0; iActive < nActive; iActive++) {
      fprintf(a_fp, "%4d ", (int)Active[iActive]);
      if ((iActive + 1) % 5 == 0) {
        fprintf(a_fp, "\n");
      }
    }
    fprintf(a_fp, "\n\n");
  }

  if (Times) {
    free(Times);
    Times = NULL;
  }
  
  if (Mins) {
    free(Mins);
    Mins = NULL;
  }

  if (Maxs) {
    free(Maxs);
    Maxs = NULL;
  }

  if (Values) {
    free(Values);
    Values = NULL;
  }

  if (Active) {
    free(Active);
    Active = NULL;
  }

  return TRUE;
} // ttiReadVector

// --------------------------------------------------------------------------
// FUNCTION ttiTestNumTimes
// PURPOSE  Change the NumTimes to truncate timesteps
// NOTES    
// --------------------------------------------------------------------------
int ttiTestNumTimes( xid a_DatasetId, int a_Itimestep )
{
  int status = 1;

  // truncate just written timestep and test error conditions
  if (1 == a_Itimestep ||
      3 == a_Itimestep ||
      5 == a_Itimestep)
    {
      int NumTimes;

      // Test setting NumTimes after end of dataset
      status = xfSetDatasetNumTimes( a_DatasetId, a_Itimestep + 2 );
      if (status >= 0)
        printf( "%d: ERROR: xfSetDatasetNumTimes must return ERROR.\n",
                __LINE__ );

      if (1 == a_Itimestep) a_Itimestep = 1;
      if (3 == a_Itimestep) a_Itimestep = 2;
      if (5 == a_Itimestep) a_Itimestep = 3;

      // Write actual NumTimes
      status = xfSetDatasetNumTimes( a_DatasetId, a_Itimestep );
      if (status < 0)
        printf( "%d: ERROR: xfSetDatasetNumTimes must NOT return error.\n",
                __LINE__ );

      // Test setting NumTimes after end step.
      status = xfSetDatasetNumTimes( a_DatasetId, a_Itimestep + 1 );
      if (status >= 0)
        printf( "%d: ERROR: xfSetDatasetNumTimes must return ERROR.\n",
                __LINE__ );

      // Test reading NumTimes
      status = xfGetDatasetNumTimes( a_DatasetId, &NumTimes );
      if (status < 0)
        printf( "%d: ERROR: xfGetDatasetNumTimes must NOT return error.\n",
                __LINE__ );
      if (NumTimes != a_Itimestep)
        printf( "%d: ERROR: xfGetDatasetNumTimes must return CORRECT NumTimes.\n",
                __LINE__ );
    }

  return status;
}
TestTimestep.cpp tests timesteps

// TestXFormat.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <hdf5.h>
#include <Xmdf.h>
#include <Xmdf_private.h>
#include <stdio.h>

#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include "TestTimestep.h"
#include "TestDatasets.h"
#include "TestMesh.h"
#include "TestGrid.h"
#include "TestGeomPaths.h"
#include "TestXmdf.h"

#define NUMTIMES1 5
#define NUMVALUES1 5
#define NUMACTIVE1 3

#define NUMTIMESADD 1

int txiTestCalendar();
int txiTestCoordSystem(xid xGroupId, FILE *a_OutFile);
int txiTestDatasets();
int txiTestFortran();
int txiTestGeometricPaths();
int txiTestGrids();
int txiTestMeshs();
int txiTestOverwriteDsets();
int txiTestTimesteps();
int txiTestVersion();
int txiReadXFormatFile(LPCSTR a_XmdfFile, LPCSTR a_OutFile);
int txiReadXFormatFileT (LPCSTR a_XmdfFile, LPCSTR a_OutFile);


//-----------------------------------------------------------------------------
// FUNCTION  main
// PURPOSE   runs the test cases for XMDF
// NOTES
//-----------------------------------------------------------------------------
int main()
{
  int status = 0;
  ::txiReadXFormatFile("C:\\SMS\\Testcases\\bugs\\adcp_observed\\sms_adcp_observed - pete_comb_vel_vector (2).h5",
                       "C:\\SMS\\Testcases\\bugs\\adcp_observed\\sms_adcp_observed out.txt");

#if 1
  // test the timestep routines
  status = txiTestTimesteps();
  printf("=== Finished testing timesteps ===\n");
  if (status < 0) return status;

  // test the dataset routines
  status = txiTestDatasets();
  printf("=== Finished testing datasets ===\n");
  if (status < 0) return status;

  // test overwriting already-existing datasets
  status = txiTestOverwriteDsets();
  if (status < 0) return status;

  // Test Mesh stuff
  status = txiTestMeshs();
  if (status < 0) return status;

  // Test grid stuff
  status = txiTestGrids();
  if (status < 0) return status;

  // Test writing particle paths


  status = txiTestGeometricPaths();
  if (status < 0) return status;

  // Test reading files that were written by fortan.
  status = txiTestFortran();
  if (status < 0) return status;

  // Test Calendar Conversion Stuff
  status = txiTestCalendar();
  if (status < 0) return status;

  // Test reading the version written to the files
  status = txiTestVersion();
  if (status < 0) return status;
#endif


  printf("Press ENTER to Exit...");
  char pause[1024];

  //scanf("%c", pause);
   
  return 0;
}

//-----------------------------------------------------------------------------
// FUNCTION  txiTestTimesteps
// PURPOSE
// NOTES
//-----------------------------------------------------------------------------
int txiTestTimesteps()
{
  const char *SCALAR_A_FILE_C = "TT_ScalarA_c.h5";
  const char *SCALAR_A_TEXT_C = "TT_ScalarA_c.txt";
  const char *VECTOR2D_A_FILE_C = "TT_Vector2D_A_c.h5";
  const char *VECTOR2D_A_TEXT_C = "TT_Vector2D_A_c.txt";

  const char *MULTIDATASET_FILE_C = "TT_MultiDataSet_c.h5";
  const char *MULTIDATASET_TEXT_C = "TT_MultiDataSet_c.txt";

  int status = 1;
  int compression = NONE;
  xid  MultiFileId=NONE, MultiGroupId=NONE;
  int         NumOpen=0;

  char SdoGuid[37];

  strcpy(SdoGuid, "73289C80-6235-4fdc-9649-49E4F5AEB676");

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
           SdoGuid, XF_OVERWRITE_CLEAR_FILE, &MultiFileId, &MultiGroupId);

  // Write coordinates to multidatasets
  ttWriteCoordsToMulti(MultiFileId);

 // Write scalar A and Vector A to multidatasets.
  ttWriteScalarAToMulti(MultiGroupId);

  ttWriteVector2DAToMulti(MultiGroupId);

  xfCloseGroup(MultiGroupId);
  xfCloseFile(MultiFileId);
  printf("Done writing multiple datasets...\n");


  // scalar datasets
  status = ttWriteScalarA(SCALAR_A_FILE_C, compression);
  if (status < 0) {
    return status;
  }
  
  printf("Done writing scalar datasets...\n");

  // vector datasets
  status = ttWriteVector2D_A(VECTOR2D_A_FILE_C, compression);
  if (status < 0) {
    printf("Error writing dataset vector2D_A.");
    return status;
  }

  printf("Done writing vector datasets...\n");

  printf("Done writing datasets...\n");

  // Read the files back in
  status = txiReadXFormatFileT(SCALAR_A_FILE_C, SCALAR_A_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFileT(VECTOR2D_A_FILE_C, VECTOR2D_A_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFileT(MULTIDATASET_FILE_C, MULTIDATASET_TEXT_C);
  if (status < 0) {
    return status;
  }

  printf("Done reading datasets...\n");

  xfGetNumOpenIdentifiers(H5F_OBJ_ALL, &NumOpen);

  xfpCloseOpenIdentifiers(H5F_OBJ_ALL);

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
     SdoGuid, XF_OVERWRITE_CLEAR_DATASET_GROUP, &MultiFileId, &MultiGroupId);

  ttWriteScalarAToMulti(MultiGroupId);

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
     SdoGuid, XF_OVERWRITE_NONE, &MultiFileId, &MultiGroupId);

  ttWriteVector2DAToMulti(MultiGroupId);


  // Test reading information at index for multiple timesteps
  status = ttReadScalarAIndex(SCALAR_A_FILE_C, 2);
  if (status < 0) {
    return status;
  }
  printf("Done reading scalar data at index.\n");
  
  status = ttReadVector2DAIndex(VECTOR2D_A_FILE_C, 4);
  if (status < 0) {
    return status;
  }
  printf("Done reading vector data at index.\n");

  status = ttReadActivityScalarAIndex(SCALAR_A_FILE_C, 5);
  if (status < 0) {
    return status;
  }

  return status;
} // txiTestTimesteps

//-----------------------------------------------------------------------------
// #defines used in txiTestDatasets
//-----------------------------------------------------------------------------
#define XMDF_VERSION_OUT_C "XMDF_Version_c.txt"

#define SCALAR_A_FILE_C "ScalarA_c.h5"
#define SCALAR_A_TEXT_C "ScalarA_c.txt"
#define SCALAR_A_PIECES_FILE_C "ScalarA_Pieces_c.h5"
#define SCALAR_A_PIECES_TEXT_C "ScalarA_Pieces_c.txt"
#define SCALAR_A_EDITED_FILE_C "ScalarA_edited_c.h5"
#define SCALAR_A_EDITED_TEXT_C "ScalarA_edited_c.txt"
#define VECTOR2D_A_FILE_C "Vector2D_A_c.h5"
#define SCALAR_A_PIECES_ALT_FILE_C "ScalarA_Pieces_alt_c.h5"
#define SCALAR_A_PIECES_ALT_TEXT_C "ScalarA_Pieces_alt_c.txt"
#define SCALAR_A_EDITED_ALT_FILE_C "ScalarA_edited_alt_c.h5"
#define SCALAR_A_EDITED_ALT_TEXT_C "ScalarA_edited_alt_c.txt"
#define VECTOR2D_A_TEXT_C "Vector2D_A_c.txt"
#define VECTOR2D_A_FILE_PIECES_C "Vector2D_A_Pieces_c.h5"

#define SCALAR_A_FILE_F "ScalarA_f.h5"
#define SCALAR_A_TEXT_FC "ScalarA_fc.txt"
#define VECTOR2D_A_FILE_F "Vector2D_A_f.h5"
#define VECTOR2D_A_TEXT_FC "Vector2D_A_fc.txt"

#define MULTIDATASET_FILE_C "MultiDataSet_c.h5"
#define MULTIDATASET_TEXT_C "MultiDataSet_c.txt"

//-----------------------------------------------------------------------------
// FUNCTION  txiTestDatasets
// PURPOSE
// NOTES
//-----------------------------------------------------------------------------
int txiTestDatasets()
{
  int status = 1;
  int compression = NONE;
  xid  MultiFileId=NONE, MultiGroupId=NONE;
  int         NumOpen=0;

  char SdoGuid[37];

  strcpy(SdoGuid, "73289C80-6235-4fdc-9649-49E4F5AEB676");

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
           SdoGuid, XF_OVERWRITE_CLEAR_FILE, &MultiFileId, &MultiGroupId);

  // Write coordinates to multidatasets
  tdWriteCoordsToMulti(MultiFileId);

 // Write scalar A and Vector A to multidatasets.
  tdWriteScalarAToMulti(MultiGroupId);

  tdWriteVector2DAToMulti(MultiGroupId);

  xfCloseGroup(MultiGroupId);
  xfCloseFile(MultiFileId);
  printf("Done writing multiple datasets...\n");


  // scalar datasets
  status = tdWriteScalarA(SCALAR_A_FILE_C, compression);
  if (status < 0) {
    return status;
  }

  status = tdWriteScalarAPieces(SCALAR_A_PIECES_FILE_C, compression);
  if (status < 0) {
    return status;
  }

  status = tdWriteScalarAPiecesAltMinMax(SCALAR_A_PIECES_ALT_FILE_C,
                                         compression);
  if (status < 0) {
    return status;
  }
  
  printf("Done writing scalar datasets...\n");

  // vector datasets
  status = tdWriteVector2D_A(VECTOR2D_A_FILE_C, compression);
  if (status < 0) {
    printf("Error writing dataset vector2D_A.");
    return status;
  }

  status = tdWriteVector2D_A_Pieces(VECTOR2D_A_FILE_PIECES_C, compression);
  if (status < 0) {
    printf("Error writing dataset vector2D_A_Pieces");
   return status;
  }

  printf("Done writing vector datasets...\n");

  printf("Write edited scalar datasets...\n");
  status = tdEditScalarAValues(SCALAR_A_EDITED_FILE_C, compression);
  if (status < 0) {
    return status;
  }

  printf("Done writing datasets...\n");

  // Read the files back in
  status = txiReadXFormatFile(SCALAR_A_FILE_C, SCALAR_A_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFile(VECTOR2D_A_FILE_C, VECTOR2D_A_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFile(MULTIDATASET_FILE_C, MULTIDATASET_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFile(SCALAR_A_EDITED_FILE_C, SCALAR_A_EDITED_TEXT_C);
  if (status < 0) {
    return status;
  }

  printf("Done reading datasets...\n");

  xfGetNumOpenIdentifiers(H5F_OBJ_ALL, &NumOpen);

  xfpCloseOpenIdentifiers(H5F_OBJ_ALL);

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
     SdoGuid, XF_OVERWRITE_CLEAR_DATASET_GROUP, &MultiFileId, &MultiGroupId);

  tdWriteScalarAToMulti(MultiGroupId);

  xfSetupToWriteDatasets(MULTIDATASET_FILE_C, "Multidatasets","", 
     SdoGuid, XF_OVERWRITE_NONE, &MultiFileId, &MultiGroupId);

  tdWriteVector2DAToMulti(MultiGroupId);


  // Test reading information at index for multiple timesteps
  status = tdReadScalarAIndex(SCALAR_A_FILE_C, 2);
  if (status < 0) {
    return status;
  }
  printf("Done reading scalar data at index.\n");
  
  status = tdReadVector2DAIndex(VECTOR2D_A_FILE_C, 4);
  if (status < 0) {
    return status;
  }
  printf("Done reading vector data at index.\n");

  status = tdReadActivityScalarAIndex(SCALAR_A_FILE_C, 5);
  if (status < 0) {
    return status;
  }

    // Test reading information at multiple indices
  const int  nIndices = 3;
  int indices[nIndices];
  indices[0] = 2;
  indices[1] = 3;
  indices[2] = 5;
  status = tdReadScalarAIndices(SCALAR_A_FILE_C, nIndices, indices);



  return status;
} // txiTestDatasets

#define GEOMPATH_A_FILE_C "geompath_a_file_c.h5"
#define GEOMPATH_A_FILE_COUT "geompath_a_file_c_out.txt"

int txiTestGeometricPaths()
{
  int status = 1;
  int compression = NONE;
    /* test writing a geometric path file */
  printf("\n\nWriting geometric path data.\n\n");
 
  status = tmWriteTestPaths(GEOMPATH_A_FILE_C, compression);
  if (status <= 0) {
    printf("Error writing geometric path data A\n");
  }
  printf("Finished writing geometric path data A\n");

    /* test reading a geometric path file */
  status = tmReadTestPaths(GEOMPATH_A_FILE_C, GEOMPATH_A_FILE_COUT);

  return status;
}

//-----------------------------------------------------------------------------
// #defines used in txiTestOverwriteDsets
//-----------------------------------------------------------------------------

#define SCALAR_B_FILE_C "ScalarB_c.h5"
#define SCALAR_B_TEXT_C "ScalarB_c.txt"
#define VECTOR2D_B_FILE_C "Vector2D_B_c.h5"
#define VECTOR2D_B_TEXT_C "Vector2D_B_c.txt"

#define SCALAR_B_FILE_F "ScalarB_f.h5"
#define SCALAR_B_TEXT_FC "ScalarB_fc.txt"
#define VECTOR2D_B_FILE_F "Vector2D_B_f.h5"
#define VECTOR2D_B_TEXT_FC "Vector2D_B_fc.txt"

//-----------------------------------------------------------------------------
// FUNCTION  txiTestOverwriteDsets
// PURPOSE   Check to see if already-written datasets can be overwritten
// NOTES
//-----------------------------------------------------------------------------
int txiTestOverwriteDsets()
{
  int status = 1;
  int compression = NONE;

    // scalar datasets
  status = tdWriteScalarB(SCALAR_B_FILE_C, compression, 0);
  if (status < 0) {
    return status;
  }
    // overwrite scalar datasets
  status = tdWriteScalarB(SCALAR_B_FILE_C, compression, 1);
  if (status < 0) {
    return status;
  }
  
    // vector datasets
  status = tdWriteVector2D_B(VECTOR2D_B_FILE_C, compression, 0);
  if (status < 0) {
    printf("Error writing dataset vector2D_B.");
    return status;
  }
    // overwrite vector datasets
  status = tdWriteVector2D_B(VECTOR2D_B_FILE_C, compression, 1);
  if (status < 0) {
    printf("Error writing dataset vector2D_B.");
    return status;
  }

  // Read the files back in
  status = txiReadXFormatFile(SCALAR_B_FILE_C, SCALAR_B_TEXT_C);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFile(VECTOR2D_B_FILE_C, VECTOR2D_B_TEXT_C);
  if (status < 0) {
    return status;
  }

  return status;
} // txiTestDatasets

//-----------------------------------------------------------------------------
// #defines used in txiTestGrids
//-----------------------------------------------------------------------------

#define GRID_CART2D_A_FILE_C "grid_cart2d_a_file_c.h5"
#define GRID_CURV2D_A_FILE_C "grid_curv2d_a_file_c.h5"
#define GRID_CART3D_A_FILE_C "grid_cart3d_a_file_c.h5"

#define GRID_CART2D_A_OUT_C "grid_cart2d_a_out_c.txt"
#define GRID_CURV2D_A_OUT_C "grid_curv2d_a_out_c.txt"
#define GRID_CART3D_A_OUT_C "grid_cart3d_a_out_c.txt"

#define GRID_CART2D_A_FILE_F "grid_cart2d_a_file_f.h5"
#define GRID_CURV2D_A_FILE_F "grid_curv2d_a_file_f.h5"
#define GRID_CART3D_A_FILE_F "grid_cart3d_a_file_f.h5"

#define GRID_CART2D_A_OUT_FC "grid_cart2d_a_out_fc.txt"
#define GRID_CURV2D_A_OUT_FC "grid_curv2d_a_out_fc.txt"
#define GRID_CART3D_A_OUT_FC "grid_cart3d_a_out_fc.txt"

//-----------------------------------------------------------------------------
// FUNCTION  txiTestGrids
// PURPOSE
// NOTES
//-----------------------------------------------------------------------------
int txiTestGrids()
{
  int status = 1;
  int compression = NONE;

  printf("\n\nWriting grid data.\n\n");
 
  status = tgWriteTestGridCart2D(GRID_CART2D_A_FILE_C, compression);
  if (status < 0) {
    printf("Error writing grid Cartesian 2D A\n");
  }
  printf("Finished writing grid Cartesian 2D A\n");

  status = tgWriteTestGridCurv2D(GRID_CURV2D_A_FILE_C, compression);
  if (status < 0) {
    printf("Error writing grid Curvilinear 2D A\n");
  }
  printf("Finished writing grid Curvilinear 2D A\n");

  status = tgWriteTestGridCart3D(GRID_CART3D_A_FILE_C, compression);
  if (status < 0) {
    printf("Error writing grid Cartesian 3D A\n");
  }
  printf("Finished writing grid Cartesian 3D A\n"); 
  

  // read the files back in
  status = txiReadXFormatFile(GRID_CART2D_A_FILE_C, GRID_CART2D_A_OUT_C);
  if (status < 0) {
    printf("Error reading grid Cartesian 2D A\n");
  }
  printf("Finished reading grid Cartesian 2D A\n");

  status = txiReadXFormatFile(GRID_CURV2D_A_FILE_C, GRID_CURV2D_A_OUT_C);
  if (status < 0) {
    printf("Error reading grid Curvilinear 2D A\n");
  }
  printf("Finished reading grid Curvilinear 2D A\n");

  status = txiReadXFormatFile(GRID_CART3D_A_FILE_C, GRID_CART3D_A_OUT_C);
  if (status < 0) {
    printf("Error reading grid Cartesian 3D A\n");
  }
  printf("Finished reading grid Cartesian 3D A\n"); 
 

  return status;
} // txiTestGrids

//-----------------------------------------------------------------------------
// #defines used in txiTestMeshs
//-----------------------------------------------------------------------------

#define MESH_A_FILE_C  "mesh_a_file_c.h5"
#define MESH_B_FILE_C  "mesh_b_file_c.h5"
#define MESH_A_OUT_C   "mesh_a_file_c.txt"
#define MESH_B_OUT_C   "mesh_b_file_c.txt"

#define MESH_A_FILE_F  "mesh_a_file_f.h5"
#define MESH_B_FILE_F  "mesh_b_file_f.h5"
#define MESH_A_OUT_FC  "mesh_a_file_fc.txt"
#define MESH_B_OUT_FC  "mesh_b_file_fc.txt"

// ---------------------------------------------------------------------------
// FUNCTION  txiTestMeshs
// PURPOSE   
// NOTES     
// ---------------------------------------------------------------------------
int txiTestMeshs ()
{
  int status = 1;
  int compression = NONE;

  status = tmWriteTestMeshA(MESH_A_FILE_C, compression);
  if (status != TRUE) {
    printf("Error writing TestMeshA\n");
    return status;
  }

  status = tmWriteTestMeshB(MESH_B_FILE_C, compression);
  if (status != TRUE) {
    printf("Error writing TestMeshB\n");
    return status;
  }

  printf("Finished writing meshes.\n");

  // read the files back in
  status = txiReadXFormatFile(MESH_A_FILE_C, MESH_A_OUT_C);
  if (status != TRUE) {
    printf("Error reading TestMeshA\n");
    return status;
  }

  // read the files back in
  status = txiReadXFormatFile(MESH_B_FILE_C, MESH_B_OUT_C);
  if (status != TRUE) {
    printf("Error reading TestMeshB\n");
    return status;
  }

  printf("Finished reading meshes.\n");

  return status;
} // txiTestMeshs
// ---------------------------------------------------------------------------
// FUNCTION  txiTestFortran
// PURPOSE   test to see if C code can read file written with fortran.
// NOTES     
// ---------------------------------------------------------------------------
int txiTestFortran ()
{
  xid    xFileId = 0;
  herr_t (*old_func)(void*);
  int     status = 1;
  int     nStatus = 1;
  void    *old_client_data;

    // Check to see if files written with C exist
  H5Eget_auto1(&old_func, &old_client_data);
    // Turn off error handling
  H5Eset_auto1(NULL, NULL);

    // Try opening a file written with C to see if one exists.
  nStatus = xfOpenFile(SCALAR_A_FILE_F, &xFileId, XTRUE);
    // If the file written with FORTRAN doesn't exist, return.
  if (nStatus < 0) {
    xfCloseFile(xFileId);
      // Restore previous error handler
    H5Eset_auto1(old_func, old_client_data);
    return FALSE;
      // If the file written with C does exist, assume all C files exist.
  }
  else {
    xfCloseFile(xFileId);
      // Restore previous error handler
    H5Eset_auto1(old_func, old_client_data);
  }

  // Read the files back in
  status = txiReadXFormatFile(SCALAR_A_FILE_F, SCALAR_A_TEXT_FC);
  if (status < 0) {
    return status;
  }
  status = txiReadXFormatFile(SCALAR_B_FILE_F, SCALAR_B_TEXT_FC);
  if (status < 0) {
    return status;
  }

  status = txiReadXFormatFile(VECTOR2D_A_FILE_F, VECTOR2D_A_TEXT_FC);
  if (status < 0) {
    return status;
  }
  status = txiReadXFormatFile(VECTOR2D_B_FILE_F, VECTOR2D_B_TEXT_FC);
  if (status < 0) {
    return status;
  }

  printf("Done reading fortran datasets...\n");

  status = txiReadXFormatFile(GRID_CART2D_A_FILE_F, GRID_CART2D_A_OUT_FC);
  if (status < 0) {
    printf("Error reading fortran grid Cartesian 2D A\n");
  }
  printf("Finished reading fortran grid Cartesian 2D A\n");

  status = txiReadXFormatFile(GRID_CURV2D_A_FILE_F, GRID_CURV2D_A_OUT_FC);
  if (status < 0) {
    printf("Error reading fortran grid Curvilinear 2D A\n");
  }
  printf("Finished reading fortran grid Curvilinear 2D A\n");

  status = txiReadXFormatFile(GRID_CART3D_A_FILE_F, GRID_CART3D_A_OUT_FC);
  if (status < 0) {
    printf("Error reading grid fortran Cartesian 3D A\n");
  }
  printf("Finished reading fortran grid Cartesian 3D A\n");


  // read the files back in
  status = txiReadXFormatFile(MESH_A_FILE_F, MESH_A_OUT_FC);
  if (status != TRUE) {
    printf("Error reading fortran TestMeshA\n");
    return status;
  }

  // read the files back in
  status = txiReadXFormatFile(MESH_B_FILE_F, MESH_B_OUT_FC);
  if (status != TRUE) {
    printf("Error reading fortran TestMeshB\n");
    return status;
  }

  printf("Finished reading fortran meshes.\n");
  
  return status;
} // txiTestFortran
// --------------------------------------------------------------------------
// FUNCTION txiReadXFormatFile
// PURPOSE  Read a file using XMDF and write information about the data
//          contained in the file to a output file
// --------------------------------------------------------------------------
int txiReadXFormatFile (LPCSTR a_XmdfFile, LPCSTR a_OutFile)
{
  int    nMeshGroups, nMaxPathLength, nGridGroups;
  char  *Paths = NULL, *IndividualPath = NULL;
  int    nStatus, i;
  float  Version;
  xid    xFileId = NONE, xGroupId = NONE;
  FILE  *fp = NULL;
//  int    NameSize;
//  char  *Name = NULL;
//  H5I_type_t IdentifierType;

  // Open the XMDF file
  nStatus = xfOpenFile(a_XmdfFile, &xFileId, XTRUE);
  if (nStatus < 0) {
    return -1;
  }

  // open the status file
  fp = fopen(a_OutFile, "w");
  if (fp == NULL) {
    xfCloseFile(xFileId);
    return -1;
  }

  fprintf(fp, "File %s opened.\n", a_XmdfFile);

  // write the version number to the file
  xfGetLibraryVersionFile(xFileId, &Version);
  fprintf(fp, "XMDF Version: %f\n", Version);

  // Write Coordinate System Informatioin to the .txt file
  nStatus = txiTestCoordSystem(xFileId, fp);
  fprintf(fp, "\n");
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // read all datasets not beneath a mesh, grid, or cross-sections
  nStatus = tdReadDatasets(xFileId, fp);
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  } 

  // Get the number and paths of datasets in the file.
  nStatus = xfGetGroupPathsSizeForMeshes(xFileId, &nMeshGroups,
                                                    &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nMaxPathLength*nMeshGroups*sizeof(char));
    nStatus = xfGetGroupPathsForMeshes(xFileId, nMeshGroups, 
                                         nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // Report the number and paths to individual meshes in the file.
  fprintf(fp, "Number of meshes in file: %d\n", nMeshGroups);
  fprintf(fp, "Paths:\n");
  for (i = 0; i < nMeshGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    fprintf(fp, "  %s\n", IndividualPath);
  }
  fprintf(fp, "\n");

  // Open each mesh group
  for (i = 0; i < nMeshGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    
    fprintf(fp, "Reading mesh in group: %s\n", IndividualPath);
    nStatus = xfOpenGroup(xFileId, IndividualPath, &xGroupId);
    if (nStatus >= 0) {
      // RDJ to delete
//      IdentifierType = H5Iget_type(xGroupId);
//      NameSize = H5Iget_name(xGroupId, NULL, NULL);
//      Name = new char[NameSize + 1];
//      NameSize = H5Iget_name(xGroupId, Name, NULL);
//      if (Name) {
//        delete [] Name;
//      }

      nStatus = tmReadMesh(xGroupId, fp);
    }
    if (nStatus < 0) {
      printf("Error reading mesh..\n");
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  // Grid stuff
  nStatus = xfGetGroupPathsSizeForGrids(xFileId, &nGridGroups,
                                                    &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nMaxPathLength*nGridGroups*sizeof(char));
    nStatus = xfGetGroupPathsForGrids(xFileId, nGridGroups, 
                                         nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // Report the number and paths to individual meshes in the file.
  fprintf(fp, "Number of grids in file: %d\n", nGridGroups);
  fprintf(fp, "Paths:\n");
  for (i = 0; i < nGridGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    fprintf(fp, "  %s\n", IndividualPath);
  }
  fprintf(fp, "\n");

  // Open each grid group
  for (i = 0; i < nGridGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    
    fprintf(fp, "Reading grid in group: %s\n", IndividualPath);
    nStatus = xfOpenGroup(xFileId, IndividualPath, &xGroupId);
    if (nStatus >= 0) {
      nStatus = tgReadGrid(xGroupId, fp);
    }
    if (nStatus < 0) {
      printf("Error reading grid..\n");
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }
  
  // TODO do grid, and cross-section stuff.
   

  // close the files
  xfCloseFile(xFileId);
  fclose(fp);
  
  return TRUE;
} // txiReadXFormatFile

// --------------------------------------------------------------------------
// FUNCTION txiReadXFormatFileT
// PURPOSE  Read a file using XMDF and write information about the data
//          contained in the file to a output file
// --------------------------------------------------------------------------
int txiReadXFormatFileT (LPCSTR a_XmdfFile, LPCSTR a_OutFile)
{
  int    nMeshGroups, nMaxPathLength, nGridGroups;
  char  *Paths = NULL, *IndividualPath = NULL;
  int    nStatus, i;
  float  Version;
  xid    xFileId = NONE, xGroupId = NONE;
  FILE  *fp = NULL;

  // Open the XMDF file
  nStatus = xfOpenFile(a_XmdfFile, &xFileId, XTRUE);
  if (nStatus < 0) {
    return -1;
  }

  // open the status file
  fp = fopen(a_OutFile, "w");
  if (fp == NULL) {
    xfCloseFile(xFileId);
    return -1;
  }

  fprintf(fp, "File %s opened.\n", a_XmdfFile);

  // write the version number to the file
  xfGetLibraryVersionFile(xFileId, &Version);
  fprintf(fp, "XMDF Version: %f\n", Version);

  // Write Coordinate System Informatioin to the .txt file
  nStatus = txiTestCoordSystem(xFileId, fp);
  fprintf(fp, "\n");
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // read all datasets not beneath a mesh, grid, or cross-sections
  nStatus = ttReadDatasets(xFileId, fp);
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  } 

  // Get the number and paths of datasets in the file.
  nStatus = xfGetGroupPathsSizeForMeshes(xFileId, &nMeshGroups,
                                                    &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nMaxPathLength*nMeshGroups*sizeof(char));
    nStatus = xfGetGroupPathsForMeshes(xFileId, nMeshGroups, 
                                         nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // Report the number and paths to individual meshes in the file.
  fprintf(fp, "Number of meshes in file: %d\n", nMeshGroups);
  fprintf(fp, "Paths:\n");
  for (i = 0; i < nMeshGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    fprintf(fp, "  %s\n", IndividualPath);
  }
  fprintf(fp, "\n");

  // Open each mesh group
  for (i = 0; i < nMeshGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    
    fprintf(fp, "Reading mesh in group: %s\n", IndividualPath);
    nStatus = xfOpenGroup(xFileId, IndividualPath, &xGroupId);
    if (nStatus >= 0) {
      nStatus = tmReadMesh(xGroupId, fp);
    }
    if (nStatus < 0) {
      printf("Error reading mesh..\n");
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }

  // Grid stuff
  nStatus = xfGetGroupPathsSizeForGrids(xFileId, &nGridGroups,
                                                    &nMaxPathLength);
  if (nStatus >= 0) {
    Paths = (char *)malloc(nMaxPathLength*nGridGroups*sizeof(char));
    nStatus = xfGetGroupPathsForGrids(xFileId, nGridGroups, 
                                         nMaxPathLength, Paths);
  }
  if (nStatus < 0) {
    xfCloseFile(xFileId);
    return -1;
  }

  // Report the number and paths to individual meshes in the file.
  fprintf(fp, "Number of grids in file: %d\n", nGridGroups);
  fprintf(fp, "Paths:\n");
  for (i = 0; i < nGridGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    fprintf(fp, "  %s\n", IndividualPath);
  }
  fprintf(fp, "\n");

  // Open each grid group
  for (i = 0; i < nGridGroups; i++) {
    IndividualPath = &Paths[i*nMaxPathLength];  
    
    fprintf(fp, "Reading grid in group: %s\n", IndividualPath);
    nStatus = xfOpenGroup(xFileId, IndividualPath, &xGroupId);
    if (nStatus >= 0) {
      nStatus = tgReadGrid(xGroupId, fp);
    }
    if (nStatus < 0) {
      printf("Error reading grid..\n");
    }
  }

  if (Paths) {
    free(Paths);
    Paths = NULL;
  }
  
  // TODO do grid, and cross-section stuff.
   

  // close the files
  xfCloseFile(xFileId);
  fclose(fp);
  
  return TRUE;
} // txiReadXFormatFileT

//-----------------------------------------------------------------------------
// FUNCTION TXI_WRITE_XMDF_VERSION
// PURPOSE  Write the XMDF version number to the screen
// NOTES
//-----------------------------------------------------------------------------
int txiTestVersion ()
{
  float    Version;

  printf("\n");

  xfGetLibraryVersion(&Version);
  printf("The current version of XMDF is: %f\n\n", Version);

  return 1;
}  // txiTestVersion

//-----------------------------------------------------------------------------
// #defines used in txiTestCalendar
//-----------------------------------------------------------------------------

#define CALENDAR_OUT_C "Calendar_c.txt"

//----------------------------------------------------------------------------
// SUBROUTINE txiTestCalendar
// PURPOSE    Check the Calculations of Julian date from calendar date or  
//            vice-versa.
// NOTES      Use #defines: ERA_IS_BCE (BC), and ERA_IS_CE (AD).
//----------------------------------------------------------------------------
int txiTestCalendar ()
{
  FILE    *fp = NULL;
  xmbool   era1, era2, era3, era4;
  int     yr1, mo1, day1, hr1, min1, sec1;
  int     yr2, mo2, day2, hr2, min2, sec2;
  int     yr3, mo3, day3, hr3, min3, sec3;
  int     yr4, mo4, day4, hr4, min4, sec4, calendarworks;
  double  julian1, julian2, julian3, julian4;

  calendarworks = 0;

  // open the status file
  fp = fopen(CALENDAR_OUT_C, "w");
  if (fp == NULL) {
    return FALSE;
  }


  fprintf(fp, "Calendar conversion:\n\n");

  era1 = ERA_IS_BCE;
  yr1 = mo1 = day1 = hr1 = min1 = sec1 = 0;
  julian1 = 2655.5;
  xfJulianToCalendar(&era1, &yr1, &mo1, &day1, &hr1, &min1, &sec1, julian1);

  yr2  = 4706;
  mo2  = 4;
  day2 = 10;
  era2 = ERA_IS_BCE;
  hr2  = min2 = sec2 = 0;
  julian2 = 0.0;
  xfCalendarToJulian(era2, yr2, mo2, day2, hr2, min2, sec2, &julian2);

  era3 = ERA_IS_CE;
  yr3  = 2004;
  mo3  = 6;
  day3 = 3;
  hr3  = 2;
  min3 = 8;
  sec3 = 32;
  julian3 = 0.0;
  xfCalendarToJulian(era3, yr3, mo3, day3, hr3, min3, sec3, &julian3);

  era4 = ERA_IS_BCE;
  yr4 = mo4 = day4 = hr4 = min4 = sec4 = 0;
  julian4 = 2453159.5892592594;
  xfJulianToCalendar(&era4, &yr4, &mo4, &day4, &hr4, &min4, &sec4, julian4);

fprintf(fp, "Dates #1 & #2  were calculated with the same date:\n\n");
fprintf(fp, "%d / %d / %d / %d / %d / %d / %d --- Julian = %f\n\n",
        era1, yr1, mo1, day1, hr1, min1, sec1, julian1);
fprintf(fp, "%d / %d / %d / %d / %d / %d / %d --- Julian = %f\n\n\n",
        era2, yr2, mo2, day2, hr2, min2, sec2, julian2);
fprintf(fp, "Dates #3 & #4  were calculated with the same date:\n\n");
fprintf(fp, "%d / %d / %d / %d / %d / %d / %d --- Julian = %f\n\n",
        era3, yr3, mo3, day3, hr3, min3, sec3, julian3);
fprintf(fp, "%d / %d / %d / %d / %d / %d / %d --- Julian = %f\n\n",
        era4, yr4, mo4, day4, hr4, min4, sec4, julian4);



  if (era1==era2 && era3==era4) {
    if (yr1==yr2 && yr3==yr4) {
      if (mo1==mo2 && mo3==mo4) {
        if (day1==day2 && day3==day4) {
          if (hr1==hr2 && hr3==hr4) {
            if (min1==min2 && min3==min4) {
              if (EQ_EPS(julian1, julian2, DBL_EPS) && 
                  EQ_EPS(julian3, julian4, DBL_EPS)) {
                                  printf("\n");
                                  printf("Calendar conversion works correctly.\n");
                                        calendarworks = 1;
    
              }
            }
          }
        }
      }
    }
  }

  if (calendarworks != 1) {
    printf("\n");
    printf("Calendar Conversion sdfse DOES NOT Work Correctly.\n");
          return -1;
  }
  else {
    return 1;
  }

}
//----------------------------------------------------------------------------
// SUBROUTINE txiTestCoordSystem
// PURPOSE    Reads a file's Coordinate Group and prints coordinate data out
//            to each text file.
// NOTES
//----------------------------------------------------------------------------
int txiTestCoordSystem (xid xFileId, FILE *a_OutFile)
{
  int     iHorizDatum, iHorizUnits, iVertDatum, iVertUnits;
  int     iLat, iLon, iUtmZone, iSpcZone, iHpgnArea, iEllipse;
  int     bHorizDatum, nStatus;
  double  dCppLat, dCppLon, dMajorR, dMinorR;
  xid     xCoordId = NONE;
  char    strHorizUnits[256], strVertDatum[256], strVertUnits[256];

  // Coordinate stuff
  // Read Coordinate Info
    // Open the Coordinate group
  nStatus = xfOpenCoordinateGroup(xFileId, &xCoordId);
  if (nStatus <= 0) {
    fprintf(a_OutFile, "\n");
    fprintf(a_OutFile, "Coordinate Group not found\n");
    fprintf(a_OutFile, "\n");
    return -1;
  }

  fprintf(a_OutFile, "\n");
  fprintf(a_OutFile, "Coordinate System:\n");

  bHorizDatum = xfGetHorizDatum(xCoordId, &iHorizDatum);
  xfGetHorizUnits(xCoordId, &iHorizUnits);
  xfGetVertDatum(xCoordId, &iVertDatum);
  xfGetVertUnits(xCoordId, &iVertUnits);
    // set horizontal units
  if (iHorizUnits == 0) {
    strcpy(strHorizUnits, "Horizontal units = US Survey Feet (=0)");
  }
  else if (iHorizUnits == 1) {
    strcpy(strHorizUnits, "Horizontal units = International Feet (=1)");
  }
  else if (iHorizUnits == 2) {
    strcpy(strHorizUnits, "Horizontal units = Meters (=2)");
  }
  else {
    strcpy(strHorizUnits, "ERROR in reading Horizontal units");
  }
    // set vertical datum
  if (iVertDatum == 0) {
    strcpy(strVertDatum, "Vertical datum = Local (=0)");
  }
  else if (iVertDatum == 1) {
    strcpy(strVertDatum, "Vertical datum = NGVD 29 (=1)");
  }
  else if (iVertDatum == 2) {
    strcpy(strVertDatum, "Vertical datum = NGVD 88 (=2)");
  }
  else {
    strcpy(strVertDatum, "ERROR in reading the Vertical datum\n");
  }
    // set vertocal units
  if (iVertUnits == 0) {
    strcpy(strVertUnits, "Vertical units = US Survey Feet (=0)");
  }
  else if (iVertUnits == 1) {
    strcpy(strVertUnits, "Vertical units = International Feet (=1)");
  }
  else if (iVertUnits == 2) {
    strcpy(strVertUnits, "Vertical units = Meters (=2)");
  }
  else {
    strcpy(strVertUnits, "ERROR in reading the Vertical units");
  }

  if (bHorizDatum >= 0) {
    switch (iHorizDatum) {
      case HORIZ_DATUM_GEOGRAPHIC:
        xfGetEllipse(xCoordId, &iEllipse);
        xfGetLat(xCoordId, &iLat);
        xfGetLon(xCoordId, &iLon);
          // Write Horizontal and Vertical Info
        fprintf(a_OutFile, "Horizontal datum = Geographic\n");
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n", strVertUnits);
          // Write Latitude data
        if (iLat == 0) {
          fprintf(a_OutFile, "  Latitude = North (=%d)\n", iLat);
        }
        else if (iLat == 1) {
          fprintf(a_OutFile, "  Latitude = South (=%d)\n", iLat);
        }
        else {
          fprintf(a_OutFile, "  LATITUDE INFO INCORRECT\n");
        }
          // Longitude
        if (iLon == 0) {
          fprintf(a_OutFile, "  Longitude = East (=%d)\n", iLon);
        }
        else if (iLon == 1) {
          fprintf(a_OutFile, "  Longitude = West (=%d)\n", iLon);
        }
        else {
          fprintf(a_OutFile, "  LONGITUDE INFO INCORRECT\n");
        }
          // Ellipse Information
          // User-defined Ellipse (==32)
        if (iEllipse == 32) {
          fprintf(a_OutFile, "Ellipse = User-defined:\n");
          xfGetMajorR(xCoordId, &dMajorR);
          xfGetMinorR(xCoordId, &dMinorR);
          fprintf(a_OutFile, "  MajorR = %lf\n", dMajorR);
          fprintf(a_OutFile, "  MinorR = %lf\n\n", dMinorR);
        }
        else {
          fprintf(a_OutFile, "Ellipse = %d\n\n", iEllipse);
        }
        break;
      case HORIZ_DATUM_UTM:
      case HORIZ_DATUM_UTM_NAD27:
      case HORIZ_DATUM_UTM_NAD83:
        xfGetUTMZone(xCoordId, &iUtmZone);
          // output info to text file
        if (iHorizDatum == HORIZ_DATUM_UTM) {
          fprintf(a_OutFile, "Horizontal datum = UTM\n");
        }
        else if (iHorizDatum == HORIZ_DATUM_UTM_NAD27) {
          fprintf(a_OutFile, "Horizontal datum = UTM NAD27 (US)\n");
        }
        else {
          fprintf(a_OutFile, "Horizontal datum = UTM NAD83 (US)\n");
        }
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n", strVertUnits);
        fprintf(a_OutFile, "UTM Zone = %d\n\n", iUtmZone);
        break;
      case HORIZ_DATUM_STATE_PLANE_NAD27:
      case HORIZ_DATUM_STATE_PLANE_NAD83:
        xfGetSPCZone(xCoordId, &iSpcZone);
          // output info to text file
        if (iHorizDatum == HORIZ_DATUM_STATE_PLANE_NAD27) {
          fprintf(a_OutFile, "Horizontal datum = State Plane NAD27 (US)\n");
        }
        else {
          fprintf(a_OutFile, "Horizontal datum = State Plane NAD83 (US)\n");
        }
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n", strVertUnits);
        fprintf(a_OutFile, "SPC Zone = %d\n\n", iSpcZone);
        break;
      case HORIZ_DATUM_UTM_HPGN:
      case HORIZ_DATUM_STATE_PLANE_HPGN:
      case HORIZ_DATUM_GEOGRAPHIC_HPGN:
        xfGetHPGNArea(xCoordId, &iHpgnArea);
        if (iHorizDatum == HORIZ_DATUM_UTM_HPGN) {
          fprintf(a_OutFile, "Horizontal datum = UTM HPGN (US)\n");
        }
        else if (iHorizDatum == HORIZ_DATUM_STATE_PLANE_HPGN) {
          fprintf(a_OutFile, "Horizontal datum = State Plane HPGN (US)\n");
        }
        else {
          fprintf(a_OutFile, "Horizontal datum = Geographic HPGN (US)\n");
        }
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n", strVertUnits);
        fprintf(a_OutFile, "HPGN Area = %d\n\n", iHpgnArea);
        break;
      case HORIZ_DATUM_CPP:
        xfGetCPPLat(xCoordId, &dCppLat);
        xfGetCPPLon(xCoordId, &dCppLon);
        fprintf(a_OutFile, "Horizontal datum = CPP (Carte Parallelo-Grammatique Projection)\n");
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n", strVertUnits);
        fprintf(a_OutFile, "CPP Latitude = %lf\n", dCppLat);
        fprintf(a_OutFile, "CPP Longitude = %lf\n\n", dCppLon);
        break;
      default:
        // do other systems
        if (iHorizDatum == HORIZ_DATUM_LOCAL) {
          fprintf(a_OutFile, "Horizontal datum = Local\n");
        }
        else if (iHorizDatum == HORIZ_DATUM_GEOGRAPHIC_NAD27) {
          fprintf(a_OutFile, "Horizontal datum = Geographic NAD27 (US)\n");
        }
        else if (iHorizDatum == HORIZ_DATUM_GEOGRAPHIC_NAD83) {
          fprintf(a_OutFile, "Horizontal datum = Geographic NAD83 (US)\n");
        }
        else {
          fprintf(a_OutFile, "ERROR: The Horizontal Datum in the .h5 file is not recognizable\n");
          return -1;
        }
        fprintf(a_OutFile, "Horizontal units = %s\n", strHorizUnits);
        fprintf(a_OutFile, "Vertical datum = %s\n", strVertDatum);
        fprintf(a_OutFile, "Vertical units = %s\n\n", strVertUnits);
        break;
    }
  }
  else {
    fprintf(a_OutFile, "Coordinate information in HDF5 file is incomplete.");
    fprintf(a_OutFile, "\n");
  }

  xfCloseGroup(xCoordId);
  xCoordId = 0;

  return TRUE;
} // txiTestCoordSystem

Generated on Wed Apr 6 08:11:20 2011 for XMDF by  doxygen 1.5.6