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

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon Jun 24 13:35:55 CDT 2013


5 new commits in MOAB:

https://bitbucket.org/fathomteam/moab/commits/19c61b3b0fbb/
Changeset:   19c61b3b0fbb
Branch:      None
User:        iulian07
Date:        2013-06-20 23:48:15
Summary:     start testing mpas intersection in parallel.
so far, there are issues with reading in parallel, because the skinning
does not work for polygons. To prove it, launch with
mbskin -a intx1.vtk out.vtk
(intx1 is the file from intx in plane from mbsclam)

Affected #:  2 files

diff --git a/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index 98d0f7a..b17b5ff 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=0.2; // this is for box error
 std::string input_mesh_file("Homme_2pt.h5m"); // input file, partitioned correctly
+std::string mpas_file("mpas_p8.h5m");
 double CubeSide = 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();
 
 int main(int argc, char **argv)
 {
@@ -73,7 +76,10 @@ int main(int argc, char **argv)
     }
   }
   //result += RUN_TEST(test_intx_in_parallel);
+  radius = CubeSide/2*sqrt(3.);
   result += RUN_TEST(test_intx_in_parallel_elem_based);
+  radius =1.;
+  //result += RUN_TEST(test_intx_mpas);
 
   MPI_Finalize();
   return result;
@@ -92,9 +98,9 @@ ErrorCode  manufacture_lagrange_mesh_on_sphere(Interface * mb, EntityHandle eule
    *   circumscribed sphere radius
    *   radius = length * math.sqrt(3) /2
    */
-  double radius = CubeSide/2*sqrt(3.);// our value depends on cube side
+  //radius = CubeSide/2*sqrt(3.);// our value depends on cube side
   Range quads;
-  rval = mb->get_entities_by_type(euler_set, MBQUAD, quads);
+  rval = mb->get_entities_by_dimension(euler_set, 2, quads);
   CHECK_ERR(rval);
 
   Range connecVerts;
@@ -177,7 +183,7 @@ void test_intx_in_parallel()
  
   Intx2MeshOnSphere worker(&mb);
 
-  double radius= CubeSide/2 * sqrt(3.) ; // input
+  //double radius= CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
   //worker.SetEntityType(MBQUAD);
@@ -244,7 +250,78 @@ void test_intx_in_parallel_elem_based()
 
   Intx2MeshOnSphere worker(&mb);
 
-  double radius= CubeSide/2 * sqrt(3.) ; // input
+  //double radius= 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="<< 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 = mb.create_meshset(MESHSET_SET, covering_lagr_set);
+  CHECK_ERR(rval);
+
+  rval = worker.create_departure_mesh_2nd_alg(euler_set, covering_lagr_set);
+  CHECK_ERR(rval);
+
+  std::stringstream ss;
+  ss<<"partial" << rank<<".vtk";
+  mb.write_file(ss.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  EntityHandle outputSet;
+  rval = mb.create_meshset(MESHSET_SET, outputSet);
+  CHECK_ERR(rval);
+  rval = worker.intersect_meshes(covering_lagr_set, euler_set, outputSet);
+  CHECK_ERR(rval);
+
+  //std::string opts_write("PARALLEL=WRITE_PART");
+  //rval = mb.write_file("manuf.h5m", 0, opts_write.c_str(), &outputSet, 1);
+  std::string opts_write("");
+  std::stringstream outf;
+  outf<<"intersect" << rank<<".h5m";
+  rval = mb.write_file(outf.str().c_str(), 0, 0, &outputSet, 1);
+  double intx_area = area_on_sphere(&mb, outputSet, radius);
+  double arrival_area = 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);
+}
+
+void test_intx_mpas()
+{
+  std::string opts = std::string("PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION")+
+          std::string(";PARALLEL_RESOLVE_SHARED_ENTS");
+  Core moab;
+  Interface & mb = moab;
+  EntityHandle euler_set;
+  ErrorCode rval;
+  rval = mb.create_meshset(MESHSET_SET, euler_set);
+  CHECK_ERR(rval);
+  std::string example(TestDir + "/" +  mpas_file);
+
+  rval = mb.load_file(example.c_str(), &euler_set, opts.c_str());
+
+  ParallelComm* pcomm = ParallelComm::get_pcomm(&mb, 0);
+  CHECK_ERR(rval);
+
+  rval = pcomm->check_all_shared_handles();
+  CHECK_ERR(rval);
+
+  // everybody will get a DP tag, including the non owned entities; so exchange tags is not required for LOC (here)
+  rval = manufacture_lagrange_mesh_on_sphere(&mb, euler_set);
+  CHECK_ERR(rval);
+
+  int rank = 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= CubeSide/2 * sqrt(3.) ; // input
   worker.SetRadius(radius);
   worker.set_box_error(EPS1);//
   //worker.SetEntityType(MBQUAD);

diff --git a/tools/mbcslam/Intx2Mesh.cpp b/tools/mbcslam/Intx2Mesh.cpp
index 4c9c5d5..69a341e 100644
--- a/tools/mbcslam/Intx2Mesh.cpp
+++ b/tools/mbcslam/Intx2Mesh.cpp
@@ -1189,7 +1189,8 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
   TLv.initialize(2, 0, 0, 3, numv); // to proc, GLOBAL ID, DP points
   TLv.enableWriteAccess();
 
-  TLq.initialize(6, 0, 0, 0, numq); // to proc, elem GLOBAL ID, connectivity[4] (global ID v)
+  int sizeTuple = 2+MAXEDGES; // max edges is now 10 :) for polygons
+  TLq.initialize(12, 0, 0, 0, numq); // to proc, elem GLOBAL ID, connectivity[10] (global ID v)
   TLq.enableWriteAccess();
   std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " quads\n";
 
@@ -1213,25 +1214,31 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
       TLv.inc_n();
     }
     // also, prep the quad for sending ...
