<p><b>cahrens@lanl.gov</b> 2010-09-27 17:20:18 -0600 (Mon, 27 Sep 2010)</p><p>New version of mpasnc2vtu.cpp whic also can visualize primal sphere view (not latlon though).<br>
</p><hr noshade><pre><font color="gray">Modified: branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp
===================================================================
--- branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp        2010-09-24 22:57:36 UTC (rev 511)
+++ branches/ocean_projects/graphics/paraview/translator/mpasnc2vtu.cpp        2010-09-27 23:20:18 UTC (rev 512)
@@ -2,8 +2,8 @@
 // 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.
+// .vtu format for sphere and latlon views or a primal grid for sphere 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.
@@ -19,7 +19,7 @@
 //
 // Version 1.5
 // Christine Ahrens
-// 9/21/2010
+// 9/27/2010
 ////////////////////////////////////////////////////////////////////////////////
 
 
@@ -41,6 +41,7 @@
     bool projectLatLon;
     bool writeBinary;
     bool singleLayer;
+    bool showPrimalGrid;
     bool isAtmosphere;
     bool includeTopography;
     bool doBugFix;
@@ -57,26 +58,38 @@
 
 // points and cells refer to DUAL points and cells
 struct geometry {
+    // from .nc file
+    int nCells;
+    int nVertices;
+    int maxEdges;
     int nVertLevels;
     int maxNVertLevels;
     int Time;
+    int vertexDegree;
+
+    // computed values
     int numCells;
     int numPoints;
+    int modNumCells;
+    int modNumPoints;
     int cellOffset;
     int pointOffset;
     int pointsPerCell;
     int currentExtraPoint;  // current extra point
     int currentExtraCell;   // current extra  cell
+
+    // from .nc file
     double* pointX;      // x coord of point
     double* pointY;      // y coord of point
     double* pointZ;      // z coord of point
-    int modNumPoints;
-    int modNumCells;
+    int* nEdgesOnCell;
     int* origConnections;   // original connections
+
+    //computed values
     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* maxLevel;      // 
     int maxCells;           // max cells
     int maxPoints;          // max points
     int verticalIndex;      // for singleLayer, which vertical level
@@ -149,38 +162,6 @@
     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
@@ -245,15 +226,6 @@
     }
 }
 
-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));
@@ -283,8 +255,12 @@
     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;   -r           &quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       show primal grid (works only for sphere view) -- default is dual grid&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;       layer_thickness -- default is 10&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       For sphere view, 100000 is a good value to start with.&quot; &lt;&lt; endl;
