<p><b>cahrens@lanl.gov</b> 2010-09-21 19:01:10 -0600 (Tue, 21 Sep 2010)</p><p>New version of translator that creates either sphere or latlon view and either single or multilayer view.  When compiled, it is called mpasnc2vtu.  Run with no arguments to see the usage information.  Writes out data in XML and binary.<br>
</p><hr noshade><pre><font color="gray">Modified: branches/ocean_projects/graphics/paraview/translator/Makefile
===================================================================
--- branches/ocean_projects/graphics/paraview/translator/Makefile        2010-09-17 17:59:55 UTC (rev 506)
+++ branches/ocean_projects/graphics/paraview/translator/Makefile        2010-09-22 01:01:10 UTC (rev 507)
@@ -10,8 +10,8 @@
 #        -lstdc++ \
 #        -L/opt/Intel/cce/10.0.023/lib/ -lirc
 
-transdual: nc2vtk_dual.cpp
-        $(CC) $(INCLUDES) -o $@ $&lt;  $(LIBS)
+mpasnc2vtu: mpasnc2vtu.cpp EncodeBase64.o
+        $(CC) $(INCLUDES) -o $@ $&lt;  EncodeBase64.o $(LIBS)
 
 .cpp.o:
         $(CC) $(MYDEBUG) $(INCLUDES) -c $&lt;
@@ -22,5 +22,8 @@
 transdualbin: nc2vtu_dualbin.cpp  EncodeBase64.o
         $(CC) $(INCLUDES) -o $@ $&lt;  EncodeBase64.o $(LIBS)
 
+transdual: nc2vtu_dual.cpp  
+        $(CC) $(INCLUDES) -o $@ $&lt;  $(LIBS)
+
 clean:
-        rm transdual transdualbin *.o
+        rm transdual transdualbin mpasnc2vtu *.o