-    Range Q = range_to_P.subset_by_type(MBQUAD);
+    Range Q = range_to_P.subset_by_dimension(2);
     for (Range::iterator it=Q.begin(); it!=Q.end(); it++)
     {
       EntityHandle q=*it;
       int global_id;
       rval = mb->tag_get_data(gid, &q, 1, &global_id);
-      ERRORR(rval, "can't get gid for quad");
+      ERRORR(rval, "can't get gid for polygon");
       int n=TLq.get_n();
-      TLq.vi_wr[6*n] = to_proc; //
-      TLq.vi_wr[6*n+1] = global_id; // global id of element, used to identify it ...
+      TLq.vi_wr[sizeTuple*n] = to_proc; //
+      TLq.vi_wr[sizeTuple*n+1] = global_id; // global id of element, used to identify it ...
       const EntityHandle * conn4;
       int num_nodes;
-      rval = mb->get_connectivity(q, conn4, num_nodes);
+      rval = mb->get_connectivity(q, conn4, num_nodes);// could be up to 10;
       ERRORR(rval, "can't get connectivity for quad");
+      if (num_nodes > MAXEDGES)
+        ERRORR(MB_FAILURE, "too many nodes in a polygon");
       for (int i=0; i<num_nodes; i++)
       {
         EntityHandle v = conn4[i];
         unsigned int index = local_verts.find(v)-local_verts.begin();
-        TLq.vi_wr[6*n+2+i] = gids[index];
+        TLq.vi_wr[sizeTuple*n+2+i] = gids[index];
+      }
+      for (int k=num_nodes; k<MAXEDGES; k++)
+      {
+        TLq.vi_wr[sizeTuple*n+2+k] = 0; // fill the rest of node ids with 0; we know that the node ids start from 1!
       }
       TLq.inc_n();
 
@@ -1264,7 +1271,7 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
       // now, all dep points should be at their place
       // look in the local list of q for this proc, and create all those quads and vertices if needed
   Range & local=Rto[my_rank];
-  Range local_q = local.subset_by_type(MBQUAD);
+  Range local_q = local.subset_by_dimension(2);
   // the local should have all the vertices in local_verts
   for (Range::iterator it=local_q.begin(); it!=local_q.end(); it++)
   {
@@ -1273,7 +1280,7 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
     const EntityHandle * conn4;
     rval = mb->get_connectivity(q, conn4, nnodes);
     ERRORR(rval, "can't get connectivity of local q ");
-    EntityHandle new_conn[4];
+    EntityHandle new_conn[MAXEDGES];
     for (int i=0; i<nnodes; i++)
     {
       EntityHandle v1=conn4[i];
@@ -1290,39 +1297,59 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
       }
       new_conn[i] = globalID_to_handle[gids[index]];
     }
-    EntityHandle new_quad;
-    rval = mb->create_element(MBQUAD, new_conn, 4, new_quad);
+    EntityHandle new_element;
+    //
+    EntityType entType = MBQUAD;
+    if (nnodes >4)
+      entType = MBPOLYGON;
+    if (nnodes <4)
+      entType = MBTRI;
+
+    rval = mb->create_element(entType, new_conn, nnodes, new_element);
     ERRORR(rval, "can't create new quad ");
-    rval = mb->add_entities(covering_lagr_set, &new_quad, 1);
-    ERRORR(rval, "can't add new quad to dep set");
+    rval = mb->add_entities(covering_lagr_set, &new_element, 1);
+    ERRORR(rval, "can't add new element to dep set");
     int gid_el;
     // get the global ID of the initial quad
     rval=mb->tag_get_data(gid, &q, 1, &gid_el);
     ERRORR(rval, "can't get element global ID ");
-    globalID_to_eh[gid_el]=new_quad;
+    globalID_to_eh[gid_el]=new_element;
   }
