added option of aggressive node removal for eatintoelement
authorAaron Becker <akbecker@gmail.com>
Thu, 16 Dec 2010 00:51:47 +0000 (18:51 -0600)
committerAaron Becker <akbecker@gmail.com>
Thu, 16 Dec 2010 00:51:47 +0000 (18:51 -0600)
src/libs/ck-libs/ParFUM/ParFUM_Adapt.h
src/libs/ck-libs/ParFUM/ParFUM_Mesh_Modify.h
src/libs/ck-libs/ParFUM/ParFUM_internals.h
src/libs/ck-libs/ParFUM/adapt.C
src/libs/ck-libs/ParFUM/adapt_lock.C
src/libs/ck-libs/ParFUM/mesh_modify.C
src/libs/ck-libs/ParFUM/util.C

index 57ac23c640cba1a60e3a9da1d3a06535004fc5dd..2e536a72d2bc6ed840ae4774e141f72835bcf71b 100644 (file)
@@ -160,9 +160,11 @@ class FEM_AdaptL : public FEM_Adapt {
                                    int e2_n3, int n3, int n4);
 
   /// Acquire an element in our ghost layer, turning it into a local element
-  int eatIntoElement(int e);
+  int eatIntoElement(int e, bool aggressive_node_removal=false);
   /// Test the adaptivity system to see if any nodes are locked
   void residualLockTest();
+  /// Release all currently held locks on this partition
+  void unlockAll();
   /// Test the mesh for corruption in connectivity/adjacency
   void structureTest();
 };
index c735ae3b42c122fae190cea5bbac591e8f8fc874..4c4e7eeb451dd7c27660a9be10b94364d0b68e40 100644 (file)
@@ -34,7 +34,7 @@ void FEM_remove_node(FEM_Mesh *m, int node);
 ///Add an element on this mesh with this connectivity
 int FEM_add_element(FEM_Mesh *m, int* conn, int conn_size, int elem_type=0, int chunkNo=-1);
 ///Remove an element on this mesh
-int FEM_remove_element(FEM_Mesh *m, int element, int elem_type=0, int permanent=-1);
+int FEM_remove_element(FEM_Mesh *m, int element, int elem_type=0, int permanent=-1, bool aggressive_node_removal=false);
 ///Purge the element from this mesh (invalidate entry)
 int FEM_purge_element(FEM_Mesh *m, int element, int elem_type=0);
 
@@ -287,6 +287,7 @@ class removeElemMsg : public CMessage_removeElemMsg {
   int elementid;
   int elemtype;
   int permanent;
+  bool aggressive_node_removal;
 };
 
 ///A message to verify if the IDXL entries for a node/element on one chunk is consistent with another chunk