Added: branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp
===================================================================
--- branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp                                (rev 0)
+++ branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp        2010-09-22 01:01:10 UTC (rev 507)
@@ -0,0 +1,1645 @@
+////////////////////////////////////////////////////////////////////////////////
+// mpasnc2vtu.cpp
+//
+// This program translates a MPAS netCDF data file to  a dual grid in ParaView
+// .vtu format.  Can do either sphere view or lat/lon view.  Can show single 
+// or multi-layers.  Can translate to xml with either ascii or binary data.
+//
+// Assumes little-endian platform.
+// Assume all variables are of interest.
+// Assume variable data type is double.
+// Assume variable dims are (Time, nCells|nVertices, nVertLevels|nVertLevelsP1)
+// Assume no more than 100 vars each for cell and point data
+// Does not deal with edge data.
+// Only vis up to nVertLevels, not nVertLevelsP1.
+// Doubles converted to be valid follow these rules:
+//        if a NaN, then become -DBL_MAX.
+//        if positive infinity, then become DBL_MAX
+//        if negative infinity, then become -DBL_MAX
+//
+// Version 1.5
+// Christine Ahrens
+// 9/21/2010
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include &lt;iostream&gt;
+#include &lt;fstream&gt;
+#include &lt;sstream&gt;
+#include &quot;stdlib.h&quot;
+#include &quot;vtkCellType.h&quot;
+#include &quot;netcdfcpp.h&quot;
+#include &lt;string&gt;
+#include &lt;cmath&gt;
+//#include &lt;math&gt;
+#include &lt;cfloat&gt;
+#include &quot;EncodeBase64.h&quot;
+
+using namespace std;
+
+struct params {
+    bool projectLatLon;
+    bool writeBinary;
+    bool singleLayer;
+    bool isAtmosphere;
+    bool includeTopography;
+    bool doBugFix;
+        int outputVertLevel;
+    char* inputFileName;
+    char* outputFileName;
+        double layerThickness;
+    bool isZeroCentered;
+    double centerLon;
+    double centerRad;
+    int startTimeStep;
+    int finishTimeStep;
+};
+
+// points and cells refer to DUAL points and cells
+struct geometry {
+    int nVertLevels;
+    int maxNVertLevels;
+    int Time;
+    int numCells;
+    int numPoints;
+    int cellOffset;
+    int pointOffset;
+    int pointsPerCell;
+    int currentExtraPoint;  // current extra point
+    int currentExtraCell;   // current extra  cell
+    double* pointX;      // x coord of point
+    double* pointY;      // y coord of point
+    double* pointZ;      // z coord of point
+    int modNumPoints;
+    int modNumCells;
+    int* origConnections;   // original connections
+    int* modConnections;    // modified connections
+    int* cellMap;           // maps from added cell to original cell #
+    int* pointMap;          // maps from added point to original point # 
+    int* maxLevelPoint;      // 
+    int maxCells;           // max cells
+    int maxPoints;          // max points
+    int verticalIndex;      // for singleLayer, which vertical level
+};
+
+#define MAX_VARS 100
+struct vars {
+        NcVar* cellVars[MAX_VARS];
+        NcVar* pointVars[MAX_VARS];
+        int numCellVars;
+        int numPointVars;
+};
+
+#define DEFAULT_LAYER_THICKNESS 10
+double PI = 3.141592;
+#define BUFF_SIZE 2048
+
+#define CHECK_MALLOC(ptr) \
+        if (ptr == NULL) { \
+                cerr &lt;&lt; &quot;malloc failed!</font>
<font color="blue">&quot;; \
+                exit(1); \
+        } 
+
+
+
+// append inFile to outFile 
+int AppendFile(string *inFile, string *outFile)
+{
+   char buff[BUFF_SIZE];
+   int readBytes = 1;
+
+   ifstream inFileStream(inFile-&gt;c_str(), ios::in|ios::binary);
+   if(!inFileStream)
+   {
+     return -1;
+   }
+
+   ofstream outFileStream(outFile-&gt;c_str(), ios::out|ios::app|ios::binary);
+   if(!outFileStream)
+   {
+     return -1;
+   }
+
+   while(readBytes != 0)
+   {
+     inFileStream.read((char*)buff, BUFF_SIZE);
+     readBytes = inFileStream.gcount();
+     outFileStream.write((char*)buff, readBytes);
+   }
+   return 0;
+}
+
+int IsInf_f(float x){
+        if (isinf(x)) {
+                return (x &lt; 0.0 ? -1 : 1);
+        } else return 0;
+}
+
+unsigned int PadSize(unsigned int binarySize) {
+    switch ((binarySize*4)%3) {
+        case 1:
+            binarySize = binarySize + 2;
+            break;
+        case 2:
+            binarySize++;
+            break;
+        case 0:
+            break;
+    }
+    return binarySize;
+}
+
+float ConvertDouble2ValidFloat(double inputData) {
+
+        // check for NaN
+        if (inputData != inputData) {
+                //cerr &lt;&lt; &quot;found NaN!&quot; &lt;&lt; endl;
+                return -FLT_MAX;
+        }
+
+        // check for infinity
+        int retval = IsInf_f((float)inputData);
+        if (retval &lt; 0) {
+                return -FLT_MAX;
+        } else if (retval &gt; 0) {
+                return FLT_MAX;
+        }
+
+        // check number too small for float
+        if (abs(inputData) &lt; 1e-126) return 0.0;
+
+        if ((float)inputData == 0) return 0.0;
+
+        if ((abs(inputData) &gt; 0) &amp;&amp; (abs(inputData) &lt; FLT_MIN)) {
+                if (inputData &lt; 0) return -FLT_MIN; else return FLT_MIN;
+        }
+
+        if (abs(inputData) &gt; FLT_MAX) {
+                if (inputData &lt; 0) return -FLT_MAX; else return FLT_MAX;
+        }
+
+        return (float)inputData;
+}
+
+double ConvertDouble2ValidDouble(double inputData) {
+
+        // check for NaN
+        if (isnan(inputData)) {
+                cerr &lt;&lt; &quot;found NaN!&quot; &lt;&lt; endl;
+                return -DBL_MAX;
+        }
+
+        // check for infinity
+        int retval = isinf(inputData);
+        if (retval &lt; 0) {
+                return -DBL_MAX;
+        } else if (retval &gt; 0) {
+                return DBL_MAX;
+        }
+
+        return inputData;
+}
+
+int CartesianToSpherical(double x, double y, double z, double* rho,
+        double* phi, double* theta)
+{
+    double trho, ttheta, tphi;
+
+    trho = sqrt( (x*x) + (y*y) + (z*z));
+    ttheta = atan2(y, x);
+    tphi = acos(z/(trho));
+    if (isnan(trho) || isnan(ttheta) || isnan(tphi)) {
+        cerr &lt;&lt; &quot;CartesianToSpherical on x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot; z: &quot; &lt;&lt; z &lt;&lt; &quot; produced nan!&quot; &lt;&lt; endl;
+        return -1;
+    }
+    *rho = trho;
+    *theta = ttheta;
+    *phi = tphi;
+    return 0;
+}
+
+int SphericalToCartesian(double rho, double phi, double theta, double* x,
+        double* y, double* z)
+{
+    double tx, ty, tz;
+    tx = rho* sin(phi) * cos(theta);
+    ty = rho* sin(phi) * sin(theta);
+    tz = rho* cos(phi);
+    if (isnan(tx) || isnan(ty) || isnan(tz)) {
+        cerr &lt;&lt; &quot;SphericalToCartesian produced nan!&quot; &lt;&lt; endl;
+        return -1;
+    }
+
+    *x = tx;
+    *y = ty;
+    *z = tz;
+     return 0;
+}
+
+void WriteDouble(EncodeBase64 &amp;b64, ofstream &amp;file, double data, bool writeBinary) {
+    double validData = ConvertDouble2ValidDouble (data);
+    if (writeBinary) {
+        b64.Write((const unsigned char*)&amp;validData, sizeof(validData));
+    } else {
+        file &lt;&lt; validData &lt;&lt; &quot; &quot;;
+    }
+}
+
+void WriteFloat(EncodeBase64 &amp;b64, ofstream &amp;file, double data, bool writeBinary) {
+    float validData = ConvertDouble2ValidFloat (data);
+    if (writeBinary) {
+        b64.Write((const unsigned char*)&amp;validData, sizeof(validData));
+    } else {
+        file &lt;&lt; validData &lt;&lt; &quot; &quot;;
+    }
+}
+
+void WriteInt(EncodeBase64 &amp;b64, ofstream &amp;file, int data, bool writeBinary) {
+    if (writeBinary) {
+        b64.Write((const unsigned char*)&amp;data, sizeof(data));
+    } else {
+        file &lt;&lt; data &lt;&lt; &quot; &quot;;
+    }
+}
+
+void WriteChar(EncodeBase64 &amp;b64, ofstream &amp;file, char data, bool writeBinary) {
+    if (writeBinary) {
+        b64.Write((const unsigned char*)&amp;data, sizeof(data));
+    } else {
+        file &lt;&lt; (int)data &lt;&lt; &quot; &quot;;
+    }
+}
+
+void PrintUsage() {
+    cerr &lt;&lt; &quot;USAGE: mpasnc2vtu [OPTIONS] infile.nc outfile.vtu&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;Create view of MPAS-style data from input file infile.nc &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;and write to XML binary .vtu format for use in ParaView.&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;A series of vtu files are created, one file for each time step.&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;with time prepended to the file name (e.g. 0outfile.vtu).&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;OPTIONS:&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -l intval     &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       vertical level, in range 0 to nVertLevels-1, default is 0 &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -m            &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       multilayer view -- default is single layer view&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -p            &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       project to lat/lon -- default is sphere view&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -t floatval   &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       layer_thickness -- use negative value for atmosphere, default is 10&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -c floatval   &quot; &lt;&lt; endl; 
+    cerr &lt;&lt; &quot;      display image with center_longitude in degrees, default is 180&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -z &quot; &lt;&lt; endl; 
+    cerr &lt;&lt; &quot;      input grid has center longitude at 0, the default is 180 degree or PI radians&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -a              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       atmosphere data (longitude data is in range -PI to PI)  &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       The -a flag also converts the multilayer view to have the &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       vertical levels stack in the positive Z direction, rather &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       the negative Z direction, which is the default.&quot; &lt;&lt; endl;     
+    cerr &lt;&lt; &quot;   -s              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       timestep to start on (defaults to 0) &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -f              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       timestep to finish on (defaults to last timestep available) &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -g              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       include topography (assumes you have maxLevelPoint variable) &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -b              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       do bugfix to ensure no connections to faraway points &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;   -x              &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       write data in ascii, not binary &quot; &lt;&lt; endl;
+
+    cerr &lt;&lt; &quot;Variables with time and vertical level are written out.&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;[vtk datafile Version 2.0, projlatlonbin Version 1.3]&quot; &lt;&lt; endl;
+    exit(1);
+}
+
+void GetArgs(int argc, char* argv[], struct params &amp;p) 
+{
+    int c;
+    optind = 1;
+
+    //set default params
+    p.writeBinary = true;
+    p.singleLayer = true;
+    p.isAtmosphere = false;
+    p.includeTopography = false;
+    p.doBugFix = false;
+    p.outputVertLevel = 0;
+    p.inputFileName = NULL;
+    p.outputFileName = NULL;
+    p.layerThickness = DEFAULT_LAYER_THICKNESS;
+    p.isZeroCentered = false;
+    p.centerLon = 180.0;
+    p.centerRad = p.centerLon * PI / 180.0;
+    p.startTimeStep = 0;
+    p.finishTimeStep = -1;
+    p.projectLatLon = false;
+
+    bool lflag = false;
+    bool tflag = false;
+    bool mflag = false;
+
+    // -l vertical level (if not specified, assume multilayer)
+    // -t layer thickness (defaults to 1/10 * radius/#layers)
+    // -c center longitude in degrees for latlon projection
+    while ((c=getopt(argc, argv, &quot;l:t:c:mazpxgbs:f:&quot;)) != -1) {
+        switch(c) {
+            case 'l':
+                lflag = true;
+                if (tflag) {
+                    cerr &lt;&lt; &quot;Can't specify -l and -t at same time.&quot; &lt;&lt; endl;
+                    exit(1);
+                }
+                p.outputVertLevel = atoi(optarg);
+                p.singleLayer = true;
+                break;
+            case 't':
+                tflag = true;
+                if (lflag) {
+                    cerr &lt;&lt; &quot;Can't specify -l and -t at same time.&quot; &lt;&lt; endl;
+                    exit(1);
+                }
+                p.layerThickness = atof(optarg);
+                p.singleLayer = false;
+                break;
+            case 'c':
+                p.centerLon = (double)atof(optarg);
+                p.centerRad = p.centerLon * PI / 180.0;
+                break;
+            case 'm':
+                mflag = true;
+                if (lflag) {
+                    cerr &lt;&lt; &quot;Can't specify -l and -m at same time.&quot; &lt;&lt; endl;
+                    exit(1);
+                }
+                p.singleLayer = false;
+                break;
+           case 'a':
+                p.isAtmosphere = true;
+                break;
+           case 'x':
+                p.writeBinary = false;
+                break;
+            case 's':
+                p.startTimeStep = atoi(optarg);
+                break;
+            case 'f':
+                p.finishTimeStep = atoi(optarg);
+                break;
+            case 'z':
+                p.isZeroCentered = true;
+                break;
+            case 'p':
+                p.projectLatLon = true;
+                break;
+            case 'g':
+                p.includeTopography = true;
+                break;
+            case 'b':
+                p.doBugFix = true;
+                break;
+            default:
+                cerr &lt;&lt; &quot;Unrecognized option: -&quot; &lt;&lt; c &lt;&lt; endl;
+                PrintUsage();
+                exit(1);
+                break;
+        }
+    }
+
+    p.inputFileName = argv[optind++];
+    p.outputFileName = argv[optind];
+
+}
+
+// Check if there is a variable by that name
+bool isNcVar(NcFile &amp;ncFile, NcToken name) {
+    int num_vars = ncFile.num_vars();
+    for (int i = 0; i &lt; num_vars; i++) {
+        NcVar* ncVar = ncFile.get_var(i);
+                if ((strcmp(ncVar-&gt;name(), name)) == 0) {
+            // we have a match, so return
+            return true;
+        }
+    }
+    return false;
+}
+
+// Check if there is a dimension by that name
+bool isNcDim(NcFile &amp;ncFile, NcToken name) {
+    int num_dims = ncFile.num_dims();
+    //cerr &lt;&lt; &quot;looking for: &quot; &lt;&lt; name &lt;&lt; endl;
+    for (int i = 0; i &lt; num_dims; i++) {
+        NcDim* ncDim = ncFile.get_dim(i);
+        //cerr &lt;&lt; &quot;checking &quot; &lt;&lt; ncDim-&gt;name() &lt;&lt; endl;
+                if ((strcmp(ncDim-&gt;name(), name)) == 0) {
+            // we have a match, so return
+            return true;
+        }
+    }
+    return false;
+}
+
+
+#define CHECK_DIM(ncFile, name) \
+    if (!isNcDim(ncFile, name)) { \
+        cerr &lt;&lt; &quot;Cannot find dimension: &quot; &lt;&lt; name &lt;&lt; endl; \
+        exit(1); \
+    }
+
+#define CHECK_VAR(ncFile, name) \
+    if (!isNcVar(ncFile, name)) { \
+        cerr &lt;&lt; &quot;Cannot find variable: &quot; &lt;&lt; name &lt;&lt; endl; \
+        exit(1); \
+    }
+
+
+// put dims into dual grid geometry
+void GetNcDims(NcFile &amp;ncFile, geometry &amp;g)
+{
+    CHECK_DIM(ncFile, &quot;nCells&quot;);
+    NcDim* nCells = ncFile.get_dim(&quot;nCells&quot;);
+    g.numPoints = nCells-&gt;size();
+    g.pointOffset = 1;
+
+    CHECK_DIM(ncFile, &quot;nVertices&quot;);
+    NcDim* nVertices = ncFile.get_dim(&quot;nVertices&quot;);
+    g.numCells = nVertices-&gt;size();
+    g.cellOffset = 0;
+
+    CHECK_DIM(ncFile, &quot;vertexDegree&quot;);
+    NcDim* vertexDegree = ncFile.get_dim(&quot;vertexDegree&quot;);
+    g.pointsPerCell = vertexDegree-&gt;size();
+
+    CHECK_DIM(ncFile, &quot;Time&quot;);
+    NcDim* Time = ncFile.get_dim(&quot;Time&quot;);
+    g.Time = Time-&gt;size();
+
+    CHECK_DIM(ncFile, &quot;nVertLevels&quot;);
+    NcDim* nVertLevels = ncFile.get_dim(&quot;nVertLevels&quot;);
+    g.nVertLevels = nVertLevels-&gt;size();
+
+    g.maxNVertLevels = g.nVertLevels;
+}
+
+void CheckArgs(params &amp;p, geometry &amp;g) 
+{
+
+        if ((g.pointsPerCell != 3) &amp;&amp; (g.pointsPerCell != 4))  {
+                cerr &lt;&lt; &quot;This code is only for hexagonal or quad grid projection&quot; &lt;&lt; endl;
+                exit(1);
+        }
+
+    // double-check we can do multilayer
+    if ((!p.singleLayer) &amp;&amp; (g.maxNVertLevels == 1)) {
+        p.singleLayer = true;
+    }
+
+    if (p.singleLayer &amp;&amp; (p.outputVertLevel &gt; (g.maxNVertLevels-1))) {
+        cerr &lt;&lt; &quot;There is no data for level &quot; &lt;&lt; p.outputVertLevel &lt;&lt; &quot;.&quot; &lt;&lt; endl;
+        exit(1);
+    }
+
+    if (p.singleLayer &amp;&amp; (p.outputVertLevel &lt; 0)) {
+        cerr &lt;&lt; &quot;Level number must be 0 or greater.&quot; &lt;&lt; endl;
+        exit(1);
+    }
+
+    if ((p.centerLon &lt; 0) || (p.centerLon &gt; 360)) {
+        cerr &lt;&lt; &quot;Center longitude must be between 0 and 360.&quot; &lt;&lt; endl;
+        exit(1);
+    }
+
+    if (p.singleLayer) {
+        g.maxNVertLevels = 1;
+    }
+
+    if (p.isAtmosphere) {
+        p.layerThickness = -p.layerThickness;
+    }
+
+    int availTimeSteps = g.Time;
+
+    if (p.startTimeStep &gt; (availTimeSteps-1)) {
+        cerr &lt;&lt; &quot;Start timestep is too large, last timestep is: &quot; &lt;&lt; availTimeSteps-1 &lt;&lt; endl;
+        exit(1);
+    }
+
+    if (p.startTimeStep &lt; 0) {
+        cerr &lt;&lt; &quot;Start timestep is too small, must be at least 0.&quot; &lt;&lt; endl;
+        exit(1);
+    }
+
+    if (p.finishTimeStep &gt; (availTimeSteps-1)) {
+        cerr &lt;&lt; &quot;Finish timestep is too large, last timestep is: &quot; &lt;&lt; availTimeSteps-1 &lt;&lt; endl;
+        exit(1);
+    }
+    
+    if (p.finishTimeStep &lt; 0) {
+        p.finishTimeStep = availTimeSteps-1;
+    }
+
+    cerr &lt;&lt; &quot;centerLon: &quot; &lt;&lt; p.centerLon &lt;&lt; &quot; singleLayer: &quot; &lt;&lt; p.singleLayer &lt;&lt; &quot; outputVertLevel: &quot; &lt;&lt; p.outputVertLevel &lt;&lt; &quot; start: &quot; &lt;&lt; p.startTimeStep &lt;&lt; &quot; finish: &quot; &lt;&lt; p.finishTimeStep &lt;&lt; &quot; isAtmosphere: &quot; &lt;&lt; p.isAtmosphere  &lt;&lt; &quot; includeTopography: &quot; &lt;&lt; p.includeTopography &lt;&lt; &quot; doBugFix: &quot; &lt;&lt; p.doBugFix &lt;&lt; &quot; layerThickness: &quot; &lt;&lt; p.layerThickness &lt;&lt; endl;
+
+}
+
+
+void GetNcVars (NcFile &amp;ncFile, vars &amp;v, const char* cellDimName, 
+        const char* pointDimName)
+{
+    int cellVarIndex = -1;
+    int pointVarIndex = -1;
+
+    int numVars = ncFile.num_vars();
+
+    for (int i = 0; i &lt; numVars; i++) {
+        NcVar* aVar = ncFile.get_var(i);
+
+        // must have 3 dims 
+        // (Time, nCells | nVertices, nVertLevels | nVertLevelsP1)
+
+        int numDims = aVar-&gt;num_dims();
+        //cout &lt;&lt; &quot;Num Dims of var: &quot; &lt;&lt; aVar-&gt;name() &lt;&lt; &quot; is &quot; &lt;&lt; numDims &lt;&lt; endl;
+        if (numDims != 3) continue;
+
+
+        // TODO, check if it is a double
+        // assume a double for now
+
+        // check for Time dim 0
+        NcToken dim0Name = aVar-&gt;get_dim(0)-&gt;name();
+        if (strcmp(dim0Name, &quot;Time&quot;)) 
+            continue;
+
+        // check for dim 1 being cell or point
+        bool isCellData = false;
+        bool isPointData = false;
+        NcToken dim1Name = aVar-&gt;get_dim(1)-&gt;name();
+        if (!strcmp(dim1Name, cellDimName)) 
+            isCellData = true;
+        else if (!strcmp(dim1Name, pointDimName)) 
+            isPointData = true; 
+        else continue;
+
+        // check if dim 2 is nVertLevels or nVertLevelsP1, too
+        NcToken dim2Name = aVar-&gt;get_dim(2)-&gt;name();
+        if ((strcmp(dim2Name, &quot;nVertLevels&quot;)) 
+                &amp;&amp; (strcmp(dim2Name, &quot;nVertLevelsP1&quot;))) {
+            continue;
+        }
+
+        // Add to cell or point var array
+        if (isCellData) {  // means it is cell data
+            cellVarIndex++;
+            if (cellVarIndex &gt; MAX_VARS-1) {
+                cerr &lt;&lt; &quot;Exceeded number of cell vars.&quot; &lt;&lt; endl;
+                exit(1);
+            }
+            v.cellVars[cellVarIndex] = aVar;
+            //cout &lt;&lt; &quot;Adding var &quot; &lt;&lt; aVar-&gt;name() &lt;&lt; &quot; to cellVars&quot; &lt;&lt; endl;
+        } else if (isPointData) 
+        { 
+            pointVarIndex++;
+            if (pointVarIndex &gt; MAX_VARS-1) {
+                cerr &lt;&lt; &quot;Exceeded number of point vars.&quot; &lt;&lt; endl;
+                exit(1);
+            }
+            v.pointVars[pointVarIndex] = aVar;
+            //cout &lt;&lt; &quot;Adding var &quot; &lt;&lt; aVar-&gt;name() &lt;&lt; &quot; to pointVars&quot; &lt;&lt; endl;
+        }
+    }
+
+    v.numPointVars = pointVarIndex+1;
+    v.numCellVars = cellVarIndex+1;
+
+}
+
+// allocate into sphere view of dual geometry
+void AllocSphereGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
+{
+    CHECK_VAR(ncFile, &quot;xCell&quot;);
+        g.pointX = (double*)malloc((g.numPoints + g.pointOffset) * sizeof(double));
+        CHECK_MALLOC(g.pointX);
+    NcVar*  xCellVar = ncFile.get_var(&quot;xCell&quot;);
+        xCellVar-&gt;get(g.pointX + g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointX[0] = 0.0L;
+
+    CHECK_VAR(ncFile, &quot;yCell&quot;);
+        g.pointY = (double*)malloc((g.numPoints + g.pointOffset) * sizeof(double));
+        CHECK_MALLOC(g.pointY);
+    NcVar*  yCellVar = ncFile.get_var(&quot;yCell&quot;);
+        yCellVar-&gt;get(g.pointY+g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointY[0] = 0.0L;
+
+    CHECK_VAR(ncFile, &quot;zCell&quot;);
+        g.pointZ = (double*)malloc((g.numPoints + g.pointOffset) * sizeof(double));
+        CHECK_MALLOC(g.pointZ);
+    NcVar*  zCellVar = ncFile.get_var(&quot;zCell&quot;);
+        zCellVar-&gt;get(g.pointZ+g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointZ[0] = 0.0L;
+
+    CHECK_VAR(ncFile, &quot;cellsOnVertex&quot;);
+        g.origConnections = (int *) malloc(g.numCells * g.pointsPerCell * 
+            sizeof(int));
+        CHECK_MALLOC(g.origConnections);
+    NcVar *connectionsVar = ncFile.get_var(&quot;cellsOnVertex&quot;);
+    connectionsVar-&gt;get(g.origConnections, g.numCells, g.pointsPerCell);
+
+    if (p.includeTopography) {
+        CHECK_VAR(ncFile, &quot;maxLevelCell&quot;);
+        g.maxLevelPoint = (int*)malloc((g.numPoints + g.numPoints) * sizeof(int));
+        CHECK_MALLOC(g.maxLevelPoint);
+        NcVar *maxLevelPointVar = ncFile.get_var(&quot;maxLevelCell&quot;);
+        maxLevelPointVar-&gt;get(g.maxLevelPoint + g.pointOffset, g.numPoints);
+    } 
+
+    g.currentExtraPoint = g.numPoints + g.pointOffset;
+    g.currentExtraCell = g.numCells + g.cellOffset;
+
+    if (p.singleLayer) {
+        g.maxCells = g.currentExtraCell;
+        g.maxPoints = g.currentExtraPoint;
+    } else {
+        g.maxCells = g.currentExtraCell*g.maxNVertLevels;
+        g.maxPoints = g.currentExtraPoint*(g.maxNVertLevels+1);
+    }
+}
+
+// allocate into lat/lon projection of dual geometry
+void AllocLatLonGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
+{
+    const float BLOATFACTOR = .5;
+        g.modNumPoints = (int)floor(g.numPoints*(1.0 + BLOATFACTOR));
+        g.modNumCells = (int)floor(g.numCells*(1.0 + BLOATFACTOR))+1;
+
+    CHECK_VAR(ncFile, &quot;lonCell&quot;);
+        g.pointX = (double*)malloc(g.modNumPoints * sizeof(double));
+        CHECK_MALLOC(g.pointX);
+    NcVar*  xCellVar = ncFile.get_var(&quot;lonCell&quot;);
+        xCellVar-&gt;get(g.pointX + g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    *g.pointX = 0.0;
+
+    CHECK_VAR(ncFile, &quot;latCell&quot;);
+        g.pointY = (double*)malloc(g.modNumPoints * sizeof(double));
+        CHECK_MALLOC(g.pointY);
+    NcVar*  yCellVar = ncFile.get_var(&quot;latCell&quot;);
+        yCellVar-&gt;get(g.pointY+g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    *g.pointY = 0.0;
+
+    CHECK_VAR(ncFile, &quot;cellsOnVertex&quot;);
+        g.origConnections = (int *) malloc(g.numCells * g.pointsPerCell * 
+            sizeof(int));
+        CHECK_MALLOC(g.origConnections);
+    NcVar *connectionsVar = ncFile.get_var(&quot;cellsOnVertex&quot;);
+    connectionsVar-&gt;get(g.origConnections, g.numCells, g.pointsPerCell);
+
+    // create my own list to include modified origConnections (due to
+    // eliminating wraparound in the lat/lon projection) plus additional
+    // cells added when mirroring cells that had previously wrapped around
+
+        g.modConnections = (int *) malloc(g.modNumCells * g.pointsPerCell 
+            * sizeof(int));
+        CHECK_MALLOC(g.modConnections);
+
+
+        // allocate an array to map the extra points and cells to the original
+        // so that when obtaining data, we know where to get it
+        g.pointMap = (int*)malloc((int)floor(g.numPoints*BLOATFACTOR) 
+            * sizeof(int));
+        CHECK_MALLOC(g.pointMap);
+        g.cellMap = (int*)malloc((int)floor(g.numCells*BLOATFACTOR) 
+            * sizeof(int));
+        CHECK_MALLOC(g.cellMap);
+
+        g.currentExtraPoint = g.numPoints + g.pointOffset;
+        g.currentExtraCell = g.numCells + g.cellOffset;
+
+    if (p.includeTopography) {
+        CHECK_VAR(ncFile, &quot;maxLevelCell&quot;);
+        g.maxLevelPoint = (int*)malloc((g.numPoints + g.numPoints) * sizeof(int));
+        CHECK_MALLOC(g.maxLevelPoint);
+        NcVar *maxLevelPointVar = ncFile.get_var(&quot;maxLevelCell&quot;);
+        maxLevelPointVar-&gt;get(g.maxLevelPoint + g.pointOffset, g.numPoints);
+    }
+}
+
+void ShiftLonData(params &amp;p, geometry &amp;g)
+{
+    // if atmospheric data, or zero centered, set center to 180 instead of 0
+    if (p.isAtmosphere || p.isZeroCentered) {
+        for (int j = g.pointOffset; j &lt; g.numPoints + g.pointOffset; j++) {
+            // need to shift over the point so center is at PI 
+            if (g.pointX[j] &lt; 0) {
+                g.pointX[j] += 2*PI;
+            }       
+        }       
+    }
+
+    if (p.centerLon != 180) {
+        for (int j = g.pointOffset; j &lt; g.numPoints + g.pointOffset; j++) {
+            // need to shift over the point if centerLon dictates
+            if (p.centerRad &lt; PI) {
+                if (g.pointX[j] &gt; (p.centerRad + PI)) {
+                    g.pointX[j] = -((2*PI) - g.pointX[j]);
+                }
+            } else if (p.centerRad &gt; PI) {
+                if (g.pointX[j] &lt; (p.centerRad - PI)) {
+                    g.pointX[j] += 2*PI;
+                }
+            }
+        }
+    }
+}
+
+
+int AddMirrorPoint(int index, double dividerX, geometry &amp;g)
+{
+    double X = g.pointX[index];
+    double Y = g.pointY[index];
+
+    // add on east
+    if (X &lt; dividerX) {
+        X += 2*PI;
+    } else { 
+        // add on west
+        X -= 2*PI;
+    }
+
+    g.pointX[g.currentExtraPoint] = X;
+    g.pointY[g.currentExtraPoint] = Y;
+
+    int mirrorPoint = g.currentExtraPoint;
+
+    // record mapping
+    *(g.pointMap + (g.currentExtraPoint - g.numPoints - g.pointOffset)) = index;
+    g.currentExtraPoint++;
+    
+    return mirrorPoint;
+}
+
+// Check for out-of-range values and do bugfix
+void FixPoints(params &amp;p, geometry &amp;g)
+{
+
+        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++ ) {
+                int *conns = g.origConnections + (j * g.pointsPerCell);
+
+        // go through and make sure none of the referenced points are
+        // out of range 
+        // if so, set all to point 0
+        for (int k = 0; k &lt; g.pointsPerCell; k++)  {
+            if  ((conns[k] &lt;= 0) || (conns[k] &gt; g.numPoints)) {
+                for (int m = 0; m &lt; g.pointsPerCell; m++)  {
+                    conns[m] = 0;
+                }
+                break;
+            } 
+        }
+
+        int lastk;
+
+        if (p.doBugFix) {
+            //BUG FIX for problem where cells are stretching to a faraway point
+            lastk = g.pointsPerCell-1;
+            const double thresh = .06981317007977; // 4 degrees
+            for (int k = 0; k &lt; g.pointsPerCell; k++)  {
+                double xdiff = abs(g.pointX[conns[k]]  
+                        - g.pointX[conns[lastk]]);
+                double ydiff = abs(g.pointY[conns[k]]  
+                        - g.pointY[conns[lastk]]);
+                // Don't look at cells at map border
+                if (ydiff &gt; thresh) {
+                    for (int m = 0; m &lt; g.pointsPerCell; m++)  {
+                        conns[m] = 0;
+                    }
+                    break;
+                } 
+            }
+        }
+    }
+}
+
+
+// Eliminate wraparound at east/west edges of lat/lon projection
+void EliminateXWrap (params &amp;p, geometry &amp;g) 
+{
+
+    // For each cell, examine vertices
+        // Add new points and cells where needed to account for wraparound.
+
+    int mirrorcell;
+    int apoint;
+    int mirrorpoint;
+
+
+        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++ ) {
+                int *conns = g.origConnections + (j * g.pointsPerCell);
+                int *modConns = g.modConnections + (j * g.pointsPerCell);
+        int lastk;
+
+        // Determine if we are wrapping in X direction
+                lastk = g.pointsPerCell-1;
+                bool xWrap = false;
+                for (int k = 0; k &lt; g.pointsPerCell; k++) {
+                        if (abs(g.pointX[conns[k]]  
+                        - g.pointX[conns[lastk]]) &gt; 5.5) xWrap = true;
+                        lastk = k;
+                }
+
+        // If we wrapped in X direction, modify cell and add mirror cell
+                if (xWrap) {
+                        
+            // first point is anchor it doesn't move
+                        double anchorX = g.pointX[conns[0]];
+                        double anchorY = g.pointY[conns[0]];
+                        modConns[0] = conns[0];
+
+                        // modify existing cell, so it doesn't wrap
+                        // move points to one side
+            for (int k = 1; k &lt; g.pointsPerCell; k++) {
+                int neigh = conns[k];
+
+                                // add a new point, figure out east or west
+                                if (abs(g.pointX[neigh] - anchorX) &gt; 5.5)  {
+                    modConns[k] = AddMirrorPoint(neigh, anchorX, g);
+                                } else {
+                                        // use existing kth point 
+                                        modConns[k] = neigh;
+                                }
+                        }
+
+            // move addedConns to modConnections extra cells area
+            int* addedConns = g.modConnections 
+                + (g.currentExtraCell * g.pointsPerCell);
+              
+            // add a mirroring cell to other side    
+
+            // add mirrored anchor first
+            addedConns[0] = AddMirrorPoint(conns[0], p.centerRad, g);
+            anchorX = g.pointX[addedConns[0]];
+
+            // add mirror cell points if needed
+                        for (int k = 1; k &lt; g.pointsPerCell; k++) {
+                int neigh = conns[k];
+
+                                // add a new point for neighbor, figure out east or west
+                                if (abs(g.pointX[neigh] - anchorX) &gt; 5.5)  {
+                    addedConns[k] = AddMirrorPoint(neigh, anchorX, g);
+                                } else {
+                                        // use existing kth point 
+                                        addedConns[k] = neigh;
+                                }
+                        }
+                        *(g.cellMap + (g.currentExtraCell - g.numCells - g.cellOffset)) = j;
+                        g.currentExtraCell++;
+                } else {
+
+            // just add cell &quot;as is&quot; to modConnections
+                        for (int k=0; k&lt; g.pointsPerCell; k++) {
+                                modConns[k] = conns[k];
+                        }
+                }
+                if (g.currentExtraCell &gt; g.modNumCells) {
+                        cerr &lt;&lt; &quot;Exceeded storage for extra cells!&quot; &lt;&lt; endl;
+                        exit(1);
+                }
+                if (g.currentExtraPoint &gt; g.modNumPoints) {
+                        cerr &lt;&lt; &quot;Exceeded storage for extra points!&quot; &lt;&lt; endl;
+                        exit(1);
+                }
+        }
+
+    if (p.singleLayer) {
+        g.maxCells = g.currentExtraCell;
+        g.maxPoints = g.currentExtraPoint;
+    } else {
+        g.maxCells = g.currentExtraCell*g.maxNVertLevels;
+        g.maxPoints = g.currentExtraPoint*(g.maxNVertLevels+1);
+    }
+}
+
+void WritePoints(ofstream &amp;geoFile, EncodeBase64 &amp;b64, params &amp;p, geometry &amp;g) 
+{
+        // write points  (the points are the primal-grid cell centers)
+
+        // write the point at each vertical level, plus one level for last layer
+
+    geoFile &lt;&lt; &quot;      &lt;Points&gt;&quot; &lt;&lt; endl;
+
+    string formatString;
+
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    // see if we can change to double
+
+    //geoFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float32\&quot; Name=\&quot;Points\&quot; NumberOfComponents=\&quot;3\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt;&quot; &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float64\&quot; Name=\&quot;Points\&quot; NumberOfComponents=\&quot;3\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt;&quot; &lt;&lt; endl;
+
+    geoFile.precision(16);
+
+    geoFile &lt;&lt; &quot;          &quot;;
+
+    if (p.writeBinary) {
+        b64.StartWriting();
+        //int binarySize = g.maxPoints*sizeof(float)*3;
+        int binarySize = g.maxPoints*sizeof(double)*3;
+        binarySize = PadSize(binarySize);
+        b64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+    }
+
+        //cout &lt;&lt; &quot;Writing points at each level&quot; &lt;&lt; endl;
+
+        for (int j = 0; j &lt; g.currentExtraPoint; j++ )
+        {
+
+                //float x, y, z;
+                double x, y, z;
+
+        if (p.projectLatLon) {
+                    x = g.pointX[j] * 180.0 / PI;
+                    y = g.pointY[j] * 180.0 / PI;
+            z = 0.0;
+        } else {
+                    x = g.pointX[j];
+                    y = g.pointY[j];
+            z = g.pointZ[j];
+        }
+
+        if (p.singleLayer) {
+            if (p.writeBinary) {
+                //b64.Write((const unsigned char*)&amp;x, sizeof(float));
+                b64.Write((const unsigned char*)&amp;x, sizeof(double));
+                //b64.Write((const unsigned char*)&amp;y, sizeof(float));
+                b64.Write((const unsigned char*)&amp;y, sizeof(double));
+                //b64.Write((const unsigned char*)&amp;z, sizeof(float));
+                b64.Write((const unsigned char*)&amp;z, sizeof(double));
+            } else {
+                geoFile &lt;&lt; &quot;          &quot; &lt;&lt; x &lt;&lt; &quot; &quot; &lt;&lt; y &lt;&lt; &quot; &quot; &lt;&lt; z &lt;&lt; endl;
+            }
+        } else {
+            double rho, rholevel, theta, phi;
+            int retval = -1; 
+
+            if (!p.projectLatLon) {
+                if ((x != 0.0) || (y != 0.0) || (z != 0.0)) {
+                    retval = CartesianToSpherical(x, y, z, &amp;rho, &amp;phi, &amp;theta);
+                }
+            }
+
+            for (int levelNum = 0; levelNum &lt; g.maxNVertLevels+1; levelNum++) {
+                if (p.projectLatLon){
+                    z = -(((double)levelNum)*p.layerThickness);
+                } else {
+                    if (!retval &amp;&amp; ((x != 0.0) || (y != 0.0) || (z != 0.0))) {
+                        rholevel = rho - (p.layerThickness * levelNum);
+                        SphericalToCartesian(rholevel, phi, theta, &amp;x, &amp;y, &amp;z);
+                    }
+                }
+
+                if (p.writeBinary) {
+                    //b64.Write((const unsigned char*)&amp;x, sizeof(float));
+                    b64.Write((const unsigned char*)&amp;x, sizeof(double));
+                    //b64.Write((const unsigned char*)&amp;y, sizeof(float));
+                    b64.Write((const unsigned char*)&amp;y, sizeof(double));
+                    //b64.Write((const unsigned char*)&amp;z, sizeof(float));
+                    b64.Write((const unsigned char*)&amp;z, sizeof(double));
+                } else {
+                    geoFile &lt;&lt; &quot;          &quot; &lt;&lt; x &lt;&lt; &quot; &quot; &lt;&lt; y &lt;&lt; &quot; &quot; &lt;&lt; z &lt;&lt; endl;
+                }
+            }
+        }
+        }        
+
+    if (p.writeBinary) {
+        b64.EndWriting();
+        geoFile &lt;&lt; endl;
+    }
+
+    geoFile &lt;&lt; &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;      &lt;/Points&gt;&quot; &lt;&lt; endl;
+}
+
+
+void WriteConnectivity(ofstream &amp;geoFile, EncodeBase64 &amp;b64, params &amp;p, 
+        geometry &amp;g)
+{
+
+    // Write cell connectivity
+
+    string formatString;
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    geoFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Int32\&quot; Name=\&quot;connectivity\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt;&quot; &lt;&lt; endl;
+
+    // for each cell, write the points for each
+
+
+    if (p.writeBinary) {
+        geoFile &lt;&lt; &quot;          &quot;;
+        b64.StartWriting();
+        int binarySize;
+        if (p.singleLayer) {
+           binarySize = g.maxCells*g.pointsPerCell*sizeof(int);
+        } else {
+           binarySize = g.maxCells*g.pointsPerCell*2*sizeof(int);
+        }
+        binarySize = PadSize(binarySize);
+        //cout &lt;&lt; &quot;BinarySize: &quot; &lt;&lt; binarySize &lt;&lt; endl;
+        b64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+    }
+
+    // for each cell, write number of points for each
+    // and then list the points by number
+
+    //cout &lt;&lt; &quot;Writing connectivity&quot; &lt;&lt; endl;
+
+    unsigned int val;
+
+    for (int j = 0; j &lt; g.currentExtraCell ; j++) {
+
+        int* conns;
+        if (p.projectLatLon) {
+           conns = g.modConnections + (j * g.pointsPerCell);
+        } else {
+            conns = g.origConnections + (j * g.pointsPerCell);
+        }
+
+        int minLevel= 0; 
+
+        if (p.includeTopography) {
+            int* connections;
+
+            //check if it is a mirror cell, if so, get original
+            if (j &gt;= g.numCells + g.cellOffset) {
+                //cout &lt;&lt; &quot;setting origCell&quot; &lt;&lt; endl;
+                int origCellNum = *(g.cellMap + (j - g.numCells - g.cellOffset));
+                //cout &lt;&lt; &quot;mirror cell: &quot; &lt;&lt;j&lt;&lt; &quot; origCell: &quot;&lt;&lt; origCell &lt;&lt; endl;
+                conns = g.origConnections + (origCellNum*g.pointsPerCell);
+            } else connections = g.origConnections + (j * g.pointsPerCell);
+
+            //cout &lt;&lt; &quot;calc minLevel&quot; &lt;&lt; endl;
+            minLevel = g.maxLevelPoint[conns[0]];
+            //cout &lt;&lt; &quot;initial minLevel:&quot; &lt;&lt; minLevel &lt;&lt; endl;
+            // Take the min of the maxLevelPoint of each point 
+            for (int k = 1; k &lt; g.pointsPerCell; k++)  {
+                minLevel = min(minLevel, g.maxLevelPoint[connections[k]]);
+            }
+            //cout &lt;&lt; endl;
+        }
+
+        if (p.singleLayer) {
+            if (!p.writeBinary) geoFile &lt;&lt; &quot;          &quot;;
+
+            // If that min is greater than or equal to this output level,
+            // include the cell, otherwise set all points to zero.
+
+            if (p.includeTopography &amp;&amp; ((minLevel-1) &lt; p.outputVertLevel)) {
+                //cerr &lt;&lt; &quot;Setting all points to zero&quot; &lt;&lt; endl;
+                val = 0;
+                for (int k = 0; k &lt; g.pointsPerCell; k++)  {
+                    WriteInt(b64, geoFile, val, p.writeBinary); 
+                }
+            } else {
+                for (int k = 0; k &lt; g.pointsPerCell; k++)  {
+                    WriteInt(b64, geoFile, conns[k], p.writeBinary); 
+                }
+            }
+
+            if (!p.writeBinary) geoFile &lt;&lt; endl;
+        } else { // multilayer
+
+            // for each level, write the cell
+            for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                if(!p.writeBinary) geoFile &lt;&lt; &quot;          &quot;;
+
+                if (p.includeTopography &amp;&amp; ((minLevel-1) &lt; levelNum)) {
+                    // setting all points to zero
+                    val = 0;
+                    for (int m = 0; m &lt; g.pointsPerCell*2; m++)  {
+                        WriteInt(b64, geoFile, val, p.writeBinary); 
+                    }
+
+                } else {
+
+                    for (int k = 0; k &lt; g.pointsPerCell; k++) 
+                    { 
+                        val = (conns[k]*(g.maxNVertLevels+1)) + levelNum;
+                        WriteInt(b64, geoFile, val, p.writeBinary); 
+                    }
+
+                    for (int k = 0; k &lt; g.pointsPerCell; k++) 
+                    {                
+                        val = (conns[k]*(g.maxNVertLevels+1)) + levelNum + 1;
+                        WriteInt(b64, geoFile, val, p.writeBinary); 
+                    }
+                }
+                if (!p.writeBinary) geoFile &lt;&lt; endl;
+            }
+        }
+    }
+
+    if (p.writeBinary) {
+        b64.EndWriting();
+        geoFile &lt;&lt; endl;
+    }
+
+    geoFile &lt;&lt; &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+
+}
+
+
+void WriteOffsets(ofstream &amp;geoFile, EncodeBase64 &amp;b64, params &amp;p, geometry &amp;g)
+{
+    string formatString;
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    // Specify the offset into connectivity array for the end of each cell
+    geoFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Int32\&quot; Name=\&quot;offsets\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt;&quot;;
+
+    if (p.writeBinary) {
+        geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+        b64.StartWriting();
+        int binarySize = g.maxCells*sizeof(int);
+        binarySize = PadSize(binarySize);
+        //cout &lt;&lt; &quot;BinarySize: &quot; &lt;&lt; binarySize &lt;&lt; endl;
+        b64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+    }
+
+    int counter = 0;
+    unsigned int offset = 0;
+
+    for (int j = 0; j &lt; g.maxCells ; j++) {
+        if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+        if (p.singleLayer) {
+            offset += g.pointsPerCell;
+        } else {
+            offset += 2*g.pointsPerCell;
+        }
+        WriteInt(b64, geoFile, offset, p.writeBinary); 
+        counter++;
+    }
+
+    if (p.writeBinary) {
+        b64.EndWriting();
+    }
+
+    geoFile &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+}
+
+
+void WriteCellTypes(ofstream &amp;geoFile, EncodeBase64 &amp;b64,params &amp;p, geometry &amp;g)
+{
+    // write cell types 
+    unsigned char cellType;
+    switch (g.pointsPerCell) {
+        case 3:
+            if (p.singleLayer) {
+                cellType = VTK_TRIANGLE;
+            } else {
+                cellType = VTK_WEDGE;
+            }
+            break;
+        case 4:
+            if (p.singleLayer) {
+                cellType = VTK_QUAD;
+            } else {
+                cellType = VTK_HEXAHEDRON;
+            }
+            break;
+        default:
+            break;
+    }
+
+    string formatString;
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    geoFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;UInt8\&quot; Name=\&quot;types\&quot; format=\&quot;&quot; &lt;&lt; 
+        formatString &lt;&lt; &quot;\&quot;&gt;&quot;;
+
+    if (p.writeBinary) {
+        geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+        b64.StartWriting();
+        int binarySize = g.maxCells*sizeof(char);
+        binarySize = PadSize(binarySize);
+        //cout &lt;&lt; &quot;BinarySize: &quot; &lt;&lt; binarySize &lt;&lt; endl;
+        b64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+    }
+
+    for (int j = 0; j &lt; g.maxCells ; j++) {
+        if ((!p.writeBinary) &amp;&amp; (j%6 == 0)) {
+            geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+        }
+        WriteChar(b64, geoFile, cellType, p.writeBinary); 
+    }
+
+    if (p.writeBinary) b64.EndWriting();
+
+    geoFile &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+}
+
+
+void WriteGeometry(ostringstream &amp;geoFileName, params &amp;p, geometry &amp;g)
+{
+        geoFileName &lt;&lt; &quot;geo_&quot; &lt;&lt; p.outputFileName;         
+
+        ofstream geoFile(geoFileName.str().c_str(), ios::out);
+        if (!geoFile)
+        {
+                cerr &lt;&lt; &quot;output file &quot; &lt;&lt; geoFileName &lt;&lt; &quot; could not be opened&quot; &lt;&lt;endl;
+                exit(1);
+        }
+
+    EncodeBase64 b64(&amp;geoFile);
+
+    WritePoints(geoFile, b64, p, g);
+
+    geoFile &lt;&lt; &quot;      &lt;Cells&gt;&quot; &lt;&lt; endl;
+
+    WriteConnectivity(geoFile, b64, p, g);
+    WriteOffsets(geoFile, b64, p, g);
+    WriteCellTypes(geoFile, b64, p, g);
+
+    geoFile &lt;&lt; &quot;      &lt;/Cells&gt;&quot; &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;    &lt;/Piece&gt;&quot; &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;  &lt;/UnstructuredGrid&gt;&quot; &lt;&lt; endl;
+    geoFile &lt;&lt; &quot;&lt;/VTKFile&gt;&quot; &lt;&lt; endl;
+    geoFile.close();
+}
+
+
+void DeallocBasicGeometry(params &amp;p, geometry &amp;g)
+{
+    free (g.pointX);
+    free (g.pointY);
+    free (g.origConnections);
+
+    if (p.projectLatLon) {
+        free(g.modConnections);
+    } else {
+        free (g.pointZ);
+    }
+
+    if (p.includeTopography) {
+        free(g.maxLevelPoint);
+    }
+}
+
+
+void WritePointVarData(ofstream &amp;vtkFile, EncodeBase64 &amp;vtkb64, int t, 
+        params &amp;p, geometry &amp;g, vars &amp;v) 
+{
+    // If by point, write out point data
+    vtkFile &lt;&lt; &quot;      &lt;PointData&gt;&quot; &lt;&lt; endl;
+
+    double* pointVarData;
+    pointVarData = (double*)malloc((sizeof(double)) * g.currentExtraPoint 
+            * g.maxNVertLevels);
+    CHECK_MALLOC(pointVarData);
+
+    int vertLevelIndex = 0;
+    if (p.singleLayer) vertLevelIndex = p.outputVertLevel;
+
+    string formatString;
+
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    for (int i = 0; i &lt; v.numPointVars; i++) {
+
+        // Read variable number i data for that timestep
+
+        v.pointVars[i]-&gt;set_cur(t, 0, vertLevelIndex);
+        if (p.singleLayer) {
+            v.pointVars[i]-&gt;get(pointVarData+g.pointOffset, 1, g.numPoints, 1);
+        } else {
+            v.pointVars[i]-&gt;get(pointVarData + 
+                    (g.maxNVertLevels * g.pointOffset), 1, 
+                    g.numPoints, g.maxNVertLevels);
+        }
+
+        // Write variable number i data for that timestep
+
+        //vtkFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float32\&quot; Name=\&quot;&quot; &lt;&lt; 
+        vtkFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float64\&quot; Name=\&quot;&quot; &lt;&lt; 
+            v.pointVars[i]-&gt;name();
+        vtkFile &lt;&lt; &quot;\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt; &quot; &lt;&lt; endl;
+
+
+        vtkFile &lt;&lt; &quot;          &quot;;
+
+        double *var_target;
+        //float validData;
+        double validData;
+
+        if (p.writeBinary) {
+            vtkb64.StartWriting();
+            //int binarySize = g.maxPoints*sizeof(float);
+            int binarySize = g.maxPoints*sizeof(double);
+            binarySize = PadSize(binarySize);
+            //cout &lt;&lt; &quot;BinarySize: &quot; &lt;&lt; binarySize &lt;&lt; endl;
+            vtkb64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+        }
+
+        // if (g.pointOffset == 1)
+        //write dummy
+        // 0th pointVarData value is a filler, zero, which is not necessarily in 
+        // the range of the other data, so we look at the 1st value instead for
+        // our dummy
+        if (p.singleLayer) {
+            var_target = pointVarData + 1;
+            //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+            WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+        } else {
+            var_target = pointVarData + g.maxNVertLevels;
+            for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                var_target++;
+            }
+
+            // write highest level dummy point (duplicate of last level)
+            var_target--;
+            //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+            WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+
+            // Now set the var_target to the 1st data value
+            var_target = pointVarData + g.maxNVertLevels;
+        }
+
+        for (int j = g.pointOffset; j &lt; g.numPoints + g.pointOffset; j++) {
+
+            if (p.singleLayer) {
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                var_target++;
+            } else {
+
+                // write data for one point -- lowest level to highest
+                for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                    //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    var_target++;
+                }
+            
+                // for last layer of points, repeat last level's values
+                // Need Mark's input on this one
+                var_target--;
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                var_target++;
+            }
+        }
+
+        // put out data for extra points
+        for (int j = g.pointOffset + g.numPoints; j &lt; g.currentExtraPoint; j++) {
+            // use map to find out what point data we are using
+            var_target = pointVarData + ((*(g.pointMap + j - g.numPoints - g.pointOffset))*g.maxNVertLevels);
+
+            if (p.singleLayer) {
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                //validData = ConvertDouble2ValidFloat (*var_target);
+                validData = ConvertDouble2ValidDouble (*var_target);
+                var_target++;
+            } else {
+                // write data for one point -- lowest level to highest
+                for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                    //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    var_target++;
+                }
+            
+                // for last layer of points, repeat last level's values
+                // Need Mark's input on this one
+                var_target--;
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+            }
+        }
+        if (p.writeBinary) vtkb64.EndWriting();
+        vtkFile &lt;&lt; endl &lt;&lt;  &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+
+    }
+
+    free (pointVarData);
+
+    vtkFile &lt;&lt; &quot;      &lt;/PointData&gt;&quot; &lt;&lt; endl;
+
+}
+
+
+void WriteCellVarData(ofstream &amp;vtkFile, EncodeBase64 &amp;vtkb64, int t, 
+        params &amp;p, geometry &amp;g, vars &amp;v) 
+{
+    // if by cell, then write out cell data
+    double* cellVarData;
+    // use maxCell instead?
+    cellVarData = (double*)malloc((sizeof(double))  * g.currentExtraCell 
+            * g.maxNVertLevels);
+    CHECK_MALLOC(cellVarData);
+
+    vtkFile &lt;&lt; &quot;      &lt;CellData&gt;&quot; &lt;&lt; endl;
+
+    int vertLevelIndex = 0;
+    if (p.singleLayer) vertLevelIndex = p.outputVertLevel;
+
+    string formatString;
+
+    if (p.writeBinary) {
+        formatString = &quot;binary&quot;;
+    } else {
+        formatString = &quot;ascii&quot;;
+    }
+
+    for (int i = 0; i &lt; v.numCellVars; i++) {
+
+        // Write variable number v data for that timestep
+        //vtkFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float32\&quot; Name=\&quot;&quot; &lt;&lt; 
+        vtkFile &lt;&lt; &quot;        &lt;DataArray type=\&quot;Float64\&quot; Name=\&quot;&quot; &lt;&lt; 
+            v.cellVars[i]-&gt;name() &lt;&lt; &quot;\&quot; format=\&quot;&quot; &lt;&lt; formatString &lt;&lt; &quot;\&quot;&gt; &quot; ;
+
+        // Read variable number v data for that timestep and level
+        v.cellVars[i]-&gt;set_cur(t, 0, vertLevelIndex);
+        if (p.singleLayer) {
+            v.cellVars[i]-&gt;get(cellVarData + g.cellOffset, 1, g.numCells,1);
+        } else {
+            v.cellVars[i]-&gt;get(cellVarData + (g.cellOffset * g.maxNVertLevels),
+                    1, g.numCells, g.maxNVertLevels);
+        }
+
+        if (p.writeBinary) {
+            vtkFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+            vtkb64.StartWriting();
+            //int binarySize = g.maxCells*sizeof(float);
+            int binarySize = g.maxCells*sizeof(double);
+            binarySize = PadSize(binarySize);
+            //cout &lt;&lt; &quot;BinarySize: &quot; &lt;&lt; binarySize &lt;&lt; endl;
+            vtkb64.Write((const unsigned char*)&amp;binarySize, sizeof(int));
+        }
+
+        double *var_target = cellVarData;
+        int counter = 0;
+
+        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++) {
+
+            if (p.singleLayer) {
+                if ((!p.writeBinary) &amp;&amp; (j%6 == 0)) vtkFile &lt;&lt; endl 
+                    &lt;&lt; &quot;          &quot;;
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                var_target++;
+            } else {
+                for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++)
+                {
+                    if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) vtkFile &lt;&lt; endl 
+                        &lt;&lt; &quot;          &quot;;
+                    //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    var_target++;
+                    counter++;
+                }
+            }
+        }
+
+        // put out for extra cells
+        counter = 0;
+        for (int j = g.numCells + g.cellOffset; j &lt; g.currentExtraCell; j++) {
+            
+            var_target = cellVarData 
+                + (*(g.cellMap + j - g.numCells - g.cellOffset))
+                *g.maxNVertLevels;
+            if (p.singleLayer) {
+                if ((!p.writeBinary) &amp;&amp; (j%6 == 0)) 
+                    vtkFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+                //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+            } else {
+                for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++)
+                {
+                    if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) 
+                        vtkFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+                    //WriteFloat(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    WriteDouble(vtkb64, vtkFile, *var_target, p.writeBinary);
+                    var_target++;
+                    counter++;
+                }
+            }    
+        }
+
+        if (p.writeBinary) {
+            vtkb64.EndWriting();
+        }
+        vtkFile &lt;&lt; endl &lt;&lt;  &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
+
+    }
+
+    vtkFile &lt;&lt; &quot;      &lt;/CellData&gt;&quot; &lt;&lt; endl;
+
+    free(cellVarData);
+}
+
+
+void WriteVarData(ostringstream &amp;vtkFileName, int t, params &amp;p, geometry &amp;g,
+        vars &amp;v) 
+{
+    vtkFileName &lt;&lt; t &lt;&lt; p.outputFileName;
+    ofstream vtkFile(vtkFileName.str().c_str(), ios::out);
+    if (!vtkFile)
+    {
+        cerr &lt;&lt; &quot;vtk output file could not be opened&quot; &lt;&lt;endl;
+        exit(1);
+    }
+
+    vtkFile.precision(16);
+
+    vtkFile &lt;&lt; &quot;&lt;VTKFile type=\&quot;UnstructuredGrid\&quot; version=\&quot;0.1\&quot; byte_order=\&quot;LittleEndian\&quot;&gt;&quot; &lt;&lt; endl;
+    vtkFile &lt;&lt; &quot;  &lt;UnstructuredGrid&gt;&quot; &lt;&lt; endl;
+
+    vtkFile &lt;&lt; &quot;    &lt;Piece NumberOfPoints=\&quot;&quot; &lt;&lt; g.maxPoints &lt;&lt; &quot;\&quot; NumberOfCells=\&quot;&quot; &lt;&lt; g.maxCells  &lt;&lt; &quot;\&quot;&gt;&quot; &lt;&lt; endl; 
+
+    EncodeBase64 vtkb64(&amp;vtkFile);
+
+    WritePointVarData(vtkFile, vtkb64, t, p, g, v);
+    WriteCellVarData(vtkFile, vtkb64, t, p, g, v);
+
+    vtkFile.close();
+}
+
+
+int main(int argc, char* argv[])
+{
+    if (argc &lt; 3)   {
+        PrintUsage();
+        exit(1);
+    }
+
+    struct params p;
+    GetArgs(argc, argv, p);
+
+        NcFile ncFile(p.inputFileName);
+        if (!ncFile.is_valid()) 
+        {
+                cerr &lt;&lt; &quot;Couldn't open file: &quot; &lt;&lt; p.inputFileName &lt;&lt; endl;
+                exit(1);
+        }
+
+    // figure out geometry of a dual-grid lat/lon projection
+    geometry g;
+    GetNcDims(ncFile, g);
+    CheckArgs(p, g);
+    if (p.projectLatLon) {
+        AllocLatLonGeometry(ncFile, p, g);
+        ShiftLonData(p, g);
+        FixPoints(p, g);
+        EliminateXWrap(p, g);
+    } else {
+        AllocSphereGeometry(ncFile, p, g);
+    }
+        
+        // write a file with the geometry.
+        ostringstream geoFileName;
+    WriteGeometry(geoFileName, p, g); 
+    DeallocBasicGeometry(p, g);
+
+        // figure out what variables to visualize
+    vars v;
+    GetNcVars(ncFile, v, &quot;nVertices&quot;, &quot;nCells&quot;);
+
+    // For each timestep, write data for each variable
+        for (int t = p.startTimeStep; t &lt;= p.finishTimeStep; t++) {
+
+                ostringstream vtkFileName;
+
+        WriteVarData(vtkFileName, t, p, g, v);
+
+        // append geoFile to vtkFile
+        string geoFileNameString = geoFileName.str();
+        string vtkFileNameString = vtkFileName.str();
+        int appRetVal = AppendFile(&amp;geoFileNameString, &amp;vtkFileNameString);
+    }
+    
+    return(0);
+}
+


Property changes on: branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/x-c++src
Name: svn:keywords
   + Author Date ID Revision
Name: svn:eol-style
   + native

</font>
</pre>