+    cerr &lt;&lt; &quot;       For latlon view, 10 is a good value to start with.&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; 
@@ -299,7 +275,7 @@
     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;       include topography (assumes you have maxLevelCell 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;
@@ -331,6 +307,7 @@
     p.startTimeStep = 0;
     p.finishTimeStep = -1;
     p.projectLatLon = false;
+    p.showPrimalGrid = false;
 
     bool lflag = false;
     bool tflag = false;
@@ -339,7 +316,7 @@
     // -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) {
+    while ((c=getopt(argc, argv, &quot;l:t:c:mazrpxgbs:f:&quot;)) != -1) {
         switch(c) {
             case 'l':
                 lflag = true;
@@ -389,6 +366,9 @@
             case 'p':
                 p.projectLatLon = true;
                 break;
+            case 'r':
+                p.showPrimalGrid = true;
+                break;
             case 'g':
                 p.includeTopography = true;
                 break;
@@ -450,22 +430,20 @@
     }
 
 
-// put dims into dual grid geometry
+// put dims into 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;
+    g.nCells = nCells-&gt;size();
 
     CHECK_DIM(ncFile, &quot;nVertices&quot;);
     NcDim* nVertices = ncFile.get_dim(&quot;nVertices&quot;);
-    g.numCells = nVertices-&gt;size();
-    g.cellOffset = 0;
+    g.nVertices = nVertices-&gt;size();
 
     CHECK_DIM(ncFile, &quot;vertexDegree&quot;);
-    NcDim* vertexDegree = ncFile.get_dim(&quot;vertexDegree&quot;);
-    g.pointsPerCell = vertexDegree-&gt;size();
+    NcDim* vertexDegreeDim = ncFile.get_dim(&quot;vertexDegree&quot;);
+    g.vertexDegree = vertexDegreeDim-&gt;size();
 
     CHECK_DIM(ncFile, &quot;Time&quot;);
     NcDim* Time = ncFile.get_dim(&quot;Time&quot;);
@@ -476,16 +454,26 @@
     g.nVertLevels = nVertLevels-&gt;size();
 
     g.maxNVertLevels = g.nVertLevels;
+
+    CHECK_DIM(ncFile, &quot;maxEdges&quot;);
+    NcDim* maxEdgesDim = ncFile.get_dim(&quot;maxEdges&quot;);
+    g.maxEdges = maxEdgesDim-&gt;size();
+
 }
 
 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;
+        if ((g.vertexDegree != 3) &amp;&amp; (g.vertexDegree != 4))  {
+                cerr &lt;&lt; &quot;This code is only for grid with vertexDegree 3 or 4.&quot; &lt;&lt; endl;
                 exit(1);
         }
 
+    if (p.projectLatLon &amp;&amp; p.showPrimalGrid) {
+        cerr &lt;&lt; &quot;Cannot currently view latlon projection with primal grid.&quot; &lt;&lt; endl;
+        exit(1);
+    }
+
     // double-check we can do multilayer
     if ((!p.singleLayer) &amp;&amp; (g.maxNVertLevels == 1)) {
         p.singleLayer = true;
@@ -610,9 +598,79 @@
 
 }
 
+// allocate into sphere view of primal geometry
+void AllocPrimalSphereGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
+{
+    g.numPoints = g.nVertices;
+    g.numCells = g.nCells;
+    g.pointsPerCell = g.maxEdges;
+    g.pointOffset = 1;
+
+    CHECK_VAR(ncFile, &quot;xVertex&quot;);
+    g.pointX = (double*)malloc((g.numPoints+g.pointOffset) * sizeof(double));
+    CHECK_MALLOC(g.pointX);
+    NcVar*  xVar = ncFile.get_var(&quot;xVertex&quot;);
+    xVar-&gt;get(g.pointX + g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointX[0] = 0.0;
+
+    CHECK_VAR(ncFile, &quot;yVertex&quot;);
+    g.pointY = (double*)malloc((g.numPoints+g.pointOffset) * sizeof(double));
+    CHECK_MALLOC(g.pointY);
+    NcVar*  yVar = ncFile.get_var(&quot;yVertex&quot;);
+    yVar-&gt;get(g.pointY + g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointY[0] = 0.0;
+
+    CHECK_VAR(ncFile, &quot;zVertex&quot;);
+    g.pointZ = (double*)malloc((g.numPoints+g.pointOffset) * sizeof(double));
+    CHECK_MALLOC(g.pointZ);
+    NcVar*  zVar = ncFile.get_var(&quot;zVertex&quot;);
+    zVar-&gt;get(g.pointZ + g.pointOffset, g.numPoints);
+    // point 0 is 0.0
+    g.pointZ[0] = 0.0;
+
+    CHECK_VAR(ncFile, &quot;nEdgesOnCell&quot;);
+    g.nEdgesOnCell = (int *) malloc(g.numCells * sizeof(int));
+    CHECK_MALLOC(g.nEdgesOnCell);
+    NcVar *eVar = ncFile.get_var(&quot;nEdgesOnCell&quot;);
+    eVar-&gt;get(g.nEdgesOnCell, g.numCells);
+
+    CHECK_VAR(ncFile, &quot;verticesOnCell&quot;);
+    g.origConnections = (int*)malloc(sizeof(int) * g.pointsPerCell * g.numCells);
+    CHECK_MALLOC(g.origConnections);
+    NcVar *verticesOnCellVar = ncFile.get_var(&quot;verticesOnCell&quot;);
+    // We need to account for the 0th cell connections.
+    verticesOnCellVar-&gt;get(g.origConnections, g.numCells, g.pointsPerCell);
+
+    if (p.includeTopography) {
+        CHECK_VAR(ncFile, &quot;maxLevelCell&quot;);
+        g.maxLevel = (int*)malloc((g.numCells) * sizeof(int));
+        CHECK_MALLOC(g.maxLevel);
+        NcVar *maxLevelVar = ncFile.get_var(&quot;maxLevelCell&quot;);
+        maxLevelVar-&gt;get(g.maxLevel, g.numCells);
+    } 
+
+    g.currentExtraPoint = g.numPoints + g.pointOffset;
+    g.currentExtraCell = g.numCells;
+
+    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 sphere view of dual geometry
-void AllocSphereGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
+void AllocDualSphereGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
 {
+    g.numPoints = g.nCells;
+    g.pointOffset = 1;
+    g.numCells = g.nVertices;
+    g.pointsPerCell = g.vertexDegree;
+
     CHECK_VAR(ncFile, &quot;xCell&quot;);
         g.pointX = (double*)malloc((g.numPoints + g.pointOffset) * sizeof(double));
         CHECK_MALLOC(g.pointX);
@@ -646,14 +704,14 @@
 
     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.maxLevel = (int*)malloc((g.numPoints + g.pointOffset) * sizeof(int));
+        CHECK_MALLOC(g.maxLevel);
+        NcVar *maxLevelVar = ncFile.get_var(&quot;maxLevelCell&quot;);
+        maxLevelVar-&gt;get(g.maxLevel + g.pointOffset, g.numPoints);
     } 
 
     g.currentExtraPoint = g.numPoints + g.pointOffset;
-    g.currentExtraCell = g.numCells + g.cellOffset;
+    g.currentExtraCell = g.numCells;
 
     if (p.singleLayer) {
         g.maxCells = g.currentExtraCell;
@@ -667,6 +725,11 @@
 // allocate into lat/lon projection of dual geometry
 void AllocLatLonGeometry(NcFile &amp;ncFile, params &amp;p, geometry &amp;g)
 {
+    g.numPoints = g.nCells;
+    g.pointOffset = 1;
+    g.numCells = g.nVertices;
+    g.pointsPerCell = g.vertexDegree;
+
     const float BLOATFACTOR = .5;
         g.modNumPoints = (int)floor(g.numPoints*(1.0 + BLOATFACTOR));
         g.modNumCells = (int)floor(g.numCells*(1.0 + BLOATFACTOR))+1;
@@ -713,14 +776,14 @@
         CHECK_MALLOC(g.cellMap);
 
         g.currentExtraPoint = g.numPoints + g.pointOffset;
-        g.currentExtraCell = g.numCells + g.cellOffset;
+        g.currentExtraCell = g.numCells;
 
     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.maxLevel = (int*)malloc((g.numPoints + g.numPoints) * sizeof(int));
+        CHECK_MALLOC(g.maxLevel);
+        NcVar *maxLevelVar = ncFile.get_var(&quot;maxLevelCell&quot;);
+        maxLevelVar-&gt;get(g.maxLevel + g.pointOffset, g.numPoints);
     }
 }
 
@@ -782,15 +845,22 @@
 void FixPoints(params &amp;p, geometry &amp;g)
 {
 
-        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++ ) {
+        for (int j = 0; j &lt; g.numCells; 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++)  {
+        int pointsPer2DCell;
+        if (p.showPrimalGrid) {
+            pointsPer2DCell = g.nEdgesOnCell[j];
+        } else {
+            pointsPer2DCell = g.pointsPerCell;
+        }
+
+        for (int k = 0; k &lt; pointsPer2DCell; k++)  {
             if  ((conns[k] &lt;= 0) || (conns[k] &gt; g.numPoints)) {
-                for (int m = 0; m &lt; g.pointsPerCell; m++)  {
+                for (int m = 0; m &lt; pointsPer2DCell; m++)  {
                     conns[m] = 0;
                 }
                 break;
@@ -799,7 +869,7 @@
 
         int lastk;
 
-        if (p.doBugFix) {
+        if (p.doBugFix &amp;&amp; p.projectLatLon) {
             //BUG FIX for problem where cells are stretching to a faraway point
             lastk = g.pointsPerCell-1;
             const double thresh = .06981317007977; // 4 degrees
@@ -833,7 +903,7 @@
     int mirrorpoint;
 
 
-        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++ ) {
+        for (int j = 0; j &lt; g.numCells; j++ ) {
                 int *conns = g.origConnections + (j * g.pointsPerCell);
                 int *modConns = g.modConnections + (j * g.pointsPerCell);
         int lastk;
@@ -891,7 +961,7 @@
                                         addedConns[k] = neigh;
                                 }
                         }
-                        *(g.cellMap + (g.currentExtraCell - g.numCells - g.cellOffset)) = j;
+                        *(g.cellMap + (g.currentExtraCell - g.numCells)) = j;
                         g.currentExtraCell++;
                 } else {
 
@@ -937,7 +1007,6 @@
 
     // 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);
@@ -957,7 +1026,6 @@
         for (int j = 0; j &lt; g.currentExtraPoint; j++ )
         {
 
-                //float x, y, z;
                 double x, y, z;
 
         if (p.projectLatLon) {
@@ -1046,23 +1114,43 @@
     if (p.writeBinary) {
         geoFile &lt;&lt; &quot;          &quot;;
         b64.StartWriting();
-        int binarySize;
-        if (p.singleLayer) {
-           binarySize = g.maxCells*g.pointsPerCell*sizeof(int);
+
+        // figure out the binary size
+        int binarySize = 0;
+
+        // for primal grid, add up number of edges of each cell
+        if (p.showPrimalGrid) {
+
+            for (int j=0; j &lt; g.currentExtraCell; j++) {
+                binarySize += g.nEdgesOnCell[j];
+            }
+
+            binarySize *= sizeof(int);
+
+            if (!p.singleLayer) {
+                binarySize *= g.maxNVertLevels;
+            }
+
+        // otherwise compute based on set cell size
         } else {
-           binarySize = g.maxCells*g.pointsPerCell*2*sizeof(int);
+            binarySize = g.maxCells * g.pointsPerCell * sizeof(int);
         }
+
+        // if multilayer, mult by 2 since cells are 3D
+        if (!p.singleLayer) {
+           binarySize *= 2; 
+        }
+
         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
+    // For each cell,  list the points by number
 
     //cout &lt;&lt; &quot;Writing connectivity&quot; &lt;&lt; endl;
 
-    unsigned int val;
+    int val;
 
     for (int j = 0; j &lt; g.currentExtraCell ; j++) {
 
@@ -1079,23 +1167,36 @@
             int* connections;
 
             //check if it is a mirror cell, if so, get original
-            if (j &gt;= g.numCells + g.cellOffset) {
+            if (j &gt;= g.numCells) {
                 //cout &lt;&lt; &quot;setting origCell&quot; &lt;&lt; endl;
-                int origCellNum = *(g.cellMap + (j - g.numCells - g.cellOffset));
+                int origCellNum = *(g.cellMap + (j - g.numCells));
                 //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]]);
+            // if primal, just use maxLevel to determine the level of the cell
+            if (p.showPrimalGrid) {
+                minLevel = g.maxLevel[j];
+
+            // otherwise, take the min of the levels of the points of the cell    
+            } else {
+                //cout &lt;&lt; &quot;calc minLevel&quot; &lt;&lt; endl;
+                minLevel = g.maxLevel[conns[0]];
+                //cout &lt;&lt; &quot;initial minLevel:&quot; &lt;&lt; minLevel &lt;&lt; endl;
+                // Take the min of the maxLevelof each point 
+                for (int k = 1; k &lt; g.pointsPerCell; k++)  {
+                    minLevel = min(minLevel, g.maxLevel[connections[k]]);
+                }
             }
-            //cout &lt;&lt; endl;
         }
 
+        int pointsPer2DCell;
+        if (p.showPrimalGrid) {
+            pointsPer2DCell = g.nEdgesOnCell[j];
+        } else {
+            pointsPer2DCell = g.pointsPerCell;
+        }
+
         if (p.singleLayer) {
             if (!p.writeBinary) geoFile &lt;&lt; &quot;          &quot;;
 
@@ -1105,11 +1206,11 @@
             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++)  {
+                for (int k = 0; k &lt; pointsPer2DCell; k++)  {
                     WriteInt(b64, geoFile, val, p.writeBinary); 
                 }
             } else {
-                for (int k = 0; k &lt; g.pointsPerCell; k++)  {
+                for (int k = 0; k &lt; pointsPer2DCell; k++)  {
                     WriteInt(b64, geoFile, conns[k], p.writeBinary); 
                 }
             }
@@ -1124,21 +1225,27 @@
                 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++)  {
+                    for (int m = 0; m &lt; pointsPer2DCell*2; m++)  {
                         WriteInt(b64, geoFile, val, p.writeBinary); 
                     }
 
                 } else {
 
-                    for (int k = 0; k &lt; g.pointsPerCell; k++) 
+                    for (int k = 0; k &lt; pointsPer2DCell; k++) 
                     { 
                         val = (conns[k]*(g.maxNVertLevels+1)) + levelNum;
+                        if (false) {
+                            cout &lt;&lt; &quot;conn pt: &quot; &lt;&lt; (signed int)val &lt;&lt; &quot; j: &quot; &lt;&lt; j &lt;&lt; &quot; k: &quot; &lt;&lt; k &lt;&lt; &quot; levelNum: &quot; &lt;&lt; levelNum &lt;&lt; &quot; conns[k] = &quot; &lt;&lt; conns[k] &lt;&lt; endl;
+                        }
                         WriteInt(b64, geoFile, val, p.writeBinary); 
                     }
 
-                    for (int k = 0; k &lt; g.pointsPerCell; k++) 
+                    for (int k = 0; k &lt; pointsPer2DCell; k++) 
                     {                
                         val = (conns[k]*(g.maxNVertLevels+1)) + levelNum + 1;
+                        if (false) {
+                            cout &lt;&lt; &quot;conn pt: &quot; &lt;&lt; (signed int)val &lt;&lt; &quot; j: &quot; &lt;&lt; j &lt;&lt; &quot; k: &quot; &lt;&lt; k &lt;&lt; &quot; levelNum: &quot; &lt;&lt; levelNum &lt;&lt; &quot; conns[k] = &quot; &lt;&lt; conns[k] &lt;&lt; endl;
+                        }
                         WriteInt(b64, geoFile, val, p.writeBinary); 
                     }
                 }
@@ -1181,15 +1288,28 @@
     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;;
+    for (int j = 0; j &lt; g.currentExtraCell ; j++) {
+
+        int pointsPer2DCell;
+        if (p.showPrimalGrid) {
+            pointsPer2DCell = g.nEdgesOnCell[j];
+        } else {
+            pointsPer2DCell = g.pointsPerCell;
+        }
+
         if (p.singleLayer) {
-            offset += g.pointsPerCell;
+            if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+            offset += pointsPer2DCell;
+            WriteInt(b64, geoFile, offset, p.writeBinary); 
+            counter++;
         } else {
-            offset += 2*g.pointsPerCell;
+            for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+                offset += 2*pointsPer2DCell;
+                WriteInt(b64, geoFile, offset, p.writeBinary); 
+                counter++;
+            }
         }
-        WriteInt(b64, geoFile, offset, p.writeBinary); 
-        counter++;
     }
 
     if (p.writeBinary) {
@@ -1200,30 +1320,54 @@
     geoFile &lt;&lt; &quot;        &lt;/DataArray&gt;&quot; &lt;&lt; endl;
 }
 
+unsigned char GetCellType(int numPointsPer2DCell, bool make3D) {
 
-void WriteCellTypes(ofstream &amp;geoFile, EncodeBase64 &amp;b64,params &amp;p, geometry &amp;g)
-{
-    // write cell types 
     unsigned char cellType;
-    switch (g.pointsPerCell) {
+    switch (numPointsPer2DCell) {
         case 3:
-            if (p.singleLayer) {
+            if (!make3D) {
                 cellType = VTK_TRIANGLE;
             } else {
                 cellType = VTK_WEDGE;
             }
             break;
         case 4:
-            if (p.singleLayer) {
+            if (!make3D) {
                 cellType = VTK_QUAD;
             } else {
                 cellType = VTK_HEXAHEDRON;
             }
             break;
+        case 5:
+            if (!make3D) {
+                cellType = VTK_POLYGON;
+            } else {
+                cellType = VTK_PENTAGONAL_PRISM;
+            }
+            break;
+        case 6:
+            if (!make3D) {
+                cellType = VTK_POLYGON;
+            } else {
+                cellType = VTK_HEXAGONAL_PRISM;
+            }
+            break;
         default:
             break;
     }
+    return cellType;
+}
 
+
+void WriteCellTypes(ofstream &amp;geoFile, EncodeBase64 &amp;b64,params &amp;p, geometry &amp;g)
+{
+    // write cell types 
+    unsigned char cellType;
+
+    if (!p.showPrimalGrid) {
+        cellType = GetCellType(g.pointsPerCell, !p.singleLayer);
+    }
+
     string formatString;
     if (p.writeBinary) {
         formatString = &quot;binary&quot;;
@@ -1243,11 +1387,25 @@
         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;;
+    int counter = 0;
+
+    for (int j = 0; j &lt; g.currentExtraCell ; j++) {
+
+        if (p.showPrimalGrid) {
+            cellType = GetCellType(g.nEdgesOnCell[j], !p.singleLayer);
         }
-        WriteChar(b64, geoFile, cellType, p.writeBinary); 
+
+        if (p.singleLayer) {
+            if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+            WriteChar(b64, geoFile, cellType, p.writeBinary); 
+            counter++;
+        } else {
+            for (int levelNum = 0; levelNum &lt; g.maxNVertLevels; levelNum++) {
+                if ((!p.writeBinary) &amp;&amp; (counter%6 == 0)) geoFile &lt;&lt; endl &lt;&lt; &quot;          &quot;;
+                WriteChar(b64, geoFile, cellType, p.writeBinary); 
+                counter++;
+            }
+        }
     }
 
     if (p.writeBinary) b64.EndWriting();
@@ -1299,8 +1457,12 @@
     }
 
     if (p.includeTopography) {
-        free(g.maxLevelPoint);
+        free(g.maxLevel);
     }
+
+    if (p.showPrimalGrid) {
+        free(g.nEdgesOnCell);
+    }
 }
 
 
@@ -1341,7 +1503,6 @@
 
         // 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;
@@ -1350,7 +1511,6 @@
         vtkFile &lt;&lt; &quot;          &quot;;
 
         double *var_target;
-        //float validData;
         double validData;
 
         if (p.writeBinary) {
@@ -1368,20 +1528,17 @@
         // 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);
+            var_target = pointVarData + g.pointOffset; 
             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
@@ -1391,14 +1548,12 @@
         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++;
                 }
@@ -1406,7 +1561,6 @@
                 // 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++;
             }
@@ -1418,15 +1572,11 @@
             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++;
                 }
@@ -1434,7 +1584,6 @@
                 // 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);
             }
         }
@@ -1476,17 +1625,15 @@
     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);
+            v.cellVars[i]-&gt;get(cellVarData, 1, g.numCells,1);
         } else {
-            v.cellVars[i]-&gt;get(cellVarData + (g.cellOffset * g.maxNVertLevels),
-                    1, g.numCells, g.maxNVertLevels);
+            v.cellVars[i]-&gt;get(cellVarData, 1, g.numCells, g.maxNVertLevels);
         }
 
         if (p.writeBinary) {
@@ -1502,12 +1649,11 @@
         double *var_target = cellVarData;
         int counter = 0;
 
-        for (int j = g.cellOffset; j &lt; g.numCells + g.cellOffset; j++) {
+        for (int j = 0; j &lt; g.numCells; 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 {
@@ -1515,7 +1661,6 @@
                 {
                     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++;
@@ -1525,22 +1670,20 @@
 
         // put out for extra cells
         counter = 0;
-        for (int j = g.numCells + g.cellOffset; j &lt; g.currentExtraCell; j++) {
+        for (int j = g.numCells; j &lt; g.currentExtraCell; j++) {
             
             var_target = cellVarData 
-                + (*(g.cellMap + j - g.numCells - g.cellOffset))
+                + (*(g.cellMap + j - g.numCells))
                 *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++;
@@ -1608,6 +1751,7 @@
     // 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);
@@ -1615,7 +1759,12 @@
         FixPoints(p, g);
         EliminateXWrap(p, g);
     } else {
-        AllocSphereGeometry(ncFile, p, g);
+        if (p.showPrimalGrid) {
+            AllocPrimalSphereGeometry(ncFile, p, g);
+        } else {
+            AllocDualSphereGeometry(ncFile, p, g);
+        }
+        FixPoints(p, g);
     }
         
         // write a file with the geometry.
@@ -1625,7 +1774,11 @@
 
         // figure out what variables to visualize
     vars v;
-    GetNcVars(ncFile, v, &quot;nVertices&quot;, &quot;nCells&quot;);
+    if (p.showPrimalGrid) {
+       GetNcVars(ncFile, v, &quot;nCells&quot;, &quot;nVertices&quot;);
+    } else {
+       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++) {

</font>
</pre>