index 2b0e6e589980e4e92f3ebfc667496222b43ca13d..36a828c870a54a9154c28b11050c26d15acd7ef1 100644 (file)
@@ -2827,7 +2827,7 @@ class FEM_MUtil {
   ///Add the element with this conn (indices, typeOfIndices) on this chunk (called from remote chunk)
   void addGhostElementRemote(FEM_Mesh *m, int chk, int elemType, int *indices, int *typeOfIndex, int connSize);
   ///Remove this element on this chunk (called from remote chunk)
-  void removeElemRemote(FEM_Mesh *m, int chk, int elementid, int elemtype, int permanent);
+  void removeElemRemote(FEM_Mesh *m, int chk, int elementid, int elemtype, int permanent, bool aggressive_node_removal=false);
   ///Remove this ghost element on this chunk, also delete some ghost nodes and elements
   void removeGhostElementRemote(FEM_Mesh *m, int chk, int elementid, int elemtype, int numGhostIndex, int *ghostIndices, int numGhostRNIndex, int *ghostRNIndices, int numGhostREIndex, int *ghostREIndices, int numSharedIndex, int *sharedIndices);
 
@@ -2836,7 +2836,7 @@ class FEM_MUtil {
   ///Add this node to the shared Idxl list (called from remote chunk)
   void addToSharedList(FEM_Mesh *m, int fromChk, int sharedIdx);
   ///Acquire the element specified by this ghost index
-  int eatIntoElement(int localIdx);
+  int eatIntoElement(int localIdx, bool aggressive_node_removal=false);
 
   ///Does this chunk know about this node index (on any idxl list with 'chk')
   bool knowsAbtNode(int chk, int nodeId);
@@ -2885,6 +2885,8 @@ class FEM_MUtil {
   void verifyIdxlListRemote(FEM_Mesh *m, int fromChk, int fsize, int type);
   ///Test that there are no remaining acquired locks on this mesh
   int residualLockTest(FEM_Mesh *m);
+  /// Release all currently held locks on this partition
+  void unlockAll(FEM_Mesh* m);
 };
 
 
index 9eead87ccc91f6d1b1c2d6462889865953c43b98..04523f15fcbb1a0e6b1e9adbcd646eeafcff7b7b 100644 (file)
@@ -837,9 +837,9 @@ int FEM_Adapt::vertex_split_help(int n, int n1, int n2, int e1, int e3)
 // ======================  END vertex_split ===================
 
 
-int FEM_AdaptL::eatIntoElement(int e)
+int FEM_AdaptL::eatIntoElement(int e, bool aggressive_node_removal)
 {
-    return theMod->fmUtil->eatIntoElement(e);
+    return theMod->fmUtil->eatIntoElement(e, aggressive_node_removal);
 }
 
 
@@ -849,6 +849,11 @@ void FEM_AdaptL::residualLockTest()
 }
 
 
+void FEM_AdaptL::unlockAll() {
+    theMod->fmUtil->unlockAll(theMod->fmMesh);
+}
+
+
 void FEM_AdaptL::structureTest()
 {
     theMod->fmUtil->StructureTest(theMod->fmMesh);
index 5c52162fefa2a32985e682e81f37f776654217f1..2147bcc0b624bb09cd48ea81ab315b822e221caa 100644 (file)
@@ -6,8 +6,7 @@
 #include "ParFUM.h"
 #include "ParFUM_internals.h"
 
-#define DEBUG_LOCKS
-
+//#define DEBUG_LOCKS
 //#define DEBUG_1
 #define ERVAL -1000000000  //might cause a problem if there are 100million nodes
 #define ERVAL1 -1000000001
@@ -17,6 +16,9 @@
  * nodes which specifies if locks for each nodes has been acquired or not
  */
 int FEM_AdaptL::lockNodes(int *gotlocks, int *lockrnodes, int numRNodes, int *lockwnodes, int numWNodes) {
+#ifdef CPSD
+    return true;
+#endif
   bool donelocks = false;
   int numNodes = numRNodes + numWNodes;
   for(int i=0; i<numNodes; i++) gotlocks[i] = 0;
@@ -98,6 +100,9 @@ int FEM_AdaptL::lockNodes(int *gotlocks, int *lockrnodes, int numRNodes, int *lo
 /** Same as above, instead it unlocks the nodes
  */
 int FEM_AdaptL::unlockNodes(int *gotlocks, int *lockrnodes, int numRNodes, int *lockwnodes, int numWNodes) {
+#ifdef CPSD
+    return true;
+#endif
   bool donelocks = false;
   int numNodes = numRNodes + numWNodes;
   int *ungetlocks = (int*)malloc(numNodes*sizeof(int));
@@ -193,7 +198,7 @@ int FEM_AdaptL::edge_flip(int n1, int n2) {
       numtries++;
       if(numtries>=13+(7*theMod->idx)%43) {
        if(!warned) {
-         //CkPrintf("[%d]Warning: Possibly a livelock in edge_flip %d & %d, supporting %d, %d\n",theMod->idx,n1,n2,n3,n4);
+         CkPrintf("[%d]Warning: Possibly a livelock in edge_flip %d & %d, supporting %d, %d\n",theMod->idx,n1,n2,n3,n4);
          warned = true;
        }
        CthYield();
@@ -242,17 +247,14 @@ int FEM_AdaptL::edge_bisect(int n1, int n2) {
   for(int i=0; i<numNodes; i++) {
     gotlocks[i] = -1;
   }
-  while(!done) {
 #ifdef CPSD
-      int gotlock = 1;
+  isEdge = findAdjData(n1, n2, &e1, &e2, &e1_n1, &e1_n2, &e1_n3, &e2_n1, &e2_n2, &e2_n3,&n3, &n4);
 #else
+  while(!done) {
     int gotlock = lockNodes(gotlocks, locknodes, 0, locknodes, numNodes);
-#endif
     isEdge = findAdjData(n1, n2, &e1, &e2, &e1_n1, &e1_n2, &e1_n3, &e2_n1, &e2_n2, &e2_n3,&n3, &n4);
     if(isEdge == -1) {
-#ifndef CPSD
       unlockNodes(gotlocks, locknodes, 0, locknodes, numNodes);
-#endif
 #ifdef DEBUG_1
       CkPrintf("[%d]Warning: Bisect %d->%d not done as it is no longer a valid edge\n",theMod->idx,n1,n2);
 #endif
@@ -262,9 +264,7 @@ int FEM_AdaptL::edge_bisect(int n1, int n2) {
       done = true;
     }
     else {
-#ifndef CPSD
       unlockNodes(gotlocks, locknodes, 0, locknodes, numNodes);
-#endif
       locknodes[2] = n3;
       locknodes[3] = n4;
       numtries++;
@@ -280,11 +280,11 @@ int FEM_AdaptL::edge_bisect(int n1, int n2) {
       CthYield();
     }
   }
+#endif
   int ret = edge_bisect_help(e1, e2, n1, n2, e1_n1, e1_n2, e1_n3, e2_n1, e2_n2, e2_n3, n3, n4);
 #ifndef CPSD
   unlockNodes(gotlocks, locknodes, 0, locknodes, numNodes);
 #endif
-
   return ret;
 }
 
@@ -368,7 +368,7 @@ int FEM_AdaptL::vertex_remove(int n1, int n2) {
       numtries++;
       if(numtries>=13+(7*theMod->idx)%43) {
        if(!warned) {
-         //CkPrintf("[%d]Warning: Possibly a livelock in vertex_remove %d & %d, supporting %d, %d and %d\n",theMod->idx,n1,n2,n3,n4,n5);
+         CkPrintf("[%d]Warning: Possibly a livelock in vertex_remove %d & %d, supporting %d, %d and %d\n",theMod->idx,n1,n2,n3,n4,n5);
          warned = true;
        }
        numtries = 0;
@@ -622,7 +622,7 @@ int FEM_AdaptL::edge_contraction(int n1, int n2) {
        }
       }
       if(numtries>=50) {
-       //CkPrintf("Possibly a livelock in cloud nodes edge_contract\n");
+       CkPrintf("Possibly a livelock in cloud nodes edge_contract\n");
        //it is ok to skip an edge_contract, if the lock is too difficult to get
        isEdge = findAdjData(n1, n2, &e1, &e2, &e1_n1, &e1_n2, &e1_n3, &e2_n1, &e2_n2, &e2_n3,&n3, &n4);
        if(isEdge!=-1) {
@@ -646,7 +646,7 @@ int FEM_AdaptL::edge_contraction(int n1, int n2) {
       numtries++;
       if(numtries>=50) {
        if(!warned) {
-         //CkPrintf("[%d]Warning: Possibly a livelock in edge_contract %d & %d, supporting %d, %d. Avoiding this contract operation.\n",theMod->idx,n1,n2,n3,n4);
+         CkPrintf("[%d]Warning: Possibly a livelock in edge_contract %d & %d, supporting %d, %d. Avoiding this contract operation.\n",theMod->idx,n1,n2,n3,n4);
          warned = true;
        }
         //it is ok to skip an edge_contract, if the lock is too difficult to get
@@ -1199,7 +1199,7 @@ int FEM_AdaptL::edge_contraction_help(int *e1P, int *e2P, int n1, int n2, int e1
            unlockNodes(gotlocks1, lockw, 0, lockw, size);
            free(gotlocks1);
            free(lockw);
-           //CkPrintf("Possibly a livelock in edge_contract_help\n");
+           CkPrintf("Possibly a livelock in edge_contract_help\n");
            delete [] eConn;
            if(nesize!=0) delete[] nbrElems;
            free(gotlocks);
index b458914a6785bdd1d882e16cb0e18597d58d8ac8..f34f76887250d8ab38f0d8c31de92d1c49157afd 100644 (file)
@@ -1076,7 +1076,7 @@ void FEM_remove_element_local(FEM_Mesh *m, int element, int etype){
     The idxl info will be deleted in Purge, that way shared 
     chunks could still refer to it, needed for solution transfer
 */
-int FEM_remove_element(FEM_Mesh *m, int elementid, int elemtype, int permanent){
+int FEM_remove_element(FEM_Mesh *m, int elementid, int elemtype, int permanent, bool aggressive_node_removal){
   //CkAssert(elementid != -1);
 #ifdef DEBUG_2
   CkPrintf("removeElement, line %d\n", __LINE__);
@@ -1097,6 +1097,7 @@ int FEM_remove_element(FEM_Mesh *m, int elementid, int elemtype, int permanent){
     rm->elementid = sharedIdx;
     rm->elemtype = elemtype;
     rm->permanent = permanent;
+    rm->aggressive_node_removal = aggressive_node_removal;
     meshMod[remoteChunk].removeElementRemote(rm);
     // remove local ghost element, now done in purge
 #ifdef DEBUG_2
@@ -1470,23 +1471,26 @@ int FEM_remove_element(FEM_Mesh *m, int elementid, int elemtype, int permanent){
 #endif
 // This code removes nodes that we still need in cases involving acquisition/flip for
 // CPSD. I don't really follow the logic here, so I'm just cutting this bit out for now
-#ifndef CPSD
-                 if(!irec1) {
-                   if(!losinglocal) {
-                     FEM_remove_node_local(m,nodes[j]);
-                   }
-                   else {
-                     deleteNodeLater = nodes[j];
-                   }
+//#ifndef CPSD
+          CkPrintf("removeElement, aggressive_node_removal: %d\n", aggressive_node_removal);
+          if (aggressive_node_removal) {
+              if(!irec1) {
+                  if(!losinglocal) {
+                      FEM_remove_node_local(m,nodes[j]);
+                  }
+                  else {
+                      deleteNodeLater = nodes[j];
+                  }
 #ifdef DEBUG_2
-  CkPrintf("removeElement, line %d\n", __LINE__);
-#endif
-                   //if losing a local node, then can remove it only after its attributes 
-                   //have been copied, since this is the only copy.. 
-                   //(as no other chunk has this node as local/shared)
-                   //so we'll need to delete the ghostsend idxl entry and the node later
-                 }
+                  CkPrintf("removeElement, line %d\n", __LINE__);
 #endif
+                  //if losing a local node, then can remove it only after its attributes 
+                  //have been copied, since this is the only copy.. 
+                  //(as no other chunk has this node as local/shared)
+                  //so we'll need to delete the ghostsend idxl entry and the node later
+              }
+          }
+//#endif
                }
              }
              if(numElems!=0) delete[] elems;
@@ -2415,7 +2419,7 @@ void femMeshModify::removeGhostElem(removeGhostElemMsg *fm) {
 
 void femMeshModify::removeElementRemote(removeElemMsg *fm) {
   CtvAccess(_curTCharm) = tc;
-  fmUtil->removeElemRemote(fmMesh, fm->chk, fm->elementid, fm->elemtype, fm->permanent);
+  fmUtil->removeElemRemote(fmMesh, fm->chk, fm->elementid, fm->elemtype, fm->permanent, fm->aggressive_node_removal);
   delete fm;
   return;
 }
index bf41f1629314c7dbd1873951d25795d6a0e7eb47..8ebbbc626e9c8d4e07ea0ff2e988e8d41db61194 100644 (file)
@@ -626,10 +626,11 @@ void FEM_MUtil::addGhostElementRemote(FEM_Mesh *m, int chk, int elemType, int *i
 
 /** Remove this element, permanent specifies if this element is permanently removed
  */
-void FEM_MUtil::removeElemRemote(FEM_Mesh *m, int chk, int elementid, int elemtype, int permanent) {
+void FEM_MUtil::removeElemRemote(FEM_Mesh *m, int chk, int elementid, int elemtype, int permanent,
+        bool aggressive_node_removal) {
   const IDXL_List ll = m->elem[elemtype].ghostSend.addList(chk);
   int localIdx = ll[elementid];
-  FEM_remove_element(m, localIdx, elemtype, permanent);
+  FEM_remove_element(m, localIdx, elemtype, permanent, aggressive_node_removal);
   return;
 }
 
@@ -913,13 +914,14 @@ void FEM_MUtil::addToSharedList(FEM_Mesh *m, int fromChk, int sharedIdx) {
     Add a new element with this connectivity ON THIS CHUNK
     Update the lock on any node which changes owners
  */
-int FEM_MUtil::eatIntoElement(int localIdx) {
+int FEM_MUtil::eatIntoElement(int localIdx, bool aggressive_node_removal) {
   CkAssert(FEM_Is_ghost_index(localIdx));
   int nodesPerEl = mmod->fmMesh->elem[0].getConn().width();
   int *adjnodes = new int[nodesPerEl];
   int *oldnodes = new int[nodesPerEl];
   int elemtype = 0;
   mmod->fmMesh->e2n_getAll(localIdx, adjnodes, elemtype);
+  CkPrintf("Chunk %d eating elem %d(%d,%d,%d) %d\n",idx,localIdx,adjnodes[0],adjnodes[1],adjnodes[2], aggressive_node_removal);
 #ifdef DEBUG_1
   CkPrintf("Chunk %d eating elem %d(%d,%d,%d)\n",idx,localIdx,adjnodes[0],adjnodes[1],adjnodes[2]);
 #endif
@@ -937,7 +939,7 @@ int FEM_MUtil::eatIntoElement(int localIdx) {
 #ifdef DEBUG_1
   CkPrintf("eatIntoElement::remove\n");
 #endif
-  FEM_remove_element(mmod->fmMesh,localIdx,elemtype,idx);
+  FEM_remove_element(mmod->fmMesh,localIdx,elemtype,idx,aggressive_node_removal);
 #ifdef DEBUG_1
   CkPrintf("eatIntoElement::done removing\n");
 #endif
@@ -965,14 +967,14 @@ int FEM_MUtil::eatIntoElement(int localIdx) {
 #endif
   copyElemData(0,localIdx,newEl); //special copy across chunk
   FEM_purge_element(mmod->fmMesh,localIdx,elemtype);
-#ifndef CPSD
+//#ifndef CPSD
   for(int i=0; i<nodesPerEl; i++) {
     if(adjnodes[i]!=oldnodes[i]) {
       //correct the lock
       FEM_Modify_LockUpdate(mmod->fmMesh,adjnodes[i]);
     }
   }
-#endif
+//#endif
   free(adjnodes);
   free(oldnodes);
   return newEl;
@@ -1380,302 +1382,302 @@ void FEM_MUtil::FEM_Print_coords(FEM_Mesh *m, int nodeid) {
     Validity of nodes/elements
 */
 void FEM_MUtil::StructureTest(FEM_Mesh *m) {
-  int noNodes = m->node.size();
-  int noEle = m->elem[0].size();
-  int noGhostEle = m->elem[0].ghost->size();
-  int noGhostNodes = m->node.ghost->size();
-  int wdt = m->elem[0].getConn().width();
-  int *e2n = (int*)malloc(wdt*sizeof(int));
-  for(int i=0; i<noEle; i++) {
-    if(m->elem[0].is_valid(i)) {
-      m->e2n_getAll(i,e2n,0);
-      //must have all different connections
-      if(e2n[0]==e2n[1] || e2n[1]==e2n[2] || e2n[2]==e2n[0]) {
-       CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",i,e2n[0],e2n[1],e2n[2]);
-       CkAssert(false);
-      }
-      //local elem must have all local node connectivity 
-      if(e2n[0]<0 || e2n[1]<0 || e2n[2]<0) {
-       CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",i,e2n[0],e2n[1],e2n[2]);
-       CkAssert(false);
-      }
-      for(int j=0; j<3; j++) {
-       //all nodes must be valid and all local elems should have local connectivity
-       CkAssert(m->node.is_valid(e2n[j]));
-      }
-      int e2e[3];
-      m->e2e_getAll(i,e2e,0);
-      if((e2e[0]==e2e[1]) && (e2e[0]==e2e[2]) && (e2e[0]!=-1)) {
-       CkPrintf("ERROR: element %d, has e2e (%d,%d,%d)\n",i,e2e[0],e2e[1],e2e[2]);
-       CkAssert(false);
-      }
-    }
-  }
-  for(int i=0; i<noGhostEle; i++) {
-    if(m->elem[0].ghost->is_valid(i)) {
-      int ghostIndex = FEM_To_ghost_index(i);
-      m->e2n_getAll(ghostIndex,e2n,0);
-      if(e2n[0]==e2n[1] || e2n[1]==e2n[2] || e2n[2]==e2n[0]) {
-       //must have all different connections
-       CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",ghostIndex,e2n[0],e2n[1],e2n[2]);
-       CkAssert(false);
-      }
-      if(!(e2n[0]>=0 || e2n[1]>=0 || e2n[2]>=0)) {
-       //must have at least one local node
-       CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",ghostIndex,e2n[0],e2n[1],e2n[2]);
-       CkAssert(false);
-      }
-      for(int j=0; j<3; j++) {
-       //all nodes must be valid
-       if(e2n[j]>=0) CkAssert(m->node.is_valid(e2n[j]));
-       else CkAssert(m->node.ghost->is_valid(FEM_From_ghost_index(e2n[j])));
-      }
-      int e2e[3];
-      m->e2e_getAll(ghostIndex,e2e,0);
-      if((e2e[0]==e2e[1]) && (e2e[0]==e2e[2]) && (e2e[0]!=-1)) {
-       CkPrintf("ERROR: element %d, has e2e (%d,%d,%d)\n",i,e2e[0],e2e[1],e2e[2]);
-       CkAssert(false);
-      }
+    int noNodes = m->node.size();
+    int noEle = m->elem[0].size();
+    int noGhostEle = m->elem[0].ghost->size();
+    int noGhostNodes = m->node.ghost->size();
+    int wdt = m->elem[0].getConn().width();
+    int *e2n = (int*)malloc(wdt*sizeof(int));
+    for(int i=0; i<noEle; i++) {
+        if(m->elem[0].is_valid(i)) {
+            m->e2n_getAll(i,e2n,0);
+            //must have all different connections
+            if(e2n[0]==e2n[1] || e2n[1]==e2n[2] || e2n[2]==e2n[0]) {
+                CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",i,e2n[0],e2n[1],e2n[2]);
+                CkAssert(false);
+            }
+            //local elem must have all local node connectivity 
+            if(e2n[0]<0 || e2n[1]<0 || e2n[2]<0) {
+                CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",i,e2n[0],e2n[1],e2n[2]);
+                CkAssert(false);
+            }
+            for(int j=0; j<3; j++) {
+                //all nodes must be valid and all local elems should have local connectivity
+                CkAssert(m->node.is_valid(e2n[j]));
+            }
+            int e2e[3];
+            m->e2e_getAll(i,e2e,0);
+            if((e2e[0]==e2e[1]) && (e2e[0]==e2e[2]) && (e2e[0]!=-1)) {
+                CkPrintf("ERROR: element %d, has e2e (%d,%d,%d)\n",i,e2e[0],e2e[1],e2e[2]);
+                CkAssert(false);
+            }
+        }
     }
-  }
-  int *n2e, n2esize=0;
-  int *n2n, n2nsize=0;
-  for(int i=0; i<noNodes; i++) {
-    if(m->node.is_valid(i)) {
-      m->n2e_getAll(i,n2e,n2esize);
-      m->n2n_getAll(i,n2n,n2nsize);
-      if(n2esize>n2nsize) {
-       FEM_Print_coords(m,i);
-       FEM_Print_n2e(m,i);
-       FEM_Print_n2n(m,i);
-       CkPrintf("ERROR: local node %d, with inconsistent adjacency list\n",i);
-       CkAssert(false);
-      }
-    }
-    else {
-      continue;
-    }
-    if(n2esize > 0) {
-      for(int j=0; j<n2esize; j++) {
-       CkAssert(n2e[j]!=-1);
-       if(FEM_Is_ghost_index(n2e[j])) CkAssert(m->elem[0].ghost->is_valid(FEM_From_ghost_index(n2e[j]))==1);
-       else CkAssert(m->elem[0].is_valid(n2e[j])==1);
-      }
-      m->e2n_getAll(n2e[0],e2n,0);
-      //any local/shared node should have at least one local element connected to it
-      bool done = false;
-      for(int j=0; j<n2esize; j++) {
-       if(n2e[j] >= 0) {
-         done = true; 
-         break;
-       }
-      }
-      if(!done) {
-       FEM_Print_coords(m,i);
-       FEM_Print_n2e(m,i);
-       FEM_Print_n2n(m,i);
-       CkPrintf("ERROR: isolated local node %d, with no local element connectivity\n",i);
-       CkAssert(false);
-      }
-      //ensure that there is a cloud of connectivity, no disconnected elements, other than boundaries
-      int testnode = i;
-      int startnode = (e2n[0]==testnode) ? e2n[1] : e2n[0];
-      int othernode = (e2n[2]==testnode) ? e2n[1] : e2n[2];
-      int previousnode = startnode;
-      int nextnode = -1;
-      int numdeadends = 0;
-      int numunused = n2esize-1;
-      n2e[0] = -1;
-      for(int j=0; j<n2esize-1; j++) {
-       nextnode = -1;
-       for(int k=1; k<n2esize; k++) {
-         if(n2e[k]==-1) continue;
-         m->e2n_getAll(n2e[k],e2n,0);
-         if(e2n[0]==previousnode || e2n[1]==previousnode || e2n[2]==previousnode) {
-           nextnode = (e2n[0]==previousnode) ? ((e2n[1]==testnode)? e2n[2]:e2n[1]) : ((e2n[1]==previousnode)? ((e2n[0]==testnode)? e2n[2]:e2n[0]):((e2n[1]==testnode)? e2n[0]:e2n[1]));
-           previousnode = nextnode;
-           n2e[k] = -1;
-           numunused--;
-         }
-       }
-       if(nextnode==othernode && othernode!=-1) {
-         //it has reached a full circle
-         break;
-       }
-       else if(nextnode==-1) {
-         //this is one edge, start travelling along the other end
-         numdeadends++;
-         previousnode = othernode;
-         othernode = -1;
-       }
-       if(numdeadends>2 && numunused!=0) {
-         FEM_Print_coords(m,i);
-         FEM_Print_n2e(m,i);
-         FEM_Print_n2n(m,i);
-         CkPrintf("ERROR: cloud connectivity of node %d is discontinuous\n",i);
-         CkAssert(false);
-       }
-      }
-      if(n2esize>0) delete[] n2e; n2esize=0;
-      //reconstruct n2n from n2e & e2n
-      int n2n1size = 0;
-      int *n2n1 = (int*)malloc(n2nsize*sizeof(int));
-      int n2n1Count = 0;
-      m->n2e_getAll(i,n2e,n2esize);
-      for(int j=0; j<n2esize; j++) {
-       CkAssert(n2e[j]!=-1);
-       //each of these elems should have me in its e2n
-       int e2n1[3];
-       m->e2n_getAll(n2e[j],e2n1,0);
-       if(e2n1[0]!=i && e2n1[1]!=i && e2n1[2]!=i) {
-         FEM_Print_coords(m,i);
-         FEM_Print_n2e(m,i);
-         FEM_Print_e2n(m,n2e[j]);
-         CkPrintf("ERROR: ghost elem %d & ghost node %d have inconsistent adjacency list\n",n2e[j],i);
-         CkAssert(false);
-       }
-       for(int k=0; k<3;k++) {
-         if(e2n1[k] == i) continue;
-         bool flag1 = true;
-         for(int l=0; l<n2n1Count; l++) {
-           if(e2n1[k] == n2n1[l]) flag1 = false;
-         }
-         if(flag1 && n2n1Count<n2nsize) { //this is not in the list
-           n2n1[n2n1Count] = e2n1[k];
-           n2n1Count++;
-         }
-       }
-      }
-      //verify if n2n1 has the same nodes as n2n
-      bool flag2 = true;
-      if(n2n1Count!=n2nsize) flag2 = false;
-      for(int j=0; j<n2n1Count; j++) {
-       bool flag1 = false;
-       for(int k=0; k<n2nsize; k++) {
-         if(n2n[k]==n2n1[j]) flag1 = true;
-       }
-       if(!flag1) {
-         flag2 = false;
-         break;
-       }
-      }
-      if(!flag2) {
-       FEM_Print_coords(m,i);
-       FEM_Print_n2n(m,i);
-       for(int l=0; l<n2esize; l++) FEM_Print_e2n(m,n2e[l]);
-       CkPrintf("ERROR: ghost node %d has inconsistent adjacency list\n",i);
-       CkAssert(false);
-      }
-      
-      delete [] n2n1;
-      if(n2esize>0) delete [] n2e; n2esize=0;
-      if(n2nsize>0) delete [] n2n; n2nsize=0;
+    for(int i=0; i<noGhostEle; i++) {
+        if(m->elem[0].ghost->is_valid(i)) {
+            int ghostIndex = FEM_To_ghost_index(i);
+            m->e2n_getAll(ghostIndex,e2n,0);
+            if(e2n[0]==e2n[1] || e2n[1]==e2n[2] || e2n[2]==e2n[0]) {
+                //must have all different connections
+                CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",ghostIndex,e2n[0],e2n[1],e2n[2]);
+                CkAssert(false);
+            }
+            if(!(e2n[0]>=0 || e2n[1]>=0 || e2n[2]>=0)) {
+                //must have at least one local node
+                CkPrintf("ERROR: element %d, has connectivity (%d,%d,%d)\n",ghostIndex,e2n[0],e2n[1],e2n[2]);
+                CkAssert(false);
+            }
+            for(int j=0; j<3; j++) {
+                //all nodes must be valid
+                if(e2n[j]>=0) CkAssert(m->node.is_valid(e2n[j]));
+                else CkAssert(m->node.ghost->is_valid(FEM_From_ghost_index(e2n[j])));
+            }
+            int e2e[3];
+            m->e2e_getAll(ghostIndex,e2e,0);
+            if((e2e[0]==e2e[1]) && (e2e[0]==e2e[2]) && (e2e[0]!=-1)) {
+                CkPrintf("ERROR: element %d, has e2e (%d,%d,%d)\n",i,e2e[0],e2e[1],e2e[2]);
+                CkAssert(false);
+            }
+        }
     }
-  }
-  if(n2esize>0) delete [] n2e; n2esize=0;
-  if(n2nsize>0) delete [] n2n; n2nsize=0;
-  for(int i=0; i<noGhostNodes; i++) {
-    int ghostidx = FEM_To_ghost_index(i);
-    if(m->node.ghost->is_valid(i)) {
-      m->n2e_getAll(ghostidx,n2e,n2esize);
-      m->n2n_getAll(ghostidx,n2n,n2nsize);
-      bool done = false;
-      for(int k=0;k<n2nsize;k++) {
-       if(n2n[k]>=0) {
-         done = true;
-         break;
-       }
-      }
-      if(n2esize>n2nsize || !done) {
-       FEM_Print_coords(m,ghostidx);
-       FEM_Print_n2e(m,ghostidx);
-       FEM_Print_n2n(m,ghostidx);
-       CkPrintf("ERROR: ghost node %d, with inconsistent adjacency list\n",ghostidx);
-       CkAssert(false);
-      }
-      if(n2esize > 0) {
-       //reconstruct n2n from n2e & e2n
-       int n2n1size = 0;
-       int *n2n1 = (int*)malloc(n2nsize*sizeof(int));
-       int n2n1Count = 0;
-       for(int j=0; j<n2esize; j++) {
-         CkAssert(n2e[j]!=-1);
-         if(FEM_Is_ghost_index(n2e[j])) {
-           CkAssert(m->elem[0].ghost->is_valid(FEM_From_ghost_index(n2e[j]))==1);
-         }
-         else {
-           CkAssert(m->elem[0].is_valid(n2e[j])==1);
-         }
-         //each of these elems should have me in its e2n
-         int e2n1[3];
-         m->e2n_getAll(n2e[j],e2n1,0);
-         if(e2n1[0]!=ghostidx && e2n1[1]!=ghostidx && e2n1[2]!=ghostidx) {
-           FEM_Print_coords(m,ghostidx);
-           FEM_Print_n2e(m,ghostidx);
-           FEM_Print_e2n(m,n2e[j]);
-           CkPrintf("ERROR: ghost elem %d & ghost node %d have inconsistent adjacency list\n",n2e[j],ghostidx);
-           CkAssert(false);
-         }
-         for(int k=0; k<3;k++) {
-           if(e2n1[k] == ghostidx) continue;
-           bool flag1 = true;
-           for(int l=0; l<n2n1Count; l++) {
-             if(e2n1[k] == n2n1[l]) flag1 = false;
-           }
-           if(flag1 && n2n1Count<n2nsize) { //this is not in the list
-             n2n1[n2n1Count] = e2n1[k];
-             n2n1Count++;
-           }
-         }
-       }
-       //verify if n2n1 has the same nodes as n2n
-       bool flag2 = true;
-       if(n2n1Count!=n2nsize) flag2 = false;
-       for(int j=0; j<n2n1Count; j++) {
-         bool flag1 = false;
-         for(int k=0; k<n2nsize; k++) {
-           if(n2n[k]==n2n1[j]) flag1 = true;
-         }
-         if(!flag1) {
-           flag2 = false;
-           break;
-         }
-       }
-       if(!flag2) {
-         FEM_Print_coords(m,ghostidx);
-         FEM_Print_n2n(m,ghostidx);
-         for(int l=0; l<n2esize; l++) FEM_Print_e2n(m,n2e[l]);
-         CkPrintf("ERROR: ghost node %d has inconsistent adjacency list\n",ghostidx);
-         CkAssert(false);
-       }
-       delete[] n2n1;
-       delete[] n2e;
-      }
-      if(n2nsize > 0) {
-       for(int j=0; j<n2nsize; j++) {
-         CkAssert(n2n[j]!=-1);
-       }
-       delete[] n2n;
-      }
-      //verify that it is coming correctly from all chunks as a ghost
-      const IDXL_Rec *irec = m->node.ghost->ghostRecv.getRec(i);
-      //go to a chunk which owns it & verify that these are the only chunks that own it
-      int remChk = irec->getChk(0);
-      int sharedIdx = irec->getIdx(0);
-      int numsh = irec->getShared();
-      verifyghostsendMsg *vmsg = new(numsh,0)verifyghostsendMsg();
-      vmsg->fromChk = idx;
-      vmsg->sharedIdx = sharedIdx;
-      vmsg->numchks = numsh;
-      for(int k=0; k<numsh; k++) vmsg->chunks[k] = irec->getChk(k);
-      meshMod[remChk].verifyghostsend(vmsg);
+    int *n2e, n2esize=0;
+    int *n2n, n2nsize=0;
+    for(int i=0; i<noNodes; i++) {
+        if(m->node.is_valid(i)) {
+            m->n2e_getAll(i,n2e,n2esize);
+            m->n2n_getAll(i,n2n,n2nsize);
+            if(n2esize>n2nsize) {
+                FEM_Print_coords(m,i);
+                FEM_Print_n2e(m,i);
+                FEM_Print_n2n(m,i);
+                CkPrintf("ERROR: local node %d, with inconsistent adjacency list\n",i);
+                CkAssert(false);
+            }
+        }
+        else {
+            continue;
+        }
+        if(n2esize > 0) {
+            for(int j=0; j<n2esize; j++) {
+                CkAssert(n2e[j]!=-1);
+                if(FEM_Is_ghost_index(n2e[j])) CkAssert(m->elem[0].ghost->is_valid(FEM_From_ghost_index(n2e[j]))==1);
+                else CkAssert(m->elem[0].is_valid(n2e[j])==1);
+            }
+            m->e2n_getAll(n2e[0],e2n,0);
+            //any local/shared node should have at least one local element connected to it
+            bool done = false;
+            for(int j=0; j<n2esize; j++) {
+                if(n2e[j] >= 0) {
+                    done = true; 
+                    break;
+                }
+            }
+            if(!done) {
+                FEM_Print_coords(m,i);
+                FEM_Print_n2e(m,i);
+                FEM_Print_n2n(m,i);
+                CkPrintf("ERROR: isolated local node %d, with no local element connectivity\n",i);
+                CkAssert(false);
+            }
+            //ensure that there is a cloud of connectivity, no disconnected elements, other than boundaries
+            int testnode = i;
+            int startnode = (e2n[0]==testnode) ? e2n[1] : e2n[0];
+            int othernode = (e2n[2]==testnode) ? e2n[1] : e2n[2];
+            int previousnode = startnode;
+            int nextnode = -1;
+            int numdeadends = 0;
+            int numunused = n2esize-1;
+            n2e[0] = -1;
+            for(int j=0; j<n2esize-1; j++) {
+                nextnode = -1;
+                for(int k=1; k<n2esize; k++) {
+                    if(n2e[k]==-1) continue;
+                    m->e2n_getAll(n2e[k],e2n,0);
+                    if(e2n[0]==previousnode || e2n[1]==previousnode || e2n[2]==previousnode) {
+                        nextnode = (e2n[0]==previousnode) ? ((e2n[1]==testnode)? e2n[2]:e2n[1]) : ((e2n[1]==previousnode)? ((e2n[0]==testnode)? e2n[2]:e2n[0]):((e2n[1]==testnode)? e2n[0]:e2n[1]));
+                        previousnode = nextnode;
+                        n2e[k] = -1;
+                        numunused--;
+                    }
+                }
+                if(nextnode==othernode && othernode!=-1) {
+                    //it has reached a full circle
+                    break;
+                }
+                else if(nextnode==-1) {
+                    //this is one edge, start travelling along the other end
+                    numdeadends++;
+                    previousnode = othernode;
+                    othernode = -1;
+                }
+                if(numdeadends>2 && numunused!=0) {
+                    FEM_Print_coords(m,i);
+                    FEM_Print_n2e(m,i);
+                    FEM_Print_n2n(m,i);
+                    CkPrintf("ERROR: cloud connectivity of node %d is discontinuous\n",i);
+                    CkAssert(false);
+                }
+            }
+            if(n2esize>0) delete[] n2e; n2esize=0;
+            //reconstruct n2n from n2e & e2n
+            int n2n1size = 0;
+            int *n2n1 = (int*)malloc(n2nsize*sizeof(int));
+            int n2n1Count = 0;
+            m->n2e_getAll(i,n2e,n2esize);
+            for(int j=0; j<n2esize; j++) {
+                CkAssert(n2e[j]!=-1);
+                //each of these elems should have me in its e2n
+                int e2n1[3];
+                m->e2n_getAll(n2e[j],e2n1,0);
+                if(e2n1[0]!=i && e2n1[1]!=i && e2n1[2]!=i) {
+                    FEM_Print_coords(m,i);
+                    FEM_Print_n2e(m,i);
+                    FEM_Print_e2n(m,n2e[j]);
+                    CkPrintf("ERROR: ghost elem %d & ghost node %d have inconsistent adjacency list\n",n2e[j],i);
+                    CkAssert(false);
+                }
+                for(int k=0; k<3;k++) {
+                    if(e2n1[k] == i) continue;
+                    bool flag1 = true;
+                    for(int l=0; l<n2n1Count; l++) {
+                        if(e2n1[k] == n2n1[l]) flag1 = false;
+                    }
+                    if(flag1 && n2n1Count<n2nsize) { //this is not in the list
+                        n2n1[n2n1Count] = e2n1[k];
+                        n2n1Count++;
+                    }
+                }
+            }
+            //verify if n2n1 has the same nodes as n2n
+            bool flag2 = true;
+            if(n2n1Count!=n2nsize) flag2 = false;
+            for(int j=0; j<n2n1Count; j++) {
+                bool flag1 = false;
+                for(int k=0; k<n2nsize; k++) {
+                    if(n2n[k]==n2n1[j]) flag1 = true;
+                }
+                if(!flag1) {
+                    flag2 = false;
+                    break;
+                }
+            }
+            if(!flag2) {
+                FEM_Print_coords(m,i);
+                FEM_Print_n2n(m,i);
+                for(int l=0; l<n2esize; l++) FEM_Print_e2n(m,n2e[l]);
+                CkPrintf("ERROR: ghost node %d has inconsistent adjacency list\n",i);
+                CkAssert(false);
+            }
+
+            delete [] n2n1;
+            if(n2esize>0) delete [] n2e; n2esize=0;
+            if(n2nsize>0) delete [] n2n; n2nsize=0;
+        }
     }
-    else {
-      continue;
+    if(n2esize>0) delete [] n2e; n2esize=0;
+    if(n2nsize>0) delete [] n2n; n2nsize=0;
+    for(int i=0; i<noGhostNodes; i++) {
+        int ghostidx = FEM_To_ghost_index(i);
+        if(m->node.ghost->is_valid(i)) {
+            m->n2e_getAll(ghostidx,n2e,n2esize);
+            m->n2n_getAll(ghostidx,n2n,n2nsize);
+            bool done = false;
+            for(int k=0;k<n2nsize;k++) {
+                if(n2n[k]>=0) {
+                    done = true;
+                    break;
+                }
+            }
+            if(n2esize>n2nsize || !done) {
+                FEM_Print_coords(m,ghostidx);
+                FEM_Print_n2e(m,ghostidx);
+                FEM_Print_n2n(m,ghostidx);
+                CkPrintf("ERROR: ghost node %d, with inconsistent adjacency list\n",ghostidx);
+                CkAssert(false);
+            }
+            if(n2esize > 0) {
+                //reconstruct n2n from n2e & e2n
+                int n2n1size = 0;
+                int *n2n1 = (int*)malloc(n2nsize*sizeof(int));
+                int n2n1Count = 0;
+                for(int j=0; j<n2esize; j++) {
+                    CkAssert(n2e[j]!=-1);
+                    if(FEM_Is_ghost_index(n2e[j])) {
+                        CkAssert(m->elem[0].ghost->is_valid(FEM_From_ghost_index(n2e[j]))==1);
+                    }
+                    else {
+                        CkAssert(m->elem[0].is_valid(n2e[j])==1);
+                    }
+                    //each of these elems should have me in its e2n
+                    int e2n1[3];
+                    m->e2n_getAll(n2e[j],e2n1,0);
+                    if(e2n1[0]!=ghostidx && e2n1[1]!=ghostidx && e2n1[2]!=ghostidx) {
+                        FEM_Print_coords(m,ghostidx);
+                        FEM_Print_n2e(m,ghostidx);
+                        FEM_Print_e2n(m,n2e[j]);
+                        CkPrintf("ERROR: ghost elem %d & ghost node %d have inconsistent adjacency list\n",n2e[j],ghostidx);
+                        CkAssert(false);
+                    }
+                    for(int k=0; k<3;k++) {
+                        if(e2n1[k] == ghostidx) continue;
+                        bool flag1 = true;
+                        for(int l=0; l<n2n1Count; l++) {
+                            if(e2n1[k] == n2n1[l]) flag1 = false;
+                        }
+                        if(flag1 && n2n1Count<n2nsize) { //this is not in the list
+                            n2n1[n2n1Count] = e2n1[k];
+                            n2n1Count++;
+                        }
+                    }
+                }
+                //verify if n2n1 has the same nodes as n2n
+                bool flag2 = true;
+                if(n2n1Count!=n2nsize) flag2 = false;
+                for(int j=0; j<n2n1Count; j++) {
+                    bool flag1 = false;
+                    for(int k=0; k<n2nsize; k++) {
+                        if(n2n[k]==n2n1[j]) flag1 = true;
+                    }
+                    if(!flag1) {
+                        flag2 = false;
+                        break;
+                    }
+                }
+                if(!flag2) {
+                    FEM_Print_coords(m,ghostidx);
+                    FEM_Print_n2n(m,ghostidx);
+                    for(int l=0; l<n2esize; l++) FEM_Print_e2n(m,n2e[l]);
+                    CkPrintf("ERROR: ghost node %d has inconsistent adjacency list\n",ghostidx);
+                    CkAssert(false);
+                }
+                delete[] n2n1;
+                delete[] n2e;
+            }
+            if(n2nsize > 0) {
+                for(int j=0; j<n2nsize; j++) {
+                    CkAssert(n2n[j]!=-1);
+                }
+                delete[] n2n;
+            }
+            //verify that it is coming correctly from all chunks as a ghost
+            const IDXL_Rec *irec = m->node.ghost->ghostRecv.getRec(i);
+            //go to a chunk which owns it & verify that these are the only chunks that own it
+            int remChk = irec->getChk(0);
+            int sharedIdx = irec->getIdx(0);
+            int numsh = irec->getShared();
+            verifyghostsendMsg *vmsg = new(numsh,0)verifyghostsendMsg();
+            vmsg->fromChk = idx;
+            vmsg->sharedIdx = sharedIdx;
+            vmsg->numchks = numsh;
+            for(int k=0; k<numsh; k++) vmsg->chunks[k] = irec->getChk(k);
+            meshMod[remChk].verifyghostsend(vmsg);
+        }
+        else {
+            continue;
+        }
     }
-  }
-  free(e2n);
-  return;
+    free(e2n);
+    return;
 }
 
 /** The area test verifies that the area of no element is less than the SLIVERAREA
@@ -1792,7 +1794,10 @@ int FEM_MUtil::residualLockTest(FEM_Mesh *m) {
   int noNodes = m->node.size();
   for(int i=0; i<noNodes; i++) {
     if(m->node.is_valid(i)) {
-      CkAssert(!mmod->fmLockN[i].haslocks());
+      if (mmod->fmLockN[i].haslocks()) {
+          CkPrintf("[%d] Node %d has a residual lock\n", FEM_My_partition(), i);
+          CkAssert(false);
+      }
     }
   }
   for(int i=0; i<mmod->numChunks; i++) {
@@ -1800,3 +1805,22 @@ int FEM_MUtil::residualLockTest(FEM_Mesh *m) {
   }
   return 1;
 }
+
+/**
+ * Remove all extant node locks in the mesh. Probably only useful for debugging
+ * and very special cases.
+ */
+void FEM_MUtil::unlockAll(FEM_Mesh *m) {
+  int noNodes = m->node.size();
+  for(int i=0; i<noNodes; i++) {
+    if(m->node.is_valid(i)) {
+      if (mmod->fmLockN[i].haslocks()) {
+          mmod->fmLockN[i].reset(i, mmod);
+      }
+    }
+  }
+  for(int i=0; i<mmod->numChunks; i++) {
+    mmod->fmIdxlLock[i] = false;
+  }
+}
+