[MOAB-dev] commit/MOAB: 16 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon Jul 1 17:32:18 CDT 2013


16 new commits in MOAB:

https://bitbucket.org/fathomteam/moab/commits/00e8666eaab6/
Changeset:   00e8666eaab6
Branch:      None
User:        danwu
Date:        2013-06-05 20:23:11
Summary:     Merged fathomteam/moab into master
Affected #:  0 files



https://bitbucket.org/fathomteam/moab/commits/45d3b4be81ba/
Changeset:   45d3b4be81ba
Branch:      None
User:        danwu
Date:        2013-06-05 22:12:43
Summary:     Merged fathomteam/moab into master
Affected #:  1 file

diff --git a/test/io/read_nc.cpp b/test/io/read_nc.cpp
index 0e5af72..558958c 100644
--- a/test/io/read_nc.cpp
+++ b/test/io/read_nc.cpp
@@ -4,74 +4,240 @@
 using namespace moab;
=20
 #ifdef MESHDIR
-static const char example[] =3D STRINGIFY(MESHDIR) "/io/camEul26x48x96.t3.=
nc";
+static const char example_eul[] =3D STRINGIFY(MESHDIR) "/io/camEul26x48x96=
.t3.nc";
+static const char example_fv[] =3D STRINGIFY(MESHDIR) "/io/fv26x46x72.t.3.=
nc";
 #else
-static const char example[] =3D "/io/camEul26x48x96.t3.nc";
+static const char example_eul[] =3D "/io/camEul26x48x96.t3.nc";
+static const char example_fv[] =3D "/io/fv26x46x72.t.3.nc";
 #endif
=20
 #ifdef USE_MPI
 #include "moab_mpi.h"
 #endif
=20
-void read_file( Interface& moab, const char* input_file );
-void test_read_all();
-void test_read_onevar();
-void test_read_onetimestep();
-void test_read_nomesh();
-void test_read_novars();
-ErrorCode get_options(std::string &opts);
+// CAM-EUL
+void test_read_eul_all();
+void test_read_eul_onevar();
+void test_read_eul_onetimestep();
+void test_read_eul_nomesh();
+void test_read_eul_novars();
=20
-int main(int argc, char *argv[])
+// CAM-FV
+void test_read_fv_all();
+void test_read_fv_onevar();
+void test_read_fv_onetimestep();
+void test_read_fv_nomesh();
+void test_read_fv_novars();
+
+ErrorCode get_options(std::string& opts);
+
+int main(int argc, char* argv[])
 {
   int result =3D 0;
=20
 #ifdef USE_MPI
   int fail =3D MPI_Init(&argc, &argv);
-  if (fail) return 1;
+  if (fail)
+    return 1;
 #else
-  argv[0]=3Dargv[argc-argc];// to remove the warnings in serial mode about=
 unused variables
+  argv[0] =3D argv[argc - argc]; // to remove the warnings in serial mode =
about unused variables
 #endif
- =20
-  result +=3D RUN_TEST(test_read_all);
-  result +=3D RUN_TEST(test_read_onevar);
-  result +=3D RUN_TEST(test_read_onetimestep);
-  result +=3D RUN_TEST(test_read_nomesh);
-  result +=3D RUN_TEST(test_read_novars);
- =20
+
+  result +=3D RUN_TEST(test_read_eul_all);
+  result +=3D RUN_TEST(test_read_eul_onevar);
+  result +=3D RUN_TEST(test_read_eul_onetimestep);
+  result +=3D RUN_TEST(test_read_eul_nomesh);
+  result +=3D RUN_TEST(test_read_eul_novars);
+
+  // Exclude test_read_fv_all() since reading edge data is not implemented=
 in MOAB yet
+  //result +=3D RUN_TEST(test_read_fv_all);
+  result +=3D RUN_TEST(test_read_fv_onevar);
+  result +=3D RUN_TEST(test_read_fv_onetimestep);
+  result +=3D RUN_TEST(test_read_fv_nomesh);
+  result +=3D RUN_TEST(test_read_fv_novars);
+
 #ifdef USE_MPI
   fail =3D MPI_Finalize();
   if (fail) return 1;
 #endif
- =20
+
   return result;
 }
=20
+void test_read_eul_all()
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
+
+  rval =3D mb.load_file(example_eul, NULL, opts.c_str());
+  CHECK_ERR(rval);
=20
-void test_read_all()
+    // check for proper tags
+  Tag Ttag0, Ttag1, coordTag;
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("COORDS", 3, MB_TYPE_DOUBLE, coordTag);
+  CHECK_ERR(rval);
+}
+
+void test_read_eul_onevar()=20
 {
   Core moab;
   Interface& mb =3D moab;
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
=20
+  opts +=3D std::string(";VARIABLE=3DT");
+  rval =3D mb.load_file(example_eul, NULL, opts.c_str());
+  CHECK_ERR(rval);
+
+    // check for proper tags
+  Tag Ttag0, Ttag1;
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_eul_onetimestep()
+{
+  Core moab;
+  Interface& mb =3D moab;
   std::string opts;
   ErrorCode rval =3D get_options(opts);
   CHECK_ERR(rval);
- =20
-  rval =3D mb.load_file( example, NULL, opts.c_str());
+
+  opts +=3D std::string(";VARIABLE=3DT;TIMESTEP=3D1");
+  rval =3D mb.load_file(example_eul, NULL, opts.c_str());
   CHECK_ERR(rval);
- =20
+
+    // check for proper tags
+  Tag Ttag0, Ttag1;
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_eul_nomesh()=20
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+    // need a set for nomesh to work right
+  EntityHandle set;
+  ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
+  CHECK_ERR(rval);
+
+  std::string orig, opts;
+  rval =3D get_options(orig);
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D0");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+    // check for proper tag
+  Tag Ttag0, Ttag1;
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+    // now read 2nd timestep with nomesh option
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+    // check for proper tag
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_eul_novars()=20
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+    // need a set for nomesh to work right
+  EntityHandle set;
+  ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
+  CHECK_ERR(rval);
+
+  std::string orig, opts;
+  rval =3D get_options(orig);
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";NOMESH;VARIABLE=3D");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";VARIABLE=3D;TIMESTEP=3D0");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+    // check for proper tag
+  Tag Ttag0, Ttag1;
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D0;NOMESH");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
+  CHECK_ERR(rval);
+
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+    // now read 2nd timestep with nomesh option
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example_eul, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+    // check for proper tag
+  rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_fv_all()
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
+
+  rval =3D mb.load_file(example_fv, NULL, opts.c_str());
+  CHECK_ERR(rval);
+
     // check for proper tags
   Tag Ttag0, Ttag1, coordTag;
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_ERR(rval);
- =20
+
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_ERR(rval);
=20
-  rval=3Dmb.tag_get_handle("COORDS", 3 ,MB_TYPE_DOUBLE, coordTag);
+  rval=3Dmb.tag_get_handle("COORDS", 3, MB_TYPE_DOUBLE, coordTag);
   CHECK_ERR(rval);
 }
=20
-void test_read_onevar()=20
+void test_read_fv_onevar()=20
 {
   Core moab;
   Interface& mb =3D moab;
@@ -80,19 +246,19 @@ void test_read_onevar()
   CHECK_ERR(rval);
=20
   opts +=3D std::string(";VARIABLE=3DT");
-  rval =3D mb.load_file( example, NULL, opts.c_str());
+  rval =3D mb.load_file(example_fv, NULL, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tags
   Tag Ttag0, Ttag1;
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_ERR(rval);
- =20
+
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_ERR(rval);
 }
=20
-void test_read_onetimestep()
+void test_read_fv_onetimestep()
 {
   Core moab;
   Interface& mb =3D moab;
@@ -100,20 +266,20 @@ void test_read_onetimestep()
   ErrorCode rval =3D get_options(opts);
   CHECK_ERR(rval);
=20
-  opts +=3D std::string(";TIMESTEP=3D1");
-  rval =3D mb.load_file( example, NULL, opts.c_str() );
+  opts +=3D std::string(";VARIABLE=3DT;TIMESTEP=3D1");
+  rval =3D mb.load_file(example_fv, NULL, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tags
   Tag Ttag0, Ttag1;
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
- =20
+
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_ERR(rval);
 }
=20
-void test_read_nomesh()=20
+void test_read_fv_nomesh()=20
 {
   Core moab;
   Interface& mb =3D moab;
@@ -122,34 +288,34 @@ void test_read_nomesh()
   EntityHandle set;
   ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
   CHECK_ERR(rval);
- =20
+
   std::string orig, opts;
   rval =3D get_options(orig);
   CHECK_ERR(rval);
=20
-  opts =3D orig + std::string(";TIMESTEP=3D0");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D0");
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tag
   Tag Ttag0, Ttag1;
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_ERR(rval);
- =20
+
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
=20
     // now read 2nd timestep with nomesh option
-  opts =3D orig + std::string(";TIMESTEP=3D1;NOMESH");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tag
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_ERR(rval);
 }
=20
-void test_read_novars()=20
+void test_read_fv_novars()=20
 {
   Core moab;
   Interface& mb =3D moab;
@@ -158,28 +324,28 @@ void test_read_novars()
   EntityHandle set;
   ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
   CHECK_ERR(rval);
- =20
+
   std::string orig, opts;
   rval =3D get_options(orig);
   CHECK_ERR(rval);
=20
   opts =3D orig + std::string(";NOMESH;VARIABLE=3D");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
   opts =3D orig + std::string(";VARIABLE=3D;TIMESTEP=3D0");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tag
   Tag Ttag0, Ttag1;
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
- =20
+
   opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D0;NOMESH");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
   rval =3D mb.tag_get_handle("T0", 26, MB_TYPE_DOUBLE, Ttag0);
   CHECK_ERR(rval);
=20
@@ -187,16 +353,16 @@ void test_read_novars()
   CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
=20
     // now read 2nd timestep with nomesh option
-  opts =3D orig + std::string(";TIMESTEP=3D1;NOMESH");
-  rval =3D mb.load_file( example, &set, opts.c_str() );
+  opts =3D orig + std::string(";VARIABLE=3DT;TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example_fv, &set, opts.c_str());
   CHECK_ERR(rval);
- =20
+
     // check for proper tag
   rval =3D mb.tag_get_handle("T1", 26, MB_TYPE_DOUBLE, Ttag1);
   CHECK_ERR(rval);
 }
=20
-ErrorCode get_options(std::string &opts)=20
+ErrorCode get_options(std::string& opts)=20
 {
 #ifdef USE_MPI
     // use parallel options


https://bitbucket.org/fathomteam/moab/commits/48b6301dbdaa/
Changeset:   48b6301dbdaa
Branch:      None
User:        danwu
Date:        2013-06-05 22:50:20
Summary:     Merged fathomteam/moab into master
Affected #:  1 file

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 6490b24..32faa58 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -34,7 +34,7 @@ bool NCHelperHOMME::can_read_file(ReadNC* readNC, int fil=
eId)
   // If global attribute "np" exists then it should be the HOMME grid
   if (readNC->globalAtts.find("np") !=3D readNC->globalAtts.end()) {
     // Make sure it is CAM grid
-	std::map<std::string, ReadNC::AttData>::iterator attIt =3D readNC->global=
Atts.find("source");
+    std::map<std::string, ReadNC::AttData>::iterator attIt =3D readNC->glo=
balAtts.find("source");
     if (attIt =3D=3D readNC->globalAtts.end()) {
       readNC->readMeshIface->report_error("%s", "File does not have source=
 global attribute.");
       return false;


https://bitbucket.org/fathomteam/moab/commits/0146d4671191/
Changeset:   0146d4671191
Branch:      None
User:        danwu
Date:        2013-06-11 21:54:56
Summary:     Update enum EntityLocation, and change ReadNC and the helpers =
accordingly.

Affected #:  9 files

diff --git a/src/io/NCHelper.hpp b/src/io/NCHelper.hpp
index 852fc61..16f2a3c 100644
--- a/src/io/NCHelper.hpp
+++ b/src/io/NCHelper.hpp
@@ -22,7 +22,7 @@ public:
   static NCHelper* get_nc_helper(ReadNC* readNC, int fileId, const FileOpt=
ions& opts);
=20
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set) =3D 0;
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads) =3D 0;
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces) =3D 0;
   virtual std::string get_mesh_type_name() =3D 0;
   virtual bool is_scd_mesh() =3D 0;
=20

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index a01d4b8..cac789c 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -343,7 +343,7 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.va=
rDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCQUAD;
+      vd.entLoc =3D ReadNC::ENTLOCFACE;
   }
=20
   // <coordinate_dim_name>
@@ -473,9 +473,9 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperEuler::create_verts_quads(ScdInterface* scdi, const File=
Options& opts, EntityHandle file_set, Range& quads)
+ErrorCode NCHelperEuler::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& faces)
 {
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
+  return _readNC->create_scd_verts_quads(scdi, file_set, faces);
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelperEuler.hpp b/src/io/NCHelperEuler.hpp
index b1c4c21..6bf2a51 100644
--- a/src/io/NCHelperEuler.hpp
+++ b/src/io/NCHelperEuler.hpp
@@ -24,7 +24,7 @@ public:
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
=20
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
=20
   virtual std::string get_mesh_type_name() { return "CAM_EUL"; }
=20

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index 566b719..9bb5564 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -333,7 +333,7 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.va=
rDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCQUAD;
+      vd.entLoc =3D ReadNC::ENTLOCFACE;
     else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=3D v=
d.varDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
       vd.entLoc =3D ReadNC::ENTLOCNSEDGE;
@@ -469,9 +469,9 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperFV::create_verts_quads(ScdInterface* scdi, const FileOpt=
ions& opts, EntityHandle file_set, Range& quads)
+ErrorCode NCHelperFV::create_mesh(ScdInterface* scdi, const FileOptions& o=
pts, EntityHandle file_set, Range& faces)
 {
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
+  return _readNC->create_scd_verts_quads(scdi, file_set, faces);
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelperFV.hpp b/src/io/NCHelperFV.hpp
index afcd9b8..0a1ba76 100644
--- a/src/io/NCHelperFV.hpp
+++ b/src/io/NCHelperFV.hpp
@@ -22,7 +22,7 @@ public:
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
   virtual std::string get_mesh_type_name() { return "CAM_FV"; }
   virtual bool is_scd_mesh() { return true; }
 };

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 32faa58..6f6b102 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -180,7 +180,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iDim) !=3D vd.var=
Dims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), kDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCNODE;
+      vd.entLoc =3D ReadNC::ENTLOCVERT;
   }
=20
   std::copy(gDims, gDims + 6, lDims);
@@ -199,7 +199,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperHOMME::create_verts_quads(ScdInterface* scdi, const File=
Options& opts, EntityHandle file_set, Range& quads)
+ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& quads)
 {
   Interface*& mbImpl =3D _readNC->mbImpl;
   std::string& fileName =3D _readNC->fileName;

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index feb3cad..827c39f 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -22,7 +22,7 @@ public:
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& elems);
   virtual std::string get_mesh_type_name() { return "CAM_SE"; }
   virtual bool is_scd_mesh() { return false; }
=20

diff --git a/src/io/ReadNC.cpp b/src/io/ReadNC.cpp
index 514f724..5e7eaf2 100644
--- a/src/io/ReadNC.cpp
+++ b/src/io/ReadNC.cpp
@@ -205,15 +205,15 @@ ErrorCode ReadNC::load_file(const char *file_name, co=
nst EntityHandle* file_set,
   rval =3D myHelper->init_mesh_vals(opts, tmp_set);
   ERRORR(rval, "Trouble initializing mesh values.");
=20
-  // Create mesh vertex/quads sequences
-  Range quads;
+  // Create mesh vertex/edge/face sequences
+  Range faces;
   if (noMesh && !noVars) {
-    rval =3D check_verts_quads(tmp_set);
+    rval =3D check_verts_faces(tmp_set);
     ERRORR(rval, "Mesh characteristics didn't match from last read.\n");
   }
   else if (!noMesh) {
-    rval =3D myHelper->create_verts_quads(scdi, opts, tmp_set, quads);
-    ERRORR(rval, "Trouble creating vertices and quads.");
+    rval =3D myHelper->create_mesh(scdi, opts, tmp_set, faces);
+    ERRORR(rval, "Trouble creating mesh.");
   }
=20
   bool scd_mesh =3D myHelper->is_scd_mesh();
@@ -244,21 +244,21 @@ ErrorCode ReadNC::load_file(const char *file_name, co=
nst EntityHandle* file_set,
     rval =3D mbImpl->create_meshset(MESHSET_SET, partn_set);
     ERRORR(rval, "Trouble creating partition set.");
=20
-    rval =3D mbImpl->add_entities(partn_set,quads);
-    ERRORR(rval, "Couldn't add new quads to partition set.");
+    rval =3D mbImpl->add_entities(partn_set, faces);
+    ERRORR(rval, "Couldn't add new faces to partition set.");
=20
     Range verts;
-    rval =3D mbImpl->get_connectivity(quads, verts);
-    ERRORR(rval, "Couldn't get verts of quads");
+    rval =3D mbImpl->get_connectivity(faces, verts);
+    ERRORR(rval, "Couldn't get verts of faces");
=20
-    rval =3D mbImpl->add_entities(partn_set,verts);
+    rval =3D mbImpl->add_entities(partn_set, verts);
     ERRORR(rval, "Couldn't add new verts to partition set.");
=20
     myPcomm->partition_sets().insert(partn_set);
=20
     //write partition tag name on partition set
     Tag part_tag;
-    rval =3D mbImpl->tag_get_handle( partitionTagName.c_str(), 1, MB_TYPE_=
INTEGER, part_tag );
+    rval =3D mbImpl->tag_get_handle(partitionTagName.c_str(), 1, MB_TYPE_I=
NTEGER, part_tag);
     if (MB_SUCCESS !=3D rval) {
       // fall back to the partition tag
       part_tag =3D myPcomm->partition_tag();
@@ -266,12 +266,13 @@ ErrorCode ReadNC::load_file(const char *file_name, co=
nst EntityHandle* file_set,
=20
     int dum_rank =3D myPcomm->proc_config().proc_rank();
     rval =3D mbImpl->tag_set_data(part_tag, &partn_set, 1, &dum_rank);
-    if (MB_SUCCESS !=3D rval) return rval;
+    if (MB_SUCCESS !=3D rval)
+      return rval;
   }
 #endif
=20
   mbImpl->release_interface(scdi);
-  ERRORR(rval, "Trouble creating scd element sequence.");
+  ERRORR(rval, "Trouble creating element sequence.");
=20
   // create nc conventional tags when loading header info only
   if (noMesh && noVars) {
@@ -476,7 +477,7 @@ ErrorCode ReadNC::check_ucd_localGid(EntityHandle tmp_s=
et)
   return MB_SUCCESS;
 }
=20
-ErrorCode ReadNC::check_verts_quads(EntityHandle file_set) {
+ErrorCode ReadNC::check_verts_faces(EntityHandle file_set) {
   // check parameters on this read against what was on the mesh from last =
read
   // get the number of vertices
   int num_verts;
@@ -702,10 +703,8 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle =
file_set, std::vector<VarD
=20
   std::vector<EntityHandle>* ehandles =3D NULL;
   Range* range =3D NULL;
-  //std::vector<EntityHandle> verts_handles;
   std::vector<EntityHandle> ns_edges_handles;
   std::vector<EntityHandle> ew_edges_handles;
-  //std::vector<EntityHandle> quads_handles;
=20
   // get vertices in set
   Range verts;
@@ -713,8 +712,6 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle f=
ile_set, std::vector<VarD
   ERRORR(rval, "Trouble getting vertices in set.");
   assert("Should only have a single vertex subrange, since they were read =
in one shot" &&
       verts.psize() =3D=3D 1);
-  //verts_handles.resize(verts.size());
-  //std::copy(verts.begin(), verts.end(), verts_handles.begin());
=20
   Range edges;
   rval =3D mbImpl->get_entities_by_dimension(file_set, 1, edges);
@@ -730,25 +727,22 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle=
 file_set, std::vector<VarD
   // FIXME: initialize ew_edges_handles to get the right order
   //std::copy(edges.begin(), edges.end(), ew_edges_handles.begin());
=20
-  // get quads in set
-  Range quads;
-  rval =3D mbImpl->get_entities_by_dimension(file_set, 2, quads);
-  ERRORR(rval, "Trouble getting quads in set.");
-  assert("Should only have a single quad subrange, since they were read in=
 one shot" &&
-      quads.psize() =3D=3D 1);
-  //quads_handles.resize(quads.size());
-  //std::copy(quads.begin(), quads.end(), quads_handles.begin());
+  // get faces in set
+  Range faces;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 2, faces);
+  ERRORR(rval, "Trouble getting faces in set.");
+  assert("Should only have a single face subrange, since they were read in=
 one shot" &&
+      faces.psize() =3D=3D 1);
=20
 #ifdef USE_MPI
-  moab::Range quads_owned;
+  moab::Range faces_owned;
   if (isParallel)
   {
-    rval =3D myPcomm->filter_pstatus(quads, PSTATUS_NOT_OWNED, PSTATUS_NOT=
, -1,
-      &quads_owned);
-    ERRORR(rval, "Trouble getting owned quads in set.");
+    rval =3D myPcomm->filter_pstatus(faces, PSTATUS_NOT_OWNED, PSTATUS_NOT=
, -1, &faces_owned);
+    ERRORR(rval, "Trouble getting owned faces in set.");
   }
   else
-    quads_owned=3Dquads;// not running in parallel, but still with MPI
+    faces_owned =3D faces; // not running in parallel, but still with MPI
 #endif
=20
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
@@ -793,7 +787,7 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle f=
ile_set, std::vector<VarD
       }
=20
       switch (vdatas[i].entLoc) {
-        case 0:
+        case ENTLOCVERT:
           // vertices
           if (scd_mesh) {
             // only structured mesh has j parameter that multiplies i to g=
et total # vertices
@@ -806,14 +800,14 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle=
 file_set, std::vector<VarD
           {
             // we will start from the first localGid, actually; we will re=
set that
             // later on, anyway, in a loop
-            vdatas[i].readDims[t].push_back(localGid[0]-1);
+            vdatas[i].readDims[t].push_back(localGid[0] - 1);
             vdatas[i].readCounts[t].push_back(localGid.size());
           }
=20
           assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
           range =3D &verts;
           break;
-        case 1:
+        case ENTLOCNSEDGE:
           // north/south edges
           /*
            vdatas[i].readDims[t].push_back(lDims[1]);
@@ -826,10 +820,9 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle =
file_set, std::vector<VarD
            ehandles =3D &ns_edges_handles;
            range =3D &verts; // FIXME: should remove when edge handles are=
 used
            */
-          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.")
-          ;
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
           break;
-        case 2:
+        case ENTLOCEWEDGE:
           // east/west edges
           /*
            vdatas[i].readDims[t].push_back(lCDims[1]);
@@ -847,11 +840,10 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle=
 file_set, std::vector<VarD
            ehandles =3D &ew_edges_handles;
            range =3D &verts; // FIXME: should remove when edge handles are=
 used
            */
-          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.")
-          ;
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
           break;
-        case 3:
-          // quads
+        case ENTLOCFACE:
+          // faces
           vdatas[i].readDims[t].push_back(lCDims[1]);
           vdatas[i].readDims[t].push_back(lCDims[0]);
           vdatas[i].readCounts[t].push_back(lCDims[4] - lCDims[1] + 1);
@@ -859,17 +851,22 @@ ErrorCode ReadNC::read_variable_allocate(EntityHandle=
 file_set, std::vector<VarD
           assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
=20
 #ifdef USE_MPI
-          range =3D &quads_owned;
+          range =3D &faces_owned;
 #else
-          range =3D &quads;
+          range =3D &faces;
 #endif
           break;
-        case 4:
-          // set
+        case ENTLOCSET:
+          // sets
+          break;
+        case ENTLOCEDGE:
+          // edges
+          break;
+        case ENTLOCREGION:
+          // regions
           break;
         default:
-          ERRORR(MB_FAILURE, "Unrecoganized entity location type.")
-          ;
+          ERRORR(MB_FAILURE, "Unrecoganized entity location type.");
           break;
       }
=20
@@ -925,7 +922,7 @@ ErrorCode ReadNC::read_variables(EntityHandle file_set,=
 std::vector<std::string>
 #endif
       rval =3D read_variable_to_nonset(file_set, vdatas, tstep_nums, scd_m=
esh);
=20
-    ERRORR(rval, "Trouble read variables to entities verts/edges/quads.");
+    ERRORR(rval, "Trouble read variables to entities verts/edges/faces.");
   }
=20
   return MB_SUCCESS;
@@ -1029,14 +1026,12 @@ ErrorCode ReadNC::read_variable_to_set(EntityHandle=
 file_set, std::vector<VarDat
         case NC_CHAR:
           success =3D NCFUNCAG(_vara_text)(fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               (char*) data NCREQ);
-          ERRORS(success, "Failed to read char data.")
-          ;
+          ERRORS(success, "Failed to read char data.");
           break;
         case NC_DOUBLE:
           success =3D NCFUNCAG(_vara_double)(fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               (double*) data NCREQ);
-          ERRORS(success, "Failed to read double data.")
-          ;
+          ERRORS(success, "Failed to read double data.");
           break;
         case NC_FLOAT: {
           success =3D NCFUNCAG(_vara_float)(fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
@@ -1047,14 +1042,12 @@ ErrorCode ReadNC::read_variable_to_set(EntityHandle=
 file_set, std::vector<VarDat
         case NC_INT:
           success =3D NCFUNCAG(_vara_int)(fileId, vdatas[i].varId, &vdatas=
[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               (int*) data NCREQ);
-          ERRORS(success, "Failed to read int data.")
-          ;
+          ERRORS(success, "Failed to read int data.");
           break;
         case NC_SHORT:
           success =3D NCFUNCAG(_vara_short)(fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               (short*) data NCREQ);
-          ERRORS(success, "Failed to read short data.")
-          ;
+          ERRORS(success, "Failed to read short data.");
           break;
         default:
           success =3D 1;
@@ -1122,7 +1115,7 @@ ErrorCode ReadNC::read_variable_to_nonset(EntityHandl=
e file_set, std::vector<Var
       }
       else {
         sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
-        nj =3D 1; // for ucdMesh, nj holds # quads, so here should reset t=
o 1
+        nj =3D 1; // for ucdMesh, nj holds # faces, so here should reset t=
o 1
       }
=20
       switch (vdatas[i].varDataType) {
@@ -1174,12 +1167,11 @@ ErrorCode ReadNC::read_variable_to_nonset(EntityHan=
dle file_set, std::vector<Var
             // assume that the last dimension is for the ncol,
             // node varying variable
=20
-            size_t indexInFloatArray=3D 0;
-            size_t ic=3D0;
-            for (
-                Range::pair_iterator pair_iter =3D localGid.pair_begin();
-                pair_iter!=3DlocalGid.pair_end();
-                pair_iter++, ic++)
+            size_t indexInFloatArray =3D 0;
+            size_t ic =3D 0;
+            for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+                 pair_iter!=3DlocalGid.pair_end();
+                 pair_iter++, ic++)
             {
               EntityHandle starth =3D pair_iter->first;
               EntityHandle endh =3D pair_iter->second;// inclusive
@@ -1192,9 +1184,9 @@ ErrorCode ReadNC::read_variable_to_nonset(EntityHandl=
e file_set, std::vector<Var
               ERRORS(success, "Failed to read float data in loop");
               // we need to increment the index in float array for the
               // next subrange
-              indexInFloatArray+=3D (endh-starth+1)*1*vdatas[i].numLev; //
+              indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].n=
umLev;
             }
-            assert(ic=3D=3DlocalGid.psize());
+            assert(ic =3D=3D localGid.psize());
             //
           }
           if (vdatas[i].numLev !=3D 1)
@@ -1293,10 +1285,10 @@ ErrorCode ReadNC::read_variable_to_nonset_async(Ent=
ityHandle file_set, std::vect
       size_t nk =3D vdatas[i].readCounts[t][1];
=20
       sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
-      size_t nj =3D 1; // for ucdMesh, nj holds # quads, so here should re=
set to 1
+      size_t nj =3D 1; // for ucdMesh, nj holds # faces, so here should re=
set to 1
=20
-      if (sz<=3D0)
-        continue;// nothing to read, why worry?
+      if (sz <=3D 0)
+        continue; // nothing to read, why worry?
=20
       switch (vdatas[i].varDataType) {
         case NC_BYTE:
@@ -1317,17 +1309,16 @@ ErrorCode ReadNC::read_variable_to_nonset_async(Ent=
ityHandle file_set, std::vect
           // assume that the last dimension is for the ncol,
           // node varying variable
=20
-          size_t indexInDoubleArray=3D 0;
-          size_t ic=3D0;
-          for (
-              Range::pair_iterator pair_iter =3D localGid.pair_begin();
-              pair_iter!=3DlocalGid.pair_end();
-              pair_iter++, ic++)
+          size_t indexInDoubleArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+               pair_iter!=3DlocalGid.pair_end();
+               pair_iter++, ic++)
           {
             EntityHandle starth =3D pair_iter->first;
-            EntityHandle endh =3D pair_iter->second;// inclusive
-            vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth-1);
-            vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh-starth=
+1);
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
=20
             // do a partial read, in each subrange
             // wait outside this loop
@@ -1337,7 +1328,7 @@ ErrorCode ReadNC::read_variable_to_nonset_async(Entit=
yHandle file_set, std::vect
             ERRORS(success, "Failed to read double data in loop");
             // we need to increment the index in float array for the
             // next subrange
-            indexInDoubleArray+=3D (endh-starth+1)*1*vdatas[i].numLev; //
+            indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
           }
           assert(ic=3D=3DlocalGid.psize());
           //
@@ -1525,7 +1516,7 @@ ErrorCode ReadNC::convert_variable(VarData &var_data,=
 int tstep_num, bool scd_me
=20
 ErrorCode ReadNC::get_tag_to_set(VarData &var_data, int tstep_num, Tag &ta=
gh) {
   std::ostringstream tag_name;
-  if ((!var_data.has_t)||( var_data.varDims.size()<=3D1))
+  if ((!var_data.has_t) || (var_data.varDims.size() <=3D 1))
     tag_name << var_data.varName;
   else if (!tstep_num) {
     std::string tmp_name =3D var_data.varName + "0";
@@ -1597,10 +1588,10 @@ void ReadNC::init_dims_with_no_cvars_info() {
   // hack: look at all dimensions, and see if we have one that does not ap=
pear in the list of varInfo names
   // right now, candidates are ncol and nbnd
   // for them, create dummy tags
-  for (unsigned int i=3D0; i<dimNames.size(); i++)
+  for (unsigned int i =3D 0; i < dimNames.size(); i++)
   {
     // if there is a var with this name, skip, we are fine; if not, create=
 a varInfo...
-    if ( varInfo.find(dimNames[i])!=3DvarInfo.end())
+    if (varInfo.find(dimNames[i]) !=3D varInfo.end())
       continue; // we already have a variable with this dimension name
=20
     int sizeTotalVar =3D varInfo.size();
@@ -1677,7 +1668,6 @@ ErrorCode ReadNC::read_header() {
 }
=20
 ErrorCode ReadNC::get_attributes(int var_id, int num_atts, std::map<std::s=
tring, AttData> &atts, const char *prefix) {
-
   char dum_name[120];
=20
   for (int i =3D 0; i < num_atts; i++) {
@@ -1783,7 +1773,6 @@ ErrorCode ReadNC::get_variables() {
=20
     ErrorCode rval =3D get_attributes(i, data.numAtts, data.varAtts, "   "=
);
     ERRORR(rval, "Trouble getting attributes for a variable.");
-
   }
=20
   return MB_SUCCESS;
@@ -1840,7 +1829,6 @@ ErrorCode ReadNC::create_tags(ScdInterface *scdi, Ent=
ityHandle file_set, const s
   // <__DIM_VALUES>
   Tag dimValsTag =3D 0;
   tag_name =3D "__DIM_VALUES";
-  //std::vector<int> dim;
   int dimValsSz =3D (int)dimVals.size();
=20
   rval =3D mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_INTEGER, di=
mValsTag, MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);
@@ -2051,40 +2039,35 @@ ErrorCode ReadNC::create_attrib_string(const std::m=
ap<std::string, AttData>& att
         sz =3D attIt->second.attLen;
         attData =3D (char *) malloc(sz);
         success =3D NCFUNC(get_att_text)(fileId, attIt->second.attVarId, a=
ttIt->second.attName.c_str(), (char*) attData);
-        ERRORS(success, "Failed to read attribute char data.")
-        ;
+        ERRORS(success, "Failed to read attribute char data.");
         ssAtt << "char;";
         break;
       case NC_DOUBLE:
         sz =3D attIt->second.attLen * sizeof(double);
         attData =3D (double *) malloc(sz);
         success =3D NCFUNC(get_att_double)(fileId, attIt->second.attVarId,=
 attIt->second.attName.c_str(), (double*) attData);
-        ERRORS(success, "Failed to read attribute double data.")
-        ;
+        ERRORS(success, "Failed to read attribute double data.");
         ssAtt << "double;";
         break;
       case NC_FLOAT:
         sz =3D attIt->second.attLen * sizeof(float);
         attData =3D (float *) malloc(sz);
         success =3D NCFUNC(get_att_float)(fileId, attIt->second.attVarId, =
attIt->second.attName.c_str(), (float*) attData);
-        ERRORS(success, "Failed to read attribute float data.")
-        ;
+        ERRORS(success, "Failed to read attribute float data.");
         ssAtt << "float;";
         break;
       case NC_INT:
         sz =3D attIt->second.attLen * sizeof(int);
         attData =3D (int *) malloc(sz);
         success =3D NCFUNC(get_att_int)(fileId, attIt->second.attVarId, at=
tIt->second.attName.c_str(), (int*) attData);
-        ERRORS(success, "Failed to read attribute int data.")
-        ;
+        ERRORS(success, "Failed to read attribute int data.");
         ssAtt << "int;";
         break;
       case NC_SHORT:
         sz =3D attIt->second.attLen * sizeof(short);
         attData =3D (short *) malloc(sz);
         success =3D NCFUNC(get_att_short)(fileId, attIt->second.attVarId, =
attIt->second.attName.c_str(), (short*) attData);
-        ERRORS(success, "Failed to read attribute short data.")
-        ;
+        ERRORS(success, "Failed to read attribute short data.");
         ssAtt << "short;";
         break;
       default:

diff --git a/src/io/ReadNC.hpp b/src/io/ReadNC.hpp
index cd1ca6b..7e16215 100644
--- a/src/io/ReadNC.hpp
+++ b/src/io/ReadNC.hpp
@@ -74,14 +74,14 @@ class ReadNC : public ReaderIface
=20
 public:
=20
-  static ReaderIface* factory( Interface* );
+  static ReaderIface* factory(Interface*);
=20
     //! load an NC file
-  ErrorCode load_file( const char* file_name,
+  ErrorCode load_file(const char* file_name,
                        const EntityHandle* file_set,
                        const FileOptions& opts,
                        const SubsetList* subset_list =3D 0,
-                       const Tag* file_id_tag =3D 0 );
+                       const Tag* file_id_tag =3D 0);
=20
    //! Constructor
    ReadNC(Interface* impl =3D NULL);
@@ -89,15 +89,15 @@ public:
    //! Destructor
   virtual ~ReadNC();
=20
-  virtual ErrorCode read_tag_values( const char* file_name,
-                                     const char* tag_name,
-                                     const FileOptions& opts,
-                                     std::vector<int>& tag_values_out,
-                                     const SubsetList* subset_list =3D 0 );
+  virtual ErrorCode read_tag_values(const char* file_name,
+                                    const char* tag_name,
+                                    const FileOptions& opts,
+                                    std::vector<int>& tag_values_out,
+                                    const SubsetList* subset_list =3D 0);
=20
   // ENTLOCNSEDGE for north/south edge
   // ENTLOCWEEDGE for west/east edge
-  enum EntityLocation {ENTLOCNODE=3D0, ENTLOCNSEDGE, ENTLOCEWEDGE, ENTLOCQ=
UAD, ENTLOCSET};
+  enum EntityLocation {ENTLOCVERT =3D 0, ENTLOCNSEDGE, ENTLOCEWEDGE, ENTLO=
CFACE, ENTLOCSET, ENTLOCEDGE, ENTLOCREGION};
=20
 private:
=20
@@ -143,7 +143,7 @@ private:
   ErrorCode read_header();
=20
     //! get all global attributes in the file
-  ErrorCode get_attributes(int var_id, int num_atts, std::map<std::string,=
AttData> &atts,
+  ErrorCode get_attributes(int var_id, int num_atts, std::map<std::string,=
 AttData> &atts,
                            const char *prefix=3D"");
=20
     //! get all dimensions in the file
@@ -158,14 +158,14 @@ private:
     //! number of dimensions in this nc file
   unsigned int number_dimensions();
=20
-    //! create vertices for scd mesh
-  ErrorCode create_scd_verts_quads(ScdInterface *scdi, EntityHandle file_s=
et, Range &quads);
+    //! create vertices and faces for scd mesh
+  ErrorCode create_scd_verts_quads(ScdInterface *scdi, EntityHandle file_s=
et, Range &faces);
=20
     //! make sure that localGid is properly initialized for ucd mesh
   ErrorCode check_ucd_localGid(EntityHandle file_set);
=20
-    //! check number of vertices and elements against what's already in fi=
le_set
-  ErrorCode check_verts_quads(EntityHandle file_set);
+    //! check number of vertices and faces against what's already in file_=
set
+  ErrorCode check_verts_faces(EntityHandle file_set);
=20
   ErrorCode parse_options(const FileOptions &opts,
                           std::vector<std::string> &var_names,=20
@@ -240,7 +240,7 @@ private:
         for (std::size_t j =3D 0; j !=3D nj; ++j)
           for (std::size_t i =3D 0; i !=3D ni; ++i)
             for (std::size_t k =3D 0; k !=3D nk; ++k)=20
-              tmp_data[j*nik+i*nk+k] =3D source[k*nij+j*ni+i];        =20
+              tmp_data[j*nik + i*nk + k] =3D source[k*nij + j*ni + i];
         return MB_SUCCESS;
       }
=20
@@ -249,22 +249,22 @@ private:
   // we read one time step, one variable at a time, usually, so we will
   template <typename T> ErrorCode kji_to_jik_stride(size_t , size_t nj, si=
ze_t nk, void *dest, T *source)
       {
-        std::size_t idxInSource=3D0;// position of the start of the stride
+        std::size_t idxInSource =3D 0;// position of the start of the stri=
de
         // for each subrange, we will transpose a matrix of size subrange*=
nj*nk (subrange takes
         //                                                                =
       the role of ni)
         T *tmp_data =3D reinterpret_cast<T*>(dest);
         for (
           Range::pair_iterator pair_iter =3D localGid.pair_begin();
-          pair_iter!=3DlocalGid.pair_end();
+          pair_iter !=3D localGid.pair_end();
           pair_iter++)
         {
-          std::size_t size_range=3D pair_iter->second - pair_iter->first+1;
+          std::size_t size_range =3D pair_iter->second - pair_iter->first =
+ 1;
           std::size_t nik =3D size_range * nk, nij =3D size_range * nj;
           for (std::size_t j =3D 0; j !=3D nj; ++j)
             for (std::size_t i =3D 0; i !=3D size_range; ++i)
               for (std::size_t k =3D 0; k !=3D nk; ++k)
-                tmp_data[idxInSource + j*nik+i*nk+k] =3D source[idxInSourc=
e + k*nij+j*size_range+i];
-          idxInSource+=3D(size_range*nj*nk);
+                tmp_data[idxInSource + j*nik + i*nk + k] =3D source[idxInS=
ource + k*nij + j*size_range + i];
+          idxInSource +=3D (size_range * nj * nk);
         }
         return MB_SUCCESS;
       }
@@ -287,7 +287,7 @@ private:
   // these should be taken out when we fix the dummy var info things
   std::set<std::string> dummyVarNames;
   std::vector<int> dimVals;
-  std::string iName, jName, kName,tName;
+  std::string iName, jName, kName, tName;
   std::string iCName, jCName;
=20
     //! global attribs
@@ -314,7 +314,7 @@ private:
   //! center values for i/j
   std::vector<double> ilCVals, jlCVals;
=20
-    //! dimension numbers for i, j, t
+    //! dimension numbers for i, j, k, t
   int iDim, jDim, kDim, tDim;
=20
     //! center dimension numbers for i, j


https://bitbucket.org/fathomteam/moab/commits/04a1a74a19f2/
Changeset:   04a1a74a19f2
Branch:      None
User:        danwu
Date:        2013-06-11 22:50:45
Summary:     Support reading MPAS file type in ReadNC (initial submission).

Affected #:  8 files

diff --git a/src/io/Makefile.am b/src/io/Makefile.am
index b7eae6a..bb5b7cb 100644
--- a/src/io/Makefile.am
+++ b/src/io/Makefile.am
@@ -21,6 +21,7 @@ if NETCDF_FILE
                      NCHelperEuler.cpp NCHelperEuler.hpp \
                      NCHelperFV.cpp NCHelperFV.hpp \
                      NCHelperHOMME.cpp NCHelperHOMME.hpp \
+                     NCHelperMPAS.cpp NCHelperMPAS.hpp \
                      ReadGCRM.cpp ReadGCRM.hpp
 else
   MOAB_NETCDF_SRCS =3D
@@ -33,6 +34,7 @@ if !NETCDF_FILE
                      NCHelperEuler.cpp NCHelperEuler.hpp \
                      NCHelperFV.cpp NCHelperFV.hpp \
                      NCHelperHOMME.cpp NCHelperHOMME.hpp \
+                     NCHelperMPAS.cpp NCHelperMPAS.hpp \
                      ReadGCRM.cpp ReadGCRM.hpp
 endif
 endif

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index e0f021e..731e3af 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -2,20 +2,45 @@
 #include "NCHelperEuler.hpp"
 #include "NCHelperFV.hpp"
 #include "NCHelperHOMME.hpp"
-#include "moab/ReadUtilIface.hpp"
+#include "NCHelperMPAS.hpp"
=20
 namespace moab {
=20
 NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int fileId, const FileOp=
tions& opts)
 {
-  if (NCHelperEuler::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperEuler(readNC, fileId);
-  else if (NCHelperFV::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperFV(readNC, fileId);
-  else if (NCHelperHOMME::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts);
-  else // Unknown NetCDF grid (will fill this in later for POP, CICE and C=
LM)
-    return NULL;
+  // Check if CF convention is being followed
+  bool is_CF =3D false;
+
+  std::map<std::string, ReadNC::AttData>& globalAtts =3D readNC->globalAtt=
s;
+  std::map<std::string, ReadNC::AttData>::iterator attIt =3D globalAtts.fi=
nd("conventions");
+  if (attIt =3D=3D globalAtts.end())
+    attIt =3D globalAtts.find("Conventions");
+
+  if (attIt !=3D globalAtts.end()) {
+    unsigned int sz =3D attIt->second.attLen;
+    std::string att_data;
+    att_data.resize(sz + 1);
+    att_data[sz] =3D '\000';
+    int success =3D NCFUNC(get_att_text)(fileId, attIt->second.attVarId, a=
ttIt->second.attName.c_str(), &att_data[0]);
+    if (0 =3D=3D success && att_data.find("CF") !=3D std::string::npos)
+      is_CF =3D true;
+  }
+
+  if (is_CF) {
+    if (NCHelperEuler::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperEuler(readNC, fileId);
+    else if (NCHelperFV::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperFV(readNC, fileId);
+    else if (NCHelperHOMME::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts);
+  }
+  else {
+    if (NCHelperMPAS::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperMPAS(readNC, fileId, opts);
+  }
+
+  // Unknown NetCDF grid (will fill this in later for POP, CICE and CLM)
+  return NULL;
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index cac789c..1fd5673 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -473,9 +473,9 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperEuler::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& faces)
+ErrorCode NCHelperEuler::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& quads)
 {
-  return _readNC->create_scd_verts_quads(scdi, file_set, faces);
+  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index 9bb5564..8e23542 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -469,9 +469,9 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperFV::create_mesh(ScdInterface* scdi, const FileOptions& o=
pts, EntityHandle file_set, Range& faces)
+ErrorCode NCHelperFV::create_mesh(ScdInterface* scdi, const FileOptions& o=
pts, EntityHandle file_set, Range& quads)
 {
-  return _readNC->create_scd_verts_quads(scdi, file_set, faces);
+  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index 827c39f..3deebd3 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -22,7 +22,7 @@ public:
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& elems);
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
   virtual std::string get_mesh_type_name() { return "CAM_SE"; }
   virtual bool is_scd_mesh() { return false; }
=20

diff --git a/src/io/NCHelperMPAS.cpp b/src/io/NCHelperMPAS.cpp
new file mode 100644
index 0000000..b2ae8bc
--- /dev/null
+++ b/src/io/NCHelperMPAS.cpp
@@ -0,0 +1,46 @@
+#include "NCHelperMPAS.hpp"
+#include "moab/ReadUtilIface.hpp"
+#include "FileOptions.hpp"
+#include "moab/SpectralMeshTool.hpp"
+
+#include <cmath>
+
+#define ERRORR(rval, str) \
+    if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", =
str); return rval;}
+
+#define ERRORS(err, str) \
+    if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_F=
AILURE;}
+
+namespace moab {
+
+NCHelperMPAS::NCHelperMPAS(ReadNC* readNC, int fileId, const FileOptions& =
opts) : NCHelper(readNC, fileId)
+{
+  if (MB_SUCCESS =3D=3D opts.match_option("PARTITION_METHOD", "NODAL_PARTI=
TION"))
+    readNC->partMethod =3D -1;
+}
+
+bool NCHelperMPAS::can_read_file(ReadNC* readNC, int fileId)
+{
+  std::vector<std::string>& dimNames =3D readNC->dimNames;
+
+  // If dimension name "vertexDegree" exists then it should be the MPAS gr=
id
+  if (std::find(dimNames.begin(), dimNames.end(), std::string("vertexDegre=
e")) !=3D dimNames.end()) {
+    return true;
+  }
+
+  return false;
+}
+
+ErrorCode NCHelperMPAS::init_mesh_vals(const FileOptions& opts, EntityHand=
le file_set)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+
+ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi, const FileOptions&=
 opts, EntityHandle file_set, Range& faces)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+
+} // namespace moab

diff --git a/src/io/NCHelperMPAS.hpp b/src/io/NCHelperMPAS.hpp
new file mode 100644
index 0000000..54c7146
--- /dev/null
+++ b/src/io/NCHelperMPAS.hpp
@@ -0,0 +1,32 @@
+//-------------------------------------------------------------------------
+// Filename      : NCHelperMPAS.hpp
+//
+// Purpose       : Climate NC file helper for MPAS grid
+//
+// Creator       : Danqing Wu
+//-------------------------------------------------------------------------
+
+#ifndef NCHELPERMPAS_HPP
+#define NCHELPERMPAS_HPP
+
+#include "NCHelper.hpp"
+
+namespace moab {
+
+//! Child helper class for MPAS grid
+class NCHelperMPAS : public NCHelper
+{
+public:
+  NCHelperMPAS(ReadNC* readNC, int fileId, const FileOptions& opts);
+  static bool can_read_file(ReadNC* readNC, int fileId);
+
+private:
+  virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  virtual std::string get_mesh_type_name() { return "MPAS"; }
+  virtual bool is_scd_mesh() { return false; }
+};
+
+} // namespace moab
+
+#endif

diff --git a/src/io/ReadNC.hpp b/src/io/ReadNC.hpp
index 7e16215..c2af40e 100644
--- a/src/io/ReadNC.hpp
+++ b/src/io/ReadNC.hpp
@@ -71,6 +71,7 @@ class ReadNC : public ReaderIface
   friend class NCHelperEuler;
   friend class NCHelperFV;
   friend class NCHelperHOMME;
+  friend class NCHelperMPAS;
=20
 public:
=20
@@ -158,8 +159,8 @@ private:
     //! number of dimensions in this nc file
   unsigned int number_dimensions();
=20
-    //! create vertices and faces for scd mesh
-  ErrorCode create_scd_verts_quads(ScdInterface *scdi, EntityHandle file_s=
et, Range &faces);
+    //! create vertices and quads for scd mesh
+  ErrorCode create_scd_verts_quads(ScdInterface *scdi, EntityHandle file_s=
et, Range &quads);
=20
     //! make sure that localGid is properly initialized for ucd mesh
   ErrorCode check_ucd_localGid(EntityHandle file_set);


https://bitbucket.org/fathomteam/moab/commits/8be23c31aa55/
Changeset:   8be23c31aa55
Branch:      None
User:        danwu
Date:        2013-06-12 15:51:49
Summary:     ReadNC no longer returns an error when CF convention is not be=
ing followed (MPAS format does not follow CF convention)

Affected #:  1 file

diff --git a/src/io/ReadNC.cpp b/src/io/ReadNC.cpp
index 5e7eaf2..87cd6dd 100644
--- a/src/io/ReadNC.cpp
+++ b/src/io/ReadNC.cpp
@@ -175,25 +175,6 @@ ErrorCode ReadNC::load_file(const char *file_name, con=
st EntityHandle* file_set,
   if (!scdi)
     return MB_FAILURE;
=20
-  // Check if CF convention is being followed
-  std::map<std::string, AttData>::iterator attIt =3D globalAtts.find("conv=
entions");
-  if (attIt =3D=3D globalAtts.end())
-    attIt =3D globalAtts.find("Conventions");
-
-  if (attIt =3D=3D globalAtts.end()) {
-    ERRORR(MB_FAILURE, "File does not have conventions global attribute.");
-  }
-
-  unsigned int sz =3D attIt->second.attLen;
-  std::string att_data;
-  att_data.resize(sz + 1);
-  att_data[sz] =3D '\000';
-  success =3D NCFUNC(get_att_text)(fileId, attIt->second.attVarId, attIt->=
second.attName.c_str(), &att_data[0]);
-  ERRORS(success, "Failed to read conventions global attribute char data."=
);
-  if (att_data.find("CF") =3D=3D std::string::npos) {
-    ERRORR(MB_FAILURE, "File not following known conventions.");
-  }
-
   if (myHelper !=3D NULL)
     delete myHelper;
=20


https://bitbucket.org/fathomteam/moab/commits/f374962f486b/
Changeset:   f374962f486b
Branch:      None
User:        danwu
Date:        2013-06-18 19:59:57
Summary:     Introduced ScdNCHelper and UcdNCHelper classes to further refa=
ctor ReadNC code, especially read_variables(). This will make things easier=
 to read MPAS file type later.

Affected #:  12 files

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index 731e3af..350e6ae 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -4,6 +4,15 @@
 #include "NCHelperHOMME.hpp"
 #include "NCHelperMPAS.hpp"
=20
+#include "moab/ReadUtilIface.hpp"
+#include "MBTagConventions.hpp"
+
+#define ERRORR(rval, str) \
+    if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", =
str); return rval;}
+
+#define ERRORS(err, str) \
+    if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_F=
AILURE;}
+
 namespace moab {
=20
 NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int fileId, const FileOp=
tions& opts)
@@ -43,4 +52,945 @@ NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int f=
ileId, const FileOptions&
   return NULL;
 }
=20
+ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, const FileOptions& =
opts, EntityHandle file_set, Range& faces)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  int (&gDims)[6] =3D _readNC->gDims;
+  int (&lDims)[6] =3D _readNC->lDims;
+  std::vector<double>& ilVals =3D _readNC->ilVals;
+  std::vector<double>& jlVals =3D _readNC->jlVals;
+  std::vector<double>& klVals =3D _readNC->klVals;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  int (&locallyPeriodic)[2] =3D _readNC->locallyPeriodic;
+  int (&globallyPeriodic)[2] =3D _readNC->globallyPeriodic;
+  ScdParData& parData =3D _readNC->parData;
+
+  Range tmp_range;
+  ScdBox *scd_box;
+
+  ErrorCode rval =3D scdi->construct_box(HomCoord(lDims[0], lDims[1], lDim=
s[2], 1), HomCoord(lDims[3], lDims[4], lDims[5], 1), NULL,
+      0, scd_box, locallyPeriodic, &parData);
+  ERRORR(rval, "Trouble creating scd vertex sequence.");
+
+  // add box set and new vertices, elements to the file set
+  tmp_range.insert(scd_box->start_vertex(), scd_box->start_vertex() + scd_=
box->num_vertices() - 1);
+  tmp_range.insert(scd_box->start_element(), scd_box->start_element() + sc=
d_box->num_elements() - 1);
+  tmp_range.insert(scd_box->box_set());
+  rval =3D mbImpl->add_entities(file_set, tmp_range);
+  ERRORR(rval, "Couldn't add new vertices to file set.");
+
+  dbgOut.tprintf(1, "scdbox %d quads, %d vertices\n", scd_box->num_element=
s(), scd_box->num_vertices());
+
+  // get a ptr to global id memory
+  void* data;
+  int count;
+  const Range::iterator topv =3D tmp_range.upper_bound(tmp_range.begin(), =
tmp_range.end(), scd_box->start_vertex()
+      + scd_box->num_vertices());
+  rval =3D mbImpl->tag_iterate(mGlobalIdTag, tmp_range.begin(), topv, coun=
t, data);
+  ERRORR(rval, "Failed to get tag iterator.");
+  assert(count =3D=3D scd_box->num_vertices());
+  int* gid_data =3D (int*) data;
+
+  // set the vertex coordinates
+  double *xc, *yc, *zc;
+  rval =3D scd_box->get_coordinate_arrays(xc, yc, zc);
+  ERRORR(rval, "Couldn't get vertex coordinate arrays.");
+
+  int i, j, k, il, jl, kl, itmp;
+  int dil =3D lDims[3] - lDims[0] + 1;
+  int djl =3D lDims[4] - lDims[1] + 1;
+  int di =3D gDims[3] - gDims[0] + 1;
+  int dj =3D gDims[4] - gDims[1] + 1;
+  assert(dil =3D=3D (int)ilVals.size() && djl =3D=3D (int)jlVals.size() &&
+      (-1 =3D=3D lDims[2] || lDims[5]-lDims[2]+1 =3D=3D (int)klVals.size()=
));
+#define INDEX(i, j, k) ()
+  for (kl =3D lDims[2]; kl <=3D lDims[5]; kl++) {
+    k =3D kl - lDims[2];
+    for (jl =3D lDims[1]; jl <=3D lDims[4]; jl++) {
+      j =3D jl - lDims[1];
+      for (il =3D lDims[0]; il <=3D lDims[3]; il++) {
+        i =3D il - lDims[0];
+        unsigned int pos =3D i + j * dil + k * dil * djl;
+        xc[pos] =3D ilVals[i];
+        yc[pos] =3D jlVals[j];
+        zc[pos] =3D (-1 =3D=3D lDims[2] ? 0.0 : klVals[k]);
+        itmp =3D (!locallyPeriodic[0] && globallyPeriodic[0] && il =3D=3D =
gDims[3] ? gDims[0] : il);
+        *gid_data =3D (-1 !=3D kl ? kl * di * dj : 0) + jl * di + itmp + 1;
+        gid_data++;
+      }
+    }
+  }
+#undef INDEX
+
+#ifndef NDEBUG
+  int num_verts =3D (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1] + 1) =
* (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
+  std::vector<int> gids(num_verts);
+  Range verts(scd_box->start_vertex(), scd_box->start_vertex() + scd_box->=
num_vertices() - 1);
+  rval =3D mbImpl->tag_get_data(mGlobalIdTag, verts, &gids[0]);
+  ERRORR(rval, "Trouble getting gid values.");
+  int vmin =3D *(std::min_element(gids.begin(), gids.end())), vmax =3D *(s=
td::max_element(gids.begin(), gids.end()));
+  dbgOut.tprintf(1, "Vertex gids %d-%d\n", vmin, vmax);
+#endif
+
+  // add elements to the range passed in
+  faces.insert(scd_box->start_element(), scd_box->start_element() + scd_bo=
x->num_elements() - 1);
+
+  if (2 <=3D dbgOut.get_verbosity()) {
+    assert(scd_box->boundary_complete());
+    EntityHandle dum_ent =3D scd_box->start_element();
+    rval =3D mbImpl->list_entities(&dum_ent, 1);
+    ERRORR(rval, "Trouble listing first hex.");
+
+    std::vector<EntityHandle> connect;
+    rval =3D mbImpl->get_connectivity(&dum_ent, 1, connect);
+    ERRORR(rval, "Trouble getting connectivity.");
+
+    rval =3D mbImpl->list_entities(&connect[0], connect.size());
+    ERRORR(rval, "Trouble listing element connectivity.");
+  }
+
+  Range edges;
+  mbImpl->get_adjacencies(faces, 1, true, edges, Interface::UNION);
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_variables(EntityHandle file_set, std::vector<s=
td::string>& var_names, std::vector<int>& tstep_nums)
+{
+  std::vector<ReadNC::VarData> vdatas;
+  std::vector<ReadNC::VarData> vsetdatas;
+
+  ErrorCode rval =3D read_scd_variable_setup(var_names, tstep_nums, vdatas=
, vsetdatas);
+  ERRORR(rval, "Trouble setting up read variable.");
+
+  // create COORDS tag for quads
+  rval =3D _readNC->create_quad_coordinate_tag(file_set);
+  ERRORR(rval, "Trouble creating coordinate tags to entities quads");
+
+  if (!vsetdatas.empty()) {
+    rval =3D read_scd_variable_to_set(file_set, vsetdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to set.");
+  }
+
+  if (!vdatas.empty()) {
+    rval =3D read_scd_variable_to_nonset(file_set, vdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to entities verts/edges/faces.");
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_setup(std::vector<std::string>& v=
ar_names, std::vector<int>& tstep_nums,
+                                               std::vector<ReadNC::VarData=
>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
+{
+  std::map<std::string, ReadNC::VarData>& varInfo =3D _readNC->varInfo;
+  int& tMin =3D _readNC->tMin;
+  int& tMax =3D _readNC->tMax;
+  int& iDim =3D _readNC->iDim;
+  int& jDim =3D _readNC->jDim;
+  int& tDim =3D _readNC->tDim;
+  int& iCDim =3D _readNC->iCDim;
+  int& jCDim =3D _readNC->jCDim;
+
+  std::map<std::string, ReadNC::VarData>::iterator mit;
+
+  // if empty read them all
+  if (var_names.empty()) {
+    for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
+      ReadNC::VarData vd =3D (*mit).second;
+      if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.=
varDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=3D=
 vd.varDims.end()) && (std::find(vd.varDims.begin(),
+         vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jCDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), iDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else
+        vsetdatas.push_back(vd);
+    }
+  }
+  else {
+    for (unsigned int i =3D 0; i < var_names.size(); i++) {
+      mit =3D varInfo.find(var_names[i]);
+      if (mit !=3D varInfo.end()) {
+        ReadNC::VarData vd =3D (*mit).second;
+        if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D v=
d.varDims.end()) && (std::find(vd.varDims.begin(),
+           vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jCDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), iDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else
+          vsetdatas.push_back(vd);
+      }
+      else ERRORR(MB_FAILURE, "Couldn't find variable.");
+    }
+  }
+
+  if (tstep_nums.empty() && -1 !=3D tMin) {
+    // no timesteps input, get them all
+    for (int i =3D tMin; i <=3D tMax; i++)
+      tstep_nums.push_back(i);
+  }
+  if (!tstep_nums.empty()) {
+    for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+      vdatas[i].varTags.resize(tstep_nums.size(), 0);
+      vdatas[i].varDatas.resize(tstep_nums.size());
+      vdatas[i].readDims.resize(tstep_nums.size());
+      vdatas[i].readCounts.resize(tstep_nums.size());
+    }
+    for (unsigned int i =3D 0; i < vsetdatas.size(); i++) {
+      if ((std::find(vsetdatas[i].varDims.begin(), vsetdatas[i].varDims.en=
d(), tDim) !=3D vsetdatas[i].varDims.end())
+          && (vsetdatas[i].varDims.size() !=3D 1)) {
+        vsetdatas[i].varTags.resize(tstep_nums.size(), 0);
+        vsetdatas[i].varDatas.resize(tstep_nums.size());
+        vsetdatas[i].readDims.resize(tstep_nums.size());
+        vsetdatas[i].readCounts.resize(tstep_nums.size());
+      }
+      else {
+        vsetdatas[i].varTags.resize(1, 0);
+        vsetdatas[i].varDatas.resize(1);
+        vsetdatas[i].readDims.resize(1);
+        vsetdatas[i].readCounts.resize(1);
+      }
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_set_allocate(std::vector<ReadN=
C::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
+      vdatas[i].has_t =3D true;
+
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+
+      // set up the dimensions and counts
+      // first variable dimension is time, if it exists
+      if (vdatas[i].has_t)
+      {
+        if (vdatas[i].varDims.size() !=3D 1)
+        {
+          vdatas[i].readDims[t].push_back(tstep_nums[t]);
+          vdatas[i].readCounts[t].push_back(1);
+        }
+        else
+        {
+          vdatas[i].readDims[t].push_back(0);
+          vdatas[i].readCounts[t].push_back(tstep_nums.size());
+        }
+      }
+
+      // set up other dimensions and counts
+      if (vdatas[i].varDims.empty()) {
+        // scalar variable
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(1);
+      }
+      else {
+        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
+          if (tDim !=3D vdatas[i].varDims[idx]){
+            // push other variable dimensions, except time, which was alre=
ady pushed
+            vdatas[i].readDims[t].push_back(0);
+            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
+          }
+        }
+      }
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      vdatas[i].sz =3D sz;
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          vdatas[i].varDatas[t] =3D new char[sz];
+          break;
+        case NC_DOUBLE:
+        case NC_FLOAT:
+          vdatas[i].varDatas[t] =3D new double[sz];
+          break;
+        case NC_INT:
+        case NC_SHORT:
+          vdatas[i].varDatas[t] =3D new int[sz];
+          break;
+        default:
+          std::cerr << "Unrecognized data type for tag " << std::endl;
+          rval =3D MB_FAILURE;
+      }
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_set(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_scd_variable_to_set_allocate(vdatas, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables to set.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if (dummyVarNames.find(vdatas[i].varName)!=3D dummyVarNames.end() )
+       continue;// this is a dummy one, we don't have it; we created it fo=
r the dummy tag
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      void* data =3D vdatas[i].varDatas[t];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (char*) data NCREQ);
+          ERRORS(success, "Failed to read char data.");
+          break;
+        case NC_DOUBLE:
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (double*) data NCREQ);
+          ERRORS(success, "Failed to read double data.");
+          break;
+        case NC_FLOAT: {
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (float*) data NCREQ);
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT:
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (int*) data NCREQ);
+          ERRORS(success, "Failed to read int data.");
+          break;
+        case NC_SHORT:
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (short*) data NCREQ);
+          ERRORS(success, "Failed to read short data.");
+          break;
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_scd_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allocate(EntityHandle f=
ile_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  std::vector<std::string>& dimNames =3D _readNC->dimNames;
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int (&lDims)[6] =3D _readNC->lDims;
+  int (&lCDims)[6] =3D _readNC->lCDims;
+  int& tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  bool& isParallel =3D _readNC->isParallel;
+ #ifdef USE_MPI
+  ParallelComm*& myPcomm =3D _readNC->myPcomm;
+#endif
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  Range* range =3D NULL;
+
+  // get vertices in set
+  Range verts;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 0, verts);
+  ERRORR(rval, "Trouble getting vertices in set.");
+  assert("Should only have a single vertex subrange, since they were read =
in one shot" &&
+      verts.psize() =3D=3D 1);
+
+  Range edges;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 1, edges);
+  ERRORR(rval, "Trouble getting edges in set.");
+
+  // get faces in set
+  Range faces;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 2, faces);
+  ERRORR(rval, "Trouble getting faces in set.");
+  assert("Should only have a single face subrange, since they were read in=
 one shot" &&
+      faces.psize() =3D=3D 1);
+
+#ifdef USE_MPI
+  moab::Range faces_owned;
+  if (isParallel)
+  {
+    rval =3D myPcomm->filter_pstatus(faces, PSTATUS_NOT_OWNED, PSTATUS_NOT=
, -1, &faces_owned);
+    ERRORR(rval, "Trouble getting owned faces in set.");
+  }
+  else
+    faces_owned =3D faces; // not running in parallel, but still with MPI
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      std::vector<std::string>::iterator vit;
+      int idx_lev =3D 0;
+      int idx_ilev =3D 0;
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
+        idx_lev =3D vit - dimNames.begin();
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
+        idx_ilev =3D vit - dimNames.begin();
+      if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), id=
x_lev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_lev];
+      else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_ilev];
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+      }
+      else if (vdatas[i].varDims[0] !=3D tDim) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
+      }
+
+      // set up the dimensions and counts
+      // first time
+      vdatas[i].readDims[t].push_back(tstep_nums[t]);
+      vdatas[i].readCounts[t].push_back(1);
+
+      // then z/y/x
+      if (vdatas[i].numLev !=3D 1) {
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(vdatas[i].numLev);
+      }
+
+      switch (vdatas[i].entLoc) {
+        case ReadNC::ENTLOCVERT:
+          // vertices
+          // only structured mesh has j parameter that multiplies i to get=
 total # vertices
+          vdatas[i].readDims[t].push_back(lDims[1]);
+          vdatas[i].readCounts[t].push_back(lDims[4] - lDims[1] + 1);
+          vdatas[i].readDims[t].push_back(lDims[0]);
+          vdatas[i].readCounts[t].push_back(lDims[3] - lDims[0] + 1);
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+          range =3D &verts;
+          break;
+        case ReadNC::ENTLOCNSEDGE:
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
+          break;
+        case ReadNC::ENTLOCEWEDGE:
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
+          break;
+        case ReadNC::ENTLOCFACE:
+          // faces
+          vdatas[i].readDims[t].push_back(lCDims[1]);
+          vdatas[i].readDims[t].push_back(lCDims[0]);
+          vdatas[i].readCounts[t].push_back(lCDims[4] - lCDims[1] + 1);
+          vdatas[i].readCounts[t].push_back(lCDims[3] - lCDims[0] + 1);
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+#ifdef USE_MPI
+          range =3D &faces_owned;
+#else
+          range =3D &faces;
+#endif
+          break;
+        case ReadNC::ENTLOCSET:
+          // set
+          break;
+        default:
+          ERRORR(MB_FAILURE, "Unrecognized entity location type.");
+          break;
+      }
+
+      // get ptr to tag space
+      void* data;
+      int count;
+      rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
+      ERRORR(rval, "Failed to get tag iterator.");
+      assert((unsigned)count =3D=3D range->size());
+      vdatas[i].varDatas[t] =3D data;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_nonset(EntityHandle file_set, =
std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_scd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D vdatas[i].readCounts[t][3];
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          std::vector<char> tmpchardata(sz);
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpchardata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpchardata=
[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpchardata.size(); idx++)
+              ((char*) data)[idx] =3D tmpchardata[idx];
+          }
+          ERRORS(success, "Failed to read char data.");
+          break;
+        }
+        case NC_DOUBLE: {
+          std::vector<double> tmpdoubledata(sz);
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpdoubledata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpdoubleda=
ta[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpfloatdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          std::vector<int> tmpintdata(sz);
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpintdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
+              ((int*) data)[idx] =3D tmpintdata[idx];
+          }
+          ERRORS(success, "Failed to read int data.");
+          break;
+        }
+        case NC_SHORT: {
+          std::vector<short> tmpshortdata(sz);
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpshortdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
+              ((short*) data)[idx] =3D tmpshortdata[idx];
+          }
+          ERRORS(success, "Failed to read short data.");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_scd_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+
+ErrorCode ScdNCHelper::convert_scd_variable(ReadNC::VarData& var_data, int=
 tstep_num)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  // get ptr to tag space
+  void* data =3D var_data.varDatas[tstep_num];
+
+  std::size_t sz =3D 1;
+  for (std::size_t idx =3D 0; idx !=3D var_data.readCounts[tstep_num].size=
(); idx++)
+    sz *=3D var_data.readCounts[tstep_num][idx];
+
+  // finally, read into that space
+  int success =3D 0;
+  int* idata;
+  double* ddata;
+  float* fdata;
+  short* sdata;
+
+  switch (var_data.varDataType) {
+    case NC_FLOAT:
+      ddata =3D (double*) var_data.varDatas[tstep_num];
+      fdata =3D (float*) var_data.varDatas[tstep_num];
+      // convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        ddata[i] =3D fdata[i];
+      break;
+    case NC_SHORT:
+      idata =3D (int*) var_data.varDatas[tstep_num];
+      sdata =3D (short*) var_data.varDatas[tstep_num];
+      // convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        idata[i] =3D sdata[i];
+      break;
+    default:
+      success =3D 1;
+  }
+
+  if (2 <=3D dbgOut.get_verbosity() && !success) {
+    double dmin, dmax;
+    int imin, imax;
+    switch (var_data.varDataType) {
+      case NC_DOUBLE:
+      case NC_FLOAT:
+        ddata =3D (double*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        dmin =3D dmax =3D ddata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (ddata[i] < dmin)
+            dmin =3D ddata[i];
+          if (ddata[i] > dmax)
+            dmax =3D ddata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
+        break;
+      case NC_INT:
+      case NC_SHORT:
+        idata =3D (int*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        imin =3D imax =3D idata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (idata[i] < imin)
+            imin =3D idata[i];
+          if (idata[i] > imax)
+            imax =3D idata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
+        break;
+      case NC_NAT:
+      case NC_BYTE:
+      case NC_CHAR:
+        break;
+      default: //default case added to remove compiler warnings
+        success =3D 1;
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode UcdNCHelper::read_variables(EntityHandle file_set, std::vector<s=
td::string>& var_names, std::vector<int>& tstep_nums)
+{
+  std::vector<ReadNC::VarData> vdatas;
+  std::vector<ReadNC::VarData> vsetdatas;
+
+  ErrorCode rval =3D read_ucd_variable_setup(var_names, tstep_nums, vdatas=
, vsetdatas);
+  ERRORR(rval, "Trouble setting up read variable.");
+
+  if (!vdatas.empty()) {
+#ifdef PNETCDF_FILE
+    // in serial, we will use the old read, everything is contiguous
+    // in parallel, we will use async read in pnetcdf
+    // the other mechanism is not working, forget about it
+    rval =3D read_ucd_variable_to_nonset_async(file_set, vdatas, tstep_num=
s);
+#else
+    rval =3D read_ucd_variable_to_nonset(file_set, vdatas, tstep_nums);
+#endif
+    ERRORR(rval, "Trouble read variables to entities verts/edges/faces.");
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode UcdNCHelper::read_ucd_variable_to_set_allocate(std::vector<ReadN=
C::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
+      vdatas[i].has_t =3D true;
+
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+
+      // set up the dimensions and counts
+      // first variable dimension is time, if it exists
+      if (vdatas[i].has_t)
+      {
+        if (vdatas[i].varDims.size() !=3D 1)
+        {
+          vdatas[i].readDims[t].push_back(tstep_nums[t]);
+          vdatas[i].readCounts[t].push_back(1);
+        }
+        else
+        {
+          vdatas[i].readDims[t].push_back(0);
+          vdatas[i].readCounts[t].push_back(tstep_nums.size());
+        }
+      }
+
+      // set up other dimensions and counts
+      if (vdatas[i].varDims.empty()) {
+        // scalar variable
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(1);
+      }
+      else {
+        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
+          if (tDim !=3D vdatas[i].varDims[idx]){
+            // push other variable dimensions, except time, which was alre=
ady pushed
+            vdatas[i].readDims[t].push_back(0);
+            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
+          }
+        }
+      }
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      vdatas[i].sz =3D sz;
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          vdatas[i].varDatas[t] =3D new char[sz];
+          break;
+        case NC_DOUBLE:
+        case NC_FLOAT:
+          vdatas[i].varDatas[t] =3D new double[sz];
+          break;
+        case NC_INT:
+        case NC_SHORT:
+          vdatas[i].varDatas[t] =3D new int[sz];
+          break;
+        default:
+          std::cerr << "Unrecognized data type for tag " << std::endl;
+          rval =3D MB_FAILURE;
+      }
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode UcdNCHelper::read_ucd_variable_to_set(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas, std::vector<int> &tstep_nums)
+{
+  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_ucd_variable_to_set_allocate(vdatas, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables to set.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if (dummyVarNames.find(vdatas[i].varName) !=3D dummyVarNames.end() )
+       continue; // this is a dummy one, we don't have it; we created it f=
or the dummy tag
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      void* data =3D vdatas[i].varDatas[t];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (char*) data NCREQ);
+          ERRORS(success, "Failed to read char data.");
+          break;
+        case NC_DOUBLE:
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (double*) data NCREQ);
+          ERRORS(success, "Failed to read double data.");
+          break;
+        case NC_FLOAT: {
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (float*) data NCREQ);
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT:
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (int*) data NCREQ);
+          ERRORS(success, "Failed to read int data.");
+          break;
+        case NC_SHORT:
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (short*) data NCREQ);
+          ERRORS(success, "Failed to read short data.");
+          break;
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
 } // namespace moab

diff --git a/src/io/NCHelper.hpp b/src/io/NCHelper.hpp
index 16f2a3c..6aac571 100644
--- a/src/io/NCHelper.hpp
+++ b/src/io/NCHelper.hpp
@@ -18,19 +18,83 @@ class NCHelper
 {
 public:
   NCHelper(ReadNC* readNC, int fileId) : _readNC(readNC), _fileId(fileId) =
{}
+  virtual ~NCHelper() {}
=20
   static NCHelper* get_nc_helper(ReadNC* readNC, int fileId, const FileOpt=
ions& opts);
=20
+  //! Interfaces to be implemented by child classes
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set) =3D 0;
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces) =3D 0;
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums) =3D 0;
   virtual std::string get_mesh_type_name() =3D 0;
-  virtual bool is_scd_mesh() =3D 0;
=20
 protected:
   ReadNC* _readNC;
   int _fileId;
 };
=20
+//! Child helper class for structured mesh, e.g. CAM_EL or CAM_FV
+class ScdNCHelper : public NCHelper
+{
+public:
+  ScdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  virtual ~ScdNCHelper() {}
+
+private:
+  //! Implementation of NCHelper::create_mesh()
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  //! Implementation of NCHelper::read_variables()
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums);
+
+  //! These functions are used by read_variables(), fully implemented
+  ErrorCode read_scd_variable_setup(std::vector<std::string>& var_names,
+                                    std::vector<int>& tstep_nums,
+                                    std::vector<ReadNC::VarData>& vdatas,
+                                    std::vector<ReadNC::VarData>& vsetdata=
s);
+  ErrorCode read_scd_variable_to_set_allocate(std::vector<ReadNC::VarData>=
& vdatas,
+                                              std::vector<int>& tstep_nums=
);
+  ErrorCode read_scd_variable_to_set(EntityHandle file_set, std::vector<Re=
adNC::VarData>& vdatas,
+                                     std::vector<int>& tstep_nums);
+  ErrorCode read_scd_variable_to_nonset_allocate(EntityHandle file_set, st=
d::vector<ReadNC::VarData>& vdatas,
+                                                 std::vector<int>& tstep_n=
ums);
+  ErrorCode read_scd_variable_to_nonset(EntityHandle file_set, std::vector=
<ReadNC::VarData>& vdatas,
+                                        std::vector<int>& tstep_nums);
+  ErrorCode convert_scd_variable(ReadNC::VarData& var_data, int tstep_num);
+};
+
+//! Child helper class for unstructured mesh, e.g. CAM_SE (HOMME) or MPAS
+class UcdNCHelper : public NCHelper
+{
+public:
+  UcdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  virtual ~UcdNCHelper() {}
+
+private:
+  //! Implementation of NCHelper::read_variables()
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names,
+                                   std::vector<int> &tstep_nums);
+
+  //! These functions are used by read_variables(), partially implemented
+  virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
+                                            std::vector<int>& tstep_nums,
+                                            std::vector<ReadNC::VarData>& =
vdatas,
+                                            std::vector<ReadNC::VarData>& =
vsetdatas) =3D 0;
+  ErrorCode read_ucd_variable_to_set_allocate(std::vector<ReadNC::VarData>=
& vdatas,
+                                              std::vector<int>& tstep_nums=
);
+  ErrorCode read_ucd_variable_to_set(EntityHandle file_set, std::vector<Re=
adNC::VarData>& vdatas,
+                                     std::vector<int>& tstep_nums);
+  virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
+                                                         std::vector<int>&=
 tstep_nums) =3D 0;
+#ifdef PNETCDF_FILE
+  virtual ErrorCode read_ucd_variable_to_nonset_async(EntityHandle file_se=
t, std::vector<ReadNC::VarData>& vdatas,
+                                                      std::vector<int>& ts=
tep_nums) =3D 0;
+#else
+  virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
+                                                std::vector<int>& tstep_nu=
ms) =3D 0;
+#endif
+  virtual ErrorCode convert_ucd_variable(ReadNC::VarData& var_data, int ts=
tep_num) =3D 0;
+};
+
 } // namespace moab
=20
 #endif

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index 1fd5673..c225841 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -473,9 +473,4 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperEuler::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& quads)
-{
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
-}
-
 } // namespace moab

diff --git a/src/io/NCHelperEuler.hpp b/src/io/NCHelperEuler.hpp
index 6bf2a51..a0d6aef 100644
--- a/src/io/NCHelperEuler.hpp
+++ b/src/io/NCHelperEuler.hpp
@@ -14,21 +14,16 @@
 namespace moab {
=20
 //! Child helper class for Eulerian Spectral grid (CAM_EUL)
-class NCHelperEuler : public NCHelper
+class NCHelperEuler : public ScdNCHelper
 {
 public:
-  NCHelperEuler(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  NCHelperEuler(ReadNC* readNC, int fileId) : ScdNCHelper(readNC, fileId) =
{}
=20
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-
-  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
-
   virtual std::string get_mesh_type_name() { return "CAM_EUL"; }
-
-  virtual bool is_scd_mesh() { return true; }
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index 8e23542..cdc4392 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -469,9 +469,4 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperFV::create_mesh(ScdInterface* scdi, const FileOptions& o=
pts, EntityHandle file_set, Range& quads)
-{
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
-}
-
 } // namespace moab

diff --git a/src/io/NCHelperFV.hpp b/src/io/NCHelperFV.hpp
index 0a1ba76..7dde6dc 100644
--- a/src/io/NCHelperFV.hpp
+++ b/src/io/NCHelperFV.hpp
@@ -14,17 +14,15 @@
 namespace moab {
=20
 //! Child helper class for Finite Volume grid (CAM_FV)
-class NCHelperFV : public NCHelper
+class NCHelperFV : public ScdNCHelper
 {
 public:
-  NCHelperFV(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  NCHelperFV(ReadNC* readNC, int fileId) : ScdNCHelper(readNC, fileId) {}
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
   virtual std::string get_mesh_type_name() { return "CAM_FV"; }
-  virtual bool is_scd_mesh() { return true; }
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 6f6b102..6694abb 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -2,6 +2,7 @@
 #include "moab/ReadUtilIface.hpp"
 #include "FileOptions.hpp"
 #include "moab/SpectralMeshTool.hpp"
+#include "MBTagConventions.hpp"
=20
 #include <cmath>
=20
@@ -13,7 +14,7 @@
=20
 namespace moab {
=20
-NCHelperHOMME::NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions=
& opts) : NCHelper(readNC, fileId), _spectralOrder(-1)
+NCHelperHOMME::NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions=
& opts) : UcdNCHelper(readNC, fileId), _spectralOrder(-1)
 {
   // Calculate spectral order
   std::map<std::string, ReadNC::AttData>::iterator attIt =3D readNC->globa=
lAtts.find("np");
@@ -199,7 +200,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& quads)
+ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& faces)
 {
   Interface*& mbImpl =3D _readNC->mbImpl;
   std::string& fileName =3D _readNC->fileName;
@@ -381,12 +382,12 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* sc=
di, const FileOptions& opts
=20
   // get ptr to gid memory for vertices
   Range vert_range(start_vertex, start_vertex + num_local_verts - 1);
-  void *data;
+  void* data;
   int count;
   rval =3D mbImpl->tag_iterate(mGlobalIdTag, vert_range.begin(), vert_rang=
e.end(), count, data);
   ERRORR(rval, "Failed to get tag iterator.");
   assert(count =3D=3D (int) num_local_verts);
-  int *gid_data =3D (int*) data;
+  int* gid_data =3D (int*) data;
   std::copy(localGid.begin(), localGid.end(), gid_data);
   // duplicate global id data, which will be used to resolve sharing
   if (mpFileIdTag) {
@@ -417,7 +418,7 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi=
, const FileOptions& opts
   }
=20
   // add new vertices and elements to the set
-  quads.merge(tmp_range);
+  faces.merge(tmp_range);
   tmp_range.insert(start_vertex, start_vertex + num_local_verts - 1);
   rval =3D mbImpl->add_entities(file_set, tmp_range);
   ERRORR(rval, "Couldn't add new vertices and quads/hexes to file set.");
@@ -503,4 +504,596 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* sc=
di, const FileOptions& opts
   return MB_SUCCESS;
 }
=20
+ErrorCode NCHelperHOMME::read_ucd_variable_setup(std::vector<std::string>&=
 var_names, std::vector<int>& tstep_nums,
+                                                 std::vector<ReadNC::VarDa=
ta>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
+{
+  std::map<std::string, ReadNC::VarData>& varInfo =3D _readNC->varInfo;
+  int& tMin =3D _readNC->tMin;
+  int& tMax =3D _readNC->tMax;
+  int& iDim =3D _readNC->iDim;
+  int& kDim =3D _readNC->kDim;
+  int& tDim =3D _readNC->tDim;
+
+  std::map<std::string, ReadNC::VarData>::iterator mit;
+
+  if (var_names.empty()) {
+    for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
+      ReadNC::VarData vd =3D (*mit).second;
+      if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd.v=
arDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), iDim)
+          !=3D vd.varDims.end()))
+        vdatas.push_back(vd); //3d data (time, ncol, ilev) read here
+      else
+        vsetdatas.push_back(vd);
+    }
+  }
+  else {
+    for (unsigned int i =3D 0; i < var_names.size(); i++) {
+
+      mit =3D varInfo.find(var_names[i]);
+      if (mit !=3D varInfo.end()) {
+        ReadNC::VarData vd =3D (*mit).second;
+        if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd=
.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(v=
d.varDims.begin(), vd.varDims.end(), iDim)
+            !=3D vd.varDims.end()))
+          vdatas.push_back(vd); //3d data
+        else
+          vsetdatas.push_back(vd);
+      }
+      else ERRORR(MB_FAILURE, "Couldn't find variable.");
+    }
+  }
+
+  if (tstep_nums.empty() && -1 !=3D tMin) {
+    // no timesteps input, get them all
+    for (int i =3D tMin; i <=3D tMax; i++)
+      tstep_nums.push_back(i);
+  }
+  if (!tstep_nums.empty()) {
+    for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+      vdatas[i].varTags.resize(tstep_nums.size(), 0);
+      vdatas[i].varDatas.resize(tstep_nums.size());
+      vdatas[i].readDims.resize(tstep_nums.size());
+      vdatas[i].readCounts.resize(tstep_nums.size());
+    }
+    for (unsigned int i =3D 0; i < vsetdatas.size(); i++) {
+      if ((std::find(vsetdatas[i].varDims.begin(), vsetdatas[i].varDims.en=
d(), tDim) !=3D vsetdatas[i].varDims.end())
+          && (vsetdatas[i].varDims.size() !=3D 1)) {
+        vsetdatas[i].varTags.resize(tstep_nums.size(), 0);
+        vsetdatas[i].varDatas.resize(tstep_nums.size());
+        vsetdatas[i].readDims.resize(tstep_nums.size());
+        vsetdatas[i].readCounts.resize(tstep_nums.size());
+      }
+      else {
+        vsetdatas[i].varTags.resize(1, 0);
+        vsetdatas[i].varDatas.resize(1);
+        vsetdatas[i].readDims.resize(1);
+        vsetdatas[i].readCounts.resize(1);
+      }
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_allocate(EntityHandle=
 file_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nu=
ms)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  std::vector<std::string>& dimNames =3D _readNC->dimNames;
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+   int& tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  Range* range =3D NULL;
+
+  // get vertices in set
+  Range verts;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 0, verts);
+  ERRORR(rval, "Trouble getting vertices in set.");
+  assert("Should only have a single vertex subrange, since they were read =
in one shot" &&
+      verts.psize() =3D=3D 1);
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      std::vector<std::string>::iterator vit;
+      int idx_lev =3D 0;
+      int idx_ilev =3D 0;
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
+        idx_lev =3D vit - dimNames.begin();
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
+        idx_ilev =3D vit - dimNames.begin();
+      if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), id=
x_lev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_lev];
+      else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_ilev];
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+      }
+      else if (vdatas[i].varDims[0] !=3D tDim) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
+      }
+
+      // set up the dimensions and counts
+      // first time
+      vdatas[i].readDims[t].push_back(tstep_nums[t]);
+      vdatas[i].readCounts[t].push_back(1);
+
+      // then numLev/numVertices
+      if (vdatas[i].numLev !=3D 1) {
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(vdatas[i].numLev);
+      }
+
+      switch (vdatas[i].entLoc) {
+        case ReadNC::ENTLOCVERT:
+          // vertices
+          // we will start from the first localGid, actually; we will rese=
t that
+          // later on, anyway, in a loop
+          vdatas[i].readDims[t].push_back(localGid[0]-1);
+          vdatas[i].readCounts[t].push_back(localGid.size());
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+          range =3D &verts;
+          break;
+        case ReadNC::ENTLOCSET:
+          // set
+          break;
+        default:
+          ERRORR(MB_FAILURE, "Unrecognized entity location type.");
+          break;
+      }
+
+      // get ptr to tag space
+      void* data;
+      int count;
+      rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
+      ERRORR(rval, "Failed to get tag iterator.");
+      assert((unsigned)count =3D=3D range->size());
+      vdatas[i].varDatas[t] =3D data;
+    }
+  }
+
+  return rval;
+}
+
+#ifdef PNETCDF_FILE
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_async(EntityHandle fi=
le_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // finally, read into that space
+  int success;
+  // MPI_offset or size_t?
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
+      if (sz <=3D 0)
+        continue; // nothing to read, why worry?
+
+      // we will synchronize all these reads with the other processors,
+      // so the wait will be inside this double loop; is it too much?
+      size_t nb_reads =3D localGid.psize();
+      std::vector<int> requests(nb_reads), statuss(nb_reads);
+      size_t idxReq =3D 0;
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D 1; // for HOMME, nj holds # quads, so here should set =
to 1
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        case NC_DOUBLE: {
+          // copy from float case
+          std::vector<double> tmpdoubledata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInDoubleArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
+
+            // do a partial read, in each subrange
+            // wait outside this loop
+            success =3D NCFUNCAG2(_vara_double)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpdoubledata[indexInDoubleArray]) NCREQ2);
+            ERRORS(success, "Failed to read double data in loop");
+            // we need to increment the index in float array for the
+            // next subrange
+            indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          success =3D ncmpi_wait_all(_fileId, requests.size(), &requests[0=
], &statuss[0]);
+          ERRORS(success, "Failed on wait_all.");
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik_stride(ni, nj, nk, data, &tmpd=
oubledata[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInFloatArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
+
+            // do a partial read, in each subrange
+            // wait outside this loop
+            success =3D NCFUNCAG2(_vara_float)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpfloatdata[indexInFloatArray]) NCREQ2);
+            ERRORS(success, "Failed to read float data in loop");
+            // we need to increment the index in float array for the
+            // next subrange
+            indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].num=
Lev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          success =3D ncmpi_wait_all(_fileId, requests.size(), &requests[0=
], &statuss[0]);
+          ERRORS(success, "Failed on wait_all.");
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik_stride(ni, nj, nk, data, &tmpf=
loatdata[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        case NC_SHORT: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+#else
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(EntityHandle file_set=
, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D 1; // for HOMME, nj holds # quads, so here should set =
to 1
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          std::vector<char> tmpchardata(sz);
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpchardata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpchardata=
[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpchardata.size(); idx++)
+              ((char*) data)[idx] =3D tmpchardata[idx];
+          }
+          ERRORS(success, "Failed to read char data.");
+          break;
+        }
+        case NC_DOUBLE: {
+          // copy from float case
+          std::vector<double> tmpdoubledata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInDoubleArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh - star=
th + 1);
+
+            success =3D NCFUNCAG(_vara_double)(fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpdoubledata[indexInDoubleArray]) NCREQ);
+            ERRORS(success, "Failed to read float data in loop");
+            // we need to increment the index in float array for the
+            // next subrange
+            indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpdoubleda=
ta[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInFloatArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh - star=
th + 1);
+
+            success =3D NCFUNCAG(_vara_float)(fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpfloatdata[indexInFloatArray]) NCREQ);
+            ERRORS(success, "Failed to read float data in loop");
+            // we need to increment the index in float array for the
+            // next subrange
+            indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].num=
Lev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          std::vector<int> tmpintdata(sz);
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpintdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
+              ((int*) data)[idx] =3D tmpintdata[idx];
+          }
+          ERRORS(success, "Failed to read int data.");
+          break;
+        }
+        case NC_SHORT: {
+          std::vector<short> tmpshortdata(sz);
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpshortdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
+              ((short*) data)[idx] =3D tmpshortdata[idx];
+          }
+          ERRORS(success, "Failed to read short data.");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+#endif
+
+ErrorCode NCHelperHOMME::convert_ucd_variable(ReadNC::VarData& var_data, i=
nt tstep_num)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  // get ptr to tag space
+  void* data =3D var_data.varDatas[tstep_num];
+
+  std::size_t sz =3D var_data.numLev * localGid.size(); // how many nodes =
are we reading?
+
+  // finally, read into that space
+  int success =3D 0;
+  int* idata;
+  double* ddata;
+  float* fdata;
+  short* sdata;
+
+  switch (var_data.varDataType) {
+    case NC_FLOAT:
+      ddata =3D (double*) var_data.varDatas[tstep_num];
+      fdata =3D (float*) var_data.varDatas[tstep_num];
+      // convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        ddata[i] =3D fdata[i];
+      break;
+    case NC_SHORT:
+      idata =3D (int*) var_data.varDatas[tstep_num];
+      sdata =3D (short*) var_data.varDatas[tstep_num];
+      // convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        idata[i] =3D sdata[i];
+      break;
+    default:
+      success =3D 1;
+  }
+
+  if (2 <=3D dbgOut.get_verbosity() && !success) {
+    double dmin, dmax;
+    int imin, imax;
+    switch (var_data.varDataType) {
+      case NC_DOUBLE:
+      case NC_FLOAT:
+        ddata =3D (double*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        dmin =3D dmax =3D ddata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (ddata[i] < dmin)
+            dmin =3D ddata[i];
+          if (ddata[i] > dmax)
+            dmax =3D ddata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
+        break;
+      case NC_INT:
+      case NC_SHORT:
+        idata =3D (int*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        imin =3D imax =3D idata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (idata[i] < imin)
+            imin =3D idata[i];
+          if (idata[i] > imax)
+            imax =3D idata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
+        break;
+      case NC_NAT:
+      case NC_BYTE:
+      case NC_CHAR:
+        break;
+      default: //default case added to remove compiler warnings
+        success =3D 1;
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index 3deebd3..3fc3724 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -14,20 +14,42 @@
 namespace moab {
=20
 //! Child helper class for HOMME grid (CAM_SE)
-class NCHelperHOMME : public NCHelper
+class NCHelperHOMME : public UcdNCHelper
 {
 public:
   NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions& opts);
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
+  //! Implementation of NCHelper::init_mesh_vals()
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
+  //! Implementation of NCHelper::create_mesh()
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  //! Implementation of NCHelper::get_mesh_type_name()
   virtual std::string get_mesh_type_name() { return "CAM_SE"; }
-  virtual bool is_scd_mesh() { return false; }
+
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_allocate()
+  virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
+                                                         std::vector<int>&=
 tstep_nums);
+  //! Implementation of UcdNCHelper::read_ucd_variable_setup()
+  virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
+                                            std::vector<int>& tstep_nums,
+                                            std::vector<ReadNC::VarData>& =
vdatas,
+                                            std::vector<ReadNC::VarData>& =
vsetdatas);
+#ifdef PNETCDF_FILE
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_async()
+  virtual ErrorCode read_ucd_variable_to_nonset_async(EntityHandle file_se=
t, std::vector<ReadNC::VarData>& vdatas,
+                                                      std::vector<int>& ts=
tep_nums);
+#else
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset()
+  virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
+                                                std::vector<int>& tstep_nu=
ms);
+#endif
+  //! Implementation of UcdNCHelper::convert_ucd_variable()
+  virtual ErrorCode convert_ucd_variable(ReadNC::VarData& var_data, int ts=
tep_num);
=20
 private:
-  int _spectralOrder; // read from variable 'np'
+  int _spectralOrder; // Read from variable 'np'
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperMPAS.cpp b/src/io/NCHelperMPAS.cpp
index b2ae8bc..1793585 100644
--- a/src/io/NCHelperMPAS.cpp
+++ b/src/io/NCHelperMPAS.cpp
@@ -13,7 +13,7 @@
=20
 namespace moab {
=20
-NCHelperMPAS::NCHelperMPAS(ReadNC* readNC, int fileId, const FileOptions& =
opts) : NCHelper(readNC, fileId)
+NCHelperMPAS::NCHelperMPAS(ReadNC* readNC, int fileId, const FileOptions& =
opts) : UcdNCHelper(readNC, fileId)
 {
   if (MB_SUCCESS =3D=3D opts.match_option("PARTITION_METHOD", "NODAL_PARTI=
TION"))
     readNC->partMethod =3D -1;
@@ -24,9 +24,8 @@ bool NCHelperMPAS::can_read_file(ReadNC* readNC, int file=
Id)
   std::vector<std::string>& dimNames =3D readNC->dimNames;
=20
   // If dimension name "vertexDegree" exists then it should be the MPAS gr=
id
-  if (std::find(dimNames.begin(), dimNames.end(), std::string("vertexDegre=
e")) !=3D dimNames.end()) {
+  if (std::find(dimNames.begin(), dimNames.end(), std::string("vertexDegre=
e")) !=3D dimNames.end())
     return true;
-  }
=20
   return false;
 }
@@ -43,4 +42,37 @@ ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi, =
const FileOptions& opts,
   return MB_SUCCESS;
 }
=20
+ErrorCode NCHelperMPAS::read_ucd_variable_setup(std::vector<std::string>& =
var_names, std::vector<int>& tstep_nums,
+                                                 std::vector<ReadNC::VarDa=
ta>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+
+ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset_allocate(EntityHandle =
file_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_num=
s)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+
+#ifdef PNETCDF_FILE
+ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset_async(EntityHandle fil=
e_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+#else
+ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset(EntityHandle file_set,=
 std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+#endif
+
+ErrorCode NCHelperMPAS::convert_ucd_variable(ReadNC::VarData& var_data, in=
t tstep_num)
+{
+  // TBD
+  return MB_SUCCESS;
+}
+
 } // namespace moab

diff --git a/src/io/NCHelperMPAS.hpp b/src/io/NCHelperMPAS.hpp
index 54c7146..1426e62 100644
--- a/src/io/NCHelperMPAS.hpp
+++ b/src/io/NCHelperMPAS.hpp
@@ -14,17 +14,39 @@
 namespace moab {
=20
 //! Child helper class for MPAS grid
-class NCHelperMPAS : public NCHelper
+class NCHelperMPAS : public UcdNCHelper
 {
 public:
   NCHelperMPAS(ReadNC* readNC, int fileId, const FileOptions& opts);
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
+  //! Implementation of NCHelper::init_mesh_vals()
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  //! Implementation of NCHelper::create_mesh()
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
+  //! Implementation of NCHelper::get_mesh_type_name()
   virtual std::string get_mesh_type_name() { return "MPAS"; }
-  virtual bool is_scd_mesh() { return false; }
+
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_allocate()
+  virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
+                                                         std::vector<int>&=
 tstep_nums);
+  //! Implementation of UcdNCHelper::read_ucd_variable_setup()
+  virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
+                                            std::vector<int>& tstep_nums,
+                                            std::vector<ReadNC::VarData>& =
vdatas,
+                                            std::vector<ReadNC::VarData>& =
vsetdatas);
+#ifdef PNETCDF_FILE
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_async()
+  virtual ErrorCode read_ucd_variable_to_nonset_async(EntityHandle file_se=
t, std::vector<ReadNC::VarData>& vdatas,
+                                                      std::vector<int>& ts=
tep_nums);
+#else
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset()
+  virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
+                                                std::vector<int>& tstep_nu=
ms);
+#endif
+  //! Implementation of UcdNCHelper::convert_ucd_variable()
+  virtual ErrorCode convert_ucd_variable(ReadNC::VarData& var_data, int ts=
tep_num);
 };
=20
 } // namespace moab

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/fathomteam/moab/commits/baace931a9a9/
Changeset:   baace931a9a9
Branch:      None
User:        danwu
Date:        2013-06-25 16:18:53
Summary:     Merged fathomteam/moab into master
Affected #:  29 files

diff --git a/MeshFiles/unittest/io/Makefile.am b/MeshFiles/unittest/io/Make=
file.am
index ece20cf..8257e5f 100644
--- a/MeshFiles/unittest/io/Makefile.am
+++ b/MeshFiles/unittest/io/Makefile.am
@@ -3,6 +3,7 @@ EXTRA_DIST =3D HommeMapping.nc \
              brick_cubit10.2.cub \
              brick_cubit10.cub \
              camEul26x48x96.t3.nc \
+             fv26x46x72.t.3.nc \
 	     cubtest12.cub \
 	     cubtest.jou \
 	     dum.sat \

diff --git a/MeshFiles/unittest/mpas_p8.h5m b/MeshFiles/unittest/mpas_p8.h5m
new file mode 100644
index 0000000..75662d2
Binary files /dev/null and b/MeshFiles/unittest/mpas_p8.h5m differ

diff --git a/doc/DG/moabDG.h b/doc/DG/moabDG.h
new file mode 100644
index 0000000..d2e14f0
--- /dev/null
+++ b/doc/DG/moabDG.h
@@ -0,0 +1,259 @@
+/*! \page developerguide Developer's Guide (MOAB 4.6)
+=20
+  \subpage dg-contents
+=20
+  \subpage dg-figures
+
+  \page dg-contents Table of Contents
+
+  \ref sequence
+
+  \ref manager
+
+  \ref s-mesh
+
+  \ref sets
+
+  \section sequence  1. EntitySequence & SequenceData
+
+  \subsection figure1 Figure 1: EntitySequences For One SequenceData
+
+The <I>SequenceData</I> class manages as set of arrays of per-entity value=
s. Each
+<I>SequenceData</I> has a start and end handle denoting the block of entit=
ies for which
+the arrays contain data. The arrays managed by a <I>SequenceData</I> insta=
nce are
+divided into three groups:
+
+- Type-specific data (connectivity, coordinates, etc.): zero or more array=
s.
+- Adjacency data: zero or one array.
+- Dense tag data: zero or more arrays.
+.
+
+The abstract <I>EntitySequence</I> class is a non-strict subset of a <I>Se=
quenceData</I>.
+It contains a pointer to a <I>SequenceData</I> and the start and end handl=
es to indi-
+cate the subset of the referenced <I>SequenceData</I>. The <I>EntitySequen=
ce</I> class is
+used to represent the regions of valid (or allocated) handles in a <I>Sequ=
enceData</I>.
+A <I>SequenceData</I> is expected to be referenced by one or more <I>Entit=
ySequence</I>
+instances.
+
+Initial <I>EntitySequence</I> and <I>SequenceData</I> pairs are typically =
created in one
+of two configurations. When reading from a file, a <I>SequenceData</I> wil=
l be created
+to represent all of a single type of entity contained in a file. As all en=
tries in the <I>SequenceData</I> correspond to valid handles (entities read=
 from the file) a single
+<I>EntitySequence</I> instance corresponding to the entire <I>SequenceData=
</I> is initially
+created. The second configuration arises when allocating a single entity. =
If no
+entities have been allocated yet, a new <I>SequenceData</I> must be create=
d to store
+the entity data. It is created with a constant size (e.g. 4k entities). Th=
e new
+<I>EntitySequence</I> corresponds to only the first entity in the <I>Seque=
nceData</I>: the
+one allocated entity. As subsequent entities are allocated, the <I>EntityS=
equence</I>
+is extended to cover more of the corresponding <I>SequenceData</I>.
+
+Concrete subclasses of the <I>EntitySequence</I> class are responsible for=
 rep-
+resenting specific types of entities using the array storage provided by t=
he
+<I>SequenceData</I> class. They also handle allocating <I>SequenceData</I>=
 instances with
+appropriate arrays for storing a particular type of entity. Each concrete =
subclass
+typically provides two constructors corresponding to the two initial alloc=
ation
+configurations described in the previous paragraph. <I>EntitySequence</I> =
imple-
+mentations also provide a split method, which is a type of factory method.=
 It
+modifies the called sequence and creates a new sequence such that the rang=
e of
+entities represented by the original sequence is split.
+
+The <I>VertexSequence</I> class provides an <I>EntitySequence</I> for stor=
ing ver-
+tex data. It references a SequenceData containing three arrays of doubles
+for storing the blocked vertex coordinate data. The <I>ElementSequence</I>=
 class
+extends the <I>EntitySequence</I> interface with element-specific function=
ality. The
+<I>UnstructuredElemSeq</I> class is the concrete implementation of <I>Elem=
entSequence</I>
+used to represent unstructured elements, polygons, and polyhedra. <I>MeshS=
etSequence</I>
+is the <I>EntitySequence</I> used for storing entity sets.
+
+Each <I>EntitySequence</I> implementation also provides an implementation =
of
+the values per entity method. This value is used to determine if an exist-
+ing <I>SequenceData</I> that has available entities is suitable for storin=
g a particular
+entity. For example, <I>UnstructuredElemSeq</I> returns the number of node=
s per el-
+ement from values per entity. When allocating a new element with a specific
+number of nodes, this value is used to determine if that element may be st=
ored
+in a specific <I>SequenceData</I>. For vertices, this value is always zero=
. This could
+be changed to the number of coordinates per vertex, allowing representatio=
n of
+mixed-dimension data. However, API changes would be required to utilize su=
ch
+a feature. Sequences for which the corresponding data cannot be used to st=
ore
+new entities (e.g. structured mesh discussed in a later section) will retu=
rn -1 or
+some other invalid value.
+
+ \ref dg-contents
+
+  \section manager 2. TypeSequenceManager & SequenceManager=20
+
+The <I>TypeSequenceManager</I> class maintains an organized set of <I>Enti=
tySequence</I>
+instances and corresponding <I>SequenceData</I> instances. It is used to m=
anage
+all such instances for entities of a single <I>EntityType</I>. <I>TypeSequ=
enceManager</I>
+enforces the following four rules on its contained data:
+
+-# No two <I>SequenceData</I> instances may overlap. =20
+-# No two <I>EntitySequence</I> instances may overlap.
+-# Every <I>EntitySequence</I> must be a subset of a <I>SequenceData</I>.
+-# Any pair of <I>EntitySequence</I> instances referencing the same <I>Seq=
uenceData</I> must be separated by at least one unallocated handle.
+.
+
+  \subsection figure2 Figure 2: SequenceManager and Related Classes
+
+The first three rules are required for the validity of the data model. The
+fourth rule avoids unnecessary inefficiency. It is implemented by merging =
such
+adjacent sequences. In some cases, other classes (e.g. <I>SequenceManager<=
/I>) can
+modify an <I>EntitySequence</I> such that the fourth rule is violated. In =
such cases,
+the <I>TypeSequenceManager::notify</I> prepended or <I>TypeSequenceManager=
::notify</I> appended
+method must be called to maintain the integrity of the data<sup>1</sup>. T=
he above rules
+(including the fourth) are assumed in many other methods of the <I>TypeSeq=
uenceManager</I>
+class, such that those methods will fail or behave unexpectedly if the man=
aged
+data does not conform to the rules.
+
+<I>TypeSequenceManager</I> contains three principal data structures. The f=
irst is
+a <I>std::set</I> of <I>EntitySequence</I> pointers sorted using a custom =
comparison op-
+erator that queries the start and end handles of the referenced sequences.=
 The
+comparison operation is defined as: <I>a->end_handle() < b->start_handle()=
</I>.
+This method of comparison has the advantage that a sequence corresponding =
to
+a specific handle can be located by searching the set for a =E2=80=9Cseque=
nce=E2=80=9D beginning
+and ending with the search value. The lower bound and find methods pro-
+vided by the library are guaranteed to return the sequence, if it exists. =
Using
+such a comparison operator will result in undefined behavior if the set co=
ntains
+overlapping sequences. This is acceptable, as rule two above prohibits such
+a configuration. However, some care must be taken in writing and modifying
+methods in <I>TypeSequenceManager</I> so as to avoid having overlapping se=
quences
+as a transitory state of some operation.
+
+The second important data member of <I>TypeSequenceManager</I> is a pointer
+to the last referenced <I>EntitySequence</I>. This =E2=80=9Ccached=E2=80=
=9D value is used to speed up
+searches by entity handle. This pointer is never null unless the sequence =
is empty.
+This rule is maintained to avoid unnecessary branches in fast query paths.=
 In
+cases where the last referenced sequence is deleted, <I>TypeSequenceManage=
r</I> will
+typically assign an arbitrary sequence (e.g. the first one) to the last re=
ferenced
+pointer.
+
+The third data member of <I>TypeSequenceManager</I> is a <I>std::set</I> o=
f <I>SequenceData</I>
+instances that are not completely covered by a <I>EntitySequence</I> insta=
nce<sup>2</sup>.
+This list is searched when allocating new handles. <I>TypeSequenceManager<=
/I> also
+embeds in each <I>SequenceData</I> instance a reference to the first corre=
sponding
+<I>EntitySequence</I> so that it may be located quickly from only the <I>S=
equenceData</I>
+pointer.
+
+The <I>SequenceManager</I> class contains an array of <I>TypeSequenceManag=
er</I> in-
+stances, one for each <I>EntityType</I>. It also provides all type-specifi=
c operations
+such as allocating the correct <I>EntitySequence</I> subtype for a given <=
I>EntityType</I>.
+
+<sup>1</sup>This source of potential error can be eliminated with changes =
to the entity set representation. This is discussed in a later section.
+
+<sup>2</sup>Given rule four for the data managed by a <I>TypeSequenceManag=
er</I>, any <I>SequenceData</I> for which all handles are allocated will be=
 referenced by exactly one <I>EntitySequence</I>.
+
+  \ref dg-contents
+
+ \section s-mesh 3. Structured Mesh
+
+Structured mesh storage is implemented using subclasses of <I>SequenceData=
</I>:
+<I>ScdElementData</I> and <I>ScdVertexData</I>. The <I>StructuredElementSe=
q</I> class is
+used to access the structured element connectivity. A standard <I>VertexSe=
quence</I>
+instance is used to access the ScdVertexData because the vertex data stora=
ge
+is the same as for unstructured mesh.
+
+  \ref dg-contents
+
+  \section sets 4. Entity Sets
+
+- MeshSetSequence
+
+The <I>MeshSetSequence</I> class is the same as most other subclasses of <=
I>EntitySequence</I>
+in that it utilizes SequenceData to store its data. A single array in the =
<I>SequenceData</I>
+is used to store instances of the MeshSet class, one per allocated <I>Enti=
tyHandle</I>.
+<I>SequenceData</I> allocates all of its managed arrays using malloc and f=
ree as
+simple arrays of bytes. <I>MeshSetSequence</I> does in-place construction =
and de-
+struction of <I>MeshSet</I> instances within that array. This is similar t=
o what is
+done by <I>std::vector</I> and other container classes that may own more s=
torage
+than is required at a given time for contained objects.
+
+- MeshSet
+
+  \subsection figure3 Figure 3: SequenceManager and Related Classes
+
+The <I>MeshSet</I> class is used to represent a single entity set instance=
 in MOAB.
+The class is optimized to minimize storage (further possible improvements =
in
+storage size are discussed later.)
+
+Figure 3 shows the memory layout of an instance of the <I>MeshSet</I> clas=
s.
+The flags member holds the set creation bit flags: <I>MESHSET_TRACK_OWNER<=
/I>,
+<I>MESHSET_SET</I>, and <I>MESHSET_ORDERED</I>. The presence of the <I>MES=
HSET_TRACK_OWNER</I>
+indicates that reverse links from the contained entities back to the ownin=
g set
+should be maintained in the adjacency list of each entity. The <I>MESHSET_=
SET</I>
+and <I>MESHSET_ORDERED</I> bits are mutually exclusive, and as such most c=
ode only
+tests for the <I>MESHSET_ORDERED</I>, meaning that in practice the <I>MESH=
SET_SET</I> bit is
+ignored. <I>MESHSET_ORDERED</I> indicates that the set may contain duplica=
te handles
+and that the order that the handles are added to the set should be preserv=
ed.
+In practice, such sets are stored as a simple list of handles. <I>MESHSET_=
SET</I> (or in
+practice, the lack of <I>MESHSET_ORDERED</I>) indicates that the order of =
the handles
+need not be preserved and that the set may not contain duplicate handles. =
Such
+sets are stored in a sorted range-compacted format similar to that of the =
Range
+class.
+
+The memory for storing contents, parents, and children are each handled in
+the same way. The data in the class is composed of a 2-bit =E2=80=98size=
=E2=80=99 field and two
+values, where the two values may either be two handles or two pointers. Th=
e size
+bit-fields are grouped together to reduce the required amount of memory. I=
f the
+numerical value of the 2-bit size field is 0 then the corresponding list i=
s empty.
+If the 2-bit size field is either 1 or 2, then the contents of the corresp=
onding list
+are stored directly in the corresponding two data fields of the MeshSet ob=
ject.
+If the 2-bit size field has a value of 3 (11 binary), then the correspondi=
ng two
+data fields store the begin and end pointers of an external array of handl=
es.
+The number of handles in the external array can be obtained by taking the
+difference of the start and end pointers. Note that unlike <I>std::vector<=
/I>, we
+do not store both an allocated and used size. We store only the =E2=80=98u=
sed=E2=80=99 size
+and call std::realloc whenever the used size is modified, thus we rely on =
the
+std::malloc implementation in the standard C library to track =E2=80=98all=
ocated=E2=80=99 size
+for us. In practice this performs well but does not return memory to the =
=E2=80=98system=E2=80=99
+when lists shrink (unless they shrink to zero). This overall scheme could =
exhibit
+poor performance if the size of one of the data lists in the set frequentl=
y changes
+between less than two and more than two handles, as this will result in fr=
equent
+releasing and re-allocating of the memory for the corresponding array.
+
+If the <I>MESHSET_ORDERED</I> flag is not present, then the set contents l=
ist (parent
+and child lists are unaffected) is stored in a range-compacted format. In =
this
+format the number of handles stored in the array is always a multiple of t=
wo.
+Each consecutive pair of handles indicate the start and end, inclusive, of=
 a range
+of handles contained in the set. All such handle range pairs are stored in=
 sorted
+order and do not overlap. Nor is the end handle of one range ever one less=
 than
+the start handle of the next. All such =E2=80=98adjacent=E2=80=99 range pa=
irs are merged into a
+single pair. The code for insertion and removal of handles from range-form=
atted
+set content lists is fairly complex. The implementation will guarantee tha=
t a
+given call to insert entities into a range or remove entities from a range=
 is never
+worse than O(ln n) + O(m + n), where =E2=80=98n=E2=80=99 is the number of =
handles to insert
+and =E2=80=98m=E2=80=99 is the number of handles already contained in the =
set. So it is generally
+much more efficient to build Ranges of handles to insert (and remove) and =
call
+MOAB to insert (or remove) the entire list at once rather than making may
+calls to insert (or remove) one or a few handles from the contents of a se=
t.
+The set storage could probably be further minimized by allowing up to six
+handles in one of the lists to be elided. That is, as there are six potent=
ial =E2=80=98slots=E2=80=99
+in the MeshSet object then if two of the lists are empty it should be poss=
ible to store up to six values of the remaining list directly in the MeshSe=
t object.
+However, the additional runtime cost of such complexity could easily outwe=
igh
+any storage advantage. Further investigation into this has not been done b=
ecause
+the primary motivation for the storage optimization was to support binary =
trees.
+
+Another possible optimization of storage would be to remove the <I>MeshSet=
</I>
+object entirely and instead store the data in a =E2=80=98blocked=E2=80=99 =
format. The corre-
+sponding <I>SequenceData</I> would contain four arrays: flags, parents, ch=
ildren, and
+contents instead of a single array of <I>MeshSet</I> objects. If this were=
 done then
+no storage need ever be allocated for parent or child links if none of the=
 sets
+in a <I>SequenceData</I> has parent or child links. The effectiveness of t=
he storage
+reduction would depend greatly on how sets get grouped into <I>SequenceDat=
as</I>.
+This alternate storage scheme might also allow for better cache utilizatio=
n as it
+would group like data together. It is often the case that application code=
 that
+is querying the contents of one set will query the contents of many but ne=
ver
+query the parents or children of any set. Or that an application will quer=
y only
+parent or child links of a set without every querying other set properties=
. The
+downside of this solution is that it makes the implementation a little les=
s mod-
+ular and maintainable because the existing logic contained in the <I>MeshS=
et</I> class
+would need to be spread throughout the <I>MeshSetSequence</I> class.
+
+  \ref dg-contents
+
+  \page dg-figures List of Figures
+
+  \ref figure1
+
+  \ref figure2
+
+  \ref figure3
+*/

diff --git a/doc/UG/moabUG.h b/doc/UG/moabUG.h
new file mode 100644
index 0000000..cea942d
--- /dev/null
+++ b/doc/UG/moabUG.h
@@ -0,0 +1,1064 @@
+/*! \page userguide User's Guide (MOAB 4.6)
+=20
+  \subpage team=20
+=20
+  \subpage contents
+=20
+  \subpage figures
+=20
+  \subpage tables
+=20
+  \subpage differences
+
+  \subpage building
+
+  \page team MOAB team members
+ <h2>The MOAB Team, including: </h2>
+=20
+ - Timothy J. Tautges (Argonne National Lab, Univ Wisconsin-Madison)=20
+ - Iulian Grindeanu (Argonne National Lab)=20
+ - Rajeev Jain (Argonne National Lab)
+ - Xiabing Xu (Argonne National Lab)
+
+
+ <h2>Emeritus members:</h2>
+=20
+ - Jason A. Kraftcheck
+ - Brandon M. Smith
+ - Hong-Jun Kim
+ - Jim Porter
+=20
+  \page contents Table of Contents
+=20
+  \ref introduction =20
+
+  \ref interface    =20
+
+     \ref twoone   =20
+
+     \ref twotwo    =20
+
+     \ref twothree      =20
+
+     \ref twofour  =20
+
+  \ref api    =20
+
+  \ref services     =20
+
+    \ref fourone   =20
+
+    \ref fourtwo  =20
+
+    \ref fourthree =20
+
+    \ref fourfour     =20
+
+    \ref fourfive   =20
+
+    \ref foursix =20
+
+  \ref parallel     =20
+
+    \ref fiveone   =20
+
+    \ref fivetwo    =20
+
+    \ref fivethree   =20
+
+    \ref fivefour     =20
+
+  \ref applications  =20
+
+  \ref implementation        =20
+
+  \ref representation    =20
+
+  \ref element   =20
+
+    \ref nineone =20
+
+    \ref ninetwo       =20
+
+    \ref ninethree     =20
+
+  \ref performance  =20
+
+  \ref conclusions   =20
+
+  \ref references=20
+
+  \section introduction 1. Introduction
+
+In scientific computing, systems of partial differential equations (PDEs) =
are solved on computers.  One of the most widely used methods to solve PDEs=
 numerically is to solve over discrete neighborhoods or =E2=80=9Celements=
=E2=80=9D of the domain.  Popular discretization methods include Finite Dif=
ference (FD), Finite Element (FE), and Finite Volume (FV).  These methods r=
equire the decomposition of the domain into a discretized representation, w=
hich is referred to as a =E2=80=9Cmesh=E2=80=9D.  The mesh is one of the fu=
ndamental types of data linking the various tools in the analysis process (=
mesh generation, analysis, visualization, etc.).  Thus, the representation =
of mesh data and operations on those data play a very important role in PDE=
-based simulations.
+=20
+MOAB is a component for representing and evaluating mesh data.  MOAB can s=
tore structured and unstructured mesh, consisting of elements in the finite=
 element =E2=80=9Czoo=E2=80=9D, along with polygons and polyhedra.  The fun=
ctional interface to MOAB is simple, consisting of only four fundamental da=
ta types.  This data is quite powerful, allowing the representation of most=
 types of metadata commonly found on the mesh.  Internally MOAB uses array-=
based storage for fine-grained data, which in many cases provides more effi=
cient access, especially for large portions of mesh and associated data.  M=
OAB is optimized for efficiency in space and time, based on access to mesh =
in chunks rather than through individual entities, while also versatile eno=
ugh to support individual entity access.
+
+The MOAB data model consists of the following four fundamental types: mesh=
 interface instance, mesh entities (vertex, edge, tri, etc.), sets, and tag=
s.  Entities are addressed through handles rather than pointers, to allow t=
he underlying representation of an entity to change without changing the ha=
ndle to that entity.  Sets are arbitrary groupings of mesh entities and oth=
er sets.  Sets also support parent/child relationships as a relation distin=
ct from sets containing other sets.  The directed graph provided by set par=
ent/child relationships is useful for embedding graphs whose nodes include =
collections of mesh entities; this approach has been used to represent a wi=
de variety of application-specific data, including geometric model topology=
, processor partitions, and various types of search trees.  Tags are named =
data which can be assigned to the mesh as a whole, individual entities, or =
sets.  Tags are a mechanism for attaching data to individual entities, and =
sets are a mechanism for describing relations between entities; the combina=
tion of these two mechanisms is a powerful yet simple interface for represe=
nting metadata or application-specific data.
+
+Various mesh-related tools are provided with MOAB or can be used directly =
with MOAB.  These tools can be used for mesh format translation (mbconvert)=
, mesh skinning (Skinner class), solution transfer between meshes (MBCouple=
r tool), ray tracing and other geometric searches (OrientedBoxTreeTool, Ada=
ptiveKDTree), visualization (vtkMOABReader tool), and relation between mesh=
 and geometric models (the separately-packed Lasso tool).  These tools are =
described later in this document.
+
+MOAB is written in the C++ programming language, with applications interac=
ting with MOAB mostly through its moab::Interface class.  All of the MOAB f=
unctions and classes are isolated in and accessed through the moab namespac=
e<sup>1</sup>. The remainder of this report gives class and function names =
without the =E2=80=9Cmoab::=E2=80=9D namespace qualification; unless otherw=
ise noted, the namespace qualifier should be added to all class and functio=
n names referenced here.  MOAB also implements the iMesh interface, which i=
s specified in C but can be called directly from other languages.  Almost a=
ll of the functionality in MOAB can be accessed through the iMesh interface=
.  MOAB is developed and supported on the Linux and MacOS operating systems=
, as well as various HPC operating systems.  MOAB can be used on parallel c=
omputing systems as well, including both clusters and high-end parallel sys=
tems like IBM BG/P and Cray systems.  MOAB is released under a standard LGP=
L open source software license.
+
+MOAB is used in several ways in various applications.  MOAB serves as the =
underlying mesh data representation in several scientific computing applica=
tions [1].  MOAB can also be used as a mesh format translator, using reader=
s and writers included in MOAB.  MOAB has also been used as a bridge to cou=
ple results in multi-physics analysis and to link these applications with o=
ther mesh services [2].
+
+The remainder of this report is organized as follows.  Section 2, =E2=80=
=9CGetting Started=E2=80=9D, provides a few simple examples of using MOAB t=
o perform simple tasks on a mesh.  Section 3 discusses the MOAB data model =
in more detail, including some aspects of the implementation.  Section 4 su=
mmarizes the MOAB function API.  Section 5 describes some of the tools incl=
uded with MOAB, and the implementation of mesh readers/writers for MOAB.  S=
ection 6 describes how to build MOAB-based applications.  Section 7 contain=
s a brief description of MOAB=E2=80=99s relation to the iMesh mesh interfac=
e.  Sections 8 and 9 discuss MOAB's representations of structured and spect=
ral element meshes, respectively.  Section 10 gives helpful hints for acces=
sing MOAB in an efficient manner from applications.  Section 11 gives a con=
clusion and future plans for MOAB development.  Section 12 gives references=
 cited in this report.
+
+Several other sources of information about MOAB may also be of interest to=
 readers.  Meta-data conventions define how sets and /or tags are used toge=
ther to represent various commonly-used simulation constructs; conventions =
used by MOAB are described in Ref [4], which is also included in the MOAB s=
ource distribution.  This document is maintained separately from this docum=
ent, since it is expected to change over time.  The MOAB project maintains =
a wiki [5], which links to most MOAB-related information.  MOAB also uses s=
everal mailing lists [6],[7] for MOAB-related discussions.  Potential users=
 are encouraged to interact with the MOAB team using these mailing lists.
+
+<sup>1</sup> Non-namespaced names are also provided for backward compatibi=
lity, with the =E2=80=9CMB=E2=80=9D prefix added to the class or variable n=
ame.
+
+ \ref contents
+
+ \section interface 2. MOAB Data Model
+The MOAB data model describes the basic types used in MOAB and the languag=
e used to communicate that data to applications.  This chapter describes th=
at data model, along with some of the reasons for some of the design choice=
s in MOAB.
+
+ \ref contents
+
+ \subsection twoone 2.1. MOAB Interface
+MOAB is written in C++.  The primary interface with applications is throug=
h member functions of the abstract base class Interface.  The MOAB library =
is created by instantiating Core, which implements the Interface API.  Mult=
iple instances of MOAB can exist concurrently in the same application; mesh=
 entities are not shared between these instancesi<sup>2</sup>.  MOAB is mos=
t easily viewed as a database of mesh objects accessed through the instance=
.  No other assumptions explicitly made about the nature of the mesh stored=
 there; for example, there is no fundamental requirement that elements fill=
 space or do not overlap each other geometrically.
+=20
+<sup>2</sup> One exception to this statement is when the parallel interfac=
e to MOAB is used; in this case, entity sharing between instances is handle=
d explicitly using message passing.  This is described in more detail in Se=
ction 5 of this document.
+
+ \ref contents
+
+ \subsection twotwo 2.2. Mesh Entities
+MOAB represents the following topological mesh entities: vertex, edge, tri=
angle, quadrilateral, polygon, tetrahedron, pyramid, prism, knife, hexahedr=
on, polyhedron.  MOAB uses the EntityType enumeration to refer to these ent=
ity types (see Table 1).  This enumeration has several special characterist=
ics, chosen intentionally: the types begin with vertex, entity types are gr=
ouped by topological dimension, with lower-dimensional entities appearing b=
efore higher dimensions; the enumeration includes an entity type for sets (=
described in the next section); and MBMAXTYPE is included at the end of thi=
s enumeration, and can be used to terminate loops over type.  In addition t=
o these defined values, the an increment operator (++) is defined such that=
 variables of type EntityType can be used as iterators in loops.
+MOAB refers to entities using =E2=80=9Chandles=E2=80=9D.  Handles are impl=
emented as long integer data types, with the four highest-order bits used t=
o store the entity type (mesh vertex, edge, tri, etc.) and the remaining bi=
ts storing the entity id.  This scheme is convenient for applications becau=
se:
+- Handles sort lexicographically by type and dimension; this can be useful=
 for grouping and iterating over entities by type.
+- The type of an entity is indicated by the handle itself, without needing=
 to call a function.
+- Entities allocated in sequence will typically have contiguous handles; t=
his characteristic can be used to efficiently store and operate on large li=
sts of handles.
+.
+
+This handle implementation is exposed to applications intentionally, becau=
se of optimizations that it enables, and is unlikely to change in future ve=
rsions.
+
+  \subsection tableone Table 1: Values defined for the EntityType enumerat=
ed type.
+<table border=3D"1">
+<tr>
+<td>MBVERTEX =3D 0</td>
+<td>MBPRISM</td>
+</tr>
+<tr>
+<td>MBEDGE</td>
+<td>MBKNIFE</td>
+</tr>
+<tr>
+<td>MBTRI</td>
+<td>MBHEX</td>
+</tr>
+<tr>
+<td>MBQUAD</td>
+<td>MBPOLYHEDRON</td>
+</tr>
+<tr>
+<td>MBPOLYGON</td>
+<td>MBENTITYSET</td>
+</tr>
+<tr>
+<td>MBTET</td>
+<td>MBMAXTYPE</td>
+</tr>
+<tr>
+<td>MBPYRAMID</td>
+<td></td>
+</tr>
+</table>
+
+MOAB defines a special class for storing lists of entity handles, named Ra=
nge.  This class stores handles as a series of (start_handle, end_handle) s=
ubrange tuples.  If a list of handles has large contiguous ranges, it can b=
e represented in almost constant size using Range.  Since entities are typi=
cally created in groups, e.g. during mesh generation or file import, a high=
 degree of contiguity in handle space is typical.  Range provides an interf=
ace similar to C++ STL containers like std::vector, containing iterator dat=
a types and functions for initializing and iterating over entity handles st=
ored in the range.  Range also provides functions for efficient Boolean ope=
rations like subtraction and intersection.  Most API functions in MOAB come=
 in both range-based and vector-based variants.  By definition, a list of e=
ntities stored in an Range is always sorted, and can contain a given entity=
 handle only once.  Range cannot store the handle 0 (zero).
+
+Typical usage of an Range object would look like:
+
+\code
+using namespace moab;
+   int my_function(Range &from_range) {
+          int num_in_range =3D from_range.size();
+          Range to_range;
+          Range::iterator rit;
+    for (rit =3D from_range.begin(); rit !=3D from_range.end(); rit++) {
+            EntityHandle this_ent =3D *rit;
+            to_range.insert(this_ent);
+          }
+        }
+\endcode
+
+Here, the range is iterated similar to how std::vector is iterated.
+
+  \ref contents
+
+ \subsection adjacencies 2.2.1. Adjacencies & AEntities=20
+
+The term adjacencies is used to refer to those entities topologically conn=
ected to a given entity, e.g. the faces bounded by a given edge or the vert=
ices bounding a given region.  The same term is used for both higher-dimens=
ional (or bounded) and lower-dimensional (or bounding) adjacent entities.  =
MOAB provides functions for querying adjacent entities by target dimension,=
 using the same functions for higher- and lower-dimension adjacencies.  By =
default, MOAB stores the minimum data necessary to recover adjacencies betw=
een entities.  When a mesh is initially loaded into MOAB, only entity-verte=
x (i.e. =E2=80=9Cdownward=E2=80=9D) adjacencies are stored, in the form of =
entity connectivity.  When =E2=80=9Cupward=E2=80=9D adjacencies are request=
ed for the first time, e.g. from vertices to regions, MOAB stores all verte=
x-entity adjacencies explicitly, for all entities in the mesh.  Non-vertex =
entity to entity adjacencies are never stored, unless explicitly requested =
by the application.
+
+In its most fundamental form, a mesh need only be represented by its verti=
ces and the entities of maximal topological dimension.  For example, a hexa=
hedral mesh can be represented as the connectivity of the hex elements and =
the vertices forming the hexes.  Edges and faces in a 3D mesh need not be e=
xplicitly represented.  We refer to such entities as =E2=80=9CAEntities=E2=
=80=9D, where =E2=80=98A=E2=80=99 refers to =E2=80=9CAuxiliary=E2=80=9D, =
=E2=80=9CAncillary=E2=80=9D, and a number of other words mostly beginning w=
ith =E2=80=98A=E2=80=99.  Individual AEntities are created only when reques=
ted by applications, either using mesh modification functions or by request=
ing adjacencies with a special =E2=80=9Ccreate if missing=E2=80=9D flag pas=
sed as =E2=80=9Ctrue=E2=80=9D.  This reduces the overall memory usage when =
representing large meshes.  Note entities must be explicitly represented be=
fore they can be assigned tag values or added to entity sets (described in =
following Sections).
+
+\ref contents
+
+ \subsection twothree 2.3. Entity Sets
+Entity sets are used to store arbitrary collections of entities and other =
sets.  Sets are used for a variety of things in mesh-based applications, fr=
om the set of entities discretizing a given geometric model entity to the e=
ntities partitioned to a specific processor in a parallel finite element ap=
plication.  MOAB entity sets can also store parent/child relations with oth=
er entity sets, with these relations distinct from contains relations.  Par=
ent/child relations are useful for building directed graphs with graph node=
s representing collections of mesh entities; this construct can be used, fo=
r example, to represent an interface of mesh faces shared by two distinct c=
ollections of mesh regions.  MOAB also defines one special set, the =E2=80=
=9Croot set=E2=80=9D or the interface itself; all entities are part of this=
 set by definition.  Defining a root set allows the use of a single set of =
MOAB API functions to query entities in the overall mesh as well as its sub=
sets.
+
+MOAB entity sets can be one of two distinct types: list-type entity sets p=
reserve the order in which entities are added to the set, and can store a g=
iven entity handle multiple times in the same set; set-type sets are always=
 ordered by handle, regardless of the order of addition to the set, and can=
 store a given entity handle only once.  This characteristic is assigned wh=
en the set is created, and cannot be changed during the set=E2=80=99s lifet=
ime.
+
+MOAB provides the option to track or not track entities in a set.  When en=
tities (and sets) are deleted by other operations in MOAB, they will also b=
e removed from containing sets for which tracking has been enabled.  This b=
ehavior is assigned when the set is created, and cannot be changed during t=
he set=E2=80=99s lifetime.  The cost of turning tracking on for a given set=
 is sizeof(EntityHandle) for each entity added to the set; MOAB stores cont=
aining sets in the same list which stores adjacencies to other entities.
+
+Using an entity set looks like the following:
+\code
+using namespace moab;
+// load a file using MOAB, putting the loaded mesh into a file set
+EntityHandle file_set;
+ErrorCode rval =3D moab->create_meshset(MESHSET_SET, file_set);
+rval =3D moab->load_file(=E2=80=9Cfname.vtk=E2=80=9D, &file_set);
+Range set_ents;
+// get all the 3D entities in the set
+rval =3D moab->get_entities_by_dimension(file_set, 3, set_ents);
+\endcode
+
+Entity sets are often used in conjunction with tags (described in the next=
 section), and provide a powerful mechanism to store a variety of meta-data=
 with meshes.
+
+\ref contents
+
+ \subsection twofour 2.4. Tags=20
+
+Applications of a mesh database often need to attach data to mesh entities=
.  The types of attached data are often not known at compile time, and can =
vary across individual entities and entity types.  MOAB refers to this atta=
ched data as a =E2=80=9Ctag=E2=80=9D.  Tags can be thought of loosely as a =
variable, which can be given a distinct value for individual entities, enti=
ty sets, or for the interface itself.  A tag is referenced using a handle, =
similarly to how entities are referenced in MOAB.  Each MOAB tag has the fo=
llowing characteristics, which can be queried through the MOAB interface:
+- Name
+- Size (in bytes)
+- Storage type
+- Data type (integer, double, opaque, entity handle)
+- Handle
+.
+
+The storage type determines how tag values are stored on entities. =20
+
+- Dense: Dense tag values are stored in arrays which match arrays of conti=
guous entity handles.  Dense tags are more efficient in both storage and me=
mory if large numbers of entities are assigned the same tag.  Storage for a=
 given dense tag is not allocated until a tag value is set on an entity; me=
mory for a given dense tag is allocated for all entities in a given sequenc=
e at the same time.
+- Sparse: Sparse tags are stored as a list of (entity handle, tag value) t=
uples, one list per sparse tag, sorted by entity handle.
+- Bit: Bit tags are stored similarly to dense tags, but with special handl=
ing to allow allocation in bit-size amounts per entity.
+.
+
+MOAB also supports variable-length tags, which can have a different length=
 for each entity they are assigned to.  Variable length tags are stored sim=
ilarly to sparse tags.
+
+The data type of a tag can either be one understood at compile time (integ=
er, double, entity handle), in which case the tag value can be saved and re=
stored properly to/from files and between computers of different architectu=
re (MOAB provides a native HDF5-based save/restore format for this purpose;=
 see Section 4.6).  The opaque data type is used for character strings, or =
for allocating =E2=80=9Craw memory=E2=80=9D for use by applications (e.g. f=
or storage application-defined structures or other abstract data types).  T=
hese tags are saved and restored as raw memory, with no special handling fo=
r endian or precision differences.
+
+An application would use the following code to attach a double-precision t=
ag to vertices in a mesh, e.g. to assign a temperature field to those verti=
ces:
+
+\code
+using namespace moab;
+// load a file using MOAB and get the vertices
+ErrorCode rval =3D moab->load_file(=E2=80=9Cfname.vtk=E2=80=9D);
+Range verts;
+rval =3D moab->get_entities_by_dimension(0, 0, verts);
+// create a tag called =E2=80=9CTEMPERATURE=E2=80=9D
+Tag temperature;
+double def_val =3D -1.0d-300, new_val =3D 273.0;
+rval =3D moab->tag_create(=E2=80=9CTEMPERATURE=E2=80=9D, sizeof(double), M=
B_TAG_DENSE,=20
+                        MB_TYPE_DOUBLE, temperature, &def_val);
+// assign a value to vertices
+for (Range::iterator vit =3D verts.begin();=20
+     vit !=3D verts.end(); vit++)=20
+  rval =3D moab->tag_set_data(temperature, &(*rit), 1, &new_val);
+
+\endcode
+
+The semantic meaning of a tag is determined by applications using it.  How=
ever, to promote interoperability between applications, there are a number =
of tag names reserved by MOAB which are intended to be used by convention. =
 Mesh readers and writers in MOAB use these tag conventions, and applicatio=
ns can use them as well to access the same data. Ref. [4] maintains an up-t=
o-date list of conventions for meta-data usage in MOAB.
+
+  \ref contents
+
+  \section api 3. MOAB API Design Philosophy and Summary
+
+This section describes the design philosophy behind MOAB, and summarizes t=
he functions, data types and enumerated variables in the MOAB API.  A compl=
ete description of the MOAB API is available in online documentation in the=
 MOAB distribution [8].
+
+MOAB is designed to operate efficiently on collections of entities.  Entit=
ies are often created or referenced in groups (e.g. the mesh faces discreti=
zing a given geometric face, the 3D elements read from a file), with those =
groups having some form of temporal or spatial locality.  The interface pro=
vides special mechanisms for reading data directly into the native storage =
used in MOAB, and for writing large collections of entities directly from t=
hat storage, to avoid data copies.  MOAB applications structured to take ad=
vantage of that locality will typically operate more efficiently.
+
+MOAB has been designed to maximize the flexibility of mesh data which can =
be represented.  There is no explicit constraint on the geometric structure=
 of meshes represented in MOAB, or on the connectivity between elements.  I=
n particular, MOAB allows the representation of multiple entities with the =
same exact connectivity; however, in these cases, explicit adjacencies must=
 be used to distinguish adjacencies with AEntities bounding such entities.
+
+The number of vertices used to represent a given topological entity can va=
ry, depending on analysis needs; this is often the case in FEA.  For exampl=
e, applications often use =E2=80=9Cquadratic=E2=80=9D or 10-vertex tetrahed=
ral, with vertices at edge midpoints as well as corners.  MOAB does not dis=
tinguish these variants by entity type, referring to all variants as =E2=80=
=9Ctetrahedra=E2=80=9D.  The number of vertices for a given entity is used =
to distinguish the variants, with canonical numbering conventions used to d=
etermine placement of the vertices [9].  This is similar to how such variat=
ions are represented in the Exodus [10] and Patran [11] file formats.  In p=
ractice, we find that this simplifies coding in applications, since in many=
 cases the handling of entities depends only on the number of corner vertic=
es in the element.  Some MOAB API functions provide a flag which determines=
 whether corner or all vertices are requested.
+
+The MOAB API is designed to balance complexity and ease of use.  This bala=
nce is evident in the following general design characteristics:
+
+- Entity lists: Lists of entities are passed to and from MOAB in a variety=
 of forms.  Lists output from MOAB are passed as either STL vector or Range=
 data types.  Either of these constructs may be more efficient in both time=
 and memory, depending on the semantics of the data being requested.  Input=
 lists are passed as either Range=E2=80=99s, or as a pointer to EntityHandl=
e and a size.  The latter allows the same function to be used when passing =
individual entities, without requiring construction of an otherwise unneede=
d STL vector.
+- Entity sets: Most query functions accept an entity set as input.  Applic=
ations can pass zero to indicate a request for the whole interface.  Note t=
hat this convention applies only to query functions; attempts to add or sub=
tract entities to/from the interface using set-based modification functions=
, or to add parents or children to the interface set, will fail.  Allowing =
specification of the interface set in this manner avoids the need for a sep=
arate set of API functions to query the database as a whole.
+- Implicit Booleans in output lists: A number of query functions in MOAB a=
llow specification of a Boolean operation (Interface::INTERSECT or Interfac=
e::UNION).  This operation is applied to the results of the query, often el=
iminating the need for code the application would need to otherwise impleme=
nt.  For example, to find the set of vertices shared by a collection of qua=
drilaterals, the application would pass that list of quadrilaterals to a re=
quest for vertex adjacencies, with Interface::INTERSECT passed for the Bool=
ean flag.  The list of vertices returned would be the same as if the applic=
ation called that function for each individual entity, and computed the int=
ersection of the results over all the quadrilaterals.  Applications may als=
o input non-empty lists to store the results, in which case the intersectio=
n is also performed with entities already in the list.  In many cases, this=
 allows optimizations in both time and memory inside the MOAB implementatio=
n.=20
+.
+
+Since these objectives are at odds with each other, tradeoffs had to be ma=
de between them.  Some specific issues that came up are:
+
+- Using ranges: Where possible, entities can be referenced using either ra=
nges (which allow efficient storage of long lists) or STL vectors (which al=
low list order to be preserved), in both input and output arguments.
+- Entities in sets: Accessing the entities in a set is done using the same=
 functions which access entities in the entire mesh.  The whole mesh is ref=
erenced by specifying a set handle of zero<sup>3</sup>.
+- Entity vectors on input: Functions which could normally take a single en=
tity as input are specified to take a vector of handles instead.  Single en=
tities are specified by taking the address of that entity handle and specif=
ying a list length of one.  This minimizes the number of functions, while p=
reserving the ability to input single entities.<sup>4</sup>
+.
+
+Table 2 lists basic data types and enumerated variables defined and used b=
y MOAB.  Values of the ErrorCode enumeration are returned from most MOAB fu=
nctions, and can be compared to those listed in Appendix [ref-appendix].
+
+MOAB uses several pre-defined tag names to define data commonly found in v=
arious mesh-based analyses.  Ref. [4] describes these meta-data conventions=
 in more detail.  These conventions will be added to as new conventions eme=
rge for using sets and tags in MOAB applications.
+
+  \subsection tabletwo Table 2: Basic data types and enums defined in MOAB.
+
+<table border=3D"1">
+<tr>
+<th>Enum / Type</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>ErrorCode</td>
+<td>Specific error codes returned from MOAB</td>
+</tr>
+<tr>
+<td>EntityHandle</td>
+<td>Type used to represent entity handles</td>
+</tr>
+<tr>
+<td>Tag</td>
+<td>Type used to represent tag handles</td>
+</tr>
+<tr>
+<td>TagType</td>
+<td>Type used to represent tag storage type</td>
+</tr>
+<tr>
+<td>DataType</td>
+<td>Type used to represent tag data type</td>
+</tr>
+</table>
+
+Table 3 lists the various groups of functions that comprise the MOAB API. =
 This is listed here strictly as a reference to the various types of functi=
onality supported by MOAB; for a more detailed description of the scope and=
 syntax of the MOAB API, see the online documentation [8].
+
+  \subsection tablethree Table 3: Groups of functions in MOAB API.  See Re=
f. [8] for more details.
+
+<table border=3D"1">
+<tr>
+<th>Function group</th>
+<th>Examples</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>Constructor, destructor, interface</td>
+<td>Interface, ~Core, query_interface</td>
+<td>Construct/destroy interface; get pointer to read/write interface</td>
+</tr>
+<tr>
+<td>Entity query</td>
+<td>get_entities_by_dimension, get_entities_by_handle</td>
+<td>Get entities by dimension, type, etc.</td>
+</tr>
+<tr>
+<td>Adjacencies</td>
+<td>get_adjacencies, set_adjacencies, add_adjacencies</td>
+<td>Get topologically adjacent entities; set or add explicit adjacencies</=
td>
+</tr>
+<tr>
+<td>Vertex coordinates</td>
+<td>get_coords, set_coords</td>
+<td>Get/set vertex coordinates</td>
+</tr>
+<tr>
+<td>Connectivity</td>
+<td>get_connectivity, set_connectivity</td>
+<td>Get/set connectivity of non-vertex entities</td>
+</tr>
+<tr>
+<td>Sets</td>
+<td>create_meshset, add_entities, add_parent_child</td>
+<td>Create and work with entity sets</td>
+</tr>
+<tr>
+<td>Tags</td>
+<td>tag_get_data, tag_create</td>
+<td>Create, read, write tag data</td>
+</tr>
+<tr>
+<td>Handles</td>
+<td>type_from_handle, id_from_handle</td>
+<td>Go between handles and types/ids</td>
+</tr>
+<tr>
+<td>File handling</td>
+<td>load_mesh, save_mesh</td>
+<td>Read/write mesh files</td>
+</tr>
+<tr>
+<td>Geometric dimension</td>
+<td>get_dimension, set_dimension</td>
+<td>Get/set geometric dimension of mesh</td>
+</tr>
+<tr>
+<td>Mesh modification</td>
+<td>create_vertex, delete_entity</td>
+<td>Create or delete mesh entities</td>
+</tr>
+<tr>
+<td>Information</td>
+<td>list_entities, get_last_error</td>
+<td>Get or print certain information</td>
+</tr>
+<tr>
+<td>High-order nodes</td>
+<td>high_order_node</td>
+<td>Get information on high-order nodes</td>
+</tr>
+<tr>
+<td>Canonical numbering</td>
+<td>side_number</td>
+<td>Get canonical numbering information</td>
+</tr>
+</table>
+
+<sup>3</sup>In iMesh, the whole mesh is specified by a special entity set =
handle, referred to as the =E2=80=9Croot set=E2=80=9D.
+
+<sup>4</sup>Note that STL vectors of entity handles can be input in this m=
anner by using &vector[0] and vector.size() for the 1d vector address and s=
ize, respectively.
+
+ \ref contents
+
+ \section services 4. Related Mesh Services
+
+A number of mesh-based services are often used in conjunction with a mesh =
library.  For example, parallel applications often need to visualize the me=
sh and associated data.  Other services, like spatial interpolation or find=
ing the faces on the =E2=80=9Cskin=E2=80=9D of a 3D mesh, can be implemente=
d more efficiently using knowledge of specific data structures in MOAB.  Se=
veral of these services provided with MOAB are described in this chapter.
+
+ \ref contents
+
+  \subsection fourone 4.1. Visualization
+
+Visualization is one of the most common needs associated with meshes.  The=
 primary tool used to visualize MOAB meshes is VisIt [12].  Users can speci=
fy that VisIt read mesh directly out of the MOAB instance, by specifying th=
e ITAPS-MOABC mesh format and a file readable by MOAB (see xxx).
+
+There are some initial capabilities in VisIt for limited viewing and manip=
ulation of tag data and some types of entity sets.  Tag data is visualized =
using the same mechanisms used to view other field data in VisIt, e.g. usin=
g a pseudocolor plot; sets are viewed using VisIt=E2=80=99s SIL window, acc=
essed by selecting the SIL icon in the data selection window.  xxx shows a =
vertex-based radiation temperature field computed by the Cooper rad-hydro c=
ode [1] for a subset of geometric volumes in a mesh.  =20
+
+Reorganization of VisIt=E2=80=99s set handling is also underway, to increa=
se versatility and flexibility of this important mechanism.
+
+ \ref contents
+
+  \subsection fourtwo 4.2. Parallel Decomposition
+
+To support parallel simulation, applications often need to partition a mes=
h into parts, designed to balance the load and minimize communication betwe=
en sets.  MOAB includes the MBZoltan tool for this purpose, constructed on =
the well-known Zoltan partitioning library [13].  After computing the parti=
tion using Zoltan, MBZoltan stores the partition as either tags on individu=
al entities in the partition, or as tagged sets, one set per part.  Since a=
 partition often exhibits locality similar to how the entities were created=
, storing it as sets (based on Range=E2=80=99s) is often more memory-effici=
ent than an entity tag-based representation.  Xxx shows a partition compute=
d with MBZoltan (and visualized in VisIt).=20
+
+ \ref contents
+
+  \subsection fourthree 4.3. Skinner
+
+An operation commonly applied to mesh is to compute the outermost =E2=80=
=9Cskin=E2=80=9D bounding a contiguous block of elements.  This skin consis=
ts of elements of one fewer topological dimension, arranged in one or more =
topological balls on the boundary of the elements.  The Skinner tool comput=
es the skin of a mesh in a memory-efficient manner.  Skinner uses knowledge=
 about whether vertex-entity adjacencies and AEntities exist to minimize me=
mory requirements and searching time required during the skinning process. =
 This skin can be provided as a single collection of entities, or as sets o=
f entities distinguished by forward and reverse orientation with respect to=
 higher-dimensional entities in the set being skinned.
+
+The following code fragment shows how Skinner can be used to compute the s=
kin of a range of hex elements:
+
+ \code
+using namespace moab;
+Range hexes, faces;
+ErrorCode rval =3D moab->get_entities_by_dimension(0, 3, hexes);
+Skinner myskinner(moab);
+bool verts_too =3D false;
+ErrorCode rval =3D myskinner.find_skin(hexes, verts_too, faces);
+\endcode
+
+Skinner can also skin a mesh based on geometric topology groupings importe=
d with the mesh.  The geometric topology groupings contain information abou=
t the mesh =E2=80=9Cowned=E2=80=9D by each of the entities in the geometric=
 model, e.g. the model vertices, edges, etc.  Links between the mesh sets c=
orresponding to those entities can be inferred directly from the mesh.  Ski=
nning a mesh this way will typically be much faster than doing so on the ac=
tual mesh elements, because there is no need to create and destroy interior=
 faces on the mesh.
+
+ \ref contents
+
+  \subsection fourfour 4.4. Tree Decompositions
+
+MOAB provides several mechanisms for spatial decomposition and searching i=
n a mesh:
+
+- AdaptiveKDTree: Adaptive KD tree, a space-filling decomposition with axi=
s-aligned splitting planes, enabling fast searching.
+- BSPTree: Binary Space Partition tree, with non-axis-aligned partitions, =
for fast spatial searches with slightly better memory efficiency than KD tr=
ees.
+- OrientedBoxTreeTool: Oriented Bounding Box tree hierarchy, useful for fa=
st ray-tracing on collections of mesh facets.
+.
+
+These trees have various space and time searching efficiencies.  All are i=
mplemented based on entity sets and parent/child relations between those se=
ts, allowing storage of a tree decomposition using MOAB=E2=80=99s native fi=
le storage mechanism (see Section 4.6.1).  MOAB=E2=80=99s entity set implem=
entation is specialized for memory efficiency when representing binary tree=
s.  Tree decompositions in MOAB have been used to implement fast ray tracin=
g to support radiation transport [14], solution coupling between meshes [2]=
, and embedded boundary mesh generation [15].  MOAB also includes the DAGMC=
 tool, supporting Monte Carlo radiation transport.
+
+The following code fragment shows very basic use of AdaptiveKDTree.  A ran=
ge of entities is put in the tree; the leaf containing a given point is fou=
nd, and the entities in that leaf are returned.
+\code
+using namespace moab;
+// create the adaptive kd tree from a range of tets
+EntityHandle tree_root
+AdaptiveKDTree myTree(moab);
+ErrorCode rval =3D myTree.build_tree(tets, tree_root);
+
+// get the overall bounding box corners
+double boxmax[3], boxmin;
+rval =3D myTree.get_tree_box(tree_root, boxmax, boxmin);
+
+// get the tree leaf containing point xyz, and the tets in that leaf
+AdaptiveKDTreeIter treeiter;
+rval =3D myTree.leaf_containing_point(tree_root, xyz, treeiter);
+Range leaf_tets;
+rval =3D moab->get_entities_by_dimension(treeiter.handle(), 3,=20
+                                       leaf_tets, false);
+\endcode
+
+More detailed examples of using the various tree decompositions in MOAB ca=
n be found in [ref-treeexamples].
+
+ \ref contents
+
+  \subsection fourfive 4.5. File Reader/Writer Interfaces
+
+Mesh readers and writers communicate mesh into/out of MOAB from/to disk fi=
les.  Reading a mesh often involves importing large sets of data, for examp=
le coordinates of all the nodes in the mesh.  Normally, this process would =
involve reading data from the file into a temporary data buffer, then copyi=
ng data from there into its destination in MOAB.  To avoid the expense of c=
opying data, MOAB has implemented a reader/writer interface that provides d=
irect access to blocks of memory used to represent mesh.
+
+The reader interface, declared in ReadUtilIface, is used to request blocks=
 of memory for storing coordinate positions and element connectivity.  The =
pointers returned from these functions point to the actual memory used to r=
epresent those data in MOAB.  Once data is written to that memory, no furth=
er copying is done.  This not only saves time, but it also eliminates the n=
eed to allocate a large memory buffer for intermediate storage of these dat=
a.=20
+
+MOAB allocates memory for nodes and elements (and their corresponding dens=
e tags) in chunks, to avoid frequent allocation/de-allocation of small chun=
ks of memory.  The chunk size used depends on from where the mesh is being =
created, and can strongly affect the performance (and memory layout) of MOA=
B.  Since dense tags are allocated at the chunk size, this can also affect =
overall memory usage in cases where the mesh size is small but the number o=
f dense tags or dense tag size is large.  When creating vertices and elemen=
ts through the normal MOAB API, default chunk sizes defined in the Sequence=
Manager class are used.  However, most of the file readers in MOAB allocate=
 the exact amount of space necessary to represent the mesh being read.  The=
re are also a few exceptions to this:
+
+- When compiled in parallel, this space is increased by a factor of 1.5, t=
o allow subsequent creation of ghost vertices/elements in the same chunk as=
 the original mesh.
+- The .cub file reader, which creates nodes and elements for individual ge=
ometric entities in separate calls, allocates using the default vertex/elem=
ent sequence sizes, which are defined in the SequenceManager class in MOAB.
+.
+
+Applications calling the reader interface functions directly can specify t=
he allocation chunk size as an optional parameter.
+
+The reader interface consists of the following functions:
+
+- get_node_arrays: Given the number of vertices requested, the number of g=
eometric dimensions, and a requested start id, allocates a block of vertex =
handles and returns pointers to coordinate arrays in memory, along with the=
 actual start handle for that block of vertices.
+- get_element_array: Given the number of elements requested, the number of=
 vertices per element, the element type and the requested start id, allocat=
es the block of elements, and returns a pointer to the connectivity array f=
or those elements and the actual start handle for that block.  The number o=
f vertices per element is necessary because those elements may include high=
er-order nodes, and MOAB stores these as part of the normal connectivity ar=
ray.
+- update_adjacencies: This function takes the start handle for a block of =
elements and the connectivity of those elements, and updates adjacencies fo=
r those elements.  Which adjacencies are updated depends on the options set=
 in AEntityFactory.
+.
+
+The following code fragment illustrates the use of ReadUtilIface to read a=
 mesh directly into MOAB=E2=80=99s native representation.  This code assume=
s that connectivity is specified in terms of vertex indices, with vertex in=
dices starting from 1.
+
+\code
+// get the read iface from moab
+ReadUtilIface *iface;
+ErrorCode rval =3D moab->get_interface("ReadUtilIface", &iface);
+
+// allocate a block of vertex handles and read xyz=E2=80=99s into them
+std::vector<double*> arrays;
+EntityHandle startv, *starth;
+rval =3D iface->get_node_arrays(3, num_nodes, 0, startv, arrays);
+for (int i =3D 0; i < num_nodes; i++)
+  infile >> arrays[0][i] >> arrays[1][i] >> arrays[2][i];
+
+// allocate block of hex handles and read connectivity into them
+rval =3D iface->get_element_array(num_hexes, 8, MBHEX, 0, starth);
+for (int i =3D 0; i < 8*num_hexes; i++)
+  infile >> starth[i];
+
+// change connectivity indices to vertex handles
+for (int i =3D 0; i < 8*num_hexes; i++)
+  starth[i] +=3D startv-1;
+\endcode
+
+The writer interface, declared in WriteUtilIface, provides functions that =
support writing vertex coordinates and element connectivity to storage loca=
tions input by the application.  Assembling these data is a common task for=
 writing mesh, and can be non-trivial when exporting only subsets of a mesh=
.  The writer interface declares the following functions:
+
+- get_node_arrays: Given already-allocated memory and the number of vertic=
es and dimensions, and a range of vertices, this function writes vertex coo=
rdinates to that memory.  If a tag is input, that tag is also written with =
integer vertex ids, starting with 1, corresponding to the order the vertice=
s appear in that sequence (these ids are used to write the connectivity arr=
ay in the form of vertex indices).
+- get_element_array: Given a range of elements and the tag holding vertex =
ids, and a pointer to memory, the connectivity of the specified elements ar=
e written to that memory, in terms of the indices referenced by the specifi=
ed tag.  Again, the number of vertices per element is input, to allow the d=
irect output of higher-order vertices.
+- gather_nodes_from_elements: Given a range of elements, this function ret=
urns the range of vertices used by those elements.  If a bit-type tag is in=
put, vertices returned are also marked with 0x1 using that tag.  If no tag =
is input, the implementation of this function uses its own bit tag for mark=
ing, to avoid using an n2 algorithm for gathering vertices.
+- reorder: Given a permutation vector, this function reorders the connecti=
vity for entities with specified type and number of vertices per entity to =
match that permutation.  This function is needed for writing connectivity i=
nto numbering systems other than that used internally in MOAB.
+.
+
+The following code fragment shows how to use WriteUtilIface to write the v=
ertex coordinates and connectivity indices for a subset of entities.
+
+\code
+using namespace moab;
+// get the write iface from moab
+WriteUtilIface *iface;
+ErrorCode rval =3D moab->get_interface("WriteUtilIface", &iface);
+
+// get all hexes the model, and choose the first 10 of those
+Range tmp_hexes, hexes, verts;
+rval =3D moab->get_entities_by_type(0, MBHEX, tmp_hexes);
+for (int i =3D 0; i < 10; i++) hexes.insert(tmp_hexes[i]);
+rval =3D iface->gather_nodes_from_elements(hexes, 0, verts);
+
+// assign vertex ids
+iface->assign_ids(verts, 0, 1);
+
+// allocate space for coordinates & write them
+std::vector<double*> arrays(3);
+for (int i =3D 0; i < 3; i++) arrays[i] =3D new double[verts.size()];
+iface->get_node_arrays(3, verts.size(), verts, 0, 1, arrays);
+
+// put connect=E2=80=99y in array, in the form of indices into vertex array
+std::vector<int> conn(8*hexes.size());
+iface->get_element_array(hexes.size(), 8, 0, hexes, 0, 1, &conn[0]);
+\endcode
+
+ \ref contents
+
+  \subsection foursix 4.6. File Readers/Writers Packaged With MOAB
+
+MOAB has been designed to efficiently represent data and metadata commonly=
 found in finite element mesh files.  Readers and writers are included with=
 MOAB which import/export specific types of metadata in terms of MOAB sets =
and tags, as described earlier in this document.  The number of readers and=
 writers in MOAB will probably grow over time, and so they are not enumerat=
ed here.  See the src/io/README file in the MOAB source distribution for a =
current list of supported formats.
+
+Because of its generic support for readers and writers, described in the p=
revious section, MOAB is also a good environment for constructing new mesh =
readers and writers.  The ReadTemplate and WriteTemplate classes in src/io =
are useful starting points for constructing new file readers/writers; appli=
cations are encouraged to submit their own readers/writers for inclusion in=
 MOAB=E2=80=99s contrib/io directory in the MOAB source.=20
+
+The usefulness of a file reader/writer is determined not only by its abili=
ty to read and write nodes and elements, but also in its ability to store t=
he various types of meta-data included with the typical mesh.  MOAB readers=
 and writers are distinguished by their ability to preserve meta-data in me=
shes that they read and write.  For example, MOAB=E2=80=99s CUB reader impo=
rts not only the mesh saved from CUBIT, but also the grouping of mesh entit=
ies into sets which reflect the geometric topology of the model used to gen=
erate the mesh.  See [4] for a more detailed description of meta-data conve=
ntions used in MOAB=E2=80=99s file readers and writers, and the individual =
file reader/writer header files in src/io for details about the specific re=
aders and writers.
+
+Three specific file readers in MOAB bear further discussion: MOAB=E2=80=99=
s native HDF5-based file reader/writer; the CUB reader, used to import mesh=
 and meta-data represented in CUBIT; and the CGM reader, which imports geom=
etric models.  These are described next.
+
+ \ref contents
+
+  \subsection native 4.6.1. Native HD5-Based Reader/Writer
+
+A mesh database must be able to save and restore the data stored in its da=
ta model, at least to the extent to which it understands the semantics of t=
hat data.  MOAB defines an HDF5-based file format that can store data embed=
ded in MOAB.  By convention, these files are given an =E2=80=9C.h5m=E2=80=
=9D file extension.  When reading or writing large amounts of data, it is r=
ecommended to use this file format, as it is the most complete and also the=
 most efficient of the file readers/writers in MOAB.=20
+
+  \subsection cub 4.6.2. CUB Reader
+
+CUBIT is a toolkit for generating tetrahedral and hexahedral finite elemen=
t meshes from solid model geometry [16].  This tool saves and restores data=
 in a custom =E2=80=9C.cub=E2=80=9D file, which stores both mesh and geomet=
ry (and data relating the two).  The CUB reader in MOAB can import and inte=
rpret much of the meta-data information saved in .cub files.  Ref. [4] desc=
ribes the conventions used to store this meta-data in the MOAB data model. =
 The information read from .cub files, and stored in the MOAB data model, i=
ncludes:
+
+- Geometric model entities and topology
+- Model entity names and ids
+- Groups, element blocks, nodesets, and sidesets, including model entities=
 stored in them
+- Mesh scheme and interval size information assigned to model entities
+.
+
+Note that although information about model entities is recovered, MOAB by =
default does not depend on a solid modeling engine; this information is sto=
red in the form of entity sets and parent/child relations between them.  Se=
e Ref. [4] for more information.
+
+ \ref contents
+
+  \subsection cgm 4.6.3. CGM Reader
+
+The Common Geometry Module (CGM) [17] is a library for representing solid =
model and other types of solid geometry data.  The CUBIT mesh generation to=
olkit uses CGM for its geometric modeling support, and CGM can restore geom=
etric models in the exact state in which they were represented in CUBIT.  M=
OAB contains a CGM reader, which can be enabled with a configure option.  U=
sing this reader, MOAB can read geometric models, and represent their model=
 topology using entity sets linked by parent/child relations.  The mesh in =
these models comes directly from the modeling engine faceting routines; the=
se are the same facets used to visualize solid models in other graphics eng=
ines.  When used in conjunction with the VisIt visualization tool (see Sect=
ion  ), this provides a solution for visualizing geometric models.  Xxx sho=
ws a model imported using MOAB=E2=80=99s CGM reader and visualized with Vis=
It.=20
+
+ \ref contents
+
+  \section parallel 5. Parallel Mesh Representation and Query
+
+A parallel mesh representation must strike a careful balance between provi=
ding an interface to mesh similar to that of a serial mesh, while also allo=
wing the discovery of parallel aspects of the mesh and performance of paral=
lel mesh-based operations efficiently.  MOAB supports a spatial domain-deco=
mposed view of a parallel mesh, where each subdomain is assigned to a proce=
ssor, lower-dimensional entities on interfaces between subdomains are share=
d between processors, and ghost entities can be exchanged with neighboring =
processors.  Locally, each subdomain, along with any locally-represented gh=
ost entities, are accessed through a local MOAB instance.  Parallel aspects=
 of the mesh, e.g. whether entities are shared, on an interface, or ghost e=
ntities, are embedded in the same data model (entities, sets, tags, interfa=
ce) used in the rest of MOAB.  MOAB provides a suite of parallel functions =
for initializing and communicating with a parallel mesh, along with functio=
ns to query the parallel aspects of the mesh.
+
+  \ref contents
+
+  \subsection fiveone 5.1. Nomenclature & Representation
+
+Before discussing how to access parallel aspects of a mesh, several terms =
need to be defined: =20
+
+<B>Shared entity:</B> An entity shared by one or several other processors.
+
+<B>Multi-shared entity:</B> An entity shared by more than two processors.
+
+<B>Owning Processor:</B> Each shared entity is owned by exactly one proces=
sor.  This processor has the right to set tag values on the entity and have=
 those values propagated to any sharing processors. =20
+
+<B>Part:</B> The collection of entities assigned to a given processor.  Wh=
en reading mesh in parallel, the entities in a Part, along with any lower-d=
imensional entities adjacent to those, will be read onto the assigned proce=
ssor.
+
+<B>Partition:</B> A collection of Parts which take part in parallel collec=
tive communication, usually associated with an MPI communicator.
+
+<B>Interface:</B> A collection of mesh entities bounding entities in multi=
ple parts.  Interface entities are owned by a single processor, but are rep=
resented on all parts/processors they bound.
+
+<B>Ghost entity:</B> A shared, non-interface, non-owned entity.
+
+<B>Parallel status:</B> A characteristic of entities and sets represented =
in parallel. The parallel status, or =E2=80=9Cpstatus=E2=80=9D, is represen=
ted by a bit field stored in an unsigned character, with bit values as desc=
ribed in Table 4.
+
+  \subsection tablefour Table 4: Bits representing various parallel charac=
teristics of a mesh.  Also listed are enumerated values that can be used in=
 bitmask expressions; these enumerated variables are declared in MBParallel=
Conventions.h.
+
+<table border=3D"1">
+<tr>
+<th>Bit</th>
+<th>Name</th>
+<th>Represents</th>
+</tr>
+<tr>
+<td>0x1</td>
+<td>PSTATUS_NOT_OWNED</td>
+<td>Not owned by the local processor</td>
+</tr>
+<tr>
+<td>0x2</td>
+<td>PSTATUS_SHARED</td>
+<td>Shared by exactly two processorstd>
+</tr>
+<tr>
+<td>0x4</td>
+<td>PSTATUS_MULTISHARED</td>
+<td>Shared by three or more processors</td>
+</tr>
+<tr>
+<td>0x8</td>
+<td>PSTATUS_INTERFACE</td>
+<td>Part of lower-dimensional interface shared by multiple processors</td>
+</tr>
+<tr>
+<td>0x10</td>
+<td>PSTATUS_GHOST</td>
+<td>Non-owned, non-interface entities represented locally</td>
+</tr>
+</table>
+
+Parallel functionality is described in the following sections.  First, met=
hods to load a mesh into a parallel representation are described; next, fun=
ctions for accessing parallel aspects of a mesh are described; functions fo=
r communicating mesh and tag data are described.
+
+  \ref contents
+
+  \subsection fivetwo 5.2. Parallel Mesh Initialization
+
+Parallel mesh is initialized in MOAB in several steps:
+
+-#  Establish a local mesh on each processor, either by reading the mesh i=
nto that representation from disk, or by creating mesh locally through the =
normal MOAB interface. =20
+-#  Find vertices, then other entities, shared between processors, based o=
n a globally-consistent vertex numbering stored on the GLOBAL_ID tag. =20
+-#  Exchange ghost or halo elements within a certain depth of processor in=
terfaces with neighboring processors. =20
+.
+
+These steps can be executed by a single call to MOAB=E2=80=99s load_file f=
unction, using the procedure described in Section 5.2.1.  Or, they can be e=
xecuted in smaller increments calling specific functions in MOAB=E2=80=99s =
ParallelComm class, as described in Section 5.2.2.  Closely related to the =
latter method is the handling of communicators, described in more detail in=
 Section.
+
+  \ref contents
+
+  \subsection initialization 5.2.1. Parallel Mesh Initialization by Loadin=
g a File
+
+In the file reading approach, a mesh must contain some definition of the p=
artition (the assignment of mesh, usually regions, to processors).  Partiti=
ons can be derived from other set structures already on the mesh, or can be=
 computed explicitly for that purpose by tools like mbzoltan (see Section 4=
.2).  For example, geometric volumes used to generate the mesh, and region-=
based material type assignments, are both acceptable partitions (see Ref. [=
4] for information about this and other meta-data often accompanying mesh).=
  In addition to defining the groupings of regions into parts, the assignme=
nt of specific parts to processors can be done implicitly or using addition=
al data stored with the partition.
+
+MOAB implements several specific methods for loading mesh into a parallel =
representation:
+
+- READ_PART: each processor reads only the mesh used by its part(s).
+
+- READ_DELETE: each processor reads the entire mesh, then deletes the mesh=
 not used by its part(s).
+
+- BCAST_DELETE: the root processor reads and broadcasts the mesh; each pro=
cessor then deletes the mesh not used by its part(s).
+
+The READ_DELETE and BCAST_DELETE methods are supported for all file types =
MOAB is able to read, while READ_PART is only implemented for MOAB=E2=80=99=
s native HDF5-based file format.
+
+Various other options control the selection of part sets or other details =
of the parallel read process.  For example, the application can specify the=
 tags, and optionally tag values, which identify parts, and whether those p=
arts should be distributed according to tag value or using round-robin assi=
gnment.
+
+The options used to specify loading method, the data used to identify part=
s, and other parameters controlling the parallel read process, are shown in=
 Table 5. =20
+  \subsection tablefive Table 5: Options passed to MOAB=E2=80=99s load_fil=
e function identifying the partition and other parameters controlling the p=
arallel read of mesh data.  Options and values should appear in option stri=
ng as =E2=80=9Coption=3Dval=E2=80=9D, with a delimiter (usually =E2=80=9C;=
=E2=80=9D) between options.
+
+<table border=3D"1">
+<tr>
+<th>Option</th>
+<th>Value</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>PARTITION</td>
+<td><tag_name></td>
+<td>Sets with the specified tag name should be used as part sets</td>
+</tr>
+<tr>
+<td>PARTITION_VAL</td>
+<td><val1, val2-val3, ...></td>
+<td>Integer values to be combined with tag name, with ranges input using v=
al1, val2-val3.  Not meaningful unless PARTITION option is also given.</td>
+</tr>
+<tr>
+<td>PARTITION_DISTRIBUTE</td>
+<td>(none)</td>
+<td>If present, or values are not input using PARTITION_VAL, sets with tag=
 indicated in PARTITION option are partitioned across processors in round-r=
obin fashion.</td>
+</tr>
+<tr>
+<td>PARALLEL_RESOLVE_SHARED_ENTS</td>
+<td><pd.sd></td>
+<td>Resolve entities shared between processors, where partition is made up=
 of pd- dimensional entities, and entities of dimension sd and lower should=
 be resolved.</td>
+</tr>
+<tr>
+<td>PARALLEL_GHOSTS</td>
+<td><gd.bd.nl[.ad]></td>
+<td>Exchange ghost elements at shared inter-processor interfaces.  Ghost e=
lements of dimension gd will be exchanged.  Ghost elements are chosen going=
 through bd-dimensional interface entities.  Number of layers of ghost elem=
ents is specified in nl.  If ad is present, lower-dimensional entities boun=
ding exchanged ghost entities will also be exchanged; allowed values for ad=
 are 1 (exchange bounding edges), 2 (faces), or 3 (edges and faces).</td>
+</tr>
+<tr>
+<td>CPUTIME</td>
+<td>(none)</td>
+<td>Print cpu time required for each step of parallel read & initializatio=
n.</td>
+</tr>
+<tr>
+<td>MPI_IO_RANK</td>
+<td><r></td>
+<td>If read method requires reading mesh onto a single processor, processo=
r with rank r is used to do that read.</td>
+</tr>
+</table>
+
+Several example option strings controlling parallel reading and initializa=
tion are:
+
+<B>=E2=80=9CPARALLEL=3DREAD_DELETE; PARTITION=3DMATERIAL_SET; PARTITION_VA=
L=3D100, 200, 600-700=E2=80=9D:</B> The whole mesh is read by every process=
or; this processor keeps mesh in sets assigned the tag whose name is =E2=80=
=9CMATERIAL_SET=E2=80=9D and whose value is any one of 100, 200, and 600-70=
0 inclusive.
+
+<B>=E2=80=9CPARALLEL=3DREAD_PART; PARTITION=3DPARALLEL_PARTITION, PARTITIO=
N_VAL=3D2=E2=80=9D:</B> Each processor reads only its mesh; this processor,=
 whose rank is 2, is responsible for elements in a set with the PARALLEL_PA=
RTITION tag whose value is 2.  This would by typical input for a mesh which=
 had already been partitioned with e.g. Zoltan or Parmetis.
+
+<B>=E2=80=9CPARALLEL=3DBCAST_DELETE; PARTITION=3DGEOM_DIMENSION, PARTITION=
_VAL=3D3, PARTITION_DISTRIBUTE=E2=80=9D:</B> The root processor reads the f=
ile and broadcasts the whole mesh to all processors.  If a list is construc=
ted with entity sets whose GEOM_DIMENSION tag is 3, i.e. sets corresponding=
 to geometric volumes in the original geometric model, this processor is re=
sponsible for all elements with index R+iP, i >=3D 0 (i.e. a round-robin di=
stribution).
+
+ \ref contents
+
+  \subsection functions 5.2.2. Parallel Mesh Initialization Using Functions
+
+After creating the local mesh on each processor, an application can call t=
he following functions in ParallelComm to establish information on shared m=
esh entities.  See the [ref-directparmesh example] in the MOAB source tree =
for a complete example of how this is done from an application.
+
+- ParallelComm::resolve_shared_entities (collective): Resolves shared enti=
ties between processors, based on GLOBAL_ID tag values of vertices.  Variou=
s forms are available, based on entities to be evaluated and maximum dimens=
ion for which entity sharing should be found.
+
+- ParallelComm::exchange_ghost_cells (collective): Exchange ghost entities=
 with processors sharing an interface with this processor, based on specifi=
ed ghost dimension (dimension of ghost entities exchanged), bridge dimensio=
n, number of layers, and type of adjacencies to ghost entities.  An entity =
is sent as a ghost if it is within that number of layers, across entities o=
f the bridge dimension, with entities owned by the receiving processor, or =
if it is a lower-dimensional entity adjacent to a ghost entity and that opt=
ion is requested.
+.
+
+ \ref contents
+
+  \subsection communicator 5.2.3. Communicator Handling
+
+The ParallelComm constructor takes arguments for an MPI communicator and a=
 MOAB instance.  The ParallelComm instance stores the MPI communicator, and=
 registers itself with the MOAB instance.  Applications can specify the Par=
allelComm index to be used for a given file operation, thereby specifying t=
he MPI communicator for that parallel operation.  For example:
+
+\code
+using namespace moab;
+// pass a communicator to the constructor, getting back the index
+MPI_Comm my_mpicomm;
+int pcomm_index;
+ParallelComm my_pcomm(moab, my_mpicomm, &pcomm_index);
+
+// write the pcomm index into a string option
+char load_opt[32];
+sprintf(load_opt, "PARALLEL=3DBCAST_DELETE;PARALLEL_COMM=3D%d",=20
+   pcomm_index);
+
+// specify that option in a parallel read operation
+ErrorCode rval =3D moab->load_file(load_opt, fname, ...)
+\endcode
+
+In the above code fragment, the ParallelComm instance with index pcomm_ind=
ex will be used in the parallel file read, so that the operation executes o=
ver the specified MPI communicator.  If no ParallelComm instance is specifi=
ed for a parallel file operation, a default instance will be defined, using=
 MPI_COMM_WORLD.
+
+Applications needing to retrieve a ParallelComm instance created previousl=
y and stored with the MOAB instance, e.g. by a different code component, ca=
n do so using a static function on ParallelComm:
+
+\code
+ParallelComm *my_pcomm =3D ParallelComm::get_pcomm(moab, pcomm_index);
+\endcode
+
+ParallelComm also provides the ParallelComm::get_all_pcomm function, for r=
etrieving all ParallelComm instances stored with a MOAB instance.  For synt=
ax and usage of this function, see the MOAB online documentation for Parall=
elComm.hpp [8].
+
+ \ref contents
+
+  \subsection fivethree 5.3. Parallel Mesh Query Functions
+
+Various functions are commonly used in parallel mesh-based applications.  =
Functions marked as being collective must be called collectively for all pr=
ocessors that are members of the communicator associated with the ParallelC=
omm instance used for the call.
+
+<B>ParallelComm::get_pstatus:</B>  Get the parallel status for the entity.
+
+<B>ParallelComm::get_pstatus_entities:</B> Get all entities whose pstatus =
satisfies (pstatus & val).
+
+<B>ParallelComm::get_owner:</B> Get the rank of the owning processor for t=
he specified entity.
+
+<B>ParallelComm::get_owner_handle:</B> Get the rank of the owning processo=
r for the specified entity, and the entity's handle on the owning processor.
+
+<B>ParallelComm::get_sharing_data:</B> Get the sharing processor(s) and ha=
ndle(s) for an entity or entities.  Various overloaded versions are availab=
le, some with an optional =E2=80=9Coperation=E2=80=9D argument, where Inter=
face::INTERSECT or Interface::UNION can be specified.  This is similar to t=
he operation arguments to Interface::get_adjacencies.
+
+<B>ParallelComm::get_shared_entities:</B> Get entities shared with the giv=
en processor, or with all processors.  This function has optional arguments=
 for specifying dimension, whether interface entities are requested, and wh=
ether to return just owned entities.
+
+<B>ParallelComm::get_interface_procs:</B> Return all processors with whom =
this processor shares an interface.
+
+<B>ParallelComm::get_comm_procs:</B> Return all processors with whom this =
processor communicates.
+
+  \ref contents
+
+  \subsection fivefour 5.4. Parallel Mesh Communication
+
+Once a parallel mesh has been initialized, applications can call the Paral=
lelComm::exchange_tags function for exchanging tag values between processor=
s.  This function causes the owning processor to send the specified tag val=
ues for all shared, owned entities to other processors sharing those entiti=
es.  Asynchronous communication is used to hide latency, and only point-to-=
point communication is used in these calls.
+
+  \ref contents
+
+  \section applications 6. Building MOAB-Based Applications
+
+There are two primary mechanisms supported by MOAB for building applicatio=
ns, one based on MOAB-defined make variables, and the other based on the us=
e of libtool and autoconf.  Both assume the use of a =E2=80=9Cmake=E2=80=9D=
-based build system. =20
+
+The easiest way to incorporate MOAB into an application=E2=80=99s build pr=
ocess is to include the =E2=80=9Cmoab.make=E2=80=9D file into the applicati=
on=E2=80=99s Makefile, adding the make variables MOAB_INCLUDES and MOAB_LIB=
S_LINK to application=E2=80=99s compile and link commands, respectively.  M=
OAB_INCLUDES contains compiler options specifying the location of MOAB incl=
ude files, and any preprocessor definitions required by MOAB.  MOAB_LIBS_LI=
NK contains both the options telling where libraries can be found, and the =
link options which incorporate those libraries into the application.  Any l=
ibraries depended on by the particular configuration of MOAB are included i=
n that definition, e.g. the HDF5 library.  Using this method to incorporate=
 MOAB is the most straightforward; for example, the following Makefile is u=
sed to build one of the example problems packaged with the MOAB source:
+\code
+include ${MOAB_LIB_DIR}/moab.make
+
+GetEntities : GetEntities.o
+	${CXX} $< ${MOAB_LIBS_LINK} -o $@
+
+.cpp.o :=20
+	${CXX} ${MOAB_INCLUDES} -c $<
+\endcode
+
+Here, the MOAB_LIB_DIR environment variable or make argument definition sp=
ecifies where the MOAB library is installed; this is also the location of t=
he moab.make file.  Once that file has been included, MOAB_INCLUDES and MOA=
B_LIBS_LINK can be used, as shown.
+
+Other make variables are defined in the moab.make file which simplify buil=
ding applications:
+
+- MOAB_LIBDIR, MOAB_INCLUDEDIR: the directories into which MOAB libraries =
and include files will be installed, respectively.  Note that some include =
files are put in a subdirectory named =E2=80=9Cmoab=E2=80=9D below that dir=
ectory, to reflect namespace naming conventions used in MOAB.
+
+- MOAB_CXXFLAGS, MOAB_CFLAGS, MOAB_LDFLAGS: Options passed to the C++ and =
C compilers and the linker, respectively.
+
+- MOAB_CXX, MOAB_CC, MOAB_FC: C++, C, and Fortran compilers specified to M=
OAB at configure time, respectively.
+.
+
+The second method for incorporating MOAB into an application=E2=80=99s bui=
ld system is to use autoconf and libtool.  MOAB is configured using these t=
ools, and generates the =E2=80=9C.la=E2=80=9D files that hold information o=
n library dependencies that can be used in application build systems also b=
ased on autoconf and libtool.  Further information on this subject is beyon=
d the scope of this User=E2=80=99s Guide; see the =E2=80=9C.la=E2=80=9D fil=
es as installed by MOAB, and contact the MOAB developer=E2=80=99s mailing l=
ist [6] for more details.
+
+  \ref contents
+
+  \section implementation  7. iMesh (ITAPS Mesh Interface) Implementation =
in MOAB
+
+iMesh is a common API to mesh data developed as part of the Interoperable =
Tools for Advanced Petascale Simulations (ITAPS) project [18].  Application=
s using the iMesh interface can operate on any implementation of that inter=
face, including MOAB.  MOAB-based applications can take advantage of other =
services implemented on top of iMesh, including the MESQUITE mesh improveme=
nt toolkit [19] and the GRUMMP mesh improvement library [20].
+
+MOAB=E2=80=99s native interface is accessed through the Interface abstract=
 C++ base class.  Wrappers are not provided in other languages; rather, app=
lications wanting to access MOAB from those languages should do so through =
iMesh.  In most cases, the data models and functionality available through =
MOAB and iMesh are identical.  However, there are a few differences, subtle=
 and not-so-subtle, between the two:
+
+<B>SPARSE tags used by default:</B> MOAB=E2=80=99s iMesh implementation cr=
eates SPARSE tags by default, because of semantic requirements of other tag=
-related functions in iMesh.  To create DENSE tags through iMesh, use the i=
Mesh_createTagWithOptions extension function (see below).
+
+<B>Higher-order elements:</B> ITAPS currently handles higher-order element=
s (e.g. a 10-node tetrahedron) usi[21]<sup>5</sup>.  As described in [sec-e=
ntities], MOAB supports higher-order entities by allowing various numbers o=
f vertices to define topological entities like quadrilateral or tetrahedron=
.  Applications can specify flags to the connectivity and adjacency functio=
ns specifying whether corner or all vertices are requested.
+
+<B>Self-adjacencies:</B> In MOAB=E2=80=99s native interface, entities are =
always self-adjacent<sup>6</sup>; that is, adjacencies of equal dimension r=
equested from an entity will always include that entity, while from iMesh w=
ill not include that entity.
+
+<B>Option strings:</B> The iMesh specification requires that options in th=
e options string passed to various functions (e.g. iMesh_load) be prepended=
 with the implementation name required to parse them, and delimited with sp=
aces.  Thus, a MOAB-targeted option would appear as =E2=80=9Cmoab:PARALLEL=
=3DREAD_PART moab:PARTITION=3DMATERIAL_SET=E2=80=9D.
+
+To provide complete MOAB support from other languages through iMesh, a col=
lection of iMesh extension functions are also available.  A general descrip=
tion of these extensions appears below; for a complete description, see the=
 online documentation for iMesh-extensions.h [8].
+
+- Recursive get_entities functions: There are many cases where sets includ=
e other sets (see [4] for more information).  MOAB provides iMesh_getEntiti=
esRec, and other recursive-supporting functions, to get all non-set entitie=
s of a given type or topology accessible from input set(s).  Similar functi=
ons are available for number of entities of a given type/topology.
+
+- Get entities by tag, and optionally tag value: It is common to search fo=
r entities with a given tag, and possibly tag value(s); functions like iMes=
h_getEntitiesByTag are provided for this purpose.
+
+- Options to createTag: To provide more control over the tag type, the iMe=
sh_createTagWithOptions is provided.  The storage type is controlled with t=
he =E2=80=9C
+
+- MBCNType: Canonical numbering evaluations are commonly needed by applica=
tions, e.g. to apply boundary conditions locally.  The MBCN package provide=
s these evaluations in terms of entity types defined in MOAB [9]; the getMB=
CNType is required to translate between iMesh_Topology and MBCN type.
+
+- Iterator step: Step an iterator a specified number of entities; allows a=
dvancement of an iterator without needing to allocate memory to hold the en=
tity handles stepped over.
+
+- Direct access to tag storage: The Interface::tag_iterate function allows=
 an application get a pointer to the memory used to store a given tag.  For=
 dense tags on contiguous ranges of entities, this provides more efficient =
access to tags.  The iMesh functionn iMesh_tagIterate provides access to th=
is functionlity.  See examples/TagIterateC.c and examples/TagIterateF.F for=
 examples of how to use this from C and Fortran, respectively.=20
+.
+
+As required by the iMesh specification, MOAB generates the =E2=80=9CiMesh-=
Defs.inc=E2=80=9D file and installs it with the iMesh and MOAB libraries.  =
This file defines make variables which can be used to build iMesh-based app=
lications.  The method used here is quite similar to that used for MOAB its=
elf (see Section 6).  In particular, the IMESH_INCLUDES and IMESH_LIBS make=
 variables can be used with application compile and link commands, respecti=
vely, with other make variables similar to those provided in moab.make also=
 available.
+
+Note that using the iMesh interface from Fortran-based applications requir=
es a compiler that supports Cray pointers, along with the pass-by-value (%V=
AL) extension.  Almost all compilers support those extensions; however, if =
using the gcc series of compilers, you must use gfortran 4.3 or later.
+
+<sup>5</sup>There are currently no implementations of this interface.
+
+<sup>6</sup>iMesh and MOAB both define adjacencies using the topological c=
oncept of closure.  Since the closure of an entity includes the entity itse=
lf, the d-dimensional entities on the closure of a given entity should incl=
ude the entity itself.
+
+ \ref contents
+
+  \section representation 8. Structured Mesh Representation
+
+A structured mesh is defined as a D-dimensional mesh whose interior vertic=
es have 2D connected edges.   Structured mesh can be stored without connect=
ivity, if certain information is kept about the parametric space of each st=
ructured block of mesh.  MOAB can represent structured mesh with implicit c=
onnectivity, saving approximately 57% of the storage cost compared to an un=
structured representation<sup>7</sup>.  Since connectivity must be computed=
 on the fly, these queries execute a bit slower than those for unstructured=
 mesh.  More information on the theory behind MOAB's structured mesh repres=
entation can be found in=20
+
+Currently, MOAB's structured mesh representation can only be used by creat=
ing structured mesh at runtime; that is, structured mesh is saved/restored =
in an unstructured format in MOAB's HDF5-based native save format.  For mor=
e details on how to use MOAB's structured mesh representation, see the scds=
eq_test.cpp source file in the test/ directory.
+
+<sup>7</sup> This assumes vertex coordinates are represented explicitly, a=
nd that there are approximately the same number of vertices and hexahedra i=
n a structured hex mesh.
+
+ \ref contents
+
+  \section element 9. Spectral Element Meshes
+
+The Spectral Element Method (SEM) is a high-order method, using a polynomi=
al Legendre interpolation basis with Gauss-Lobatto quadrature points, in co=
ntrast to the Lagrange basis used in (linear) finite elements [20].  SEM ob=
tains exponential convergence with decreasing mesh characteristic sizes, an=
d codes implementing this method typically have high floating-point intensi=
ty, making the method highly efficient on modern CPUs.  Most Nth-order SEM =
codes require tensor product cuboid (quad/hex) meshes, with each d-dimensio=
nal element containing (N+1)d degrees of freedom (DOFs).  There are various=
 methods for representing SEM meshes and solution fields on them; this docu=
ment discusses these methods and the tradeoffs between them.  The mesh part=
s of this discussion are given in terms of the iMesh mesh interface and its=
 implementation by the MOAB mesh library [21].
+
+The figure above shows a two-dimensional 3rd-order SEM mesh consisting of =
four quadrilaterals.  For this mesh, each quadrilateral has (N+1)^2=3D16 DO=
Fs, with corner and edge degrees of freedom shared between neighboring quad=
rilaterals.
+
+  \ref contents
+
+  \subsection nineone 9.1. Representations
+
+There are various representations of this mesh in a mesh database like MOA=
B, depending on how DOFs are related to mesh entities and tags on those ent=
ities.  We mention several possible representations:
+
+-# Corner vertices, element-based DOFs: Each quadrilateral is defined by f=
our vertices, ordered in CCW order typical of FE meshes.  DOFs are stored a=
s tags on quadrilaterals, with size (N+1)^2 values, ordered lexicographical=
ly (i.e. as a 2D array tag(i,j) with i varying faster than j.)  In the figu=
re above, the connectivity for face 1 would be (1, 4, 16, 13), and DOFs wou=
ld be ordered (1..16).  Note that in this representation, tag values for DO=
Fs shared by neighboring elements must be set multiple times, since there a=
re as many copies of these DOFs as elements sharing them.
+-# High-order FE-like elements: Each DOF is represented by a mesh vertex. =
Quadrilaterals each have (N+1)^2 vertices, ordered as they would be for hig=
h-order finite elements (corner vertices first, then mid-edge and mid-face =
elements; see [22]).  Mid -face, -edge, and -region vertices for a given ed=
ge/face/region would be ordered lexicographically, according to positive di=
rection in a corresponding reference element.  In the figure above, the con=
nectivity array for face 1 would be (1, 4, 16, 13, 2, 3, 8, 12, 14, 15, 5, =
9, 6, 7, 10, 11).  DOF values are stored as tags on vertices.  Since DOFs a=
re uniquely associated with vertices and vertices are shared by neighboring=
 elements, tag values only need to be set once.  Full vertex-quadrilateral =
adjacencies are available, for all vertices.
+-# Linear FE-like elements, one vertex per DOF, array with DOF vertices: E=
ach quadrilateral is defined by four (corner) vertices, with additional ver=
tices representing mid-edge and mid-face DOFs.  An additional =E2=80=9CDOF =
array=E2=80=9D tag is assigned to each quadrilateral, storing the array of =
vertices representing the (N+1)^2 DOFs for the quadrilateral, ordered lexic=
ographically.  For the figure above, the connectivity array for face 1 woul=
d be (1, 4, 16, 13), and the DOF array would be (1..16), assuming that vert=
ex handles are integers as shown in the figure.  DOF values are stored as t=
ags on vertices, and lexicographically-ordered arrays of DOFs can be retrie=
ved using the DOF array tag as input to the tag_get_data function in MOAB. =
 Adjacency functions would only be meaningful for corner vertices, but tag =
values would only need to be set once per DOF.
+-# High-order FE-like elements, array with DOF vertices: This is a combina=
tion of options 2 and 3.  The advantage would be full vertex-quad adjacency=
 support and direct availability of lexicographically-ordered vertex arrays=
, at the expense of more memory.
+-# Convert to linear mesh: Since a spectral element is a cuboid with highe=
r-order vertices, it can always be converted to N^2 linear cuboids using th=
e high-order vertices as corners of the finer quads/hexes.  This is how rea=
ders in ParaView and VisIt typically import spectral meshes (CAM-SE also ex=
ports connectivity in this form).
+
+As a convenience for applications, functions could also be provided for im=
portant tasks, like assembling the vertex handles for an entity in lexograp=
hic order (useful for option 2 above), and getting an array of tag values i=
n lexicographic order (for option 3 above).
+
+  \ref contents
+
+  \subsection ninetwo 9.2. Tradeoffs
+
+There are various competing tradeoffs in the various representation types.=
  These include:
+
+- Adjacencies: being able to retrieve the element(s) using a given (corner=
 or higher-order) vertex.
+- Connectivity list: being able to retrieve the connectivity of a given el=
ement, consisting of all (corner + higher-order) vertices in the element, u=
sually in lexicographical order.  This is closely linked with being able to=
 access the connectivity list as a const*, i.e. using the list straight fro=
m memory without needing to copy it.
+- Memory vs. time: There is a memory vs. execution time tradeoff between d=
uplicating interface vertex solution/tag variables in neighboring elements =
(more memory but more time-efficient and allows direct access to tag storag=
e by applications) versus using vertex-based tags (less memory but requires=
 assembly of variables into lexicographically-ordered arrays, and prevents =
direct access from applications).
+.
+
+The lower-memory option (storing variables on vertices and assembling into=
 lexicographically-ordered arrays for application use) usually ends up cost=
ing more in memory anyway, since applications must allocate their own stora=
ge for these arrays.  On the other hand, certain applications will always c=
hoose to do that, instead of sharing storage with MOAB for these variables.=
  In the case where applications do share memory with MOAB, other tools wou=
ld need to interpret the lexicographically-ordered field arrays specially, =
instead of simply treating the vertex tags as a point-based field.
+
+  \ref contents
+
+  \subsection ninethree 9.3. MOAB Representation
+In choosing the right MOAB representation for spectral meshes, we are tryi=
ng to balance a) minimal memory usage, b) access to properly-ordered and -a=
ligned tag storage, and c) maximal compatibility with tools likely to use M=
OAB.  The solution we propose is to use a representation most like option 2=
) above, with a few optional behaviors based on application requirements. =20
+
+In brief, we propose to represent elements using the linear, FE-ordered co=
nnectivity list (containing only corner vertices from the spectral element)=
, with field variables written to either vertices, lexicographically-ordere=
d arrays on elements, or both, and with a lexicographically-ordered array (=
stored on tag SPECTRAL_VERTICES) of all (corner+higher-order) vertices stor=
ed on elements.  In the either/or case, the choice will be evident from the=
 tag size and the entities on which the tag is set.  In the both case, the =
tag name will have a =E2=80=9C-LEX=E2=80=9D suffix for the element tags, an=
d the size of the element tag will be (N+1)^2 times that of the vertex-base=
d tag.  Finally, the file set containing the spectral elements (or the root=
 set, if no file set was input to the read) will contain a =E2=80=9CSPECTRA=
L_ORDER=E2=80=9D tag whose value is N.  These conventions are described in =
the =E2=80=9CMetadata Information=E2=80=9D document distributed with the MO=
AB source code.
+
+  \ref contents
+
+  \section performance 10. Performance and Using MOAB Efficiently from App=
lications
+
+MOAB is designed to operate efficiently on groups of entities and for larg=
e meshes.  Applications will be most efficient when they operate on entitie=
s in groups, especially groups which are close in their order of creation. =
 The MOAB API is structured to encourage operations on groups of entities. =
 Conversely, MOAB will not perform as well as other libraries if there are =
frequent deletion and creation of entities.  For those types of application=
s, a mesh library using a C++ object-based representation is more appropria=
te.  In this section, performance of MOAB when executing a variety of tasks=
 is described, and compared to that of other representations.  Of course, t=
hese metrics are based on the particular models and environments where they=
 are run, and may or may not be representative of other application types.
+
+One useful measure of MOAB performance is in the representation and query =
of a large mesh.  MOAB includes a performance test, located in the test/per=
f directory, in which a single rectangular region of hexahedral elements is=
 created then queried; the following steps are performed:
+
+- Create the vertices and hexes in the mesh
+- For each vertex, get the set of connected hexahedra
+- For each hex, get the connected vertices, their coordinates, average the=
m, and assign them as a tag on the hexes
+.
+
+This test can be run on your system to determine the runtime and memory pe=
rformance for these queries in MOAB.
+
+  \ref contents
+
+  \section conclusions 11. Conclusions and Future Plans
+
+MOAB, a Mesh-Oriented datABase, provides a simple but powerful data abstra=
ction to structured and unstructured mesh, and makes that abstraction avail=
able through a function API.  MOAB provides the mesh representation for the=
 VERDE mesh verification tool, which demonstrates some of the powerful mesh=
 metadata representation capabilities in MOAB.  MOAB includes modules that =
import mesh in the ExodusII, CUBIT .cub and Vtk file formats, as well as th=
e capability to write mesh to ExodusII, all without licensing restrictions =
normally found in ExodusII-based applications.  MOAB also has the capabilit=
y to represent and query structured mesh in a way that optimizes storage sp=
ace using the parametric space of a structured mesh; see Ref. [17] for deta=
ils.
+
+Initial results have demonstrated that the data abstraction provided by MO=
AB is powerful enough to represent many different kinds of mesh data found =
in real applications, including geometric topology groupings and relations,=
 boundary condition groupings, and inter-processor interface representation=
.  Our future plans are to further explore how these abstractions can be us=
ed in the design through analysis process.
+
+  \ref contents
+
+  \section references 12. References
+
+[1]	M. Fatenejad and G.A. Moses, =E2=80=9CCooper radiation hydrodynamics c=
ode..=E2=80=9D
+
+[2]	T.J. Tautges and A. Caceres, =E2=80=9CScalable parallel solution coupl=
ing for multiphysics reactor simulation,=E2=80=9D Journal of Physics: Confe=
rence Series,  vol. 180, 2009.
+
+[3]	T.J. Tautges, MOAB Meta-Data Information, 2010.
+
+[4]	T.J. Tautges, =E2=80=9CMOAB - ITAPS =E2=80=93 Trac.=E2=80=9D, http://t=
rac.mcs.anl.gov/projects/ITAPS/wiki/MOAB
+
+[5]	=E2=80=9CMOAB Developers Email List.=E2=80=9D, moab-dev at mcs.anl.gov.
+
+[6]	=E2=80=9CMOAB Users Email List.=E2=80=9D, moab at mcs.anl.gov.
+
+[7]	=E2=80=9CMOAB online documentation.=E2=80=9D, http://gnep.mcs.anl.gov:=
8010/moab-docs/
+
+[8]	T.J. Tautges, =E2=80=9CCanonical numbering systems for finite-element =
codes,=E2=80=9D Communications in Numerical Methods in Engineering,  vol. O=
nline, Mar. 2009.
+
+[9]	L.A. Schoof and V.R. Yarberry, EXODUS II: A Finite Element Data Model,=
  Albuquerque, NM: Sandia National Laboratories, 1994.
+
+[10]	M. PATRAN, =E2=80=9CPATRAN User=E2=80=99s Manual,=E2=80=9D 2005.
+
+[11]	VisIt User's Guide.
+
+[12]	K. Devine, E. Boman, R. Heaphy, B. Hendrickson, and C. Vaughan, =E2=
=80=9CZoltan Data Management Services for Parallel Dynamic Applications,=E2=
=80=9D Computing in Science and Engineering,  vol. 4, 2002, pp. 90=E2=80=93=
97.
+
+[13]	T.J. Tautges, P.P.H. Wilson, J. Kraftcheck, B.F. Smith, and D.L. Hend=
erson, =E2=80=9CAcceleration Techniques for Direct Use of  CAD-Based Geomet=
ries in Monte Carlo Radiation Transport,=E2=80=9D International Conference =
on Mathematics, Computational Methods & Reactor Physics (M&C 2009),  Sarato=
ga Springs, NY: American Nuclear Society, 2009.
+
+[14]	H. Kim and T. Tautges, =E2=80=9CEBMesh: An Embedded Boundary Meshing =
Tool,=E2=80=9D in preparation.
+
+[15]	G.D. Sjaardema, T.J. Tautges, T.J. Wilson, S.J. Owen, T.D. Blacker, W=
.J. Bohnhoff, T.L. Edwards, J.R. Hipp, R.R. Lober, and S.A. Mitchell, CUBIT=
 mesh generation environment Volume 1: Users manual, Sandia National Labora=
tories, May 1994, 1994.
+
+[16]	T.J. Tautges, =E2=80=9CCGM: A geometry interface for mesh generation,=
 analysis and other applications,=E2=80=9D Engineering with Computers,  vol=
. 17, 2001, pp. 299-314.
+
+[17]	T. J. Tautges, MOAB-SD: Integrated structured and unstructured mesh r=
epresentation, Engineering with Computers, vol. 20, no. 3, pp. 286-293, 200=
4.
+
+[18]	=E2=80=9CInteroperable Technologies for Advanced Petascale Simulation=
s (ITAPS),=E2=80=9D Interoperable Technologies for Advanced Petascale Simul=
ations (ITAPS).
+
+[19]	P. Knupp, =E2=80=9CMesh quality improvement for SciDAC applications,=
=E2=80=9D Journal of Physics: Conference Series,  vol. 46, 2006, pp. 458-46=
2.
+
+[20]	M. O. Deville, P. F. Fischer, and E. H. Mund, High-order methods for =
incompressible fluid flow. Cambridge, UK; New York: Cambridge University Pr=
ess, 2002.
+
+[21]	T. J. Tautges, =E2=80=9CMOAB Wiki.=E2=80=9D [Online]. Available: http=
://trac.mcs.anl.gov/projects/ITAPS/wiki/MOAB. [Accessed: 30-Oct-2012].
+
+[22]	T. J. Tautges, =E2=80=9CCanonical numbering systems for finite-elemen=
t codes,=E2=80=9D International Journal for Numerical Methods in Biomedical=
 Engineering, vol. 26, no. 12, pp. 1559=E2=80=931572, 2010.
+
+
+  \ref contents
+
+  \page differences Differences Between iMesh and MOAB
+
+  The data models used in MOAB and iMesh are quite similar, but not identi=
cal.The most significant differences are the following:
+
+- Tags: MOAB differentiates between DENSE, SPARSE, and BIT tags, using dif=
ferent storage models for each, while iMesh uses a single tag concept.  iMe=
sh allows application to query whether an entity has been given a tag of a =
specified type; this query is incompatible with the concept of a DENSE tag =
with a default value.  Thus, MOAB=E2=80=99s iMesh implementation creates SP=
ARSE tags by default, and tags created and accessed through this interface =
will use more memory than DENSE tags created through MOAB=E2=80=99s native =
interface.  To mitigate this problem, MOAB implements an extension of the i=
Mesh_createTag function which allows specification of the tag type (DENSE, =
SPARSE, etc.) to be created.  See later in this section for more informatio=
n.
+
+- Higher-order nodes: ITAPS currently handles higher-order elements (e.g. =
a 10-node tetrahedron) using a special =E2=80=9CShape=E2=80=9D interface.  =
In this interface, higher-order nodes are only accessible through the AEnti=
ties which they resolve.  MOAB=E2=80=99s iMesh implementation provides acce=
ss to higher-order nodes in the same manner described in Section  , by vary=
ing the number of vertices defining each entity.  As a result, if higher-or=
der entities are used in a model, the functions returning connectivity and =
vertex adjacencies always return all vertices, rather than providing an opt=
ion to return just corner vertices.
+
+- Self-adjacencies: iMesh specifies that entities are not self-adjacent; t=
hat is, requesting adjacencies of the same dimension/type results in an err=
or.  MOAB does not consider this an error, returning the entity itself.
+
+- Adjacency table and AEntities: iMesh uses the concept of an =E2=80=9Cadj=
acency table=E2=80=9D to determine which AEntities are available and create=
d by default.  MOAB uses input arguments to the get_adjacencies functions t=
o control whether AEntities are created.  These flags provide finer-grained=
 control over AEntities, but make it slightly less convenient to ensure tha=
t AEntities of a given dimension are always created.
+.
+
+ \page figures List of Figures
+=20
+  This page is intended to be empty.
+=20
+  \page tables List of Tables
+=20
+     \ref tableone
+
+     \ref tabletwo
+
+     \ref tablethree
+
+     \ref tablefour
+
+     \ref tablefive
+=20
+  \page building Building & Installing
+=20
+  MOAB uses an autoconf and libtool-based build process by default.  The p=
rocedure used to build MOAB from scratch depends on whether the source code=
 was obtained from a =E2=80=9Ctarball=E2=80=9D or directly from the Subvers=
ion repository.  Assuming the latter, the following steps should be execute=
d for building and installing MOAB:
+  - Locate and build any required dependencies.  MOAB can be built with no=
 dependencies on other libraries; this may be useful for applications only =
needing basic mesh representation and not needing to export mesh to formats=
 implemented in other libraries.  MOAB=E2=80=99s native save/restore capabi=
lity is built on HDF5-based files; applications needing to save and restore=
 files from MOAB reliably should use this library.  MOAB also uses ExodusII=
, a netCDF-based file format developed at Sandia National Laboratories [10]=
.  Applications needing to execute these tests should also build netCDF.  N=
ote that MOAB uses netCDF=E2=80=99s C++ interface, which is not enabled by =
default in netCDF but can be enabled using the =E2=80=9C=E2=80=93enable-cxx=
=E2=80=9D option to netCDF=E2=80=99s configure script.
+  - Unpack source code into <moab>, and change current working directory t=
o that location.
+  - Execute =E2=80=9Cautoreconf =E2=80=93fi=E2=80=9D.
+  - Run configure script, by executing =E2=80=9C./configure <options>=E2=
=80=9D.  Recommended options:
+       -# =E2=80=93prefix=3D<install_dir>: directory below which MOAB libr=
ary and include files will be installed; can either be the directory used f=
or MOAB source (<moab> from step 1), or a different directory.
+       -# =E2=80=93hdf5-dir=3D<hdf5_dir>: directory whose =E2=80=9Cinclude=
=E2=80=9D and =E2=80=9Clib=E2=80=9D subdirectories hold HDF5 include and li=
brary, respectively.  MOAB uses HDF5 for its native save/restore format (se=
e Section 4.6.1).
+       -# =E2=80=93netcdf-dir=3D: directory whose =E2=80=9Cinclude=E2=80=
=9D and =E2=80=9Clib=E2=80=9D subdirectories hold netCDF include and librar=
y, respectively.  MOAB uses netCDF-based files for many of its build tests.=
  If the location of netCDF cannot be found, MOAB=E2=80=99s build tests wil=
l not function properly, but MOAB will still be usable.
+       .
+  - Run =E2=80=9Cmake check=E2=80=9D; this runs a series of build tests, t=
o verify that the MOAB build was successful.  Note this check will fail if =
netCDF is not used, but MOAB itself will still be usable from applications.
+  - Run =E2=80=9Cmake install=E2=80=9D; this copies include files and libr=
aries to subdirectories of the directory specified in the =E2=80=9Cprefix=
=E2=80=9D option.
+  .
+
+These steps are sufficient for building MOAB against HDF5 and netCDF.  By =
default, a small number of standard MOAB-based applications are also built,=
 including mbconvert (a utility for reading and writing files), mbsize (for=
 querying basic information about a mesh), and the iMesh interface (see Sec=
tion 7).  Other utilities can be enabled using various other options to the=
 configure script; for a complete list of build options, execute =E2=80=9C.=
/configure =E2=80=93help=E2=80=9D.
+=20
+ */
+

diff --git a/doc/user.dox.in b/doc/user.dox.in
index 4fed19e..ed65208 100644
--- a/doc/user.dox.in
+++ b/doc/user.dox.in
@@ -305,7 +305,9 @@ WARN_LOGFILE           =3D
 # with spaces.
=20
 INPUT                  =3D @top_srcdir@/src @top_srcdir@/src/moab \
-                         @top_srcdir@/src/parallel/moab \
+                         @top_srcdir@/doc/UG/moabUG.h \
+                         @top_srcdir@/doc/DG \
+                         @top_srcdir@/src/parallel/moab  \
                          @top_srcdir@/src/MBTagConventions.hpp \
                          @top_srcdir@/src/MBCN.h \
                          @top_srcdir@/src/MBEntityType.h \

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dc89d66..38b4130 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,6 +38,7 @@
     ScdVertexData.cpp
     SequenceData.cpp
     SequenceManager.cpp
+    SetIterator.cpp
     Skinner.cpp
     SparseTag.cpp
     StructuredElementSeq.cpp
@@ -46,6 +47,7 @@
     SweptVertexData.cpp
     SysUtil.cpp
     TagInfo.cpp
+    Types.cpp
     TypeSequenceManager.cpp
     UnstructuredElemSeq.cpp
     Util.cpp
@@ -53,7 +55,6 @@
     VarLenSparseTag.cpp
     VertexSequence.cpp
     WriteUtil.cpp
-    moab_mpe.c
   )
   include_directories(
     ${MOAB_SOURCE_DIR}/src

diff --git a/src/ScdInterface.cpp b/src/ScdInterface.cpp
index e2b18bb..8084640 100644
--- a/src/ScdInterface.cpp
+++ b/src/ScdInterface.cpp
@@ -7,12 +7,12 @@
 #include "ScdVertexData.hpp"
 #ifdef USE_MPI
 #  include "moab/ParallelComm.hpp"
+#  include "moab/TupleList.hpp"
+#  include "moab/gs.hpp"
 #endif
 #include "assert.h"
 #include <iostream>
 #include <functional>
-#include "moab/TupleList.hpp"
-#include "moab/gs.hpp"
=20
 #define ERRORR(rval, str) {if (MB_SUCCESS !=3D rval)          \
       {std::cerr << str; return rval; }}

diff --git a/src/Skinner.cpp b/src/Skinner.cpp
index fb80e58..1d284b7 100644
--- a/src/Skinner.cpp
+++ b/src/Skinner.cpp
@@ -1510,6 +1510,34 @@ ErrorCode Skinner::create_side( EntityHandle elem,
   rval =3D thisMB->get_connectivity( elem, conn, len, false, &storage );
   if (MB_SUCCESS !=3D rval) return rval;
 =20
+  // treat separately MBPOLYGON; we want to create the edge in the
+  // forward sense always ; so figure out the sense first, then get out
+  if (MBPOLYGON=3D=3Dtype && 1=3D=3Dd && MBEDGE=3D=3Dside_type)
+  {
+    // first find the first vertex in the conn list
+    int i=3D0;
+    for (i=3D0; i<len; i++)
+    {
+      if (conn[i]=3D=3Dside_conn[0])
+        break;
+    }
+    if (len =3D=3D i)
+      return MB_FAILURE; // not found, big error
+    int prevIndex =3D (i+len-1)%len;
+    int nextIndex =3D (i+1)%len;
+    EntityHandle conn2[2] =3D {side_conn[0], side_conn[1]};
+    if (conn[prevIndex]=3D=3Dside_conn[1])
+    {
+      // reverse, so the edge will be forward
+      conn2[0]=3Dside_conn[1];
+      conn2[1]=3Dside_conn[0];
+    }
+    else if  ( conn[nextIndex]!=3Dside_conn[1])
+      return MB_FAILURE; // it is not adjacent to the polygon
+
+    return thisMB->create_element( MBEDGE, conn2, 2, side_elem );
+
+  }
   // Find which side we are creating and get indices of all nodes
   // (including higher-order, if any.)
   CN::SideNumber( type, conn, side_conn, ncorner, d, side, sense, offset );

diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
index f83eb4f..d6c3e44 100644
--- a/src/io/CMakeLists.txt
+++ b/src/io/CMakeLists.txt
@@ -12,7 +12,9 @@
     ReadSmf.cpp
     ReadSms.cpp
     ReadSTL.cpp
+    ReadTemplate.cpp
     ReadTetGen.cpp
+    ReadTxt.cpp
     ReadVtk.cpp
     SMF_State.cpp
     Tqdcfr.cpp

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index c225841..146227c 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -147,7 +147,7 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
 #ifdef USE_MPI
     for (int i =3D 0; i < 6; i++)
       parData.gDims[i] =3D gDims[i];
-    for (int i =3D 0; i < 3; i++)
+    for (int i =3D 0; i < 2; i++)
       parData.gPeriodic[i] =3D globallyPeriodic[i];
     parData.partMethod =3D partMethod;
     int pdims[3];

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index cdc4392..9141938 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -158,7 +158,7 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
 #ifdef USE_MPI
     for (int i =3D 0; i < 6; i++)
       parData.gDims[i] =3D gDims[i];
-    for (int i =3D 0; i < 3; i++)
+    for (int i =3D 0; i < 2; i++)
       parData.gPeriodic[i] =3D globallyPeriodic[i];
     parData.partMethod =3D partMethod;
     int pdims[3];

diff --git a/src/moab/Interface.hpp b/src/moab/Interface.hpp
index 030b9d1..d7ad8aa 100644
--- a/src/moab/Interface.hpp
+++ b/src/moab/Interface.hpp
@@ -22,8 +22,8 @@
  * together to describe geometric topology, boundary condition, and inter-=
processor interface=20
  * groupings in a mesh.
  *
- * MOAB's API is documented in the moab::Interface class.  The User's Guid=
e is located in
- * doc/MOABv4-UG.doc in MOAB's source tree.  Questions and comments should=
 be sent to moab-dev=20
+ * MOAB's API is documented in the moab::Interface class.  The User's Guid=
e and Developer's Guide are located in
+ * <a href=3D"pages.html">related pages</a>.  Questions and comments shoul=
d be sent to moab-dev=20
  * _at_ mcs.anl.gov.
  */
=20

diff --git a/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index de30f8b..bf5cbb8 100644
--- a/test/parallel/par_intx_sph.cpp
+++ b/test/parallel/par_intx_sph.cpp
@@ -42,9 +42,12 @@ using namespace moab;
 // some input data
 double EPS1=3D0.2; // this is for box error
 std::string input_mesh_file("Homme_2pt.h5m"); // input file, partitioned c=
orrectly
+std::string mpas_file("mpas_p8.h5m");
 double CubeSide =3D 6.; // the above file starts with cube side 6; radius =
depends on cube side
+double radius;
 void test_intx_in_parallel();
 void test_intx_in_parallel_elem_based();
+void test_intx_mpas();
=20
 int main(int argc, char **argv)
 {
@@ -73,7 +76,10 @@ int main(int argc, char **argv)
     }
   }
   //result +=3D RUN_TEST(test_intx_in_parallel);
+  radius =3D CubeSide/2*sqrt(3.);
   result +=3D RUN_TEST(test_intx_in_parallel_elem_based);
+  radius =3D1.;
+  result +=3D RUN_TEST(test_intx_mpas);
=20
   MPI_Finalize();
   return result;
@@ -92,9 +98,9 @@ ErrorCode  manufacture_lagrange_mesh_on_sphere(Interface =
* mb, EntityHandle eule
    *   circumscribed sphere radius
    *   radius =3D length * math.sqrt(3) /2
    */
-  double radius =3D CubeSide/2*sqrt(3.);// our value depends on cube side
+  //radius =3D CubeSide/2*sqrt(3.);// our value depends on cube side
   Range quads;
-  rval =3D mb->get_entities_by_type(euler_set, MBQUAD, quads);
+  rval =3D mb->get_entities_by_dimension(euler_set, 2, quads);
   CHECK_ERR(rval);
=20
   Range connecVerts;
@@ -177,10 +183,10 @@ void test_intx_in_parallel()
 =20
   Intx2MeshOnSphere worker(&mb);
=20
-  double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
-  worker.SetEntityType(MBQUAD);
+  //worker.SetEntityType(MBQUAD);
=20
   worker.SetErrorTolerance(radius*1.e-8);
   worker.locate_departure_points(euler_set);
@@ -244,10 +250,10 @@ void test_intx_in_parallel_elem_based()
=20
   Intx2MeshOnSphere worker(&mb);
=20
-  double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
-  worker.SetEntityType(MBQUAD);
+  //worker.SetEntityType(MBQUAD);
=20
   worker.SetErrorTolerance(radius*1.e-8);
   std::cout << "error tolerance epsilon_1=3D"<< radius*1.e-8 << "\n";
@@ -282,3 +288,79 @@ void test_intx_in_parallel_elem_based()
       "  intersection area:" << intx_area << " rel error: " << fabs((intx_=
area-arrival_area)/arrival_area) << "\n";
   CHECK_ERR(rval);
 }
+
+void test_intx_mpas()
+{
+  std::string opts =3D std::string("PARALLEL=3DREAD_PART;PARTITION=3DPARAL=
LEL_PARTITION")+
+          std::string(";PARALLEL_RESOLVE_SHARED_ENTS");
+  Core moab;
+  Interface & mb =3D moab;
+  EntityHandle euler_set;
+  ErrorCode rval;
+  rval =3D mb.create_meshset(MESHSET_SET, euler_set);
+  CHECK_ERR(rval);
+  std::string example(TestDir + "/" +  mpas_file);
+
+  rval =3D mb.load_file(example.c_str(), &euler_set, opts.c_str());
+
+  ParallelComm* pcomm =3D ParallelComm::get_pcomm(&mb, 0);
+  CHECK_ERR(rval);
+
+  rval =3D pcomm->check_all_shared_handles();
+  CHECK_ERR(rval);
+
+  // everybody will get a DP tag, including the non owned entities; so exc=
hange tags is not required for LOC (here)
+  rval =3D manufacture_lagrange_mesh_on_sphere(&mb, euler_set);
+  CHECK_ERR(rval);
+
+  int rank =3D pcomm->proc_config().proc_rank();
+
+  std::stringstream ste;
+  ste<<"initial" << rank<<".vtk";
+  mb.write_file(ste.str().c_str(), 0, 0, &euler_set, 1);
+
+  Intx2MeshOnSphere worker(&mb);
+
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  worker.SetRadius(radius);
+  worker.set_box_error(EPS1);//
+  //worker.SetEntityType(MBQUAD);
+
+  worker.SetErrorTolerance(radius*1.e-8);
+  std::cout << "error tolerance epsilon_1=3D"<< radius*1.e-8 << "\n";
+  //  worker.locate_departure_points(euler_set);
+
+  // we need to make sure the covering set is bigger than the euler mesh
+  EntityHandle covering_lagr_set;
+  rval =3D mb.create_meshset(MESHSET_SET, covering_lagr_set);
+  CHECK_ERR(rval);
+
+  rval =3D worker.create_departure_mesh_2nd_alg(euler_set, covering_lagr_s=
et);
+  CHECK_ERR(rval);
+
+  std::stringstream ss;
+  ss<<"partial" << rank<<".vtk";
+  mb.write_file(ss.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  rval =3D enforce_convexity(&mb, covering_lagr_set);
+  CHECK_ERR(rval);
+  std::stringstream ss2;
+  ss2<<"partialConvex" << rank<<".vtk";
+  mb.write_file(ss2.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  EntityHandle outputSet;
+  rval =3D mb.create_meshset(MESHSET_SET, outputSet);
+  CHECK_ERR(rval);
+  rval =3D worker.intersect_meshes(covering_lagr_set, euler_set, outputSet=
);
+  CHECK_ERR(rval);
+
+  //std::string opts_write("PARALLEL=3DWRITE_PART");
+  //rval =3D mb.write_file("manuf.h5m", 0, opts_write.c_str(), &outputSet,=
 1);
+  std::string opts_write("");
+  std::stringstream outf;
+  outf<<"intersect" << rank<<".h5m";
+  rval =3D mb.write_file(outf.str().c_str(), 0, 0, &outputSet, 1);
+  double intx_area =3D area_on_sphere(&mb, outputSet, radius);
+  double arrival_area =3D area_on_sphere(&mb, euler_set, radius) ;
+  std::cout<< "On rank : " << rank << " arrival area: " << arrival_area<<
+      "  intersection area:" << intx_area << " rel error: " << fabs((intx_=
area-arrival_area)/arrival_area) << "\n";
+  CHECK_ERR(rval);
+}

diff --git a/tools/mbcslam/CslamUtils.cpp b/tools/mbcslam/CslamUtils.cpp
index 61d1bf0..1166a7a 100644
--- a/tools/mbcslam/CslamUtils.cpp
+++ b/tools/mbcslam/CslamUtils.cpp
@@ -12,6 +12,11 @@
 #include "ElemUtil.hpp"
 #include "moab/MergeMesh.hpp"
=20
+// this is for sstream
+#include <sstream>
+
+#include <queue>
+
 namespace moab {
 // vec utilities that could be common between quads on a plane or sphere
 double dist2(double * a, double * b)
@@ -24,24 +29,26 @@ double area2D(double *a, double *b, double *c)
   // (b-a)x(c-a) / 2
   return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) /=
 2;
 }
-int borderPointsOfXinY2(double * X, double * Y, int nsides, double * P, in=
t side[4])
+int borderPointsOfXinY2(double * X, int nX, double * Y, int nY, double * P=
, int side[MAXEDGES])
 {
   // 2 triangles, 3 corners, is the corner of X in Y?
   // Y must have a positive area
   /*
    */
   int extraPoint =3D 0;
-  for (int i =3D 0; i < nsides; i++)
+  for (int i =3D 0; i < nX; i++)
   {
-    // compute twice the area of all 4 triangles formed by a side of Y and=
 a corner of X; if one is negative, stop
+    // compute twice the area of all nY triangles formed by a side of Y an=
d a corner of X; if one is negative, stop
+    // (negative means it is outside; X and Y are all oriented such that t=
hey are positive oriented;
+    //  if one area is negative, it means it is outside the convex region,=
 for sure)
     double * A =3D X + 2 * i;
=20
     int inside =3D 1;
-    for (int j =3D 0; j < nsides; j++)
+    for (int j =3D 0; j < nY; j++)
     {
       double * B =3D Y + 2 * j;
=20
-      int j1 =3D (j + 1) % nsides;
+      int j1 =3D (j + 1) % nY;
       double * C =3D Y + 2 * j1; // no copy of data
=20
       double area2 =3D (B[0] - A[0]) * (C[1] - A[1])
@@ -54,7 +61,8 @@ int borderPointsOfXinY2(double * X, double * Y, int nside=
s, double * P, int side
     }
     if (inside)
     {
-      side[i] =3D 1;
+      side[i] =3D 1;// so vertex i of X is inside the convex region formed=
 by Y
+      // so side has nX dimension (first array)
       P[extraPoint * 2] =3D A[0];
       P[extraPoint * 2 + 1] =3D A[1];
       extraPoint++;
@@ -84,7 +92,8 @@ int SortAndRemoveDoubles2(double * P, int & nP, double ep=
silon_1)
   }
   c[0] /=3D nP;
   c[1] /=3D nP;
-  double angle[24]; // could be at most 24 points; much less usually
+  // how many
+  std::vector<double> angle(nP); // could be at most nP points
   for (k =3D 0; k < nP; k++)
   {
     double x =3D P[2 * k] - c[0], y =3D P[2 * k + 1] - c[1];
@@ -108,7 +117,7 @@ int SortAndRemoveDoubles2(double * P, int & nP, double =
epsilon_1)
       if (angle[k] > angle[k + 1])
       {
         sorted =3D 0;
-        swap2(angle + k, angle + k + 1);
+        swap2(&angle[k], &angle[k+1]);
         swap2(P + (2 * k), P + (2 * k + 2));
         swap2(P + (2 * k + 1), P + (2 * k + 3));
       }
@@ -146,8 +155,8 @@ int SortAndRemoveDoubles2(double * P, int & nP, double =
epsilon_1)
=20
 // the marks will show what edges of blue intersect the red
=20
-int EdgeIntersections2(double * blue, double * red, int nsides, int markb[=
4], int markr[4],
-    double * points, int & nPoints)
+int EdgeIntersections2(double * blue, int nsBlue, double * red, int nsRed,
+    int markb[MAXEDGES], int markr[MAXEDGES], double * points, int & nPoin=
ts)
 {
   /* EDGEINTERSECTIONS computes edge intersections of two elements
    [P,n]=3DEdgeIntersections(X,Y) computes for the two given elements  * r=
ed
@@ -158,30 +167,20 @@ int EdgeIntersections2(double * blue, double * red, i=
nt nsides, int markb[4], in
    with blue are given.
    */
=20
-  // points is an array with 48 slots   (24 * 2 doubles)
+  // points is an array with enough slots   (24 * 2 doubles)
   nPoints =3D 0;
-  markb[0] =3D markb[1] =3D markb[2] =3D markb[3] =3D 0; // no neighbors o=
f red involved yet
-  markr[0] =3D markr[1] =3D markr[2] =3D markr[3] =3D 0;
-  /*for i=3D1:3                            % find all intersections of edg=
es
-   for j=3D1:3
-   b=3DY(:,j)-X(:,i);
-   A=3D[X(:,mod(i,3)+1)-X(:,i) -Y(:,mod(j,3)+1)+Y(:,j)];
-   if rank(A)=3D=3D2                   % edges not parallel
-   r=3DA\b;
-   if r(1)>=3D0 & r(1)<=3D1 & r(2)>=3D0 & r(2)<=3D1,  % intersection found
-   k=3Dk+1; P(:,k)=3DX(:,i)+r(1)*(X(:,mod(i,3)+1)-X(:,i)); n(i)=3D1;
-   end;
-   end;
-   end;
-   end;*/
-  for (int i =3D 0; i < nsides; i++)
-  {
-    for (int j =3D 0; j < nsides; j++)
+  for (int i=3D0; i<MAXEDGES; i++){
+    markb[i]=3Dmarkr[i] =3D 0;
+  }
+
+  for (int i =3D 0; i < nsBlue; i++)
+  {
+    for (int j =3D 0; j < nsRed; j++)
     {
       double b[2];
       double a[2][2]; // 2*2
-      int iPlus1 =3D (i + 1) % nsides;
-      int jPlus1 =3D (j + 1) % nsides;
+      int iPlus1 =3D (i + 1) % nsBlue;
+      int jPlus1 =3D (j + 1) % nsRed;
       for (int k =3D 0; k < 2; k++)
       {
         b[k] =3D red[2 * j + k] - blue[2 * i + k];
@@ -636,7 +635,7 @@ double oriented_spherical_angle(double * A, double * B,=
 double * C)
   CartVect a(A), b(B), c(C);
   CartVect normalOAB =3D a * b;
   CartVect normalOCB =3D c * b;
-  CartVect orient =3D (b-a)*(c-a);
+  CartVect orient =3D (c-b)*(a-b);
   double ang =3D angle(normalOAB, normalOCB); // this is between 0 and M_PI
   if (ang!=3Dang)
   {
@@ -644,8 +643,8 @@ double oriented_spherical_angle(double * A, double * B,=
 double * C)
     std::cout << a << " " << b << " " << c <<"\n";
     std::cout << ang << "\n";
   }
-  if (orient%a < 0)
-    return (2*M_PI-ang);// the other angle
+  if (orient%b < 0)
+    return (2*M_PI-ang);// the other angle, supplement
=20
   return ang;
=20
@@ -861,4 +860,136 @@ void departure_point_case1(CartVect & arrival_point, =
double t, double delta_t, C
   departure_point =3D spherical_to_cart(sph_dep);
   return;
 }
+// break the nonconvex quads into triangles; remove the quad from the set?=
 yes.
+// maybe radius is not needed;
+//
+ErrorCode enforce_convexity(Interface * mb, EntityHandle lset)
+{
+  // look at each quad; compute all 4 angles; if one is reflex, break alon=
g that diagonal
+  // replace it with 2 triangles, and remove from set;
+  // it should work for all polygons / tested first for case 1, with dt 0.=
5 (too much deformation)
+  // get all entities of dimension 2
+  // then get the connectivity, etc
+  Range inputRange;
+  ErrorCode rval =3D mb->get_entities_by_dimension(lset, 2, inputRange);
+  if (MB_SUCCESS !=3D rval)
+    return rval;
+
+  std::vector<double> coords;
+  coords.resize(3*MAXEDGES); // at most 10 vertices per polygon
+  // we should create a queue with new polygons that need processing for r=
eflex angles
+  //  (obtuse)
+  std::queue<EntityHandle> newPolys;
+  int brokenPolys=3D0;
+  Range::iterator eit =3D inputRange.begin();
+  while (eit !=3D inputRange.end() || !newPolys.empty())
+  {
+    EntityHandle eh;
+    if (eit !=3D inputRange.end())
+    {
+      eh =3D *eit;
+      eit++;
+    }
+    else
+    {
+      eh =3D newPolys.front();
+      newPolys.pop();
+    }
+    // get the nodes, then the coordinates
+    const EntityHandle * verts;
+    int num_nodes;
+    rval =3D mb->get_connectivity(eh, verts, num_nodes);
+    if (MB_SUCCESS !=3D rval)
+      return rval;
+    coords.resize(3 * num_nodes);
+    if (num_nodes < 4)
+      continue; // if already triangles, don't bother
+       // get coordinates
+    rval =3D mb->get_coords(verts, num_nodes, &coords[0]);
+    if (MB_SUCCESS !=3D rval)
+     return rval;
+    // compute each angle
+    bool alreadyBroken =3D false;
+
+    for (int i=3D0; i<num_nodes; i++)
+    {
+      double * A =3D &coords[3*i];
+      double * B =3D &coords[3*((i+1)%num_nodes)];
+      double * C =3D &coords[3*((i+2)%num_nodes)];
+      double angle =3D oriented_spherical_angle(A, B, C);
+      if (angle-M_PI > 0.) // even almost reflex is bad; break it!
+      {
+        if (alreadyBroken)
+        {
+          mb->list_entities(&eh, 1);
+          mb->list_entities(verts, num_nodes);
+          double * D =3D &coords[3*((i+3)%num_nodes)];
+          std::cout<< "ABC: " << angle << " \n";
+          std::cout<< "BCD: " << oriented_spherical_angle( B, C, D) << " \=
n";
+          std::cout<< "CDA: " << oriented_spherical_angle( C, D, A) << " \=
n";
+          std::cout<< "DAB: " << oriented_spherical_angle( D, A, B)<< " \n=
";
+          std::cout << " this quad has at least 2 angles > 180, it has ser=
ious issues\n";
+
+          return MB_FAILURE;
+        }
+        // the bad angle is at i+1;
+        // create 1 triangle and one polygon; add the polygon to the input=
 range, so
+        // it will be processed too
+        // also, add both to the set :) and remove the original polygon fr=
om the set
+        // break the next triangle, even though not optimal
+        // so create the triangle i+1, i+2, i+3; remove i+2 from original =
list
+        // even though not optimal in general, it is good enough.
+        EntityHandle conn3[3]=3D{ verts[ (i+1)%num_nodes],
+            verts[ (i+2)%num_nodes],
+            verts[ (i+3)%num_nodes] };
+        // create a polygon with num_nodes-1 vertices, and connectivity
+        // verts[i+1], verts[i+3], (all except i+2)
+        std::vector<EntityHandle> conn(num_nodes-1);
+        for (int j=3D1; j<num_nodes; j++)
+        {
+          conn[j-1]=3Dverts[(i+j+2)%num_nodes];
+        }
+        EntityHandle newElement;
+        rval =3D mb->create_element(MBTRI, conn3, 3, newElement);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+
+        rval =3D mb->add_entities(lset, &newElement, 1);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+        if (num_nodes =3D=3D 4)
+        {
+          // create another triangle
+          rval =3D mb->create_element(MBTRI, &conn[0], 3, newElement);
+          if (MB_SUCCESS !=3D rval)
+            return rval;
+        }
+        else
+        {
+          // create another polygon, and add it to the inputRange
+          rval =3D mb->create_element(MBPOLYGON, &conn[0], num_nodes-1, ne=
wElement);
+          if (MB_SUCCESS !=3D rval)
+            return rval;
+          newPolys.push(newElement); // because it has less number of edge=
s, the
+          // reverse should work to find it.
+        }
+        rval =3D mb->add_entities(lset, &newElement, 1);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+        mb->remove_entities(lset, &eh, 1);
+        brokenPolys++;
+        /*std::cout<<"remove: " ;
+        mb->list_entities(&eh, 1);
+
+        std::stringstream fff;
+        fff << "file0" <<  brokenQuads<< ".vtk";
+        mb->write_file(fff.str().c_str(), 0, 0, &lset, 1);*/
+        alreadyBroken=3Dtrue; // get out of the loop, element is broken
+      }
+    }
+  }
+  std::cout << brokenPolys << " concave polygons were decomposed in convex=
 ones \n";
+  return MB_SUCCESS;
+}
+
 } //namespace moab

diff --git a/tools/mbcslam/CslamUtils.hpp b/tools/mbcslam/CslamUtils.hpp
index e244138..c32a264 100644
--- a/tools/mbcslam/CslamUtils.hpp
+++ b/tools/mbcslam/CslamUtils.hpp
@@ -11,16 +11,20 @@
 #include "moab/Core.hpp"
 #include "moab/Interface.hpp"
=20
+// maximum number of edges on each convex polygon of interest
+#define MAXEDGES 10
+#define MAXEDGES2 20 // used for coordinates in plane
+
 namespace moab
 {
 double dist2(double * a, double * b);
 double area2D(double *a, double *b, double *c);
-int borderPointsOfXinY2(double * X, double * Y, int nsides, double * P, in=
t side[4]);
+int borderPointsOfXinY2(double * X, int nX, double * Y, int nY, double * P=
, int side[MAXEDGES]);
 int SortAndRemoveDoubles2(double * P, int & nP, double epsilon);
 // the marks will show what edges of blue intersect the red
=20
-int EdgeIntersections2(double * blue, double * red, int nsides, int markb[=
4], int markr[4],
-    double * points, int & nPoints);
+int EdgeIntersections2(double * blue, int nsBlue, double * red, int nsRed,
+    int markb[MAXEDGES], int markr[MAXEDGES], double * points, int & nPoin=
ts);
=20
 // vec utils related to gnomonic projection on a sphere
=20
@@ -122,5 +126,9 @@ double distance_on_great_circle(CartVect & p1, CartVect=
 & p2);
=20
 void departure_point_case1(CartVect & arrival_point, double t, double delt=
a_t, CartVect & departure_point);
=20
+// break the nonconvex quads into triangles; remove the quad from the set?=
 yes.
+// maybe radius is not needed;
+//
+ErrorCode enforce_convexity(Interface * mb, EntityHandle set);
 }
 #endif /* CSLAMUTILS_HPP_ */

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/fathomteam/moab/commits/1a3252077efd/
Changeset:   1a3252077efd
Branch:      None
User:        danwu
Date:        2013-06-26 20:10:56
Summary:     Support reading MPAS file type in ReadNC (in progress).

Affected #:  7 files

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index 350e6ae..30eb430 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -52,6 +52,268 @@ NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int f=
ileId, const FileOptions&
   return NULL;
 }
=20
+ErrorCode NCHelper::read_variable_to_set_allocate(std::vector<ReadNC::VarD=
ata>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
+      vdatas[i].has_t =3D true;
+
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+
+      // set up the dimensions and counts
+      // first variable dimension is time, if it exists
+      if (vdatas[i].has_t)
+      {
+        if (vdatas[i].varDims.size() !=3D 1)
+        {
+          vdatas[i].readDims[t].push_back(tstep_nums[t]);
+          vdatas[i].readCounts[t].push_back(1);
+        }
+        else
+        {
+          vdatas[i].readDims[t].push_back(0);
+          vdatas[i].readCounts[t].push_back(tstep_nums.size());
+        }
+      }
+
+      // set up other dimensions and counts
+      if (vdatas[i].varDims.empty()) {
+        // scalar variable
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(1);
+      }
+      else {
+        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
+          if (tDim !=3D vdatas[i].varDims[idx]){
+            // push other variable dimensions, except time, which was alre=
ady pushed
+            vdatas[i].readDims[t].push_back(0);
+            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
+          }
+        }
+      }
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      vdatas[i].sz =3D sz;
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          vdatas[i].varDatas[t] =3D new char[sz];
+          break;
+        case NC_DOUBLE:
+        case NC_FLOAT:
+          vdatas[i].varDatas[t] =3D new double[sz];
+          break;
+        case NC_INT:
+        case NC_SHORT:
+          vdatas[i].varDatas[t] =3D new int[sz];
+          break;
+        default:
+          std::cerr << "Unrecognized data type for tag " << std::endl;
+          rval =3D MB_FAILURE;
+      }
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode NCHelper::read_variable_to_set(EntityHandle file_set, std::vecto=
r<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_variable_to_set_allocate(vdatas, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables to set.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if (dummyVarNames.find(vdatas[i].varName) !=3D dummyVarNames.end() )
+       continue;// this is a dummy one, we don't have it; we created it fo=
r the dummy tag
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      void* data =3D vdatas[i].varDatas[t];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (char*) data NCREQ);
+          ERRORS(success, "Failed to read char data.");
+          break;
+        case NC_DOUBLE:
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (double*) data NCREQ);
+          ERRORS(success, "Failed to read double data.");
+          break;
+        case NC_FLOAT: {
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (float*) data NCREQ);
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT:
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (int*) data NCREQ);
+          ERRORS(success, "Failed to read int data.");
+          break;
+        case NC_SHORT:
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (short*) data NCREQ);
+          ERRORS(success, "Failed to read short data.");
+          break;
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode NCHelper::convert_variable(ReadNC::VarData& var_data, int tstep_=
num)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  // Get ptr to tag space
+  void* data =3D var_data.varDatas[tstep_num];
+
+  std::size_t sz =3D 1;
+  for (std::size_t idx =3D 0; idx !=3D var_data.readCounts[tstep_num].size=
(); idx++)
+    sz *=3D var_data.readCounts[tstep_num][idx];
+
+  // Finally, read into that space
+  int success =3D 0;
+  int* idata;
+  double* ddata;
+  float* fdata;
+  short* sdata;
+
+  switch (var_data.varDataType) {
+    case NC_FLOAT:
+      ddata =3D (double*) var_data.varDatas[tstep_num];
+      fdata =3D (float*) var_data.varDatas[tstep_num];
+      // Convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        ddata[i] =3D fdata[i];
+      break;
+    case NC_SHORT:
+      idata =3D (int*) var_data.varDatas[tstep_num];
+      sdata =3D (short*) var_data.varDatas[tstep_num];
+      // Convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        idata[i] =3D sdata[i];
+      break;
+    default:
+      success =3D 1;
+  }
+
+  if (2 <=3D dbgOut.get_verbosity() && !success) {
+    double dmin, dmax;
+    int imin, imax;
+    switch (var_data.varDataType) {
+      case NC_DOUBLE:
+      case NC_FLOAT:
+        ddata =3D (double*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        dmin =3D dmax =3D ddata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (ddata[i] < dmin)
+            dmin =3D ddata[i];
+          if (ddata[i] > dmax)
+            dmax =3D ddata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
+        break;
+      case NC_INT:
+      case NC_SHORT:
+        idata =3D (int*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        imin =3D imax =3D idata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (idata[i] < imin)
+            imin =3D idata[i];
+          if (idata[i] > imax)
+            imax =3D idata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
+        break;
+      case NC_NAT:
+      case NC_BYTE:
+      case NC_CHAR:
+        break;
+      default: // Default case added to remove compiler warnings
+        success =3D 1;
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
 ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, const FileOptions& =
opts, EntityHandle file_set, Range& faces)
 {
   Interface*& mbImpl =3D _readNC->mbImpl;
@@ -73,7 +335,7 @@ ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, c=
onst FileOptions& opts,
       0, scd_box, locallyPeriodic, &parData);
   ERRORR(rval, "Trouble creating scd vertex sequence.");
=20
-  // add box set and new vertices, elements to the file set
+  // Add box set and new vertices, elements to the file set
   tmp_range.insert(scd_box->start_vertex(), scd_box->start_vertex() + scd_=
box->num_vertices() - 1);
   tmp_range.insert(scd_box->start_element(), scd_box->start_element() + sc=
d_box->num_elements() - 1);
   tmp_range.insert(scd_box->box_set());
@@ -82,7 +344,7 @@ ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, c=
onst FileOptions& opts,
=20
   dbgOut.tprintf(1, "scdbox %d quads, %d vertices\n", scd_box->num_element=
s(), scd_box->num_vertices());
=20
-  // get a ptr to global id memory
+  // Get a ptr to global id memory
   void* data;
   int count;
   const Range::iterator topv =3D tmp_range.upper_bound(tmp_range.begin(), =
tmp_range.end(), scd_box->start_vertex()
@@ -92,7 +354,7 @@ ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, c=
onst FileOptions& opts,
   assert(count =3D=3D scd_box->num_vertices());
   int* gid_data =3D (int*) data;
=20
-  // set the vertex coordinates
+  // Set the vertex coordinates
   double *xc, *yc, *zc;
   rval =3D scd_box->get_coordinate_arrays(xc, yc, zc);
   ERRORR(rval, "Couldn't get vertex coordinate arrays.");
@@ -169,7 +431,7 @@ ErrorCode ScdNCHelper::read_variables(EntityHandle file=
_set, std::vector<std::st
   ERRORR(rval, "Trouble creating coordinate tags to entities quads");
=20
   if (!vsetdatas.empty()) {
-    rval =3D read_scd_variable_to_set(file_set, vsetdatas, tstep_nums);
+    rval =3D read_variable_to_set(file_set, vsetdatas, tstep_nums);
     ERRORR(rval, "Trouble read variables to set.");
   }
=20
@@ -195,7 +457,7 @@ ErrorCode ScdNCHelper::read_scd_variable_setup(std::vec=
tor<std::string>& var_nam
=20
   std::map<std::string, ReadNC::VarData>::iterator mit;
=20
-  // if empty read them all
+  // If empty read them all
   if (var_names.empty()) {
     for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
       ReadNC::VarData vd =3D (*mit).second;
@@ -265,189 +527,10 @@ ErrorCode ScdNCHelper::read_scd_variable_setup(std::=
vector<std::string>& var_nam
   return MB_SUCCESS;
 }
=20
-ErrorCode ScdNCHelper::read_scd_variable_to_set_allocate(std::vector<ReadN=
C::VarData>& vdatas, std::vector<int>& tstep_nums)
+ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allocate(EntityHandle f=
ile_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
 {
-  std::vector<int>& dimVals =3D _readNC->dimVals;
-  int tDim =3D _readNC->tDim;
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-
-  ErrorCode rval =3D MB_SUCCESS;
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
-      vdatas[i].has_t =3D true;
-
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
-
-      // get the tag to read into
-      if (!vdatas[i].varTags[t]) {
-        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
-        ERRORR(rval, "Trouble getting tag.");
-      }
-
-      // assume point-based values for now?
-      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
-        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
-
-      // set up the dimensions and counts
-      // first variable dimension is time, if it exists
-      if (vdatas[i].has_t)
-      {
-        if (vdatas[i].varDims.size() !=3D 1)
-        {
-          vdatas[i].readDims[t].push_back(tstep_nums[t]);
-          vdatas[i].readCounts[t].push_back(1);
-        }
-        else
-        {
-          vdatas[i].readDims[t].push_back(0);
-          vdatas[i].readCounts[t].push_back(tstep_nums.size());
-        }
-      }
-
-      // set up other dimensions and counts
-      if (vdatas[i].varDims.empty()) {
-        // scalar variable
-        vdatas[i].readDims[t].push_back(0);
-        vdatas[i].readCounts[t].push_back(1);
-      }
-      else {
-        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
-          if (tDim !=3D vdatas[i].varDims[idx]){
-            // push other variable dimensions, except time, which was alre=
ady pushed
-            vdatas[i].readDims[t].push_back(0);
-            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
-          }
-        }
-      }
-      std::size_t sz =3D 1;
-      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
-        sz *=3D vdatas[i].readCounts[t][idx];
-      vdatas[i].sz =3D sz;
-      switch (vdatas[i].varDataType) {
-        case NC_BYTE:
-        case NC_CHAR:
-          vdatas[i].varDatas[t] =3D new char[sz];
-          break;
-        case NC_DOUBLE:
-        case NC_FLOAT:
-          vdatas[i].varDatas[t] =3D new double[sz];
-          break;
-        case NC_INT:
-        case NC_SHORT:
-          vdatas[i].varDatas[t] =3D new int[sz];
-          break;
-        default:
-          std::cerr << "Unrecognized data type for tag " << std::endl;
-          rval =3D MB_FAILURE;
-      }
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-  return rval;
-}
-
-ErrorCode ScdNCHelper::read_scd_variable_to_set(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
-{
-  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
-  Interface*& mbImpl =3D _readNC->mbImpl;
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-
-  ErrorCode rval =3D read_scd_variable_to_set_allocate(vdatas, tstep_nums);
-  ERRORR(rval, "Trouble allocating read variables to set.");
-
-  // finally, read into that space
-  int success;
-  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    if (dummyVarNames.find(vdatas[i].varName)!=3D dummyVarNames.end() )
-       continue;// this is a dummy one, we don't have it; we created it fo=
r the dummy tag
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      void* data =3D vdatas[i].varDatas[t];
-
-      switch (vdatas[i].varDataType) {
-        case NC_BYTE:
-        case NC_CHAR:
-          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (char*) data NCREQ);
-          ERRORS(success, "Failed to read char data.");
-          break;
-        case NC_DOUBLE:
-          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (double*) data NCREQ);
-          ERRORS(success, "Failed to read double data.");
-          break;
-        case NC_FLOAT: {
-          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (float*) data NCREQ);
-          ERRORS(success, "Failed to read float data.");
-          break;
-        }
-        case NC_INT:
-          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (int*) data NCREQ);
-          ERRORS(success, "Failed to read int data.");
-          break;
-        case NC_SHORT:
-          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (short*) data NCREQ);
-          ERRORS(success, "Failed to read short data.");
-          break;
-        default:
-          success =3D 1;
-      }
-
-      if (success)
-        ERRORR(MB_FAILURE, "Trouble reading variable.");
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-#ifdef NCWAIT
-  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
-  ERRORS(success, "Failed on wait_all.");
-#endif
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D convert_scd_variable(vdatas[i], t);
-      if (MB_SUCCESS !=3D tmp_rval)
-        rval =3D tmp_rval;
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-  // debug output, if requested
-  if (1 =3D=3D dbgOut.get_verbosity()) {
-    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
-    for (unsigned int i =3D 1; i < vdatas.size(); i++)
-      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
-    dbgOut.tprintf(1, "\n");
-  }
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
-      if (MB_SUCCESS !=3D tmp_rval)
-        rval =3D tmp_rval;
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-  return rval;
-}
-
-ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allocate(EntityHandle f=
ile_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
-{
-  Interface*& mbImpl =3D _readNC->mbImpl;
-  std::vector<std::string>& dimNames =3D _readNC->dimNames;
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  std::vector<std::string>& dimNames =3D _readNC->dimNames;
   std::vector<int>& dimVals =3D _readNC->dimVals;
   int (&lDims)[6] =3D _readNC->lDims;
   int (&lCDims)[6] =3D _readNC->lCDims;
@@ -473,7 +556,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allo=
cate(EntityHandle file_se
   rval =3D mbImpl->get_entities_by_dimension(file_set, 1, edges);
   ERRORR(rval, "Trouble getting edges in set.");
=20
-  // get faces in set
+  // Get faces in set
   Range faces;
   rval =3D mbImpl->get_entities_by_dimension(file_set, 2, faces);
   ERRORR(rval, "Trouble getting faces in set.");
@@ -496,8 +579,8 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allo=
cate(EntityHandle file_se
       dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
=20
       std::vector<std::string>::iterator vit;
-      int idx_lev =3D 0;
-      int idx_ilev =3D 0;
+      int idx_lev =3D -1;
+      int idx_ilev =3D -1;
       if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
         idx_lev =3D vit - dimNames.begin();
       if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
@@ -507,13 +590,13 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_al=
locate(EntityHandle file_se
       else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
         vdatas[i].numLev =3D dimVals[idx_ilev];
=20
-      // get the tag to read into
+      // Get the tag to read into
       if (!vdatas[i].varTags[t]) {
         rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
         ERRORR(rval, "Trouble getting tag.");
       }
=20
-      // assume point-based values for now?
+      // Assume point-based values for now?
       if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
         ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
       }
@@ -521,8 +604,8 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allo=
cate(EntityHandle file_se
         ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
       }
=20
-      // set up the dimensions and counts
-      // first time
+      // Set up the dimensions and counts
+      // First time
       vdatas[i].readDims[t].push_back(tstep_nums[t]);
       vdatas[i].readCounts[t].push_back(1);
=20
@@ -570,7 +653,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allo=
cate(EntityHandle file_se
           break;
       }
=20
-      // get ptr to tag space
+      // Get ptr to tag space
       void* data;
       int count;
       rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
@@ -590,7 +673,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Enti=
tyHandle file_set, std::v
   ErrorCode rval =3D read_scd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
   ERRORR(rval, "Trouble allocating read variables.");
=20
-  // finally, read into that space
+  // Finally, read into that space
   int success;
   std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
@@ -638,7 +721,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Enti=
tyHandle file_set, std::v
           success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               &tmpfloatdata[0] NCREQ);
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
@@ -652,7 +735,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Enti=
tyHandle file_set, std::v
           success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               &tmpintdata[0] NCREQ);
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
@@ -666,7 +749,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Enti=
tyHandle file_set, std::v
           success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               &tmpshortdata[0] NCREQ);
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
@@ -692,7 +775,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Enti=
tyHandle file_set, std::v
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
     for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
       dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D convert_scd_variable(vdatas[i], t);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
       if (MB_SUCCESS !=3D tmp_rval)
         rval =3D tmp_rval;
     }
@@ -708,89 +791,6 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset(Ent=
ityHandle file_set, std::v
   return rval;
 }
=20
-ErrorCode ScdNCHelper::convert_scd_variable(ReadNC::VarData& var_data, int=
 tstep_num)
-{
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-
-  // get ptr to tag space
-  void* data =3D var_data.varDatas[tstep_num];
-
-  std::size_t sz =3D 1;
-  for (std::size_t idx =3D 0; idx !=3D var_data.readCounts[tstep_num].size=
(); idx++)
-    sz *=3D var_data.readCounts[tstep_num][idx];
-
-  // finally, read into that space
-  int success =3D 0;
-  int* idata;
-  double* ddata;
-  float* fdata;
-  short* sdata;
-
-  switch (var_data.varDataType) {
-    case NC_FLOAT:
-      ddata =3D (double*) var_data.varDatas[tstep_num];
-      fdata =3D (float*) var_data.varDatas[tstep_num];
-      // convert in-place
-      for (int i =3D sz - 1; i >=3D 0; i--)
-        ddata[i] =3D fdata[i];
-      break;
-    case NC_SHORT:
-      idata =3D (int*) var_data.varDatas[tstep_num];
-      sdata =3D (short*) var_data.varDatas[tstep_num];
-      // convert in-place
-      for (int i =3D sz - 1; i >=3D 0; i--)
-        idata[i] =3D sdata[i];
-      break;
-    default:
-      success =3D 1;
-  }
-
-  if (2 <=3D dbgOut.get_verbosity() && !success) {
-    double dmin, dmax;
-    int imin, imax;
-    switch (var_data.varDataType) {
-      case NC_DOUBLE:
-      case NC_FLOAT:
-        ddata =3D (double*) data;
-        if (sz =3D=3D 0)
-          break;
-
-        dmin =3D dmax =3D ddata[0];
-        for (unsigned int i =3D 1; i < sz; i++) {
-          if (ddata[i] < dmin)
-            dmin =3D ddata[i];
-          if (ddata[i] > dmax)
-            dmax =3D ddata[i];
-        }
-        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
-        break;
-      case NC_INT:
-      case NC_SHORT:
-        idata =3D (int*) data;
-        if (sz =3D=3D 0)
-          break;
-
-        imin =3D imax =3D idata[0];
-        for (unsigned int i =3D 1; i < sz; i++) {
-          if (idata[i] < imin)
-            imin =3D idata[i];
-          if (idata[i] > imax)
-            imax =3D idata[i];
-        }
-        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
-        break;
-      case NC_NAT:
-      case NC_BYTE:
-      case NC_CHAR:
-        break;
-      default: //default case added to remove compiler warnings
-        success =3D 1;
-    }
-  }
-
-  return MB_SUCCESS;
-}
-
 ErrorCode UcdNCHelper::read_variables(EntityHandle file_set, std::vector<s=
td::string>& var_names, std::vector<int>& tstep_nums)
 {
   std::vector<ReadNC::VarData> vdatas;
@@ -799,6 +799,11 @@ ErrorCode UcdNCHelper::read_variables(EntityHandle fil=
e_set, std::vector<std::st
   ErrorCode rval =3D read_ucd_variable_setup(var_names, tstep_nums, vdatas=
, vsetdatas);
   ERRORR(rval, "Trouble setting up read variable.");
=20
+  if (!vsetdatas.empty()) {
+    rval =3D read_variable_to_set(file_set, vsetdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to set.");
+  }
+
   if (!vdatas.empty()) {
 #ifdef PNETCDF_FILE
     // in serial, we will use the old read, everything is contiguous
@@ -814,183 +819,4 @@ ErrorCode UcdNCHelper::read_variables(EntityHandle fi=
le_set, std::vector<std::st
   return MB_SUCCESS;
 }
=20
-ErrorCode UcdNCHelper::read_ucd_variable_to_set_allocate(std::vector<ReadN=
C::VarData>& vdatas, std::vector<int>& tstep_nums)
-{
-  std::vector<int>& dimVals =3D _readNC->dimVals;
-  int tDim =3D _readNC->tDim;
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-
-  ErrorCode rval =3D MB_SUCCESS;
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
-      vdatas[i].has_t =3D true;
-
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
-
-      // get the tag to read into
-      if (!vdatas[i].varTags[t]) {
-        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
-        ERRORR(rval, "Trouble getting tag.");
-      }
-
-      // assume point-based values for now?
-      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
-        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
-
-      // set up the dimensions and counts
-      // first variable dimension is time, if it exists
-      if (vdatas[i].has_t)
-      {
-        if (vdatas[i].varDims.size() !=3D 1)
-        {
-          vdatas[i].readDims[t].push_back(tstep_nums[t]);
-          vdatas[i].readCounts[t].push_back(1);
-        }
-        else
-        {
-          vdatas[i].readDims[t].push_back(0);
-          vdatas[i].readCounts[t].push_back(tstep_nums.size());
-        }
-      }
-
-      // set up other dimensions and counts
-      if (vdatas[i].varDims.empty()) {
-        // scalar variable
-        vdatas[i].readDims[t].push_back(0);
-        vdatas[i].readCounts[t].push_back(1);
-      }
-      else {
-        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
-          if (tDim !=3D vdatas[i].varDims[idx]){
-            // push other variable dimensions, except time, which was alre=
ady pushed
-            vdatas[i].readDims[t].push_back(0);
-            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
-          }
-        }
-      }
-      std::size_t sz =3D 1;
-      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
-        sz *=3D vdatas[i].readCounts[t][idx];
-      vdatas[i].sz =3D sz;
-      switch (vdatas[i].varDataType) {
-        case NC_BYTE:
-        case NC_CHAR:
-          vdatas[i].varDatas[t] =3D new char[sz];
-          break;
-        case NC_DOUBLE:
-        case NC_FLOAT:
-          vdatas[i].varDatas[t] =3D new double[sz];
-          break;
-        case NC_INT:
-        case NC_SHORT:
-          vdatas[i].varDatas[t] =3D new int[sz];
-          break;
-        default:
-          std::cerr << "Unrecognized data type for tag " << std::endl;
-          rval =3D MB_FAILURE;
-      }
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-  return rval;
-}
-
-ErrorCode UcdNCHelper::read_ucd_variable_to_set(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas, std::vector<int> &tstep_nums)
-{
-  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
-  Interface*& mbImpl =3D _readNC->mbImpl;
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-
-  ErrorCode rval =3D read_ucd_variable_to_set_allocate(vdatas, tstep_nums);
-  ERRORR(rval, "Trouble allocating read variables to set.");
-
-  // finally, read into that space
-  int success;
-  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    if (dummyVarNames.find(vdatas[i].varName) !=3D dummyVarNames.end() )
-       continue; // this is a dummy one, we don't have it; we created it f=
or the dummy tag
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      void* data =3D vdatas[i].varDatas[t];
-
-      switch (vdatas[i].varDataType) {
-        case NC_BYTE:
-        case NC_CHAR:
-          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (char*) data NCREQ);
-          ERRORS(success, "Failed to read char data.");
-          break;
-        case NC_DOUBLE:
-          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (double*) data NCREQ);
-          ERRORS(success, "Failed to read double data.");
-          break;
-        case NC_FLOAT: {
-          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (float*) data NCREQ);
-          ERRORS(success, "Failed to read float data.");
-          break;
-        }
-        case NC_INT:
-          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (int*) data NCREQ);
-          ERRORS(success, "Failed to read int data.");
-          break;
-        case NC_SHORT:
-          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
-              (short*) data NCREQ);
-          ERRORS(success, "Failed to read short data.");
-          break;
-        default:
-          success =3D 1;
-      }
-
-      if (success)
-        ERRORR(MB_FAILURE, "Trouble reading variable.");
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-#ifdef NCWAIT
-  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
-  ERRORS(success, "Failed on wait_all.");
-#endif
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
-      if (MB_SUCCESS !=3D tmp_rval)
-        rval =3D tmp_rval;
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-  // debug output, if requested
-  if (1 =3D=3D dbgOut.get_verbosity()) {
-    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
-    for (unsigned int i =3D 1; i < vdatas.size(); i++)
-      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
-    dbgOut.tprintf(1, "\n");
-  }
-
-  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
-    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
-      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
-      if (MB_SUCCESS !=3D tmp_rval)
-        rval =3D tmp_rval;
-      if (vdatas[i].varDims.size() <=3D 1)
-        break;
-    }
-  }
-
-  return rval;
-}
-
 } // namespace moab

diff --git a/src/io/NCHelper.hpp b/src/io/NCHelper.hpp
index 6aac571..8f63336 100644
--- a/src/io/NCHelper.hpp
+++ b/src/io/NCHelper.hpp
@@ -20,20 +20,32 @@ public:
   NCHelper(ReadNC* readNC, int fileId) : _readNC(readNC), _fileId(fileId) =
{}
   virtual ~NCHelper() {}
=20
+  //! Get appropriate helper instance for ReadNC class
   static NCHelper* get_nc_helper(ReadNC* readNC, int fileId, const FileOpt=
ions& opts);
=20
-  //! Interfaces to be implemented by child classes
+  //! Interfaces to be implemented in child classes
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set) =3D 0;
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces) =3D 0;
   virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums) =3D 0;
   virtual std::string get_mesh_type_name() =3D 0;
=20
 protected:
+  //! Read set variables, common to scd mesh and ucd mesh
+  ErrorCode read_variable_to_set(EntityHandle file_set, std::vector<ReadNC=
::VarData>& vdatas, std::vector<int>& tstep_nums);
+
+  //! Convert variables in place
+  ErrorCode convert_variable(ReadNC::VarData& var_data, int tstep_num);
+
+private:
+  //! Used by read_variable_to_set()
+  ErrorCode read_variable_to_set_allocate(std::vector<ReadNC::VarData>& vd=
atas, std::vector<int>& tstep_nums);
+
+protected:
   ReadNC* _readNC;
   int _fileId;
 };
=20
-//! Child helper class for structured mesh, e.g. CAM_EL or CAM_FV
+//! Child helper class for scd mesh, e.g. CAM_EL or CAM_FV
 class ScdNCHelper : public NCHelper
 {
 public:
@@ -46,27 +58,27 @@ private:
   //! Implementation of NCHelper::read_variables()
   virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums);
=20
-  //! These functions are used by read_variables(), fully implemented
+  //! Separate set and non-set variables for scd mesh
   ErrorCode read_scd_variable_setup(std::vector<std::string>& var_names,
                                     std::vector<int>& tstep_nums,
                                     std::vector<ReadNC::VarData>& vdatas,
                                     std::vector<ReadNC::VarData>& vsetdata=
s);
-  ErrorCode read_scd_variable_to_set_allocate(std::vector<ReadNC::VarData>=
& vdatas,
-                                              std::vector<int>& tstep_nums=
);
-  ErrorCode read_scd_variable_to_set(EntityHandle file_set, std::vector<Re=
adNC::VarData>& vdatas,
-                                     std::vector<int>& tstep_nums);
+
+  //! Read non-set variables for scd mesh
   ErrorCode read_scd_variable_to_nonset_allocate(EntityHandle file_set, st=
d::vector<ReadNC::VarData>& vdatas,
                                                  std::vector<int>& tstep_n=
ums);
   ErrorCode read_scd_variable_to_nonset(EntityHandle file_set, std::vector=
<ReadNC::VarData>& vdatas,
                                         std::vector<int>& tstep_nums);
-  ErrorCode convert_scd_variable(ReadNC::VarData& var_data, int tstep_num);
 };
=20
-//! Child helper class for unstructured mesh, e.g. CAM_SE (HOMME) or MPAS
+//! Child helper class for ucd mesh, e.g. CAM_SE (HOMME) or MPAS
 class UcdNCHelper : public NCHelper
 {
 public:
-  UcdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  UcdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId),
+  cDim(-1), eDim(-1), vDim(-1), levDim(-1),
+  nCells(0), nEdges(0), nVertices(0),
+  nLocalCells(0), nLocalEdges(0), nLocalVertices(0) {}
   virtual ~UcdNCHelper() {}
=20
 private:
@@ -74,15 +86,13 @@ private:
   virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names,
                                    std::vector<int> &tstep_nums);
=20
-  //! These functions are used by read_variables(), partially implemented
+  //! Separate set and non-set variables for ucd mesh (implemented differe=
ntly in child classes)
   virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
                                             std::vector<int>& tstep_nums,
                                             std::vector<ReadNC::VarData>& =
vdatas,
                                             std::vector<ReadNC::VarData>& =
vsetdatas) =3D 0;
-  ErrorCode read_ucd_variable_to_set_allocate(std::vector<ReadNC::VarData>=
& vdatas,
-                                              std::vector<int>& tstep_nums=
);
-  ErrorCode read_ucd_variable_to_set(EntityHandle file_set, std::vector<Re=
adNC::VarData>& vdatas,
-                                     std::vector<int>& tstep_nums);
+
+  //! Read non-set variables for ucd mesh (implemented differently in chil=
d classes)
   virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
                                                          std::vector<int>&=
 tstep_nums) =3D 0;
 #ifdef PNETCDF_FILE
@@ -92,7 +102,23 @@ private:
   virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
                                                 std::vector<int>& tstep_nu=
ms) =3D 0;
 #endif
-  virtual ErrorCode convert_ucd_variable(ReadNC::VarData& var_data, int ts=
tep_num) =3D 0;
+
+protected:
+  //! Dimension numbers for nCells, nEdges, nVertices, nLevels
+  int cDim, eDim, vDim, levDim;
+
+  //! Coordinate values for vertices
+  std::vector<double> xVertVals, yVertVals, zVertVals;
+
+  int nCells;
+  int nEdges;
+  int nVertices;
+
+  int nLocalCells;
+  int nLocalEdges;
+  int nLocalVertices;
+
+  Range localGidCells, localGidEdges, localGidVerts;
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 6694abb..60d63c0 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -2,15 +2,14 @@
 #include "moab/ReadUtilIface.hpp"
 #include "FileOptions.hpp"
 #include "moab/SpectralMeshTool.hpp"
-#include "MBTagConventions.hpp"
=20
 #include <cmath>
=20
 #define ERRORR(rval, str) \
-    if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", =
str); return rval;}
+  if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", st=
r); return rval;}
=20
 #define ERRORS(err, str) \
-    if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_F=
AILURE;}
+  if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_FAI=
LURE;}
=20
 namespace moab {
=20
@@ -92,7 +91,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptions=
& opts, EntityHandle fi
   tMin =3D 0;
   tName =3D dimNames[idx];
=20
-  // get number of vertices (labeled as number of columns) and levels
+  // Get number of vertices (labeled as number of columns) and levels
   gDims[0] =3D gDims[3] =3D -1;
   if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ncol")) !=3D d=
imNames.end()) {
     idx =3D vit - dimNames.begin();
@@ -144,9 +143,9 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
       rval =3D _readNC->read_coordinate("lev", gDims[2], gDims[5], klVals);
       ERRORR(rval, "Trouble reading z variable.");
=20
-      // decide whether down is positive
+      // Decide whether down is positive
       char posval[10];
-      int success =3D NCFUNC(get_att_text)(_readNC->fileId, (*vmit).second=
.varId, "positive", posval);
+      int success =3D NCFUNC(get_att_text)(_fileId, (*vmit).second.varId, =
"positive", posval);
       if (0 =3D=3D success && !strcmp(posval, "down")) {
         for (std::vector<double>::iterator dvit =3D klVals.begin(); dvit !=
=3D klVals.end(); ++dvit)
           (*dvit) *=3D -1.0;
@@ -350,7 +349,7 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi=
, const FileOptions& opts
     ERRORR(rval, "Failed to get fine connectivity of spectral elements.");
   }
=20
-  // on this proc, I get columns ldims[1]..ldims[4], inclusive; need to fi=
nd which vertices those correpond to
+  // on this proc, I get columns lDims[1]..lDims[4], inclusive; need to fi=
nd which vertices those correspond to
   unsigned int num_local_verts =3D localGid.size();
   unsigned int num_total_verts =3D gDims[3] - gDims[0] + 1;
=20
@@ -367,17 +366,21 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* sc=
di, const FileOptions& opts
   int i;
   for (i =3D 0, rit =3D localGid.begin(); i < (int)num_local_verts; i++, +=
+rit) {
     assert(*rit < ilVals.size() + 1);
-    xptr[i] =3D ilVals[(*rit) - 1];
-    yptr[i] =3D jlVals[(*rit) - 1];
-    zptr[i] =3D klVals[lDims[2]];
+    xptr[i] =3D ilVals[(*rit) - 1]; // lon
+    yptr[i] =3D jlVals[(*rit) - 1]; // lat
+    zptr[i] =3D klVals[lDims[2]]; // dummy
   }
=20
   const double pideg =3D acos(-1.0) / 180.0;
   for (i =3D 0; i < (int)num_local_verts; i++) {
     double cosphi =3D cos(pideg * yptr[i]);
-    double zmult =3D sin(pideg * yptr[i]), xmult =3D cosphi * cos(xptr[i] =
* pideg), ymult =3D cosphi * sin(xptr[i] * pideg);
+    double zmult =3D sin(pideg * yptr[i]);
+    double xmult =3D cosphi * cos(xptr[i] * pideg);
+    double ymult =3D cosphi * sin(xptr[i] * pideg);
     double rad =3D 8.0e3 + klVals[lDims[2]];
-    xptr[i] =3D rad * xmult, yptr[i] =3D rad * ymult, zptr[i] =3D rad * zm=
ult;
+    xptr[i] =3D rad * xmult;
+    yptr[i] =3D rad * ymult;
+    zptr[i] =3D rad * zmult;
   }
=20
   // get ptr to gid memory for vertices
@@ -516,13 +519,14 @@ ErrorCode NCHelperHOMME::read_ucd_variable_setup(std:=
:vector<std::string>& var_n
=20
   std::map<std::string, ReadNC::VarData>::iterator mit;
=20
+  // If empty read them all
   if (var_names.empty()) {
     for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
       ReadNC::VarData vd =3D (*mit).second;
       if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd.v=
arDims.end()) && (std::find(vd.varDims.begin(),
           vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), iDim)
           !=3D vd.varDims.end()))
-        vdatas.push_back(vd); //3d data (time, ncol, ilev) read here
+        vdatas.push_back(vd); // 3d data (time, lev, ncol) read here
       else
         vsetdatas.push_back(vd);
     }
@@ -536,11 +540,13 @@ ErrorCode NCHelperHOMME::read_ucd_variable_setup(std:=
:vector<std::string>& var_n
         if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd=
.varDims.end()) && (std::find(vd.varDims.begin(),
             vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(v=
d.varDims.begin(), vd.varDims.end(), iDim)
             !=3D vd.varDims.end()))
-          vdatas.push_back(vd); //3d data
+          vdatas.push_back(vd); // 3d data (time, lev, ncol) read here
         else
           vsetdatas.push_back(vd);
       }
-      else ERRORR(MB_FAILURE, "Couldn't find variable.");
+      else {
+        ERRORR(MB_FAILURE, "Couldn't find variable.");
+      }
     }
   }
=20
@@ -589,7 +595,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_al=
locate(EntityHandle file_
=20
   Range* range =3D NULL;
=20
-  // get vertices in set
+  // Get vertices in set
   Range verts;
   rval =3D mbImpl->get_entities_by_dimension(file_set, 0, verts);
   ERRORR(rval, "Trouble getting vertices in set.");
@@ -601,8 +607,8 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_al=
locate(EntityHandle file_
       dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
=20
       std::vector<std::string>::iterator vit;
-      int idx_lev =3D 0;
-      int idx_ilev =3D 0;
+      int idx_lev =3D -1;
+      int idx_ilev =3D -1;
       if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
         idx_lev =3D vit - dimNames.begin();
       if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
@@ -612,13 +618,13 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_=
allocate(EntityHandle file_
       else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
         vdatas[i].numLev =3D dimVals[idx_ilev];
=20
-      // get the tag to read into
+      // Get the tag to read into
       if (!vdatas[i].varTags[t]) {
         rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
         ERRORR(rval, "Trouble getting tag.");
       }
=20
-      // assume point-based values for now?
+      // Assume point-based values for now?
       if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
         ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
       }
@@ -626,23 +632,24 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_=
allocate(EntityHandle file_
         ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
       }
=20
-      // set up the dimensions and counts
-      // first time
+      // Set up the dimensions and counts
+      // First: time
       vdatas[i].readDims[t].push_back(tstep_nums[t]);
       vdatas[i].readCounts[t].push_back(1);
=20
-      // then numLev/numVertices
+      // Next: numLev
       if (vdatas[i].numLev !=3D 1) {
         vdatas[i].readDims[t].push_back(0);
         vdatas[i].readCounts[t].push_back(vdatas[i].numLev);
       }
=20
+      // Finally: nVertices
       switch (vdatas[i].entLoc) {
         case ReadNC::ENTLOCVERT:
           // vertices
           // we will start from the first localGid, actually; we will rese=
t that
           // later on, anyway, in a loop
-          vdatas[i].readDims[t].push_back(localGid[0]-1);
+          vdatas[i].readDims[t].push_back(localGid[0] - 1);
           vdatas[i].readCounts[t].push_back(localGid.size());
           assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
           range =3D &verts;
@@ -655,7 +662,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_al=
locate(EntityHandle file_
           break;
       }
=20
-      // get ptr to tag space
+      // Get ptr to tag space
       void* data;
       int count;
       rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
@@ -677,7 +684,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_as=
ync(EntityHandle file_set
   ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
   ERRORR(rval, "Trouble allocating read variables.");
=20
-  // finally, read into that space
+  // Finally, read into that space
   int success;
   // MPI_offset or size_t?
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
@@ -693,7 +700,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_as=
ync(EntityHandle file_set
       size_t idxReq =3D 0;
       void* data =3D vdatas[i].varDatas[t];
       size_t ni =3D vdatas[i].readCounts[t][2];
-      size_t nj =3D 1; // for HOMME, nj holds # quads, so here should set =
to 1
+      size_t nj =3D 1; // For HOMME, nj holds # quads, so here should set =
to 1
       size_t nk =3D vdatas[i].readCounts[t][1];
=20
       switch (vdatas[i].varDataType) {
@@ -731,7 +738,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_as=
ync(EntityHandle file_set
                 &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
                             &(tmpdoubledata[indexInDoubleArray]) NCREQ2);
             ERRORS(success, "Failed to read double data in loop");
-            // we need to increment the index in float array for the
+            // we need to increment the index in double array for the
             // next subrange
             indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
           }
@@ -817,7 +824,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_as=
ync(EntityHandle file_set
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
     for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
       dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
       if (MB_SUCCESS !=3D tmp_rval)
         rval =3D tmp_rval;
     }
@@ -836,11 +843,12 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_=
async(EntityHandle file_set
 ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(EntityHandle file_set=
, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
 {
   DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
=20
   ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
   ERRORR(rval, "Trouble allocating read variables.");
=20
-  // finally, read into that space
+  // Finally, read into that space
   int success;
   std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
@@ -848,7 +856,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(En=
tityHandle file_set, std:
       std::size_t sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
       void* data =3D vdatas[i].varDatas[t];
       size_t ni =3D vdatas[i].readCounts[t][2];
-      size_t nj =3D 1; // for HOMME, nj holds # quads, so here should set =
to 1
+      size_t nj =3D 1; // For HOMME, nj holds # quads, so here should set =
to 1
       size_t nk =3D vdatas[i].readCounts[t][1];
=20
       switch (vdatas[i].varDataType) {
@@ -868,7 +876,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(En=
tityHandle file_set, std:
           break;
         }
         case NC_DOUBLE: {
-          // copy from float case
+          // Copy from float case
           std::vector<double> tmpdoubledata(sz);
=20
           // in the case of ucd mesh, and on multiple proc,
@@ -877,31 +885,30 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(=
EntityHandle file_set, std:
           // basically, we have to give a different point
           // for data to start, for every subrange :(
           size_t nbDims =3D vdatas[i].readDims[t].size();
-          // assume that the last dimension is for the ncol,
-          // node varying variable
=20
+          // Assume that the last dimension is for the ncol
           size_t indexInDoubleArray =3D 0;
           size_t ic =3D 0;
           for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
               pair_iter !=3D localGid.pair_end();
               pair_iter++, ic++) {
             EntityHandle starth =3D pair_iter->first;
-            EntityHandle endh =3D pair_iter->second; // inclusive
-            vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth - 1);
-            vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh - star=
th + 1);
+            EntityHandle endh =3D pair_iter->second; // Inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
=20
-            success =3D NCFUNCAG(_vara_double)(fileId, vdatas[i].varId,
+            success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId,
                 &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
                             &(tmpdoubledata[indexInDoubleArray]) NCREQ);
             ERRORS(success, "Failed to read float data in loop");
-            // we need to increment the index in float array for the
+            // We need to increment the index in double array for the
             // next subrange
             indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
           }
           assert(ic =3D=3D localGid.psize());
=20
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpdoubleda=
ta[0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
@@ -919,31 +926,30 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(=
EntityHandle file_set, std:
           // basically, we have to give a different point
           // for data to start, for every subrange :(
           size_t nbDims =3D vdatas[i].readDims[t].size();
-          // assume that the last dimension is for the ncol,
-          // node varying variable
=20
+          // Assume that the last dimension is for the ncol
           size_t indexInFloatArray =3D 0;
           size_t ic =3D 0;
           for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
               pair_iter !=3D localGid.pair_end();
               pair_iter++, ic++) {
             EntityHandle starth =3D pair_iter->first;
-            EntityHandle endh =3D pair_iter->second; // inclusive
+            EntityHandle endh =3D pair_iter->second; // Inclusive
             vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth - 1);
             vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh - star=
th + 1);
=20
-            success =3D NCFUNCAG(_vara_float)(fileId, vdatas[i].varId,
+            success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId,
                 &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
                             &(tmpfloatdata[indexInFloatArray]) NCREQ);
             ERRORS(success, "Failed to read float data in loop");
-            // we need to increment the index in float array for the
+            // We need to increment the index in float array for the
             // next subrange
             indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].num=
Lev;
           }
           assert(ic =3D=3D localGid.psize());
=20
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
@@ -957,7 +963,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(En=
tityHandle file_set, std:
           success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               &tmpintdata[0] NCREQ);
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
@@ -971,7 +977,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(En=
tityHandle file_set, std:
           success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
               &tmpshortdata[0] NCREQ);
           if (vdatas[i].numLev !=3D 1)
-            // switch from k varying slowest to k varying fastest
+            // Switch from k varying slowest to k varying fastest
             success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
           else {
             for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
@@ -997,7 +1003,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(E=
ntityHandle file_set, std:
   for (unsigned int i =3D 0; i < vdatas.size(); i++) {
     for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
       dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
-      ErrorCode tmp_rval =3D convert_ucd_variable(vdatas[i], t);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
       if (MB_SUCCESS !=3D tmp_rval)
         rval =3D tmp_rval;
     }
@@ -1014,86 +1020,4 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset=
(EntityHandle file_set, std:
 }
 #endif
=20
-ErrorCode NCHelperHOMME::convert_ucd_variable(ReadNC::VarData& var_data, i=
nt tstep_num)
-{
-  DebugOutput& dbgOut =3D _readNC->dbgOut;
-  Range& localGid =3D _readNC->localGid;
-
-  // get ptr to tag space
-  void* data =3D var_data.varDatas[tstep_num];
-
-  std::size_t sz =3D var_data.numLev * localGid.size(); // how many nodes =
are we reading?
-
-  // finally, read into that space
-  int success =3D 0;
-  int* idata;
-  double* ddata;
-  float* fdata;
-  short* sdata;
-
-  switch (var_data.varDataType) {
-    case NC_FLOAT:
-      ddata =3D (double*) var_data.varDatas[tstep_num];
-      fdata =3D (float*) var_data.varDatas[tstep_num];
-      // convert in-place
-      for (int i =3D sz - 1; i >=3D 0; i--)
-        ddata[i] =3D fdata[i];
-      break;
-    case NC_SHORT:
-      idata =3D (int*) var_data.varDatas[tstep_num];
-      sdata =3D (short*) var_data.varDatas[tstep_num];
-      // convert in-place
-      for (int i =3D sz - 1; i >=3D 0; i--)
-        idata[i] =3D sdata[i];
-      break;
-    default:
-      success =3D 1;
-  }
-
-  if (2 <=3D dbgOut.get_verbosity() && !success) {
-    double dmin, dmax;
-    int imin, imax;
-    switch (var_data.varDataType) {
-      case NC_DOUBLE:
-      case NC_FLOAT:
-        ddata =3D (double*) data;
-        if (sz =3D=3D 0)
-          break;
-
-        dmin =3D dmax =3D ddata[0];
-        for (unsigned int i =3D 1; i < sz; i++) {
-          if (ddata[i] < dmin)
-            dmin =3D ddata[i];
-          if (ddata[i] > dmax)
-            dmax =3D ddata[i];
-        }
-        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
-        break;
-      case NC_INT:
-      case NC_SHORT:
-        idata =3D (int*) data;
-        if (sz =3D=3D 0)
-          break;
-
-        imin =3D imax =3D idata[0];
-        for (unsigned int i =3D 1; i < sz; i++) {
-          if (idata[i] < imin)
-            imin =3D idata[i];
-          if (idata[i] > imax)
-            imax =3D idata[i];
-        }
-        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
-        break;
-      case NC_NAT:
-      case NC_BYTE:
-      case NC_CHAR:
-        break;
-      default: //default case added to remove compiler warnings
-        success =3D 1;
-    }
-  }
-
-  return MB_SUCCESS;
-}
-
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index 3fc3724..b7dc7ac 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -45,8 +45,6 @@ private:
   virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
                                                 std::vector<int>& tstep_nu=
ms);
 #endif
-  //! Implementation of UcdNCHelper::convert_ucd_variable()
-  virtual ErrorCode convert_ucd_variable(ReadNC::VarData& var_data, int ts=
tep_num);
=20
 private:
   int _spectralOrder; // Read from variable 'np'

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/fathomteam/moab/commits/23f9da1daf5d/
Changeset:   23f9da1daf5d
Branch:      None
User:        danwu
Date:        2013-06-26 20:11:28
Summary:     Merge branch 'master' of https://bitbucket.org/danwu/moab

Affected #:  29 files

diff --git a/MeshFiles/unittest/io/Makefile.am b/MeshFiles/unittest/io/Make=
file.am
index ece20cf..8257e5f 100644
--- a/MeshFiles/unittest/io/Makefile.am
+++ b/MeshFiles/unittest/io/Makefile.am
@@ -3,6 +3,7 @@ EXTRA_DIST =3D HommeMapping.nc \
              brick_cubit10.2.cub \
              brick_cubit10.cub \
              camEul26x48x96.t3.nc \
+             fv26x46x72.t.3.nc \
 	     cubtest12.cub \
 	     cubtest.jou \
 	     dum.sat \

diff --git a/MeshFiles/unittest/mpas_p8.h5m b/MeshFiles/unittest/mpas_p8.h5m
new file mode 100644
index 0000000..75662d2
Binary files /dev/null and b/MeshFiles/unittest/mpas_p8.h5m differ

diff --git a/doc/DG/moabDG.h b/doc/DG/moabDG.h
new file mode 100644
index 0000000..d2e14f0
--- /dev/null
+++ b/doc/DG/moabDG.h
@@ -0,0 +1,259 @@
+/*! \page developerguide Developer's Guide (MOAB 4.6)
+=20
+  \subpage dg-contents
+=20
+  \subpage dg-figures
+
+  \page dg-contents Table of Contents
+
+  \ref sequence
+
+  \ref manager
+
+  \ref s-mesh
+
+  \ref sets
+
+  \section sequence  1. EntitySequence & SequenceData
+
+  \subsection figure1 Figure 1: EntitySequences For One SequenceData
+
+The <I>SequenceData</I> class manages as set of arrays of per-entity value=
s. Each
+<I>SequenceData</I> has a start and end handle denoting the block of entit=
ies for which
+the arrays contain data. The arrays managed by a <I>SequenceData</I> insta=
nce are
+divided into three groups:
+
+- Type-specific data (connectivity, coordinates, etc.): zero or more array=
s.
+- Adjacency data: zero or one array.
+- Dense tag data: zero or more arrays.
+.
+
+The abstract <I>EntitySequence</I> class is a non-strict subset of a <I>Se=
quenceData</I>.
+It contains a pointer to a <I>SequenceData</I> and the start and end handl=
es to indi-
+cate the subset of the referenced <I>SequenceData</I>. The <I>EntitySequen=
ce</I> class is
+used to represent the regions of valid (or allocated) handles in a <I>Sequ=
enceData</I>.
+A <I>SequenceData</I> is expected to be referenced by one or more <I>Entit=
ySequence</I>
+instances.
+
+Initial <I>EntitySequence</I> and <I>SequenceData</I> pairs are typically =
created in one
+of two configurations. When reading from a file, a <I>SequenceData</I> wil=
l be created
+to represent all of a single type of entity contained in a file. As all en=
tries in the <I>SequenceData</I> correspond to valid handles (entities read=
 from the file) a single
+<I>EntitySequence</I> instance corresponding to the entire <I>SequenceData=
</I> is initially
+created. The second configuration arises when allocating a single entity. =
If no
+entities have been allocated yet, a new <I>SequenceData</I> must be create=
d to store
+the entity data. It is created with a constant size (e.g. 4k entities). Th=
e new
+<I>EntitySequence</I> corresponds to only the first entity in the <I>Seque=
nceData</I>: the
+one allocated entity. As subsequent entities are allocated, the <I>EntityS=
equence</I>
+is extended to cover more of the corresponding <I>SequenceData</I>.
+
+Concrete subclasses of the <I>EntitySequence</I> class are responsible for=
 rep-
+resenting specific types of entities using the array storage provided by t=
he
+<I>SequenceData</I> class. They also handle allocating <I>SequenceData</I>=
 instances with
+appropriate arrays for storing a particular type of entity. Each concrete =
subclass
+typically provides two constructors corresponding to the two initial alloc=
ation
+configurations described in the previous paragraph. <I>EntitySequence</I> =
imple-
+mentations also provide a split method, which is a type of factory method.=
 It
+modifies the called sequence and creates a new sequence such that the rang=
e of
+entities represented by the original sequence is split.
+
+The <I>VertexSequence</I> class provides an <I>EntitySequence</I> for stor=
ing ver-
+tex data. It references a SequenceData containing three arrays of doubles
+for storing the blocked vertex coordinate data. The <I>ElementSequence</I>=
 class
+extends the <I>EntitySequence</I> interface with element-specific function=
ality. The
+<I>UnstructuredElemSeq</I> class is the concrete implementation of <I>Elem=
entSequence</I>
+used to represent unstructured elements, polygons, and polyhedra. <I>MeshS=
etSequence</I>
+is the <I>EntitySequence</I> used for storing entity sets.
+
+Each <I>EntitySequence</I> implementation also provides an implementation =
of
+the values per entity method. This value is used to determine if an exist-
+ing <I>SequenceData</I> that has available entities is suitable for storin=
g a particular
+entity. For example, <I>UnstructuredElemSeq</I> returns the number of node=
s per el-
+ement from values per entity. When allocating a new element with a specific
+number of nodes, this value is used to determine if that element may be st=
ored
+in a specific <I>SequenceData</I>. For vertices, this value is always zero=
. This could
+be changed to the number of coordinates per vertex, allowing representatio=
n of
+mixed-dimension data. However, API changes would be required to utilize su=
ch
+a feature. Sequences for which the corresponding data cannot be used to st=
ore
+new entities (e.g. structured mesh discussed in a later section) will retu=
rn -1 or
+some other invalid value.
+
+ \ref dg-contents
+
+  \section manager 2. TypeSequenceManager & SequenceManager=20
+
+The <I>TypeSequenceManager</I> class maintains an organized set of <I>Enti=
tySequence</I>
+instances and corresponding <I>SequenceData</I> instances. It is used to m=
anage
+all such instances for entities of a single <I>EntityType</I>. <I>TypeSequ=
enceManager</I>
+enforces the following four rules on its contained data:
+
+-# No two <I>SequenceData</I> instances may overlap. =20
+-# No two <I>EntitySequence</I> instances may overlap.
+-# Every <I>EntitySequence</I> must be a subset of a <I>SequenceData</I>.
+-# Any pair of <I>EntitySequence</I> instances referencing the same <I>Seq=
uenceData</I> must be separated by at least one unallocated handle.
+.
+
+  \subsection figure2 Figure 2: SequenceManager and Related Classes
+
+The first three rules are required for the validity of the data model. The
+fourth rule avoids unnecessary inefficiency. It is implemented by merging =
such
+adjacent sequences. In some cases, other classes (e.g. <I>SequenceManager<=
/I>) can
+modify an <I>EntitySequence</I> such that the fourth rule is violated. In =
such cases,
+the <I>TypeSequenceManager::notify</I> prepended or <I>TypeSequenceManager=
::notify</I> appended
+method must be called to maintain the integrity of the data<sup>1</sup>. T=
he above rules
+(including the fourth) are assumed in many other methods of the <I>TypeSeq=
uenceManager</I>
+class, such that those methods will fail or behave unexpectedly if the man=
aged
+data does not conform to the rules.
+
+<I>TypeSequenceManager</I> contains three principal data structures. The f=
irst is
+a <I>std::set</I> of <I>EntitySequence</I> pointers sorted using a custom =
comparison op-
+erator that queries the start and end handles of the referenced sequences.=
 The
+comparison operation is defined as: <I>a->end_handle() < b->start_handle()=
</I>.
+This method of comparison has the advantage that a sequence corresponding =
to
+a specific handle can be located by searching the set for a =E2=80=9Cseque=
nce=E2=80=9D beginning
+and ending with the search value. The lower bound and find methods pro-
+vided by the library are guaranteed to return the sequence, if it exists. =
Using
+such a comparison operator will result in undefined behavior if the set co=
ntains
+overlapping sequences. This is acceptable, as rule two above prohibits such
+a configuration. However, some care must be taken in writing and modifying
+methods in <I>TypeSequenceManager</I> so as to avoid having overlapping se=
quences
+as a transitory state of some operation.
+
+The second important data member of <I>TypeSequenceManager</I> is a pointer
+to the last referenced <I>EntitySequence</I>. This =E2=80=9Ccached=E2=80=
=9D value is used to speed up
+searches by entity handle. This pointer is never null unless the sequence =
is empty.
+This rule is maintained to avoid unnecessary branches in fast query paths.=
 In
+cases where the last referenced sequence is deleted, <I>TypeSequenceManage=
r</I> will
+typically assign an arbitrary sequence (e.g. the first one) to the last re=
ferenced
+pointer.
+
+The third data member of <I>TypeSequenceManager</I> is a <I>std::set</I> o=
f <I>SequenceData</I>
+instances that are not completely covered by a <I>EntitySequence</I> insta=
nce<sup>2</sup>.
+This list is searched when allocating new handles. <I>TypeSequenceManager<=
/I> also
+embeds in each <I>SequenceData</I> instance a reference to the first corre=
sponding
+<I>EntitySequence</I> so that it may be located quickly from only the <I>S=
equenceData</I>
+pointer.
+
+The <I>SequenceManager</I> class contains an array of <I>TypeSequenceManag=
er</I> in-
+stances, one for each <I>EntityType</I>. It also provides all type-specifi=
c operations
+such as allocating the correct <I>EntitySequence</I> subtype for a given <=
I>EntityType</I>.
+
+<sup>1</sup>This source of potential error can be eliminated with changes =
to the entity set representation. This is discussed in a later section.
+
+<sup>2</sup>Given rule four for the data managed by a <I>TypeSequenceManag=
er</I>, any <I>SequenceData</I> for which all handles are allocated will be=
 referenced by exactly one <I>EntitySequence</I>.
+
+  \ref dg-contents
+
+ \section s-mesh 3. Structured Mesh
+
+Structured mesh storage is implemented using subclasses of <I>SequenceData=
</I>:
+<I>ScdElementData</I> and <I>ScdVertexData</I>. The <I>StructuredElementSe=
q</I> class is
+used to access the structured element connectivity. A standard <I>VertexSe=
quence</I>
+instance is used to access the ScdVertexData because the vertex data stora=
ge
+is the same as for unstructured mesh.
+
+  \ref dg-contents
+
+  \section sets 4. Entity Sets
+
+- MeshSetSequence
+
+The <I>MeshSetSequence</I> class is the same as most other subclasses of <=
I>EntitySequence</I>
+in that it utilizes SequenceData to store its data. A single array in the =
<I>SequenceData</I>
+is used to store instances of the MeshSet class, one per allocated <I>Enti=
tyHandle</I>.
+<I>SequenceData</I> allocates all of its managed arrays using malloc and f=
ree as
+simple arrays of bytes. <I>MeshSetSequence</I> does in-place construction =
and de-
+struction of <I>MeshSet</I> instances within that array. This is similar t=
o what is
+done by <I>std::vector</I> and other container classes that may own more s=
torage
+than is required at a given time for contained objects.
+
+- MeshSet
+
+  \subsection figure3 Figure 3: SequenceManager and Related Classes
+
+The <I>MeshSet</I> class is used to represent a single entity set instance=
 in MOAB.
+The class is optimized to minimize storage (further possible improvements =
in
+storage size are discussed later.)
+
+Figure 3 shows the memory layout of an instance of the <I>MeshSet</I> clas=
s.
+The flags member holds the set creation bit flags: <I>MESHSET_TRACK_OWNER<=
/I>,
+<I>MESHSET_SET</I>, and <I>MESHSET_ORDERED</I>. The presence of the <I>MES=
HSET_TRACK_OWNER</I>
+indicates that reverse links from the contained entities back to the ownin=
g set
+should be maintained in the adjacency list of each entity. The <I>MESHSET_=
SET</I>
+and <I>MESHSET_ORDERED</I> bits are mutually exclusive, and as such most c=
ode only
+tests for the <I>MESHSET_ORDERED</I>, meaning that in practice the <I>MESH=
SET_SET</I> bit is
+ignored. <I>MESHSET_ORDERED</I> indicates that the set may contain duplica=
te handles
+and that the order that the handles are added to the set should be preserv=
ed.
+In practice, such sets are stored as a simple list of handles. <I>MESHSET_=
SET</I> (or in
+practice, the lack of <I>MESHSET_ORDERED</I>) indicates that the order of =
the handles
+need not be preserved and that the set may not contain duplicate handles. =
Such
+sets are stored in a sorted range-compacted format similar to that of the =
Range
+class.
+
+The memory for storing contents, parents, and children are each handled in
+the same way. The data in the class is composed of a 2-bit =E2=80=98size=
=E2=80=99 field and two
+values, where the two values may either be two handles or two pointers. Th=
e size
+bit-fields are grouped together to reduce the required amount of memory. I=
f the
+numerical value of the 2-bit size field is 0 then the corresponding list i=
s empty.
+If the 2-bit size field is either 1 or 2, then the contents of the corresp=
onding list
+are stored directly in the corresponding two data fields of the MeshSet ob=
ject.
+If the 2-bit size field has a value of 3 (11 binary), then the correspondi=
ng two
+data fields store the begin and end pointers of an external array of handl=
es.
+The number of handles in the external array can be obtained by taking the
+difference of the start and end pointers. Note that unlike <I>std::vector<=
/I>, we
+do not store both an allocated and used size. We store only the =E2=80=98u=
sed=E2=80=99 size
+and call std::realloc whenever the used size is modified, thus we rely on =
the
+std::malloc implementation in the standard C library to track =E2=80=98all=
ocated=E2=80=99 size
+for us. In practice this performs well but does not return memory to the =
=E2=80=98system=E2=80=99
+when lists shrink (unless they shrink to zero). This overall scheme could =
exhibit
+poor performance if the size of one of the data lists in the set frequentl=
y changes
+between less than two and more than two handles, as this will result in fr=
equent
+releasing and re-allocating of the memory for the corresponding array.
+
+If the <I>MESHSET_ORDERED</I> flag is not present, then the set contents l=
ist (parent
+and child lists are unaffected) is stored in a range-compacted format. In =
this
+format the number of handles stored in the array is always a multiple of t=
wo.
+Each consecutive pair of handles indicate the start and end, inclusive, of=
 a range
+of handles contained in the set. All such handle range pairs are stored in=
 sorted
+order and do not overlap. Nor is the end handle of one range ever one less=
 than
+the start handle of the next. All such =E2=80=98adjacent=E2=80=99 range pa=
irs are merged into a
+single pair. The code for insertion and removal of handles from range-form=
atted
+set content lists is fairly complex. The implementation will guarantee tha=
t a
+given call to insert entities into a range or remove entities from a range=
 is never
+worse than O(ln n) + O(m + n), where =E2=80=98n=E2=80=99 is the number of =
handles to insert
+and =E2=80=98m=E2=80=99 is the number of handles already contained in the =
set. So it is generally
+much more efficient to build Ranges of handles to insert (and remove) and =
call
+MOAB to insert (or remove) the entire list at once rather than making may
+calls to insert (or remove) one or a few handles from the contents of a se=
t.
+The set storage could probably be further minimized by allowing up to six
+handles in one of the lists to be elided. That is, as there are six potent=
ial =E2=80=98slots=E2=80=99
+in the MeshSet object then if two of the lists are empty it should be poss=
ible to store up to six values of the remaining list directly in the MeshSe=
t object.
+However, the additional runtime cost of such complexity could easily outwe=
igh
+any storage advantage. Further investigation into this has not been done b=
ecause
+the primary motivation for the storage optimization was to support binary =
trees.
+
+Another possible optimization of storage would be to remove the <I>MeshSet=
</I>
+object entirely and instead store the data in a =E2=80=98blocked=E2=80=99 =
format. The corre-
+sponding <I>SequenceData</I> would contain four arrays: flags, parents, ch=
ildren, and
+contents instead of a single array of <I>MeshSet</I> objects. If this were=
 done then
+no storage need ever be allocated for parent or child links if none of the=
 sets
+in a <I>SequenceData</I> has parent or child links. The effectiveness of t=
he storage
+reduction would depend greatly on how sets get grouped into <I>SequenceDat=
as</I>.
+This alternate storage scheme might also allow for better cache utilizatio=
n as it
+would group like data together. It is often the case that application code=
 that
+is querying the contents of one set will query the contents of many but ne=
ver
+query the parents or children of any set. Or that an application will quer=
y only
+parent or child links of a set without every querying other set properties=
. The
+downside of this solution is that it makes the implementation a little les=
s mod-
+ular and maintainable because the existing logic contained in the <I>MeshS=
et</I> class
+would need to be spread throughout the <I>MeshSetSequence</I> class.
+
+  \ref dg-contents
+
+  \page dg-figures List of Figures
+
+  \ref figure1
+
+  \ref figure2
+
+  \ref figure3
+*/

diff --git a/doc/UG/moabUG.h b/doc/UG/moabUG.h
new file mode 100644
index 0000000..cea942d
--- /dev/null
+++ b/doc/UG/moabUG.h
@@ -0,0 +1,1064 @@
+/*! \page userguide User's Guide (MOAB 4.6)
+=20
+  \subpage team=20
+=20
+  \subpage contents
+=20
+  \subpage figures
+=20
+  \subpage tables
+=20
+  \subpage differences
+
+  \subpage building
+
+  \page team MOAB team members
+ <h2>The MOAB Team, including: </h2>
+=20
+ - Timothy J. Tautges (Argonne National Lab, Univ Wisconsin-Madison)=20
+ - Iulian Grindeanu (Argonne National Lab)=20
+ - Rajeev Jain (Argonne National Lab)
+ - Xiabing Xu (Argonne National Lab)
+
+
+ <h2>Emeritus members:</h2>
+=20
+ - Jason A. Kraftcheck
+ - Brandon M. Smith
+ - Hong-Jun Kim
+ - Jim Porter
+=20
+  \page contents Table of Contents
+=20
+  \ref introduction =20
+
+  \ref interface    =20
+
+     \ref twoone   =20
+
+     \ref twotwo    =20
+
+     \ref twothree      =20
+
+     \ref twofour  =20
+
+  \ref api    =20
+
+  \ref services     =20
+
+    \ref fourone   =20
+
+    \ref fourtwo  =20
+
+    \ref fourthree =20
+
+    \ref fourfour     =20
+
+    \ref fourfive   =20
+
+    \ref foursix =20
+
+  \ref parallel     =20
+
+    \ref fiveone   =20
+
+    \ref fivetwo    =20
+
+    \ref fivethree   =20
+
+    \ref fivefour     =20
+
+  \ref applications  =20
+
+  \ref implementation        =20
+
+  \ref representation    =20
+
+  \ref element   =20
+
+    \ref nineone =20
+
+    \ref ninetwo       =20
+
+    \ref ninethree     =20
+
+  \ref performance  =20
+
+  \ref conclusions   =20
+
+  \ref references=20
+
+  \section introduction 1. Introduction
+
+In scientific computing, systems of partial differential equations (PDEs) =
are solved on computers.  One of the most widely used methods to solve PDEs=
 numerically is to solve over discrete neighborhoods or =E2=80=9Celements=
=E2=80=9D of the domain.  Popular discretization methods include Finite Dif=
ference (FD), Finite Element (FE), and Finite Volume (FV).  These methods r=
equire the decomposition of the domain into a discretized representation, w=
hich is referred to as a =E2=80=9Cmesh=E2=80=9D.  The mesh is one of the fu=
ndamental types of data linking the various tools in the analysis process (=
mesh generation, analysis, visualization, etc.).  Thus, the representation =
of mesh data and operations on those data play a very important role in PDE=
-based simulations.
+=20
+MOAB is a component for representing and evaluating mesh data.  MOAB can s=
tore structured and unstructured mesh, consisting of elements in the finite=
 element =E2=80=9Czoo=E2=80=9D, along with polygons and polyhedra.  The fun=
ctional interface to MOAB is simple, consisting of only four fundamental da=
ta types.  This data is quite powerful, allowing the representation of most=
 types of metadata commonly found on the mesh.  Internally MOAB uses array-=
based storage for fine-grained data, which in many cases provides more effi=
cient access, especially for large portions of mesh and associated data.  M=
OAB is optimized for efficiency in space and time, based on access to mesh =
in chunks rather than through individual entities, while also versatile eno=
ugh to support individual entity access.
+
+The MOAB data model consists of the following four fundamental types: mesh=
 interface instance, mesh entities (vertex, edge, tri, etc.), sets, and tag=
s.  Entities are addressed through handles rather than pointers, to allow t=
he underlying representation of an entity to change without changing the ha=
ndle to that entity.  Sets are arbitrary groupings of mesh entities and oth=
er sets.  Sets also support parent/child relationships as a relation distin=
ct from sets containing other sets.  The directed graph provided by set par=
ent/child relationships is useful for embedding graphs whose nodes include =
collections of mesh entities; this approach has been used to represent a wi=
de variety of application-specific data, including geometric model topology=
, processor partitions, and various types of search trees.  Tags are named =
data which can be assigned to the mesh as a whole, individual entities, or =
sets.  Tags are a mechanism for attaching data to individual entities, and =
sets are a mechanism for describing relations between entities; the combina=
tion of these two mechanisms is a powerful yet simple interface for represe=
nting metadata or application-specific data.
+
+Various mesh-related tools are provided with MOAB or can be used directly =
with MOAB.  These tools can be used for mesh format translation (mbconvert)=
, mesh skinning (Skinner class), solution transfer between meshes (MBCouple=
r tool), ray tracing and other geometric searches (OrientedBoxTreeTool, Ada=
ptiveKDTree), visualization (vtkMOABReader tool), and relation between mesh=
 and geometric models (the separately-packed Lasso tool).  These tools are =
described later in this document.
+
+MOAB is written in the C++ programming language, with applications interac=
ting with MOAB mostly through its moab::Interface class.  All of the MOAB f=
unctions and classes are isolated in and accessed through the moab namespac=
e<sup>1</sup>. The remainder of this report gives class and function names =
without the =E2=80=9Cmoab::=E2=80=9D namespace qualification; unless otherw=
ise noted, the namespace qualifier should be added to all class and functio=
n names referenced here.  MOAB also implements the iMesh interface, which i=
s specified in C but can be called directly from other languages.  Almost a=
ll of the functionality in MOAB can be accessed through the iMesh interface=
.  MOAB is developed and supported on the Linux and MacOS operating systems=
, as well as various HPC operating systems.  MOAB can be used on parallel c=
omputing systems as well, including both clusters and high-end parallel sys=
tems like IBM BG/P and Cray systems.  MOAB is released under a standard LGP=
L open source software license.
+
+MOAB is used in several ways in various applications.  MOAB serves as the =
underlying mesh data representation in several scientific computing applica=
tions [1].  MOAB can also be used as a mesh format translator, using reader=
s and writers included in MOAB.  MOAB has also been used as a bridge to cou=
ple results in multi-physics analysis and to link these applications with o=
ther mesh services [2].
+
+The remainder of this report is organized as follows.  Section 2, =E2=80=
=9CGetting Started=E2=80=9D, provides a few simple examples of using MOAB t=
o perform simple tasks on a mesh.  Section 3 discusses the MOAB data model =
in more detail, including some aspects of the implementation.  Section 4 su=
mmarizes the MOAB function API.  Section 5 describes some of the tools incl=
uded with MOAB, and the implementation of mesh readers/writers for MOAB.  S=
ection 6 describes how to build MOAB-based applications.  Section 7 contain=
s a brief description of MOAB=E2=80=99s relation to the iMesh mesh interfac=
e.  Sections 8 and 9 discuss MOAB's representations of structured and spect=
ral element meshes, respectively.  Section 10 gives helpful hints for acces=
sing MOAB in an efficient manner from applications.  Section 11 gives a con=
clusion and future plans for MOAB development.  Section 12 gives references=
 cited in this report.
+
+Several other sources of information about MOAB may also be of interest to=
 readers.  Meta-data conventions define how sets and /or tags are used toge=
ther to represent various commonly-used simulation constructs; conventions =
used by MOAB are described in Ref [4], which is also included in the MOAB s=
ource distribution.  This document is maintained separately from this docum=
ent, since it is expected to change over time.  The MOAB project maintains =
a wiki [5], which links to most MOAB-related information.  MOAB also uses s=
everal mailing lists [6],[7] for MOAB-related discussions.  Potential users=
 are encouraged to interact with the MOAB team using these mailing lists.
+
+<sup>1</sup> Non-namespaced names are also provided for backward compatibi=
lity, with the =E2=80=9CMB=E2=80=9D prefix added to the class or variable n=
ame.
+
+ \ref contents
+
+ \section interface 2. MOAB Data Model
+The MOAB data model describes the basic types used in MOAB and the languag=
e used to communicate that data to applications.  This chapter describes th=
at data model, along with some of the reasons for some of the design choice=
s in MOAB.
+
+ \ref contents
+
+ \subsection twoone 2.1. MOAB Interface
+MOAB is written in C++.  The primary interface with applications is throug=
h member functions of the abstract base class Interface.  The MOAB library =
is created by instantiating Core, which implements the Interface API.  Mult=
iple instances of MOAB can exist concurrently in the same application; mesh=
 entities are not shared between these instancesi<sup>2</sup>.  MOAB is mos=
t easily viewed as a database of mesh objects accessed through the instance=
.  No other assumptions explicitly made about the nature of the mesh stored=
 there; for example, there is no fundamental requirement that elements fill=
 space or do not overlap each other geometrically.
+=20
+<sup>2</sup> One exception to this statement is when the parallel interfac=
e to MOAB is used; in this case, entity sharing between instances is handle=
d explicitly using message passing.  This is described in more detail in Se=
ction 5 of this document.
+
+ \ref contents
+
+ \subsection twotwo 2.2. Mesh Entities
+MOAB represents the following topological mesh entities: vertex, edge, tri=
angle, quadrilateral, polygon, tetrahedron, pyramid, prism, knife, hexahedr=
on, polyhedron.  MOAB uses the EntityType enumeration to refer to these ent=
ity types (see Table 1).  This enumeration has several special characterist=
ics, chosen intentionally: the types begin with vertex, entity types are gr=
ouped by topological dimension, with lower-dimensional entities appearing b=
efore higher dimensions; the enumeration includes an entity type for sets (=
described in the next section); and MBMAXTYPE is included at the end of thi=
s enumeration, and can be used to terminate loops over type.  In addition t=
o these defined values, the an increment operator (++) is defined such that=
 variables of type EntityType can be used as iterators in loops.
+MOAB refers to entities using =E2=80=9Chandles=E2=80=9D.  Handles are impl=
emented as long integer data types, with the four highest-order bits used t=
o store the entity type (mesh vertex, edge, tri, etc.) and the remaining bi=
ts storing the entity id.  This scheme is convenient for applications becau=
se:
+- Handles sort lexicographically by type and dimension; this can be useful=
 for grouping and iterating over entities by type.
+- The type of an entity is indicated by the handle itself, without needing=
 to call a function.
+- Entities allocated in sequence will typically have contiguous handles; t=
his characteristic can be used to efficiently store and operate on large li=
sts of handles.
+.
+
+This handle implementation is exposed to applications intentionally, becau=
se of optimizations that it enables, and is unlikely to change in future ve=
rsions.
+
+  \subsection tableone Table 1: Values defined for the EntityType enumerat=
ed type.
+<table border=3D"1">
+<tr>
+<td>MBVERTEX =3D 0</td>
+<td>MBPRISM</td>
+</tr>
+<tr>
+<td>MBEDGE</td>
+<td>MBKNIFE</td>
+</tr>
+<tr>
+<td>MBTRI</td>
+<td>MBHEX</td>
+</tr>
+<tr>
+<td>MBQUAD</td>
+<td>MBPOLYHEDRON</td>
+</tr>
+<tr>
+<td>MBPOLYGON</td>
+<td>MBENTITYSET</td>
+</tr>
+<tr>
+<td>MBTET</td>
+<td>MBMAXTYPE</td>
+</tr>
+<tr>
+<td>MBPYRAMID</td>
+<td></td>
+</tr>
+</table>
+
+MOAB defines a special class for storing lists of entity handles, named Ra=
nge.  This class stores handles as a series of (start_handle, end_handle) s=
ubrange tuples.  If a list of handles has large contiguous ranges, it can b=
e represented in almost constant size using Range.  Since entities are typi=
cally created in groups, e.g. during mesh generation or file import, a high=
 degree of contiguity in handle space is typical.  Range provides an interf=
ace similar to C++ STL containers like std::vector, containing iterator dat=
a types and functions for initializing and iterating over entity handles st=
ored in the range.  Range also provides functions for efficient Boolean ope=
rations like subtraction and intersection.  Most API functions in MOAB come=
 in both range-based and vector-based variants.  By definition, a list of e=
ntities stored in an Range is always sorted, and can contain a given entity=
 handle only once.  Range cannot store the handle 0 (zero).
+
+Typical usage of an Range object would look like:
+
+\code
+using namespace moab;
+   int my_function(Range &from_range) {
+          int num_in_range =3D from_range.size();
+          Range to_range;
+          Range::iterator rit;
+    for (rit =3D from_range.begin(); rit !=3D from_range.end(); rit++) {
+            EntityHandle this_ent =3D *rit;
+            to_range.insert(this_ent);
+          }
+        }
+\endcode
+
+Here, the range is iterated similar to how std::vector is iterated.
+
+  \ref contents
+
+ \subsection adjacencies 2.2.1. Adjacencies & AEntities=20
+
+The term adjacencies is used to refer to those entities topologically conn=
ected to a given entity, e.g. the faces bounded by a given edge or the vert=
ices bounding a given region.  The same term is used for both higher-dimens=
ional (or bounded) and lower-dimensional (or bounding) adjacent entities.  =
MOAB provides functions for querying adjacent entities by target dimension,=
 using the same functions for higher- and lower-dimension adjacencies.  By =
default, MOAB stores the minimum data necessary to recover adjacencies betw=
een entities.  When a mesh is initially loaded into MOAB, only entity-verte=
x (i.e. =E2=80=9Cdownward=E2=80=9D) adjacencies are stored, in the form of =
entity connectivity.  When =E2=80=9Cupward=E2=80=9D adjacencies are request=
ed for the first time, e.g. from vertices to regions, MOAB stores all verte=
x-entity adjacencies explicitly, for all entities in the mesh.  Non-vertex =
entity to entity adjacencies are never stored, unless explicitly requested =
by the application.
+
+In its most fundamental form, a mesh need only be represented by its verti=
ces and the entities of maximal topological dimension.  For example, a hexa=
hedral mesh can be represented as the connectivity of the hex elements and =
the vertices forming the hexes.  Edges and faces in a 3D mesh need not be e=
xplicitly represented.  We refer to such entities as =E2=80=9CAEntities=E2=
=80=9D, where =E2=80=98A=E2=80=99 refers to =E2=80=9CAuxiliary=E2=80=9D, =
=E2=80=9CAncillary=E2=80=9D, and a number of other words mostly beginning w=
ith =E2=80=98A=E2=80=99.  Individual AEntities are created only when reques=
ted by applications, either using mesh modification functions or by request=
ing adjacencies with a special =E2=80=9Ccreate if missing=E2=80=9D flag pas=
sed as =E2=80=9Ctrue=E2=80=9D.  This reduces the overall memory usage when =
representing large meshes.  Note entities must be explicitly represented be=
fore they can be assigned tag values or added to entity sets (described in =
following Sections).
+
+\ref contents
+
+ \subsection twothree 2.3. Entity Sets
+Entity sets are used to store arbitrary collections of entities and other =
sets.  Sets are used for a variety of things in mesh-based applications, fr=
om the set of entities discretizing a given geometric model entity to the e=
ntities partitioned to a specific processor in a parallel finite element ap=
plication.  MOAB entity sets can also store parent/child relations with oth=
er entity sets, with these relations distinct from contains relations.  Par=
ent/child relations are useful for building directed graphs with graph node=
s representing collections of mesh entities; this construct can be used, fo=
r example, to represent an interface of mesh faces shared by two distinct c=
ollections of mesh regions.  MOAB also defines one special set, the =E2=80=
=9Croot set=E2=80=9D or the interface itself; all entities are part of this=
 set by definition.  Defining a root set allows the use of a single set of =
MOAB API functions to query entities in the overall mesh as well as its sub=
sets.
+
+MOAB entity sets can be one of two distinct types: list-type entity sets p=
reserve the order in which entities are added to the set, and can store a g=
iven entity handle multiple times in the same set; set-type sets are always=
 ordered by handle, regardless of the order of addition to the set, and can=
 store a given entity handle only once.  This characteristic is assigned wh=
en the set is created, and cannot be changed during the set=E2=80=99s lifet=
ime.
+
+MOAB provides the option to track or not track entities in a set.  When en=
tities (and sets) are deleted by other operations in MOAB, they will also b=
e removed from containing sets for which tracking has been enabled.  This b=
ehavior is assigned when the set is created, and cannot be changed during t=
he set=E2=80=99s lifetime.  The cost of turning tracking on for a given set=
 is sizeof(EntityHandle) for each entity added to the set; MOAB stores cont=
aining sets in the same list which stores adjacencies to other entities.
+
+Using an entity set looks like the following:
+\code
+using namespace moab;
+// load a file using MOAB, putting the loaded mesh into a file set
+EntityHandle file_set;
+ErrorCode rval =3D moab->create_meshset(MESHSET_SET, file_set);
+rval =3D moab->load_file(=E2=80=9Cfname.vtk=E2=80=9D, &file_set);
+Range set_ents;
+// get all the 3D entities in the set
+rval =3D moab->get_entities_by_dimension(file_set, 3, set_ents);
+\endcode
+
+Entity sets are often used in conjunction with tags (described in the next=
 section), and provide a powerful mechanism to store a variety of meta-data=
 with meshes.
+
+\ref contents
+
+ \subsection twofour 2.4. Tags=20
+
+Applications of a mesh database often need to attach data to mesh entities=
.  The types of attached data are often not known at compile time, and can =
vary across individual entities and entity types.  MOAB refers to this atta=
ched data as a =E2=80=9Ctag=E2=80=9D.  Tags can be thought of loosely as a =
variable, which can be given a distinct value for individual entities, enti=
ty sets, or for the interface itself.  A tag is referenced using a handle, =
similarly to how entities are referenced in MOAB.  Each MOAB tag has the fo=
llowing characteristics, which can be queried through the MOAB interface:
+- Name
+- Size (in bytes)
+- Storage type
+- Data type (integer, double, opaque, entity handle)
+- Handle
+.
+
+The storage type determines how tag values are stored on entities. =20
+
+- Dense: Dense tag values are stored in arrays which match arrays of conti=
guous entity handles.  Dense tags are more efficient in both storage and me=
mory if large numbers of entities are assigned the same tag.  Storage for a=
 given dense tag is not allocated until a tag value is set on an entity; me=
mory for a given dense tag is allocated for all entities in a given sequenc=
e at the same time.
+- Sparse: Sparse tags are stored as a list of (entity handle, tag value) t=
uples, one list per sparse tag, sorted by entity handle.
+- Bit: Bit tags are stored similarly to dense tags, but with special handl=
ing to allow allocation in bit-size amounts per entity.
+.
+
+MOAB also supports variable-length tags, which can have a different length=
 for each entity they are assigned to.  Variable length tags are stored sim=
ilarly to sparse tags.
+
+The data type of a tag can either be one understood at compile time (integ=
er, double, entity handle), in which case the tag value can be saved and re=
stored properly to/from files and between computers of different architectu=
re (MOAB provides a native HDF5-based save/restore format for this purpose;=
 see Section 4.6).  The opaque data type is used for character strings, or =
for allocating =E2=80=9Craw memory=E2=80=9D for use by applications (e.g. f=
or storage application-defined structures or other abstract data types).  T=
hese tags are saved and restored as raw memory, with no special handling fo=
r endian or precision differences.
+
+An application would use the following code to attach a double-precision t=
ag to vertices in a mesh, e.g. to assign a temperature field to those verti=
ces:
+
+\code
+using namespace moab;
+// load a file using MOAB and get the vertices
+ErrorCode rval =3D moab->load_file(=E2=80=9Cfname.vtk=E2=80=9D);
+Range verts;
+rval =3D moab->get_entities_by_dimension(0, 0, verts);
+// create a tag called =E2=80=9CTEMPERATURE=E2=80=9D
+Tag temperature;
+double def_val =3D -1.0d-300, new_val =3D 273.0;
+rval =3D moab->tag_create(=E2=80=9CTEMPERATURE=E2=80=9D, sizeof(double), M=
B_TAG_DENSE,=20
+                        MB_TYPE_DOUBLE, temperature, &def_val);
+// assign a value to vertices
+for (Range::iterator vit =3D verts.begin();=20
+     vit !=3D verts.end(); vit++)=20
+  rval =3D moab->tag_set_data(temperature, &(*rit), 1, &new_val);
+
+\endcode
+
+The semantic meaning of a tag is determined by applications using it.  How=
ever, to promote interoperability between applications, there are a number =
of tag names reserved by MOAB which are intended to be used by convention. =
 Mesh readers and writers in MOAB use these tag conventions, and applicatio=
ns can use them as well to access the same data. Ref. [4] maintains an up-t=
o-date list of conventions for meta-data usage in MOAB.
+
+  \ref contents
+
+  \section api 3. MOAB API Design Philosophy and Summary
+
+This section describes the design philosophy behind MOAB, and summarizes t=
he functions, data types and enumerated variables in the MOAB API.  A compl=
ete description of the MOAB API is available in online documentation in the=
 MOAB distribution [8].
+
+MOAB is designed to operate efficiently on collections of entities.  Entit=
ies are often created or referenced in groups (e.g. the mesh faces discreti=
zing a given geometric face, the 3D elements read from a file), with those =
groups having some form of temporal or spatial locality.  The interface pro=
vides special mechanisms for reading data directly into the native storage =
used in MOAB, and for writing large collections of entities directly from t=
hat storage, to avoid data copies.  MOAB applications structured to take ad=
vantage of that locality will typically operate more efficiently.
+
+MOAB has been designed to maximize the flexibility of mesh data which can =
be represented.  There is no explicit constraint on the geometric structure=
 of meshes represented in MOAB, or on the connectivity between elements.  I=
n particular, MOAB allows the representation of multiple entities with the =
same exact connectivity; however, in these cases, explicit adjacencies must=
 be used to distinguish adjacencies with AEntities bounding such entities.
+
+The number of vertices used to represent a given topological entity can va=
ry, depending on analysis needs; this is often the case in FEA.  For exampl=
e, applications often use =E2=80=9Cquadratic=E2=80=9D or 10-vertex tetrahed=
ral, with vertices at edge midpoints as well as corners.  MOAB does not dis=
tinguish these variants by entity type, referring to all variants as =E2=80=
=9Ctetrahedra=E2=80=9D.  The number of vertices for a given entity is used =
to distinguish the variants, with canonical numbering conventions used to d=
etermine placement of the vertices [9].  This is similar to how such variat=
ions are represented in the Exodus [10] and Patran [11] file formats.  In p=
ractice, we find that this simplifies coding in applications, since in many=
 cases the handling of entities depends only on the number of corner vertic=
es in the element.  Some MOAB API functions provide a flag which determines=
 whether corner or all vertices are requested.
+
+The MOAB API is designed to balance complexity and ease of use.  This bala=
nce is evident in the following general design characteristics:
+
+- Entity lists: Lists of entities are passed to and from MOAB in a variety=
 of forms.  Lists output from MOAB are passed as either STL vector or Range=
 data types.  Either of these constructs may be more efficient in both time=
 and memory, depending on the semantics of the data being requested.  Input=
 lists are passed as either Range=E2=80=99s, or as a pointer to EntityHandl=
e and a size.  The latter allows the same function to be used when passing =
individual entities, without requiring construction of an otherwise unneede=
d STL vector.
+- Entity sets: Most query functions accept an entity set as input.  Applic=
ations can pass zero to indicate a request for the whole interface.  Note t=
hat this convention applies only to query functions; attempts to add or sub=
tract entities to/from the interface using set-based modification functions=
, or to add parents or children to the interface set, will fail.  Allowing =
specification of the interface set in this manner avoids the need for a sep=
arate set of API functions to query the database as a whole.
+- Implicit Booleans in output lists: A number of query functions in MOAB a=
llow specification of a Boolean operation (Interface::INTERSECT or Interfac=
e::UNION).  This operation is applied to the results of the query, often el=
iminating the need for code the application would need to otherwise impleme=
nt.  For example, to find the set of vertices shared by a collection of qua=
drilaterals, the application would pass that list of quadrilaterals to a re=
quest for vertex adjacencies, with Interface::INTERSECT passed for the Bool=
ean flag.  The list of vertices returned would be the same as if the applic=
ation called that function for each individual entity, and computed the int=
ersection of the results over all the quadrilaterals.  Applications may als=
o input non-empty lists to store the results, in which case the intersectio=
n is also performed with entities already in the list.  In many cases, this=
 allows optimizations in both time and memory inside the MOAB implementatio=
n.=20
+.
+
+Since these objectives are at odds with each other, tradeoffs had to be ma=
de between them.  Some specific issues that came up are:
+
+- Using ranges: Where possible, entities can be referenced using either ra=
nges (which allow efficient storage of long lists) or STL vectors (which al=
low list order to be preserved), in both input and output arguments.
+- Entities in sets: Accessing the entities in a set is done using the same=
 functions which access entities in the entire mesh.  The whole mesh is ref=
erenced by specifying a set handle of zero<sup>3</sup>.
+- Entity vectors on input: Functions which could normally take a single en=
tity as input are specified to take a vector of handles instead.  Single en=
tities are specified by taking the address of that entity handle and specif=
ying a list length of one.  This minimizes the number of functions, while p=
reserving the ability to input single entities.<sup>4</sup>
+.
+
+Table 2 lists basic data types and enumerated variables defined and used b=
y MOAB.  Values of the ErrorCode enumeration are returned from most MOAB fu=
nctions, and can be compared to those listed in Appendix [ref-appendix].
+
+MOAB uses several pre-defined tag names to define data commonly found in v=
arious mesh-based analyses.  Ref. [4] describes these meta-data conventions=
 in more detail.  These conventions will be added to as new conventions eme=
rge for using sets and tags in MOAB applications.
+
+  \subsection tabletwo Table 2: Basic data types and enums defined in MOAB.
+
+<table border=3D"1">
+<tr>
+<th>Enum / Type</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>ErrorCode</td>
+<td>Specific error codes returned from MOAB</td>
+</tr>
+<tr>
+<td>EntityHandle</td>
+<td>Type used to represent entity handles</td>
+</tr>
+<tr>
+<td>Tag</td>
+<td>Type used to represent tag handles</td>
+</tr>
+<tr>
+<td>TagType</td>
+<td>Type used to represent tag storage type</td>
+</tr>
+<tr>
+<td>DataType</td>
+<td>Type used to represent tag data type</td>
+</tr>
+</table>
+
+Table 3 lists the various groups of functions that comprise the MOAB API. =
 This is listed here strictly as a reference to the various types of functi=
onality supported by MOAB; for a more detailed description of the scope and=
 syntax of the MOAB API, see the online documentation [8].
+
+  \subsection tablethree Table 3: Groups of functions in MOAB API.  See Re=
f. [8] for more details.
+
+<table border=3D"1">
+<tr>
+<th>Function group</th>
+<th>Examples</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>Constructor, destructor, interface</td>
+<td>Interface, ~Core, query_interface</td>
+<td>Construct/destroy interface; get pointer to read/write interface</td>
+</tr>
+<tr>
+<td>Entity query</td>
+<td>get_entities_by_dimension, get_entities_by_handle</td>
+<td>Get entities by dimension, type, etc.</td>
+</tr>
+<tr>
+<td>Adjacencies</td>
+<td>get_adjacencies, set_adjacencies, add_adjacencies</td>
+<td>Get topologically adjacent entities; set or add explicit adjacencies</=
td>
+</tr>
+<tr>
+<td>Vertex coordinates</td>
+<td>get_coords, set_coords</td>
+<td>Get/set vertex coordinates</td>
+</tr>
+<tr>
+<td>Connectivity</td>
+<td>get_connectivity, set_connectivity</td>
+<td>Get/set connectivity of non-vertex entities</td>
+</tr>
+<tr>
+<td>Sets</td>
+<td>create_meshset, add_entities, add_parent_child</td>
+<td>Create and work with entity sets</td>
+</tr>
+<tr>
+<td>Tags</td>
+<td>tag_get_data, tag_create</td>
+<td>Create, read, write tag data</td>
+</tr>
+<tr>
+<td>Handles</td>
+<td>type_from_handle, id_from_handle</td>
+<td>Go between handles and types/ids</td>
+</tr>
+<tr>
+<td>File handling</td>
+<td>load_mesh, save_mesh</td>
+<td>Read/write mesh files</td>
+</tr>
+<tr>
+<td>Geometric dimension</td>
+<td>get_dimension, set_dimension</td>
+<td>Get/set geometric dimension of mesh</td>
+</tr>
+<tr>
+<td>Mesh modification</td>
+<td>create_vertex, delete_entity</td>
+<td>Create or delete mesh entities</td>
+</tr>
+<tr>
+<td>Information</td>
+<td>list_entities, get_last_error</td>
+<td>Get or print certain information</td>
+</tr>
+<tr>
+<td>High-order nodes</td>
+<td>high_order_node</td>
+<td>Get information on high-order nodes</td>
+</tr>
+<tr>
+<td>Canonical numbering</td>
+<td>side_number</td>
+<td>Get canonical numbering information</td>
+</tr>
+</table>
+
+<sup>3</sup>In iMesh, the whole mesh is specified by a special entity set =
handle, referred to as the =E2=80=9Croot set=E2=80=9D.
+
+<sup>4</sup>Note that STL vectors of entity handles can be input in this m=
anner by using &vector[0] and vector.size() for the 1d vector address and s=
ize, respectively.
+
+ \ref contents
+
+ \section services 4. Related Mesh Services
+
+A number of mesh-based services are often used in conjunction with a mesh =
library.  For example, parallel applications often need to visualize the me=
sh and associated data.  Other services, like spatial interpolation or find=
ing the faces on the =E2=80=9Cskin=E2=80=9D of a 3D mesh, can be implemente=
d more efficiently using knowledge of specific data structures in MOAB.  Se=
veral of these services provided with MOAB are described in this chapter.
+
+ \ref contents
+
+  \subsection fourone 4.1. Visualization
+
+Visualization is one of the most common needs associated with meshes.  The=
 primary tool used to visualize MOAB meshes is VisIt [12].  Users can speci=
fy that VisIt read mesh directly out of the MOAB instance, by specifying th=
e ITAPS-MOABC mesh format and a file readable by MOAB (see xxx).
+
+There are some initial capabilities in VisIt for limited viewing and manip=
ulation of tag data and some types of entity sets.  Tag data is visualized =
using the same mechanisms used to view other field data in VisIt, e.g. usin=
g a pseudocolor plot; sets are viewed using VisIt=E2=80=99s SIL window, acc=
essed by selecting the SIL icon in the data selection window.  xxx shows a =
vertex-based radiation temperature field computed by the Cooper rad-hydro c=
ode [1] for a subset of geometric volumes in a mesh.  =20
+
+Reorganization of VisIt=E2=80=99s set handling is also underway, to increa=
se versatility and flexibility of this important mechanism.
+
+ \ref contents
+
+  \subsection fourtwo 4.2. Parallel Decomposition
+
+To support parallel simulation, applications often need to partition a mes=
h into parts, designed to balance the load and minimize communication betwe=
en sets.  MOAB includes the MBZoltan tool for this purpose, constructed on =
the well-known Zoltan partitioning library [13].  After computing the parti=
tion using Zoltan, MBZoltan stores the partition as either tags on individu=
al entities in the partition, or as tagged sets, one set per part.  Since a=
 partition often exhibits locality similar to how the entities were created=
, storing it as sets (based on Range=E2=80=99s) is often more memory-effici=
ent than an entity tag-based representation.  Xxx shows a partition compute=
d with MBZoltan (and visualized in VisIt).=20
+
+ \ref contents
+
+  \subsection fourthree 4.3. Skinner
+
+An operation commonly applied to mesh is to compute the outermost =E2=80=
=9Cskin=E2=80=9D bounding a contiguous block of elements.  This skin consis=
ts of elements of one fewer topological dimension, arranged in one or more =
topological balls on the boundary of the elements.  The Skinner tool comput=
es the skin of a mesh in a memory-efficient manner.  Skinner uses knowledge=
 about whether vertex-entity adjacencies and AEntities exist to minimize me=
mory requirements and searching time required during the skinning process. =
 This skin can be provided as a single collection of entities, or as sets o=
f entities distinguished by forward and reverse orientation with respect to=
 higher-dimensional entities in the set being skinned.
+
+The following code fragment shows how Skinner can be used to compute the s=
kin of a range of hex elements:
+
+ \code
+using namespace moab;
+Range hexes, faces;
+ErrorCode rval =3D moab->get_entities_by_dimension(0, 3, hexes);
+Skinner myskinner(moab);
+bool verts_too =3D false;
+ErrorCode rval =3D myskinner.find_skin(hexes, verts_too, faces);
+\endcode
+
+Skinner can also skin a mesh based on geometric topology groupings importe=
d with the mesh.  The geometric topology groupings contain information abou=
t the mesh =E2=80=9Cowned=E2=80=9D by each of the entities in the geometric=
 model, e.g. the model vertices, edges, etc.  Links between the mesh sets c=
orresponding to those entities can be inferred directly from the mesh.  Ski=
nning a mesh this way will typically be much faster than doing so on the ac=
tual mesh elements, because there is no need to create and destroy interior=
 faces on the mesh.
+
+ \ref contents
+
+  \subsection fourfour 4.4. Tree Decompositions
+
+MOAB provides several mechanisms for spatial decomposition and searching i=
n a mesh:
+
+- AdaptiveKDTree: Adaptive KD tree, a space-filling decomposition with axi=
s-aligned splitting planes, enabling fast searching.
+- BSPTree: Binary Space Partition tree, with non-axis-aligned partitions, =
for fast spatial searches with slightly better memory efficiency than KD tr=
ees.
+- OrientedBoxTreeTool: Oriented Bounding Box tree hierarchy, useful for fa=
st ray-tracing on collections of mesh facets.
+.
+
+These trees have various space and time searching efficiencies.  All are i=
mplemented based on entity sets and parent/child relations between those se=
ts, allowing storage of a tree decomposition using MOAB=E2=80=99s native fi=
le storage mechanism (see Section 4.6.1).  MOAB=E2=80=99s entity set implem=
entation is specialized for memory efficiency when representing binary tree=
s.  Tree decompositions in MOAB have been used to implement fast ray tracin=
g to support radiation transport [14], solution coupling between meshes [2]=
, and embedded boundary mesh generation [15].  MOAB also includes the DAGMC=
 tool, supporting Monte Carlo radiation transport.
+
+The following code fragment shows very basic use of AdaptiveKDTree.  A ran=
ge of entities is put in the tree; the leaf containing a given point is fou=
nd, and the entities in that leaf are returned.
+\code
+using namespace moab;
+// create the adaptive kd tree from a range of tets
+EntityHandle tree_root
+AdaptiveKDTree myTree(moab);
+ErrorCode rval =3D myTree.build_tree(tets, tree_root);
+
+// get the overall bounding box corners
+double boxmax[3], boxmin;
+rval =3D myTree.get_tree_box(tree_root, boxmax, boxmin);
+
+// get the tree leaf containing point xyz, and the tets in that leaf
+AdaptiveKDTreeIter treeiter;
+rval =3D myTree.leaf_containing_point(tree_root, xyz, treeiter);
+Range leaf_tets;
+rval =3D moab->get_entities_by_dimension(treeiter.handle(), 3,=20
+                                       leaf_tets, false);
+\endcode
+
+More detailed examples of using the various tree decompositions in MOAB ca=
n be found in [ref-treeexamples].
+
+ \ref contents
+
+  \subsection fourfive 4.5. File Reader/Writer Interfaces
+
+Mesh readers and writers communicate mesh into/out of MOAB from/to disk fi=
les.  Reading a mesh often involves importing large sets of data, for examp=
le coordinates of all the nodes in the mesh.  Normally, this process would =
involve reading data from the file into a temporary data buffer, then copyi=
ng data from there into its destination in MOAB.  To avoid the expense of c=
opying data, MOAB has implemented a reader/writer interface that provides d=
irect access to blocks of memory used to represent mesh.
+
+The reader interface, declared in ReadUtilIface, is used to request blocks=
 of memory for storing coordinate positions and element connectivity.  The =
pointers returned from these functions point to the actual memory used to r=
epresent those data in MOAB.  Once data is written to that memory, no furth=
er copying is done.  This not only saves time, but it also eliminates the n=
eed to allocate a large memory buffer for intermediate storage of these dat=
a.=20
+
+MOAB allocates memory for nodes and elements (and their corresponding dens=
e tags) in chunks, to avoid frequent allocation/de-allocation of small chun=
ks of memory.  The chunk size used depends on from where the mesh is being =
created, and can strongly affect the performance (and memory layout) of MOA=
B.  Since dense tags are allocated at the chunk size, this can also affect =
overall memory usage in cases where the mesh size is small but the number o=
f dense tags or dense tag size is large.  When creating vertices and elemen=
ts through the normal MOAB API, default chunk sizes defined in the Sequence=
Manager class are used.  However, most of the file readers in MOAB allocate=
 the exact amount of space necessary to represent the mesh being read.  The=
re are also a few exceptions to this:
+
+- When compiled in parallel, this space is increased by a factor of 1.5, t=
o allow subsequent creation of ghost vertices/elements in the same chunk as=
 the original mesh.
+- The .cub file reader, which creates nodes and elements for individual ge=
ometric entities in separate calls, allocates using the default vertex/elem=
ent sequence sizes, which are defined in the SequenceManager class in MOAB.
+.
+
+Applications calling the reader interface functions directly can specify t=
he allocation chunk size as an optional parameter.
+
+The reader interface consists of the following functions:
+
+- get_node_arrays: Given the number of vertices requested, the number of g=
eometric dimensions, and a requested start id, allocates a block of vertex =
handles and returns pointers to coordinate arrays in memory, along with the=
 actual start handle for that block of vertices.
+- get_element_array: Given the number of elements requested, the number of=
 vertices per element, the element type and the requested start id, allocat=
es the block of elements, and returns a pointer to the connectivity array f=
or those elements and the actual start handle for that block.  The number o=
f vertices per element is necessary because those elements may include high=
er-order nodes, and MOAB stores these as part of the normal connectivity ar=
ray.
+- update_adjacencies: This function takes the start handle for a block of =
elements and the connectivity of those elements, and updates adjacencies fo=
r those elements.  Which adjacencies are updated depends on the options set=
 in AEntityFactory.
+.
+
+The following code fragment illustrates the use of ReadUtilIface to read a=
 mesh directly into MOAB=E2=80=99s native representation.  This code assume=
s that connectivity is specified in terms of vertex indices, with vertex in=
dices starting from 1.
+
+\code
+// get the read iface from moab
+ReadUtilIface *iface;
+ErrorCode rval =3D moab->get_interface("ReadUtilIface", &iface);
+
+// allocate a block of vertex handles and read xyz=E2=80=99s into them
+std::vector<double*> arrays;
+EntityHandle startv, *starth;
+rval =3D iface->get_node_arrays(3, num_nodes, 0, startv, arrays);
+for (int i =3D 0; i < num_nodes; i++)
+  infile >> arrays[0][i] >> arrays[1][i] >> arrays[2][i];
+
+// allocate block of hex handles and read connectivity into them
+rval =3D iface->get_element_array(num_hexes, 8, MBHEX, 0, starth);
+for (int i =3D 0; i < 8*num_hexes; i++)
+  infile >> starth[i];
+
+// change connectivity indices to vertex handles
+for (int i =3D 0; i < 8*num_hexes; i++)
+  starth[i] +=3D startv-1;
+\endcode
+
+The writer interface, declared in WriteUtilIface, provides functions that =
support writing vertex coordinates and element connectivity to storage loca=
tions input by the application.  Assembling these data is a common task for=
 writing mesh, and can be non-trivial when exporting only subsets of a mesh=
.  The writer interface declares the following functions:
+
+- get_node_arrays: Given already-allocated memory and the number of vertic=
es and dimensions, and a range of vertices, this function writes vertex coo=
rdinates to that memory.  If a tag is input, that tag is also written with =
integer vertex ids, starting with 1, corresponding to the order the vertice=
s appear in that sequence (these ids are used to write the connectivity arr=
ay in the form of vertex indices).
+- get_element_array: Given a range of elements and the tag holding vertex =
ids, and a pointer to memory, the connectivity of the specified elements ar=
e written to that memory, in terms of the indices referenced by the specifi=
ed tag.  Again, the number of vertices per element is input, to allow the d=
irect output of higher-order vertices.
+- gather_nodes_from_elements: Given a range of elements, this function ret=
urns the range of vertices used by those elements.  If a bit-type tag is in=
put, vertices returned are also marked with 0x1 using that tag.  If no tag =
is input, the implementation of this function uses its own bit tag for mark=
ing, to avoid using an n2 algorithm for gathering vertices.
+- reorder: Given a permutation vector, this function reorders the connecti=
vity for entities with specified type and number of vertices per entity to =
match that permutation.  This function is needed for writing connectivity i=
nto numbering systems other than that used internally in MOAB.
+.
+
+The following code fragment shows how to use WriteUtilIface to write the v=
ertex coordinates and connectivity indices for a subset of entities.
+
+\code
+using namespace moab;
+// get the write iface from moab
+WriteUtilIface *iface;
+ErrorCode rval =3D moab->get_interface("WriteUtilIface", &iface);
+
+// get all hexes the model, and choose the first 10 of those
+Range tmp_hexes, hexes, verts;
+rval =3D moab->get_entities_by_type(0, MBHEX, tmp_hexes);
+for (int i =3D 0; i < 10; i++) hexes.insert(tmp_hexes[i]);
+rval =3D iface->gather_nodes_from_elements(hexes, 0, verts);
+
+// assign vertex ids
+iface->assign_ids(verts, 0, 1);
+
+// allocate space for coordinates & write them
+std::vector<double*> arrays(3);
+for (int i =3D 0; i < 3; i++) arrays[i] =3D new double[verts.size()];
+iface->get_node_arrays(3, verts.size(), verts, 0, 1, arrays);
+
+// put connect=E2=80=99y in array, in the form of indices into vertex array
+std::vector<int> conn(8*hexes.size());
+iface->get_element_array(hexes.size(), 8, 0, hexes, 0, 1, &conn[0]);
+\endcode
+
+ \ref contents
+
+  \subsection foursix 4.6. File Readers/Writers Packaged With MOAB
+
+MOAB has been designed to efficiently represent data and metadata commonly=
 found in finite element mesh files.  Readers and writers are included with=
 MOAB which import/export specific types of metadata in terms of MOAB sets =
and tags, as described earlier in this document.  The number of readers and=
 writers in MOAB will probably grow over time, and so they are not enumerat=
ed here.  See the src/io/README file in the MOAB source distribution for a =
current list of supported formats.
+
+Because of its generic support for readers and writers, described in the p=
revious section, MOAB is also a good environment for constructing new mesh =
readers and writers.  The ReadTemplate and WriteTemplate classes in src/io =
are useful starting points for constructing new file readers/writers; appli=
cations are encouraged to submit their own readers/writers for inclusion in=
 MOAB=E2=80=99s contrib/io directory in the MOAB source.=20
+
+The usefulness of a file reader/writer is determined not only by its abili=
ty to read and write nodes and elements, but also in its ability to store t=
he various types of meta-data included with the typical mesh.  MOAB readers=
 and writers are distinguished by their ability to preserve meta-data in me=
shes that they read and write.  For example, MOAB=E2=80=99s CUB reader impo=
rts not only the mesh saved from CUBIT, but also the grouping of mesh entit=
ies into sets which reflect the geometric topology of the model used to gen=
erate the mesh.  See [4] for a more detailed description of meta-data conve=
ntions used in MOAB=E2=80=99s file readers and writers, and the individual =
file reader/writer header files in src/io for details about the specific re=
aders and writers.
+
+Three specific file readers in MOAB bear further discussion: MOAB=E2=80=99=
s native HDF5-based file reader/writer; the CUB reader, used to import mesh=
 and meta-data represented in CUBIT; and the CGM reader, which imports geom=
etric models.  These are described next.
+
+ \ref contents
+
+  \subsection native 4.6.1. Native HD5-Based Reader/Writer
+
+A mesh database must be able to save and restore the data stored in its da=
ta model, at least to the extent to which it understands the semantics of t=
hat data.  MOAB defines an HDF5-based file format that can store data embed=
ded in MOAB.  By convention, these files are given an =E2=80=9C.h5m=E2=80=
=9D file extension.  When reading or writing large amounts of data, it is r=
ecommended to use this file format, as it is the most complete and also the=
 most efficient of the file readers/writers in MOAB.=20
+
+  \subsection cub 4.6.2. CUB Reader
+
+CUBIT is a toolkit for generating tetrahedral and hexahedral finite elemen=
t meshes from solid model geometry [16].  This tool saves and restores data=
 in a custom =E2=80=9C.cub=E2=80=9D file, which stores both mesh and geomet=
ry (and data relating the two).  The CUB reader in MOAB can import and inte=
rpret much of the meta-data information saved in .cub files.  Ref. [4] desc=
ribes the conventions used to store this meta-data in the MOAB data model. =
 The information read from .cub files, and stored in the MOAB data model, i=
ncludes:
+
+- Geometric model entities and topology
+- Model entity names and ids
+- Groups, element blocks, nodesets, and sidesets, including model entities=
 stored in them
+- Mesh scheme and interval size information assigned to model entities
+.
+
+Note that although information about model entities is recovered, MOAB by =
default does not depend on a solid modeling engine; this information is sto=
red in the form of entity sets and parent/child relations between them.  Se=
e Ref. [4] for more information.
+
+ \ref contents
+
+  \subsection cgm 4.6.3. CGM Reader
+
+The Common Geometry Module (CGM) [17] is a library for representing solid =
model and other types of solid geometry data.  The CUBIT mesh generation to=
olkit uses CGM for its geometric modeling support, and CGM can restore geom=
etric models in the exact state in which they were represented in CUBIT.  M=
OAB contains a CGM reader, which can be enabled with a configure option.  U=
sing this reader, MOAB can read geometric models, and represent their model=
 topology using entity sets linked by parent/child relations.  The mesh in =
these models comes directly from the modeling engine faceting routines; the=
se are the same facets used to visualize solid models in other graphics eng=
ines.  When used in conjunction with the VisIt visualization tool (see Sect=
ion  ), this provides a solution for visualizing geometric models.  Xxx sho=
ws a model imported using MOAB=E2=80=99s CGM reader and visualized with Vis=
It.=20
+
+ \ref contents
+
+  \section parallel 5. Parallel Mesh Representation and Query
+
+A parallel mesh representation must strike a careful balance between provi=
ding an interface to mesh similar to that of a serial mesh, while also allo=
wing the discovery of parallel aspects of the mesh and performance of paral=
lel mesh-based operations efficiently.  MOAB supports a spatial domain-deco=
mposed view of a parallel mesh, where each subdomain is assigned to a proce=
ssor, lower-dimensional entities on interfaces between subdomains are share=
d between processors, and ghost entities can be exchanged with neighboring =
processors.  Locally, each subdomain, along with any locally-represented gh=
ost entities, are accessed through a local MOAB instance.  Parallel aspects=
 of the mesh, e.g. whether entities are shared, on an interface, or ghost e=
ntities, are embedded in the same data model (entities, sets, tags, interfa=
ce) used in the rest of MOAB.  MOAB provides a suite of parallel functions =
for initializing and communicating with a parallel mesh, along with functio=
ns to query the parallel aspects of the mesh.
+
+  \ref contents
+
+  \subsection fiveone 5.1. Nomenclature & Representation
+
+Before discussing how to access parallel aspects of a mesh, several terms =
need to be defined: =20
+
+<B>Shared entity:</B> An entity shared by one or several other processors.
+
+<B>Multi-shared entity:</B> An entity shared by more than two processors.
+
+<B>Owning Processor:</B> Each shared entity is owned by exactly one proces=
sor.  This processor has the right to set tag values on the entity and have=
 those values propagated to any sharing processors. =20
+
+<B>Part:</B> The collection of entities assigned to a given processor.  Wh=
en reading mesh in parallel, the entities in a Part, along with any lower-d=
imensional entities adjacent to those, will be read onto the assigned proce=
ssor.
+
+<B>Partition:</B> A collection of Parts which take part in parallel collec=
tive communication, usually associated with an MPI communicator.
+
+<B>Interface:</B> A collection of mesh entities bounding entities in multi=
ple parts.  Interface entities are owned by a single processor, but are rep=
resented on all parts/processors they bound.
+
+<B>Ghost entity:</B> A shared, non-interface, non-owned entity.
+
+<B>Parallel status:</B> A characteristic of entities and sets represented =
in parallel. The parallel status, or =E2=80=9Cpstatus=E2=80=9D, is represen=
ted by a bit field stored in an unsigned character, with bit values as desc=
ribed in Table 4.
+
+  \subsection tablefour Table 4: Bits representing various parallel charac=
teristics of a mesh.  Also listed are enumerated values that can be used in=
 bitmask expressions; these enumerated variables are declared in MBParallel=
Conventions.h.
+
+<table border=3D"1">
+<tr>
+<th>Bit</th>
+<th>Name</th>
+<th>Represents</th>
+</tr>
+<tr>
+<td>0x1</td>
+<td>PSTATUS_NOT_OWNED</td>
+<td>Not owned by the local processor</td>
+</tr>
+<tr>
+<td>0x2</td>
+<td>PSTATUS_SHARED</td>
+<td>Shared by exactly two processorstd>
+</tr>
+<tr>
+<td>0x4</td>
+<td>PSTATUS_MULTISHARED</td>
+<td>Shared by three or more processors</td>
+</tr>
+<tr>
+<td>0x8</td>
+<td>PSTATUS_INTERFACE</td>
+<td>Part of lower-dimensional interface shared by multiple processors</td>
+</tr>
+<tr>
+<td>0x10</td>
+<td>PSTATUS_GHOST</td>
+<td>Non-owned, non-interface entities represented locally</td>
+</tr>
+</table>
+
+Parallel functionality is described in the following sections.  First, met=
hods to load a mesh into a parallel representation are described; next, fun=
ctions for accessing parallel aspects of a mesh are described; functions fo=
r communicating mesh and tag data are described.
+
+  \ref contents
+
+  \subsection fivetwo 5.2. Parallel Mesh Initialization
+
+Parallel mesh is initialized in MOAB in several steps:
+
+-#  Establish a local mesh on each processor, either by reading the mesh i=
nto that representation from disk, or by creating mesh locally through the =
normal MOAB interface. =20
+-#  Find vertices, then other entities, shared between processors, based o=
n a globally-consistent vertex numbering stored on the GLOBAL_ID tag. =20
+-#  Exchange ghost or halo elements within a certain depth of processor in=
terfaces with neighboring processors. =20
+.
+
+These steps can be executed by a single call to MOAB=E2=80=99s load_file f=
unction, using the procedure described in Section 5.2.1.  Or, they can be e=
xecuted in smaller increments calling specific functions in MOAB=E2=80=99s =
ParallelComm class, as described in Section 5.2.2.  Closely related to the =
latter method is the handling of communicators, described in more detail in=
 Section.
+
+  \ref contents
+
+  \subsection initialization 5.2.1. Parallel Mesh Initialization by Loadin=
g a File
+
+In the file reading approach, a mesh must contain some definition of the p=
artition (the assignment of mesh, usually regions, to processors).  Partiti=
ons can be derived from other set structures already on the mesh, or can be=
 computed explicitly for that purpose by tools like mbzoltan (see Section 4=
.2).  For example, geometric volumes used to generate the mesh, and region-=
based material type assignments, are both acceptable partitions (see Ref. [=
4] for information about this and other meta-data often accompanying mesh).=
  In addition to defining the groupings of regions into parts, the assignme=
nt of specific parts to processors can be done implicitly or using addition=
al data stored with the partition.
+
+MOAB implements several specific methods for loading mesh into a parallel =
representation:
+
+- READ_PART: each processor reads only the mesh used by its part(s).
+
+- READ_DELETE: each processor reads the entire mesh, then deletes the mesh=
 not used by its part(s).
+
+- BCAST_DELETE: the root processor reads and broadcasts the mesh; each pro=
cessor then deletes the mesh not used by its part(s).
+
+The READ_DELETE and BCAST_DELETE methods are supported for all file types =
MOAB is able to read, while READ_PART is only implemented for MOAB=E2=80=99=
s native HDF5-based file format.
+
+Various other options control the selection of part sets or other details =
of the parallel read process.  For example, the application can specify the=
 tags, and optionally tag values, which identify parts, and whether those p=
arts should be distributed according to tag value or using round-robin assi=
gnment.
+
+The options used to specify loading method, the data used to identify part=
s, and other parameters controlling the parallel read process, are shown in=
 Table 5. =20
+  \subsection tablefive Table 5: Options passed to MOAB=E2=80=99s load_fil=
e function identifying the partition and other parameters controlling the p=
arallel read of mesh data.  Options and values should appear in option stri=
ng as =E2=80=9Coption=3Dval=E2=80=9D, with a delimiter (usually =E2=80=9C;=
=E2=80=9D) between options.
+
+<table border=3D"1">
+<tr>
+<th>Option</th>
+<th>Value</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>PARTITION</td>
+<td><tag_name></td>
+<td>Sets with the specified tag name should be used as part sets</td>
+</tr>
+<tr>
+<td>PARTITION_VAL</td>
+<td><val1, val2-val3, ...></td>
+<td>Integer values to be combined with tag name, with ranges input using v=
al1, val2-val3.  Not meaningful unless PARTITION option is also given.</td>
+</tr>
+<tr>
+<td>PARTITION_DISTRIBUTE</td>
+<td>(none)</td>
+<td>If present, or values are not input using PARTITION_VAL, sets with tag=
 indicated in PARTITION option are partitioned across processors in round-r=
obin fashion.</td>
+</tr>
+<tr>
+<td>PARALLEL_RESOLVE_SHARED_ENTS</td>
+<td><pd.sd></td>
+<td>Resolve entities shared between processors, where partition is made up=
 of pd- dimensional entities, and entities of dimension sd and lower should=
 be resolved.</td>
+</tr>
+<tr>
+<td>PARALLEL_GHOSTS</td>
+<td><gd.bd.nl[.ad]></td>
+<td>Exchange ghost elements at shared inter-processor interfaces.  Ghost e=
lements of dimension gd will be exchanged.  Ghost elements are chosen going=
 through bd-dimensional interface entities.  Number of layers of ghost elem=
ents is specified in nl.  If ad is present, lower-dimensional entities boun=
ding exchanged ghost entities will also be exchanged; allowed values for ad=
 are 1 (exchange bounding edges), 2 (faces), or 3 (edges and faces).</td>
+</tr>
+<tr>
+<td>CPUTIME</td>
+<td>(none)</td>
+<td>Print cpu time required for each step of parallel read & initializatio=
n.</td>
+</tr>
+<tr>
+<td>MPI_IO_RANK</td>
+<td><r></td>
+<td>If read method requires reading mesh onto a single processor, processo=
r with rank r is used to do that read.</td>
+</tr>
+</table>
+
+Several example option strings controlling parallel reading and initializa=
tion are:
+
+<B>=E2=80=9CPARALLEL=3DREAD_DELETE; PARTITION=3DMATERIAL_SET; PARTITION_VA=
L=3D100, 200, 600-700=E2=80=9D:</B> The whole mesh is read by every process=
or; this processor keeps mesh in sets assigned the tag whose name is =E2=80=
=9CMATERIAL_SET=E2=80=9D and whose value is any one of 100, 200, and 600-70=
0 inclusive.
+
+<B>=E2=80=9CPARALLEL=3DREAD_PART; PARTITION=3DPARALLEL_PARTITION, PARTITIO=
N_VAL=3D2=E2=80=9D:</B> Each processor reads only its mesh; this processor,=
 whose rank is 2, is responsible for elements in a set with the PARALLEL_PA=
RTITION tag whose value is 2.  This would by typical input for a mesh which=
 had already been partitioned with e.g. Zoltan or Parmetis.
+
+<B>=E2=80=9CPARALLEL=3DBCAST_DELETE; PARTITION=3DGEOM_DIMENSION, PARTITION=
_VAL=3D3, PARTITION_DISTRIBUTE=E2=80=9D:</B> The root processor reads the f=
ile and broadcasts the whole mesh to all processors.  If a list is construc=
ted with entity sets whose GEOM_DIMENSION tag is 3, i.e. sets corresponding=
 to geometric volumes in the original geometric model, this processor is re=
sponsible for all elements with index R+iP, i >=3D 0 (i.e. a round-robin di=
stribution).
+
+ \ref contents
+
+  \subsection functions 5.2.2. Parallel Mesh Initialization Using Functions
+
+After creating the local mesh on each processor, an application can call t=
he following functions in ParallelComm to establish information on shared m=
esh entities.  See the [ref-directparmesh example] in the MOAB source tree =
for a complete example of how this is done from an application.
+
+- ParallelComm::resolve_shared_entities (collective): Resolves shared enti=
ties between processors, based on GLOBAL_ID tag values of vertices.  Variou=
s forms are available, based on entities to be evaluated and maximum dimens=
ion for which entity sharing should be found.
+
+- ParallelComm::exchange_ghost_cells (collective): Exchange ghost entities=
 with processors sharing an interface with this processor, based on specifi=
ed ghost dimension (dimension of ghost entities exchanged), bridge dimensio=
n, number of layers, and type of adjacencies to ghost entities.  An entity =
is sent as a ghost if it is within that number of layers, across entities o=
f the bridge dimension, with entities owned by the receiving processor, or =
if it is a lower-dimensional entity adjacent to a ghost entity and that opt=
ion is requested.
+.
+
+ \ref contents
+
+  \subsection communicator 5.2.3. Communicator Handling
+
+The ParallelComm constructor takes arguments for an MPI communicator and a=
 MOAB instance.  The ParallelComm instance stores the MPI communicator, and=
 registers itself with the MOAB instance.  Applications can specify the Par=
allelComm index to be used for a given file operation, thereby specifying t=
he MPI communicator for that parallel operation.  For example:
+
+\code
+using namespace moab;
+// pass a communicator to the constructor, getting back the index
+MPI_Comm my_mpicomm;
+int pcomm_index;
+ParallelComm my_pcomm(moab, my_mpicomm, &pcomm_index);
+
+// write the pcomm index into a string option
+char load_opt[32];
+sprintf(load_opt, "PARALLEL=3DBCAST_DELETE;PARALLEL_COMM=3D%d",=20
+   pcomm_index);
+
+// specify that option in a parallel read operation
+ErrorCode rval =3D moab->load_file(load_opt, fname, ...)
+\endcode
+
+In the above code fragment, the ParallelComm instance with index pcomm_ind=
ex will be used in the parallel file read, so that the operation executes o=
ver the specified MPI communicator.  If no ParallelComm instance is specifi=
ed for a parallel file operation, a default instance will be defined, using=
 MPI_COMM_WORLD.
+
+Applications needing to retrieve a ParallelComm instance created previousl=
y and stored with the MOAB instance, e.g. by a different code component, ca=
n do so using a static function on ParallelComm:
+
+\code
+ParallelComm *my_pcomm =3D ParallelComm::get_pcomm(moab, pcomm_index);
+\endcode
+
+ParallelComm also provides the ParallelComm::get_all_pcomm function, for r=
etrieving all ParallelComm instances stored with a MOAB instance.  For synt=
ax and usage of this function, see the MOAB online documentation for Parall=
elComm.hpp [8].
+
+ \ref contents
+
+  \subsection fivethree 5.3. Parallel Mesh Query Functions
+
+Various functions are commonly used in parallel mesh-based applications.  =
Functions marked as being collective must be called collectively for all pr=
ocessors that are members of the communicator associated with the ParallelC=
omm instance used for the call.
+
+<B>ParallelComm::get_pstatus:</B>  Get the parallel status for the entity.
+
+<B>ParallelComm::get_pstatus_entities:</B> Get all entities whose pstatus =
satisfies (pstatus & val).
+
+<B>ParallelComm::get_owner:</B> Get the rank of the owning processor for t=
he specified entity.
+
+<B>ParallelComm::get_owner_handle:</B> Get the rank of the owning processo=
r for the specified entity, and the entity's handle on the owning processor.
+
+<B>ParallelComm::get_sharing_data:</B> Get the sharing processor(s) and ha=
ndle(s) for an entity or entities.  Various overloaded versions are availab=
le, some with an optional =E2=80=9Coperation=E2=80=9D argument, where Inter=
face::INTERSECT or Interface::UNION can be specified.  This is similar to t=
he operation arguments to Interface::get_adjacencies.
+
+<B>ParallelComm::get_shared_entities:</B> Get entities shared with the giv=
en processor, or with all processors.  This function has optional arguments=
 for specifying dimension, whether interface entities are requested, and wh=
ether to return just owned entities.
+
+<B>ParallelComm::get_interface_procs:</B> Return all processors with whom =
this processor shares an interface.
+
+<B>ParallelComm::get_comm_procs:</B> Return all processors with whom this =
processor communicates.
+
+  \ref contents
+
+  \subsection fivefour 5.4. Parallel Mesh Communication
+
+Once a parallel mesh has been initialized, applications can call the Paral=
lelComm::exchange_tags function for exchanging tag values between processor=
s.  This function causes the owning processor to send the specified tag val=
ues for all shared, owned entities to other processors sharing those entiti=
es.  Asynchronous communication is used to hide latency, and only point-to-=
point communication is used in these calls.
+
+  \ref contents
+
+  \section applications 6. Building MOAB-Based Applications
+
+There are two primary mechanisms supported by MOAB for building applicatio=
ns, one based on MOAB-defined make variables, and the other based on the us=
e of libtool and autoconf.  Both assume the use of a =E2=80=9Cmake=E2=80=9D=
-based build system. =20
+
+The easiest way to incorporate MOAB into an application=E2=80=99s build pr=
ocess is to include the =E2=80=9Cmoab.make=E2=80=9D file into the applicati=
on=E2=80=99s Makefile, adding the make variables MOAB_INCLUDES and MOAB_LIB=
S_LINK to application=E2=80=99s compile and link commands, respectively.  M=
OAB_INCLUDES contains compiler options specifying the location of MOAB incl=
ude files, and any preprocessor definitions required by MOAB.  MOAB_LIBS_LI=
NK contains both the options telling where libraries can be found, and the =
link options which incorporate those libraries into the application.  Any l=
ibraries depended on by the particular configuration of MOAB are included i=
n that definition, e.g. the HDF5 library.  Using this method to incorporate=
 MOAB is the most straightforward; for example, the following Makefile is u=
sed to build one of the example problems packaged with the MOAB source:
+\code
+include ${MOAB_LIB_DIR}/moab.make
+
+GetEntities : GetEntities.o
+	${CXX} $< ${MOAB_LIBS_LINK} -o $@
+
+.cpp.o :=20
+	${CXX} ${MOAB_INCLUDES} -c $<
+\endcode
+
+Here, the MOAB_LIB_DIR environment variable or make argument definition sp=
ecifies where the MOAB library is installed; this is also the location of t=
he moab.make file.  Once that file has been included, MOAB_INCLUDES and MOA=
B_LIBS_LINK can be used, as shown.
+
+Other make variables are defined in the moab.make file which simplify buil=
ding applications:
+
+- MOAB_LIBDIR, MOAB_INCLUDEDIR: the directories into which MOAB libraries =
and include files will be installed, respectively.  Note that some include =
files are put in a subdirectory named =E2=80=9Cmoab=E2=80=9D below that dir=
ectory, to reflect namespace naming conventions used in MOAB.
+
+- MOAB_CXXFLAGS, MOAB_CFLAGS, MOAB_LDFLAGS: Options passed to the C++ and =
C compilers and the linker, respectively.
+
+- MOAB_CXX, MOAB_CC, MOAB_FC: C++, C, and Fortran compilers specified to M=
OAB at configure time, respectively.
+.
+
+The second method for incorporating MOAB into an application=E2=80=99s bui=
ld system is to use autoconf and libtool.  MOAB is configured using these t=
ools, and generates the =E2=80=9C.la=E2=80=9D files that hold information o=
n library dependencies that can be used in application build systems also b=
ased on autoconf and libtool.  Further information on this subject is beyon=
d the scope of this User=E2=80=99s Guide; see the =E2=80=9C.la=E2=80=9D fil=
es as installed by MOAB, and contact the MOAB developer=E2=80=99s mailing l=
ist [6] for more details.
+
+  \ref contents
+
+  \section implementation  7. iMesh (ITAPS Mesh Interface) Implementation =
in MOAB
+
+iMesh is a common API to mesh data developed as part of the Interoperable =
Tools for Advanced Petascale Simulations (ITAPS) project [18].  Application=
s using the iMesh interface can operate on any implementation of that inter=
face, including MOAB.  MOAB-based applications can take advantage of other =
services implemented on top of iMesh, including the MESQUITE mesh improveme=
nt toolkit [19] and the GRUMMP mesh improvement library [20].
+
+MOAB=E2=80=99s native interface is accessed through the Interface abstract=
 C++ base class.  Wrappers are not provided in other languages; rather, app=
lications wanting to access MOAB from those languages should do so through =
iMesh.  In most cases, the data models and functionality available through =
MOAB and iMesh are identical.  However, there are a few differences, subtle=
 and not-so-subtle, between the two:
+
+<B>SPARSE tags used by default:</B> MOAB=E2=80=99s iMesh implementation cr=
eates SPARSE tags by default, because of semantic requirements of other tag=
-related functions in iMesh.  To create DENSE tags through iMesh, use the i=
Mesh_createTagWithOptions extension function (see below).
+
+<B>Higher-order elements:</B> ITAPS currently handles higher-order element=
s (e.g. a 10-node tetrahedron) usi[21]<sup>5</sup>.  As described in [sec-e=
ntities], MOAB supports higher-order entities by allowing various numbers o=
f vertices to define topological entities like quadrilateral or tetrahedron=
.  Applications can specify flags to the connectivity and adjacency functio=
ns specifying whether corner or all vertices are requested.
+
+<B>Self-adjacencies:</B> In MOAB=E2=80=99s native interface, entities are =
always self-adjacent<sup>6</sup>; that is, adjacencies of equal dimension r=
equested from an entity will always include that entity, while from iMesh w=
ill not include that entity.
+
+<B>Option strings:</B> The iMesh specification requires that options in th=
e options string passed to various functions (e.g. iMesh_load) be prepended=
 with the implementation name required to parse them, and delimited with sp=
aces.  Thus, a MOAB-targeted option would appear as =E2=80=9Cmoab:PARALLEL=
=3DREAD_PART moab:PARTITION=3DMATERIAL_SET=E2=80=9D.
+
+To provide complete MOAB support from other languages through iMesh, a col=
lection of iMesh extension functions are also available.  A general descrip=
tion of these extensions appears below; for a complete description, see the=
 online documentation for iMesh-extensions.h [8].
+
+- Recursive get_entities functions: There are many cases where sets includ=
e other sets (see [4] for more information).  MOAB provides iMesh_getEntiti=
esRec, and other recursive-supporting functions, to get all non-set entitie=
s of a given type or topology accessible from input set(s).  Similar functi=
ons are available for number of entities of a given type/topology.
+
+- Get entities by tag, and optionally tag value: It is common to search fo=
r entities with a given tag, and possibly tag value(s); functions like iMes=
h_getEntitiesByTag are provided for this purpose.
+
+- Options to createTag: To provide more control over the tag type, the iMe=
sh_createTagWithOptions is provided.  The storage type is controlled with t=
he =E2=80=9C
+
+- MBCNType: Canonical numbering evaluations are commonly needed by applica=
tions, e.g. to apply boundary conditions locally.  The MBCN package provide=
s these evaluations in terms of entity types defined in MOAB [9]; the getMB=
CNType is required to translate between iMesh_Topology and MBCN type.
+
+- Iterator step: Step an iterator a specified number of entities; allows a=
dvancement of an iterator without needing to allocate memory to hold the en=
tity handles stepped over.
+
+- Direct access to tag storage: The Interface::tag_iterate function allows=
 an application get a pointer to the memory used to store a given tag.  For=
 dense tags on contiguous ranges of entities, this provides more efficient =
access to tags.  The iMesh functionn iMesh_tagIterate provides access to th=
is functionlity.  See examples/TagIterateC.c and examples/TagIterateF.F for=
 examples of how to use this from C and Fortran, respectively.=20
+.
+
+As required by the iMesh specification, MOAB generates the =E2=80=9CiMesh-=
Defs.inc=E2=80=9D file and installs it with the iMesh and MOAB libraries.  =
This file defines make variables which can be used to build iMesh-based app=
lications.  The method used here is quite similar to that used for MOAB its=
elf (see Section 6).  In particular, the IMESH_INCLUDES and IMESH_LIBS make=
 variables can be used with application compile and link commands, respecti=
vely, with other make variables similar to those provided in moab.make also=
 available.
+
+Note that using the iMesh interface from Fortran-based applications requir=
es a compiler that supports Cray pointers, along with the pass-by-value (%V=
AL) extension.  Almost all compilers support those extensions; however, if =
using the gcc series of compilers, you must use gfortran 4.3 or later.
+
+<sup>5</sup>There are currently no implementations of this interface.
+
+<sup>6</sup>iMesh and MOAB both define adjacencies using the topological c=
oncept of closure.  Since the closure of an entity includes the entity itse=
lf, the d-dimensional entities on the closure of a given entity should incl=
ude the entity itself.
+
+ \ref contents
+
+  \section representation 8. Structured Mesh Representation
+
+A structured mesh is defined as a D-dimensional mesh whose interior vertic=
es have 2D connected edges.   Structured mesh can be stored without connect=
ivity, if certain information is kept about the parametric space of each st=
ructured block of mesh.  MOAB can represent structured mesh with implicit c=
onnectivity, saving approximately 57% of the storage cost compared to an un=
structured representation<sup>7</sup>.  Since connectivity must be computed=
 on the fly, these queries execute a bit slower than those for unstructured=
 mesh.  More information on the theory behind MOAB's structured mesh repres=
entation can be found in=20
+
+Currently, MOAB's structured mesh representation can only be used by creat=
ing structured mesh at runtime; that is, structured mesh is saved/restored =
in an unstructured format in MOAB's HDF5-based native save format.  For mor=
e details on how to use MOAB's structured mesh representation, see the scds=
eq_test.cpp source file in the test/ directory.
+
+<sup>7</sup> This assumes vertex coordinates are represented explicitly, a=
nd that there are approximately the same number of vertices and hexahedra i=
n a structured hex mesh.
+
+ \ref contents
+
+  \section element 9. Spectral Element Meshes
+
+The Spectral Element Method (SEM) is a high-order method, using a polynomi=
al Legendre interpolation basis with Gauss-Lobatto quadrature points, in co=
ntrast to the Lagrange basis used in (linear) finite elements [20].  SEM ob=
tains exponential convergence with decreasing mesh characteristic sizes, an=
d codes implementing this method typically have high floating-point intensi=
ty, making the method highly efficient on modern CPUs.  Most Nth-order SEM =
codes require tensor product cuboid (quad/hex) meshes, with each d-dimensio=
nal element containing (N+1)d degrees of freedom (DOFs).  There are various=
 methods for representing SEM meshes and solution fields on them; this docu=
ment discusses these methods and the tradeoffs between them.  The mesh part=
s of this discussion are given in terms of the iMesh mesh interface and its=
 implementation by the MOAB mesh library [21].
+
+The figure above shows a two-dimensional 3rd-order SEM mesh consisting of =
four quadrilaterals.  For this mesh, each quadrilateral has (N+1)^2=3D16 DO=
Fs, with corner and edge degrees of freedom shared between neighboring quad=
rilaterals.
+
+  \ref contents
+
+  \subsection nineone 9.1. Representations
+
+There are various representations of this mesh in a mesh database like MOA=
B, depending on how DOFs are related to mesh entities and tags on those ent=
ities.  We mention several possible representations:
+
+-# Corner vertices, element-based DOFs: Each quadrilateral is defined by f=
our vertices, ordered in CCW order typical of FE meshes.  DOFs are stored a=
s tags on quadrilaterals, with size (N+1)^2 values, ordered lexicographical=
ly (i.e. as a 2D array tag(i,j) with i varying faster than j.)  In the figu=
re above, the connectivity for face 1 would be (1, 4, 16, 13), and DOFs wou=
ld be ordered (1..16).  Note that in this representation, tag values for DO=
Fs shared by neighboring elements must be set multiple times, since there a=
re as many copies of these DOFs as elements sharing them.
+-# High-order FE-like elements: Each DOF is represented by a mesh vertex. =
Quadrilaterals each have (N+1)^2 vertices, ordered as they would be for hig=
h-order finite elements (corner vertices first, then mid-edge and mid-face =
elements; see [22]).  Mid -face, -edge, and -region vertices for a given ed=
ge/face/region would be ordered lexicographically, according to positive di=
rection in a corresponding reference element.  In the figure above, the con=
nectivity array for face 1 would be (1, 4, 16, 13, 2, 3, 8, 12, 14, 15, 5, =
9, 6, 7, 10, 11).  DOF values are stored as tags on vertices.  Since DOFs a=
re uniquely associated with vertices and vertices are shared by neighboring=
 elements, tag values only need to be set once.  Full vertex-quadrilateral =
adjacencies are available, for all vertices.
+-# Linear FE-like elements, one vertex per DOF, array with DOF vertices: E=
ach quadrilateral is defined by four (corner) vertices, with additional ver=
tices representing mid-edge and mid-face DOFs.  An additional =E2=80=9CDOF =
array=E2=80=9D tag is assigned to each quadrilateral, storing the array of =
vertices representing the (N+1)^2 DOFs for the quadrilateral, ordered lexic=
ographically.  For the figure above, the connectivity array for face 1 woul=
d be (1, 4, 16, 13), and the DOF array would be (1..16), assuming that vert=
ex handles are integers as shown in the figure.  DOF values are stored as t=
ags on vertices, and lexicographically-ordered arrays of DOFs can be retrie=
ved using the DOF array tag as input to the tag_get_data function in MOAB. =
 Adjacency functions would only be meaningful for corner vertices, but tag =
values would only need to be set once per DOF.
+-# High-order FE-like elements, array with DOF vertices: This is a combina=
tion of options 2 and 3.  The advantage would be full vertex-quad adjacency=
 support and direct availability of lexicographically-ordered vertex arrays=
, at the expense of more memory.
+-# Convert to linear mesh: Since a spectral element is a cuboid with highe=
r-order vertices, it can always be converted to N^2 linear cuboids using th=
e high-order vertices as corners of the finer quads/hexes.  This is how rea=
ders in ParaView and VisIt typically import spectral meshes (CAM-SE also ex=
ports connectivity in this form).
+
+As a convenience for applications, functions could also be provided for im=
portant tasks, like assembling the vertex handles for an entity in lexograp=
hic order (useful for option 2 above), and getting an array of tag values i=
n lexicographic order (for option 3 above).
+
+  \ref contents
+
+  \subsection ninetwo 9.2. Tradeoffs
+
+There are various competing tradeoffs in the various representation types.=
  These include:
+
+- Adjacencies: being able to retrieve the element(s) using a given (corner=
 or higher-order) vertex.
+- Connectivity list: being able to retrieve the connectivity of a given el=
ement, consisting of all (corner + higher-order) vertices in the element, u=
sually in lexicographical order.  This is closely linked with being able to=
 access the connectivity list as a const*, i.e. using the list straight fro=
m memory without needing to copy it.
+- Memory vs. time: There is a memory vs. execution time tradeoff between d=
uplicating interface vertex solution/tag variables in neighboring elements =
(more memory but more time-efficient and allows direct access to tag storag=
e by applications) versus using vertex-based tags (less memory but requires=
 assembly of variables into lexicographically-ordered arrays, and prevents =
direct access from applications).
+.
+
+The lower-memory option (storing variables on vertices and assembling into=
 lexicographically-ordered arrays for application use) usually ends up cost=
ing more in memory anyway, since applications must allocate their own stora=
ge for these arrays.  On the other hand, certain applications will always c=
hoose to do that, instead of sharing storage with MOAB for these variables.=
  In the case where applications do share memory with MOAB, other tools wou=
ld need to interpret the lexicographically-ordered field arrays specially, =
instead of simply treating the vertex tags as a point-based field.
+
+  \ref contents
+
+  \subsection ninethree 9.3. MOAB Representation
+In choosing the right MOAB representation for spectral meshes, we are tryi=
ng to balance a) minimal memory usage, b) access to properly-ordered and -a=
ligned tag storage, and c) maximal compatibility with tools likely to use M=
OAB.  The solution we propose is to use a representation most like option 2=
) above, with a few optional behaviors based on application requirements. =20
+
+In brief, we propose to represent elements using the linear, FE-ordered co=
nnectivity list (containing only corner vertices from the spectral element)=
, with field variables written to either vertices, lexicographically-ordere=
d arrays on elements, or both, and with a lexicographically-ordered array (=
stored on tag SPECTRAL_VERTICES) of all (corner+higher-order) vertices stor=
ed on elements.  In the either/or case, the choice will be evident from the=
 tag size and the entities on which the tag is set.  In the both case, the =
tag name will have a =E2=80=9C-LEX=E2=80=9D suffix for the element tags, an=
d the size of the element tag will be (N+1)^2 times that of the vertex-base=
d tag.  Finally, the file set containing the spectral elements (or the root=
 set, if no file set was input to the read) will contain a =E2=80=9CSPECTRA=
L_ORDER=E2=80=9D tag whose value is N.  These conventions are described in =
the =E2=80=9CMetadata Information=E2=80=9D document distributed with the MO=
AB source code.
+
+  \ref contents
+
+  \section performance 10. Performance and Using MOAB Efficiently from App=
lications
+
+MOAB is designed to operate efficiently on groups of entities and for larg=
e meshes.  Applications will be most efficient when they operate on entitie=
s in groups, especially groups which are close in their order of creation. =
 The MOAB API is structured to encourage operations on groups of entities. =
 Conversely, MOAB will not perform as well as other libraries if there are =
frequent deletion and creation of entities.  For those types of application=
s, a mesh library using a C++ object-based representation is more appropria=
te.  In this section, performance of MOAB when executing a variety of tasks=
 is described, and compared to that of other representations.  Of course, t=
hese metrics are based on the particular models and environments where they=
 are run, and may or may not be representative of other application types.
+
+One useful measure of MOAB performance is in the representation and query =
of a large mesh.  MOAB includes a performance test, located in the test/per=
f directory, in which a single rectangular region of hexahedral elements is=
 created then queried; the following steps are performed:
+
+- Create the vertices and hexes in the mesh
+- For each vertex, get the set of connected hexahedra
+- For each hex, get the connected vertices, their coordinates, average the=
m, and assign them as a tag on the hexes
+.
+
+This test can be run on your system to determine the runtime and memory pe=
rformance for these queries in MOAB.
+
+  \ref contents
+
+  \section conclusions 11. Conclusions and Future Plans
+
+MOAB, a Mesh-Oriented datABase, provides a simple but powerful data abstra=
ction to structured and unstructured mesh, and makes that abstraction avail=
able through a function API.  MOAB provides the mesh representation for the=
 VERDE mesh verification tool, which demonstrates some of the powerful mesh=
 metadata representation capabilities in MOAB.  MOAB includes modules that =
import mesh in the ExodusII, CUBIT .cub and Vtk file formats, as well as th=
e capability to write mesh to ExodusII, all without licensing restrictions =
normally found in ExodusII-based applications.  MOAB also has the capabilit=
y to represent and query structured mesh in a way that optimizes storage sp=
ace using the parametric space of a structured mesh; see Ref. [17] for deta=
ils.
+
+Initial results have demonstrated that the data abstraction provided by MO=
AB is powerful enough to represent many different kinds of mesh data found =
in real applications, including geometric topology groupings and relations,=
 boundary condition groupings, and inter-processor interface representation=
.  Our future plans are to further explore how these abstractions can be us=
ed in the design through analysis process.
+
+  \ref contents
+
+  \section references 12. References
+
+[1]	M. Fatenejad and G.A. Moses, =E2=80=9CCooper radiation hydrodynamics c=
ode..=E2=80=9D
+
+[2]	T.J. Tautges and A. Caceres, =E2=80=9CScalable parallel solution coupl=
ing for multiphysics reactor simulation,=E2=80=9D Journal of Physics: Confe=
rence Series,  vol. 180, 2009.
+
+[3]	T.J. Tautges, MOAB Meta-Data Information, 2010.
+
+[4]	T.J. Tautges, =E2=80=9CMOAB - ITAPS =E2=80=93 Trac.=E2=80=9D, http://t=
rac.mcs.anl.gov/projects/ITAPS/wiki/MOAB
+
+[5]	=E2=80=9CMOAB Developers Email List.=E2=80=9D, moab-dev at mcs.anl.gov.
+
+[6]	=E2=80=9CMOAB Users Email List.=E2=80=9D, moab at mcs.anl.gov.
+
+[7]	=E2=80=9CMOAB online documentation.=E2=80=9D, http://gnep.mcs.anl.gov:=
8010/moab-docs/
+
+[8]	T.J. Tautges, =E2=80=9CCanonical numbering systems for finite-element =
codes,=E2=80=9D Communications in Numerical Methods in Engineering,  vol. O=
nline, Mar. 2009.
+
+[9]	L.A. Schoof and V.R. Yarberry, EXODUS II: A Finite Element Data Model,=
  Albuquerque, NM: Sandia National Laboratories, 1994.
+
+[10]	M. PATRAN, =E2=80=9CPATRAN User=E2=80=99s Manual,=E2=80=9D 2005.
+
+[11]	VisIt User's Guide.
+
+[12]	K. Devine, E. Boman, R. Heaphy, B. Hendrickson, and C. Vaughan, =E2=
=80=9CZoltan Data Management Services for Parallel Dynamic Applications,=E2=
=80=9D Computing in Science and Engineering,  vol. 4, 2002, pp. 90=E2=80=93=
97.
+
+[13]	T.J. Tautges, P.P.H. Wilson, J. Kraftcheck, B.F. Smith, and D.L. Hend=
erson, =E2=80=9CAcceleration Techniques for Direct Use of  CAD-Based Geomet=
ries in Monte Carlo Radiation Transport,=E2=80=9D International Conference =
on Mathematics, Computational Methods & Reactor Physics (M&C 2009),  Sarato=
ga Springs, NY: American Nuclear Society, 2009.
+
+[14]	H. Kim and T. Tautges, =E2=80=9CEBMesh: An Embedded Boundary Meshing =
Tool,=E2=80=9D in preparation.
+
+[15]	G.D. Sjaardema, T.J. Tautges, T.J. Wilson, S.J. Owen, T.D. Blacker, W=
.J. Bohnhoff, T.L. Edwards, J.R. Hipp, R.R. Lober, and S.A. Mitchell, CUBIT=
 mesh generation environment Volume 1: Users manual, Sandia National Labora=
tories, May 1994, 1994.
+
+[16]	T.J. Tautges, =E2=80=9CCGM: A geometry interface for mesh generation,=
 analysis and other applications,=E2=80=9D Engineering with Computers,  vol=
. 17, 2001, pp. 299-314.
+
+[17]	T. J. Tautges, MOAB-SD: Integrated structured and unstructured mesh r=
epresentation, Engineering with Computers, vol. 20, no. 3, pp. 286-293, 200=
4.
+
+[18]	=E2=80=9CInteroperable Technologies for Advanced Petascale Simulation=
s (ITAPS),=E2=80=9D Interoperable Technologies for Advanced Petascale Simul=
ations (ITAPS).
+
+[19]	P. Knupp, =E2=80=9CMesh quality improvement for SciDAC applications,=
=E2=80=9D Journal of Physics: Conference Series,  vol. 46, 2006, pp. 458-46=
2.
+
+[20]	M. O. Deville, P. F. Fischer, and E. H. Mund, High-order methods for =
incompressible fluid flow. Cambridge, UK; New York: Cambridge University Pr=
ess, 2002.
+
+[21]	T. J. Tautges, =E2=80=9CMOAB Wiki.=E2=80=9D [Online]. Available: http=
://trac.mcs.anl.gov/projects/ITAPS/wiki/MOAB. [Accessed: 30-Oct-2012].
+
+[22]	T. J. Tautges, =E2=80=9CCanonical numbering systems for finite-elemen=
t codes,=E2=80=9D International Journal for Numerical Methods in Biomedical=
 Engineering, vol. 26, no. 12, pp. 1559=E2=80=931572, 2010.
+
+
+  \ref contents
+
+  \page differences Differences Between iMesh and MOAB
+
+  The data models used in MOAB and iMesh are quite similar, but not identi=
cal.The most significant differences are the following:
+
+- Tags: MOAB differentiates between DENSE, SPARSE, and BIT tags, using dif=
ferent storage models for each, while iMesh uses a single tag concept.  iMe=
sh allows application to query whether an entity has been given a tag of a =
specified type; this query is incompatible with the concept of a DENSE tag =
with a default value.  Thus, MOAB=E2=80=99s iMesh implementation creates SP=
ARSE tags by default, and tags created and accessed through this interface =
will use more memory than DENSE tags created through MOAB=E2=80=99s native =
interface.  To mitigate this problem, MOAB implements an extension of the i=
Mesh_createTag function which allows specification of the tag type (DENSE, =
SPARSE, etc.) to be created.  See later in this section for more informatio=
n.
+
+- Higher-order nodes: ITAPS currently handles higher-order elements (e.g. =
a 10-node tetrahedron) using a special =E2=80=9CShape=E2=80=9D interface.  =
In this interface, higher-order nodes are only accessible through the AEnti=
ties which they resolve.  MOAB=E2=80=99s iMesh implementation provides acce=
ss to higher-order nodes in the same manner described in Section  , by vary=
ing the number of vertices defining each entity.  As a result, if higher-or=
der entities are used in a model, the functions returning connectivity and =
vertex adjacencies always return all vertices, rather than providing an opt=
ion to return just corner vertices.
+
+- Self-adjacencies: iMesh specifies that entities are not self-adjacent; t=
hat is, requesting adjacencies of the same dimension/type results in an err=
or.  MOAB does not consider this an error, returning the entity itself.
+
+- Adjacency table and AEntities: iMesh uses the concept of an =E2=80=9Cadj=
acency table=E2=80=9D to determine which AEntities are available and create=
d by default.  MOAB uses input arguments to the get_adjacencies functions t=
o control whether AEntities are created.  These flags provide finer-grained=
 control over AEntities, but make it slightly less convenient to ensure tha=
t AEntities of a given dimension are always created.
+.
+
+ \page figures List of Figures
+=20
+  This page is intended to be empty.
+=20
+  \page tables List of Tables
+=20
+     \ref tableone
+
+     \ref tabletwo
+
+     \ref tablethree
+
+     \ref tablefour
+
+     \ref tablefive
+=20
+  \page building Building & Installing
+=20
+  MOAB uses an autoconf and libtool-based build process by default.  The p=
rocedure used to build MOAB from scratch depends on whether the source code=
 was obtained from a =E2=80=9Ctarball=E2=80=9D or directly from the Subvers=
ion repository.  Assuming the latter, the following steps should be execute=
d for building and installing MOAB:
+  - Locate and build any required dependencies.  MOAB can be built with no=
 dependencies on other libraries; this may be useful for applications only =
needing basic mesh representation and not needing to export mesh to formats=
 implemented in other libraries.  MOAB=E2=80=99s native save/restore capabi=
lity is built on HDF5-based files; applications needing to save and restore=
 files from MOAB reliably should use this library.  MOAB also uses ExodusII=
, a netCDF-based file format developed at Sandia National Laboratories [10]=
.  Applications needing to execute these tests should also build netCDF.  N=
ote that MOAB uses netCDF=E2=80=99s C++ interface, which is not enabled by =
default in netCDF but can be enabled using the =E2=80=9C=E2=80=93enable-cxx=
=E2=80=9D option to netCDF=E2=80=99s configure script.
+  - Unpack source code into <moab>, and change current working directory t=
o that location.
+  - Execute =E2=80=9Cautoreconf =E2=80=93fi=E2=80=9D.
+  - Run configure script, by executing =E2=80=9C./configure <options>=E2=
=80=9D.  Recommended options:
+       -# =E2=80=93prefix=3D<install_dir>: directory below which MOAB libr=
ary and include files will be installed; can either be the directory used f=
or MOAB source (<moab> from step 1), or a different directory.
+       -# =E2=80=93hdf5-dir=3D<hdf5_dir>: directory whose =E2=80=9Cinclude=
=E2=80=9D and =E2=80=9Clib=E2=80=9D subdirectories hold HDF5 include and li=
brary, respectively.  MOAB uses HDF5 for its native save/restore format (se=
e Section 4.6.1).
+       -# =E2=80=93netcdf-dir=3D: directory whose =E2=80=9Cinclude=E2=80=
=9D and =E2=80=9Clib=E2=80=9D subdirectories hold netCDF include and librar=
y, respectively.  MOAB uses netCDF-based files for many of its build tests.=
  If the location of netCDF cannot be found, MOAB=E2=80=99s build tests wil=
l not function properly, but MOAB will still be usable.
+       .
+  - Run =E2=80=9Cmake check=E2=80=9D; this runs a series of build tests, t=
o verify that the MOAB build was successful.  Note this check will fail if =
netCDF is not used, but MOAB itself will still be usable from applications.
+  - Run =E2=80=9Cmake install=E2=80=9D; this copies include files and libr=
aries to subdirectories of the directory specified in the =E2=80=9Cprefix=
=E2=80=9D option.
+  .
+
+These steps are sufficient for building MOAB against HDF5 and netCDF.  By =
default, a small number of standard MOAB-based applications are also built,=
 including mbconvert (a utility for reading and writing files), mbsize (for=
 querying basic information about a mesh), and the iMesh interface (see Sec=
tion 7).  Other utilities can be enabled using various other options to the=
 configure script; for a complete list of build options, execute =E2=80=9C.=
/configure =E2=80=93help=E2=80=9D.
+=20
+ */
+

diff --git a/doc/user.dox.in b/doc/user.dox.in
index 4fed19e..ed65208 100644
--- a/doc/user.dox.in
+++ b/doc/user.dox.in
@@ -305,7 +305,9 @@ WARN_LOGFILE           =3D
 # with spaces.
=20
 INPUT                  =3D @top_srcdir@/src @top_srcdir@/src/moab \
-                         @top_srcdir@/src/parallel/moab \
+                         @top_srcdir@/doc/UG/moabUG.h \
+                         @top_srcdir@/doc/DG \
+                         @top_srcdir@/src/parallel/moab  \
                          @top_srcdir@/src/MBTagConventions.hpp \
                          @top_srcdir@/src/MBCN.h \
                          @top_srcdir@/src/MBEntityType.h \

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dc89d66..38b4130 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,6 +38,7 @@
     ScdVertexData.cpp
     SequenceData.cpp
     SequenceManager.cpp
+    SetIterator.cpp
     Skinner.cpp
     SparseTag.cpp
     StructuredElementSeq.cpp
@@ -46,6 +47,7 @@
     SweptVertexData.cpp
     SysUtil.cpp
     TagInfo.cpp
+    Types.cpp
     TypeSequenceManager.cpp
     UnstructuredElemSeq.cpp
     Util.cpp
@@ -53,7 +55,6 @@
     VarLenSparseTag.cpp
     VertexSequence.cpp
     WriteUtil.cpp
-    moab_mpe.c
   )
   include_directories(
     ${MOAB_SOURCE_DIR}/src

diff --git a/src/ScdInterface.cpp b/src/ScdInterface.cpp
index e2b18bb..8084640 100644
--- a/src/ScdInterface.cpp
+++ b/src/ScdInterface.cpp
@@ -7,12 +7,12 @@
 #include "ScdVertexData.hpp"
 #ifdef USE_MPI
 #  include "moab/ParallelComm.hpp"
+#  include "moab/TupleList.hpp"
+#  include "moab/gs.hpp"
 #endif
 #include "assert.h"
 #include <iostream>
 #include <functional>
-#include "moab/TupleList.hpp"
-#include "moab/gs.hpp"
=20
 #define ERRORR(rval, str) {if (MB_SUCCESS !=3D rval)          \
       {std::cerr << str; return rval; }}

diff --git a/src/Skinner.cpp b/src/Skinner.cpp
index fb80e58..1d284b7 100644
--- a/src/Skinner.cpp
+++ b/src/Skinner.cpp
@@ -1510,6 +1510,34 @@ ErrorCode Skinner::create_side( EntityHandle elem,
   rval =3D thisMB->get_connectivity( elem, conn, len, false, &storage );
   if (MB_SUCCESS !=3D rval) return rval;
 =20
+  // treat separately MBPOLYGON; we want to create the edge in the
+  // forward sense always ; so figure out the sense first, then get out
+  if (MBPOLYGON=3D=3Dtype && 1=3D=3Dd && MBEDGE=3D=3Dside_type)
+  {
+    // first find the first vertex in the conn list
+    int i=3D0;
+    for (i=3D0; i<len; i++)
+    {
+      if (conn[i]=3D=3Dside_conn[0])
+        break;
+    }
+    if (len =3D=3D i)
+      return MB_FAILURE; // not found, big error
+    int prevIndex =3D (i+len-1)%len;
+    int nextIndex =3D (i+1)%len;
+    EntityHandle conn2[2] =3D {side_conn[0], side_conn[1]};
+    if (conn[prevIndex]=3D=3Dside_conn[1])
+    {
+      // reverse, so the edge will be forward
+      conn2[0]=3Dside_conn[1];
+      conn2[1]=3Dside_conn[0];
+    }
+    else if  ( conn[nextIndex]!=3Dside_conn[1])
+      return MB_FAILURE; // it is not adjacent to the polygon
+
+    return thisMB->create_element( MBEDGE, conn2, 2, side_elem );
+
+  }
   // Find which side we are creating and get indices of all nodes
   // (including higher-order, if any.)
   CN::SideNumber( type, conn, side_conn, ncorner, d, side, sense, offset );

diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
index f83eb4f..d6c3e44 100644
--- a/src/io/CMakeLists.txt
+++ b/src/io/CMakeLists.txt
@@ -12,7 +12,9 @@
     ReadSmf.cpp
     ReadSms.cpp
     ReadSTL.cpp
+    ReadTemplate.cpp
     ReadTetGen.cpp
+    ReadTxt.cpp
     ReadVtk.cpp
     SMF_State.cpp
     Tqdcfr.cpp

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index c225841..146227c 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -147,7 +147,7 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
 #ifdef USE_MPI
     for (int i =3D 0; i < 6; i++)
       parData.gDims[i] =3D gDims[i];
-    for (int i =3D 0; i < 3; i++)
+    for (int i =3D 0; i < 2; i++)
       parData.gPeriodic[i] =3D globallyPeriodic[i];
     parData.partMethod =3D partMethod;
     int pdims[3];

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index cdc4392..9141938 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -158,7 +158,7 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
 #ifdef USE_MPI
     for (int i =3D 0; i < 6; i++)
       parData.gDims[i] =3D gDims[i];
-    for (int i =3D 0; i < 3; i++)
+    for (int i =3D 0; i < 2; i++)
       parData.gPeriodic[i] =3D globallyPeriodic[i];
     parData.partMethod =3D partMethod;
     int pdims[3];

diff --git a/src/moab/Interface.hpp b/src/moab/Interface.hpp
index 030b9d1..d7ad8aa 100644
--- a/src/moab/Interface.hpp
+++ b/src/moab/Interface.hpp
@@ -22,8 +22,8 @@
  * together to describe geometric topology, boundary condition, and inter-=
processor interface=20
  * groupings in a mesh.
  *
- * MOAB's API is documented in the moab::Interface class.  The User's Guid=
e is located in
- * doc/MOABv4-UG.doc in MOAB's source tree.  Questions and comments should=
 be sent to moab-dev=20
+ * MOAB's API is documented in the moab::Interface class.  The User's Guid=
e and Developer's Guide are located in
+ * <a href=3D"pages.html">related pages</a>.  Questions and comments shoul=
d be sent to moab-dev=20
  * _at_ mcs.anl.gov.
  */
=20

diff --git a/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index de30f8b..bf5cbb8 100644
--- a/test/parallel/par_intx_sph.cpp
+++ b/test/parallel/par_intx_sph.cpp
@@ -42,9 +42,12 @@ using namespace moab;
 // some input data
 double EPS1=3D0.2; // this is for box error
 std::string input_mesh_file("Homme_2pt.h5m"); // input file, partitioned c=
orrectly
+std::string mpas_file("mpas_p8.h5m");
 double CubeSide =3D 6.; // the above file starts with cube side 6; radius =
depends on cube side
+double radius;
 void test_intx_in_parallel();
 void test_intx_in_parallel_elem_based();
+void test_intx_mpas();
=20
 int main(int argc, char **argv)
 {
@@ -73,7 +76,10 @@ int main(int argc, char **argv)
     }
   }
   //result +=3D RUN_TEST(test_intx_in_parallel);
+  radius =3D CubeSide/2*sqrt(3.);
   result +=3D RUN_TEST(test_intx_in_parallel_elem_based);
+  radius =3D1.;
+  result +=3D RUN_TEST(test_intx_mpas);
=20
   MPI_Finalize();
   return result;
@@ -92,9 +98,9 @@ ErrorCode  manufacture_lagrange_mesh_on_sphere(Interface =
* mb, EntityHandle eule
    *   circumscribed sphere radius
    *   radius =3D length * math.sqrt(3) /2
    */
-  double radius =3D CubeSide/2*sqrt(3.);// our value depends on cube side
+  //radius =3D CubeSide/2*sqrt(3.);// our value depends on cube side
   Range quads;
-  rval =3D mb->get_entities_by_type(euler_set, MBQUAD, quads);
+  rval =3D mb->get_entities_by_dimension(euler_set, 2, quads);
   CHECK_ERR(rval);
=20
   Range connecVerts;
@@ -177,10 +183,10 @@ void test_intx_in_parallel()
 =20
   Intx2MeshOnSphere worker(&mb);
=20
-  double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
-  worker.SetEntityType(MBQUAD);
+  //worker.SetEntityType(MBQUAD);
=20
   worker.SetErrorTolerance(radius*1.e-8);
   worker.locate_departure_points(euler_set);
@@ -244,10 +250,10 @@ void test_intx_in_parallel_elem_based()
=20
   Intx2MeshOnSphere worker(&mb);
=20
-  double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
-  worker.SetEntityType(MBQUAD);
+  //worker.SetEntityType(MBQUAD);
=20
   worker.SetErrorTolerance(radius*1.e-8);
   std::cout << "error tolerance epsilon_1=3D"<< radius*1.e-8 << "\n";
@@ -282,3 +288,79 @@ void test_intx_in_parallel_elem_based()
       "  intersection area:" << intx_area << " rel error: " << fabs((intx_=
area-arrival_area)/arrival_area) << "\n";
   CHECK_ERR(rval);
 }
+
+void test_intx_mpas()
+{
+  std::string opts =3D std::string("PARALLEL=3DREAD_PART;PARTITION=3DPARAL=
LEL_PARTITION")+
+          std::string(";PARALLEL_RESOLVE_SHARED_ENTS");
+  Core moab;
+  Interface & mb =3D moab;
+  EntityHandle euler_set;
+  ErrorCode rval;
+  rval =3D mb.create_meshset(MESHSET_SET, euler_set);
+  CHECK_ERR(rval);
+  std::string example(TestDir + "/" +  mpas_file);
+
+  rval =3D mb.load_file(example.c_str(), &euler_set, opts.c_str());
+
+  ParallelComm* pcomm =3D ParallelComm::get_pcomm(&mb, 0);
+  CHECK_ERR(rval);
+
+  rval =3D pcomm->check_all_shared_handles();
+  CHECK_ERR(rval);
+
+  // everybody will get a DP tag, including the non owned entities; so exc=
hange tags is not required for LOC (here)
+  rval =3D manufacture_lagrange_mesh_on_sphere(&mb, euler_set);
+  CHECK_ERR(rval);
+
+  int rank =3D pcomm->proc_config().proc_rank();
+
+  std::stringstream ste;
+  ste<<"initial" << rank<<".vtk";
+  mb.write_file(ste.str().c_str(), 0, 0, &euler_set, 1);
+
+  Intx2MeshOnSphere worker(&mb);
+
+  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
+  worker.SetRadius(radius);
+  worker.set_box_error(EPS1);//
+  //worker.SetEntityType(MBQUAD);
+
+  worker.SetErrorTolerance(radius*1.e-8);
+  std::cout << "error tolerance epsilon_1=3D"<< radius*1.e-8 << "\n";
+  //  worker.locate_departure_points(euler_set);
+
+  // we need to make sure the covering set is bigger than the euler mesh
+  EntityHandle covering_lagr_set;
+  rval =3D mb.create_meshset(MESHSET_SET, covering_lagr_set);
+  CHECK_ERR(rval);
+
+  rval =3D worker.create_departure_mesh_2nd_alg(euler_set, covering_lagr_s=
et);
+  CHECK_ERR(rval);
+
+  std::stringstream ss;
+  ss<<"partial" << rank<<".vtk";
+  mb.write_file(ss.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  rval =3D enforce_convexity(&mb, covering_lagr_set);
+  CHECK_ERR(rval);
+  std::stringstream ss2;
+  ss2<<"partialConvex" << rank<<".vtk";
+  mb.write_file(ss2.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  EntityHandle outputSet;
+  rval =3D mb.create_meshset(MESHSET_SET, outputSet);
+  CHECK_ERR(rval);
+  rval =3D worker.intersect_meshes(covering_lagr_set, euler_set, outputSet=
);
+  CHECK_ERR(rval);
+
+  //std::string opts_write("PARALLEL=3DWRITE_PART");
+  //rval =3D mb.write_file("manuf.h5m", 0, opts_write.c_str(), &outputSet,=
 1);
+  std::string opts_write("");
+  std::stringstream outf;
+  outf<<"intersect" << rank<<".h5m";
+  rval =3D mb.write_file(outf.str().c_str(), 0, 0, &outputSet, 1);
+  double intx_area =3D area_on_sphere(&mb, outputSet, radius);
+  double arrival_area =3D area_on_sphere(&mb, euler_set, radius) ;
+  std::cout<< "On rank : " << rank << " arrival area: " << arrival_area<<
+      "  intersection area:" << intx_area << " rel error: " << fabs((intx_=
area-arrival_area)/arrival_area) << "\n";
+  CHECK_ERR(rval);
+}

diff --git a/tools/mbcslam/CslamUtils.cpp b/tools/mbcslam/CslamUtils.cpp
index 61d1bf0..1166a7a 100644
--- a/tools/mbcslam/CslamUtils.cpp
+++ b/tools/mbcslam/CslamUtils.cpp
@@ -12,6 +12,11 @@
 #include "ElemUtil.hpp"
 #include "moab/MergeMesh.hpp"
=20
+// this is for sstream
+#include <sstream>
+
+#include <queue>
+
 namespace moab {
 // vec utilities that could be common between quads on a plane or sphere
 double dist2(double * a, double * b)
@@ -24,24 +29,26 @@ double area2D(double *a, double *b, double *c)
   // (b-a)x(c-a) / 2
   return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) /=
 2;
 }
-int borderPointsOfXinY2(double * X, double * Y, int nsides, double * P, in=
t side[4])
+int borderPointsOfXinY2(double * X, int nX, double * Y, int nY, double * P=
, int side[MAXEDGES])
 {
   // 2 triangles, 3 corners, is the corner of X in Y?
   // Y must have a positive area
   /*
    */
   int extraPoint =3D 0;
-  for (int i =3D 0; i < nsides; i++)
+  for (int i =3D 0; i < nX; i++)
   {
-    // compute twice the area of all 4 triangles formed by a side of Y and=
 a corner of X; if one is negative, stop
+    // compute twice the area of all nY triangles formed by a side of Y an=
d a corner of X; if one is negative, stop
+    // (negative means it is outside; X and Y are all oriented such that t=
hey are positive oriented;
+    //  if one area is negative, it means it is outside the convex region,=
 for sure)
     double * A =3D X + 2 * i;
=20
     int inside =3D 1;
-    for (int j =3D 0; j < nsides; j++)
+    for (int j =3D 0; j < nY; j++)
     {
       double * B =3D Y + 2 * j;
=20
-      int j1 =3D (j + 1) % nsides;
+      int j1 =3D (j + 1) % nY;
       double * C =3D Y + 2 * j1; // no copy of data
=20
       double area2 =3D (B[0] - A[0]) * (C[1] - A[1])
@@ -54,7 +61,8 @@ int borderPointsOfXinY2(double * X, double * Y, int nside=
s, double * P, int side
     }
     if (inside)
     {
-      side[i] =3D 1;
+      side[i] =3D 1;// so vertex i of X is inside the convex region formed=
 by Y
+      // so side has nX dimension (first array)
       P[extraPoint * 2] =3D A[0];
       P[extraPoint * 2 + 1] =3D A[1];
       extraPoint++;
@@ -84,7 +92,8 @@ int SortAndRemoveDoubles2(double * P, int & nP, double ep=
silon_1)
   }
   c[0] /=3D nP;
   c[1] /=3D nP;
-  double angle[24]; // could be at most 24 points; much less usually
+  // how many
+  std::vector<double> angle(nP); // could be at most nP points
   for (k =3D 0; k < nP; k++)
   {
     double x =3D P[2 * k] - c[0], y =3D P[2 * k + 1] - c[1];
@@ -108,7 +117,7 @@ int SortAndRemoveDoubles2(double * P, int & nP, double =
epsilon_1)
       if (angle[k] > angle[k + 1])
       {
         sorted =3D 0;
-        swap2(angle + k, angle + k + 1);
+        swap2(&angle[k], &angle[k+1]);
         swap2(P + (2 * k), P + (2 * k + 2));
         swap2(P + (2 * k + 1), P + (2 * k + 3));
       }
@@ -146,8 +155,8 @@ int SortAndRemoveDoubles2(double * P, int & nP, double =
epsilon_1)
=20
 // the marks will show what edges of blue intersect the red
=20
-int EdgeIntersections2(double * blue, double * red, int nsides, int markb[=
4], int markr[4],
-    double * points, int & nPoints)
+int EdgeIntersections2(double * blue, int nsBlue, double * red, int nsRed,
+    int markb[MAXEDGES], int markr[MAXEDGES], double * points, int & nPoin=
ts)
 {
   /* EDGEINTERSECTIONS computes edge intersections of two elements
    [P,n]=3DEdgeIntersections(X,Y) computes for the two given elements  * r=
ed
@@ -158,30 +167,20 @@ int EdgeIntersections2(double * blue, double * red, i=
nt nsides, int markb[4], in
    with blue are given.
    */
=20
-  // points is an array with 48 slots   (24 * 2 doubles)
+  // points is an array with enough slots   (24 * 2 doubles)
   nPoints =3D 0;
-  markb[0] =3D markb[1] =3D markb[2] =3D markb[3] =3D 0; // no neighbors o=
f red involved yet
-  markr[0] =3D markr[1] =3D markr[2] =3D markr[3] =3D 0;
-  /*for i=3D1:3                            % find all intersections of edg=
es
-   for j=3D1:3
-   b=3DY(:,j)-X(:,i);
-   A=3D[X(:,mod(i,3)+1)-X(:,i) -Y(:,mod(j,3)+1)+Y(:,j)];
-   if rank(A)=3D=3D2                   % edges not parallel
-   r=3DA\b;
-   if r(1)>=3D0 & r(1)<=3D1 & r(2)>=3D0 & r(2)<=3D1,  % intersection found
-   k=3Dk+1; P(:,k)=3DX(:,i)+r(1)*(X(:,mod(i,3)+1)-X(:,i)); n(i)=3D1;
-   end;
-   end;
-   end;
-   end;*/
-  for (int i =3D 0; i < nsides; i++)
-  {
-    for (int j =3D 0; j < nsides; j++)
+  for (int i=3D0; i<MAXEDGES; i++){
+    markb[i]=3Dmarkr[i] =3D 0;
+  }
+
+  for (int i =3D 0; i < nsBlue; i++)
+  {
+    for (int j =3D 0; j < nsRed; j++)
     {
       double b[2];
       double a[2][2]; // 2*2
-      int iPlus1 =3D (i + 1) % nsides;
-      int jPlus1 =3D (j + 1) % nsides;
+      int iPlus1 =3D (i + 1) % nsBlue;
+      int jPlus1 =3D (j + 1) % nsRed;
       for (int k =3D 0; k < 2; k++)
       {
         b[k] =3D red[2 * j + k] - blue[2 * i + k];
@@ -636,7 +635,7 @@ double oriented_spherical_angle(double * A, double * B,=
 double * C)
   CartVect a(A), b(B), c(C);
   CartVect normalOAB =3D a * b;
   CartVect normalOCB =3D c * b;
-  CartVect orient =3D (b-a)*(c-a);
+  CartVect orient =3D (c-b)*(a-b);
   double ang =3D angle(normalOAB, normalOCB); // this is between 0 and M_PI
   if (ang!=3Dang)
   {
@@ -644,8 +643,8 @@ double oriented_spherical_angle(double * A, double * B,=
 double * C)
     std::cout << a << " " << b << " " << c <<"\n";
     std::cout << ang << "\n";
   }
-  if (orient%a < 0)
-    return (2*M_PI-ang);// the other angle
+  if (orient%b < 0)
+    return (2*M_PI-ang);// the other angle, supplement
=20
   return ang;
=20
@@ -861,4 +860,136 @@ void departure_point_case1(CartVect & arrival_point, =
double t, double delta_t, C
   departure_point =3D spherical_to_cart(sph_dep);
   return;
 }
+// break the nonconvex quads into triangles; remove the quad from the set?=
 yes.
+// maybe radius is not needed;
+//
+ErrorCode enforce_convexity(Interface * mb, EntityHandle lset)
+{
+  // look at each quad; compute all 4 angles; if one is reflex, break alon=
g that diagonal
+  // replace it with 2 triangles, and remove from set;
+  // it should work for all polygons / tested first for case 1, with dt 0.=
5 (too much deformation)
+  // get all entities of dimension 2
+  // then get the connectivity, etc
+  Range inputRange;
+  ErrorCode rval =3D mb->get_entities_by_dimension(lset, 2, inputRange);
+  if (MB_SUCCESS !=3D rval)
+    return rval;
+
+  std::vector<double> coords;
+  coords.resize(3*MAXEDGES); // at most 10 vertices per polygon
+  // we should create a queue with new polygons that need processing for r=
eflex angles
+  //  (obtuse)
+  std::queue<EntityHandle> newPolys;
+  int brokenPolys=3D0;
+  Range::iterator eit =3D inputRange.begin();
+  while (eit !=3D inputRange.end() || !newPolys.empty())
+  {
+    EntityHandle eh;
+    if (eit !=3D inputRange.end())
+    {
+      eh =3D *eit;
+      eit++;
+    }
+    else
+    {
+      eh =3D newPolys.front();
+      newPolys.pop();
+    }
+    // get the nodes, then the coordinates
+    const EntityHandle * verts;
+    int num_nodes;
+    rval =3D mb->get_connectivity(eh, verts, num_nodes);
+    if (MB_SUCCESS !=3D rval)
+      return rval;
+    coords.resize(3 * num_nodes);
+    if (num_nodes < 4)
+      continue; // if already triangles, don't bother
+       // get coordinates
+    rval =3D mb->get_coords(verts, num_nodes, &coords[0]);
+    if (MB_SUCCESS !=3D rval)
+     return rval;
+    // compute each angle
+    bool alreadyBroken =3D false;
+
+    for (int i=3D0; i<num_nodes; i++)
+    {
+      double * A =3D &coords[3*i];
+      double * B =3D &coords[3*((i+1)%num_nodes)];
+      double * C =3D &coords[3*((i+2)%num_nodes)];
+      double angle =3D oriented_spherical_angle(A, B, C);
+      if (angle-M_PI > 0.) // even almost reflex is bad; break it!
+      {
+        if (alreadyBroken)
+        {
+          mb->list_entities(&eh, 1);
+          mb->list_entities(verts, num_nodes);
+          double * D =3D &coords[3*((i+3)%num_nodes)];
+          std::cout<< "ABC: " << angle << " \n";
+          std::cout<< "BCD: " << oriented_spherical_angle( B, C, D) << " \=
n";
+          std::cout<< "CDA: " << oriented_spherical_angle( C, D, A) << " \=
n";
+          std::cout<< "DAB: " << oriented_spherical_angle( D, A, B)<< " \n=
";
+          std::cout << " this quad has at least 2 angles > 180, it has ser=
ious issues\n";
+
+          return MB_FAILURE;
+        }
+        // the bad angle is at i+1;
+        // create 1 triangle and one polygon; add the polygon to the input=
 range, so
+        // it will be processed too
+        // also, add both to the set :) and remove the original polygon fr=
om the set
+        // break the next triangle, even though not optimal
+        // so create the triangle i+1, i+2, i+3; remove i+2 from original =
list
+        // even though not optimal in general, it is good enough.
+        EntityHandle conn3[3]=3D{ verts[ (i+1)%num_nodes],
+            verts[ (i+2)%num_nodes],
+            verts[ (i+3)%num_nodes] };
+        // create a polygon with num_nodes-1 vertices, and connectivity
+        // verts[i+1], verts[i+3], (all except i+2)
+        std::vector<EntityHandle> conn(num_nodes-1);
+        for (int j=3D1; j<num_nodes; j++)
+        {
+          conn[j-1]=3Dverts[(i+j+2)%num_nodes];
+        }
+        EntityHandle newElement;
+        rval =3D mb->create_element(MBTRI, conn3, 3, newElement);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+
+        rval =3D mb->add_entities(lset, &newElement, 1);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+        if (num_nodes =3D=3D 4)
+        {
+          // create another triangle
+          rval =3D mb->create_element(MBTRI, &conn[0], 3, newElement);
+          if (MB_SUCCESS !=3D rval)
+            return rval;
+        }
+        else
+        {
+          // create another polygon, and add it to the inputRange
+          rval =3D mb->create_element(MBPOLYGON, &conn[0], num_nodes-1, ne=
wElement);
+          if (MB_SUCCESS !=3D rval)
+            return rval;
+          newPolys.push(newElement); // because it has less number of edge=
s, the
+          // reverse should work to find it.
+        }
+        rval =3D mb->add_entities(lset, &newElement, 1);
+        if (MB_SUCCESS !=3D rval)
+          return rval;
+        mb->remove_entities(lset, &eh, 1);
+        brokenPolys++;
+        /*std::cout<<"remove: " ;
+        mb->list_entities(&eh, 1);
+
+        std::stringstream fff;
+        fff << "file0" <<  brokenQuads<< ".vtk";
+        mb->write_file(fff.str().c_str(), 0, 0, &lset, 1);*/
+        alreadyBroken=3Dtrue; // get out of the loop, element is broken
+      }
+    }
+  }
+  std::cout << brokenPolys << " concave polygons were decomposed in convex=
 ones \n";
+  return MB_SUCCESS;
+}
+
 } //namespace moab

diff --git a/tools/mbcslam/CslamUtils.hpp b/tools/mbcslam/CslamUtils.hpp
index e244138..c32a264 100644
--- a/tools/mbcslam/CslamUtils.hpp
+++ b/tools/mbcslam/CslamUtils.hpp
@@ -11,16 +11,20 @@
 #include "moab/Core.hpp"
 #include "moab/Interface.hpp"
=20
+// maximum number of edges on each convex polygon of interest
+#define MAXEDGES 10
+#define MAXEDGES2 20 // used for coordinates in plane
+
 namespace moab
 {
 double dist2(double * a, double * b);
 double area2D(double *a, double *b, double *c);
-int borderPointsOfXinY2(double * X, double * Y, int nsides, double * P, in=
t side[4]);
+int borderPointsOfXinY2(double * X, int nX, double * Y, int nY, double * P=
, int side[MAXEDGES]);
 int SortAndRemoveDoubles2(double * P, int & nP, double epsilon);
 // the marks will show what edges of blue intersect the red
=20
-int EdgeIntersections2(double * blue, double * red, int nsides, int markb[=
4], int markr[4],
-    double * points, int & nPoints);
+int EdgeIntersections2(double * blue, int nsBlue, double * red, int nsRed,
+    int markb[MAXEDGES], int markr[MAXEDGES], double * points, int & nPoin=
ts);
=20
 // vec utils related to gnomonic projection on a sphere
=20
@@ -122,5 +126,9 @@ double distance_on_great_circle(CartVect & p1, CartVect=
 & p2);
=20
 void departure_point_case1(CartVect & arrival_point, double t, double delt=
a_t, CartVect & departure_point);
=20
+// break the nonconvex quads into triangles; remove the quad from the set?=
 yes.
+// maybe radius is not needed;
+//
+ErrorCode enforce_convexity(Interface * mb, EntityHandle set);
 }
 #endif /* CSLAMUTILS_HPP_ */

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/fathomteam/moab/commits/2819cc86fa05/
Changeset:   2819cc86fa05
Branch:      None
User:        danwu
Date:        2013-07-01 15:48:48
Summary:     Added read_mpas_nc.cpp and mpasx1.642.t.2.nc (a small MPAS fil=
e), as a unit test for reading MPAS files. Fixed a few bugs to make this te=
st pass

Affected #:  11 files

diff --git a/MeshFiles/unittest/io/mpasx1.642.t.2.nc b/MeshFiles/unittest/i=
o/mpasx1.642.t.2.nc
new file mode 100644
index 0000000..f1e8c94
Binary files /dev/null and b/MeshFiles/unittest/io/mpasx1.642.t.2.nc differ

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index 30eb430..eb58441 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -93,16 +93,16 @@ ErrorCode NCHelper::read_variable_to_set_allocate(std::=
vector<ReadNC::VarData>&
         }
       }
=20
-      // set up other dimensions and counts
+      // Set up other dimensions and counts
       if (vdatas[i].varDims.empty()) {
-        // scalar variable
+        // Scalar variable
         vdatas[i].readDims[t].push_back(0);
         vdatas[i].readCounts[t].push_back(1);
       }
       else {
         for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
           if (tDim !=3D vdatas[i].varDims[idx]){
-            // push other variable dimensions, except time, which was alre=
ady pushed
+            // Push other variable dimensions, except time, which was alre=
ady pushed
             vdatas[i].readDims[t].push_back(0);
             vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
           }
@@ -314,6 +314,41 @@ ErrorCode NCHelper::convert_variable(ReadNC::VarData& =
var_data, int tstep_num)
   return MB_SUCCESS;
 }
=20
+ErrorCode ScdNCHelper::check_existing_mesh(EntityHandle file_set) {
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  int (&lDims)[6] =3D _readNC->lDims;
+
+  // Get the number of vertices
+  int num_verts;
+  ErrorCode rval =3D mbImpl->get_number_entities_by_dimension(file_set, 0,=
 num_verts);
+  ERRORR(rval, "Trouble getting number of vertices.");
+
+  // Check against parameters
+  if (num_verts > 0)
+  {
+    int expected_verts =3D (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1=
] + 1) * (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
+    if (num_verts !=3D expected_verts) {
+      ERRORR(MB_FAILURE, "Number of vertices doesn't match.");
+    }
+  }
+
+  // Check the number of elements too
+  int num_elems;
+  rval =3D mbImpl->get_number_entities_by_dimension(file_set, (-1 =3D=3D l=
Dims[2] ? 2 : 3), num_elems);
+  ERRORR(rval, "Trouble getting number of elements.");
+
+  // Check against parameters
+  if (num_elems > 0)
+  {
+    int expected_elems =3D (lDims[3] - lDims[0]) * (lDims[4] - lDims[1]) *=
 (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2]);
+    if (num_elems !=3D expected_elems) {
+      ERRORR(MB_FAILURE, "Number of elements doesn't match.");
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
 ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, const FileOptions& =
opts, EntityHandle file_set, Range& faces)
 {
   Interface*& mbImpl =3D _readNC->mbImpl;
@@ -592,7 +627,7 @@ ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allo=
cate(EntityHandle file_se
=20
       // Get the tag to read into
       if (!vdatas[i].varTags[t]) {
-        rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
+        rval =3D _readNC->get_tag_to_nonset(vdatas[i], tstep_nums[t], vdat=
as[i].varTags[t], vdatas[i].numLev);
         ERRORR(rval, "Trouble getting tag.");
       }
=20

diff --git a/src/io/NCHelper.hpp b/src/io/NCHelper.hpp
index 8f63336..0ac9b0c 100644
--- a/src/io/NCHelper.hpp
+++ b/src/io/NCHelper.hpp
@@ -25,6 +25,7 @@ public:
=20
   //! Interfaces to be implemented in child classes
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set) =3D 0;
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set) =3D 0;
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces) =3D 0;
   virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums) =3D 0;
   virtual std::string get_mesh_type_name() =3D 0;
@@ -53,6 +54,8 @@ public:
   virtual ~ScdNCHelper() {}
=20
 private:
+  //! Implementation of NCHelper::check_existing_mesh()
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set);
   //! Implementation of NCHelper::create_mesh()
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
   //! Implementation of NCHelper::read_variables()

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 60d63c0..e963564 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -191,10 +191,46 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOpt=
ions& opts, EntityHandle fi
   // with no corresponding variables
   _readNC->init_dims_with_no_cvars_info();
=20
-  // This check is for HOMME and other ucd mesh. When ReadNC class instance
-  // gets out of scope in a script (and deleted), the localGid will be lost
-  rval =3D _readNC->check_ucd_localGid(file_set);
-  ERRORR(rval, "Trouble checking local Gid for ucd mesh.");
+  return MB_SUCCESS;
+}
+
+// When noMesh option is used on this read, the old ReadNC class instance =
for last read can get out
+// of scope (and deleted). The old instance initialized localGidVerts prop=
erly when the mesh was
+// created, but it is now lost. The new instance (will not create the mesh=
 with noMesh option) has
+// to restore it based on the existing mesh from last read
+ErrorCode NCHelperHOMME::check_existing_mesh(EntityHandle tmp_set)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  bool& noMesh =3D _readNC->noMesh;
+  Range& localGid =3D _readNC->localGid;
+
+  if (noMesh && localGid.empty()) {
+    // We need to populate localGid range with the gids of vertices from t=
he tmp_set
+    // localGid is important in reading the variable data into the nodes
+    // also, for our purposes, localGid is truly the GLOBAL_ID tag data, n=
ot other
+    // file_id tags that could get passed around in other scenarios for pa=
rallel reading
+    // for nodal_partition, this local gid is easier, should be initialize=
d with only
+    // the owned nodes
+
+    // We need to get all vertices from tmp_set (it is the input set in no=
_mesh scenario)
+    Range local_verts;
+    ErrorCode rval =3D mbImpl->get_entities_by_dimension(tmp_set, 0, local=
_verts);
+    if (MB_FAILURE =3D=3D rval)
+      return rval;
+
+    if (!local_verts.empty()) {
+      std::vector<int> gids(local_verts.size());
+
+      // !IMPORTANT : this has to be the GLOBAL_ID tag
+      rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+
+      // This will do a smart copy
+      std::copy(gids.begin(), gids.end(), range_inserter(localGid));
+    }
+  }
=20
   return MB_SUCCESS;
 }
@@ -282,9 +318,9 @@ ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi=
, const FileOptions& opts
   int cornerVarId;
   success =3D NCFUNC(inq_varid)(connectId, "element_corners", &cornerVarId=
);
   ERRORS(success, "Failed to get variable id.");
-  NCDF_SIZE tmp_dims[2] =3D {0, 0}, tmp_counts[2] =3D {4, static_cast<size=
_t>(num_quads)};
+  NCDF_SIZE tmp_starts[2] =3D {0, 0}, tmp_counts[2] =3D {4, static_cast<si=
ze_t>(num_quads)};
   std::vector<int> tmp_conn(4 * num_quads), tmp_conn2(4 * num_quads);
-  success =3D NCFUNCAG(_vara_int)(connectId, cornerVarId, tmp_dims, tmp_co=
unts, &tmp_conn2[0] NCREQ);
+  success =3D NCFUNCAG(_vara_int)(connectId, cornerVarId, tmp_starts, tmp_=
counts, &tmp_conn2[0] NCREQ);
   ERRORS(success, "Failed to get temporary connectivity.");
   success =3D NCFUNC(close)(connectId);
   ERRORS(success, "Failed on close.");
@@ -620,7 +656,7 @@ ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_al=
locate(EntityHandle file_
=20
       // Get the tag to read into
       if (!vdatas[i].varTags[t]) {
-        rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
+        rval =3D _readNC->get_tag_to_nonset(vdatas[i], tstep_nums[t], vdat=
as[i].varTags[t], vdatas[i].numLev);
         ERRORR(rval, "Trouble getting tag.");
       }
=20

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index b7dc7ac..f900829 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -23,6 +23,8 @@ public:
 private:
   //! Implementation of NCHelper::init_mesh_vals()
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
+  //! Implementation of NCHelper::check_existing_mesh()
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set);
   //! Implementation of NCHelper::create_mesh()
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
   //! Implementation of NCHelper::get_mesh_type_name()

diff --git a/src/io/NCHelperMPAS.cpp b/src/io/NCHelperMPAS.cpp
index 9f66ead..0d4573f 100644
--- a/src/io/NCHelperMPAS.cpp
+++ b/src/io/NCHelperMPAS.cpp
@@ -174,8 +174,104 @@ ErrorCode NCHelperMPAS::init_mesh_vals(const FileOpti=
ons& opts, EntityHandle fil
   return MB_SUCCESS;
 }
=20
+// When noMesh option is used on this read, the old ReadNC class instance =
for last read can get out
+// of scope (and deleted). The old instance initialized some variables pro=
perly when the mesh was
+// created, but they are now lost. The new instance (will not create the m=
esh with noMesh option)
+// has to restore them based on the existing mesh from last read
+ErrorCode NCHelperMPAS::check_existing_mesh(EntityHandle tmp_set)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  bool& noMesh =3D _readNC->noMesh;
+
+  if (noMesh) {
+    ErrorCode rval;
+
+    if (localGidVerts.empty()) {
+      // Get all vertices from tmp_set (it is the input set in no_mesh sce=
nario)
+      Range local_verts;
+      rval =3D mbImpl->get_entities_by_dimension(tmp_set, 0, local_verts);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+
+      if (!local_verts.empty()) {
+        std::vector<int> gids(local_verts.size());
+
+        // !IMPORTANT : this has to be the GLOBAL_ID tag
+        rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
+        if (MB_FAILURE =3D=3D rval)
+          return rval;
+
+        // Restore localGidVerts
+        std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidVerts=
));
+        nLocalVertices =3D localGidVerts.size();
+      }
+    }
+
+    if (localGidEdges.empty()) {
+      // Get all edges from tmp_set (it is the input set in no_mesh scenar=
io)
+      Range local_edges;
+      rval =3D mbImpl->get_entities_by_dimension(tmp_set, 1, local_edges);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+
+      if (!local_edges.empty()) {
+        std::vector<int> gids(local_edges.size());
+
+        // !IMPORTANT : this has to be the GLOBAL_ID tag
+        rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_edges, &gids[0]);
+        if (MB_FAILURE =3D=3D rval)
+          return rval;
+
+        // Restore localGidEdges
+        std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidEdges=
));
+        nLocalEdges =3D localGidEdges.size();
+      }
+    }
+
+    if (localGidCells.empty()) {
+      // Get all cells from tmp_set (it is the input set in no_mesh scenar=
io)
+      Range local_cells;
+      rval =3D mbImpl->get_entities_by_dimension(tmp_set, 2, local_cells);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+
+      if (!local_cells.empty()) {
+        std::vector<int> gids(local_cells.size());
+
+        // !IMPORTANT : this has to be the GLOBAL_ID tag
+        rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_cells, &gids[0]);
+        if (MB_FAILURE =3D=3D rval)
+          return rval;
+
+        // Restore localGidCells
+        std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidCells=
));
+        nLocalCells =3D localGidCells.size();
+
+        // Restore cellHandleToGlobalID
+        Range::const_iterator rit;
+        int i;
+        for (rit =3D local_cells.begin(), i =3D 0; rit !=3D local_cells.en=
d(); ++rit, i++)
+          cellHandleToGlobalID[*rit] =3D gids[i];
+      }
+    }
+
+    // Restore numCellGroups
+    if (0 =3D=3D numCellGroups) {
+      Tag numCellGroupsTag;
+      rval =3D mbImpl->tag_get_handle("__NUM_CELL_GROUPS", 1, MB_TYPE_INTE=
GER, numCellGroupsTag);
+      rval =3D mbImpl->tag_get_data(numCellGroupsTag, &tmp_set, 1, &numCel=
lGroups);
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
 ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi, const FileOptions&=
 opts, EntityHandle file_set, Range& faces)
 {
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  const Tag*& mpFileIdTag =3D _readNC->mpFileIdTag;
   bool& isParallel =3D _readNC->isParallel;
 #ifdef USE_MPI
   ParallelComm*& myPcomm =3D _readNC->myPcomm;
@@ -208,62 +304,78 @@ ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scd=
i, const FileOptions& opts,
     nLocalCells++;
   start_cell_idx +=3D std::min(rank, iextra);
   start_cell_idx++; // 0 based -> 1 based
+
   localGidCells.insert(start_cell_idx, start_cell_idx + nLocalCells - 1);
=20
   // Read number of edges on each cell
   int nEdgesOnCellVarId;
   int success =3D NCFUNC(inq_varid)(_fileId, "nEdgesOnCell", &nEdgesOnCell=
VarId);
   ERRORS(success, "Failed to get variable id of nEdgesOnCell.");
-  NCDF_SIZE tmp_dims_1[1] =3D {static_cast<size_t>(start_cell_idx - 1)};
+  NCDF_SIZE tmp_starts_1[1] =3D {static_cast<size_t>(start_cell_idx - 1)};
   NCDF_SIZE tmp_counts_1[1] =3D {static_cast<size_t>(nLocalCells)};
   std::vector<int> num_edges_on_cell(nLocalCells);
-  success =3D NCFUNCAG(_vara_int)(_fileId, nEdgesOnCellVarId, tmp_dims_1, =
tmp_counts_1, &num_edges_on_cell[0] NCREQ);
+  success =3D NCFUNCAG(_vara_int)(_fileId, nEdgesOnCellVarId, tmp_starts_1=
, tmp_counts_1, &num_edges_on_cell[0] NCREQ);
   ERRORS(success, "Failed to read variable values of nEdgesOnCell.");
=20
   // Read vertices on each cell (connectivity)
   int verticesOnCellVarId;
   success =3D NCFUNC(inq_varid)(_fileId, "verticesOnCell", &verticesOnCell=
VarId);
   ERRORS(success, "Failed to get variable id of verticesOnCell.");
-  NCDF_SIZE tmp_dims_2[2] =3D {static_cast<size_t>(start_cell_idx - 1), 0};
+  NCDF_SIZE tmp_starts_2[2] =3D {static_cast<size_t>(start_cell_idx - 1), =
0};
   NCDF_SIZE tmp_counts_2[2] =3D {static_cast<size_t>(nLocalCells), maxCell=
Edges};
   std::vector<int> vertices_on_cell(nLocalCells * maxCellEdges);
-  success =3D NCFUNCAG(_vara_int)(_fileId, verticesOnCellVarId, tmp_dims_2=
, tmp_counts_2, &vertices_on_cell[0] NCREQ);
+  success =3D NCFUNCAG(_vara_int)(_fileId, verticesOnCellVarId, tmp_starts=
_2, tmp_counts_2, &vertices_on_cell[0] NCREQ);
   ERRORS(success, "Failed to read variable values of verticesOnCell.");
=20
   // Read edges on each cell
   int edgesOnCellVarId;
   success =3D NCFUNC(inq_varid)(_fileId, "edgesOnCell", &edgesOnCellVarId);
   ERRORS(success, "Failed to get variable id of edgesOnCell.");
-  NCDF_SIZE tmp_dims_3[2] =3D {static_cast<size_t>(start_cell_idx - 1), 0};
+  NCDF_SIZE tmp_starts_3[2] =3D {static_cast<size_t>(start_cell_idx - 1), =
0};
   NCDF_SIZE tmp_counts_3[2] =3D {static_cast<size_t>(nLocalCells), maxCell=
Edges};
   std::vector<int> edges_on_cell(nLocalCells * maxCellEdges);
-  success =3D NCFUNCAG(_vara_int)(_fileId, edgesOnCellVarId, tmp_dims_3, t=
mp_counts_3, &edges_on_cell[0] NCREQ);
+  success =3D NCFUNCAG(_vara_int)(_fileId, edgesOnCellVarId, tmp_starts_3,=
 tmp_counts_3, &edges_on_cell[0] NCREQ);
   ERRORS(success, "Failed to read variable values of edgesOnCell.");
=20
   // Divide cells into groups based on the number of edges
   std::vector<int> cells_with_n_edges[MAX_EDGES_PER_CELL + 1];
   for (int i =3D 0; i < nLocalCells; i++) {
+    int cell_index =3D start_cell_idx + i; // Global cell index
     int num_edges =3D num_edges_on_cell[i];
-    cells_with_n_edges[num_edges].push_back(i);
+    cells_with_n_edges[num_edges].push_back(cell_index);
   }
=20
   // For each non-empty cell group, create cells and set connectivity arra=
y initially based on file ids
   EntityHandle start_element;
   EntityHandle* conn_arr_cells_with_n_edges[MAX_EDGES_PER_CELL + 1];
   Range tmp_range;
+  void* data;
+  int count;
+  int* gid_data;
   std::set<int> local_vertices_set;
   std::set<int> local_edges_set;
+  numCellGroups =3D 0;
   for (int i =3D 3; i <=3D maxCellEdges; i++) {
     int num_cells =3D cells_with_n_edges[i].size();
     if (num_cells > 0) {
       numCellGroups++;
+
       rval =3D _readNC->readMeshIface->get_element_connect(num_cells, i, M=
BPOLYGON, 0, start_element, conn_arr_cells_with_n_edges[i], num_cells);
       tmp_range.insert(start_element, start_element + num_cells - 1);
       faces.insert(start_element, start_element + num_cells - 1);
=20
+      // Get ptr to gid memory for cells
+      Range cell_range(start_element, start_element + num_cells - 1);
+      rval =3D mbImpl->tag_iterate(mGlobalIdTag, cell_range.begin(), cell_=
range.end(), count, data);
+      ERRORR(rval, "Failed to get tag iterator on global id tag.");
+      assert(count =3D=3D (int) num_cells);
+      gid_data =3D (int*) data;
+      std::copy(cells_with_n_edges[i].begin(), cells_with_n_edges[i].end()=
, gid_data);
+
       for (int j =3D 0; j < num_cells; j++) {
-        int cell_idx =3D cells_with_n_edges[i][j];
-        CellEntityHandleToIndex[start_element + j] =3D cell_idx;
+        int cell_idx =3D cells_with_n_edges[i][j]; // Global cell index
+        cellHandleToGlobalID[start_element + j] =3D cell_idx;
+        cell_idx -=3D start_cell_idx; // Local cell index
         for (int k =3D 0; k < i; k++) {
           conn_arr_cells_with_n_edges[i][i * j + k] =3D vertices_on_cell[c=
ell_idx * maxCellEdges + k];
           local_vertices_set.insert(vertices_on_cell[cell_idx * maxCellEdg=
es + k]);
@@ -273,6 +385,13 @@ ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi=
, const FileOptions& opts,
     }
   }
=20
+  // Set tag for numCellGroups
+  Tag numCellGroupsTag =3D 0;
+  rval =3D mbImpl->tag_get_handle("__NUM_CELL_GROUPS", 1, MB_TYPE_INTEGER,=
 numCellGroupsTag, MB_TAG_SPARSE | MB_TAG_CREAT);
+  ERRORR(rval, "Trouble creating __NUM_CELL_GROUPS tag.");
+  rval =3D mbImpl->tag_set_data(numCellGroupsTag, &file_set, 1, &numCellGr=
oups);
+  ERRORR(rval, "Trouble setting data for __NUM_CELL_GROUPS tag.");
+
   // Collect localGid for vertices
   std::copy(local_vertices_set.rbegin(), local_vertices_set.rend(), range_=
inserter(localGidVerts));
   nLocalVertices =3D localGidVerts.size();
@@ -296,6 +415,23 @@ ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi=
, const FileOptions& opts,
     zptr[vert_idx] =3D zVertVals[(*rit) - 1];
   }
=20
+  // Get ptr to gid memory for vertices
+  Range vert_range(start_vertex, start_vertex + nLocalVertices - 1);
+  rval =3D mbImpl->tag_iterate(mGlobalIdTag, vert_range.begin(), vert_rang=
e.end(), count, data);
+  ERRORR(rval, "Failed to get tag iterator on global id tag.");
+  assert(count =3D=3D (int) nLocalVertices);
+  gid_data =3D (int*) data;
+  std::copy(localGidVerts.begin(), localGidVerts.end(), gid_data);
+
+  // Duplicate global id data, which will be used to resolve sharing
+  if (mpFileIdTag) {
+    rval =3D mbImpl->tag_iterate(*mpFileIdTag, vert_range.begin(), vert_ra=
nge.end(), count, data);
+    ERRORR(rval, "Failed to get tag iterator on file id tag.");
+    assert(count =3D=3D (int) nLocalVertices);
+    gid_data =3D (int*) data;
+    std::copy(localGidVerts.begin(), localGidVerts.end(), gid_data);
+  }
+
   // Create map from file ids to vertex handles
   std::map<EntityHandle, EntityHandle> vert_handles;
   for (rit =3D localGidVerts.begin(), vert_idx =3D 0; rit !=3D localGidVer=
ts.end(); ++rit, vert_idx++)
@@ -334,6 +470,14 @@ ErrorCode NCHelperMPAS::create_mesh(ScdInterface* scdi=
, const FileOptions& opts,
     conn_arr_edges[edge_idx + 1] =3D vert_handles[gloabl_vert_id_2];
   }
=20
+  // Get ptr to gid memory for edges
+  Range edge_range(start_edge, start_edge + nLocalEdges - 1);
+  rval =3D mbImpl->tag_iterate(mGlobalIdTag, edge_range.begin(), edge_rang=
e.end(), count, data);
+  ERRORR(rval, "Failed to get tag iterator on global id tag.");
+  assert(count =3D=3D (int) nLocalEdges);
+  gid_data =3D (int*) data;
+  std::copy(localGidEdges.begin(), localGidEdges.end(), gid_data);
+
   // Add new vertices, elements and edges to the file set
   rval =3D _readNC->mbImpl->add_entities(file_set, tmp_range);
   ERRORR(rval, "Couldn't add new vertices/faces/edges to file set.");
@@ -355,27 +499,8 @@ ErrorCode NCHelperMPAS::read_ucd_variable_setup(std::v=
ector<std::string>& var_na
   if (var_names.empty()) {
     for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
       ReadNC::VarData vd =3D (*mit).second;
-      if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd.v=
arDims.end()) && (std::find(vd.varDims.begin(),
-          vd.varDims.end(), cDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), levDim)
-          !=3D vd.varDims.end()))
-        vdatas.push_back(vd); // 3d data (Time, nCells, nVertLevels) read =
here
-      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D=
 vd.varDims.end()) && (std::find(vd.varDims.begin(),
-          vd.varDims.end(), eDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), levDim)
-          !=3D vd.varDims.end()))
-        vdatas.push_back(vd); // 3d data (Time, nEdges, nVertLevels) read =
here
-      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D=
 vd.varDims.end()) && (std::find(vd.varDims.begin(),
-          vd.varDims.end(), vDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), levDim)
-          !=3D vd.varDims.end()))
-        vdatas.push_back(vd); // 3d data (Time, nVertices, nVertLevels) re=
ad here
-      else if (1 =3D=3D vd.varDims.size())
-        vsetdatas.push_back(vd);
-    }
-  }
-  else {
-    for (unsigned int i =3D 0; i < var_names.size(); i++) {
-      mit =3D varInfo.find(var_names[i]);
-      if (mit !=3D varInfo.end()) {
-        ReadNC::VarData vd =3D (*mit).second;
+      if (3 =3D=3D vd.varDims.size())
+      {
         if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd=
.varDims.end()) && (std::find(vd.varDims.begin(),
             vd.varDims.end(), cDim) !=3D vd.varDims.end()) && (std::find(v=
d.varDims.begin(), vd.varDims.end(), levDim)
             !=3D vd.varDims.end()))
@@ -388,6 +513,30 @@ ErrorCode NCHelperMPAS::read_ucd_variable_setup(std::v=
ector<std::string>& var_na
             vd.varDims.end(), vDim) !=3D vd.varDims.end()) && (std::find(v=
d.varDims.begin(), vd.varDims.end(), levDim)
             !=3D vd.varDims.end()))
           vdatas.push_back(vd); // 3d data (Time, nVertices, nVertLevels) =
read here
+      }
+      else if (1 =3D=3D vd.varDims.size())
+        vsetdatas.push_back(vd);
+    }
+  }
+  else {
+    for (unsigned int i =3D 0; i < var_names.size(); i++) {
+      mit =3D varInfo.find(var_names[i]);
+      if (mit !=3D varInfo.end()) {
+        ReadNC::VarData vd =3D (*mit).second;
+        if (3 =3D=3D vd.varDims.size()) {
+          if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D =
vd.varDims.end()) && (std::find(vd.varDims.begin(),
+              vd.varDims.end(), cDim) !=3D vd.varDims.end()) && (std::find=
(vd.varDims.begin(), vd.varDims.end(), levDim)
+              !=3D vd.varDims.end()))
+            vdatas.push_back(vd); // 3d data (Time, nCells, nVertLevels) r=
ead here
+          else if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) =
!=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+              vd.varDims.end(), eDim) !=3D vd.varDims.end()) && (std::find=
(vd.varDims.begin(), vd.varDims.end(), levDim)
+              !=3D vd.varDims.end()))
+            vdatas.push_back(vd); // 3d data (Time, nEdges, nVertLevels) r=
ead here
+          else if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) =
!=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+              vd.varDims.end(), vDim) !=3D vd.varDims.end()) && (std::find=
(vd.varDims.begin(), vd.varDims.end(), levDim)
+              !=3D vd.varDims.end()))
+            vdatas.push_back(vd); // 3d data (Time, nVertices, nVertLevels=
) read here
+        }
         else if (1 =3D=3D vd.varDims.size())
           vsetdatas.push_back(vd);
       }
@@ -488,7 +637,7 @@ ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset_all=
ocate(EntityHandle file_s
=20
       // Get the tag to read into
       if (!vdatas[i].varTags[t]) {
-        rval =3D _readNC->get_tag(vdatas[i], tstep_nums[t], vdatas[i].varT=
ags[t], vdatas[i].numLev);
+        rval =3D _readNC->get_tag_to_nonset(vdatas[i], tstep_nums[t], vdat=
as[i].varTags[t], vdatas[i].numLev);
         ERRORR(rval, "Trouble getting tag.");
       }
=20
@@ -649,7 +798,8 @@ ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset_asy=
nc(EntityHandle file_set,
               ERRORR(rval, "Failed to get tag iterator.");
=20
               for (int j =3D 0; j < count; j++) {
-                int cell_idx =3D CellEntityHandleToIndex[*(iter + j)];
+                int cell_idx =3D cellHandleToGlobalID[*(iter + j)]; // Glo=
bal cell index
+                cell_idx -=3D localGidCells[0]; // Local cell index
                 for (int level =3D 0; level < vdatas[i].numLev; level++)
                   ((double*) ptr)[j * vdatas[i].numLev + level] =3D tmpdou=
bledata[cell_idx * vdatas[i].numLev + level];
               }
@@ -788,7 +938,8 @@ ErrorCode NCHelperMPAS::read_ucd_variable_to_nonset(Ent=
ityHandle file_set, std::
               ERRORR(rval, "Failed to get tag iterator.");
=20
               for (int j =3D 0; j < count; j++) {
-                int cell_idx =3D CellEntityHandleToIndex[*(iter + j)];
+                int cell_idx =3D cellHandleToGlobalID[*(iter + j)]; // Glo=
bal cell index
+                cell_idx -=3D localGidCells[0]; // Local cell index
                 for (int level =3D 0; level < vdatas[i].numLev; level++)
                   ((double*) ptr)[j * vdatas[i].numLev + level] =3D tmpdou=
bledata[cell_idx * vdatas[i].numLev + level];
               }

diff --git a/src/io/NCHelperMPAS.hpp b/src/io/NCHelperMPAS.hpp
index 7f056ec..70deab0 100644
--- a/src/io/NCHelperMPAS.hpp
+++ b/src/io/NCHelperMPAS.hpp
@@ -23,6 +23,8 @@ public:
 private:
   //! Implementation of NCHelper::init_mesh_vals()
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
+  //! Implementation of NCHelper::check_existing_mesh()
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set);
   //! Implementation of NCHelper::create_mesh()
   virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& quads);
   //! Implementation of NCHelper::get_mesh_type_name()
@@ -50,7 +52,7 @@ private:
   int maxCellEdges;
   int numCellGroups;
   std::vector<int> verticesOnEdge;
-  std::map<EntityHandle, int> CellEntityHandleToIndex;
+  std::map<EntityHandle, int> cellHandleToGlobalID;
   Range facesOwned;
 };
=20

diff --git a/src/io/ReadNC.cpp b/src/io/ReadNC.cpp
index dddf21c..78c3fbc 100644
--- a/src/io/ReadNC.cpp
+++ b/src/io/ReadNC.cpp
@@ -10,7 +10,6 @@
 #include <iostream>
 #include <sstream>
 #include <map>
-#include <dirent.h>
=20
 #include "moab/Core.hpp"
 #include "moab/ReaderIface.hpp"
@@ -20,13 +19,11 @@
 #include "moab/ScdInterface.hpp"
 #include "moab/SpectralMeshTool.hpp"
=20
-//#include "bil.h"
-
 #define ERRORR(rval, str) \
-    if (MB_SUCCESS !=3D rval) {readMeshIface->report_error("%s", str); ret=
urn rval;}
+  if (MB_SUCCESS !=3D rval) { readMeshIface->report_error("%s", str); retu=
rn rval; }
=20
 #define ERRORS(err, str) \
-    if (err) {readMeshIface->report_error("%s", str); return MB_FAILURE;}
+  if (err) { readMeshIface->report_error("%s", str); return MB_FAILURE; }
=20
 namespace moab {
=20
@@ -36,8 +33,7 @@ ReaderIface* ReadNC::factory(Interface* iface) {
=20
 ReadNC::ReadNC(Interface* impl) :
   mbImpl(impl), CPU_WORD_SIZE(-1), IO_WORD_SIZE(-1), fileId(-1), tMin(-1),=
 tMax(-1), iDim(-1), jDim(-1), tDim(-1), iCDim(-1),
-  jCDim(-1), numUnLim(-1), mCurrentMeshHandle(0), startVertex(0), startEle=
m(0), mGlobalIdTag(0), mpFileIdTag(NULL), max_line_length(-1),
-  max_str_length(-1), vertexOffset(0), dbgOut(stderr), isParallel(false), =
partMethod(-1),
+  jCDim(-1), numUnLim(-1), mGlobalIdTag(0), mpFileIdTag(NULL), dbgOut(stde=
rr), isParallel(false), partMethod(-1),
 #ifdef USE_MPI
   myPcomm(NULL),=20
 #endif
@@ -73,15 +69,8 @@ void ReadNC::reset() {
   iDim =3D jDim =3D tDim =3D -1;
   iCDim =3D jCDim =3D -1;
   numUnLim =3D -1;
-  mCurrentMeshHandle =3D 0;
-  startVertex =3D startElem =3D 0;
   mGlobalIdTag =3D 0;
-  max_line_length =3D -1;
-  max_str_length =3D -1;
-  vertexOffset =3D 0;
   dbgOut =3D stderr;
-  mCurrentMeshHandle =3D 0;
-  vertexOffset =3D 0;
=20
 #ifdef USE_MPI
   myPcomm =3D NULL;
@@ -102,18 +91,16 @@ ErrorCode ReadNC::load_file(const char* file_name, con=
st EntityHandle* file_set,
   std::vector<std::string> var_names;
   std::vector<int> tstep_nums;
   std::vector<double> tstep_vals;
-  /*
-  if (file_id_tag)
-    mGlobalIdTag =3D *file_id_tag;
-  else {
-    */
-    //! get and cache predefined tag handles
+
+  // Get and cache predefined tag handles
   int dum_val =3D 0;
   rval =3D mbImpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, =
mGlobalIdTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum_val);
   if (MB_SUCCESS !=3D rval)
     return rval;
-  mpFileIdTag =3D file_id_tag; // store the pointer to the tag ; if not nu=
ll, set when global id tag
-  // is set too, with the same data , duplicated
+
+  // Store the pointer to the tag; if not null, set when global id tag
+  // is set too, with the same data, duplicated
+  mpFileIdTag =3D file_id_tag;
=20
   std::string partition_tag_name;
   rval =3D parse_options(opts, var_names, tstep_nums, tstep_vals);
@@ -135,28 +122,11 @@ ErrorCode ReadNC::load_file(const char* file_name, co=
nst EntityHandle* file_set,
=20
   ERRORS(success, "Trouble opening file.");
=20
-  // BIL data
-
-  if (BIL_mode_enabled(file_name)) {
-
-    rval =3D get_BIL_dir();
-    ERRORS(rval, "Failed to find directory with BIL data.");
-
-    dbgOut.tprintf(1, "Reading BIL data from directory: %s\n", BIL_dir.c_s=
tr());
-
-    rval =3D load_BIL(BIL_dir, file_set, opts, file_id_tag);
-    ERRORR(rval, "Trouble reading BIL data.");
-
-    return rval;
-  }
-
-  // end of BIL
-
   // Read the header (num dimensions, dimensions, num variables, global at=
tribs)
   rval =3D read_header();
-  ERRORR(rval, " ");
+  ERRORR(rval, "Trouble reading file header.");
=20
-  // make sure there's a file set to put things in
+  // Make sure there's a file set to put things in
   EntityHandle tmp_set;
   if (noMesh && !file_set) {
     ERRORR(MB_FAILURE, "NOMESH option requires non-NULL file set on input.=
\n");
@@ -168,7 +138,7 @@ ErrorCode ReadNC::load_file(const char* file_name, cons=
t EntityHandle* file_set,
   else
     tmp_set =3D *file_set;
=20
-  // get the scd interface
+  // Get the scd interface
   ScdInterface *scdi =3D NULL;
   rval =3D mbImpl->query_interface(scdi);
   if (!scdi)
@@ -177,21 +147,25 @@ ErrorCode ReadNC::load_file(const char* file_name, co=
nst EntityHandle* file_set,
   if (myHelper !=3D NULL)
     delete myHelper;
=20
+  // Get appropriate NC helper instance based on information read from the=
 header
   myHelper =3D NCHelper::get_nc_helper(this, fileId, opts);
   if (myHelper =3D=3D NULL) {
     ERRORR(MB_FAILURE, "Failed to get NCHelper class instance.");
   }
=20
+  // Initialize mesh values
   rval =3D myHelper->init_mesh_vals(opts, tmp_set);
   ERRORR(rval, "Trouble initializing mesh values.");
=20
-  // Create mesh vertex/edge/face sequences
-  Range faces;
+  // Check existing mesh from last read
   if (noMesh && !noVars) {
-    rval =3D check_verts_faces(tmp_set);
-    ERRORR(rval, "Mesh characteristics didn't match from last read.\n");
+    rval =3D myHelper->check_existing_mesh(tmp_set);
+    ERRORR(rval, "Trouble checking mesh from last read.\n");
   }
-  else if (!noMesh) {
+
+  // Create mesh vertex/edge/face sequences
+  Range faces;
+  if (!noMesh) {
     rval =3D myHelper->create_mesh(scdi, opts, tmp_set, faces);
     ERRORR(rval, "Trouble creating mesh.");
   }
@@ -203,20 +177,23 @@ ErrorCode ReadNC::load_file(const char* file_name, co=
nst EntityHandle* file_set,
       return rval;
   }
   else {
-    // read dimension variable by default, the ones that are also variables
+    // Read dimension variable by default, the ones that are also variables
     std::vector<std::string> filteredDimNames;
     for (unsigned int i =3D 0; i < dimNames.size(); i++) {
       std::map<std::string, VarData>::iterator mit =3D varInfo.find(dimNam=
es[i]);
       if (mit !=3D varInfo.end())
         filteredDimNames.push_back(dimNames[i]);
     }
-    rval =3D myHelper->read_variables(tmp_set, filteredDimNames, tstep_num=
s);
-    if (MB_FAILURE =3D=3D rval)
-      return rval;
+
+    if (!filteredDimNames.empty()) {
+      rval =3D myHelper->read_variables(tmp_set, filteredDimNames, tstep_n=
ums);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+    }
   }
=20
 #ifdef USE_MPI
-  // create partition set, and populate with elements
+  // Create partition set, and populate with elements
   if (isParallel) {
     EntityHandle partn_set;
     rval =3D mbImpl->create_meshset(MESHSET_SET, partn_set);
@@ -234,11 +211,11 @@ ErrorCode ReadNC::load_file(const char* file_name, co=
nst EntityHandle* file_set,
=20
     myPcomm->partition_sets().insert(partn_set);
=20
-    //write partition tag name on partition set
+    // Write partition tag name on partition set
     Tag part_tag;
     rval =3D mbImpl->tag_get_handle(partitionTagName.c_str(), 1, MB_TYPE_I=
NTEGER, part_tag);
     if (MB_SUCCESS !=3D rval) {
-      // fall back to the partition tag
+      // Fall back to the partition tag
       part_tag =3D myPcomm->partition_tag();
     }
=20
@@ -249,85 +226,21 @@ ErrorCode ReadNC::load_file(const char* file_name, co=
nst EntityHandle* file_set,
   }
 #endif
=20
-  // create nc conventional tags when loading header info only
+  // Create nc conventional tags when loading header info only
   if (noMesh && noVars) {
-    rval =3D create_tags(scdi, tmp_set, tstep_nums);
+    rval =3D create_conventional_tags(scdi, tmp_set, tstep_nums);
     ERRORR(rval, "Trouble creating nc conventional tags.");
   }
=20
   mbImpl->release_interface(scdi);
=20
-  // close the file
+  // Close the file
   success =3D NCFUNC(close)(fileId);
   ERRORS(success, "Trouble closing file.");
=20
   return MB_SUCCESS;
 }
    =20
-ErrorCode ReadNC::load_BIL(std::string, const EntityHandle*, const FileOpt=
ions&, const Tag*) {
-  /*
-   BIL_Init( MPI_COMM_WORLD );
-
-   void ** buffer;
-
-   DIR * dir;
-   struct dirent * ent;
-   dir =3D opendir(dir_name.c_str());
-   if (dir !=3D NULL) {
-   while ((ent =3D readdir(dir)) !=3D NULL) {
-   if (strlen(ent->d_name) > 3) { //filter out . and ..
-
-   dbgOut.tprintf(1,"reading block from %s\n",ent->d_name);
-
-   int num_dims =3D 3;
-   int time_d =3D 1;
-   int lev_d  =3D 26;
-   int ncol_d =3D 3458;
-   int block_start[3] =3D {0,0,0};
-   int block_size[3]  =3D {time_d, lev_d, ncol_d};
-   const char * file_name =3D ent->d_name;
-   const char * var_name =3D "T";
-
-   BIL_Add_block_nc(num_dims, block_start, block_size,
-   file_name, var_name, buffer);
-   }
-   }
-   closedir (dir);
-   }
-
-   BIL_Read();
-
-   BIL_Finalize();
-   */
-  return MB_SUCCESS;
-}
-
-ErrorCode ReadNC::get_BIL_dir() {
-  std::map<std::string, AttData> dirAtt;
-  ErrorCode result =3D get_attributes(NC_GLOBAL, 1, dirAtt);
-  ERRORR(result, "Failed to get BIL_DIR attribute");
-
-  std::string attname;
-  std::map<std::string, AttData>::iterator attIt =3D dirAtt.find("BIL_DIR"=
);
-
-  unsigned int sz =3D attIt->second.attLen;
-  char *att_data =3D (char *) malloc(sz + 1);
-  att_data[sz] =3D '\000';
-  int success =3D NCFUNC(get_att_text)(fileId, attIt->second.attVarId, att=
It->second.attName.c_str(), (char*) att_data);
-  ERRORS(success, "Trouble getting BIL data directory.");
-  BIL_dir =3D std::string(att_data);
-
-  return MB_SUCCESS;
-}
-
-bool ReadNC::BIL_mode_enabled(const char* file_name) {
-  std::string file_path =3D std::string(file_name);
-  int idx =3D file_path.find_last_of("/");
-  std::string file =3D file_path.substr(idx + 1);
-
-  return (file =3D=3D "BIL_DIR.nc");
-}
-
 ErrorCode ReadNC::parse_options(const FileOptions& opts, std::vector<std::=
string>& var_names, std::vector<int>& tstep_nums,
                                 std::vector<double>& tstep_vals) {
   int tmpval;
@@ -420,65 +333,6 @@ ErrorCode ReadNC::parse_options(const FileOptions& opt=
s, std::vector<std::string
   return MB_SUCCESS;
 }
=20
-// In a script, the ReadNC class instance can get out of scope (and delete=
d). In that
-// case, the localGid (initialized properly when the mesh was created) wil=
l be lost,
-// so it has to be properly refilled with the Global Ids of the local vert=
ices
-ErrorCode ReadNC::check_ucd_localGid(EntityHandle tmp_set) {
-  if (noMesh && localGid.empty()) {
-    // we need to populate localGid range with the gids of vertices from t=
he tmp_set
-    // localGid is important in reading the variable data into the nodes
-    // also, for our purposes, localGid is truly the GLOBAL_ID tag data, n=
ot other
-    // file_id tags that could get passed around in other scenarios for pa=
rallel reading
-    // for nodal_partition, this local gid is easier, should be initialize=
d with only
-    // the owned nodes
-
-    // we need to get all vertices from tmp_set (it is the input set in no=
_mesh scenario)
-    Range local_verts;
-    ErrorCode rval =3D mbImpl->get_entities_by_dimension(tmp_set, 0, local=
_verts);
-    if (MB_FAILURE =3D=3D rval)
-      return rval;
-
-    if (!local_verts.empty()) {
-      std::vector<int> gids(local_verts.size());
-
-      // !IMPORTANT : this has to be the GLOBAL_ID tag
-      rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
-      if (MB_FAILURE =3D=3D rval)
-        return rval;
-
-      // this will do a smart copy
-      std::copy(gids.begin(), gids.end(), range_inserter(localGid));
-    }
-  }
-
-  return MB_SUCCESS;
-}
-
-ErrorCode ReadNC::check_verts_faces(EntityHandle file_set) {
-  // check parameters on this read against what was on the mesh from last =
read
-  // get the number of vertices
-  int num_verts;
-  ErrorCode rval =3D mbImpl->get_number_entities_by_dimension(file_set, 0,=
 num_verts);
-  ERRORR(rval, "Trouble getting number of vertices.");
-
-  // check against parameters
-  //int expected_verts =3D (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1=
] + 1) * (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
-  //if (num_verts !=3D expected_verts)
-  //ERRORR(MB_FAILURE, "Number of vertices doesn't match.");
-
-  // check the number of elements too
-  int num_elems;
-  rval =3D mbImpl->get_number_entities_by_dimension(file_set, (-1 =3D=3D l=
Dims[2] ? 2 : 3), num_elems);
-  ERRORR(rval, "Trouble getting number of elements.");
-
-  // check against parameters
-  //int expected_elems =3D (lDims[3] - lDims[0]) * (lDims[4] - lDims[1]) *=
 (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2]);
-  //if (num_elems !=3D expected_elems)
-  //ERRORR(MB_FAILURE, "Number of elements doesn't match.");
-
-  return MB_SUCCESS;
-}
-
 ErrorCode ReadNC::get_tag_to_set(VarData& var_data, int tstep_num, Tag& ta=
gh) {
   std::ostringstream tag_name;
   if ((!var_data.has_t) || (var_data.varDims.size() <=3D 1))
@@ -515,7 +369,7 @@ ErrorCode ReadNC::get_tag_to_set(VarData& var_data, int=
 tstep_num, Tag& tagh) {
   return rval;
 }
=20
-ErrorCode ReadNC::get_tag(VarData& var_data, int tstep_num, Tag& tagh, int=
 num_lev) {
+ErrorCode ReadNC::get_tag_to_nonset(VarData& var_data, int tstep_num, Tag&=
 tagh, int num_lev) {
   std::ostringstream tag_name;
   if (!tstep_num) {
     std::string tmp_name =3D var_data.varName + "0";
@@ -654,7 +508,7 @@ ErrorCode ReadNC::get_attributes(int var_id, int num_at=
ts, std::map<std::string,
 }
=20
 ErrorCode ReadNC::get_dimensions(int file_id, std::vector<std::string>& di=
m_names, std::vector<int>& dim_vals) {
-  // get the number of dimensions
+  // Get the number of dimensions
   int num_dims;
   int success =3D NCFUNC(inq_ndims)(file_id, &num_dims);
   ERRORS(success, "Trouble getting number of dimensions.");
@@ -747,7 +601,7 @@ ErrorCode ReadNC::read_tag_values(const char*, const ch=
ar*, const FileOptions&,
   return MB_FAILURE;
 }
=20
-ErrorCode ReadNC::create_tags(ScdInterface* scdi, EntityHandle file_set, c=
onst std::vector<int>& tstep_nums) {
+ErrorCode ReadNC::create_conventional_tags(ScdInterface* scdi, EntityHandl=
e file_set, const std::vector<int>& tstep_nums) {
   ErrorCode rval;
   std::string tag_name;
=20

diff --git a/src/io/ReadNC.hpp b/src/io/ReadNC.hpp
index 39b3f43..3e44e5a 100644
--- a/src/io/ReadNC.hpp
+++ b/src/io/ReadNC.hpp
@@ -118,18 +118,17 @@ private:
   class VarData
   {
     public:
-    VarData() : varId(-1), numAtts(-1), read(false), entLoc(ENTLOCSET), nu=
mLev(1), sz(0), has_t(false) {}
+    VarData() : varId(-1), numAtts(-1), entLoc(ENTLOCSET), numLev(1), sz(0=
), has_t(false) {}
     int varId;
     int numAtts;
     nc_type varDataType;
-    std::vector<int> varDims; // the dimension indices making up this mult=
i-dimensional variable
-    std::map<std::string,AttData> varAtts;
+    std::vector<int> varDims; // The dimension indices making up this mult=
i-dimensional variable
+    std::map<std::string, AttData> varAtts;
     std::string varName;
-    bool read;
-    std::vector<Tag> varTags; // one tag for each timestep, varTags[t]
+    std::vector<Tag> varTags; // One tag for each time step, varTags[t]
     std::vector<void*> varDatas;
-    std::vector<std::vector<NCDF_SIZE> > readDims; // start value for this=
 [t][dim]
-    std::vector<std::vector<NCDF_SIZE> > readCounts; // number of data val=
ues for this [t][dim]
+    std::vector<std::vector<NCDF_SIZE> > readDims; // Start value for this=
 [t][dim]
+    std::vector<std::vector<NCDF_SIZE> > readCounts; // Number of data val=
ues for this [t][dim]
     int entLoc;
     int numLev;
     int sz;
@@ -158,14 +157,8 @@ private:
   ErrorCode read_coordinate(const char* var_name, int lmin, int lmax,
                             std::vector<double>& cvals);
=20
-  //! number of dimensions in this nc file
-  unsigned int number_dimensions();
-
   //! make sure that localGid is properly initialized for ucd mesh
-  ErrorCode check_ucd_localGid(EntityHandle file_set);
-
-  //! check number of vertices and faces against what's already in file_set
-  ErrorCode check_verts_faces(EntityHandle file_set);
+  //ErrorCode check_ucd_localGid(EntityHandle file_set);
=20
   ErrorCode parse_options(const FileOptions& opts,
                           std::vector<std::string>& var_names,
@@ -174,11 +167,11 @@ private:
=20
   ErrorCode get_tag_to_set(VarData& var_data, int tstep_num, Tag& tagh);
=20
-  ErrorCode get_tag(VarData &var_data, int tstep_num, Tag &tagh, int num_l=
ev);
+  ErrorCode get_tag_to_nonset(VarData& var_data, int tstep_num, Tag& tagh,=
 int num_lev);
=20
   //! create nc conventional tags
-  ErrorCode create_tags(ScdInterface* scdi, EntityHandle file_set,
-                        const std::vector<int> &tstep_nums);
+  ErrorCode create_conventional_tags(ScdInterface* scdi, EntityHandle file=
_set,
+                                     const std::vector<int>& tstep_nums);
=20
   //! create a character string attString of attMap.  with '\0'
   //! terminating each attribute name, ';' separating the data type
@@ -196,15 +189,6 @@ private:
   //! coordinate variables - this info is used for creating tags
   void init_dims_with_no_cvars_info();
=20
-  ErrorCode load_BIL(std::string dir_name,
-                     const EntityHandle* file_set,
-                     const FileOptions& opts,
-                     const Tag* file_id_tag);
-
-  ErrorCode get_BIL_dir();
-
-  bool BIL_mode_enabled(const char* file_name);
-
   template <typename T> ErrorCode kji_to_jik(size_t ni, size_t nj, size_t =
nk, void* dest, T* source)
   {
     size_t nik =3D ni * nk, nij =3D ni * nj;
@@ -292,12 +276,6 @@ private:
   //! number of the dimension of unlimited dimension, if any
   int numUnLim;
=20
-  //! Meshset Handle for the mesh that is currently being read
-  EntityHandle mCurrentMeshHandle;
-
-  //! starting vertex and element handles for this read
-  EntityHandle startVertex, startElem;
-
   //! Cached tags for reading. Note that all these tags are defined when t=
he
   //! core is initialized.
   Tag mGlobalIdTag;
@@ -306,15 +284,10 @@ private:
   //! it gets deleted at the end of resolve sharing, but it will have same=
 data
   //! as the global id tag
   //! global id tag is preserved, and is needed later on.
-  const Tag * mpFileIdTag;
-
-  int max_line_length, max_str_length;
-
-  //! range of entities in initial mesh, before this read
-  Range initRange;
+  const Tag* mpFileIdTag;
=20
   //! offset of first vertex id
-  int vertexOffset;
+  //int vertexOffset;
=20
   //! debug stuff
   DebugOutput dbgOut;
@@ -337,35 +310,20 @@ private:
   //! parallel data object, to be cached with ScdBox
   ScdParData parData;
=20
-  //! directory where data is stored for BIL reader
-  std::string BIL_dir;
-
 #ifdef USE_MPI
   ParallelComm* myPcomm;
 #endif
=20
-  //! read option
+  //! Read options
   bool noMesh;
-
-  //! read option
   bool noVars;
-
-  //! read option
   bool spectralMesh;
-
-  //! read option
   std::string partitionTagName;
=20
   //! Helper class instance
   NCHelper* myHelper;
 };
=20
-//! inline functions
-inline unsigned int ReadNC::number_dimensions()=20
-{
-  return dimVals.size();
-}
-
 } // namespace moab
=20
 #endif

diff --git a/test/io/Makefile.am b/test/io/Makefile.am
index 3eeeaf1..d9bab74 100644
--- a/test/io/Makefile.am
+++ b/test/io/Makefile.am
@@ -12,7 +12,7 @@ AM_CPPFLAGS +=3D -DSRCDIR=3D$(srcdir) \
=20
 if NETCDF_FILE
   EXODUS_TEST =3D exodus_test
-  NC_TEST =3D read_nc read_ucd_nc
+  NC_TEST =3D read_nc read_ucd_nc read_mpas_nc
 else
   EXODUS_TEST =3D=20
   NC_TEST =3D=20
@@ -58,6 +58,7 @@ gmsh_test_SOURCES =3D $(srcdir)/../TestUtil.hpp gmsh_test=
.cc
 nastran_test_SOURCES =3D $(srcdir)/../TestUtil.hpp nastran_test.cc
 read_nc_SOURCES =3D $(srcdir)/../TestUtil.hpp read_nc.cpp
 read_ucd_nc_SOURCES =3D $(srcdir)/../TestUtil.hpp read_ucd_nc.cpp
+read_mpas_nc_SOURCES =3D $(srcdir)/../TestUtil.hpp read_mpas_nc.cpp
 ideas_test_SOURCES =3D $(srcdir)/../TestUtil.hpp ideas_test.cc
 stl_test_SOURCES =3D $(srcdir)/../TestUtil.hpp stl_test.cc
 smf_test_SOURCES =3D $(srcdir)/../TestUtil.hpp smf_test.cc

diff --git a/test/io/read_mpas_nc.cpp b/test/io/read_mpas_nc.cpp
new file mode 100644
index 0000000..49ce0e2
--- /dev/null
+++ b/test/io/read_mpas_nc.cpp
@@ -0,0 +1,267 @@
+#include "TestUtil.hpp"
+#include "moab/Core.hpp"
+
+using namespace moab;
+
+#ifdef MESHDIR
+static const char example[] =3D STRINGIFY(MESHDIR) "/io/mpasx1.642.t.2.nc";
+#else
+static const char example[] =3D "/io/mpasx1.642.t.2.nc";
+#endif
+
+#ifdef USE_MPI
+#include "moab_mpi.h"
+#endif
+
+void test_read_all();
+void test_read_onevar();
+void test_read_onetimestep();
+void test_read_nomesh();
+void test_read_novars();
+
+ErrorCode get_options(std::string& opts);
+
+int main(int argc, char* argv[])
+{
+  int result =3D 0;
+
+#ifdef USE_MPI
+  int fail =3D MPI_Init(&argc, &argv);
+  if (fail)
+    return 1;
+#else
+  argv[0] =3D argv[argc-argc]; // To remove the warnings in serial mode ab=
out unused variables
+#endif
+
+  //result +=3D RUN_TEST(test_read_all);
+  //result +=3D RUN_TEST(test_read_onevar);
+  //result +=3D RUN_TEST(test_read_onetimestep);
+  //result +=3D RUN_TEST(test_read_nomesh);
+  result +=3D RUN_TEST(test_read_novars);
+
+#ifdef USE_MPI
+  fail =3D MPI_Finalize();
+  if (fail)
+    return 1;
+#endif
+
+  return result;
+}
+
+void test_read_all()
+{
+  const double eps =3D 1e-20;
+  double val[2];
+  Core moab;
+  Interface& mb =3D moab;
+
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
+
+  rval =3D mb.load_file(example, NULL, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check tags for vertex variable vorticity
+  Tag vorticity_tag0, vorticity_tag1;
+  rval =3D mb.tag_get_handle("vorticity0", 1, MB_TYPE_DOUBLE, vorticity_ta=
g0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("vorticity1", 1, MB_TYPE_DOUBLE, vorticity_ta=
g1);
+  CHECK_ERR(rval);
+
+  // Get vertices (1280 edges)
+  Range verts;
+  rval =3D mb.get_entities_by_type(0, MBVERTEX, verts);
+  assert(rval =3D=3D MB_SUCCESS);
+  CHECK_EQUAL((size_t)1280, verts.size());
+  CHECK_EQUAL((size_t)1, verts.psize());
+
+  // Check vorticity tag values on first two vertices
+  EntityHandle vert_ents[] =3D {verts[0], verts[1]};
+  rval =3D mb.tag_get_data(vorticity_tag0, &vert_ents[0], 2, val);
+  CHECK_REAL_EQUAL(1.1, val[0], eps);
+  CHECK_REAL_EQUAL(1.2, val[1], eps);
+  rval =3D mb.tag_get_data(vorticity_tag1, &vert_ents[0], 2, val);
+  CHECK_REAL_EQUAL(2.1, val[0], eps);
+  CHECK_REAL_EQUAL(2.2, val[1], eps);
+
+  // Check tags for edge variable u
+  Tag u_tag0, u_tag1;
+  rval =3D mb.tag_get_handle("u0", 1, MB_TYPE_DOUBLE, u_tag0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("u1", 1, MB_TYPE_DOUBLE, u_tag1);
+  CHECK_ERR(rval);
+
+  // Get edges (1920 edges)
+  Range edges;
+  rval =3D mb.get_entities_by_type(0, MBEDGE, edges);
+  assert(rval =3D=3D MB_SUCCESS);
+  CHECK_EQUAL((size_t)1920, edges.size());
+  CHECK_EQUAL((size_t)1, edges.psize());
+
+  // Check u tag values on two specified edges
+  EntityHandle edge_ents[] =3D {edges[5], edges[6]};
+  rval =3D mb.tag_get_data(u_tag0, &edge_ents[0], 2, val);
+  CHECK_REAL_EQUAL(1.113138721544778, val[0], eps);
+  CHECK_REAL_EQUAL(-1.113138721930009, val[1], eps);
+  rval =3D mb.tag_get_data(u_tag1, &edge_ents[0], 2, val);
+  CHECK_REAL_EQUAL(2.113138721544778, val[0], eps);
+  CHECK_REAL_EQUAL(-2.113138721930009, val[1], eps);
+
+  // Check tags for cell variable ke
+  Tag ke_tag0, ke_tag1;
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_ERR(rval);
+
+  // Get cells (12 pentagons and 630 hexagons)
+  Range cells;
+  rval =3D mb.get_entities_by_type(0, MBPOLYGON, cells);
+  assert(rval =3D=3D MB_SUCCESS);
+  CHECK_EQUAL((size_t)642, cells.size());
+  CHECK_EQUAL((size_t)2, cells.psize());
+
+  // Check ke tag values on first pentagon and first hexagon
+  EntityHandle cell_ents[] =3D {cells[0], cells[12]};
+  rval =3D mb.tag_get_data(ke_tag0, &cell_ents[0], 2, val);
+  CHECK_REAL_EQUAL(1.5, val[0], eps);
+  CHECK_REAL_EQUAL(1.6, val[1], eps);
+  rval =3D mb.tag_get_data(ke_tag1, &cell_ents[0], 2, val);
+  CHECK_REAL_EQUAL(2.5, val[0], eps);
+  CHECK_REAL_EQUAL(2.6, val[1], eps);
+}
+
+void test_read_onevar()=20
+{
+  Core moab;
+  Interface& mb =3D moab;
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
+
+  opts +=3D std::string(";VARIABLE=3Dke");
+  rval =3D mb.load_file(example, NULL, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tags
+  Tag ke_tag0, ke_tag1;
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_onetimestep()
+{
+  Core moab;
+  Interface& mb =3D moab;
+  std::string opts;
+  ErrorCode rval =3D get_options(opts);
+  CHECK_ERR(rval);
+
+  opts +=3D std::string(";TIMESTEP=3D1");
+  rval =3D mb.load_file( example, NULL, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tags
+  Tag ke_tag0, ke_tag1;
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_nomesh()=20
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+  // Need a set for nomesh to work right
+  EntityHandle set;
+  ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
+  CHECK_ERR(rval);
+
+  std::string orig, opts;
+  rval =3D get_options(orig);
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";TIMESTEP=3D0");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+ =20
+  // Check for proper tags
+  Tag ke_tag0, ke_tag1;
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+  // Now read 2nd timestep with nomesh option
+  opts =3D orig + std::string(";TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tag
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_ERR(rval);
+}
+
+void test_read_novars()
+{
+  Core moab;
+  Interface& mb =3D moab;
+
+  // Need a set for nomesh to work right
+  EntityHandle set;
+  ErrorCode rval =3D mb.create_meshset(MESHSET_SET, set);
+  CHECK_ERR(rval);
+
+  std::string orig, opts;
+  rval =3D get_options(orig);
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";NOMESH;VARIABLE=3D");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  opts =3D orig + std::string(";VARIABLE=3D;TIMESTEP=3D0");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tag
+  Tag ke_tag0, ke_tag1;
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+  opts =3D orig + std::string(";VARIABLE=3Dke;TIMESTEP=3D0;NOMESH");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tags
+  rval =3D mb.tag_get_handle("ke0", 1, MB_TYPE_DOUBLE, ke_tag0);
+  CHECK_ERR(rval);
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_EQUAL(rval, MB_TAG_NOT_FOUND);
+
+  // Now read 2nd timestep with nomesh option
+  opts =3D orig + std::string(";VARIABLE=3Dke;TIMESTEP=3D1;NOMESH");
+  rval =3D mb.load_file(example, &set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Check for proper tag
+  rval =3D mb.tag_get_handle("ke1", 1, MB_TYPE_DOUBLE, ke_tag1);
+  CHECK_ERR(rval);
+}
+
+ErrorCode get_options(std::string &opts)=20
+{
+#ifdef USE_MPI
+  // Use parallel options
+  opts =3D std::string(";;PARALLEL=3DREAD_PART;PARTITION_METHOD=3DTRIVIAL_=
PARTITION");
+  return MB_SUCCESS;
+#else
+  opts =3D std::string(";;");
+  return MB_SUCCESS;
+#endif
+}


https://bitbucket.org/fathomteam/moab/commits/044aeccd9c74/
Changeset:   044aeccd9c74
Branch:      None
User:        danwu
Date:        2013-07-01 17:09:22
Summary:     The commented out code to check the number of elements in orig=
inal ReadNC::check_verts_quads() seems incorrect when it is tested. Still k=
eep it commented out at this time.

Affected #:  1 file

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index eb58441..e0eae99 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -337,6 +337,7 @@ ErrorCode ScdNCHelper::check_existing_mesh(EntityHandle=
 file_set) {
   rval =3D mbImpl->get_number_entities_by_dimension(file_set, (-1 =3D=3D l=
Dims[2] ? 2 : 3), num_elems);
   ERRORR(rval, "Trouble getting number of elements.");
=20
+  /*
   // Check against parameters
   if (num_elems > 0)
   {
@@ -345,6 +346,7 @@ ErrorCode ScdNCHelper::check_existing_mesh(EntityHandle=
 file_set) {
       ERRORR(MB_FAILURE, "Number of elements doesn't match.");
     }
   }
+  */
=20
   return MB_SUCCESS;
 }


https://bitbucket.org/fathomteam/moab/commits/71d97b5e6a62/
Changeset:   71d97b5e6a62
Branch:      None
User:        danwu
Date:        2013-07-01 21:08:40
Summary:     Added mpastrvpart.cpp to test parallel reading of MPAS file

Affected #:  2 files

diff --git a/test/parallel/Makefile.am b/test/parallel/Makefile.am
index d86a8bf..72fb443 100644
--- a/test/parallel/Makefile.am
+++ b/test/parallel/Makefile.am
@@ -55,7 +55,7 @@ else
 endif
=20
 if PNETCDF_FILE
-  PNETCDF_TESTS =3D  ucdtrvpart read_nc_par=20
+  PNETCDF_TESTS =3D  ucdtrvpart read_nc_par mpastrvpart
 else
   PNETCDF_TESTS =3D=20
 endif
@@ -90,6 +90,7 @@ scdpart_SOURCES =3D scdpart.cpp
 if PNETCDF_FILE
   ucdtrvpart_SOURCES =3D ucdtrvpart.cpp
   read_nc_par_SOURCES=3D../io/read_nc.cpp
+  mpastrvpart_SOURCES =3D mpastrvpart.cpp
 endif
=20
 if ENABLE_mbcoupler

diff --git a/test/parallel/mpastrvpart.cpp b/test/parallel/mpastrvpart.cpp
new file mode 100644
index 0000000..386b126
--- /dev/null
+++ b/test/parallel/mpastrvpart.cpp
@@ -0,0 +1,122 @@
+#include "TestUtil.hpp"
+#include "moab/Core.hpp"
+#include "moab/ParallelComm.hpp"
+#include "moab/ProgOptions.hpp"
+#include "MBParallelConventions.h"
+#include "moab/Util.hpp"
+
+using namespace moab;
+
+#ifdef MESHDIR
+static const char example[] =3D STRINGIFY(MESHDIR) "/io/mpasx1.642.t.2.nc";
+#endif
+
+void test_read_parallel_mpas_trivial();
+void test_read_parallel(int num_verts, bool test_nb_nodes, int num_edges, =
bool test_nb_edges);
+
+void test_multiple_loads_of_same_file();
+
+std::string partition_method;
+
+int main(int argc, char* argv[])
+{
+  MPI_Init(&argc, &argv);
+  int result =3D 0;
+
+  result +=3D RUN_TEST(test_read_parallel_mpas_trivial);
+  result +=3D RUN_TEST(test_multiple_loads_of_same_file);
+
+  MPI_Finalize();
+  return result;
+}
+
+void test_read_parallel_mpas_trivial()
+{
+  partition_method =3D std::string(";PARTITION_METHOD=3DTRIVIAL_PARTITION;=
PARALLEL_RESOLVE_SHARED_ENTS");
+
+  test_read_parallel(1280, true, 1920, true);
+}
+ =20
+void test_read_parallel(int num_verts, bool test_nb_nodes, int num_edges, =
bool test_nb_edges)
+{
+  Core moab;
+  Interface& mb =3D moab;
+  EntityHandle file_set;
+  ErrorCode rval;
+  rval =3D mb.create_meshset(MESHSET_SET, file_set);
+  CHECK_ERR(rval);
+
+  std::string opt =3D std::string("PARALLEL=3DREAD_PART") +
+      partition_method;
+  rval =3D mb.load_file(example, &file_set, opt.c_str());
+  CHECK_ERR(rval);
+
+  ParallelComm* pcomm =3D ParallelComm::get_pcomm(&mb, 0);
+
+  rval =3D pcomm->check_all_shared_handles();
+  CHECK_ERR(rval);
+
+  // Get the total # owned verts
+  Range verts;
+  rval =3D mb.get_entities_by_type(0, MBVERTEX, verts);
+  CHECK_ERR(rval);
+  rval =3D pcomm->filter_pstatus(verts, PSTATUS_NOT_OWNED, PSTATUS_NOT);
+  CHECK_ERR(rval);
+
+  int my_verts_num =3D verts.size(), total_verts;
+  std::cout << "proc: " << pcomm->proc_config().proc_rank() << " verts:" <=
< my_verts_num << "\n";
+  MPI_Reduce(&my_verts_num, &total_verts, 1, MPI_INTEGER, MPI_SUM, 0, pcom=
m->proc_config().proc_comm());
+
+  if (0 =3D=3D pcomm->proc_config().proc_rank())
+  {
+    std::cout << "total vertices: " << total_verts << "\n";
+    if (test_nb_nodes)
+      CHECK_EQUAL(total_verts, num_verts);
+  }
+
+  // Get the total # owned edges
+  Range edges;
+  rval =3D mb.get_entities_by_type(0, MBEDGE, edges);
+  CHECK_ERR(rval);
+  rval =3D pcomm->filter_pstatus(edges, PSTATUS_NOT_OWNED, PSTATUS_NOT);
+  CHECK_ERR(rval);
+
+  int my_edges_num =3D edges.size(), total_edges;
+  std::cout << "proc: " << pcomm->proc_config().proc_rank() << " edges:" <=
< my_edges_num << "\n";
+  MPI_Reduce(&my_edges_num, &total_edges, 1, MPI_INTEGER, MPI_SUM, 0, pcom=
m->proc_config().proc_comm());
+
+  if (0 =3D=3D pcomm->proc_config().proc_rank())
+  {
+    std::cout << "total edges: " << total_edges << "\n";
+    if (test_nb_edges)
+      CHECK_EQUAL(total_edges, num_edges);
+  }
+
+  std::string write_options("PARALLEL=3DWRITE_PART;");
+  mb.write_file("test_mpas.h5m", NULL, write_options.c_str());
+}
+
+void test_multiple_loads_of_same_file()
+{
+  Core moab;
+  Interface& mb =3D moab;
+  EntityHandle file_set;
+  ErrorCode rval;
+  rval =3D mb.create_meshset(MESHSET_SET, file_set);
+  CHECK_ERR(rval);
+
+  // Read first only header information, no mesh, no variable
+  std::string opts("PARALLEL=3DREAD_PART;PARTITION;NOMESH;VARIABLE=3D;PART=
ITION_METHOD=3DTRIVIAL_PARTITION");
+  rval =3D mb.load_file(example, &file_set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Create mesh, no variable
+  opts=3D"PARALLEL=3DREAD_PART;PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;PART=
ITION_METHOD=3DTRIVIAL_PARTITION;VARIABLE=3D";
+  rval =3D mb.load_file(example, &file_set, opts.c_str());
+  CHECK_ERR(rval);
+
+  // Read variable ke at timestep 0, no mesh
+  opts =3D "PARALLEL=3DREAD_PART;PARTITION;PARTITION_METHOD=3DTRIVIAL_PART=
ITION;NOMESH;VARIABLE=3Dke;TIMESTEP=3D0";
+  rval =3D mb.load_file(example, &file_set, opts.c_str());
+  CHECK_ERR(rval);
+}


https://bitbucket.org/fathomteam/moab/commits/eccc26879798/
Changeset:   eccc26879798
Branch:      None
User:        danwu
Date:        2013-07-01 23:13:59
Summary:     Merged fathomteam/moab into master
Affected #:  9 files

diff --git a/doc/DG/moabDG.h b/doc/DG/moabDG.h
index d2e14f0..1091094 100644
--- a/doc/DG/moabDG.h
+++ b/doc/DG/moabDG.h
@@ -1,10 +1,45 @@
-/*! \page developerguide Developer's Guide (MOAB 4.6)
-=20
-  \subpage dg-contents
-=20
-  \subpage dg-figures
+/*! \page developerguide Developer's Guide (MOAB 4.6)
+=20
+  \subpage dg-contents
+=20
+  \subpage dg-figures
+
+  \subpage dg-tables
+*/
+
+/*!  \page dg-contents Table of Contents
+
+  \subpage sequence-info
+
+  \subpage meta-data-info
+*/
+
+/*!  \page dg-figures List of Figures
+
+    \ref figure1
+
+    \ref figure2
+
+    \ref figure3
+*/
+
+/*!  \page dg-tables List of Tables
+
+    \ref table1
+
+    \ref table2
+
+    \ref table3
+
+    \ref table4
+
+    \ref table5
+
+    \ref table6
+
+*/
=20
-  \page dg-contents Table of Contents
+/*!  \page sequence-info Sequence Info
=20
   \ref sequence
=20
@@ -14,10 +49,9 @@
=20
   \ref sets
=20
-  \section sequence  1. EntitySequence & SequenceData
+  \section sequence  EntitySequence & SequenceData=20
=20
   \subsection figure1 Figure 1: EntitySequences For One SequenceData
-
 The <I>SequenceData</I> class manages as set of arrays of per-entity value=
s. Each
 <I>SequenceData</I> has a start and end handle denoting the block of entit=
ies for which
 the arrays contain data. The arrays managed by a <I>SequenceData</I> insta=
nce are
@@ -77,9 +111,9 @@ a feature. Sequences for which the corresponding data ca=
nnot be used to store
 new entities (e.g. structured mesh discussed in a later section) will retu=
rn -1 or
 some other invalid value.
=20
- \ref dg-contents
+ \ref sequence-info "Top"
=20
-  \section manager 2. TypeSequenceManager & SequenceManager=20
+  \section manager TypeSequenceManager & SequenceManager=20
=20
 The <I>TypeSequenceManager</I> class maintains an organized set of <I>Enti=
tySequence</I>
 instances and corresponding <I>SequenceData</I> instances. It is used to m=
anage
@@ -141,119 +175,920 @@ such as allocating the correct <I>EntitySequence</I=
> subtype for a given <I>Enti
=20
 <sup>2</sup>Given rule four for the data managed by a <I>TypeSequenceManag=
er</I>, any <I>SequenceData</I> for which all handles are allocated will be=
 referenced by exactly one <I>EntitySequence</I>.
=20
-  \ref dg-contents
-
- \section s-mesh 3. Structured Mesh
-
-Structured mesh storage is implemented using subclasses of <I>SequenceData=
</I>:
-<I>ScdElementData</I> and <I>ScdVertexData</I>. The <I>StructuredElementSe=
q</I> class is
-used to access the structured element connectivity. A standard <I>VertexSe=
quence</I>
-instance is used to access the ScdVertexData because the vertex data stora=
ge
-is the same as for unstructured mesh.
-
-  \ref dg-contents
-
-  \section sets 4. Entity Sets
-
-- MeshSetSequence
-
-The <I>MeshSetSequence</I> class is the same as most other subclasses of <=
I>EntitySequence</I>
-in that it utilizes SequenceData to store its data. A single array in the =
<I>SequenceData</I>
-is used to store instances of the MeshSet class, one per allocated <I>Enti=
tyHandle</I>.
-<I>SequenceData</I> allocates all of its managed arrays using malloc and f=
ree as
-simple arrays of bytes. <I>MeshSetSequence</I> does in-place construction =
and de-
-struction of <I>MeshSet</I> instances within that array. This is similar t=
o what is
-done by <I>std::vector</I> and other container classes that may own more s=
torage
-than is required at a given time for contained objects.
-
-- MeshSet
-
-  \subsection figure3 Figure 3: SequenceManager and Related Classes
-
-The <I>MeshSet</I> class is used to represent a single entity set instance=
 in MOAB.
-The class is optimized to minimize storage (further possible improvements =
in
-storage size are discussed later.)
-
-Figure 3 shows the memory layout of an instance of the <I>MeshSet</I> clas=
s.
-The flags member holds the set creation bit flags: <I>MESHSET_TRACK_OWNER<=
/I>,
-<I>MESHSET_SET</I>, and <I>MESHSET_ORDERED</I>. The presence of the <I>MES=
HSET_TRACK_OWNER</I>
-indicates that reverse links from the contained entities back to the ownin=
g set
-should be maintained in the adjacency list of each entity. The <I>MESHSET_=
SET</I>
-and <I>MESHSET_ORDERED</I> bits are mutually exclusive, and as such most c=
ode only
-tests for the <I>MESHSET_ORDERED</I>, meaning that in practice the <I>MESH=
SET_SET</I> bit is
-ignored. <I>MESHSET_ORDERED</I> indicates that the set may contain duplica=
te handles
-and that the order that the handles are added to the set should be preserv=
ed.
-In practice, such sets are stored as a simple list of handles. <I>MESHSET_=
SET</I> (or in
-practice, the lack of <I>MESHSET_ORDERED</I>) indicates that the order of =
the handles
-need not be preserved and that the set may not contain duplicate handles. =
Such
-sets are stored in a sorted range-compacted format similar to that of the =
Range
-class.
-
-The memory for storing contents, parents, and children are each handled in
-the same way. The data in the class is composed of a 2-bit =E2=80=98size=
=E2=80=99 field and two
-values, where the two values may either be two handles or two pointers. Th=
e size
-bit-fields are grouped together to reduce the required amount of memory. I=
f the
-numerical value of the 2-bit size field is 0 then the corresponding list i=
s empty.
-If the 2-bit size field is either 1 or 2, then the contents of the corresp=
onding list
-are stored directly in the corresponding two data fields of the MeshSet ob=
ject.
-If the 2-bit size field has a value of 3 (11 binary), then the correspondi=
ng two
-data fields store the begin and end pointers of an external array of handl=
es.
-The number of handles in the external array can be obtained by taking the
-difference of the start and end pointers. Note that unlike <I>std::vector<=
/I>, we
-do not store both an allocated and used size. We store only the =E2=80=98u=
sed=E2=80=99 size
-and call std::realloc whenever the used size is modified, thus we rely on =
the
-std::malloc implementation in the standard C library to track =E2=80=98all=
ocated=E2=80=99 size
-for us. In practice this performs well but does not return memory to the =
=E2=80=98system=E2=80=99
-when lists shrink (unless they shrink to zero). This overall scheme could =
exhibit
-poor performance if the size of one of the data lists in the set frequentl=
y changes
-between less than two and more than two handles, as this will result in fr=
equent
-releasing and re-allocating of the memory for the corresponding array.
-
-If the <I>MESHSET_ORDERED</I> flag is not present, then the set contents l=
ist (parent
-and child lists are unaffected) is stored in a range-compacted format. In =
this
-format the number of handles stored in the array is always a multiple of t=
wo.
-Each consecutive pair of handles indicate the start and end, inclusive, of=
 a range
-of handles contained in the set. All such handle range pairs are stored in=
 sorted
-order and do not overlap. Nor is the end handle of one range ever one less=
 than
-the start handle of the next. All such =E2=80=98adjacent=E2=80=99 range pa=
irs are merged into a
-single pair. The code for insertion and removal of handles from range-form=
atted
-set content lists is fairly complex. The implementation will guarantee tha=
t a
-given call to insert entities into a range or remove entities from a range=
 is never
-worse than O(ln n) + O(m + n), where =E2=80=98n=E2=80=99 is the number of =
handles to insert
-and =E2=80=98m=E2=80=99 is the number of handles already contained in the =
set. So it is generally
-much more efficient to build Ranges of handles to insert (and remove) and =
call
-MOAB to insert (or remove) the entire list at once rather than making may
-calls to insert (or remove) one or a few handles from the contents of a se=
t.
-The set storage could probably be further minimized by allowing up to six
-handles in one of the lists to be elided. That is, as there are six potent=
ial =E2=80=98slots=E2=80=99
-in the MeshSet object then if two of the lists are empty it should be poss=
ible to store up to six values of the remaining list directly in the MeshSe=
t object.
-However, the additional runtime cost of such complexity could easily outwe=
igh
-any storage advantage. Further investigation into this has not been done b=
ecause
-the primary motivation for the storage optimization was to support binary =
trees.
-
-Another possible optimization of storage would be to remove the <I>MeshSet=
</I>
-object entirely and instead store the data in a =E2=80=98blocked=E2=80=99 =
format. The corre-
-sponding <I>SequenceData</I> would contain four arrays: flags, parents, ch=
ildren, and
-contents instead of a single array of <I>MeshSet</I> objects. If this were=
 done then
-no storage need ever be allocated for parent or child links if none of the=
 sets
-in a <I>SequenceData</I> has parent or child links. The effectiveness of t=
he storage
-reduction would depend greatly on how sets get grouped into <I>SequenceDat=
as</I>.
-This alternate storage scheme might also allow for better cache utilizatio=
n as it
-would group like data together. It is often the case that application code=
 that
-is querying the contents of one set will query the contents of many but ne=
ver
-query the parents or children of any set. Or that an application will quer=
y only
-parent or child links of a set without every querying other set properties=
. The
-downside of this solution is that it makes the implementation a little les=
s mod-
-ular and maintainable because the existing logic contained in the <I>MeshS=
et</I> class
-would need to be spread throughout the <I>MeshSetSequence</I> class.
-
-  \ref dg-contents
-
-  \page dg-figures List of Figures
-
-  \ref figure1
-
-  \ref figure2
-
-  \ref figure3
+  \ref sequence-info "Top"
+
+ \section s-mesh Structured Mesh
+
+Structured mesh storage is implemented using subclasses of <I>SequenceData=
</I>:
+<I>ScdElementData</I> and <I>ScdVertexData</I>. The <I>StructuredElementSe=
q</I> class is
+used to access the structured element connectivity. A standard <I>VertexSe=
quence</I>
+instance is used to access the ScdVertexData because the vertex data stora=
ge
+is the same as for unstructured mesh.
+
+  \ref sequence-info "Top"
+
+  \section sets Entity Sets
+
+- MeshSetSequence
+
+The <I>MeshSetSequence</I> class is the same as most other subclasses of <=
I>EntitySequence</I>
+in that it utilizes SequenceData to store its data. A single array in the =
<I>SequenceData</I>
+is used to store instances of the MeshSet class, one per allocated <I>Enti=
tyHandle</I>.
+<I>SequenceData</I> allocates all of its managed arrays using malloc and f=
ree as
+simple arrays of bytes. <I>MeshSetSequence</I> does in-place construction =
and de-
+struction of <I>MeshSet</I> instances within that array. This is similar t=
o what is
+done by <I>std::vector</I> and other container classes that may own more s=
torage
+than is required at a given time for contained objects.
+
+- MeshSet
+
+  \subsection figure3 Figure 3: SequenceManager and Related Classes
+
+The <I>MeshSet</I> class is used to represent a single entity set instance=
 in MOAB.
+The class is optimized to minimize storage (further possible improvements =
in
+storage size are discussed later.)
+
+Figure 3 shows the memory layout of an instance of the <I>MeshSet</I> clas=
s.
+The flags member holds the set creation bit flags: <I>MESHSET_TRACK_OWNER<=
/I>,
+<I>MESHSET_SET</I>, and <I>MESHSET_ORDERED</I>. The presence of the <I>MES=
HSET_TRACK_OWNER</I>
+indicates that reverse links from the contained entities back to the ownin=
g set
+should be maintained in the adjacency list of each entity. The <I>MESHSET_=
SET</I>
+and <I>MESHSET_ORDERED</I> bits are mutually exclusive, and as such most c=
ode only
+tests for the <I>MESHSET_ORDERED</I>, meaning that in practice the <I>MESH=
SET_SET</I> bit is
+ignored. <I>MESHSET_ORDERED</I> indicates that the set may contain duplica=
te handles
+and that the order that the handles are added to the set should be preserv=
ed.
+In practice, such sets are stored as a simple list of handles. <I>MESHSET_=
SET</I> (or in
+practice, the lack of <I>MESHSET_ORDERED</I>) indicates that the order of =
the handles
+need not be preserved and that the set may not contain duplicate handles. =
Such
+sets are stored in a sorted range-compacted format similar to that of the =
Range
+class.
+
+The memory for storing contents, parents, and children are each handled in
+the same way. The data in the class is composed of a 2-bit =E2=80=98size=
=E2=80=99 field and two
+values, where the two values may either be two handles or two pointers. Th=
e size
+bit-fields are grouped together to reduce the required amount of memory. I=
f the
+numerical value of the 2-bit size field is 0 then the corresponding list i=
s empty.
+If the 2-bit size field is either 1 or 2, then the contents of the corresp=
onding list
+are stored directly in the corresponding two data fields of the MeshSet ob=
ject.
+If the 2-bit size field has a value of 3 (11 binary), then the correspondi=
ng two
+data fields store the begin and end pointers of an external array of handl=
es.
+The number of handles in the external array can be obtained by taking the
+difference of the start and end pointers. Note that unlike <I>std::vector<=
/I>, we
+do not store both an allocated and used size. We store only the =E2=80=98u=
sed=E2=80=99 size
+and call std::realloc whenever the used size is modified, thus we rely on =
the
+std::malloc implementation in the standard C library to track =E2=80=98all=
ocated=E2=80=99 size
+for us. In practice this performs well but does not return memory to the =
=E2=80=98system=E2=80=99
+when lists shrink (unless they shrink to zero). This overall scheme could =
exhibit
+poor performance if the size of one of the data lists in the set frequentl=
y changes
+between less than two and more than two handles, as this will result in fr=
equent
+releasing and re-allocating of the memory for the corresponding array.
+
+If the <I>MESHSET_ORDERED</I> flag is not present, then the set contents l=
ist (parent
+and child lists are unaffected) is stored in a range-compacted format. In =
this
+format the number of handles stored in the array is always a multiple of t=
wo.
+Each consecutive pair of handles indicate the start and end, inclusive, of=
 a range
+of handles contained in the set. All such handle range pairs are stored in=
 sorted
+order and do not overlap. Nor is the end handle of one range ever one less=
 than
+the start handle of the next. All such =E2=80=98adjacent=E2=80=99 range pa=
irs are merged into a
+single pair. The code for insertion and removal of handles from range-form=
atted
+set content lists is fairly complex. The implementation will guarantee tha=
t a
+given call to insert entities into a range or remove entities from a range=
 is never
+worse than O(ln n) + O(m + n), where =E2=80=98n=E2=80=99 is the number of =
handles to insert
+and =E2=80=98m=E2=80=99 is the number of handles already contained in the =
set. So it is generally
+much more efficient to build Ranges of handles to insert (and remove) and =
call
+MOAB to insert (or remove) the entire list at once rather than making may
+calls to insert (or remove) one or a few handles from the contents of a se=
t.
+The set storage could probably be further minimized by allowing up to six
+handles in one of the lists to be elided. That is, as there are six potent=
ial =E2=80=98slots=E2=80=99
+in the MeshSet object then if two of the lists are empty it should be poss=
ible to store up to six values of the remaining list directly in the MeshSe=
t object.
+However, the additional runtime cost of such complexity could easily outwe=
igh
+any storage advantage. Further investigation into this has not been done b=
ecause
+the primary motivation for the storage optimization was to support binary =
trees.
+
+Another possible optimization of storage would be to remove the <I>MeshSet=
</I>
+object entirely and instead store the data in a =E2=80=98blocked=E2=80=99 =
format. The corre-
+sponding <I>SequenceData</I> would contain four arrays: flags, parents, ch=
ildren, and
+contents instead of a single array of <I>MeshSet</I> objects. If this were=
 done then
+no storage need ever be allocated for parent or child links if none of the=
 sets
+in a <I>SequenceData</I> has parent or child links. The effectiveness of t=
he storage
+reduction would depend greatly on how sets get grouped into <I>SequenceDat=
as</I>.
+This alternate storage scheme might also allow for better cache utilizatio=
n as it
+would group like data together. It is often the case that application code=
 that
+is querying the contents of one set will query the contents of many but ne=
ver
+query the parents or children of any set. Or that an application will quer=
y only
+parent or child links of a set without every querying other set properties=
. The
+downside of this solution is that it makes the implementation a little les=
s mod-
+ular and maintainable because the existing logic contained in the <I>MeshS=
et</I> class
+would need to be spread throughout the <I>MeshSetSequence</I> class.
+
+  \ref sequence-info "Top"
 */
+
+/*! \page meta-data-info I/O and Meta-Data Storage Conventions in MOAB
+
+  <Center><H3> Timothy J. Tautges </H3></Center>
+
+    \ref meta-introduction
+
+    \ref meta-conventions
+
+    \ref meta-options
+
+    \ref meta-references
+
+    \ref appendixA
+
+    \ref appendixB
+
+    \ref appendixC
+
+    \ref appendixD
+
+    \ref appendixE
+
+  \section meta-introduction  Introduction
+
+The Mesh-Oriented datABase (MOAB) is a library for representing finite ele=
ment and other types of mesh data [1].  Various types of meta-data are ofte=
n used in conjunction with a mesh.  Examples include boundary condition gro=
upings, material types, and provenance information for the mesh.  Because t=
he data model used in MOAB is so abstract, conventions are useful for descr=
ibing how meta-data is stored into that data model.  This document describe=
s those conventions for several types of data commonly found in meshes stor=
ed in MOAB.  Because the data models used by MOAB and iMesh, the ITAPS mesh=
 interface [2], are so similar, the conventions described here apply almost=
 unmodified to iMesh as well as to MOAB.
+
+The meshes represented in MOAB originate in a variety of forms, including =
mesh read from files of various formats (e.g. CUBIT =E2=80=9C.cub=E2=80=9D =
file, VTK, etc.) as well as mesh written into MOAB directly by various soft=
ware libraries (e.g. MeshKit).  Although there is no standard for naming or=
 storing meta-data with a mesh, there is a great deal of commonality in the=
 types of meta-data typically found with mesh data.  This document describe=
s conventions that have been established for commonly encountered meta-data=
.  Various mesh readers implemented in MOAB attempt to read meta-data from =
a file and write it into the MOAB data model using these conventions.  Alth=
ough there is no requirement to store a given type of meta-data in the form=
 described here, a number of services have been written to handle meta-data=
 using these conventions, no matter the source of the meta-data being proce=
ssed.
+
+Several specific tools are often used in concert with MOAB and bear specia=
l mention here.  The CUBIT toolkit generates finite element meshes, and sav=
es them to a native save file (referred to as a =E2=80=9C.cub=E2=80=9D file=
) which MOAB is able to read.  Reading CUBIT meshes into MOAB through the .=
cub file format is preferred over other formats, since most other mesh form=
ats written by CUBIT do not save most meta-data.  The MeshKit library also =
generates mesh using CGM and MOAB, and uses the same conventions for storin=
g meshes into MOAB.  Finally, MOAB includes a CGM reader which can read a g=
eometric model into a faceted representation in MOAB.  Meta-data from all t=
hese tools are stored in MOAB using the conventions described here.=20
+
+The MOAB data model consists of the following basic types:
+- <B>Entity</B>: The basic elements of topology, e.g. vertex, edge, triang=
le, tetrahedron, etc.  MOAB represents all types in the finite element zoo,=
 plus polygons and polyhedra.
+- <B>Entity Set</B>: An arbitrary collection of entities and other sets.  =
Sets can have parent/child relations with other sets, and these relations a=
re distinct from =E2=80=9Ccontains=E2=80=9D relations.
+- <B>Interface</B>: The interface object through which other entities are =
accessed, in the sense of object-oriented-programming.  iMesh refers to the=
 interface as the =E2=80=9Croot=E2=80=9D set.
+- <B>Tag</B>: A piece of data that can be assigned a distinct value to eac=
h entity and entity set, and to the interface itself.  Tags have a prescrib=
ed name, size in bytes, and data type; allowed data types are integer, doub=
le, entity handle, and byte or opaque.
+.
+
+The following section describes each meta-data tag convention in detail; t=
hese conventions are also summarized in Table 1.
+
+  \ref meta-data-info "Top"
+
+  \section meta-conventions  Meta-Data Conventions
+
+Meta-data is stored in MOAB and iMesh in the form of tags applied to eithe=
r entities or entity sets.  For meta-data represented as entity sets, the c=
ontents of those sets are determined by the convention, with tags on those =
sets identifying them with the convention and adding any other semantic dat=
a.
+
+Each meta-data convention is described in a subsection below.  Each conven=
tion begins with a short description of:
+- Whether tags associated with the convention are assigned to entities or =
entity sets
+- The tag(s) associated with the convention; information for each tag incl=
udes the name, the data type (I=3Dinteger, D=3Ddouble, C=3Dcharacter, H=3Dh=
andle), and the tag length.  Tag lengths are specified after an asterisk (*=
); for example, C*32 implies a tag with character type and length 32.  Unsp=
ecified lengths correspond to length one.
+.
+
+<H3>Name</H3>
+
+(Data: Entity sets, entities; Tag(s): NAME/C*32)
+
+Character strings are used in many different contexts in applications.  MO=
AB uses the =E2=80=9CNAME=E2=80=9D tag to store character strings used to n=
ame entities.  This tag is of byte-type and is of length 32 bytes.  Note th=
at the string stored in this tag may or may not be terminated with a NULL c=
haracter.  It is always prudent account for missing NULL terminator, to avo=
id buffer overflow errors in the application.  Applications are free to def=
ine their own version of the NAME tag with a longer length, though this def=
inition may conflict with other services attempting to use this tag with th=
e conventional size.  Applications needing a string tag with a longer or va=
riable length can also use MOAB=E2=80=99s variable-length tag type, though =
this will not be compatible with iMesh.
+
+<H3>Title </H3>
+
+(Data: Entity sets (file or instance); Tag(s): TITLE/C*strlen)
+
+The title tag is meant to hold the overall identifier of a mesh, written a=
t generation time or read from a file generated with a non-MOAB tool.  The =
tag length is variable, and is set by the application directly (by calling =
the tag_create function) or indirectly (by embedding the title in a file re=
ad by MOAB).
+
+<H3> Global Identifier </H3>
+
+(Data: Entity sets, entities; Tag(s): GLOBAL_ID/I)
+
+Global identifiers are used in many different contexts in applications.  G=
eometric model entities are identified by dimension and id, e.g. =E2=80=9CV=
olume 1=E2=80=9D.  Mesh vertices and elements are identified similarly in m=
esh generation codes.  Boundary conditions and material types are identifie=
d similarly.  This tag is used to store such information.  This tag is curr=
ently stored in a 32-byte integer, though this may change in the future.
+
+<H3> Geometric Model Information </H3>
+
+(Data: Entity sets; Tag(s): GEOM_DIMENSION/I, GLOBAL_ID/I, NAME/C*32, CATE=
GORY/C*32, GEOM_SENSE_2(EH[2]), GEOM_SENSE_N_ENTS(EH*N), GEOM_SENSE_N_SENSE=
S(I*N))
+
+Mesh generation is often performed starting from a geometric model, repres=
ented in some form of CAD engine.  Many of the meshes used by MOAB are gene=
rated based on the CGM library.  Geometric models contain both topological =
information (the topological entities in the geometric model) and shape inf=
ormation (the geometric shape of those entities), as well as other meta-dat=
a written to the entities in a model.  When a mesh is read from a CUBIT .cu=
b file, meta-data from the geometric model is read and represented in the M=
OAB data model, as described below. <B> Note that although MOAB reads and r=
epresents meta-data associated with the geometric model, it does not repres=
ent the geometric model itself.</B>  Therefore, shape-related information, =
e.g. the arc length of an edge or surface normal at a given point, can be r=
etrieved only from the model represented in CGM or another geometric modeli=
ng engine.
+
+The information contained in a geometric model, read into and represented =
in MOAB, consists of:
+- Model entities (vertex, edge, face, volume)
+- Topological relationships between model entities
+- Groups of model entities
+- Model entity/group ids
+- Model entity/group names
+.
+The storage of this information into MOAB's data model is described for ea=
ch type is described below.
+
+- <B>Entities </B>
+
+Entities in the geometric model (VERTEX, EDGE, FACE, VOLUME) are each repr=
esented by an entity set<sup>1</sup>.  These sets are tagged with the =E2=
=80=9CGEOM_DIMENSION=E2=80=9D tag, with integer value equal to the topologi=
cal dimension of the entity (VERTEX =3D 0, EDGE =3D 1, etc.)  These sets co=
ntain the mesh owned by the corresponding entity in the geometric model.  N=
ote this does not include mesh owned by bounding entities; thus, the set fo=
r a FACE will not contain the mesh vertices owned by bounding EDGEs in the =
geometric model.  These sets may or may not contain mesh entities of interm=
ediate dimension, e.g. mesh edges owned by a FACE or faces owned by a VOLUM=
E, depending on the application generating the mesh or the file from which =
the mesh was read.  These sets are all set-types, i.e. the order of entitie=
s in the sets is not significant, except in the case of EDGE sets, where or=
der of the mesh vertices and edges corresponds to the relative order of ver=
tices and edges at the time of mesh generation.  In MOAB, these sets are no=
n-tracking by default, i.e. entities do not have knowledge of which geometr=
y sets they are members of.
+
+<sup>1</sup>Body-type entities from CUBIT are not explicitly represented i=
n MOAB.
+
+- <B> Topological Relationships </B>
+
+In the geometric model, each FACE is bounded by zero or more EDGEs; other =
topological relationships between geometric entities exist in a similar man=
ner.  These relationships are embedded in the data model using parent/child=
 relations between entity sets.  For example, the entity set corresponding =
to a FACE will have child sets, each corresponding to a bounding EDGE, and =
parent sets, each corresponding to a VOLUME bounded by that FACE.  The rela=
tive order of sets in those parent/child lists is not significant, thus, =
=E2=80=9Cloops=E2=80=9D bounding a FACE cannot reliably be inferred from th=
is data.
+
+- <B> Groups </B>
+
+Geometric entities are sometimes assigned to application-specific groups. =
 These groups are represented using entity sets, tagged with a =E2=80=9CGRO=
UP=E2=80=9D tag whose value equals the group id.  Group sets are =E2=80=9Cs=
et=E2=80=9D-type, and are not tracking sets.  These sets contain the sets c=
orresponding to geometric entities contained in the groups in the geometric=
 model, as well as any mesh entities assigned to the group.
+
+<H4> Sense </H4>
+
+A geometric face has a natural orientation, indicated by the direction of =
the normal to the face; similarly, edges have a natural orientation determi=
ned by the direction of the tangent.  When faces bound regions, or edges bo=
und faces, they do so with a sense; if a region includes a face with forwar=
d sense, that means the face's natural normal direction points out of the v=
olume.  If a face includes an edge with forward sense, that means that if o=
ne moves along the edge in the direction of its tangent, the material of th=
e face is on the left hand side.  The sense of a face (edge) with respect t=
o a region (face) it bounds is stored using tags on the face (edge).
+
+Most models allow a face to be part of only two regions.  Therefore, to st=
ore the sense of a face with respect to regions including it, a tag with tw=
o values is used.  This tag is named GEOM_SENSE_2, and has 2 EntityHandle v=
alues.  The first value corresponds to the entity set for the region for wh=
ich that face has a forward sense, and the second to the region for which t=
hat face has a reverse sense.
+
+Edges can bound more than two faces.  Therefore, two variable-length tags =
are used, one to store the EntityHandles of the faces the edge bounds, and =
the other to store the sense with which the edge bounds the corresponding f=
ace.  These tags are named GEOM_SENSE_N_ENTS and GEOM_SENSE_N_SENSES, respe=
ctively.  These are stored as variable-length tags; see the MOAB user's gui=
de for information on how to work with tags of this type.=20
+
+The following sense values are used:
+- 0: forward
+- 1: reverse
+- -1: unnknown
+
+<H3> Material Type </H3>
+
+(Data: Entity sets; Tag(s): MATERIAL_SET/I)
+
+Most finite element and other PDE-based analysis codes require a material =
type for each cell or element in the simulation.  MOAB uses entity sets to =
store this information, in the form of entity sets.  The MATERIAL_SET tag i=
s used to identify these sets.  The value of this tag is conventionally an =
integer; in most cases this stores a user-assigned identifier associated wi=
th that material.=20
+
+CUBIT assigns material types using what it calls =E2=80=9Celement blocks=
=E2=80=9D, with each element block given a user-assigned id number and opti=
onally a name.  The CUBIT and Exodus file readers in MOAB read element bloc=
ks into MATERIAL_SET sets. =20
+
+In CUBIT, materials are typically assigned by assigning geometric volumes =
to element blocks.  Therefore, material sets often contain entity sets corr=
esponding to those volumes.  Thus, a materrial set in MOAB is unlikely to c=
ontain mesh entities directly; rather, that set contains other sets which c=
ontain mesh entities.  In these cases, mesh entities can be retrieved by pa=
ssing a =E2=80=9Crecursive=E2=80=9D flag to the appropriate function (MOAB)=
, or by calling the getEntitiesRec extension function (iMesh) provided by M=
OAB.
+
+<H3> Boundary Conditions (Dirichlet, Neumann)</H3>
+
+Data: Entity sets; Tag(s): DIRICHLET_SET/I, NEUMANN_SET/I)
+
+Boundary conditions are often specified in terms of geometric model entiti=
es, similar to material types.  MOAB uses entity sets to store this informa=
tion as well.  The DIRICHLET_SET and NEUMANN_SET tags are used to represent=
 Dirichlet- and Neumann-type boundary condition sets, resp.  By convention,=
 Neumann sets usually contain (indirectly) intermediate-dimension entities =
like edges in a 2D mesh or faces in a 3D mesh, while Dirichlet sets usually=
 contain vertices.  In addition, Neumann sets are represented as sets of fa=
ces, rather than as sides of elements.  Faces can be ordered =E2=80=9Cforwa=
rd=E2=80=9D or =E2=80=9Creverse=E2=80=9D with respect to one of the boundin=
g elements, depending on whether the right-hand normal points into or out o=
f the element.  Forward-sense faces are added to the Neumann set.  Reverse-=
sense faces are put into a separate set; that set is tagged with the NEUSET=
_SENSE tag, with value =3D -1; and that reverse set is added to the Neumman=
n set.
+
+<H3> Parallel Mesh Constructs </H3>
+
+(Data: Entity sets, entities; Tag(s): PARALLEL_PART/I, PARALLEL_PARTITION/=
I, PSTATUS/C*1, PARALLEL_SHARED_PROC/I, PARALLEL/SHARED_HANDLE/H, PARALLEL_=
SHARED_PROCS/I*NP, PARALLEL_SHARED_HANDLES/H*NP)
+
+On a parallel computer, MOAB can represent the mesh on each processor as w=
ell as information about entities shared with neighboring processors.  Some=
 of this information is also relevant even when the mesh is represented on =
a serial machine.  MOAB uses several tag and set conventions to describe th=
e parallel nature of a mesh.  This information is summarized here; for a mo=
re complete description of MOAB=E2=80=99s parallel mesh representation and =
functionality, see [ref-moabpar].
+
+- <B> Parallel partition, parts </B>
+
+Most parallel mesh applications use a domain decomposition approach, where=
 each processor solves for a subset of the domain.  The set of entities sol=
ved by a given processor is referred to as a part, and the collection of pa=
rts together is called the partition.  MOAB stores each part in an entity s=
et, marked with the PARALLEL_PART tag, whose value is the rank of the proce=
ssor assigned that part; an entity set which contains all part sets is give=
n the PARALLEL_PARTITION tag, whose value is currently meaningless.  The MB=
Zoltan tool included as a tool in MOAB can partition a mesh for parallel so=
lution, and writes the partition to the mesh in the form of parts and parti=
tions.  Both these types of sets can be accessed in a serial mesh, e.g. for=
 visualization.
+
+- <B> Part interfaces </B>
+
+When a partitioned mesh has been loaded on a parallel computer, the part o=
n a given processor may share portions of its boundary with parts on other =
processors.  These shared regions are called part interfaces, and are also =
represented using entity sets.  These sets are marked with the PARALLEL_INT=
ERFACE tag, whose value is currently meaningless.
+
+- <B> Shared processor and handle </B>
+
+For entities shared between processors, it is helpful to know locally whic=
h other processor shares an entity, and what the entity=E2=80=99s handle is=
 on the remote processor.  There are two cases which are useful to distingu=
ish, first where an entity is shared with only one other processor (referre=
d to as shared), and second when a processor is shared by more than one oth=
er processor (referred to as multi-shared).   Shared entities are given the=
 PARALLEL_SHARED_PROC and PARALLEL_SHARED_HANDLE tags, which store the rank=
 of the sharing processor and the handle of the entity on that processor, r=
espectively.  Multi-shared entities are marked with the PARALLEL_SHARED_PRO=
CS and PARALLEL_SHARED_HANDLES tags; these tags have a length NP assigned a=
t compile time in MOAB, with default values of -1 for processor rank and ze=
ro for handle (which are each invalid values for the corresponding data).  =
The processors/handles sharing a given entity are then written on the front=
 of the arrays.  So, for example, an entity on processor rank 0, shared by =
processors 1 and 2, would have a PARALLEL_SHARED_PROCS tag whose values wou=
ld be [1, 2, -1, -1, =E2=80=A6], with PARALLEL_SHARED_HANDLES values of [m,=
 n, 0, 0, =E2=80=A6], where m and n would be the handles of that entity on =
processors 1 and 2.  The shared versions of these tags are =E2=80=9Cdense=
=E2=80=9D, with default values which denote unshared entities.  The multi-s=
hared tags are sparse tags in MOAB, with no default value.
+
+- <B> Parallel status </B>
+
+In addition to the tags above, MOAB also defines the PSTATUS tag, whose bi=
ts contain information about the parallel status of a given entity.  Starti=
ng with least significant bit, these bits represent whether an entity is 1)=
 not owned, 2) shared, 3) multi-shared, 4) interface, 5) a ghost entity.  T=
he first bit being set indicates =E2=80=9Cnot owned=E2=80=9D so that the de=
fault value for this tag, of zero, corresponds to an owned, unshared entity=
, which will be the state of most entities on a given processor.
+
+<H3>Structured Mesh Parameters </H3>
+
+MOAB has a structured mesh interface for creating structured mesh (see =E2=
=80=9CScdInterface.hpp=E2=80=9D header file in MOAB source code).  Along wi=
th an internal representation that is more memory-efficient (since it does =
not need to store connectivity), MOAB also creates and tags entity sets wit=
h structured mesh parameters, which can be accessed through the normal tag =
and set interface.  The following tags are used:
+- <B>BOX_DIMS</B>: This tag stores the ijk coordinates of the lower and up=
per corner of the structured mesh box(es).
+- <B>GLOBAL_BOX_DIMS</B>: If specified when the structured mesh is created=
, a tag with this name stores the global box dimensions (which may be diffe=
rent than the local box dimensions).
+- <B>BOX_PERIODIC</B>: Stores whether the box is periodic in the i (BOX_PE=
RIODIC[0]) and j (BOX_PERIODIC[1]) directions.
+- <B>__BOX_SET</B>: Pointer to the ScdBox instance corresponding to this e=
ntity set.<sup>2</sup>
+.
+Although the structured mesh is not saved as such in HDF5-format files, th=
e entity sets and corresponding tags will be saved and restored.
+
+<sup>2</sup>The double-underscore in the tag name implies that this tag wi=
ll not be saved in a file, in this case because the ScdBox instances are no=
t preserved in a file.
+
+<H3>Spectral Mesh Constructs </H3>
+
+The Spectral Element Method (SEM) is a high-order method, using a polynomi=
al Legendre interpolation basis with Gauss-Lobatto quadrature points, in co=
ntrast to the Lagrange basis used in (linear) finite elements.  A spectral =
mesh with order O contains quadrilateral or hexahedral elements comprised o=
f (O+1)d vertices.  Spectral meshes are usually represented in one of two w=
ays, either as coarse elements which point to an array of higher-order vert=
ices (and with corner vertices represented in the normal manner), or as lin=
ear quads/hexes formed from the higher-order vertices, with each original c=
oarse quad/hex represented by Od fine quads/hexes.  Similarly, the spectral=
 variables, which are normally computed at fine vertex positions, are store=
d either on those vertices, or in lexicographically-ordered arrays on eleme=
nts (with tag values repeated on neighboring elements).  MOAB can read spec=
tral meshes from a variety of formats (at this time, including CAM-SE, HOMM=
E, and Nek5000).  Which of the above two representations are controlled by =
read options and are indicated by certain tags:
+- SPECTRAL_MESH: read option indicating that spectral elements should be r=
epresented as coarse linear quads/hexes and each element containing an arra=
y of lexicographically-ordered vertex handles
+- TAG_SPECTRAL_ELEMENTS: read option; if given, spectral variables are rep=
resented as lexicographically-ordered arrays on elements
+- TAG_SPECTRAL_VERTICES: read option; if given, spectral variables are rep=
resented as tags on vertices
+- CONN=3D<filename>: in CAM-SE, the connectivity of the spectral mesh is s=
tored by default in a file named =E2=80=9CHommeMapping.nc=E2=80=9D; this op=
tion can be given to read the connectivity from a different file
+- SPECTRAL_VERTICES: tag name for array of vertex handles
+- SPECTRAL_ORDER: tag name for spectral order, written to file set or (if =
no file set given) to interface after a spectral mesh is read
+.
+
+  \ref meta-data-info "Top"
+
+  \section meta-options Reader/Writer Options
+
+All mesh file readers and writers in MOAB take an option string as an argu=
ment.  By default, the semicolon (=E2=80=9C;=E2=80=9D) delimits individual =
options in the option string.  Options used in multiple readers are describ=
ed in this section; the options enabled in specific readers/writers are des=
cribed in the corresponding appendix at the end of this document.
+
+<H3>variable=3D<var_name>[,...]</H3>
+
+By default, all field data stored with the mesh is read with the mesh, and=
 stored as tags on the associated mesh entities.  This option lists specifi=
c variables that should be read along with the mesh (note also the =E2=80=
=9Cnomesh=E2=80=9D option, described elsewhere in this document).  The vari=
able name listed will be read into a tag with the same name.  For time-depe=
ndent variables, the time step number will be appended to the variable name=
 to form the tag name.  If no =E2=80=9Ctimestep=E2=80=9D or =E2=80=9Ctimeva=
l=E2=80=9D option is given, all time steps will be read, resulting in sever=
al tags being created.  If the =E2=80=9Cnomesh=E2=80=9D option is given, th=
e application must pass the entity set resulting from the original mesh rea=
d in to the function, that this set must contain the mesh read only from th=
at file.  The mesh in the file is checked against the mesh in the set to ve=
rify that the two correspond.  The special name =E2=80=9CMOAB_ALL_VARIABLES=
=E2=80=9D can be used to indicate that all variables should be read.  Multi=
ple variable names can be specified, separated from each other by commas.
+
+<H3>nomesh </H3>
+
+Indicates that no mesh should be read from the file.  This option is used =
in conjunction with the =E2=80=9Cvariable=3D=E2=80=9D option, to read varia=
bles and assign them as tags to a previously-read mesh.  If this option is =
used, applications should pass an entity set to the read function, which sh=
ould contain the mesh previously read from the file.
+
+<H3>timestep=3D<step_number>[, ...] </H3>
+
+Read the time step number whose time value is equal to or greater than the=
 specified time value, for the specified variable(s).  Tag names for the va=
riable(s) will be formed by appending the time step number to the variable =
name.  Multiple time step values can be specified, separated from each othe=
r by commas.
+
+  \ref meta-data-info "Top"
+
+  \section meta-references References
+
+[1]	T.J. Tautges, R. Meyers, K. Merkley, C. Stimpson, and C. Ernst, MOAB: =
A Mesh-Oriented Database, Sandia National Laboratories, 2004.
+
+[2]	L. Diachin, A. Bauer, B. Fix, J. Kraftcheck, K. Jansen, X. Luo, M. Mil=
ler, C. Ollivier-Gooch, M.S. Shephard, T. Tautges, and H. Trease, =E2=80=9C=
Interoperable mesh and geometry tools for advanced petascale simulations,=
=E2=80=9D Journal of Physics: Conference Series,  vol. 78, 2007, p. 012015.
+
+\ref meta-data-info "Top"
+
+  \section appendixA Appendix A: Summary
+
+  \subsection table1 Table 1: Summary of MOAB meta-data conventions.
+
+<table border=3D"1">
+<tr>
+<th>Convention</th>
+<th>Applies to (E=3Dent, S=3Dset)</th>
+<th>Tag(s) (type/length)</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>Name</td>
+<td>E, S</td>
+<td>NAME/C*32</td>
+<td></td>
+</tr>
+<tr>
+<td>Title</td>
+<td>S</td>
+<td>TITLE/C*strlen</td>
+<td>Title of mesh</td>
+</tr>
+<tr>
+<td>Global identifier</td>
+<td>E, S</td>
+<td>GLOBAL_ID/I</td>
+<td></td>
+</tr>
+<tr>
+<td>Geometric topology</td>
+<td>S</td>
+<td>GEOM_DIMENSION/I, GLOBAL_ID/I,
+NAME/C*32,
+CATEGORY/C*32.
+GEOM_SENSE_2/EH[2],
+GEOM_SENSE_N_ENTS/EH*N,
+GEOM_SENSE_N_SENSES/I*N</td>
+<td>Sets contain mesh owned by that entity; parent/child links to bounded/=
bounding entities in geometric model</td>
+</tr>
+<tr>
+<td>Material type</td>
+<td>S</td>
+<td>MATERIAL_SET/I</td>
+<td>Set contains entities or sets assigned a common material type</td>
+</tr>
+<tr>
+<td>Boundary condition</td>
+<td>S</td>
+<td>DIRICHLET_SET/I, NEUMANN_SET/I</td>
+<td>Set contains entities or sets assigned a particular boundary condition=
; neumann sets usually contain edges (2D) or faces (3D)</td>
+</tr>
+<tr>
+<td>Parallel mesh constructs</td>
+<td>E, S</td>
+<td>PARALLEL_PART/I, PARALLEL_PARTITION/I, PSTATUS/C*1, PARALLEL_SHARED_PR=
OC/I, PARALLEL/SHARED_HANDLE/H, PARALLEL_SHARED_PROCS/I*NP, PARALLEL_SHARED=
_HANDLES/H*NP</td>
+<td> Data which describes parallel mesh</td>
+</tr>
+<tr>
+<td>Structured mesh constructs</td>
+<td>S</td>
+<td>BOX_DIMS/I*6, GLOBAL_BOX_DIMS/I*6, BOX_PERIODIC/2*I, __BOX_SET/O</td>
+<td>Data describing structured mesh </td>
+</tr>
+<tr>
+<td>Spectral mesh constructs </td>
+<td>E, S</td>
+<td>SPECTRAL_ORDER/I, SPECTRAL_VERTICES/I*(O+1)^2</td>
+<td>Data marking spectral mesh constructs</td>
+</tr>
+</table>
+=20
+  \ref meta-introduction "Back to Introduction"
+
+  \subsection table2 Table 2: Summary of MOAB conventional tag names, type=
s, and purposes.  Data types are I=3Dinteger, D=3Ddouble, C=3Dcharacter, H=
=3Dentity handle,O=3Dopaque.  Data type with *x denote length of x elements=
 of that data type.
+
+<Table border=3D"1">
+<tr>
+<th>Tag name</th>
+<th>Data type</th>
+<th>Applies to (E=3Dentity, S=3Dset)</th>
+<th>Purpose</th>
+</tr>
+<tr>
+<td>BOX_DIMS</td>
+<td>I*6</td>
+<td>S</td>
+<td>Lower and upper ijk dimensions of box, ordered (ilo, jlo, klo, ihi, jh=
i, khi)</td>
+</tr>
+<tr>
+<td>BOX_PERIODIC</td>
+<td>I*2</td>
+<td>S</td>
+<td>Indicates whether box is periodic in i (BOX_PERIODIC[0]) or j (BOX_PER=
IODIC[1])</td>
+</tr>
+<tr>
+<td>__BOX_SET</td>
+<td>O</td>
+<td>S</td>
+<td>Pointer to corresponding ScdBox instance</td>
+</tr>
+<tr>
+<td>CATEGORY</td>
+<td>C*32</td>
+<td>S</td>
+<td>String describing purpose of set; examples include =E2=80=9Cgroup=E2=
=80=9D, =E2=80=9Cvertex=E2=80=9D, =E2=80=9Cedge=E2=80=9D, =E2=80=9Csurface=
=E2=80=9D, =E2=80=9Cvolume=E2=80=9D</td>
+</tr>
+<tr>
+<td>DIRICHLET_SET </td>
+<td>I</td>
+<td>SO</td>
+<td>Entities or sets with common boundary condition</td>
+</tr>
+<tr>
+<td>GEOM_DIMENSION</td>
+<td>I</td>
+<td>S</td>
+<td>Identifies mesh entities resolving a given geometric model entity</td>
+</tr>
+<tr>
+<td>GEOM_SENSE_2</td>
+<td>EH*2</td>
+<td>S</td>
+<td> Stored on face-type geometric topology sets, values store regions hav=
ing forward and reverse sense</td>
+</tr>
+<tr>
+<td>GEOM_SENSE_N_ENTS</td>
+<td>EH*N</td>
+<td>S</td>
+<td>Stored on edge-type geometric topology sets, values store faces whose =
senses are stored in GEOM_SENSE_N_SENSES.</td>
+</tr>
+<tr>
+<td>GEOM_SENSE_N_SENSES</td>
+<td>I*N</td>
+<td>S</td>
+<td>Stored on edge-type geometric topology sets, values store senses of th=
e edge with respect to faces stored in GEOM_SENSE_N_ENTS.</td>
+</tr>
+<tr>
+<td>GLOBAL_ID</td>
+<td>I</td>
+<td>E,S</td>
+<td>Application-specific entity id</td>
+</tr>
+<tr>
+<td>MATERIAL_SET</td>
+<td>I</td>
+<td>S</td>
+<td>Entities or sets grouped by material type</td>
+</tr>
+<tr>
+<td>NAME</td>
+<td>C*32</td>
+<td>E, S</td>
+<td>User-assigned entity name(s); multiple names delimited with ?</td>
+</tr>
+<tr>
+<td>NEUMANN_SET</td>
+<td>I</td>
+<td>S</td>
+<td>Entities or sets with common boundary condition </td>
+</tr>
+<tr>
+<td>PARALLEL_PART </td>
+<td>I</td>
+<td>S</td>
+<td>Represent a part in a partition</td>
+</tr>
+<tr>
+<td>PARALLEL_PARTITION</td>
+<td>I</td>
+<td>S</td>
+<td>Represents a partition of the mesh for parallel solution, which is a c=
ollection of parts</td>
+</tr>
+<tr>
+<td>__PARALLEL_SHARED_HANDLEd</td>
+<td>H</td>
+<td>E, S</td>
+<td> Handle of this entity/set on sharing processor</td>
+</tr>
+<tr>
+<td>__PARALLEL_SHARED_PROC</td>
+<td>I</td>
+<td>E,S</td>
+<td>Rank of other processor sharing this entity/set </td>
+</tr>
+</table>
+
+\ref meta-data-info "Top"
+
+  \section appendixB Appendix B: CCMIO (Star-CD, Star-CCM+) Reader/Writer =
Conventions
+
+  \subsection table3 Table 3: Translation between CCMIO options and MOAB t=
ags.
+<Table border=3D"1">
+<tr>
+<th> Set Type</th>
+<th>CCMIO Construct</th>
+<th>MOAB Tag Name, Type</th>
+</tr>
+<tr>
+<td rowspan=3D"2">File set / Interface</td>
+<td>Title (option)</td>
+<td>=E2=80=9CTitle=E2=80=9D (C*32)</td>
+</tr>
+<tr>
+<td>CreatingProgram</td>
+<td>=E2=80=9CCreatingProgram=E2=80=9D (C*32)</td>
+</tr>
+<tr>
+<td rowspan=3D"13">Material sets</td>
+<td>Index</td>
+<td>MATERIAL_SET</td>
+</tr>
+<tr>
+<td>Label<sup>1</sup></td>
+<td>NAME</td>
+</tr>
+<tr>
+<td>MaterialId</td>
+<td>=E2=80=9CMaterialId=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>Radiation</td>
+<td>=E2=80=9CRadiation=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>PorosityId</td>
+<td>=E2=80=9CPorosityId=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>SpinId</td>
+<td>=E2=80=9CSpinId=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>GroupId</td>
+<td>=E2=80=9CGroupId=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>ColorIdx</td>
+<td>=E2=80=9CColorIdx=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>ProcessorId</td>
+<td>=E2=80=9CProcessorId=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>LightMaterial</td>
+<td>=E2=80=9CLightMaterial=E2=80=9D (I)</td>
+</tr>
+<tr>
+<td>FreeSurfaceMaterial</td>
+<td>=E2=80=9CThickness=E2=80=9D (F)</td>
+</tr>
+<tr>
+<td>Thickness</td>
+<td>=E2=80=9CThickness=E2=80=9D (F)</td>
+</tr>
+<tr>
+<td>MaterialType</td>
+<td>=E2=80=9CMaterialType=E2=80=9D (C*32)</td>
+</tr>
+<tr>
+<td rowspan=3D"5">Neumann sets</td>
+<td>Index</td>
+<td>NEUMANN_SET</td>
+</tr>
+<tr>
+<td>Label</td>
+<td>NEUMANN_SET</td>
+</tr>
+<tr>
+<td>BoundaryName</td>
+<td>NAME</td>
+</tr>
+<tr>
+<td>BoundaryType</td>
+<td>=E2=80=9CBoundaryType=E2=80=9D (C*32)</td>
+</tr>
+<tr>
+<td>ProstarRegionNumber</td>
+<td>=E2=80=9CProstarRegionNumber=E2=80=9D (I)</td>
+</tr>
+</table>
+
+Notes:
+1. If no name is present, labels the material group with =E2=80=9CMaterial=
X=E2=80=9D, where X is the index of that group.
+
+\ref meta-data-info "Top"
+
+  \section appendixC Appendix C: ExodusII Reader/Writer Conventions=20
+
+  \subsection table4 Table 4: Translation between ExodusII constructs and =
MOAB tags.
+<Table border=3D"1">
+<tr>
+<th> Data Type</th>
+<th>ExodusII Construct</th>
+<th>MOAB Tag Name, Type</th>
+</tr>
+<tr>
+<td></td>
+<td>QA records</td>
+<td>=E2=80=9CqaRecord=E2=80=9D (C*(v))<sup>2</sup></td>
+</tr>
+<tr>
+<td rowspan=3D"2">Material sets</td>
+<td>Block number</td>
+<td>MATERIAL_SET</td>
+</tr>
+<tr>
+<td>Block element type</td>
+<td>Entity type, # vertices per entity</td>
+</tr>
+<tr>
+<td rowspan=3D"2">Dirichlet sets<sup>3</sup></td>
+<td>Nodeset number</td>
+<td>DIRICHLET_SET</td>
+</tr>
+<tr>
+<td>Distribution factors</td>
+<td>=E2=80=9CdistFactor=E2=80=9D (D*(v))<sup>1</sup></td>
+</tr>
+<tr>
+<td>Neumann sets</td>
+<td>Sideset number</td>
+<td>NEUMANN_SET</td>
+</tr>
+<tr>
+<td rowspan=3D"2">Neumann sets, reverse faces3<sup>3</sup></td>
+<td>Distribution factors</td>
+<td>=E2=80=9CdistFactor=E2=80=9D (D*(v))<sup>1</sup></td>
+</tr>
+<tr>
+<td>Sides</td>
+<td>SENSE</td>
+</tr>
+<tr>
+<td>Nodes, elements</td>
+<td>node_num_map, elem_map</td>
+<td>GLOBAL_ID on nodes/elements</td>
+</tr>
+</table>
+
+Notes:
+-# Variable-length tag used for distribution factors; length for each set =
is the number of entities in
+each set, such that there is one distribution factor for each entity in th=
e set.
+-# QA records are stored as variable-length tags on file set specified on =
read. Tag is a
+concatenation of QA record strings into a single string, with '\0' used to=
 delimit lines.
+-# MOAB represents sidesets as sets of faces, rather than as sides of elem=
ents. Faces can be
+ordered =E2=80=9Cforward=E2=80=9D or =E2=80=9Creverse=E2=80=9D with respec=
t to one of the bounding elements, depending on
+whether the right-hand normal points into or out of the element. Forward-s=
ense faces are added
+to the Neumann set. Reverse-sense faces are put into a separate set; that =
set is tagged with the SENSE tag, with value =3D -1; and that reverse set i=
s added to the Neummann set.
+.
+
+  \ref meta-data-info "Top"
+
+  \section appendixD Appendix D: NC (Climate Data) Reader/Writer Conventio=
ns
+
+The climate data reader in MOAB reads files with the '.nc' filename extens=
ion. By default, this reader
+reads the whole mesh in the file and creates it as structured mesh in MOAB=
, with the mesh accessible
+through MOAB's structured mesh interface. By default, all variables and ti=
mesteps are read from the
+file, and written as tags on the mesh vertices from that file. This behavi=
or is controlled by the
+=E2=80=9Cvariable=E2=80=9D, =E2=80=9Cnomesh=E2=80=9D, =E2=80=9Ctimestep=E2=
=80=9D, and =E2=80=9Ctimeval=E2=80=9D options described earlier in this doc=
ument. If MOAB
+is compiled for parallel execution and configured with a pnetcdf reader, t=
he mesh is read in parallel,
+with a 1D or 2D decomposition designed to balance read performance and com=
munication interface
+size (for details on the partitioning method used, see the src/io/ReadNC.c=
pp source file).
+
+Mesh is put into the entity set provided to the load_file function. This e=
ntity set is also annotated with
+various tags representing information read from the file. These tags are d=
escribed in Table 5.
+
+Several other things to note about reading climate data files into MOAB:
+- Time-dependent variables: MOAB currently has no mechanism for time-depen=
dent tags. Therefore, time-dependent variables are represented using one ta=
g per timestep, with the tag name set as the variable name plus the timeste=
p index. Thus, the first few timesteps for the variable TEMPERATURE would b=
e represented in tags named TEMPERATURE0, TEMPERATURE1, etc.
+- Cell- and face-centered variables: The climate data reader currently doe=
s not do cell- and face-
+centered variables correctly.
+.
+  \subsection table5 Table 5: Summary of MOAB conventional tag names, type=
s, and purposes. Data types are I=3Dinteger, D=3Ddouble, C=3Dcharacter, H=
=3Dentity handle. Data type with *x denote length of x elements of that dat=
a type; data type with *var denote variable-length tag. Tag names with two =
underscores prepended (=E2=80=9C__=E2=80=9D) denote tags not written to a f=
ile by MOAB.
+
+<Table border=3D"1">
+<tr>
+<th> Tag name </th>
+<th>Data type </th>
+<th> Applies to (E=3Dentity, S=3Dset) </th>
+<th>Purpose </th>
+</tr>
+<tr>
+<td>__NUM_DIMS </td>
+<td>I</td>
+<td>S</td>
+<td>The number of dimensions in the netcdf file.</td>
+</tr>
+<tr>
+<td>__NUM_VARS</td>=20
+<td>I</td>
+<td>S</td>
+<td>The number of variables in the netcdf file.</td>
+</tr>
+<tr>
+<td>__DIM_NAMES </td>
+<td>C*var </td>
+<td>S </td>
+<td>The dimension names, concatenated into a
+character string, with '\0' terminating each name.
+ </td>
+</tr>
+<tr>
+<td>__DIM_NAMES=20
+</td>
+<td>C*var</td>
+<td>S</td>
+<td>The variable names, concatenated into a character
+string, with '\0' terminating each name.
+</td>
+</tr>
+<tr>
+<td><dim_name>=20
+</td>
+<td>(I or=20
+D)*va=20
+</td>
+<td>S</td>
+<td>For each dimension, the values for the dimension.
+The data type for this tag corresponds to that in the
+netcdf file. The length of this tag is the number of
+values stored for the dimension in the netcdf file.</td>
+</tr>
+<tr>
+<td>__<dim_name>_LOC_MIN MAX</td>=20
+<td>2*(I or D)</td>
+<td>S</td>
+<td>The indices (0-based) of the local min and max
+values of dimension stored locally. For spatial
+dimensions like lon or lat, this will store the
+minimum and maximum indices in the loca</td>
+</tr>
+<tr>
+<td >__<dim_name>_LOC_VAL </td>=20
+<td>(I or D)*var </td>
+<td>S</td>
+<td>The indices (0-based) of the dimension stored
+locally. This tag only makes sense for dimensions
+that can be read in multiple pieces, such as time.
+Only one of __<dim_name>_LOC_VALS and
+_LOC_MIN_MAX can be used for a given
+dimension.
+</tr>
+<tr>
+<td>__<var_name>_DIMS=20
+</td>
+<td>C*n=20
+</td>
+<td>S</td>
+<td>For each variable, the tag handles for the
+dimensions defining this variable, in netcdf
+ordering (last dimension varying fastest). The
+length of this tag, n, is # dimensions for the
+variable * sizeof(TagHandle).
+</td>
+</tr>
+<tr>
+<td><var_name><timestep_ind>=20
+</td>
+<td>(data type)</td>
+<td>E</td>
+<td>Values of the variable for timestep <timestep_ind>
+for vertices. The data type of this tag corresponds
+to that of the variable from the netcdf file.
+Timestep index is 0-based.
+</td>
+</tr>
+<tr>
+<td>__GLOBAL_ATTRIBS=20
+</td>
+<td>C*Var=20
+</td>
+<td>S</td>
+<td>The global attributes, concatenated into a character
+string, with =E2=80=98\0=E2=80=99 terminating each attribute name, =E2=80=
=98;=E2=80=99
+       separating the data type and value, and =E2=80=98;=E2=80=99
+          separating one name/data type/value from the next.
+</td>
+</tr>
+<tr>
+<td>__GLOBAL_ATTRIBS_LEN=20
+</td>
+<td>I*Var=20
+</td>
+<td>S</td>
+<td>A vector of integers, marking the end position of
+each attribute (name/data type/value) in __GLOBAL_ATTRIBS tag.
+</td>
+</tr>
+<tr>
+<td>__<var_name>_ATTRIBS=20
+</td>
+<td>C*Var
+</td>
+<td>S</td>
+<td>The variable attributes, concatenated into a
+character string, with =E2=80=98\0=E2=80=99 terminating each attribute
+   name, =E2=80=98;=E2=80=99 separating the data type and value, and =E2=
=80=98;=E2=80=99
+          separating one name/data type/value from the next.
+</td>
+</tr>
+<tr>
+<td>__<var_name>_ATTRIBS_LEN=20
+</td>
+<td>I*Var
+</td>
+<td>S</td>
+<td>A vector of integers, marking the end position of
+each attribute (name/data type/value) in
+__<var_name>_ATTRIBS tags
+</td>
+</tr>
+</table>
+
+  \ref meta-data-info "Top"
+
+  \section appendixE Appendix E: Nek5000 Reader/Writer Conventions
+
+Nek5000, or Nek, is a code that uses the spectral element method to model =
fluid, heat transfer,
+electromagnetics, and other physics. Nek uses unstructured hexahedral mesh=
es, with each hex element
+resolved by a structured grid of =E2=80=9CGauss Lebato Legendre=E2=80=9D (=
GLL) points. Nek can read meshes through
+MOAB, and can output physics variables and GLL points through MOAB as well.
+
+Since fluid is a single material in Nek, no material sets are needed. Boun=
dary conditions are mapped to
+Nek's cbc array using Neumann sets and a user-provided =E2=80=9Cusr_moab2n=
ek=E2=80=9D subroutine (for an example
+of this subroutine, see examples/moab/pipe.usr in the Nek source code). GL=
L point locations and fluid
+variables on those points are stored in tags on the hex elements. All hex =
elements have the same
+number of GLL points. The number of GLL points in each direction is stored=
 in a tag on the mesh
+instance. These tags are described in Table 6.
+
+GLL point locations and fluid variables are stored in lexicographic order,=
 similar to their storage order
+inside the Nek code.
+
+  \subsection table6 Table 6: Summary of MOAB conventional tag names, type=
s, and purposes for Nek. Data types are I=3Dinteger, D=3Ddouble, C=3Dcharac=
ter, H=3Dentity handle. Data type with *x denote length of x elements of th=
at data type; data type with *var denote variable-length tag. Tag names wit=
h two underscores prepended (=E2=80=9C__=E2=80=9D) denote tags not written =
to a file by MOAB.
+<Table border=3D"1">
+<tr>
+<th> Tag name </th>
+<th> Data Type</th>
+<th>Applies to (E=3Dentity, S=3Dset)</th>
+<th>Purpose</th>
+</tr>
+<tr>
+<td>SEM_DIMS</td>
+<td>I*3</td>
+<td>S</td>
+<td>The dimensions of the GLL mesh in each hex
+element.
+</td>
+</tr>
+<tr>
+<td>SEM_X</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>X position of GLL points (having nx*ny*nz
+values)
+</td>
+</tr>
+<tr>
+<td>SEM_Y</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Y position of GLL points (having nx*ny*nz values)</td>
+</tr>
+<tr>
+<td>SEM_Z</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Z position of GLL points (having nx*ny*nz values)</td>
+</tr>
+<tr>
+<td>VEL_X</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Fluid velocities in the x direction for GLL point
+array (having nx*ny*nz values)</td>
+</tr>
+<tr>
+<td>VEL_Y</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Fluid velocities in the y direction for GLL point
+array (having nx*ny*nz values)</td>
+</tr>
+<tr>
+<td>VEL_Z</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Fluid velocities in the z direction for GLL point
+array (having nx*ny*nz values)</td>
+</tr>
+<tr>
+<td>TEMP</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Fluid temperature for GLL point array (having
+nx*ny*nz values)
+</td>
+</tr>
+<tr>
+<td>PRESS</td>
+<td>D*nx*ny*nz</td>
+<td>E</td>
+<td>Fluid pressure for GLL point array (having
+nx*ny*nz values)
+</td>
+</tr>
+</table>
+  \ref meta-data-info "Top"
+	*/

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 38b4130..a1993c9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,8 +31,8 @@
     PolyElementSeq.cpp
     Range.cpp
     RangeSeqIntersectIter.cpp
-    ReadUtil.cpp
     ReaderWriterSet.cpp
+    ReadUtil.cpp
     ScdElementData.cpp
     ScdInterface.cpp
     ScdVertexData.cpp
@@ -56,11 +56,40 @@
     VertexSequence.cpp
     WriteUtil.cpp
   )
+
+  add_subdirectory( io )
+  set ( MOABIO_LIB_SRCS
+    io/IODebugTrack.cpp
+    io/ExoIIUtil.cpp
+    io/FileTokenizer.cpp
+    io/GmshUtil.cpp
+    io/ReadABAQUS.cpp
+    io/ReadGmsh.cpp
+    io/ReadIDEAS.cpp
+    io/ReadMCNP5.cpp
+    io/ReadNASTRAN.cpp
+    io/ReadSmf.cpp
+    io/ReadSms.cpp
+    io/ReadSTL.cpp
+    io/ReadTemplate.cpp
+    io/ReadTetGen.cpp
+    io/ReadTxt.cpp
+    io/ReadVtk.cpp
+    io/SMF_State.cpp
+    io/Tqdcfr.cpp
+    io/VtkUtil.cpp
+    io/WriteAns.cpp
+    io/WriteGMV.cpp
+    io/WriteGmsh.cpp
+    io/WriteSTL.cpp
+    io/WriteSmf.cpp
+    io/WriteTemplate.cpp
+    io/WriteVtk.cpp
+  )
   include_directories(
     ${MOAB_SOURCE_DIR}/src
-    ${MOAB_BINARY_DIR}/src
     ${MOAB_SOURCE_DIR}/src/io
-    ${MOAB_BINARY_DIR}/src/io
+    ${MOAB_SOURCE_DIR}/src/parallel
   )
=20
   if ( MOAB_USE_MPI )
@@ -82,12 +111,73 @@
   set_source_files_properties( ${MOAB_LIB_SRCS}
     COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}"
   )
+
+#  target_link_libraries( MOAB moabio )
+  if ( MOAB_USE_NETCDF )
+    find_package( NetCDF )
+    if ( NetCDF_FOUND )
+      set ( MOAB_DEFINES "${MOAB_DEFINES} -DNETCDF_FILE" )
+      set ( MOABIO_LIB_SRCS
+        ${MOABIO_LIB_SRCS}
+        io/ReadNCDF.cpp
+        io/WriteNCDF.cpp
+        io/WriteSLAC.cpp
+      )
+      include_directories(
+        ${NetCDF_INCLUDE_DIRECTORIES}
+      )
+    endif ( NetCDF_FOUND )
+  endif ( MOAB_USE_NETCDF )
+
+  if ( MOAB_USE_HDF )
+    # HDF5
+    find_package( HDF5 )
+    if ( HDF5_FOUND )
+      set ( MOAB_DEFINES "${MOAB_DEFINES} -DHDF5_FILE" )
+      check_function_exists( H5Pset_fapl_mpio MOAB_HDF_HAVE_PARALLEL )
+      set ( MOABIO_LIB_SRCS
+        ${MOABIO_LIB_SRCS}
+        io/HDF5Common.cpp
+        io/ReadHDF5.cpp
+        io/ReadHDF5Dataset.cpp
+        io/ReadHDF5VarLen.cpp
+        io/WriteHDF5.cpp
+      )
+
+#      if ( MOAB_USE_MPI AND MPI_FOUND )
+#        set ( MOABIO_LIB_SRCS
+#          ${MOABIO_LIB_SRCS}
+#          src/parallel/WriteHDF5Parallel.cpp
+#        )
+#      endif (MOAB_USE_MPI AND MPI_FOUND)
+
+      include_directories(
+        ${HDF5_INCLUDE_DIRECTORIES}
+        io/mhdf/include
+      )
+      add_subdirectory( io/mhdf )
+    endif ( HDF5_FOUND )
+  endif ( MOAB_USE_HDF )
+
+  set_source_files_properties( ${MOABIO_LIB_SRCS}
+    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}"
+  )
+
   add_library( MOAB
     ${MOAB_LIB_SRCS}
+    ${MOABIO_LIB_SRCS}
   )
- =20
-  add_subdirectory( io )
-  target_link_libraries( MOAB moabio )
+
+  if ( MOAB_USE_NETCDF AND NetCDF_FOUND )
+    MESSAGE( "Adding NetCDF dependency libraries: ${NetCDF_LIBRARIES}" )
+    target_link_libraries( MOAB ${NetCDF_LIBRARIES} )
+  endif ( MOAB_USE_NETCDF AND NetCDF_FOUND )
+
+  if ( MOAB_USE_HDF AND HDF5_FOUND )
+    MESSAGE( "Adding NetCDF dependency libraries: ${HDF5_LIBRARIES}" )
+#    add_dependencies( MOAB mhdf  )
+    target_link_libraries( MOAB mhdf ${HDF5_LIBRARIES} )
+  endif ( MOAB_USE_HDF AND HDF5_FOUND )
=20
   if ( MOAB_USE_MPI AND MPI_FOUND )
     add_subdirectory( parallel )

diff --git a/src/Skinner.cpp b/src/Skinner.cpp
index 1d284b7..5869777 100644
--- a/src/Skinner.cpp
+++ b/src/Skinner.cpp
@@ -453,16 +453,6 @@ ErrorCode Skinner::find_skin_noadj(const Range &source=
_entities,
   if(mTargetDim < 0 || source_dim > 3)
     return MB_FAILURE;
=20
-  //Core *this_core =3D dynamic_cast<Core*>(thisMB);
-  //bool use_adjs =3D false;
-  //if (!this_core->a_entity_factory()->vert_elem_adjacencies() &&
-  //  create_vert_elem_adjs)
-  //  this_core->a_entity_factory()->create_vert_elem_adjacencies();
-  //
-  //if (this_core->a_entity_factory()->vert_elem_adjacencies())
-  //  use_adjs =3D true;
-  //
-  //else=20
   initialize();
=20
   Range::const_iterator iter, end_iter;
@@ -477,7 +467,8 @@ ErrorCode Skinner::find_skin_noadj(const Range &source_=
entities,
   EntityHandle sub_conn[32];
   std::vector<EntityHandle> tmp_conn_vec;
   int num_nodes, num_sub_nodes, num_sides;
-  int sub_indices[32];
+  int sub_indices[32];// Also, assume that no polygon has more than 32 nod=
es
+  // we could increase that, but we will not display it right in visit moa=
b h5m , anyway
   EntityType sub_type;
=20
   // for each source entity
@@ -490,130 +481,95 @@ ErrorCode Skinner::find_skin_noadj(const Range &sour=
ce_entities,
    =20
     type =3D thisMB->type_from_handle(*iter);
     Range::iterator seek_iter;
-    Range dum_elems, dum_sub_elems;
    =20
-    // get connectivity of each n-1 dimension entity
-    num_sides =3D CN::NumSubEntities( type, mTargetDim );
+    // treat separately polygons (also, polyhedra will need special handli=
ng)
+    if (MBPOLYGON =3D=3D type)
+    {
+      num_sides =3D num_nodes;
+      sub_type =3D MBEDGE;
+      num_sub_nodes =3D 2;
+    }
+    else// get connectivity of each n-1 dimension entity
+      num_sides =3D CN::NumSubEntities( type, mTargetDim );
     for(int i=3D0; i<num_sides; i++)
     {
-      CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, sub_type, =
num_sub_nodes, sub_indices );
-      assert((size_t)num_sub_nodes <=3D sizeof(sub_indices)/sizeof(sub_ind=
ices[0]));
-      for(int j=3D0; j<num_sub_nodes; j++)
-        sub_conn[j] =3D conn[sub_indices[j]];
-     =20
-//      if (use_adjs) {
-//        dum_elems.clear();
-//        result =3D thisMB->get_adjacencies(sub_conn, num_sub_nodes, sour=
ce_dim, false,
-//                                         dum_elems);
-//        if (MB_SUCCESS !=3D result) return result;
-//        dum_elems =3D intersect( dum_elems, source_entities );
-//        if (dum_elems.empty()) {
-//          assert(false);  // should never happen
-//          return MB_FAILURE;
-//        }
-//        // if (dum_elems.size() > 2) {=20
-//          // source entities do not form a valid source-dim patch (t-jun=
ction).
-//          // do we care?
-//        // }
-//       =20
-//        if (1 =3D=3D dum_elems.size()) {
-//            // this sub_element is on the skin
-//
-//            // check for existing entity
-//          dum_sub_elems.clear();
-//          result =3D thisMB->get_adjacencies(sub_conn, num_sub_nodes, mT=
argetDim, false,
-//                                           dum_sub_elems);
-//          if (MB_SUCCESS !=3D result) return result;
-//          if (dum_sub_elems.empty()) {
-//              // need to create one
-//            EntityHandle tmphndl=3D0;
-//            int indices[MAX_SUB_ENTITY_VERTICES];
-//            EntityType new_type;
-//            int num_new_nodes;
-//            CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, ne=
w_type, num_new_nodes, indices );
-//            for(int j=3D0; j<num_new_nodes; j++)
-//              sub_conn[j] =3D conn[indices[j]];
-//       =20
-//            result =3D thisMB->create_element(new_type, sub_conn, =20
-//                                            num_new_nodes, tmphndl);
-//            forward_target_entities.insert(tmphndl);
-//          }
-//          else {
-//              // else find the relative sense of this entity to the sour=
ce_entity in this set
-//            int side_no, sense =3D 0, offset;
-//            if (source_entities.find(*dum_elems.begin()) =3D=3D source_e=
ntities.end()) {
-//              result =3D thisMB->side_number(*dum_elems.rbegin(), *dum_s=
ub_elems.begin(),
-//                                           side_no, sense, offset);
-//            }
-//            else {
-//              result =3D thisMB->side_number(*dum_elems.begin(), *dum_su=
b_elems.begin(),
-//                                           side_no, sense, offset);
-//            }
-//            if (-1 =3D=3D sense) reverse_target_entities.insert(*dum_sub=
_elems.begin());
-//            else if (1 =3D=3D sense) forward_target_entities.insert(*dum=
_sub_elems.begin());
-//            else return MB_FAILURE;
-//          }
-//        }
-//      }
-//      else {
-       =20
-          // see if we can match this connectivity with
-          // an existing entity
-        find_match( sub_type, sub_conn, num_sub_nodes, match, direct );
+      if(MBPOLYGON=3D=3Dtype)
+      {
+        sub_conn[0] =3D conn[i];
+        sub_conn[1] =3D conn[(i+1)%num_sides];
+      }
+      else
+      {
+        CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, sub_type=
, num_sub_nodes, sub_indices );
+        assert((size_t)num_sub_nodes <=3D sizeof(sub_indices)/sizeof(sub_i=
ndices[0]));
+        for(int j=3D0; j<num_sub_nodes; j++)
+          sub_conn[j] =3D conn[sub_indices[j]];
+      }
        =20
-          // if there is no match, create a new entity
-        if(match =3D=3D 0)
+        // see if we can match this connectivity with
+        // an existing entity
+      find_match( sub_type, sub_conn, num_sub_nodes, match, direct );
+
+        // if there is no match, create a new entity
+      if(match =3D=3D 0)
+      {
+        EntityHandle tmphndl=3D0;
+        int indices[MAX_SUB_ENTITY_VERTICES];
+        EntityType new_type;
+        int num_new_nodes;
+        if(MBPOLYGON=3D=3Dtype)
+        {
+          new_type =3D MBEDGE;
+          num_new_nodes =3D 2;
+        }
+        else
         {
-          EntityHandle tmphndl=3D0;
-          int indices[MAX_SUB_ENTITY_VERTICES];
-          EntityType new_type;
-          int num_new_nodes;
           CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, new_ty=
pe, num_new_nodes, indices );
           for(int j=3D0; j<num_new_nodes; j++)
             sub_conn[j] =3D conn[indices[j]];
-          result =3D thisMB->create_element(new_type, sub_conn, num_new_no=
des,
-                                          tmphndl);
-          assert(MB_SUCCESS =3D=3D result);
-          add_adjacency(tmphndl, sub_conn, CN::VerticesPerEntity(new_type)=
);
-          forward_target_entities.insert(tmphndl);
         }
-          // if there is a match, delete the matching entity
-          // if we can.=20
-        else
+        result =3D thisMB->create_element(new_type, sub_conn, num_new_node=
s,
+                                        tmphndl);
+        assert(MB_SUCCESS =3D=3D result);
+        add_adjacency(tmphndl, sub_conn, CN::VerticesPerEntity(new_type));
+        forward_target_entities.insert(tmphndl);
+      }
+        // if there is a match, delete the matching entity
+        // if we can.
+      else
+      {
+        if ( (seek_iter =3D forward_target_entities.find(match)) !=3D forw=
ard_target_entities.end())
         {
-          if ( (seek_iter =3D forward_target_entities.find(match)) !=3D fo=
rward_target_entities.end())
+          forward_target_entities.erase(seek_iter);
+          remove_adjacency(match);
+          if(/*!use_adjs &&*/ entity_deletable(match))
           {
-            forward_target_entities.erase(seek_iter);
-            remove_adjacency(match);
-            if(/*!use_adjs &&*/ entity_deletable(match))
-            {
-              result =3D thisMB->delete_entities(&match, 1);
-              assert(MB_SUCCESS =3D=3D result);
-            }
+            result =3D thisMB->delete_entities(&match, 1);
+            assert(MB_SUCCESS =3D=3D result);
+          }
+        }
+        else if ( (seek_iter =3D reverse_target_entities.find(match)) !=3D=
 reverse_target_entities.end())
+        {
+          reverse_target_entities.erase(seek_iter);
+          remove_adjacency(match);
+          if(/*!use_adjs &&*/ entity_deletable(match))
+          {
+            result =3D thisMB->delete_entities(&match, 1);
+            assert(MB_SUCCESS =3D=3D result);
           }
-          else if ( (seek_iter =3D reverse_target_entities.find(match)) !=
=3D reverse_target_entities.end())
+        }
+        else
+        {
+          if(direct =3D=3D FORWARD)
           {
-            reverse_target_entities.erase(seek_iter);
-            remove_adjacency(match);
-            if(/*!use_adjs &&*/ entity_deletable(match))
-            {
-              result =3D thisMB->delete_entities(&match, 1);
-              assert(MB_SUCCESS =3D=3D result);
-            }
+            forward_target_entities.insert(match);
           }
           else
           {
-            if(direct =3D=3D FORWARD)
-            {
-              forward_target_entities.insert(match);
-            }
-            else
-            {
-              reverse_target_entities.insert(match);
-            }
+            reverse_target_entities.insert(match);
           }
         }
-      //}
+      }
     }
   }
=20

diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
deleted file mode 100644
index d6c3e44..0000000
--- a/src/io/CMakeLists.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-
-  # MOAB Library
-  set ( MOABIO_LIB_SRCS
-    ExoIIUtil.cpp
-    FileTokenizer.cpp
-    GmshUtil.cpp
-    ReadABAQUS.cpp
-    ReadGmsh.cpp
-    ReadIDEAS.cpp
-    ReadMCNP5.cpp
-    ReadNASTRAN.cpp
-    ReadSmf.cpp
-    ReadSms.cpp
-    ReadSTL.cpp
-    ReadTemplate.cpp
-    ReadTetGen.cpp
-    ReadTxt.cpp
-    ReadVtk.cpp
-    SMF_State.cpp
-    Tqdcfr.cpp
-    VtkUtil.cpp
-    WriteAns.cpp
-    WriteGMV.cpp
-    WriteGmsh.cpp
-    WriteSTL.cpp
-    WriteSmf.cpp=20
-    WriteTemplate.cpp
-    WriteVtk.cpp
-  )
-  include_directories(
-    ${MOAB_SOURCE_DIR}/src
-    ${MOAB_BINARY_DIR}/src
-    ${MOAB_SOURCE_DIR}/src/parallel
-    ${MOAB_BINARY_DIR}/src/parallel
-  )
-
-  if ( MOAB_USE_NETCDF )
-    find_package( NetCDF )
-    if ( NetCDF_FOUND )
-      set ( MOAB_DEFINES "${MOAB_DEFINES} -DNETCDF_FILE" )
-      set ( MOABIO_LIB_SRCS
-        ${MOABIO_LIB_SRCS}
-        ReadNCDF.cpp
-        WriteNCDF.cpp
-        WriteSLAC.cpp
-      )
-      include_directories(
-        ${NetCDF_INCLUDE_DIRECTORIES}
-      )
-    endif ( NetCDF_FOUND )
-  endif ( MOAB_USE_NETCDF )
-
-  if ( MOAB_USE_HDF )
-    # HDF5
-    find_package( HDF5 )
-    if ( HDF5_FOUND )
-      set ( MOAB_DEFINES "${MOAB_DEFINES} -DHDF5_FILE" )
-      check_function_exists( H5Pset_fapl_mpio MOAB_HDF_HAVE_PARALLEL )
-      set ( MOABIO_LIB_SRCS
-        ${MOABIO_LIB_SRCS}
-        ReadHDF5.cpp
-        WriteHDF5.cpp
-      )
-      include_directories(
-        ${HDF5_INCLUDE_DIRECTORIES}
-        ${MOAB_SOURCE_DIR}/mhdf/include
-      )
-      add_subdirectory( mhdf )
-    endif ( HDF5_FOUND )
-  endif ( MOAB_USE_HDF )
-
-  set_source_files_properties( ${MOABIO_LIB_SRCS}
-    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}"
-  )
-  add_library( moabio
-    ${MOABIO_LIB_SRCS}
-  )
-
-  if ( MOAB_USE_HDF AND HDF5_FOUND )
-    target_link_libraries( moabio
-      mhdf
-      ${HDF5_LIBRARIES}
-    )
-  endif ( MOAB_USE_HDF AND HDF5_FOUND )
-
-  if ( MOAB_USE_NETCDF AND NetCDF_FOUND )
-    target_link_libraries( moabio
-      ${NetCDF_LIBRARIES}
-    )
-  endif ( MOAB_USE_NETCDF AND NetCDF_FOUND )

diff --git a/src/parallel/CMakeLists.txt b/src/parallel/CMakeLists.txt
index 598b6fc..7583885 100644
--- a/src/parallel/CMakeLists.txt
+++ b/src/parallel/CMakeLists.txt
@@ -5,8 +5,14 @@ set( moab_PARALLEL_SRCS
   ReadParallel.cpp
   gs.cpp
   TupleList.cpp
+  SharedSetData.cpp
 )
=20
+include_directories(
+    ${MOAB_SOURCE_DIR}/src
+    ${MOAB_SOURCE_DIR}/src/parallel
+  )
+
 if ( MOAB_USE_HDF AND MOAB_HDF_HAVE_PARALLEL )
   set( moab_PARALLEL_SRCS
     ${moab_PARALLEL_SRCS}
@@ -45,38 +51,3 @@ target_link_libraries( MOABpar
   ${MPI_EXTRA_LIBRARY}
 )
=20
-if ( MOAB_USE_MPI AND MPI_FOUND )
-  add_executable ( mbparallelcomm_test mbparallelcomm_test.cpp )
-  target_link_libraries( mbparallelcomm_test MOAB )
-  set_source_files_properties( mbparallelcomm_test.cpp
-    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
-  add_test( TestParallelComm-BcastDelete
-    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
-    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} 0 $=
{MOAB_SOURCE_DIR}/parallel/ptest.cub )
-  add_test( TestParallelComm-ReadDelete
-    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
-    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -1 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
-  add_test( TestParallelComm-ReadParallel
-    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
-    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -2 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
-  add_test( TestParallelComm-Broadcast
-    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
-    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -3 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
-
-  add_executable ( parallel_unit_tests parallel_unit_tests.cpp )
-  target_link_libraries( parallel_unit_tests MOAB )
-  add_test( TestParallel
-    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
-    ${EXECUTABLE_OUTPUT_PATH}/parallel_unit_tests ${MPIEXEC_POSTFLAGS} ${M=
OAB_SOURCE_DIR}/parallel/ptest.cub )
-  set_source_files_properties( parallel_unit_tests.cpp
-    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
-
-  if ( MOAB_USE_HDF )
-    add_executable( mhdf_parallel mhdf_parallel.c )
-    target_link_libraries( mhdf_parallel MOAB MOABpar mhdf )
-    add_test( TestMHDFParallel ${EXECUTABLE_OUTPUT_PATH}/mhdf_parallel )
-    set_source_files_properties( mhdf_parallel.c
-      COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
-  endif ( MOAB_USE_HDF )
-endif ( MOAB_USE_MPI AND MPI_FOUND )
-

diff --git a/src/parallel/ParallelComm.cpp b/src/parallel/ParallelComm.cpp
index ec908b9..348bad0 100644
--- a/src/parallel/ParallelComm.cpp
+++ b/src/parallel/ParallelComm.cpp
@@ -7234,7 +7234,7 @@ ErrorCode ParallelComm::post_irecv(std::vector<unsign=
ed int>& shared_procs,
       RRA("Failure in waitall in tag exchange.");
     }
  =20
-    myDebug->tprintf(1, "Exiting exchange_tags");
+    myDebug->tprintf(1, "Exiting reduce_tags");
=20
     return MB_SUCCESS;
   }

diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 030c3b4..3b1d28d 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2,9 +2,7 @@
=20
   include_directories(
     ${MOAB_SOURCE_DIR}/src
-    ${MOAB_BINARY_DIR}/src
     ${MOAB_SOURCE_DIR}/src/parallel
-    ${MOAB_BINARY_DIR}/src/parallel
   )
=20
   add_executable( moab_test MBTest.cpp )
@@ -43,3 +41,39 @@
   add_test( TestBSPTree ${EXECUTABLE_OUTPUT_PATH}/bsp_tree_test )
=20
=20
+if ( MOAB_USE_MPI AND MPI_FOUND )
+
+  add_executable ( mbparallelcomm_test mbparallelcomm_test.cpp )
+  target_link_libraries( mbparallelcomm_test MOAB )
+  set_source_files_properties( mbparallelcomm_test.cpp
+    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
+  add_test( TestParallelComm-BcastDelete
+    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
+    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} 0 $=
{MOAB_SOURCE_DIR}/parallel/ptest.cub )
+  add_test( TestParallelComm-ReadDelete
+    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
+    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -1 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
+  add_test( TestParallelComm-ReadParallel
+    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
+    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -2 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
+  add_test( TestParallelComm-Broadcast
+    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
+    ${EXECUTABLE_OUTPUT_PATH}/mbparallelcomm_test ${MPIEXEC_POSTFLAGS} -3 =
${MOAB_SOURCE_DIR}/parallel/ptest.cub )
+
+  if ( MOAB_USE_HDF )
+    add_executable( mhdf_parallel mhdf_parallel.c )
+    target_link_libraries( mhdf_parallel MOAB MOABpar mhdf )
+    add_test( TestMHDFParallel ${EXECUTABLE_OUTPUT_PATH}/mhdf_parallel )
+    set_source_files_properties( mhdf_parallel.c
+      COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
+  endif ( MOAB_USE_HDF )
+
+  add_executable ( parallel_unit_tests parallel_unit_tests.cpp )
+  target_link_libraries( parallel_unit_tests MOAB )
+  add_test( TestParallel
+    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
+    ${EXECUTABLE_OUTPUT_PATH}/parallel_unit_tests ${MPIEXEC_POSTFLAGS} ${M=
OAB_SOURCE_DIR}/parallel/ptest.cub )
+  set_source_files_properties( parallel_unit_tests.cpp
+    COMPILE_FLAGS "-DIS_BUILDING_MB ${MOAB_DEFINES}" )
+
+endif ( MOAB_USE_MPI AND MPI_FOUND )

diff --git a/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index bf5cbb8..f5c4b22 100644
--- a/test/parallel/par_intx_sph.cpp
+++ b/test/parallel/par_intx_sph.cpp
@@ -5,8 +5,7 @@
  *  the mesh is read in parallel; lagrangian mesh is manufactured on the f=
ly (part of the test), in
  *    a different set.
  *
- *  lagrangian mesh will be located on the euler mesh; intersections will =
be performed on the
- *  euler mesh
+ *  intersections will be performed on the euler mesh
  *  Created on: Nov 14, 2012
  */
=20
@@ -45,7 +44,6 @@ std::string input_mesh_file("Homme_2pt.h5m"); // input fi=
le, partitioned correct
 std::string mpas_file("mpas_p8.h5m");
 double CubeSide =3D 6.; // the above file starts with cube side 6; radius =
depends on cube side
 double radius;
-void test_intx_in_parallel();
 void test_intx_in_parallel_elem_based();
 void test_intx_mpas();
=20
@@ -75,7 +73,7 @@ int main(int argc, char **argv)
       index++;
     }
   }
-  //result +=3D RUN_TEST(test_intx_in_parallel);
+
   radius =3D CubeSide/2*sqrt(3.);
   result +=3D RUN_TEST(test_intx_in_parallel_elem_based);
   radius =3D1.;
@@ -157,67 +155,7 @@ ErrorCode  manufacture_lagrange_mesh_on_sphere(Interfa=
ce * mb, EntityHandle eule
=20
   return rval;
 }
-void test_intx_in_parallel()
-{
-  std::string opts =3D std::string("PARALLEL=3DREAD_PART;PARTITION=3DPARAL=
LEL_PARTITION")+
-      std::string(";PARALLEL_RESOLVE_SHARED_ENTS");
-  Core moab;
-  Interface & mb =3D moab;
-  EntityHandle euler_set;
-  ErrorCode rval;
-  rval =3D mb.create_meshset(MESHSET_SET, euler_set);
-  CHECK_ERR(rval);
-  std::string example(TestDir + "/" +  input_mesh_file);
-
-  rval =3D mb.load_file(example.c_str(), &euler_set, opts.c_str());
-
-  ParallelComm* pcomm =3D ParallelComm::get_pcomm(&mb, 0);
-  CHECK_ERR(rval);
-
-  rval =3D pcomm->check_all_shared_handles();
-  CHECK_ERR(rval);
-
-  // everybody will get a LOC tag, including the non owned entities; so ex=
change tags is not required for LOC (here)
-  rval =3D manufacture_lagrange_mesh_on_sphere(&mb, euler_set);
-  CHECK_ERR(rval);
-=20
-  Intx2MeshOnSphere worker(&mb);
=20
-  //double radius=3D CubeSide/2 * sqrt(3.) ; // input
-  worker.SetRadius(radius);
-  worker.set_box_error(EPS1);//
-  //worker.SetEntityType(MBQUAD);
-
-  worker.SetErrorTolerance(radius*1.e-8);
-  worker.locate_departure_points(euler_set);
-
-  // we need to make sure the covering set is bigger than the euler mesh
-  EntityHandle covering_lagr_set;
-  rval =3D mb.create_meshset(MESHSET_SET, covering_lagr_set);
-  CHECK_ERR(rval);
-
-  rval =3D worker.create_departure_mesh(covering_lagr_set);
-  CHECK_ERR(rval);
-  int rank =3D pcomm->proc_config().proc_rank();
-  std::stringstream ss;
-  ss<<"partial" << rank<<".vtk";
-  mb.write_file(ss.str().c_str(), 0, 0, &covering_lagr_set, 1);
-  EntityHandle outputSet;
-  rval =3D mb.create_meshset(MESHSET_SET, outputSet);
-  CHECK_ERR(rval);
-  rval =3D worker.intersect_meshes(covering_lagr_set, euler_set, outputSet=
);
-  CHECK_ERR(rval);
-
-  //std::string opts_write("PARALLEL=3DWRITE_PART");
-  //rval =3D mb.write_file("manuf.h5m", 0, opts_write.c_str(), &outputSet,=
 1);
-  std::string opts_write("");
-  std::stringstream outf;
-  outf<<"intersect" << rank<<".h5m";
-  rval =3D mb.write_file(outf.str().c_str(), 0, 0, &outputSet, 1);
-  CHECK_ERR(rval);
-
-
-}
 void test_intx_in_parallel_elem_based()
 {
   std::string opts =3D std::string("PARALLEL=3DREAD_PART;PARTITION=3DPARAL=
LEL_PARTITION")+

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/fathomteam/moab/commits/904a842703d1/
Changeset:   904a842703d1
Branch:      None
User:        danwu
Date:        2013-07-01 23:26:09
Summary:     In read_mpas_nc.cpp, restore some test functions that were com=
mented out before.

Affected #:  1 file

diff --git a/test/io/read_mpas_nc.cpp b/test/io/read_mpas_nc.cpp
index 49ce0e2..4ab8568 100644
--- a/test/io/read_mpas_nc.cpp
+++ b/test/io/read_mpas_nc.cpp
@@ -33,10 +33,10 @@ int main(int argc, char* argv[])
   argv[0] =3D argv[argc-argc]; // To remove the warnings in serial mode ab=
out unused variables
 #endif
=20
-  //result +=3D RUN_TEST(test_read_all);
-  //result +=3D RUN_TEST(test_read_onevar);
-  //result +=3D RUN_TEST(test_read_onetimestep);
-  //result +=3D RUN_TEST(test_read_nomesh);
+  result +=3D RUN_TEST(test_read_all);
+  result +=3D RUN_TEST(test_read_onevar);
+  result +=3D RUN_TEST(test_read_onetimestep);
+  result +=3D RUN_TEST(test_read_nomesh);
   result +=3D RUN_TEST(test_read_novars);
=20
 #ifdef USE_MPI


https://bitbucket.org/fathomteam/moab/commits/aa6f53b16e4a/
Changeset:   aa6f53b16e4a
Branch:      master
User:        iulian07
Date:        2013-07-02 00:32:10
Summary:     Merged in danwu/moab (pull request #7)

Latest code changes for MPAS reader
Affected #:  18 files

diff --git a/MeshFiles/unittest/io/mpasx1.642.t.2.nc b/MeshFiles/unittest/i=
o/mpasx1.642.t.2.nc
new file mode 100644
index 0000000..f1e8c94
Binary files /dev/null and b/MeshFiles/unittest/io/mpasx1.642.t.2.nc differ

diff --git a/src/io/Makefile.am b/src/io/Makefile.am
index b7eae6a..bb5b7cb 100644
--- a/src/io/Makefile.am
+++ b/src/io/Makefile.am
@@ -21,6 +21,7 @@ if NETCDF_FILE
                      NCHelperEuler.cpp NCHelperEuler.hpp \
                      NCHelperFV.cpp NCHelperFV.hpp \
                      NCHelperHOMME.cpp NCHelperHOMME.hpp \
+                     NCHelperMPAS.cpp NCHelperMPAS.hpp \
                      ReadGCRM.cpp ReadGCRM.hpp
 else
   MOAB_NETCDF_SRCS =3D
@@ -33,6 +34,7 @@ if !NETCDF_FILE
                      NCHelperEuler.cpp NCHelperEuler.hpp \
                      NCHelperFV.cpp NCHelperFV.hpp \
                      NCHelperHOMME.cpp NCHelperHOMME.hpp \
+                     NCHelperMPAS.cpp NCHelperMPAS.hpp \
                      ReadGCRM.cpp ReadGCRM.hpp
 endif
 endif

diff --git a/src/io/NCHelper.cpp b/src/io/NCHelper.cpp
index e0f021e..e0eae99 100644
--- a/src/io/NCHelper.cpp
+++ b/src/io/NCHelper.cpp
@@ -2,20 +2,858 @@
 #include "NCHelperEuler.hpp"
 #include "NCHelperFV.hpp"
 #include "NCHelperHOMME.hpp"
+#include "NCHelperMPAS.hpp"
+
 #include "moab/ReadUtilIface.hpp"
+#include "MBTagConventions.hpp"
+
+#define ERRORR(rval, str) \
+    if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", =
str); return rval;}
+
+#define ERRORS(err, str) \
+    if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_F=
AILURE;}
=20
 namespace moab {
=20
 NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int fileId, const FileOp=
tions& opts)
 {
-  if (NCHelperEuler::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperEuler(readNC, fileId);
-  else if (NCHelperFV::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperFV(readNC, fileId);
-  else if (NCHelperHOMME::can_read_file(readNC, fileId))
-    return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts);
-  else // Unknown NetCDF grid (will fill this in later for POP, CICE and C=
LM)
-    return NULL;
+  // Check if CF convention is being followed
+  bool is_CF =3D false;
+
+  std::map<std::string, ReadNC::AttData>& globalAtts =3D readNC->globalAtt=
s;
+  std::map<std::string, ReadNC::AttData>::iterator attIt =3D globalAtts.fi=
nd("conventions");
+  if (attIt =3D=3D globalAtts.end())
+    attIt =3D globalAtts.find("Conventions");
+
+  if (attIt !=3D globalAtts.end()) {
+    unsigned int sz =3D attIt->second.attLen;
+    std::string att_data;
+    att_data.resize(sz + 1);
+    att_data[sz] =3D '\000';
+    int success =3D NCFUNC(get_att_text)(fileId, attIt->second.attVarId, a=
ttIt->second.attName.c_str(), &att_data[0]);
+    if (0 =3D=3D success && att_data.find("CF") !=3D std::string::npos)
+      is_CF =3D true;
+  }
+
+  if (is_CF) {
+    if (NCHelperEuler::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperEuler(readNC, fileId);
+    else if (NCHelperFV::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperFV(readNC, fileId);
+    else if (NCHelperHOMME::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts);
+  }
+  else {
+    if (NCHelperMPAS::can_read_file(readNC, fileId))
+      return new (std::nothrow) NCHelperMPAS(readNC, fileId, opts);
+  }
+
+  // Unknown NetCDF grid (will fill this in later for POP, CICE and CLM)
+  return NULL;
+}
+
+ErrorCode NCHelper::read_variable_to_set_allocate(std::vector<ReadNC::VarD=
ata>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if ((std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDi=
m) !=3D vdatas[i].varDims.end()))
+      vdatas[i].has_t =3D true;
+
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      // get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[=
i].varTags[t]);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t)
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+
+      // set up the dimensions and counts
+      // first variable dimension is time, if it exists
+      if (vdatas[i].has_t)
+      {
+        if (vdatas[i].varDims.size() !=3D 1)
+        {
+          vdatas[i].readDims[t].push_back(tstep_nums[t]);
+          vdatas[i].readCounts[t].push_back(1);
+        }
+        else
+        {
+          vdatas[i].readDims[t].push_back(0);
+          vdatas[i].readCounts[t].push_back(tstep_nums.size());
+        }
+      }
+
+      // Set up other dimensions and counts
+      if (vdatas[i].varDims.empty()) {
+        // Scalar variable
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(1);
+      }
+      else {
+        for (unsigned int idx =3D 0; idx !=3D vdatas[i].varDims.size(); id=
x++){
+          if (tDim !=3D vdatas[i].varDims[idx]){
+            // Push other variable dimensions, except time, which was alre=
ady pushed
+            vdatas[i].readDims[t].push_back(0);
+            vdatas[i].readCounts[t].push_back(dimVals[vdatas[i].varDims[id=
x]]);
+          }
+        }
+      }
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      vdatas[i].sz =3D sz;
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          vdatas[i].varDatas[t] =3D new char[sz];
+          break;
+        case NC_DOUBLE:
+        case NC_FLOAT:
+          vdatas[i].varDatas[t] =3D new double[sz];
+          break;
+        case NC_INT:
+        case NC_SHORT:
+          vdatas[i].varDatas[t] =3D new int[sz];
+          break;
+        default:
+          std::cerr << "Unrecognized data type for tag " << std::endl;
+          rval =3D MB_FAILURE;
+      }
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode NCHelper::read_variable_to_set(EntityHandle file_set, std::vecto=
r<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  std::set<std::string>& dummyVarNames =3D _readNC->dummyVarNames;;
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_variable_to_set_allocate(vdatas, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables to set.");
+
+  // finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    if (dummyVarNames.find(vdatas[i].varName) !=3D dummyVarNames.end() )
+       continue;// this is a dummy one, we don't have it; we created it fo=
r the dummy tag
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      void* data =3D vdatas[i].varDatas[t];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR:
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (char*) data NCREQ);
+          ERRORS(success, "Failed to read char data.");
+          break;
+        case NC_DOUBLE:
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (double*) data NCREQ);
+          ERRORS(success, "Failed to read double data.");
+          break;
+        case NC_FLOAT: {
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (float*) data NCREQ);
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT:
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (int*) data NCREQ);
+          ERRORS(success, "Failed to read int data.");
+          break;
+        case NC_SHORT:
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              (short*) data NCREQ);
+          ERRORS(success, "Failed to read short data.");
+          break;
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vd=
atas[i].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], =
&file_set, 1, &(vdatas[i].varDatas[t]), &vdatas[i].sz);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+      if (vdatas[i].varDims.size() <=3D 1)
+        break;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode NCHelper::convert_variable(ReadNC::VarData& var_data, int tstep_=
num)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  // Get ptr to tag space
+  void* data =3D var_data.varDatas[tstep_num];
+
+  std::size_t sz =3D 1;
+  for (std::size_t idx =3D 0; idx !=3D var_data.readCounts[tstep_num].size=
(); idx++)
+    sz *=3D var_data.readCounts[tstep_num][idx];
+
+  // Finally, read into that space
+  int success =3D 0;
+  int* idata;
+  double* ddata;
+  float* fdata;
+  short* sdata;
+
+  switch (var_data.varDataType) {
+    case NC_FLOAT:
+      ddata =3D (double*) var_data.varDatas[tstep_num];
+      fdata =3D (float*) var_data.varDatas[tstep_num];
+      // Convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        ddata[i] =3D fdata[i];
+      break;
+    case NC_SHORT:
+      idata =3D (int*) var_data.varDatas[tstep_num];
+      sdata =3D (short*) var_data.varDatas[tstep_num];
+      // Convert in-place
+      for (int i =3D sz - 1; i >=3D 0; i--)
+        idata[i] =3D sdata[i];
+      break;
+    default:
+      success =3D 1;
+  }
+
+  if (2 <=3D dbgOut.get_verbosity() && !success) {
+    double dmin, dmax;
+    int imin, imax;
+    switch (var_data.varDataType) {
+      case NC_DOUBLE:
+      case NC_FLOAT:
+        ddata =3D (double*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        dmin =3D dmax =3D ddata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (ddata[i] < dmin)
+            dmin =3D ddata[i];
+          if (ddata[i] > dmax)
+            dmax =3D ddata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (double): min =3D %f, max =3D %f\n"=
, var_data.varName.c_str(), dmin, dmax);
+        break;
+      case NC_INT:
+      case NC_SHORT:
+        idata =3D (int*) data;
+        if (sz =3D=3D 0)
+          break;
+
+        imin =3D imax =3D idata[0];
+        for (unsigned int i =3D 1; i < sz; i++) {
+          if (idata[i] < imin)
+            imin =3D idata[i];
+          if (idata[i] > imax)
+            imax =3D idata[i];
+        }
+        dbgOut.tprintf(2, "Variable %s (int): min =3D %d, max =3D %d\n", v=
ar_data.varName.c_str(), imin, imax);
+        break;
+      case NC_NAT:
+      case NC_BYTE:
+      case NC_CHAR:
+        break;
+      default: // Default case added to remove compiler warnings
+        success =3D 1;
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::check_existing_mesh(EntityHandle file_set) {
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  int (&lDims)[6] =3D _readNC->lDims;
+
+  // Get the number of vertices
+  int num_verts;
+  ErrorCode rval =3D mbImpl->get_number_entities_by_dimension(file_set, 0,=
 num_verts);
+  ERRORR(rval, "Trouble getting number of vertices.");
+
+  // Check against parameters
+  if (num_verts > 0)
+  {
+    int expected_verts =3D (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1=
] + 1) * (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
+    if (num_verts !=3D expected_verts) {
+      ERRORR(MB_FAILURE, "Number of vertices doesn't match.");
+    }
+  }
+
+  // Check the number of elements too
+  int num_elems;
+  rval =3D mbImpl->get_number_entities_by_dimension(file_set, (-1 =3D=3D l=
Dims[2] ? 2 : 3), num_elems);
+  ERRORR(rval, "Trouble getting number of elements.");
+
+  /*
+  // Check against parameters
+  if (num_elems > 0)
+  {
+    int expected_elems =3D (lDims[3] - lDims[0]) * (lDims[4] - lDims[1]) *=
 (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2]);
+    if (num_elems !=3D expected_elems) {
+      ERRORR(MB_FAILURE, "Number of elements doesn't match.");
+    }
+  }
+  */
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::create_mesh(ScdInterface* scdi, const FileOptions& =
opts, EntityHandle file_set, Range& faces)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  int (&gDims)[6] =3D _readNC->gDims;
+  int (&lDims)[6] =3D _readNC->lDims;
+  std::vector<double>& ilVals =3D _readNC->ilVals;
+  std::vector<double>& jlVals =3D _readNC->jlVals;
+  std::vector<double>& klVals =3D _readNC->klVals;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  int (&locallyPeriodic)[2] =3D _readNC->locallyPeriodic;
+  int (&globallyPeriodic)[2] =3D _readNC->globallyPeriodic;
+  ScdParData& parData =3D _readNC->parData;
+
+  Range tmp_range;
+  ScdBox *scd_box;
+
+  ErrorCode rval =3D scdi->construct_box(HomCoord(lDims[0], lDims[1], lDim=
s[2], 1), HomCoord(lDims[3], lDims[4], lDims[5], 1), NULL,
+      0, scd_box, locallyPeriodic, &parData);
+  ERRORR(rval, "Trouble creating scd vertex sequence.");
+
+  // Add box set and new vertices, elements to the file set
+  tmp_range.insert(scd_box->start_vertex(), scd_box->start_vertex() + scd_=
box->num_vertices() - 1);
+  tmp_range.insert(scd_box->start_element(), scd_box->start_element() + sc=
d_box->num_elements() - 1);
+  tmp_range.insert(scd_box->box_set());
+  rval =3D mbImpl->add_entities(file_set, tmp_range);
+  ERRORR(rval, "Couldn't add new vertices to file set.");
+
+  dbgOut.tprintf(1, "scdbox %d quads, %d vertices\n", scd_box->num_element=
s(), scd_box->num_vertices());
+
+  // Get a ptr to global id memory
+  void* data;
+  int count;
+  const Range::iterator topv =3D tmp_range.upper_bound(tmp_range.begin(), =
tmp_range.end(), scd_box->start_vertex()
+      + scd_box->num_vertices());
+  rval =3D mbImpl->tag_iterate(mGlobalIdTag, tmp_range.begin(), topv, coun=
t, data);
+  ERRORR(rval, "Failed to get tag iterator.");
+  assert(count =3D=3D scd_box->num_vertices());
+  int* gid_data =3D (int*) data;
+
+  // Set the vertex coordinates
+  double *xc, *yc, *zc;
+  rval =3D scd_box->get_coordinate_arrays(xc, yc, zc);
+  ERRORR(rval, "Couldn't get vertex coordinate arrays.");
+
+  int i, j, k, il, jl, kl, itmp;
+  int dil =3D lDims[3] - lDims[0] + 1;
+  int djl =3D lDims[4] - lDims[1] + 1;
+  int di =3D gDims[3] - gDims[0] + 1;
+  int dj =3D gDims[4] - gDims[1] + 1;
+  assert(dil =3D=3D (int)ilVals.size() && djl =3D=3D (int)jlVals.size() &&
+      (-1 =3D=3D lDims[2] || lDims[5]-lDims[2]+1 =3D=3D (int)klVals.size()=
));
+#define INDEX(i, j, k) ()
+  for (kl =3D lDims[2]; kl <=3D lDims[5]; kl++) {
+    k =3D kl - lDims[2];
+    for (jl =3D lDims[1]; jl <=3D lDims[4]; jl++) {
+      j =3D jl - lDims[1];
+      for (il =3D lDims[0]; il <=3D lDims[3]; il++) {
+        i =3D il - lDims[0];
+        unsigned int pos =3D i + j * dil + k * dil * djl;
+        xc[pos] =3D ilVals[i];
+        yc[pos] =3D jlVals[j];
+        zc[pos] =3D (-1 =3D=3D lDims[2] ? 0.0 : klVals[k]);
+        itmp =3D (!locallyPeriodic[0] && globallyPeriodic[0] && il =3D=3D =
gDims[3] ? gDims[0] : il);
+        *gid_data =3D (-1 !=3D kl ? kl * di * dj : 0) + jl * di + itmp + 1;
+        gid_data++;
+      }
+    }
+  }
+#undef INDEX
+
+#ifndef NDEBUG
+  int num_verts =3D (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1] + 1) =
* (-1 =3D=3D lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
+  std::vector<int> gids(num_verts);
+  Range verts(scd_box->start_vertex(), scd_box->start_vertex() + scd_box->=
num_vertices() - 1);
+  rval =3D mbImpl->tag_get_data(mGlobalIdTag, verts, &gids[0]);
+  ERRORR(rval, "Trouble getting gid values.");
+  int vmin =3D *(std::min_element(gids.begin(), gids.end())), vmax =3D *(s=
td::max_element(gids.begin(), gids.end()));
+  dbgOut.tprintf(1, "Vertex gids %d-%d\n", vmin, vmax);
+#endif
+
+  // add elements to the range passed in
+  faces.insert(scd_box->start_element(), scd_box->start_element() + scd_bo=
x->num_elements() - 1);
+
+  if (2 <=3D dbgOut.get_verbosity()) {
+    assert(scd_box->boundary_complete());
+    EntityHandle dum_ent =3D scd_box->start_element();
+    rval =3D mbImpl->list_entities(&dum_ent, 1);
+    ERRORR(rval, "Trouble listing first hex.");
+
+    std::vector<EntityHandle> connect;
+    rval =3D mbImpl->get_connectivity(&dum_ent, 1, connect);
+    ERRORR(rval, "Trouble getting connectivity.");
+
+    rval =3D mbImpl->list_entities(&connect[0], connect.size());
+    ERRORR(rval, "Trouble listing element connectivity.");
+  }
+
+  Range edges;
+  mbImpl->get_adjacencies(faces, 1, true, edges, Interface::UNION);
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_variables(EntityHandle file_set, std::vector<s=
td::string>& var_names, std::vector<int>& tstep_nums)
+{
+  std::vector<ReadNC::VarData> vdatas;
+  std::vector<ReadNC::VarData> vsetdatas;
+
+  ErrorCode rval =3D read_scd_variable_setup(var_names, tstep_nums, vdatas=
, vsetdatas);
+  ERRORR(rval, "Trouble setting up read variable.");
+
+  // create COORDS tag for quads
+  rval =3D _readNC->create_quad_coordinate_tag(file_set);
+  ERRORR(rval, "Trouble creating coordinate tags to entities quads");
+
+  if (!vsetdatas.empty()) {
+    rval =3D read_variable_to_set(file_set, vsetdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to set.");
+  }
+
+  if (!vdatas.empty()) {
+    rval =3D read_scd_variable_to_nonset(file_set, vdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to entities verts/edges/faces.");
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_setup(std::vector<std::string>& v=
ar_names, std::vector<int>& tstep_nums,
+                                               std::vector<ReadNC::VarData=
>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
+{
+  std::map<std::string, ReadNC::VarData>& varInfo =3D _readNC->varInfo;
+  int& tMin =3D _readNC->tMin;
+  int& tMax =3D _readNC->tMax;
+  int& iDim =3D _readNC->iDim;
+  int& jDim =3D _readNC->jDim;
+  int& tDim =3D _readNC->tDim;
+  int& iCDim =3D _readNC->iCDim;
+  int& jCDim =3D _readNC->jCDim;
+
+  std::map<std::string, ReadNC::VarData>::iterator mit;
+
+  // If empty read them all
+  if (var_names.empty()) {
+    for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
+      ReadNC::VarData vd =3D (*mit).second;
+      if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.=
varDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=3D=
 vd.varDims.end()) && (std::find(vd.varDims.begin(),
+         vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jCDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), iDim) !=3D vd.varDims.end()))
+        vdatas.push_back(vd);
+      else
+        vsetdatas.push_back(vd);
+    }
+  }
+  else {
+    for (unsigned int i =3D 0; i < var_names.size(); i++) {
+      mit =3D varInfo.find(var_names[i]);
+      if (mit !=3D varInfo.end()) {
+        ReadNC::VarData vd =3D (*mit).second;
+        if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D v=
d.varDims.end()) && (std::find(vd.varDims.begin(),
+           vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jCDim) !=
=3D vd.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), iDim) !=3D vd.varDims.end()))
+          vdatas.push_back(vd);
+        else
+          vsetdatas.push_back(vd);
+      }
+      else ERRORR(MB_FAILURE, "Couldn't find variable.");
+    }
+  }
+
+  if (tstep_nums.empty() && -1 !=3D tMin) {
+    // no timesteps input, get them all
+    for (int i =3D tMin; i <=3D tMax; i++)
+      tstep_nums.push_back(i);
+  }
+  if (!tstep_nums.empty()) {
+    for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+      vdatas[i].varTags.resize(tstep_nums.size(), 0);
+      vdatas[i].varDatas.resize(tstep_nums.size());
+      vdatas[i].readDims.resize(tstep_nums.size());
+      vdatas[i].readCounts.resize(tstep_nums.size());
+    }
+    for (unsigned int i =3D 0; i < vsetdatas.size(); i++) {
+      if ((std::find(vsetdatas[i].varDims.begin(), vsetdatas[i].varDims.en=
d(), tDim) !=3D vsetdatas[i].varDims.end())
+          && (vsetdatas[i].varDims.size() !=3D 1)) {
+        vsetdatas[i].varTags.resize(tstep_nums.size(), 0);
+        vsetdatas[i].varDatas.resize(tstep_nums.size());
+        vsetdatas[i].readDims.resize(tstep_nums.size());
+        vsetdatas[i].readCounts.resize(tstep_nums.size());
+      }
+      else {
+        vsetdatas[i].varTags.resize(1, 0);
+        vsetdatas[i].varDatas.resize(1);
+        vsetdatas[i].readDims.resize(1);
+        vsetdatas[i].readCounts.resize(1);
+      }
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_nonset_allocate(EntityHandle f=
ile_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  std::vector<std::string>& dimNames =3D _readNC->dimNames;
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+  int (&lDims)[6] =3D _readNC->lDims;
+  int (&lCDims)[6] =3D _readNC->lCDims;
+  int& tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  bool& isParallel =3D _readNC->isParallel;
+ #ifdef USE_MPI
+  ParallelComm*& myPcomm =3D _readNC->myPcomm;
+#endif
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  Range* range =3D NULL;
+
+  // get vertices in set
+  Range verts;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 0, verts);
+  ERRORR(rval, "Trouble getting vertices in set.");
+  assert("Should only have a single vertex subrange, since they were read =
in one shot" &&
+      verts.psize() =3D=3D 1);
+
+  Range edges;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 1, edges);
+  ERRORR(rval, "Trouble getting edges in set.");
+
+  // Get faces in set
+  Range faces;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 2, faces);
+  ERRORR(rval, "Trouble getting faces in set.");
+  assert("Should only have a single face subrange, since they were read in=
 one shot" &&
+      faces.psize() =3D=3D 1);
+
+#ifdef USE_MPI
+  moab::Range faces_owned;
+  if (isParallel)
+  {
+    rval =3D myPcomm->filter_pstatus(faces, PSTATUS_NOT_OWNED, PSTATUS_NOT=
, -1, &faces_owned);
+    ERRORR(rval, "Trouble getting owned faces in set.");
+  }
+  else
+    faces_owned =3D faces; // not running in parallel, but still with MPI
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      std::vector<std::string>::iterator vit;
+      int idx_lev =3D -1;
+      int idx_ilev =3D -1;
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
+        idx_lev =3D vit - dimNames.begin();
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
+        idx_ilev =3D vit - dimNames.begin();
+      if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), id=
x_lev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_lev];
+      else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_ilev];
+
+      // Get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_nonset(vdatas[i], tstep_nums[t], vdat=
as[i].varTags[t], vdatas[i].numLev);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // Assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+      }
+      else if (vdatas[i].varDims[0] !=3D tDim) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
+      }
+
+      // Set up the dimensions and counts
+      // First time
+      vdatas[i].readDims[t].push_back(tstep_nums[t]);
+      vdatas[i].readCounts[t].push_back(1);
+
+      // then z/y/x
+      if (vdatas[i].numLev !=3D 1) {
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(vdatas[i].numLev);
+      }
+
+      switch (vdatas[i].entLoc) {
+        case ReadNC::ENTLOCVERT:
+          // vertices
+          // only structured mesh has j parameter that multiplies i to get=
 total # vertices
+          vdatas[i].readDims[t].push_back(lDims[1]);
+          vdatas[i].readCounts[t].push_back(lDims[4] - lDims[1] + 1);
+          vdatas[i].readDims[t].push_back(lDims[0]);
+          vdatas[i].readCounts[t].push_back(lDims[3] - lDims[0] + 1);
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+          range =3D &verts;
+          break;
+        case ReadNC::ENTLOCNSEDGE:
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
+          break;
+        case ReadNC::ENTLOCEWEDGE:
+          ERRORR(MB_FAILURE, "Reading edge data not implemented yet.");
+          break;
+        case ReadNC::ENTLOCFACE:
+          // faces
+          vdatas[i].readDims[t].push_back(lCDims[1]);
+          vdatas[i].readDims[t].push_back(lCDims[0]);
+          vdatas[i].readCounts[t].push_back(lCDims[4] - lCDims[1] + 1);
+          vdatas[i].readCounts[t].push_back(lCDims[3] - lCDims[0] + 1);
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+#ifdef USE_MPI
+          range =3D &faces_owned;
+#else
+          range =3D &faces;
+#endif
+          break;
+        case ReadNC::ENTLOCSET:
+          // set
+          break;
+        default:
+          ERRORR(MB_FAILURE, "Unrecognized entity location type.");
+          break;
+      }
+
+      // Get ptr to tag space
+      void* data;
+      int count;
+      rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
+      ERRORR(rval, "Failed to get tag iterator.");
+      assert((unsigned)count =3D=3D range->size());
+      vdatas[i].varDatas[t] =3D data;
+    }
+  }
+
+  return rval;
+}
+
+ErrorCode ScdNCHelper::read_scd_variable_to_nonset(EntityHandle file_set, =
std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+
+  ErrorCode rval =3D read_scd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // Finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D 1;
+      for (std::size_t idx =3D 0; idx !=3D vdatas[i].readCounts[t].size();=
 idx++)
+        sz *=3D vdatas[i].readCounts[t][idx];
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D vdatas[i].readCounts[t][3];
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          std::vector<char> tmpchardata(sz);
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpchardata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpchardata=
[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpchardata.size(); idx++)
+              ((char*) data)[idx] =3D tmpchardata[idx];
+          }
+          ERRORS(success, "Failed to read char data.");
+          break;
+        }
+        case NC_DOUBLE: {
+          std::vector<double> tmpdoubledata(sz);
+          success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vd=
atas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpdoubledata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpdoubleda=
ta[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+          success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpfloatdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          std::vector<int> tmpintdata(sz);
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpintdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
+              ((int*) data)[idx] =3D tmpintdata[idx];
+          }
+          ERRORS(success, "Failed to read int data.");
+          break;
+        }
+        case NC_SHORT: {
+          std::vector<short> tmpshortdata(sz);
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpshortdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
+              ((short*) data)[idx] =3D tmpshortdata[idx];
+          }
+          ERRORS(success, "Failed to read short data.");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+
+ErrorCode UcdNCHelper::read_variables(EntityHandle file_set, std::vector<s=
td::string>& var_names, std::vector<int>& tstep_nums)
+{
+  std::vector<ReadNC::VarData> vdatas;
+  std::vector<ReadNC::VarData> vsetdatas;
+
+  ErrorCode rval =3D read_ucd_variable_setup(var_names, tstep_nums, vdatas=
, vsetdatas);
+  ERRORR(rval, "Trouble setting up read variable.");
+
+  if (!vsetdatas.empty()) {
+    rval =3D read_variable_to_set(file_set, vsetdatas, tstep_nums);
+    ERRORR(rval, "Trouble read variables to set.");
+  }
+
+  if (!vdatas.empty()) {
+#ifdef PNETCDF_FILE
+    // in serial, we will use the old read, everything is contiguous
+    // in parallel, we will use async read in pnetcdf
+    // the other mechanism is not working, forget about it
+    rval =3D read_ucd_variable_to_nonset_async(file_set, vdatas, tstep_num=
s);
+#else
+    rval =3D read_ucd_variable_to_nonset(file_set, vdatas, tstep_nums);
+#endif
+    ERRORR(rval, "Trouble read variables to entities verts/edges/faces.");
+  }
+
+  return MB_SUCCESS;
 }
=20
 } // namespace moab

diff --git a/src/io/NCHelper.hpp b/src/io/NCHelper.hpp
index 852fc61..0ac9b0c 100644
--- a/src/io/NCHelper.hpp
+++ b/src/io/NCHelper.hpp
@@ -18,19 +18,112 @@ class NCHelper
 {
 public:
   NCHelper(ReadNC* readNC, int fileId) : _readNC(readNC), _fileId(fileId) =
{}
+  virtual ~NCHelper() {}
=20
+  //! Get appropriate helper instance for ReadNC class
   static NCHelper* get_nc_helper(ReadNC* readNC, int fileId, const FileOpt=
ions& opts);
=20
+  //! Interfaces to be implemented in child classes
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set) =3D 0;
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads) =3D 0;
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set) =3D 0;
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces) =3D 0;
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums) =3D 0;
   virtual std::string get_mesh_type_name() =3D 0;
-  virtual bool is_scd_mesh() =3D 0;
+
+protected:
+  //! Read set variables, common to scd mesh and ucd mesh
+  ErrorCode read_variable_to_set(EntityHandle file_set, std::vector<ReadNC=
::VarData>& vdatas, std::vector<int>& tstep_nums);
+
+  //! Convert variables in place
+  ErrorCode convert_variable(ReadNC::VarData& var_data, int tstep_num);
+
+private:
+  //! Used by read_variable_to_set()
+  ErrorCode read_variable_to_set_allocate(std::vector<ReadNC::VarData>& vd=
atas, std::vector<int>& tstep_nums);
=20
 protected:
   ReadNC* _readNC;
   int _fileId;
 };
=20
+//! Child helper class for scd mesh, e.g. CAM_EL or CAM_FV
+class ScdNCHelper : public NCHelper
+{
+public:
+  ScdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  virtual ~ScdNCHelper() {}
+
+private:
+  //! Implementation of NCHelper::check_existing_mesh()
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set);
+  //! Implementation of NCHelper::create_mesh()
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  //! Implementation of NCHelper::read_variables()
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names, std::vector<int>& tstep_nums);
+
+  //! Separate set and non-set variables for scd mesh
+  ErrorCode read_scd_variable_setup(std::vector<std::string>& var_names,
+                                    std::vector<int>& tstep_nums,
+                                    std::vector<ReadNC::VarData>& vdatas,
+                                    std::vector<ReadNC::VarData>& vsetdata=
s);
+
+  //! Read non-set variables for scd mesh
+  ErrorCode read_scd_variable_to_nonset_allocate(EntityHandle file_set, st=
d::vector<ReadNC::VarData>& vdatas,
+                                                 std::vector<int>& tstep_n=
ums);
+  ErrorCode read_scd_variable_to_nonset(EntityHandle file_set, std::vector=
<ReadNC::VarData>& vdatas,
+                                        std::vector<int>& tstep_nums);
+};
+
+//! Child helper class for ucd mesh, e.g. CAM_SE (HOMME) or MPAS
+class UcdNCHelper : public NCHelper
+{
+public:
+  UcdNCHelper(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId),
+  cDim(-1), eDim(-1), vDim(-1), levDim(-1),
+  nCells(0), nEdges(0), nVertices(0),
+  nLocalCells(0), nLocalEdges(0), nLocalVertices(0) {}
+  virtual ~UcdNCHelper() {}
+
+private:
+  //! Implementation of NCHelper::read_variables()
+  virtual ErrorCode read_variables(EntityHandle file_set, std::vector<std:=
:string>& var_names,
+                                   std::vector<int> &tstep_nums);
+
+  //! Separate set and non-set variables for ucd mesh (implemented differe=
ntly in child classes)
+  virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
+                                            std::vector<int>& tstep_nums,
+                                            std::vector<ReadNC::VarData>& =
vdatas,
+                                            std::vector<ReadNC::VarData>& =
vsetdatas) =3D 0;
+
+  //! Read non-set variables for ucd mesh (implemented differently in chil=
d classes)
+  virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
+                                                         std::vector<int>&=
 tstep_nums) =3D 0;
+#ifdef PNETCDF_FILE
+  virtual ErrorCode read_ucd_variable_to_nonset_async(EntityHandle file_se=
t, std::vector<ReadNC::VarData>& vdatas,
+                                                      std::vector<int>& ts=
tep_nums) =3D 0;
+#else
+  virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
+                                                std::vector<int>& tstep_nu=
ms) =3D 0;
+#endif
+
+protected:
+  //! Dimension numbers for nCells, nEdges, nVertices, nLevels
+  int cDim, eDim, vDim, levDim;
+
+  //! Coordinate values for vertices
+  std::vector<double> xVertVals, yVertVals, zVertVals;
+
+  int nCells;
+  int nEdges;
+  int nVertices;
+
+  int nLocalCells;
+  int nLocalEdges;
+  int nLocalVertices;
+
+  Range localGidCells, localGidEdges, localGidVerts;
+};
+
 } // namespace moab
=20
 #endif

diff --git a/src/io/NCHelperEuler.cpp b/src/io/NCHelperEuler.cpp
index 85b6887..146227c 100644
--- a/src/io/NCHelperEuler.cpp
+++ b/src/io/NCHelperEuler.cpp
@@ -343,7 +343,7 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.va=
rDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCQUAD;
+      vd.entLoc =3D ReadNC::ENTLOCFACE;
   }
=20
   // <coordinate_dim_name>
@@ -473,9 +473,4 @@ ErrorCode NCHelperEuler::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperEuler::create_verts_quads(ScdInterface* scdi, const File=
Options& opts, EntityHandle file_set, Range& quads)
-{
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
-}
-
 } // namespace moab

diff --git a/src/io/NCHelperEuler.hpp b/src/io/NCHelperEuler.hpp
index b1c4c21..a0d6aef 100644
--- a/src/io/NCHelperEuler.hpp
+++ b/src/io/NCHelperEuler.hpp
@@ -14,21 +14,16 @@
 namespace moab {
=20
 //! Child helper class for Eulerian Spectral grid (CAM_EUL)
-class NCHelperEuler : public NCHelper
+class NCHelperEuler : public ScdNCHelper
 {
 public:
-  NCHelperEuler(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  NCHelperEuler(ReadNC* readNC, int fileId) : ScdNCHelper(readNC, fileId) =
{}
=20
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
-
   virtual std::string get_mesh_type_name() { return "CAM_EUL"; }
-
-  virtual bool is_scd_mesh() { return true; }
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperFV.cpp b/src/io/NCHelperFV.cpp
index 93b1a99..9141938 100644
--- a/src/io/NCHelperFV.cpp
+++ b/src/io/NCHelperFV.cpp
@@ -333,7 +333,7 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iCDim) !=3D vd.va=
rDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), jCDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCQUAD;
+      vd.entLoc =3D ReadNC::ENTLOCFACE;
     else if ((std::find(vd.varDims.begin(), vd.varDims.end(), jDim) !=3D v=
d.varDims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), iCDim) !=3D vd.varDims.end()))
       vd.entLoc =3D ReadNC::ENTLOCNSEDGE;
@@ -469,9 +469,4 @@ ErrorCode NCHelperFV::init_mesh_vals(const FileOptions&=
 opts, EntityHandle file_
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperFV::create_verts_quads(ScdInterface* scdi, const FileOpt=
ions& opts, EntityHandle file_set, Range& quads)
-{
-  return _readNC->create_scd_verts_quads(scdi, file_set, quads);
-}
-
 } // namespace moab

diff --git a/src/io/NCHelperFV.hpp b/src/io/NCHelperFV.hpp
index afcd9b8..7dde6dc 100644
--- a/src/io/NCHelperFV.hpp
+++ b/src/io/NCHelperFV.hpp
@@ -14,17 +14,15 @@
 namespace moab {
=20
 //! Child helper class for Finite Volume grid (CAM_FV)
-class NCHelperFV : public NCHelper
+class NCHelperFV : public ScdNCHelper
 {
 public:
-  NCHelperFV(ReadNC* readNC, int fileId) : NCHelper(readNC, fileId) {}
+  NCHelperFV(ReadNC* readNC, int fileId) : ScdNCHelper(readNC, fileId) {}
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
   virtual std::string get_mesh_type_name() { return "CAM_FV"; }
-  virtual bool is_scd_mesh() { return true; }
 };
=20
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.cpp b/src/io/NCHelperHOMME.cpp
index 32faa58..e963564 100644
--- a/src/io/NCHelperHOMME.cpp
+++ b/src/io/NCHelperHOMME.cpp
@@ -6,14 +6,14 @@
 #include <cmath>
=20
 #define ERRORR(rval, str) \
-    if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", =
str); return rval;}
+  if (MB_SUCCESS !=3D rval) {_readNC->readMeshIface->report_error("%s", st=
r); return rval;}
=20
 #define ERRORS(err, str) \
-    if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_F=
AILURE;}
+  if (err) {_readNC->readMeshIface->report_error("%s", str); return MB_FAI=
LURE;}
=20
 namespace moab {
=20
-NCHelperHOMME::NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions=
& opts) : NCHelper(readNC, fileId), _spectralOrder(-1)
+NCHelperHOMME::NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions=
& opts) : UcdNCHelper(readNC, fileId), _spectralOrder(-1)
 {
   // Calculate spectral order
   std::map<std::string, ReadNC::AttData>::iterator attIt =3D readNC->globa=
lAtts.find("np");
@@ -91,7 +91,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptions=
& opts, EntityHandle fi
   tMin =3D 0;
   tName =3D dimNames[idx];
=20
-  // get number of vertices (labeled as number of columns) and levels
+  // Get number of vertices (labeled as number of columns) and levels
   gDims[0] =3D gDims[3] =3D -1;
   if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ncol")) !=3D d=
imNames.end()) {
     idx =3D vit - dimNames.begin();
@@ -143,9 +143,9 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
       rval =3D _readNC->read_coordinate("lev", gDims[2], gDims[5], klVals);
       ERRORR(rval, "Trouble reading z variable.");
=20
-      // decide whether down is positive
+      // Decide whether down is positive
       char posval[10];
-      int success =3D NCFUNC(get_att_text)(_readNC->fileId, (*vmit).second=
.varId, "positive", posval);
+      int success =3D NCFUNC(get_att_text)(_fileId, (*vmit).second.varId, =
"positive", posval);
       if (0 =3D=3D success && !strcmp(posval, "down")) {
         for (std::vector<double>::iterator dvit =3D klVals.begin(); dvit !=
=3D klVals.end(); ++dvit)
           (*dvit) *=3D -1.0;
@@ -180,7 +180,7 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOptio=
ns& opts, EntityHandle fi
     ReadNC::VarData& vd =3D (*mit).second;
     if ((std::find(vd.varDims.begin(), vd.varDims.end(), iDim) !=3D vd.var=
Dims.end()) && (std::find(vd.varDims.begin(),
         vd.varDims.end(), kDim) !=3D vd.varDims.end()))
-      vd.entLoc =3D ReadNC::ENTLOCNODE;
+      vd.entLoc =3D ReadNC::ENTLOCVERT;
   }
=20
   std::copy(gDims, gDims + 6, lDims);
@@ -191,15 +191,51 @@ ErrorCode NCHelperHOMME::init_mesh_vals(const FileOpt=
ions& opts, EntityHandle fi
   // with no corresponding variables
   _readNC->init_dims_with_no_cvars_info();
=20
-  // This check is for HOMME and other ucd mesh. When ReadNC class instance
-  // gets out of scope in a script (and deleted), the localGid will be lost
-  rval =3D _readNC->check_ucd_localGid(file_set);
-  ERRORR(rval, "Trouble checking local Gid for ucd mesh.");
+  return MB_SUCCESS;
+}
+
+// When noMesh option is used on this read, the old ReadNC class instance =
for last read can get out
+// of scope (and deleted). The old instance initialized localGidVerts prop=
erly when the mesh was
+// created, but it is now lost. The new instance (will not create the mesh=
 with noMesh option) has
+// to restore it based on the existing mesh from last read
+ErrorCode NCHelperHOMME::check_existing_mesh(EntityHandle tmp_set)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  Tag& mGlobalIdTag =3D _readNC->mGlobalIdTag;
+  bool& noMesh =3D _readNC->noMesh;
+  Range& localGid =3D _readNC->localGid;
+
+  if (noMesh && localGid.empty()) {
+    // We need to populate localGid range with the gids of vertices from t=
he tmp_set
+    // localGid is important in reading the variable data into the nodes
+    // also, for our purposes, localGid is truly the GLOBAL_ID tag data, n=
ot other
+    // file_id tags that could get passed around in other scenarios for pa=
rallel reading
+    // for nodal_partition, this local gid is easier, should be initialize=
d with only
+    // the owned nodes
+
+    // We need to get all vertices from tmp_set (it is the input set in no=
_mesh scenario)
+    Range local_verts;
+    ErrorCode rval =3D mbImpl->get_entities_by_dimension(tmp_set, 0, local=
_verts);
+    if (MB_FAILURE =3D=3D rval)
+      return rval;
+
+    if (!local_verts.empty()) {
+      std::vector<int> gids(local_verts.size());
+
+      // !IMPORTANT : this has to be the GLOBAL_ID tag
+      rval =3D mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
+      if (MB_FAILURE =3D=3D rval)
+        return rval;
+
+      // This will do a smart copy
+      std::copy(gids.begin(), gids.end(), range_inserter(localGid));
+    }
+  }
=20
   return MB_SUCCESS;
 }
=20
-ErrorCode NCHelperHOMME::create_verts_quads(ScdInterface* scdi, const File=
Options& opts, EntityHandle file_set, Range& quads)
+ErrorCode NCHelperHOMME::create_mesh(ScdInterface* scdi, const FileOptions=
& opts, EntityHandle file_set, Range& faces)
 {
   Interface*& mbImpl =3D _readNC->mbImpl;
   std::string& fileName =3D _readNC->fileName;
@@ -282,9 +318,9 @@ ErrorCode NCHelperHOMME::create_verts_quads(ScdInterfac=
e* scdi, const FileOption
   int cornerVarId;
   success =3D NCFUNC(inq_varid)(connectId, "element_corners", &cornerVarId=
);
   ERRORS(success, "Failed to get variable id.");
-  NCDF_SIZE tmp_dims[2] =3D {0, 0}, tmp_counts[2] =3D {4, static_cast<size=
_t>(num_quads)};
+  NCDF_SIZE tmp_starts[2] =3D {0, 0}, tmp_counts[2] =3D {4, static_cast<si=
ze_t>(num_quads)};
   std::vector<int> tmp_conn(4 * num_quads), tmp_conn2(4 * num_quads);
-  success =3D NCFUNCAG(_vara_int)(connectId, cornerVarId, tmp_dims, tmp_co=
unts, &tmp_conn2[0] NCREQ);
+  success =3D NCFUNCAG(_vara_int)(connectId, cornerVarId, tmp_starts, tmp_=
counts, &tmp_conn2[0] NCREQ);
   ERRORS(success, "Failed to get temporary connectivity.");
   success =3D NCFUNC(close)(connectId);
   ERRORS(success, "Failed on close.");
@@ -349,7 +385,7 @@ ErrorCode NCHelperHOMME::create_verts_quads(ScdInterfac=
e* scdi, const FileOption
     ERRORR(rval, "Failed to get fine connectivity of spectral elements.");
   }
=20
-  // on this proc, I get columns ldims[1]..ldims[4], inclusive; need to fi=
nd which vertices those correpond to
+  // on this proc, I get columns lDims[1]..lDims[4], inclusive; need to fi=
nd which vertices those correspond to
   unsigned int num_local_verts =3D localGid.size();
   unsigned int num_total_verts =3D gDims[3] - gDims[0] + 1;
=20
@@ -366,27 +402,31 @@ ErrorCode NCHelperHOMME::create_verts_quads(ScdInterf=
ace* scdi, const FileOption
   int i;
   for (i =3D 0, rit =3D localGid.begin(); i < (int)num_local_verts; i++, +=
+rit) {
     assert(*rit < ilVals.size() + 1);
-    xptr[i] =3D ilVals[(*rit) - 1];
-    yptr[i] =3D jlVals[(*rit) - 1];
-    zptr[i] =3D klVals[lDims[2]];
+    xptr[i] =3D ilVals[(*rit) - 1]; // lon
+    yptr[i] =3D jlVals[(*rit) - 1]; // lat
+    zptr[i] =3D klVals[lDims[2]]; // dummy
   }
=20
   const double pideg =3D acos(-1.0) / 180.0;
   for (i =3D 0; i < (int)num_local_verts; i++) {
     double cosphi =3D cos(pideg * yptr[i]);
-    double zmult =3D sin(pideg * yptr[i]), xmult =3D cosphi * cos(xptr[i] =
* pideg), ymult =3D cosphi * sin(xptr[i] * pideg);
+    double zmult =3D sin(pideg * yptr[i]);
+    double xmult =3D cosphi * cos(xptr[i] * pideg);
+    double ymult =3D cosphi * sin(xptr[i] * pideg);
     double rad =3D 8.0e3 + klVals[lDims[2]];
-    xptr[i] =3D rad * xmult, yptr[i] =3D rad * ymult, zptr[i] =3D rad * zm=
ult;
+    xptr[i] =3D rad * xmult;
+    yptr[i] =3D rad * ymult;
+    zptr[i] =3D rad * zmult;
   }
=20
   // get ptr to gid memory for vertices
   Range vert_range(start_vertex, start_vertex + num_local_verts - 1);
-  void *data;
+  void* data;
   int count;
   rval =3D mbImpl->tag_iterate(mGlobalIdTag, vert_range.begin(), vert_rang=
e.end(), count, data);
   ERRORR(rval, "Failed to get tag iterator.");
   assert(count =3D=3D (int) num_local_verts);
-  int *gid_data =3D (int*) data;
+  int* gid_data =3D (int*) data;
   std::copy(localGid.begin(), localGid.end(), gid_data);
   // duplicate global id data, which will be used to resolve sharing
   if (mpFileIdTag) {
@@ -417,7 +457,7 @@ ErrorCode NCHelperHOMME::create_verts_quads(ScdInterfac=
e* scdi, const FileOption
   }
=20
   // add new vertices and elements to the set
-  quads.merge(tmp_range);
+  faces.merge(tmp_range);
   tmp_range.insert(start_vertex, start_vertex + num_local_verts - 1);
   rval =3D mbImpl->add_entities(file_set, tmp_range);
   ERRORR(rval, "Couldn't add new vertices and quads/hexes to file set.");
@@ -503,4 +543,517 @@ ErrorCode NCHelperHOMME::create_verts_quads(ScdInterf=
ace* scdi, const FileOption
   return MB_SUCCESS;
 }
=20
+ErrorCode NCHelperHOMME::read_ucd_variable_setup(std::vector<std::string>&=
 var_names, std::vector<int>& tstep_nums,
+                                                 std::vector<ReadNC::VarDa=
ta>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
+{
+  std::map<std::string, ReadNC::VarData>& varInfo =3D _readNC->varInfo;
+  int& tMin =3D _readNC->tMin;
+  int& tMax =3D _readNC->tMax;
+  int& iDim =3D _readNC->iDim;
+  int& kDim =3D _readNC->kDim;
+  int& tDim =3D _readNC->tDim;
+
+  std::map<std::string, ReadNC::VarData>::iterator mit;
+
+  // If empty read them all
+  if (var_names.empty()) {
+    for (mit =3D varInfo.begin(); mit !=3D varInfo.end(); ++mit) {
+      ReadNC::VarData vd =3D (*mit).second;
+      if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd.v=
arDims.end()) && (std::find(vd.varDims.begin(),
+          vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(vd.=
varDims.begin(), vd.varDims.end(), iDim)
+          !=3D vd.varDims.end()))
+        vdatas.push_back(vd); // 3d data (time, lev, ncol) read here
+      else
+        vsetdatas.push_back(vd);
+    }
+  }
+  else {
+    for (unsigned int i =3D 0; i < var_names.size(); i++) {
+
+      mit =3D varInfo.find(var_names[i]);
+      if (mit !=3D varInfo.end()) {
+        ReadNC::VarData vd =3D (*mit).second;
+        if ((std::find(vd.varDims.begin(), vd.varDims.end(), tDim) !=3D vd=
.varDims.end()) && (std::find(vd.varDims.begin(),
+            vd.varDims.end(), kDim) !=3D vd.varDims.end()) && (std::find(v=
d.varDims.begin(), vd.varDims.end(), iDim)
+            !=3D vd.varDims.end()))
+          vdatas.push_back(vd); // 3d data (time, lev, ncol) read here
+        else
+          vsetdatas.push_back(vd);
+      }
+      else {
+        ERRORR(MB_FAILURE, "Couldn't find variable.");
+      }
+    }
+  }
+
+  if (tstep_nums.empty() && -1 !=3D tMin) {
+    // no timesteps input, get them all
+    for (int i =3D tMin; i <=3D tMax; i++)
+      tstep_nums.push_back(i);
+  }
+  if (!tstep_nums.empty()) {
+    for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+      vdatas[i].varTags.resize(tstep_nums.size(), 0);
+      vdatas[i].varDatas.resize(tstep_nums.size());
+      vdatas[i].readDims.resize(tstep_nums.size());
+      vdatas[i].readCounts.resize(tstep_nums.size());
+    }
+    for (unsigned int i =3D 0; i < vsetdatas.size(); i++) {
+      if ((std::find(vsetdatas[i].varDims.begin(), vsetdatas[i].varDims.en=
d(), tDim) !=3D vsetdatas[i].varDims.end())
+          && (vsetdatas[i].varDims.size() !=3D 1)) {
+        vsetdatas[i].varTags.resize(tstep_nums.size(), 0);
+        vsetdatas[i].varDatas.resize(tstep_nums.size());
+        vsetdatas[i].readDims.resize(tstep_nums.size());
+        vsetdatas[i].readCounts.resize(tstep_nums.size());
+      }
+      else {
+        vsetdatas[i].varTags.resize(1, 0);
+        vsetdatas[i].varDatas.resize(1);
+        vsetdatas[i].readDims.resize(1);
+        vsetdatas[i].readCounts.resize(1);
+      }
+    }
+  }
+
+  return MB_SUCCESS;
+}
+
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_allocate(EntityHandle=
 file_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nu=
ms)
+{
+  Interface*& mbImpl =3D _readNC->mbImpl;
+  std::vector<std::string>& dimNames =3D _readNC->dimNames;
+  std::vector<int>& dimVals =3D _readNC->dimVals;
+   int& tDim =3D _readNC->tDim;
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  ErrorCode rval =3D MB_SUCCESS;
+
+  Range* range =3D NULL;
+
+  // Get vertices in set
+  Range verts;
+  rval =3D mbImpl->get_entities_by_dimension(file_set, 0, verts);
+  ERRORR(rval, "Trouble getting vertices in set.");
+  assert("Should only have a single vertex subrange, since they were read =
in one shot" &&
+      verts.psize() =3D=3D 1);
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].v=
arName.c_str(), tstep_nums[t]);
+
+      std::vector<std::string>::iterator vit;
+      int idx_lev =3D -1;
+      int idx_ilev =3D -1;
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "lev")) !=
=3D dimNames.end())
+        idx_lev =3D vit - dimNames.begin();
+      if ((vit =3D std::find(dimNames.begin(), dimNames.end(), "ilev")) !=
=3D dimNames.end())
+        idx_ilev =3D vit - dimNames.begin();
+      if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), id=
x_lev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_lev];
+      else if (std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(=
), idx_ilev) !=3D vdatas[i].varDims.end())
+        vdatas[i].numLev =3D dimVals[idx_ilev];
+
+      // Get the tag to read into
+      if (!vdatas[i].varTags[t]) {
+        rval =3D _readNC->get_tag_to_nonset(vdatas[i], tstep_nums[t], vdat=
as[i].varTags[t], vdatas[i].numLev);
+        ERRORR(rval, "Trouble getting tag.");
+      }
+
+      // Assume point-based values for now?
+      if (-1 =3D=3D tDim || dimVals[tDim] <=3D (int) t) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number.");
+      }
+      else if (vdatas[i].varDims[0] !=3D tDim) {
+        ERRORR(MB_INDEX_OUT_OF_RANGE, "Non-default timestep number given f=
or time-independent variable.");
+      }
+
+      // Set up the dimensions and counts
+      // First: time
+      vdatas[i].readDims[t].push_back(tstep_nums[t]);
+      vdatas[i].readCounts[t].push_back(1);
+
+      // Next: numLev
+      if (vdatas[i].numLev !=3D 1) {
+        vdatas[i].readDims[t].push_back(0);
+        vdatas[i].readCounts[t].push_back(vdatas[i].numLev);
+      }
+
+      // Finally: nVertices
+      switch (vdatas[i].entLoc) {
+        case ReadNC::ENTLOCVERT:
+          // vertices
+          // we will start from the first localGid, actually; we will rese=
t that
+          // later on, anyway, in a loop
+          vdatas[i].readDims[t].push_back(localGid[0] - 1);
+          vdatas[i].readCounts[t].push_back(localGid.size());
+          assert(vdatas[i].readDims[t].size() =3D=3D vdatas[i].varDims.siz=
e());
+          range =3D &verts;
+          break;
+        case ReadNC::ENTLOCSET:
+          // set
+          break;
+        default:
+          ERRORR(MB_FAILURE, "Unrecognized entity location type.");
+          break;
+      }
+
+      // Get ptr to tag space
+      void* data;
+      int count;
+      rval =3D mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), r=
ange->end(), count, data);
+      ERRORR(rval, "Failed to get tag iterator.");
+      assert((unsigned)count =3D=3D range->size());
+      vdatas[i].varDatas[t] =3D data;
+    }
+  }
+
+  return rval;
+}
+
+#ifdef PNETCDF_FILE
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset_async(EntityHandle fi=
le_set, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // Finally, read into that space
+  int success;
+  // MPI_offset or size_t?
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
+      if (sz <=3D 0)
+        continue; // nothing to read, why worry?
+
+      // we will synchronize all these reads with the other processors,
+      // so the wait will be inside this double loop; is it too much?
+      size_t nb_reads =3D localGid.psize();
+      std::vector<int> requests(nb_reads), statuss(nb_reads);
+      size_t idxReq =3D 0;
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D 1; // For HOMME, nj holds # quads, so here should set =
to 1
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        case NC_DOUBLE: {
+          // copy from float case
+          std::vector<double> tmpdoubledata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInDoubleArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
+
+            // do a partial read, in each subrange
+            // wait outside this loop
+            success =3D NCFUNCAG2(_vara_double)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpdoubledata[indexInDoubleArray]) NCREQ2);
+            ERRORS(success, "Failed to read double data in loop");
+            // we need to increment the index in double array for the
+            // next subrange
+            indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          success =3D ncmpi_wait_all(_fileId, requests.size(), &requests[0=
], &statuss[0]);
+          ERRORS(success, "Failed on wait_all.");
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik_stride(ni, nj, nk, data, &tmpd=
oubledata[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+          // assume that the last dimension is for the ncol,
+          // node varying variable
+
+          size_t indexInFloatArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
+
+            // do a partial read, in each subrange
+            // wait outside this loop
+            success =3D NCFUNCAG2(_vara_float)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpfloatdata[indexInFloatArray]) NCREQ2);
+            ERRORS(success, "Failed to read float data in loop");
+            // we need to increment the index in float array for the
+            // next subrange
+            indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].num=
Lev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          success =3D ncmpi_wait_all(_fileId, requests.size(), &requests[0=
], &statuss[0]);
+          ERRORS(success, "Failed on wait_all.");
+
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik_stride(ni, nj, nk, data, &tmpf=
loatdata[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        case NC_SHORT: {
+          ERRORR(MB_FAILURE, "not implemented");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+#else
+ErrorCode NCHelperHOMME::read_ucd_variable_to_nonset(EntityHandle file_set=
, std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
+{
+  DebugOutput& dbgOut =3D _readNC->dbgOut;
+  Range& localGid =3D _readNC->localGid;
+
+  ErrorCode rval =3D read_ucd_variable_to_nonset_allocate(file_set, vdatas=
, tstep_nums);
+  ERRORR(rval, "Trouble allocating read variables.");
+
+  // Finally, read into that space
+  int success;
+  std::vector<int> requests(vdatas.size() * tstep_nums.size()), statuss(vd=
atas.size() * tstep_nums.size());
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      std::size_t sz =3D vdatas[i].numLev * vdatas[i].readCounts[t][2];
+      void* data =3D vdatas[i].varDatas[t];
+      size_t ni =3D vdatas[i].readCounts[t][2];
+      size_t nj =3D 1; // For HOMME, nj holds # quads, so here should set =
to 1
+      size_t nk =3D vdatas[i].readCounts[t][1];
+
+      switch (vdatas[i].varDataType) {
+        case NC_BYTE:
+        case NC_CHAR: {
+          std::vector<char> tmpchardata(sz);
+          success =3D NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdat=
as[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpchardata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpchardata=
[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpchardata.size(); idx++)
+              ((char*) data)[idx] =3D tmpchardata[idx];
+          }
+          ERRORS(success, "Failed to read char data.");
+          break;
+        }
+        case NC_DOUBLE: {
+          // Copy from float case
+          std::vector<double> tmpdoubledata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+
+          // Assume that the last dimension is for the ncol
+          size_t indexInDoubleArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // Inclusive
+            vdatas[i].readDims[t][nbDims - 1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims - 1] =3D (NCDF_SIZE) (endh - st=
arth + 1);
+
+            success =3D NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpdoubledata[indexInDoubleArray]) NCREQ);
+            ERRORS(success, "Failed to read float data in loop");
+            // We need to increment the index in double array for the
+            // next subrange
+            indexInDoubleArray +=3D (endh - starth + 1) * 1 * vdatas[i].nu=
mLev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpdoubleda=
ta[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpdoubledata.size(); idx=
++)
+              ((double*) data)[idx] =3D tmpdoubledata[idx];
+          }
+          ERRORS(success, "Failed to read double data.");
+          break;
+        }
+        case NC_FLOAT: {
+          std::vector<float> tmpfloatdata(sz);
+
+          // in the case of ucd mesh, and on multiple proc,
+          // we need to read as many times as subranges we have in the
+          // localGid range;
+          // basically, we have to give a different point
+          // for data to start, for every subrange :(
+          size_t nbDims =3D vdatas[i].readDims[t].size();
+
+          // Assume that the last dimension is for the ncol
+          size_t indexInFloatArray =3D 0;
+          size_t ic =3D 0;
+          for (Range::pair_iterator pair_iter =3D localGid.pair_begin();
+              pair_iter !=3D localGid.pair_end();
+              pair_iter++, ic++) {
+            EntityHandle starth =3D pair_iter->first;
+            EntityHandle endh =3D pair_iter->second; // Inclusive
+            vdatas[i].readDims[t][nbDims-1] =3D (NCDF_SIZE) (starth - 1);
+            vdatas[i].readCounts[t][nbDims-1] =3D (NCDF_SIZE) (endh - star=
th + 1);
+
+            success =3D NCFUNCAG(_vara_float)(_fileId, vdatas[i].varId,
+                &(vdatas[i].readDims[t][0]), &(vdatas[i].readCounts[t][0]),
+                            &(tmpfloatdata[indexInFloatArray]) NCREQ);
+            ERRORS(success, "Failed to read float data in loop");
+            // We need to increment the index in float array for the
+            // next subrange
+            indexInFloatArray +=3D (endh - starth + 1) * 1 * vdatas[i].num=
Lev;
+          }
+          assert(ic =3D=3D localGid.psize());
+
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpfloatdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpfloatdata.size(); idx+=
+)
+              ((float*) data)[idx] =3D tmpfloatdata[idx];
+          }
+          ERRORS(success, "Failed to read float data.");
+          break;
+        }
+        case NC_INT: {
+          std::vector<int> tmpintdata(sz);
+          success =3D NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdata=
s[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpintdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpintdata[=
0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpintdata.size(); idx++)
+              ((int*) data)[idx] =3D tmpintdata[idx];
+          }
+          ERRORS(success, "Failed to read int data.");
+          break;
+        }
+        case NC_SHORT: {
+          std::vector<short> tmpshortdata(sz);
+          success =3D NCFUNCAG(_vara_short)(_fileId, vdatas[i].varId, &vda=
tas[i].readDims[t][0], &vdatas[i].readCounts[t][0],
+              &tmpshortdata[0] NCREQ);
+          if (vdatas[i].numLev !=3D 1)
+            // Switch from k varying slowest to k varying fastest
+            success =3D _readNC->kji_to_jik(ni, nj, nk, data, &tmpshortdat=
a[0]);
+          else {
+            for (std::size_t idx =3D 0; idx !=3D tmpshortdata.size(); idx+=
+)
+              ((short*) data)[idx] =3D tmpshortdata[idx];
+          }
+          ERRORS(success, "Failed to read short data.");
+          break;
+        }
+        default:
+          success =3D 1;
+      }
+
+      if (success)
+        ERRORR(MB_FAILURE, "Trouble reading variable.");
+    }
+  }
+
+#ifdef NCWAIT
+  int success =3D ncmpi_wait_all(fileId, requests.size(), &requests[0], &s=
tatuss[0]);
+  ERRORS(success, "Failed on wait_all.");
+#endif
+
+  for (unsigned int i =3D 0; i < vdatas.size(); i++) {
+    for (unsigned int t =3D 0; t < tstep_nums.size(); t++) {
+      dbgOut.tprintf(2, "Converting variable %s, time step %d\n", vdatas[i=
].varName.c_str(), tstep_nums[t]);
+      ErrorCode tmp_rval =3D convert_variable(vdatas[i], t);
+      if (MB_SUCCESS !=3D tmp_rval)
+        rval =3D tmp_rval;
+    }
+  }
+  // debug output, if requested
+  if (1 =3D=3D dbgOut.get_verbosity()) {
+    dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str()=
);
+    for (unsigned int i =3D 1; i < vdatas.size(); i++)
+      dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
+    dbgOut.tprintf(1, "\n");
+  }
+
+  return rval;
+}
+#endif
+
 } // namespace moab

diff --git a/src/io/NCHelperHOMME.hpp b/src/io/NCHelperHOMME.hpp
index feb3cad..f900829 100644
--- a/src/io/NCHelperHOMME.hpp
+++ b/src/io/NCHelperHOMME.hpp
@@ -14,20 +14,42 @@
 namespace moab {
=20
 //! Child helper class for HOMME grid (CAM_SE)
-class NCHelperHOMME : public NCHelper
+class NCHelperHOMME : public UcdNCHelper
 {
 public:
   NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions& opts);
   static bool can_read_file(ReadNC* readNC, int fileId);
=20
 private:
+  //! Implementation of NCHelper::init_mesh_vals()
   virtual ErrorCode init_mesh_vals(const FileOptions& opts, EntityHandle f=
ile_set);
-  virtual ErrorCode create_verts_quads(ScdInterface* scdi, const FileOptio=
ns& opts, EntityHandle file_set, Range& quads);
+  //! Implementation of NCHelper::check_existing_mesh()
+  virtual ErrorCode check_existing_mesh(EntityHandle file_set);
+  //! Implementation of NCHelper::create_mesh()
+  virtual ErrorCode create_mesh(ScdInterface* scdi, const FileOptions& opt=
s, EntityHandle file_set, Range& faces);
+  //! Implementation of NCHelper::get_mesh_type_name()
   virtual std::string get_mesh_type_name() { return "CAM_SE"; }
-  virtual bool is_scd_mesh() { return false; }
+
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_allocate()
+  virtual ErrorCode read_ucd_variable_to_nonset_allocate(EntityHandle file=
_set, std::vector<ReadNC::VarData>& vdatas,
+                                                         std::vector<int>&=
 tstep_nums);
+  //! Implementation of UcdNCHelper::read_ucd_variable_setup()
+  virtual ErrorCode read_ucd_variable_setup(std::vector<std::string>& var_=
names,
+                                            std::vector<int>& tstep_nums,
+                                            std::vector<ReadNC::VarData>& =
vdatas,
+                                            std::vector<ReadNC::VarData>& =
vsetdatas);
+#ifdef PNETCDF_FILE
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset_async()
+  virtual ErrorCode read_ucd_variable_to_nonset_async(EntityHandle file_se=
t, std::vector<ReadNC::VarData>& vdatas,
+                                                      std::vector<int>& ts=
tep_nums);
+#else
+  //! Implementation of UcdNCHelper::read_ucd_variable_to_nonset()
+  virtual ErrorCode read_ucd_variable_to_nonset(EntityHandle file_set, std=
::vector<ReadNC::VarData>& vdatas,
+                                                std::vector<int>& tstep_nu=
ms);
+#endif
=20
 private:
-  int _spectralOrder; // read from variable 'np'
+  int _spectralOrder; // Read from variable 'np'
 };
=20
 } // namespace moab

This diff is so big that we needed to truncate the remainder.

Repository URL: https://bitbucket.org/fathomteam/moab/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.


More information about the moab-dev mailing list