-  // now look at all quads received through; we do not want to duplicate them
-  n=TLq.get_n();// number of quads received by this processor
+  // now look at all elements received through; we do not want to duplicate them
+  n=TLq.get_n();// number of elements received by this processor
   for (int i=0; i<n; i++)
   {
-    int globalIdEl = TLq.vi_rd[6*i+1];
+    int globalIdEl = TLq.vi_rd[sizeTuple*i+1];
     // do we already have a quad with this global ID, represented?
     if (globalID_to_eh.find(globalIdEl)==globalID_to_eh.end())
     {
       // construct the conn quad
-      EntityHandle new_conn[4];
-      for (int j=0; j<4; j++)
+      EntityHandle new_conn[MAXEDGES];
+      int nnodes;
+      for (int j=0; j<MAXEDGES; j++)
       {
-        int vgid = TLq.vi_rd[6*i+2+j];// vertex global ID
-        assert(globalID_to_handle.find(vgid)!=globalID_to_handle.end());
-        new_conn[j]=globalID_to_handle[vgid];
+        int vgid = TLq.vi_rd[sizeTuple*i+2+j];// vertex global ID
+        if (vgid==0)
+          new_conn[j] = 0;
+        else
+        {
+          assert(globalID_to_handle.find(vgid)!=globalID_to_handle.end());
+          new_conn[j]=globalID_to_handle[vgid];
+          nnodes = j+1;// nodes are at the beginning, and are variable number
+        }
       }
-      EntityHandle new_quad;
-      rval = mb->create_element(MBQUAD, new_conn, 4, new_quad);
-      ERRORR(rval, "can't create new quad ");
-      globalID_to_eh[globalIdEl]=new_quad;
-      rval = mb->add_entities(covering_lagr_set, &new_quad, 1);
-      ERRORR(rval, "can't add new quad to dep set");
+      EntityHandle new_element;
+      //
+      EntityType entType = MBQUAD;
+      if (nnodes >4)
+        entType = MBPOLYGON;
+      if (nnodes <4)
+        entType = MBTRI;
+      rval = mb->create_element(entType, new_conn, nnodes, new_element);
+      ERRORR(rval, "can't create new element ");
+      globalID_to_eh[globalIdEl]=new_element;
+      rval = mb->add_entities(covering_lagr_set, &new_element, 1);
+      ERRORR(rval, "can't add new element to dep set");
     }
   }
   return MB_SUCCESS;


https://bitbucket.org/fathomteam/moab/commits/3c82adc86c11/
Changeset:   3c82adc86c11
Branch:      None
User:        iulian07
Date:        2013-06-22 01:08:40
Summary:     forgot the test file for parallel intx for mpas file

Affected #:  1 file

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


https://bitbucket.org/fathomteam/moab/commits/d96605d8080f/
Changeset:   d96605d8080f
Branch:      None
User:        iulian07
Date:        2013-06-22 01:13:18
Summary:     correct the skinner to be able to skin polygons (with -a option)
still need to fix default option (no -a )
so mbskin -a intx1.vtk out.vtk works now if intx1 has polygons
mbskin intx1.vtk out.vtk does not work yet
With this fix, reading in parallel of an MPAS file works.

Still need to fix mbskin intx1.vtk out.vtk

Affected #:  3 files

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 = thisMB->get_connectivity( elem, conn, len, false, &storage );
   if (MB_SUCCESS != rval) return rval;
  
+  // 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==type && 1==d && MBEDGE==side_type)
+  {
+    // first find the first vertex in the conn list
+    int i=0;
+    for (i=0; i<len; i++)
+    {
+      if (conn[i]==side_conn[0])
+        break;
+    }
+    if (len == i)
+      return MB_FAILURE; // not found, big error
+    int prevIndex = (i+len-1)%len;
+    int nextIndex = (i+1)%len;
+    EntityHandle conn2[2] = {side_conn[0], side_conn[1]};
+    if (conn[prevIndex]==side_conn[1])
+    {
+      // reverse, so the edge will be forward
+      conn2[0]=side_conn[1];
+      conn2[1]=side_conn[0];
+    }
+    else if  ( conn[nextIndex]!=side_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/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index b17b5ff..ea51063 100644
--- a/test/parallel/par_intx_sph.cpp
+++ b/test/parallel/par_intx_sph.cpp
@@ -79,7 +79,7 @@ int main(int argc, char **argv)
   radius = CubeSide/2*sqrt(3.);
   result += RUN_TEST(test_intx_in_parallel_elem_based);
   radius =1.;
-  //result += RUN_TEST(test_intx_mpas);
+  result += RUN_TEST(test_intx_mpas);
 
   MPI_Finalize();
   return result;

diff --git a/tools/mbcslam/Intx2Mesh.cpp b/tools/mbcslam/Intx2Mesh.cpp
index 69a341e..fadbaa3 100644
--- a/tools/mbcslam/Intx2Mesh.cpp
+++ b/tools/mbcslam/Intx2Mesh.cpp
@@ -1192,7 +1192,7 @@ ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, Ent
   int sizeTuple = 2+MAXEDGES; // max edges is now 10 :) for polygons
   TLq.initialize(12, 0, 0, 0, numq); // to proc, elem GLOBAL ID, connectivity[10] (global ID v)
   TLq.enableWriteAccess();
-  std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " quads\n";
+  std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
 
   for (int to_proc=0; to_proc<numprocs; to_proc++)
   {


https://bitbucket.org/fathomteam/moab/commits/698aa864382e/
Changeset:   698aa864382e
Branch:      None
User:        iulian07
Date:        2013-06-24 19:59:19
Summary:     fix the intersection in parallel for MPAS grids.
the problem was in decomposition of concave polygons
still need to fix the case when the polygon has self intersecting edges,
or there are more than 2 obtuse angles
(it currently works fine if the quad has self intersecting edges, because
it means that there are 2 angles bigger than 180 degrees)

Affected #:  2 files

diff --git a/test/parallel/par_intx_sph.cpp b/test/parallel/par_intx_sph.cpp
index ea51063..bf5cbb8 100644
--- a/test/parallel/par_intx_sph.cpp
+++ b/test/parallel/par_intx_sph.cpp
@@ -341,6 +341,11 @@ void test_intx_mpas()
   std::stringstream ss;
   ss<<"partial" << rank<<".vtk";
   mb.write_file(ss.str().c_str(), 0, 0, &covering_lagr_set, 1);
+  rval = 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 = mb.create_meshset(MESHSET_SET, outputSet);
   CHECK_ERR(rval);

diff --git a/tools/mbcslam/CslamUtils.cpp b/tools/mbcslam/CslamUtils.cpp
index a819825..1166a7a 100644
--- a/tools/mbcslam/CslamUtils.cpp
+++ b/tools/mbcslam/CslamUtils.cpp
@@ -876,17 +876,20 @@ ErrorCode enforce_convexity(Interface * mb, EntityHandle lset)
     return rval;
 
   std::vector<double> coords;
-  coords.resize(3*10); // at most 10 vertices per polygon
+  coords.resize(3*MAXEDGES); // at most 10 vertices per polygon
   // we should create a queue with new polygons that need processing for reflex angles
   //  (obtuse)
   std::queue<EntityHandle> newPolys;
   int brokenPolys=0;
-  for (Range::iterator eit = inputRange.begin(); eit != inputRange.end()
-                                       || !newPolys.empty() ; eit++)
+  Range::iterator eit = inputRange.begin();
+  while (eit != inputRange.end() || !newPolys.empty())
   {
     EntityHandle eh;
     if (eit != inputRange.end())
+    {
       eh = *eit;
+      eit++;
+    }
     else
     {
       eh = newPolys.front();


https://bitbucket.org/fathomteam/moab/commits/e51614407ee3/
Changeset:   e51614407ee3
Branch:      master
User:        iulian07
Date:        2013-06-24 20:22:06
Summary:     Merge branch 'master' of bitbucket.org:fathomteam/moab

Affected #:  3 files

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)
+ 
+  \subpage dg-contents
+ 
+  \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 values. Each
+<I>SequenceData</I> has a start and end handle denoting the block of entities for which
+the arrays contain data. The arrays managed by a <I>SequenceData</I> instance are
+divided into three groups:
+
+- Type-specific data (connectivity, coordinates, etc.): zero or more arrays.
+- 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>SequenceData</I>.
+It contains a pointer to a <I>SequenceData</I> and the start and end handles to indi-
+cate the subset of the referenced <I>SequenceData</I>. The <I>EntitySequence</I> class is
+used to represent the regions of valid (or allocated) handles in a <I>SequenceData</I>.
+A <I>SequenceData</I> is expected to be referenced by one or more <I>EntitySequence</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> will be created
+to represent all of a single type of entity contained in a file. As all entries 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 created to store
+the entity data. It is created with a constant size (e.g. 4k entities). The new
+<I>EntitySequence</I> corresponds to only the first entity in the <I>SequenceData</I>: the
+one allocated entity. As subsequent entities are allocated, the <I>EntitySequence</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 the
+<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 allocation
+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 range of
+entities represented by the original sequence is split.
+
+The <I>VertexSequence</I> class provides an <I>EntitySequence</I> for storing 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 functionality. The
+<I>UnstructuredElemSeq</I> class is the concrete implementation of <I>ElementSequence</I>
+used to represent unstructured elements, polygons, and polyhedra. <I>MeshSetSequence</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 storing a particular
+entity. For example, <I>UnstructuredElemSeq</I> returns the number of nodes 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 stored
+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 representation of
+mixed-dimension data. However, API changes would be required to utilize such
+a feature. Sequences for which the corresponding data cannot be used to store
+new entities (e.g. structured mesh discussed in a later section) will return -1 or
+some other invalid value.
+
+ \ref dg-contents
+
+  \section manager 2. TypeSequenceManager & SequenceManager 
+
+The <I>TypeSequenceManager</I> class maintains an organized set of <I>EntitySequence</I>
+instances and corresponding <I>SequenceData</I> instances. It is used to manage
+all such instances for entities of a single <I>EntityType</I>. <I>TypeSequenceManager</I>
+enforces the following four rules on its contained data:
+
+-# No two <I>SequenceData</I> instances may overlap.  
+-# 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>SequenceData</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>. The above rules
+(including the fourth) are assumed in many other methods of the <I>TypeSequenceManager</I>
+class, such that those methods will fail or behave unexpectedly if the managed
+data does not conform to the rules.
+
+<I>TypeSequenceManager</I> contains three principal data structures. The first 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 “sequence” 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 contains
+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 sequences
+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 “cached” 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>TypeSequenceManager</I> will
+typically assign an arbitrary sequence (e.g. the first one) to the last referenced
+pointer.
+
+The third data member of <I>TypeSequenceManager</I> is a <I>std::set</I> of <I>SequenceData</I>
+instances that are not completely covered by a <I>EntitySequence</I> instance<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 corresponding
+<I>EntitySequence</I> so that it may be located quickly from only the <I>SequenceData</I>
+pointer.
+
+The <I>SequenceManager</I> class contains an array of <I>TypeSequenceManager</I> in-
+stances, one for each <I>EntityType</I>. It also provides all type-specific 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>TypeSequenceManager</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>StructuredElementSeq</I> class is
+used to access the structured element connectivity. A standard <I>VertexSequence</I>
+instance is used to access the ScdVertexData because the vertex data storage
+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>EntityHandle</I>.
+<I>SequenceData</I> allocates all of its managed arrays using malloc and free 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 to what is
+done by <I>std::vector</I> and other container classes that may own more storage
+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> class.
+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>MESHSET_TRACK_OWNER</I>
+indicates that reverse links from the contained entities back to the owning 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 code only
+tests for the <I>MESHSET_ORDERED</I>, meaning that in practice the <I>MESHSET_SET</I> bit is
+ignored. <I>MESHSET_ORDERED</I> indicates that the set may contain duplicate handles
+and that the order that the handles are added to the set should be preserved.
+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 ‘size’ field and two
+values, where the two values may either be two handles or two pointers. The size
+bit-fields are grouped together to reduce the required amount of memory. If the
+numerical value of the 2-bit size field is 0 then the corresponding list is empty.
+If the 2-bit size field is either 1 or 2, then the contents of the corresponding list
+are stored directly in the corresponding two data fields of the MeshSet object.
+If the 2-bit size field has a value of 3 (11 binary), then the corresponding two
+data fields store the begin and end pointers of an external array of handles.
+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 ‘used’ 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 ‘allocated’ size
+for us. In practice this performs well but does not return memory to the ‘system’
+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 frequently changes
+between less than two and more than two handles, as this will result in frequent
+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 list (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 two.
+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 ‘adjacent’ range pairs are merged into a
+single pair. The code for insertion and removal of handles from range-formatted
+set content lists is fairly complex. The implementation will guarantee that 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 ‘n’ is the number of handles to insert
+and ‘m’ 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 set.
+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 potential ‘slots’
+in the MeshSet object then if two of the lists are empty it should be possible to store up to six values of the remaining list directly in the MeshSet object.
+However, the additional runtime cost of such complexity could easily outweigh
+any storage advantage. Further investigation into this has not been done because
+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 ‘blocked’ format. The corre-
+sponding <I>SequenceData</I> would contain four arrays: flags, parents, children, 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 the storage
+reduction would depend greatly on how sets get grouped into <I>SequenceDatas</I>.
+This alternate storage scheme might also allow for better cache utilization 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 never
+query the parents or children of any set. Or that an application will query 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 less mod-
+ular and maintainable because the existing logic contained in the <I>MeshSet</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/user.dox.in b/doc/user.dox.in
index 6b7730b..ed65208 100644
--- a/doc/user.dox.in
+++ b/doc/user.dox.in
@@ -306,6 +306,7 @@ WARN_LOGFILE           =
 
 INPUT                  = @top_srcdir@/src @top_srcdir@/src/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 \

diff --git a/src/moab/Interface.hpp b/src/moab/Interface.hpp
index 6a04ff7..d7ad8aa 100644
--- a/src/moab/Interface.hpp
+++ b/src/moab/Interface.hpp
@@ -22,7 +22,7 @@
  * together to describe geometric topology, boundary condition, and inter-processor interface 
  * groupings in a mesh.
  *
- * MOAB's API is documented in the moab::Interface class.  The User's Guide is located in
+ * MOAB's API is documented in the moab::Interface class.  The User's Guide and Developer's Guide are located in
  * <a href="pages.html">related pages</a>.  Questions and comments should be sent to moab-dev 
  * _at_ mcs.anl.gov.
  */

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