SundanceBasicSimplicialMesh.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                              Sundance
00005 //                 Copyright (2005) Sandia Corporation
00006 // 
00007 // Copyright (year first published) Sandia Corporation.  Under the terms 
00008 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 
00009 // retains certain rights in this software.
00010 // 
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //  
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //                                                                                 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA                                                                                
00025 // Questions? Contact Kevin Long (krlong@sandia.gov), 
00026 // Sandia National Laboratories, Livermore, California, USA
00027 // 
00028 // ************************************************************************
00029 /* @HEADER@ */
00030 
00031 #include "SundanceBasicSimplicialMesh.hpp"
00032 #include "SundanceMeshType.hpp"
00033 #include "SundanceCellJacobianBatch.hpp"
00034 #include "SundanceMaximalCofacetBatch.hpp"
00035 #include "SundanceMeshSource.hpp"
00036 #include "SundanceDebug.hpp"
00037 #include "SundanceOut.hpp"
00038 #include "Teuchos_MPIContainerComm.hpp"
00039 #include "Teuchos_Time.hpp"
00040 #include "Teuchos_TimeMonitor.hpp"
00041 #include "SundanceObjectWithVerbosity.hpp"
00042 #include "SundanceCollectiveExceptionCheck.hpp"
00043 
00044 #include <unistd.h>
00045 
00046 using namespace Sundance;
00047 using namespace Sundance;
00048 using namespace Teuchos;
00049 using namespace Sundance;
00050 
00051 using std::endl;
00052 
00053 static Time& batchedFacetGrabTimer() 
00054 {
00055   static RCP<Time> rtn 
00056     = TimeMonitor::getNewTimer("batched facet grabbing"); 
00057   return *rtn;
00058 }
00059 
00060 
00061 
00062 
00063 static Time& getJacobianTimer() 
00064 {
00065   static RCP<Time> rtn 
00066     = TimeMonitor::getNewTimer("cell Jacobian grabbing"); 
00067   return *rtn;
00068 }
00069 
00070 
00071 //#define SKIP_FACES
00072 
00073 BasicSimplicialMesh::BasicSimplicialMesh(int dim, const MPIComm& comm, 
00074   const MeshEntityOrder& order)
00075   : IncrementallyCreatableMesh(dim, comm, order),
00076     numCells_(dim+1),
00077     points_(),
00078     edgeVerts_(2),
00079     faceVertLIDs_(dim),
00080     faceVertGIDs_(dim),
00081     faceEdges_(dim),
00082     faceEdgeSigns_(dim),
00083     elemVerts_(dim+1),
00084     elemEdges_(),
00085     elemEdgeSigns_(),
00086     elemFaces_(dim+1),
00087     elemFaceRotations_(dim+1),
00088     vertexSetToFaceIndexMap_(),
00089     edgeFaces_(),
00090     edgeCofacets_(),
00091     faceCofacets_(),
00092     vertEdges_(),
00093     vertFaces_(),
00094     vertCofacets_(),
00095     vertEdgePartners_(),
00096     LIDToGIDMap_(dim+1),
00097     GIDToLIDMap_(dim+1),
00098     labels_(dim+1),
00099     ownerProcID_(dim+1),
00100     faceVertGIDBase_(1),
00101     hasEdgeGIDs_(false),
00102     hasFaceGIDs_(false),
00103     neighbors_(),
00104     neighborsAreSynchronized_(false)
00105 {
00106   estimateNumVertices(1000);
00107   estimateNumElements(1000);
00108 
00109   /* Set up the pointer giving a view of the face vertex array.
00110    * Resize to 1 so that phony dereference will work, then resize to zero to make the
00111    * new array logically empty */
00112   faceVertGIDs_.resize(1);
00113   faceVertGIDBase_[0] = &(faceVertGIDs_.value(0,0));
00114   faceVertGIDs_.resize(0);
00115 
00116   /* size the element edge lists as appropriate to the mesh's dimension */
00117   if (spatialDim()==2) 
00118   {
00119     elemEdges_.setTupleSize(3);
00120     elemEdgeSigns_.setTupleSize(3);
00121   }
00122   if (spatialDim()==3) 
00123   {
00124     elemEdges_.setTupleSize(6);
00125     elemEdgeSigns_.setTupleSize(6);
00126   }
00127 
00128   neighbors_.put(comm.getRank());
00129 }
00130 
00131 
00132 void BasicSimplicialMesh::getJacobians(int cellDim, const Array<int>& cellLID,
00133   CellJacobianBatch& jBatch) const
00134 {
00135   TimeMonitor timer(getJacobianTimer());
00136 
00137   int flops = 0 ;
00138   int nCells = cellLID.size();
00139 
00140   TEST_FOR_EXCEPTION(cellDim < 0 || cellDim > spatialDim(), InternalError,
00141     "cellDim=" << cellDim 
00142     << " is not in expected range [0, " << spatialDim()
00143     << "]");
00144 
00145   jBatch.resize(cellLID.size(), spatialDim(), cellDim);
00146 
00147   if (cellDim < spatialDim())
00148   {
00149     switch(cellDim)
00150     {
00151       case 1:
00152         flops += 3*nCells;
00153         break;
00154       case 2:
00155         // 4 flops for two pt subtractions, 10 for a cross product
00156         flops += (4 + 10)*nCells;
00157         break;
00158       default:
00159         break;
00160     }
00161 
00162     for (int i=0; i<nCells; i++)
00163     {
00164       int lid = cellLID[i];
00165       double* detJ = jBatch.detJ(i);
00166       switch(cellDim)
00167       {
00168         case 0:
00169           *detJ = 1.0;
00170           break;
00171         case 1:
00172         {
00173           int a = edgeVerts_.value(lid, 0);
00174           int b = edgeVerts_.value(lid, 1);
00175           const Point& pa = points_[a];
00176           const Point& pb = points_[b];
00177           Point dx = pb-pa;
00178           *detJ = sqrt(dx*dx);
00179         }
00180         break;
00181         case 2:
00182         {
00183           int a = faceVertLIDs_.value(lid, 0);
00184           int b = faceVertLIDs_.value(lid, 1);
00185           int c = faceVertLIDs_.value(lid, 2);
00186           const Point& pa = points_[a];
00187           const Point& pb = points_[b];
00188           const Point& pc = points_[c];
00189           Point directedArea = cross(pc-pa, pb-pa);
00190           *detJ = sqrt(directedArea*directedArea);
00191         }
00192         break;
00193         default:
00194           TEST_FOR_EXCEPTION(true, InternalError, "impossible switch value "
00195             "cellDim=" << cellDim 
00196             << " in BasicSimplicialMesh::getJacobians()");
00197       }
00198     }
00199   }
00200   else
00201   {
00202     Array<double> J(cellDim*cellDim);
00203   
00204     flops += cellDim*cellDim*nCells;
00205 
00206     for (int i=0; i<cellLID.size(); i++)
00207     {
00208       int lid = cellLID[i];
00209       double* J = jBatch.jVals(i);
00210       switch(cellDim)
00211       {
00212         case 0:
00213           J[0] = 1.0;
00214           break;
00215         case 1:
00216         {
00217           int a = elemVerts_.value(lid, 0);
00218           int b = elemVerts_.value(lid, 1);
00219           const Point& pa = points_[a];
00220           const Point& pb = points_[b];
00221           J[0] = fabs(pa[0]-pb[0]);
00222         }
00223         break;
00224         case 2:
00225         {
00226           int a = elemVerts_.value(lid, 0);
00227           int b = elemVerts_.value(lid, 1);
00228           int c = elemVerts_.value(lid, 2);
00229           const Point& pa = points_[a];
00230           const Point& pb = points_[b];
00231           const Point& pc = points_[c];
00232           J[0] = pb[0] - pa[0];
00233           J[1] = pc[0] - pa[0];
00234           J[2] = pb[1] - pa[1];
00235           J[3] = pc[1] - pa[1];
00236             
00237         }
00238         break;
00239         case 3:
00240         {
00241           int a = elemVerts_.value(lid, 0);
00242           int b = elemVerts_.value(lid, 1);
00243           int c = elemVerts_.value(lid, 2);
00244           int d = elemVerts_.value(lid, 3);
00245           const Point& pa = points_[a];
00246           const Point& pb = points_[b];
00247           const Point& pc = points_[c];
00248           const Point& pd = points_[d];
00249           J[0] = pb[0] - pa[0];
00250           J[1] = pc[0] - pa[0];
00251           J[2] = pd[0] - pa[0];
00252           J[3] = pb[1] - pa[1];
00253           J[4] = pc[1] - pa[1];
00254           J[5] = pd[1] - pa[1];
00255           J[6] = pb[2] - pa[2];
00256           J[7] = pc[2] - pa[2];
00257           J[8] = pd[2] - pa[2];
00258         }
00259         break;
00260         default:
00261           TEST_FOR_EXCEPTION(true, InternalError, "impossible switch value "
00262             "cellDim=" << cellDim 
00263             << " in BasicSimplicialMesh::getJacobians()");
00264       }
00265     }
00266   }
00267   CellJacobianBatch::addFlops(flops);
00268 }
00269 
00270 
00271 
00272 void BasicSimplicialMesh::getCellDiameters(int cellDim, const Array<int>& cellLID,
00273   Array<double>& cellDiameters) const
00274 {
00275   TEST_FOR_EXCEPTION(cellDim < 0 || cellDim > spatialDim(), InternalError,
00276     "cellDim=" << cellDim 
00277     << " is not in expected range [0, " << spatialDim()
00278     << "]");
00279 
00280   cellDiameters.resize(cellLID.size());
00281 
00282   if (cellDim < spatialDim())
00283   {
00284     for (int i=0; i<cellLID.size(); i++)
00285     {
00286       int lid = cellLID[i];
00287       switch(cellDim)
00288       {
00289         case 0:
00290           cellDiameters[i] = 1.0;
00291           break;
00292         case 1:
00293         {
00294           int a = edgeVerts_.value(lid, 0);
00295           int b = edgeVerts_.value(lid, 1);
00296           const Point& pa = points_[a];
00297           const Point& pb = points_[b];
00298           Point dx = pb-pa;
00299           cellDiameters[i] = sqrt(dx*dx);
00300         }
00301         break;
00302         case 2:
00303         {
00304           int a = faceVertLIDs_.value(lid, 0);
00305           int b = faceVertLIDs_.value(lid, 1);
00306           int c = faceVertLIDs_.value(lid, 2);
00307           const Point& pa = points_[a];
00308           const Point& pb = points_[b];
00309           const Point& pc = points_[c];
00310           Point directedArea = cross(pc-pa, pb-pa);
00311           cellDiameters[i] = sqrt(directedArea*directedArea);
00312         }
00313         break;
00314         default:
00315           TEST_FOR_EXCEPTION(true, InternalError, "impossible switch value "
00316             "cellDim=" << cellDim 
00317             << " in BasicSimplicialMesh::getCellDiameters()");
00318       }
00319     }
00320   }
00321   else
00322   {
00323     for (int i=0; i<cellLID.size(); i++)
00324     {
00325       int lid = cellLID[i];
00326       switch(cellDim)
00327       {
00328         case 0:
00329           cellDiameters[i] = 1.0;
00330           break;
00331         case 1:
00332         {
00333           int a = elemVerts_.value(lid, 0);
00334           int b = elemVerts_.value(lid, 1);
00335           const Point& pa = points_[a];
00336           const Point& pb = points_[b];
00337           cellDiameters[i] = fabs(pa[0]-pb[0]);
00338         }
00339         break;
00340         case 2:
00341         {
00342           int a = elemVerts_.value(lid, 0);
00343           int b = elemVerts_.value(lid, 1);
00344           int c = elemVerts_.value(lid, 2);
00345           const Point& pa = points_[a];
00346           const Point& pb = points_[b];
00347           const Point& pc = points_[c];
00348           cellDiameters[i] 
00349             = (pa.distance(pb) + pb.distance(pc) + pa.distance(pc))/3.0;
00350         }
00351         break;
00352         case 3:
00353         {
00354           int a = elemVerts_.value(lid, 0);
00355           int b = elemVerts_.value(lid, 1);
00356           int c = elemVerts_.value(lid, 2);
00357           int d = elemVerts_.value(lid, 3);
00358           const Point& pa = points_[a];
00359           const Point& pb = points_[b];
00360           const Point& pc = points_[c];
00361           const Point& pd = points_[d];
00362                 
00363           cellDiameters[i] 
00364             = (pa.distance(pb) + pa.distance(pc) + pa.distance(pd)
00365               + pb.distance(pc) + pb.distance(pd)
00366               + pc.distance(pd))/6.0;
00367         }
00368         break;
00369         default:
00370           TEST_FOR_EXCEPTION(true, InternalError, "impossible switch value "
00371             "cellDim=" << cellDim 
00372             << " in BasicSimplicialMesh::getCellDiameters()");
00373       }
00374     }
00375   }
00376 }
00377 
00378 
00379 void BasicSimplicialMesh::pushForward(int cellDim, const Array<int>& cellLID,
00380   const Array<Point>& refQuadPts,
00381   Array<Point>& physQuadPts) const
00382 {
00383   TEST_FOR_EXCEPTION(cellDim < 0 || cellDim > spatialDim(), InternalError,
00384     "cellDim=" << cellDim 
00385     << " is not in expected range [0, " << spatialDim()
00386     << "]");
00387   int flops = 0;
00388   int nQuad = refQuadPts.size();
00389   int nCells = cellLID.size();
00390   Array<double> J(cellDim*cellDim);
00391 
00392   if (physQuadPts.size() > 0) physQuadPts.resize(0);
00393   physQuadPts.reserve(cellLID.size() * refQuadPts.size());
00394 
00395   switch(cellDim)
00396   {
00397     case 1:
00398       flops += nCells * (1 + 2*nQuad);
00399       break;
00400     case 2:
00401       if (spatialDim()==2)
00402       {
00403         flops += nCells*(4 + 8*nQuad);
00404       }
00405       else
00406       {
00407         flops += 18*nCells*nQuad;
00408       }
00409       break;
00410     case 3:
00411       flops += 27*nCells*nQuad;
00412       break;
00413     default:
00414       break;
00415   }
00416 
00417 
00418   for (int i=0; i<cellLID.size(); i++)
00419   {
00420     int lid = cellLID[i];
00421     switch(cellDim)
00422     {
00423       case 0:
00424         physQuadPts.append(points_[lid]);
00425         break;
00426       case 1:
00427       {
00428         int a, b;
00429         if (spatialDim()==1)
00430         {
00431           a = elemVerts_.value(lid, 0);
00432           b = elemVerts_.value(lid, 1);
00433         }
00434         else
00435         {
00436           a = edgeVerts_.value(lid, 0);
00437           b = edgeVerts_.value(lid, 1);
00438         }
00439         const Point& pa = points_[a];
00440         const Point& pb = points_[b];
00441         Point dx = pb-pa;
00442         for (int q=0; q<nQuad; q++)
00443         {
00444           physQuadPts.append(pa + refQuadPts[q][0]*dx);
00445         }
00446       }
00447       break;
00448       case 2:
00449       {
00450         int a,b,c;
00451         if (spatialDim()==2)
00452         {
00453           a = elemVerts_.value(lid, 0);
00454           b = elemVerts_.value(lid, 1);
00455           c = elemVerts_.value(lid, 2);
00456         }
00457         else
00458         {
00459           a = faceVertLIDs_.value(lid, 0);
00460           b = faceVertLIDs_.value(lid, 1);
00461           c = faceVertLIDs_.value(lid, 2);
00462         }
00463         const Point& pa = points_[a];
00464         const Point& pb = points_[b];
00465         const Point& pc = points_[c];
00466 
00467         if (spatialDim()==2)
00468         {
00469           J[0] = pb[0] - pa[0];
00470           J[1] = pc[0] - pa[0];
00471           J[2] = pb[1] - pa[1];
00472           J[3] = pc[1] - pa[1];
00473           for (int q=0; q<nQuad; q++)
00474           {
00475             physQuadPts.append(pa 
00476               + Point(J[0]*refQuadPts[q][0] +J[1]*refQuadPts[q][1],
00477                 J[2]*refQuadPts[q][0] +J[3]*refQuadPts[q][1]) );
00478           }
00479         }
00480         else
00481         {
00482           for (int q=0; q<nQuad; q++)
00483           {
00484             physQuadPts.append(pa 
00485               + (pb-pa)*refQuadPts[q][0] 
00486               + (pc-pa)*refQuadPts[q][1]);
00487           }
00488         }
00489             
00490       }
00491       break;
00492       case 3:
00493       {
00494         int a = elemVerts_.value(lid, 0);
00495         int b = elemVerts_.value(lid, 1);
00496         int c = elemVerts_.value(lid, 2);
00497         int d = elemVerts_.value(lid, 3);
00498         const Point& pa = points_[a];
00499         const Point& pb = points_[b];
00500         const Point& pc = points_[c];
00501         const Point& pd = points_[d];
00502         J[0] = pb[0] - pa[0];
00503         J[1] = pc[0] - pa[0];
00504         J[2] = pd[0] - pa[0];
00505         J[3] = pb[1] - pa[1];
00506         J[4] = pc[1] - pa[1];
00507         J[5] = pd[1] - pa[1];
00508         J[6] = pb[2] - pa[2];
00509         J[7] = pc[2] - pa[2];
00510         J[8] = pd[2] - pa[2];
00511             
00512         for (int q=0; q<nQuad; q++)
00513         {
00514           physQuadPts.append(pa 
00515             + Point(J[0]*refQuadPts[q][0] 
00516               + J[1]*refQuadPts[q][1]
00517               + J[2]*refQuadPts[q][2],
00518               J[3]*refQuadPts[q][0] 
00519               + J[4]*refQuadPts[q][1]
00520               + J[5]*refQuadPts[q][2],
00521               J[6]*refQuadPts[q][0] 
00522               + J[7]*refQuadPts[q][1]
00523               + J[8]*refQuadPts[q][2]));
00524 
00525         }
00526             
00527       }
00528       break;
00529       default:
00530         TEST_FOR_EXCEPTION(true, InternalError, "impossible switch value "
00531           "in BasicSimplicialMesh::getJacobians()");
00532     }
00533   }
00534 
00535   CellJacobianBatch::addFlops(flops);
00536 }
00537 
00538 void BasicSimplicialMesh::estimateNumVertices(int nPts)
00539 {
00540   points_.reserve(nPts);
00541   vertCofacets_.reserve(nPts);
00542   vertEdges_.reserve(nPts);
00543   vertEdgePartners_.reserve(nPts);
00544 
00545   ownerProcID_[0].reserve(nPts);
00546   LIDToGIDMap_[0].reserve(nPts);
00547   GIDToLIDMap_[0] = Hashtable<int,int>(nPts, 0.6);
00548   labels_[0].reserve(nPts);
00549 }
00550 
00551 void BasicSimplicialMesh::estimateNumElements(int nElems)
00552 {
00553   int nEdges = 0;
00554   int nFaces = 0;
00555 
00556   if (spatialDim()==3) 
00557   {
00558     nFaces = 5*nElems;
00559     nEdges = 5*nElems;
00560     labels_[2].reserve(nFaces);
00561   }
00562   else if (spatialDim()==2)
00563   {
00564     nEdges = 3*nElems;
00565   }
00566   
00567   labels_[1].reserve(nEdges);
00568   vertexSetToFaceIndexMap_ = Hashtable<VertexView, int>(nFaces);
00569 
00570   edgeVerts_.reserve(nEdges);
00571   faceVertLIDs_.reserve(nFaces);
00572   faceVertGIDs_.reserve(nFaces);
00573   faceEdges_.reserve(nFaces);
00574   elemVerts_.reserve(nElems);
00575   elemEdges_.reserve(nElems);
00576   elemEdgeSigns_.reserve(nElems);
00577   elemFaces_.reserve(nElems);
00578   edgeCofacets_.reserve(nEdges);
00579   faceCofacets_.reserve(nFaces);
00580 
00581   ownerProcID_[spatialDim()].reserve(nElems);
00582   LIDToGIDMap_[spatialDim()].reserve(nElems);
00583   GIDToLIDMap_[spatialDim()] = Hashtable<int,int>(nElems, 0.6);
00584   labels_[spatialDim()].reserve(nElems);
00585 
00586   /* resize to 1 so that phony dereference will work, then resize to zero to make the
00587    * new array logically empty */
00588   faceVertGIDs_.resize(1);
00589   faceVertGIDBase_[0] = &(faceVertGIDs_.value(0,0));
00590   faceVertGIDs_.resize(0);
00591 }
00592 
00593 
00594 
00595 int BasicSimplicialMesh::numCells(int cellDim) const
00596 {
00597   return numCells_[cellDim];
00598 }
00599 
00600 int BasicSimplicialMesh::ownerProcID(int cellDim, int cellLID) const
00601 {
00602   return ownerProcID_[cellDim][cellLID];
00603 }
00604 
00605 int BasicSimplicialMesh::numFacets(int cellDim, int cellLID, 
00606   int facetDim) const
00607 {
00608   if (cellDim==1)
00609   {
00610     return 2;
00611   }
00612   else if (cellDim==2)
00613   {
00614     return 3;
00615   }
00616   else 
00617   {
00618     if (facetDim==0) return 4;
00619     if (facetDim==1) return 6;
00620     return 4;
00621   }
00622 }
00623 
00624 void BasicSimplicialMesh::getFacetLIDs(int cellDim, 
00625   const Array<int>& cellLID,
00626   int facetDim,
00627   Array<int>& facetLID,
00628   Array<int>& facetSign) const 
00629 {
00630   TimeMonitor timer(batchedFacetGrabTimer());
00631 
00632   int nf = numFacets(cellDim, cellLID[0], facetDim);
00633   facetLID.resize(cellLID.size() * nf);
00634   if (facetDim > 0) facetSign.resize(cellLID.size() * nf);
00635 
00636   
00637   if (facetDim==0)
00638   {
00639     if (cellDim == spatialDim())
00640     {
00641       int ptr=0;
00642       for (int c=0; c<cellLID.size(); c++)
00643       {
00644         const int* fPtr = &(elemVerts_.value(cellLID[c], 0));
00645         for (int f=0; f<nf; f++, ptr++)
00646         {
00647           facetLID[ptr] = fPtr[f];
00648         }
00649       }
00650     }
00651     else if (cellDim==1) 
00652     {
00653       int ptr=0;
00654       for (int c=0; c<cellLID.size(); c++)
00655       {
00656         const int* fPtr = &(edgeVerts_.value(cellLID[c], 0));
00657         for (int f=0; f<nf; f++, ptr++)
00658         {
00659           facetLID[ptr] = fPtr[f];
00660         }
00661       }
00662     }
00663     else if (cellDim==2) 
00664     {
00665       int ptr=0;
00666       for (int c=0; c<cellLID.size(); c++)
00667       {
00668         const int* fPtr = &(faceVertLIDs_.value(cellLID[c], 0));
00669         for (int f=0; f<nf; f++, ptr++)
00670         {
00671           facetLID[ptr] = fPtr[f];
00672         }
00673       }
00674     }
00675   }
00676   else if (facetDim==1)
00677   {
00678     int ptr=0;
00679     if (cellDim == spatialDim())
00680     {
00681       for (int c=0; c<cellLID.size(); c++)
00682       {
00683         const int* fPtr = &(elemEdges_.value(cellLID[c], 0));
00684         const int* fsPtr = &(elemEdgeSigns_.value(cellLID[c], 0));
00685         for (int f=0; f<nf; f++, ptr++)
00686         {
00687           facetLID[ptr] = fPtr[f];
00688           facetSign[ptr] = fsPtr[f];
00689         }
00690       }
00691     }
00692     else
00693     {
00694       for (int c=0; c<cellLID.size(); c++)
00695       {
00696         const int* fPtr = &(faceEdges_.value(cellLID[c], 0));
00697         //    const int* fsPtr = &(faceEdgeSigns_.value(cellLID[c], 0));
00698         for (int f=0; f<nf; f++, ptr++)
00699         {
00700           facetLID[ptr] = fPtr[f];
00701           //  facetSign[ptr] = fsPtr[f];
00702         }
00703       }
00704     }
00705   }
00706   else
00707   {
00708     int ptr=0;
00709     for (int c=0; c<cellLID.size(); c++)
00710     {
00711       const int* fPtr = &(elemFaces_.value(cellLID[c], 0));
00712       const int* fsPtr = &(elemFaceRotations_.value(cellLID[c], 0));
00713       for (int f=0; f<nf; f++, ptr++)
00714       {
00715         facetLID[ptr] = fPtr[f];
00716         facetSign[ptr] = fsPtr[f];
00717       }
00718     }
00719   }
00720 }
00721 
00722 int BasicSimplicialMesh::facetLID(int cellDim, int cellLID,
00723   int facetDim, int facetIndex, int& facetSign) const 
00724 {
00725 
00726   if (facetDim==0)
00727   {
00728     if (cellDim == spatialDim())
00729     {
00730       return elemVerts_.value(cellLID, facetIndex);
00731     }
00732     else if (cellDim==1) return edgeVerts_.value(cellLID, facetIndex);
00733     else if (cellDim==2) return faceVertLIDs_.value(cellLID, facetIndex);
00734   }
00735   if (facetDim==1)
00736   {
00737     if (cellDim==spatialDim())
00738     {
00739       facetSign = elemEdgeSigns_.value(cellLID, facetIndex);
00740       return elemEdges_.value(cellLID, facetIndex);
00741     }
00742     else
00743     {
00744       //facetSign = faceEdgeSigns_.value(cellLID, facetIndex);
00745       return faceEdges_.value(cellLID, facetIndex);
00746     }
00747   }
00748   else
00749   {
00750     facetSign = elemFaceRotations_.value(cellLID, facetIndex);
00751     return elemFaces_.value(cellLID, facetIndex);
00752   }
00753 }
00754 
00755 
00756 int BasicSimplicialMesh::numMaxCofacets(int cellDim, int cellLID) const 
00757 {
00758 
00759   if (cellDim==0)
00760   {
00761     return vertCofacets_[cellLID].length();
00762   }
00763   if (cellDim==1)
00764   {
00765     return edgeCofacets_[cellLID].length();
00766   }
00767   if (cellDim==2)
00768   {
00769     return faceCofacets_[cellLID].length();
00770   }
00771   return -1; // -Wall
00772 }
00773 
00774 
00775 
00776 int BasicSimplicialMesh::maxCofacetLID(int cellDim, int cellLID,
00777   int cofacetIndex,
00778   int& facetIndex) const
00779 {
00780   int rtn = -1;
00781   if (cellDim==0)
00782   {
00783     rtn = vertCofacets_[cellLID][cofacetIndex];
00784   }
00785   else if (cellDim==1)
00786   {
00787     rtn = edgeCofacets_[cellLID][cofacetIndex];
00788   }
00789   else if (cellDim==2)
00790   {
00791     rtn = faceCofacets_[cellLID][cofacetIndex];
00792   }
00793   else
00794   {
00795     TEST_FOR_EXCEPTION(true, RuntimeError, "invalid cell dimension " << cellDim
00796       << " in request for cofacet");
00797   }
00798 
00799   int dummy;
00800   for (int f=0; f<numFacets(spatialDim(), rtn, cellDim); f++)
00801   {
00802     if (cellLID==facetLID(spatialDim(), rtn, cellDim, f, dummy)) 
00803     {
00804       facetIndex = f;
00805       return rtn;
00806     }
00807   }
00808   TEST_FOR_EXCEPTION(true, RuntimeError, "reverse pointer to facet not found"
00809     " in request for cofacet");
00810   return -1; // -Wall
00811 }
00812 
00813 
00814 void BasicSimplicialMesh::getMaxCofacetLIDs(
00815   const Array<int>& cellLIDs,
00816   MaximalCofacetBatch& cofacets) const
00817 {
00818   TEST_FOR_EXCEPT(cellLIDs.size()==0);
00819   int d = spatialDim() - 1;
00820   int nc = numMaxCofacets(d, cellLIDs[0]);  
00821 
00822   cofacets.reset(cellLIDs.size(), nc);
00823 
00824   for (int i=0; i<cellLIDs.size(); i++) 
00825   {
00826     int f1;
00827     int cofacet1 = maxCofacetLID(d, cellLIDs[i], 0, f1);
00828     if (nc==1) cofacets.addSingleCofacet(i, cofacet1, f1);
00829     else
00830     {
00831       int f2;
00832       int cofacet2 = maxCofacetLID(d, cellLIDs[i], 1, f2);
00833       cofacets.addTwoCofacets(i, cofacet1, f1, cofacet2, f2);
00834     }
00835   }
00836 }
00837 
00838 void BasicSimplicialMesh::getCofacets(int cellDim, int cellLID,
00839   int cofacetDim, Array<int>& cofacetLIDs) const 
00840 {
00841   //  TimeMonitor timer(cofacetGrabTimer());
00842   TEST_FOR_EXCEPTION(cofacetDim > spatialDim() || cofacetDim < 0, RuntimeError,
00843     "invalid cofacet dimension=" << cofacetDim);
00844   TEST_FOR_EXCEPTION( cofacetDim <= cellDim, RuntimeError,
00845     "invalid cofacet dimension=" << cofacetDim
00846     << " for cell dim=" << cellDim);
00847   if (cofacetDim==spatialDim())
00848   {
00849     cofacetLIDs.resize(numMaxCofacets(cellDim, cellLID));
00850     int dum=0;
00851     for (int f=0; f<cofacetLIDs.size(); f++)
00852     {
00853       cofacetLIDs[f] = maxCofacetLID(cellDim, cellLID, f, dum);
00854     }
00855   }
00856   else
00857   {
00858     if (cellDim==0)
00859     {
00860       if (cofacetDim==1) cofacetLIDs = vertEdges_[cellLID];
00861       else if (cofacetDim==2) cofacetLIDs = vertFaces_[cellLID];
00862       else TEST_FOR_EXCEPT(true);
00863     }
00864     else if (cellDim==1)
00865     { 
00866       if (cofacetDim==2) cofacetLIDs = edgeFaces_[cellLID];
00867       else TEST_FOR_EXCEPT(true);
00868     }
00869     else if (cellDim==2)
00870     {
00871       /* this should never happen, because the only possibility is a maximal cofacet,
00872        * which would have been handled above */
00873       TEST_FOR_EXCEPT(true);
00874     }
00875     else
00876     {
00877       TEST_FOR_EXCEPT(true);
00878     }
00879   }
00880 }
00881 
00882 int BasicSimplicialMesh::mapGIDToLID(int cellDim, int globalIndex) const
00883 {
00884   return GIDToLIDMap_[cellDim].get(globalIndex);
00885 }
00886 
00887 bool BasicSimplicialMesh::hasGID(int cellDim, int globalIndex) const
00888 {
00889   return GIDToLIDMap_[cellDim].containsKey(globalIndex);
00890 }
00891 
00892 int BasicSimplicialMesh::mapLIDToGID(int cellDim, int localIndex) const
00893 {
00894   return LIDToGIDMap_[cellDim][localIndex];
00895 }
00896 
00897 CellType BasicSimplicialMesh::cellType(int cellDim) const
00898 {
00899 
00900   switch(cellDim)
00901   {
00902     case 0:
00903       return PointCell;
00904     case 1:
00905       return LineCell;
00906     case 2:
00907       return TriangleCell;
00908     case 3:
00909       return TetCell;
00910     default:
00911       return NullCell; // -Wall
00912   }
00913 }
00914 
00915 int BasicSimplicialMesh::label(int cellDim, 
00916   int cellLID) const
00917 {
00918   return labels_[cellDim][cellLID];
00919 }
00920 
00921 void BasicSimplicialMesh::getLabels(int cellDim, const Array<int>& cellLID, 
00922   Array<int>& labels) const
00923 {
00924   labels.resize(cellLID.size());
00925   const Array<int>& ld = labels_[cellDim];
00926   for (int i=0; i<cellLID.size(); i++)
00927   {
00928     labels[i] = ld[cellLID[i]];
00929   }
00930 }
00931 
00932 
00933 Set<int> BasicSimplicialMesh::getAllLabelsForDimension(int cellDim) const
00934 {
00935   Set<int> rtn;
00936 
00937   const Array<int>& ld = labels_[cellDim];
00938   for (int i=0; i<ld.size(); i++)
00939   {
00940     rtn.put(ld[i]);
00941   }
00942   
00943   return rtn;
00944 }
00945 
00946 void BasicSimplicialMesh::getLIDsForLabel(int cellDim, int label, Array<int>& cellLIDs) const
00947 {
00948   cellLIDs.resize(0);
00949   const Array<int>& ld = labels_[cellDim];
00950   for (int i=0; i<ld.size(); i++)
00951   {
00952     if (ld[i] == label) cellLIDs.append(i);
00953   }
00954 }
00955 
00956 
00957 
00958 
00959 int BasicSimplicialMesh::addVertex(int globalIndex, const Point& x,
00960   int ownerProcID, int label)
00961 {
00962 
00963   int lid = points_.length();
00964   points_.append(x);
00965 
00966   SUNDANCE_OUT(this->verb() > 1,
00967     "BSM added point " << x << " lid = " << lid);
00968 
00969   numCells_[0]++;
00970 
00971   LIDToGIDMap_[0].append(globalIndex);
00972   GIDToLIDMap_[0].put(globalIndex, lid);
00973 
00974   if (comm().getRank() != ownerProcID) neighbors_.put(ownerProcID);
00975   ownerProcID_[0].append(ownerProcID);
00976   labels_[0].append(label);
00977 
00978   vertCofacets_.resize(points_.length());
00979   vertEdges_.resize(points_.length());
00980   if (spatialDim() > 2) vertFaces_.resize(points_.length());
00981   vertEdgePartners_.resize(points_.length());
00982   
00983   return lid;
00984 }
00985 
00986 int BasicSimplicialMesh::addElement(int globalIndex, 
00987   const Array<int>& vertGID,
00988   int ownerProcID, int label)
00989 {
00990   SUNDANCE_VERB_HIGH("p=" << comm().getRank() << "adding element " << globalIndex 
00991     << " with vertices:" << vertGID);
00992 
00993   /* 
00994    * do basic administrative steps for the new element: 
00995    * set LID, label, and procID; update element count. 
00996    */
00997   int lid = elemVerts_.length();
00998   elemEdgeSigns_.resize(lid+1);
00999 
01000   numCells_[spatialDim()]++;
01001 
01002   LIDToGIDMap_[spatialDim()].append(globalIndex);
01003   GIDToLIDMap_[spatialDim()].put(globalIndex, lid);
01004   labels_[spatialDim()].append(label);
01005   ownerProcID_[spatialDim()].append(ownerProcID);
01006   if (comm().getRank() != ownerProcID) neighbors_.put(ownerProcID);
01007 
01008   /* these little arrays will get used repeatedly, so make them static
01009    * to save a few cycles. */
01010   static Array<int> edges;
01011   static Array<int> faces;
01012   static Array<int> faceRotations;
01013   static Array<int> vertLID;
01014 
01015   /* find the vertex LIDs given the input GIDs */
01016   vertLID.resize(vertGID.size());
01017   for (int i=0; i<vertGID.size(); i++) 
01018   {
01019     vertLID[i] = GIDToLIDMap_[0].get(vertGID[i]);
01020   }
01021   
01022   /* 
01023    * Now comes the fun part: creating edges and faces for the 
01024    * new element, and registering it as a cofacet of its
01025    * lower-dimensional facets. 
01026    */
01027   
01028 
01029   if (spatialDim()==1)  
01030   {
01031     /* In 1D, there are neither edges nor faces. */
01032     edges.resize(0);
01033     faces.resize(0);
01034     /* register the new element as a cofacet of its vertices. */
01035     vertCofacets_[vertLID[0]].append(lid);
01036     vertCofacets_[vertLID[1]].append(lid);
01037   }
01038   if (spatialDim()==2)
01039   {
01040     /* In 2D, we need to define edges but not faces for the new element. */
01041     edges.resize(3);
01042     faces.resize(0);
01043 
01044     /* add the edges and define the relative orientations of the edges */
01045     edges[0] = addEdge(vertLID[0], vertLID[1], lid, globalIndex, 0);
01046     edges[1] = addEdge(vertLID[1], vertLID[2], lid, globalIndex, 1);
01047     edges[2] = addEdge(vertLID[2], vertLID[0], lid, globalIndex, 2);
01048 
01049     /* register the new element as a cofacet of its vertices. */
01050     vertCofacets_[vertLID[0]].append(lid);
01051     vertCofacets_[vertLID[1]].append(lid);
01052     vertCofacets_[vertLID[2]].append(lid);
01053 
01054   }
01055   else if (spatialDim()==3)
01056   {
01057     /* In 3D, we need to define edges and faces for the new element. */
01058     edges.resize(6);
01059     faces.resize(4);
01060     faceRotations.resize(4);
01061 
01062     /* add the edges and define the relative orientations of the edges */
01063     edges[0] = addEdge(vertLID[0], vertLID[1], lid, globalIndex,  0);
01064     edges[1] = addEdge(vertLID[1], vertLID[2], lid, globalIndex,  1);
01065     edges[2] = addEdge(vertLID[2], vertLID[0], lid, globalIndex,  2);
01066     edges[3] = addEdge(vertLID[0], vertLID[3], lid, globalIndex,  3);
01067     edges[4] = addEdge(vertLID[1], vertLID[3], lid, globalIndex,  4);
01068     edges[5] = addEdge(vertLID[2], vertLID[3], lid, globalIndex,  5);
01069 
01070     /* register the new element as a cofacet of its vertices. */
01071     vertCofacets_[vertLID[0]].append(lid);
01072     vertCofacets_[vertLID[1]].append(lid);
01073     vertCofacets_[vertLID[2]].append(lid);
01074     vertCofacets_[vertLID[3]].append(lid);
01075 
01076     /* add the faces and define the relative orientations of the faces */
01077     faces[0] = addFace(vertLID[0], vertLID[1], vertLID[3], 
01078       edges[0], edges[4], edges[3], lid, globalIndex, 
01079       faceRotations[0]);
01080 
01081 
01082     faces[1] = addFace(vertLID[1], vertLID[2], vertLID[3], 
01083       edges[1], edges[5], edges[4], lid, globalIndex, 
01084       faceRotations[1]);
01085 
01086     faces[2] = addFace(vertLID[0], vertLID[3], vertLID[2], 
01087       edges[3], edges[5], edges[2], lid, globalIndex, 
01088       faceRotations[2]);
01089 
01090     faces[3] = addFace(vertLID[2], vertLID[1], vertLID[0], 
01091       edges[1], edges[0], edges[2], lid, globalIndex, 
01092       faceRotations[3]);
01093   }
01094 
01095   elemVerts_.append(vertLID);
01096   if (edges.length() > 0) elemEdges_.append(edges);
01097 
01098   if (faces.length() > 0) 
01099   {
01100     elemFaces_.append(faces);
01101     elemFaceRotations_.append(faceRotations);
01102   }
01103   for (int i=0; i<edges.length(); i++) edgeCofacets_[edges[i]].append(lid);
01104 
01105 
01106   for (int i=0; i<faces.length(); i++) faceCofacets_[faces[i]].append(lid);
01107 
01108   return lid;
01109 }
01110 
01111 int BasicSimplicialMesh::addFace(int v1, int v2, int v3, 
01112   int e1, int e2, int e3,
01113   int elemLID,
01114   int elemGID,
01115   int& rotation)
01116 {
01117   /* create static data for workspace arrays and pointers that will be
01118    * used repeatedly */
01119   static Array<int> sortedVertGIDs(3);
01120   static Array<int> reorderedVertLIDs(3);
01121   static Array<int> reorderedEdgeLIDs(3);
01122   //  static Array<int> edgeSigns(3);
01123   static int* sortedGIDs = &(sortedVertGIDs[0]);
01124   static int* reorderedLIDs = &(reorderedVertLIDs[0]);
01125   static int* reorderedEdges = &(reorderedEdgeLIDs[0]);
01126 
01127   //static int* edgeSigns = &(edgeSigns[0]);
01128 
01129   /* First we check whether the face already exists, and
01130    * along the way determine the orientation of the new element's 
01131    * face relative to the absolute orientation of the face. */
01132   int lid = checkForExistingFace(v1, v2, v3, e1, e2, e3,
01133     sortedGIDs, reorderedLIDs, reorderedEdges,
01134     rotation);
01135 
01136   if (lid >= 0) /* if the face already exists, we're done */
01137   {
01138     return lid;
01139   }
01140   else /* we need to register the face */
01141   {
01142     /* get a LID for the new face */
01143     lid = faceVertLIDs_.length();
01144       
01145     /* record the new face's vertex sets (both GID and LID, ordered by GID)
01146      * and its edges (reordered to the the sorted-GID orientation) */
01147     faceVertGIDs_.append(sortedGIDs, 3);
01148     faceVertLIDs_.append(reorderedLIDs, 3);
01149     faceEdges_.append(reorderedEdges, 3);
01150 
01151     SUNDANCE_VERB_EXTREME("p=" << comm().getRank() << " adding face "
01152       << cellStr(3, sortedGIDs));
01153 
01154 
01155     /* If we own all vertices, we own the face. 
01156      * Otherwise, mark it for later assignment of ownership */
01157     int vert1Owner = ownerProcID_[0][v1];
01158     int vert2Owner = ownerProcID_[0][v2];
01159     int vert3Owner = ownerProcID_[0][v3];
01160     int myRank = comm().getRank();
01161     if (vert1Owner==myRank && vert2Owner==myRank && vert3Owner==myRank) 
01162     {
01163       ownerProcID_[2].append(myRank);
01164     }
01165     else ownerProcID_[2].append(-1);
01166 
01167     /* the face doesn't yet have a label, so set it to zero */
01168     labels_[2].append(0);
01169       
01170     /* update the view pointer to stay in synch with the resized
01171      * face vertex GID array */
01172     faceVertGIDBase_[0] = &(faceVertGIDs_.value(0,0));
01173       
01174     /* create a vertex set view that points to the new face's 
01175      * vertex GIDs. The first argument gives a pointer to the base of the
01176      * vertex GID array. The view is offset from the base by the face's
01177      * LID, and is of length 3. */
01178     VertexView face(&(faceVertGIDBase_[0]), lid, 3);
01179       
01180     /* record this vertex set in the hashtable of 
01181      * existing face vertex sets */
01182     vertexSetToFaceIndexMap_.put(face, lid);
01183       
01184     /* create space for the new face's cofacets */
01185     faceCofacets_.resize(lid+1);
01186       
01187     /* update the cell count */
01188     numCells_[spatialDim()-1]++;
01189 
01190     /* Register the face as a cofacet of its edges */
01191     edgeFaces_[e1].append(lid);
01192     edgeFaces_[e2].append(lid);
01193     edgeFaces_[e3].append(lid);
01194 
01195     /* Register the face as a cofacet of its vertices */
01196     vertFaces_[v1].append(lid);
01197     vertFaces_[v2].append(lid);
01198     vertFaces_[v3].append(lid);
01199 
01200     /* return the LID of the new face */
01201     return lid;
01202   }
01203 
01204 }
01205 
01206 
01207 void BasicSimplicialMesh::getSortedFaceVertices(int a, int b, int c,
01208   int la, int lb, int lc,
01209   int ea, int eb, int ec, 
01210   int* sortedVertGIDs,
01211   int* reorderedVertLIDs,
01212   int* reorderedEdgeLIDs,
01213   int& rotation) const
01214 {
01215   /* 
01216    * Do a hand-coded sort of a 3-tuple of vertex GIDs, reordering tuples of vertex LIDs
01217    * and edge LIDs accordingly.
01218    */
01219   if (a < b)
01220   {
01221     if (c < a) 
01222     {
01223       fillSortedArray(c,a,b,sortedVertGIDs); 
01224       fillSortedArray(lc,la,lb,reorderedVertLIDs); 
01225       fillSortedArray(ec,ea,eb,reorderedEdgeLIDs); 
01226       rotation=3;
01227     }
01228     else if (c > b) 
01229     {
01230       fillSortedArray(a,b,c,sortedVertGIDs); 
01231       fillSortedArray(la,lb,lc,reorderedVertLIDs); 
01232       fillSortedArray(ea,eb,ec,reorderedEdgeLIDs); 
01233       rotation=1;
01234     }
01235     else 
01236     {
01237       fillSortedArray(a,c,b,sortedVertGIDs); 
01238       fillSortedArray(la,lc,lb,reorderedVertLIDs); 
01239       fillSortedArray(ea,ec,eb,reorderedEdgeLIDs); 
01240       rotation=-1;
01241     }
01242   }
01243   else /* b < a */
01244   {
01245     if (c < b) 
01246     {
01247       fillSortedArray(c,b,a,sortedVertGIDs); 
01248       fillSortedArray(lc,lb,la,reorderedVertLIDs); 
01249       fillSortedArray(ec,eb,ea,reorderedEdgeLIDs); 
01250       rotation=-3;
01251     }
01252     else if (c > a) 
01253     {
01254       fillSortedArray(b,a,c,sortedVertGIDs); 
01255       fillSortedArray(lb,la,lc,reorderedVertLIDs); 
01256       fillSortedArray(eb,ea,ec,reorderedEdgeLIDs); 
01257       rotation=-2;
01258     }
01259     else
01260     {
01261       fillSortedArray(b,c,a,sortedVertGIDs); 
01262       fillSortedArray(lb,lc,la,reorderedVertLIDs); 
01263       fillSortedArray(eb,ec,ea,reorderedEdgeLIDs); 
01264       rotation=2;
01265     }
01266   }
01267 }
01268 
01269 
01270 void BasicSimplicialMesh::getSortedFaceVertices(int a, int b, int c,
01271   int* sortedVertGIDs) const
01272 {
01273   /* 
01274    * Do a hand-coded sort of a 3-tuple of vertex GIDs
01275    */
01276   if (a < b)
01277   {
01278     if (c < a) 
01279     {
01280       fillSortedArray(c,a,b,sortedVertGIDs); 
01281     }
01282     else if (c > b) 
01283     {
01284       fillSortedArray(a,b,c,sortedVertGIDs); 
01285     }
01286     else 
01287     {
01288       fillSortedArray(a,c,b,sortedVertGIDs); 
01289     }
01290   }
01291   else /* b < a */
01292   {
01293     if (c < b) 
01294     {
01295       fillSortedArray(c,b,a,sortedVertGIDs); 
01296     }
01297     else if (c > a) 
01298     {
01299       fillSortedArray(b,a,c,sortedVertGIDs); 
01300     }
01301     else
01302     {
01303       fillSortedArray(b,c,a,sortedVertGIDs); 
01304     }
01305   }
01306 }
01307 
01308 
01309 int BasicSimplicialMesh::checkForExistingEdge(int vertLID1, int vertLID2)
01310 {
01311   const Array<int>& edgePartners = vertEdgePartners_[vertLID1];
01312   for (int i=0; i<edgePartners.length(); i++)
01313   {
01314     if (edgePartners[i] == vertLID2)
01315     {
01316       return vertEdges_[vertLID1][i];
01317     }
01318   }
01319   return -1;
01320 }
01321 
01322 int BasicSimplicialMesh::checkForExistingFace(int v1, int v2, int v3,
01323   int e1, int e2, int e3,
01324   int* sortedVertGIDs,
01325   int* reorderedVertLIDs,
01326   int* reorderedEdgeLIDs,
01327   int& rotation) 
01328 {
01329   /* sort the face's vertices by global ID, reordering the vertex LIDs and
01330    * edge LIDs to follow. */
01331   int g1 = LIDToGIDMap_[0][v1];
01332   int g2 = LIDToGIDMap_[0][v2];
01333   int g3 = LIDToGIDMap_[0][v3];
01334 
01335   getSortedFaceVertices(g1, g2, g3, v1, v2, v3, e1, e2, e3, 
01336     sortedVertGIDs, reorderedVertLIDs, reorderedEdgeLIDs,
01337     rotation);
01338 
01339   /* see if the face is already in existence by checking for the
01340    * presence of the same ordered set of vertices. */
01341   VertexView inputFaceView(&(sortedVertGIDs), 0, 3);
01342 
01343   if (vertexSetToFaceIndexMap_.containsKey(inputFaceView)) 
01344   {
01345     /* return the existing face's LID */
01346     return vertexSetToFaceIndexMap_.get(inputFaceView);
01347   }
01348   else 
01349   {
01350     /* return -1 as an indication that the face does not yet exist */
01351     return -1;
01352   }
01353 }
01354 
01355 int BasicSimplicialMesh::lookupFace(int g1, int g2, int g3) 
01356 {
01357   static Array<int> sortedVertGIDs(3);
01358   static int* sortedVertGIDPtr = &(sortedVertGIDs[0]);
01359 
01360   /* sort the face's vertices by global ID */
01361   getSortedFaceVertices(g1, g2, g3, sortedVertGIDPtr);
01362 
01363   /* see if the face is already in existence by checking for the
01364    * presence of the same ordered set of vertices. */
01365   VertexView inputFaceView(&(sortedVertGIDPtr), 0, 3);
01366 
01367   if (vertexSetToFaceIndexMap_.containsKey(inputFaceView)) 
01368   {
01369     /* return the existing face's LID */
01370     return vertexSetToFaceIndexMap_.get(inputFaceView);
01371   }
01372   else 
01373   {
01374     /* return -1 as an indication that the face does not yet exist */
01375     return -1;
01376   }
01377 }
01378                                                 
01379 int BasicSimplicialMesh::addEdge(int v1, int v2, 
01380   int elemLID, int elemGID,
01381   int myFacetNumber)
01382 {
01383   /* 
01384    * First we ask if this edge already exists in the mesh. If so,
01385    * we're done. 
01386    */
01387   int lid = checkForExistingEdge(v1, v2);
01388 
01389   if (lid >= 0) 
01390   {
01391     /* determine the sign of the existing edge */
01392     int g1 = LIDToGIDMap_[0][v1];
01393     int g2 = LIDToGIDMap_[0][v2];
01394     int edgeSign;
01395     if (g2 > g1) 
01396     {
01397       edgeSign = 1;
01398     }
01399     else 
01400     {
01401       edgeSign = -1;
01402     }
01403     elemEdgeSigns_.value(elemLID, myFacetNumber) = edgeSign;
01404 
01405     /* return the LID of the pre-existing edge */
01406     return lid;
01407   }
01408   else
01409   {
01410     /* get the LID of the new edge */
01411     lid = edgeVerts_.length();
01412 
01413     /* create the new edge, oriented from lower to higher vertex GID */
01414     int g1 = LIDToGIDMap_[0][v1];
01415     int g2 = LIDToGIDMap_[0][v2];
01416     int edgeSign;
01417     if (g2 > g1) 
01418     {
01419       edgeVerts_.append(tuple(v1,v2));
01420       edgeSign = 1;
01421     }
01422     else 
01423     {
01424       edgeVerts_.append(tuple(v2,v1));
01425       edgeSign = -1;
01426     }
01427 
01428     /* if we own all vertices, we own the edge. Otherwise, mark it
01429      * for later assignment. */
01430     int vert1Owner = ownerProcID_[0][v1];
01431     int vert2Owner = ownerProcID_[0][v2];
01432     if (vert2Owner==comm().getRank() && vert1Owner==comm().getRank()) 
01433       ownerProcID_[1].append(vert1Owner);
01434     else ownerProcID_[1].append(-1);
01435 
01436     elemEdgeSigns_.value(elemLID, myFacetNumber) = edgeSign;
01437 
01438     /* register the new edge with its vertices */
01439     vertEdges_[v1].append(lid);
01440     vertEdgePartners_[v1].append(v2);
01441     vertEdges_[v2].append(lid);
01442     vertEdgePartners_[v2].append(v1);
01443     /* create storage for the cofacets of the new edge */
01444     edgeCofacets_.resize(lid+1);
01445     if (spatialDim() > 2) edgeFaces_.resize(lid+1);
01446       
01447       
01448     /* the new edge is so far unlabeled, so set its label to zero */
01449     labels_[1].append(0);
01450       
01451     /* update the edge count */
01452     numCells_[1]++;
01453   }
01454   /* return the LID of the edge */
01455   return lid;
01456 }
01457 
01458 
01459 void BasicSimplicialMesh::synchronizeGIDNumbering(int dim, int localCount) 
01460 {
01461   
01462   SUNDANCE_OUT(this->verb() > 2, 
01463     "sharing offsets for GID numbering for dim=" << dim);
01464   SUNDANCE_OUT(this->verb() > 2, 
01465     "I have " << localCount << " cells");
01466   Array<int> gidOffsets;
01467   int total;
01468   MPIContainerComm<int>::accumulate(localCount, gidOffsets, total, comm());
01469   int myOffset = gidOffsets[comm().getRank()];
01470 
01471   SUNDANCE_OUT(this->verb() > 2, 
01472     "back from MPI accumulate: offset for d=" << dim
01473     << " on p=" << comm().getRank() << " is " << myOffset);
01474 
01475   for (int i=0; i<numCells(dim); i++)
01476   {
01477     if (LIDToGIDMap_[dim][i] == -1) continue;
01478     LIDToGIDMap_[dim][i] += myOffset;
01479     GIDToLIDMap_[dim].put(LIDToGIDMap_[dim][i], i);
01480   }
01481   SUNDANCE_OUT(this->verb() > 2, 
01482     "done sharing offsets for GID numbering for dim=" << dim);
01483 }
01484 
01485 
01486 void BasicSimplicialMesh::assignIntermediateCellGIDs(int cellDim)
01487 {
01488   int myRank = comm().getRank();
01489   SUNDANCE_VERB_MEDIUM("p=" << myRank << " assigning " << cellDim 
01490     << "-cell owners");
01491 
01492   /* If we are debugging parallel code, we may want to stagger the output
01493    * from the different processors. This is done by looping over processors,
01494    * letting one do its work while the others are idle; a synchronization
01495    * point after each iteration forces this procedure to occur such
01496    * that the processors' output is staggered. 
01497    *
01498    * If we don't want staggering (as will usually be the case in production
01499    * runs) numWaits should be set to 1. 
01500    */  
01501   int numWaits = 1;
01502   if (staggerOutput())
01503   {
01504     SUNDANCE_VERB_LOW("p=" << myRank << " doing staggered output in "
01505       "assignIntermediateCellOwners()");
01506     numWaits = comm().getNProc();
01507   }
01508   
01509 
01510   /* list of vertex GIDs which serve to identify the cells whose
01511    * GIDs are needed */
01512   Array<Array<int> > outgoingRequests(comm().getNProc());
01513   Array<Array<int> > incomingRequests(comm().getNProc());
01514 
01515   /* lists of cells for which GIDs are needed from each processor */
01516   Array<Array<int> > outgoingRequestLIDs(comm().getNProc());
01517 
01518   /* lists of GIDs to be communicated. */
01519   Array<Array<int> > outgoingGIDs(comm().getNProc());
01520   Array<Array<int> > incomingGIDs(comm().getNProc());
01521 
01522   /* Define these so we're not constantly dereferencing the owners arrays */
01523   Array<int>& cellOwners = ownerProcID_[cellDim];
01524 
01525   /* run through the cells, assigning GID numbers to the locally owned ones
01526    * and compiling a list of the remotely owned ones. */
01527   int localCount = 0;
01528   ArrayOfTuples<int>* cellVerts;
01529   if (cellDim==2) cellVerts = &(faceVertLIDs_);
01530   else cellVerts = &(edgeVerts_);
01531 
01532   LIDToGIDMap_[cellDim].resize(numCells(cellDim));
01533   
01534   SUNDANCE_OUT(this->verb() > 2,  
01535     "starting loop over cells");
01536 
01537 
01538   /*
01539    * We assign edge owners as follows: 
01540    *
01541    * (1) Any edge whose vertices are owned by the same proc is owned
01542    * by that proc.  This can be done at the time of construction of
01543    * the edge.
01544    *
01545    * (2) For edges not resolved by step 1, we send a specification of
01546    * that edge to all processors neighboring this one. Each processor
01547    * then returns either its processor rank or -1 for each edge
01548    * specification it receives, according to whether or not both
01549    * vertex GIDs exist on that processor.
01550    *
01551    * (3) The ranks of all processors seeing each disputed edge having
01552    * been collected in step 2, the edge is assigned to the processor
01553    * with the largest rank.
01554    */
01555   
01556   try
01557   {
01558     resolveEdgeOwnership(cellDim);
01559   }
01560   catch(std::exception& e0)
01561   {
01562     SUNDANCE_TRACE_MSG(e0, "while resolving edge ownership");
01563   }
01564 
01565   
01566   for (int q=0; q<numWaits; q++)
01567   {
01568     if (numWaits > 1 && q != myRank) 
01569     {
01570       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01571         "off-proc error detected on proc=" << myRank
01572         << " while computing GID resolution requests");
01573       continue;
01574     }
01575     try
01576     {
01577       for (int i=0; i<numCells(cellDim); i++)
01578       {  
01579         SUNDANCE_OUT(this->verb() > 3, 
01580           "p=" << myRank 
01581           <<" cell " << i);
01582               
01583         /* If the cell is locally owned, give it a temporary
01584          * GID. This GID is temporary because it's one of a
01585          * sequence numbered from zero rather than the lowest
01586          * GID on this processor. We'll offset all of these GIDs
01587          * once we know how many cells this processor owns. */
01588         int owner = cellOwners[i];
01589         if (owner==myRank)
01590         {
01591           SUNDANCE_VERB_EXTREME("p=" << myRank 
01592             << " assigning GID=" << localCount
01593             << " to cell " 
01594             << cellToStr(cellDim, i));
01595           LIDToGIDMap_[cellDim][i] = localCount++;
01596         }
01597         else /* If the cell is remotely owned, we can't give it
01598               * a GID now. Give it a GID of -1 to mark it as
01599               * unresolved, and then add it to a list of cells for
01600               * which we'll need remote GIDs. To get a GID, we have
01601               * to look up this cell on another processor.  We can't
01602               * use the LID to identify the cell, since other procs
01603               * won't know our LID numbering. Thus we send the GIDs
01604               * of the cell's vertices, which are sufficient to
01605               * identify the cell on the other processor. */
01606         {
01607           LIDToGIDMap_[cellDim][i] = -1;
01608           SUNDANCE_OUT(this->verb() > 3, 
01609             "p=" << myRank << " adding cell LID=" << i 
01610             << " to req list");
01611           outgoingRequestLIDs[owner].append(i);
01612           for (int v=0; v<=cellDim; v++)
01613           {
01614             int ptLID = cellVerts->value(i, v);
01615             int ptGID = LIDToGIDMap_[0][ptLID];
01616             SUNDANCE_OUT(this->verb() > 3, 
01617               "p=" << myRank << " adding pt LID=" << ptLID
01618               << " GID=" << ptGID
01619               << " to req list");
01620             outgoingRequests[owner].append(ptGID);
01621           }
01622           SUNDANCE_VERB_EXTREME("p=" << myRank 
01623             << " deferring GID assignment for cell "
01624             << cellToStr(cellDim, i));
01625         }
01626       }
01627     }
01628     catch(std::exception& e0)
01629     {
01630       reportFailure(comm());
01631       SUNDANCE_TRACE_MSG(e0, "while computing GID resolution requests");
01632     }
01633     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01634       "off-proc error detected on proc=" << myRank
01635       << " while computing GID resolution requests");
01636   }
01637 
01638   /* Now that we know how many cells are locally owned, we can 
01639    * set up a global GID numbering */
01640   try
01641   {
01642     synchronizeGIDNumbering(cellDim, localCount);
01643   }
01644   catch(std::exception& e0)
01645   {
01646     reportFailure(comm());
01647     SUNDANCE_TRACE_MSG(e0, "while computing GID offsets");
01648   }
01649   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01650     "off-proc error detected on proc=" << myRank
01651     << " while computing GID offsets");
01652   
01653   /* We now share requests for cells for which remote GIDs are needed */
01654   for (int q=0; q<numWaits; q++)
01655   {
01656     if (numWaits > 1) comm().synchronize();
01657     if (numWaits > 1 && q!=myRank) continue;
01658     SUNDANCE_OUT(this->verb() > 3,
01659       "p=" << myRank << "sending requests: " 
01660       << outgoingRequests);
01661   }
01662 
01663   try
01664   {
01665     MPIContainerComm<int>::allToAll(outgoingRequests,
01666       incomingRequests,
01667       comm()); 
01668   }
01669   catch(std::exception& e0)
01670   {
01671     reportFailure(comm());
01672     SUNDANCE_TRACE_MSG(e0, "while distributing GID resolution requests");
01673   }
01674   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01675     "off-proc error detected on proc=" << myRank
01676     << " while distributing GID resolution requests");
01677 
01678 
01679   for (int q=0; q<numWaits; q++)
01680   {
01681     if (numWaits > 1) comm().synchronize();
01682     if (numWaits > 1 && q!=myRank) continue;
01683     SUNDANCE_OUT(this->verb() > 3,
01684       "p=" << myRank << "recv'd requests: " << incomingRequests);
01685   }
01686 
01687 
01688   for (int q=0; q<numWaits; q++)
01689   {
01690     if (numWaits>1 && q != myRank) 
01691     {
01692       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01693         "off-proc error detected on proc=" << myRank
01694         << " while computing edge/face GID responses");
01695       continue;
01696     }
01697     try
01698     {
01699       /* Answer the requests incoming to this processor */
01700       for (int p=0; p<comm().getNProc(); p++)
01701       {
01702         const Array<int>& requestsFromProc = incomingRequests[p];
01703               
01704         for (int c=0; c<requestsFromProc.size(); c+=(cellDim+1))
01705         {
01706           SUNDANCE_OUT(this->verb() > 3,
01707             "p=" << myRank << "processing request c=" 
01708             << c/(cellDim+1));
01709           /* The request for each cell is a tuple of vertex GIDs. 
01710            * Find the LID of the local cell that contains them */
01711           int cellLID;
01712           if (cellDim==1) 
01713           {
01714             int vertLID1 = mapGIDToLID(0, requestsFromProc[c]);
01715             int vertLID2 = mapGIDToLID(0, requestsFromProc[c+1]);
01716             SUNDANCE_VERB_HIGH("p=" << myRank 
01717               << " edge vertex GIDs are "
01718               <<  requestsFromProc[c+1]
01719               << ", " << requestsFromProc[c]);
01720             cellLID = checkForExistingEdge(vertLID1, vertLID2);
01721           }
01722           else
01723           {
01724                       
01725             SUNDANCE_VERB_HIGH("p=" << myRank 
01726               << " face vertex GIDs are "
01727               <<  requestsFromProc[c]
01728               << ", " << requestsFromProc[c+1]
01729               << ", " << requestsFromProc[c+2]);
01730             cellLID = lookupFace(requestsFromProc[c],
01731               requestsFromProc[c+1],
01732               requestsFromProc[c+2]);
01733           }
01734           SUNDANCE_VERB_HIGH("p=" << myRank << "cell LID is " 
01735             << cellLID);
01736                   
01737           TEST_FOR_EXCEPTION(cellLID < 0, RuntimeError,
01738             "unable to find requested cell "
01739             << cellStr(cellDim+1, &(requestsFromProc[c])));
01740                   
01741           /* Finally, we get the cell's GID and append to the list 
01742            * of GIDs to send back as answers. */
01743           int cellGID = mapLIDToGID(cellDim, cellLID);
01744           TEST_FOR_EXCEPTION(cellGID < 0, RuntimeError,
01745             "proc " << myRank 
01746             << " was asked by proc " << p
01747             << " to provide a GID for cell "
01748             << cellStr(cellDim+1, &(requestsFromProc[c]))
01749             << " with LID=" << cellLID
01750             << " but its GID is undefined");
01751                   
01752           outgoingGIDs[p].append(mapLIDToGID(cellDim, cellLID));
01753         }
01754       }
01755     }
01756     catch(std::exception& e0)
01757     {
01758       reportFailure(comm());
01759       SUNDANCE_TRACE_MSG(e0, "while computing edge/face GID responses");
01760     }
01761     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01762       "off-proc error detected "
01763       "on proc=" << myRank
01764       << " while computing edge/face GID responses");
01765   }
01766 
01767 
01768   /* We now share the GIDs for the requested cells */
01769   for (int q=0; q<numWaits; q++)
01770   {
01771     if (numWaits>1) comm().synchronize();
01772     if (numWaits>1 && q!=myRank) continue;
01773     SUNDANCE_OUT(this->verb() > 3,
01774       "p=" << myRank << "sending GIDs: " << outgoingGIDs);
01775   }
01776 
01777   
01778   try
01779   {
01780     MPIContainerComm<int>::allToAll(outgoingGIDs,
01781       incomingGIDs,
01782       comm());
01783   }
01784   catch(std::exception& e0)
01785   {
01786     reportFailure(comm());
01787     SUNDANCE_TRACE_MSG(e0, "while distributing edge/face GIDs");
01788   }
01789   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01790     "off-proc error detected on proc=" << myRank
01791     << " while distributing edge/face GIDs");
01792   
01793 
01794 
01795 
01796   for (int q=0; q<numWaits; q++)
01797   {
01798     if (numWaits > 1 && q != myRank) 
01799     {
01800       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01801         "off-proc error detected on proc=" << myRank
01802         << " while setting remote edge/face GIDs");
01803       continue;
01804     }
01805     try
01806     {
01807       SUNDANCE_OUT(this->verb() > 3,
01808         "p=" << myRank << "recv'ing GIDs: " << incomingGIDs);
01809           
01810       /* Now assign the cell GIDs we've recv'd from from the other procs */
01811       for (int p=0; p<comm().getNProc(); p++)
01812       {
01813         const Array<int>& gidsFromProc = incomingGIDs[p];
01814         for (int c=0; c<gidsFromProc.size(); c++)
01815         {
01816           int cellLID = outgoingRequestLIDs[p][c];
01817           int cellGID = incomingGIDs[p][c];
01818           SUNDANCE_OUT(this->verb() > 3,
01819             "p=" << myRank << 
01820             " assigning GID=" << cellGID << " to LID=" 
01821             << cellLID);
01822           LIDToGIDMap_[cellDim][cellLID] = cellGID;
01823           GIDToLIDMap_[cellDim].put(cellGID, cellLID);
01824         }
01825       }
01826           
01827 
01828       SUNDANCE_OUT(this->verb() > 2,  
01829         "p=" << myRank 
01830         << "done synchronizing cells of dimension " 
01831         << cellDim);
01832     }
01833     catch(std::exception& e0)
01834     {
01835       reportFailure(comm());
01836       SUNDANCE_TRACE_MSG(e0, " while setting remote edge/face GIDs");
01837     }
01838     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01839       "off-proc error detected on proc=" << myRank
01840       << " while setting remote edge/face GIDs");
01841   }
01842   if (cellDim==1) hasEdgeGIDs_ = true;
01843   else hasFaceGIDs_ = true;
01844 }
01845 
01846 
01847 
01848 
01849 
01850 
01851 
01852 void BasicSimplicialMesh::synchronizeNeighborLists()
01853 {
01854   if (neighborsAreSynchronized_) return ;
01855 
01856   Array<Array<int> > outgoingNeighborFlags(comm().getNProc());
01857   Array<Array<int> > incomingNeighborFlags(comm().getNProc());
01858 
01859   int myRank = comm().getRank();
01860 
01861   for (int p=0; p<comm().getNProc(); p++)
01862   {
01863     if (neighbors_.contains(p)) outgoingNeighborFlags[p].append(myRank);
01864   }
01865 
01866   try
01867   {
01868     MPIContainerComm<int>::allToAll(outgoingNeighborFlags,
01869       incomingNeighborFlags,
01870       comm()); 
01871   }
01872   catch(std::exception& e0)
01873   {
01874     reportFailure(comm());
01875     SUNDANCE_TRACE_MSG(e0, "while distributing neighbor information");
01876   }
01877   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01878     "off-proc error detected on proc=" << myRank
01879     << " while distributing neighbor information");
01880 
01881   
01882 
01883   for (int p=0; p<comm().getNProc(); p++)
01884   {
01885     if (incomingNeighborFlags[p].size() > 0) neighbors_.put(p);
01886   }
01887 
01888   neighborsAreSynchronized_ = true;
01889 }
01890 
01891 
01892 
01893 
01894 void BasicSimplicialMesh::resolveEdgeOwnership(int cellDim) 
01895 {
01896   int myRank = comm().getRank();
01897   SUNDANCE_VERB_LOW("p=" << myRank << " finding " 
01898     << cellDim << "-cell owners");
01899 
01900 
01901   /* If we are debugging parallel code, we may want to stagger the output
01902    * from the different processors. This is done by looping over processors,
01903    * letting one do its work while the others are idle; a synchronization
01904    * point after each iteration forces this procedure to occur such
01905    * that the processors' output is staggered. 
01906    *
01907    * If we don't want staggering (as will usually be the case in production
01908    * runs) numWaits should be set to 1. 
01909    */  
01910   int numWaits = 1;
01911   if (staggerOutput())
01912   {
01913     SUNDANCE_VERB_LOW("p=" << myRank << " doing staggered output in "
01914       "assignIntermediateCellOwners()");
01915     numWaits = comm().getNProc();
01916   }
01917 
01918   synchronizeNeighborLists();
01919 
01920   /* Define some helper variables to save us from lots of dereferencing */
01921   Array<int>& cellOwners = ownerProcID_[cellDim];
01922   ArrayOfTuples<int>* cellVerts;
01923   if (cellDim==2) cellVerts = &(faceVertLIDs_);
01924   else cellVerts = &(edgeVerts_);
01925 
01926   /* Dump neighbor set into an array to simplify looping */
01927   Array<int> neighbors = neighbors_.elements();
01928   SUNDANCE_VERB_LOW("p=" << myRank << " neighbors are " << neighbors);
01929   
01930 
01931 
01932   /*
01933    * In 3D it is not possible to assign all edge owners without communication. 
01934    * We assign edge owners as follows:
01935    * (1) Any edge whose vertices are owned by the same proc is owned by 
01936    *     that proc. This can be done at the time of construction of the edge. 
01937    * (2) For edges not resolved by step 1, we send a specification of that edge
01938    *     to all processors neighboring this one. Each processor then returns 
01939    *     either its processor rank or -1 for each edge specification it 
01940    *     receives, according to whether or not both vertex GIDs exist 
01941    *     on that processor. 
01942    * (3) The ranks of all processors seeing each disputed edge having been 
01943    *     collected in step 2, the edge is assigned to the processor 
01944    *     with the largest rank.
01945    */
01946 
01947 
01948       
01949   /* the index to LID map will let us remember the LIDs of edges
01950    * we've sent off for owner information */
01951   Array<int> reqIndexToEdgeLIDMap;
01952 
01953   /* compile lists of specifiers to be communicated to neighbors */
01954   Array<Array<int> > outgoingEdgeSpecifiers(comm().getNProc());
01955   Array<int> vertLID(cellDim+1);
01956   Array<int> vertGID(cellDim+1);
01957 
01958   for (int q=0; q<numWaits; q++)
01959   {
01960     if (numWaits > 1 && q != myRank) 
01961     {
01962       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
01963         "off-proc error detected on proc=" << myRank
01964         << " while determining edges to be resolved");
01965       continue;
01966     }
01967     try
01968     {
01969       for (int i=0; i<numCells(cellDim); i++)
01970       {  
01971         int owner = cellOwners[i];
01972         /* if we don't know the owner of the edge, send
01973          * information about the edge to all neighbors so we can
01974          * come to a consensus on the ownership of the edge
01975          */
01976         if (owner==-1)
01977         {
01978           /* The specification of the edge is the set of 
01979            * vertices defining the edge. */
01980           for (int v=0; v<=cellDim; v++) 
01981           {
01982             vertLID[v] = cellVerts->value(i, v);
01983             vertGID[v] = LIDToGIDMap_[0][vertLID[v]];
01984           }
01985           /* make a request to all neighbors */
01986           for (int n=0; n<neighbors.size(); n++)
01987           {
01988             for (int v=0; v<=cellDim; v++)
01989             {
01990               outgoingEdgeSpecifiers[neighbors[n]].append(vertGID[v]);
01991             }
01992           }
01993           SUNDANCE_VERB_HIGH("p=" << myRank 
01994             << " is asking all neighbors to resolve edge "
01995             << cellToStr(cellDim, i));
01996 
01997           /* Remember the LIDs of the edges about whom we're requesting
01998            * information. */
01999           reqIndexToEdgeLIDMap.append(i);
02000         }
02001       }
02002 
02003       SUNDANCE_VERB_MEDIUM("p=" << myRank 
02004         << " initially unresolved edge LIDs are "
02005         << reqIndexToEdgeLIDMap);
02006 
02007       SUNDANCE_VERB_HIGH("p=" << myRank 
02008         << " sending outgoing edge specs:") ;
02009       for (int p=0; p<comm().getNProc(); p++)
02010       {
02011         SUNDANCE_VERB_HIGH(outgoingEdgeSpecifiers[p].size()/(cellDim+1) 
02012           << " edge reqs to proc "<< p) ;
02013       }
02014       SUNDANCE_VERB_HIGH("p=" << myRank << " outgoing edge specs are " 
02015         << outgoingEdgeSpecifiers);
02016     }
02017     catch(std::exception& e0)
02018     {
02019       reportFailure(comm());
02020       SUNDANCE_TRACE_MSG(e0, "while determining edges to be resolved");
02021     }
02022     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02023       "off-proc error detected on proc=" << myRank
02024       << " while determining edges to be resolved");
02025   }
02026   
02027 
02028 
02029   /* share the unresolved edges with my neighbors */
02030   Array<Array<int> > incomingEdgeSpecifiers(comm().getNProc());
02031 
02032 
02033   try
02034   {
02035     MPIContainerComm<int>::allToAll(outgoingEdgeSpecifiers,
02036       incomingEdgeSpecifiers,
02037       comm()); 
02038   }
02039   catch(std::exception& e0)
02040   {
02041     reportFailure(comm());
02042     SUNDANCE_TRACE_MSG(e0, "while distributing edge resolution reqs");
02043   }
02044   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02045     "off-proc error detected on proc=" << myRank
02046     << " while distributing edge resolution reqs");
02047     
02048 
02049   Array<Array<int> > outgoingEdgeContainers(comm().getNProc());    
02050   for (int q=0; q<numWaits; q++)
02051   {
02052 
02053     if (numWaits > 1 && q != myRank) 
02054     {
02055       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02056         "off-proc error detected on proc=" << myRank
02057         << " while resolving edge ownership results");
02058       continue;
02059     }
02060       
02061     try
02062     {
02063       SUNDANCE_VERB_HIGH("p=" << myRank << " incoming edge specs are " 
02064         << incomingEdgeSpecifiers);
02065       /* Now, put on my receiver hat. I have received from each
02066        * other processor  an array of vertex GID pairs, each of
02067        * which may or may not exist on this processor. I need to
02068        * send back to my neighbors an indicator of whether or not I
02069        * know about both vertices defining each edge.
02070        */
02071       for (int p=0; p<comm().getNProc(); p++)
02072       {
02073         const Array<int>& edgesFromProc = incomingEdgeSpecifiers[p];
02074               
02075         int numVerts = cellDim+1;
02076         for (int c=0; c<edgesFromProc.size(); c+=numVerts)
02077         {
02078           SUNDANCE_VERB_LOW("p=" << myRank << " doing c=" << c/numVerts
02079             << " of " << edgesFromProc.size()/numVerts
02080             << " reqs from proc=" << p);
02081           /* The request for each cell is a tuple of vertex
02082            * GIDs. Find out whether this processor knows about
02083            * all of them. If this processor contains knows
02084            * both vertices of the edge and the vertex pair
02085            * forms an edge, add my rank to the pool of
02086            * potential edge owners to be returned. Otherwise,
02087            * mark with -1. */
02088 
02089           int cellLID;
02090           SUNDANCE_VERB_LOW("p=" << myRank << " looking at "
02091             << cellStr(numVerts, &(edgesFromProc[c])));
02092           /* The response will be:
02093            * (*) -1 if the proc doesn't know the edge
02094            * (*) 0  if the proc knows the edge, but doesn't know who owns it
02095            * (*) 1  if the proc owns it
02096            */
02097           int response = 0;
02098           /* See if all verts are present on this proc. Respond with -1 of not. */
02099           for (int v=0; v<numVerts; v++)
02100           {
02101             vertGID[v] = edgesFromProc[c+v];
02102             if (!GIDToLIDMap_[0].containsKey(vertGID[v])) 
02103             {
02104               response = -1;
02105               break;
02106             }
02107             else
02108             {
02109               vertLID[v] = GIDToLIDMap_[0].get(vertGID[v]);
02110             }
02111           }
02112           if (response != -1)
02113           {
02114             /* Make sure the vertices are actually organized into an edge
02115              * on this processor */
02116             if (cellDim==1)
02117             {
02118               cellLID = checkForExistingEdge(vertLID[0], vertLID[1]);
02119             }
02120             else
02121             {
02122               cellLID = lookupFace(vertGID[0], vertGID[1], vertGID[2]);
02123             }
02124             /* Respond with -1 if the edge/face doesn't exist on this proc */
02125             if (cellLID==-1)
02126             {
02127               response = -1;
02128             }
02129           }
02130 
02131           if (response == -1)
02132           {
02133             SUNDANCE_VERB_HIGH("p=" << myRank << " is unaware of cell "
02134               << cellStr(numVerts, &(vertGID[0])));
02135           } 
02136           else
02137           {
02138             SUNDANCE_VERB_HIGH("p=" << myRank << " knows about cell "
02139               << cellStr(numVerts, &(vertGID[0])));
02140             if (ownerProcID_[cellDim][cellLID] != -1) response = 1;
02141           }
02142           /* add the response to the data stream to be returned */
02143           outgoingEdgeContainers[p].append(response);
02144           SUNDANCE_VERB_LOW("p=" << myRank << " did c=" << c/numVerts
02145             << " of " << edgesFromProc.size()/numVerts 
02146             << " reqs from proc=" << p);
02147         }
02148         SUNDANCE_VERB_LOW("p=" << myRank << " done all reqs from proc "
02149           << p);
02150           
02151       }
02152       SUNDANCE_VERB_LOW("p=" << myRank << " done processing edge reqs");
02153       SUNDANCE_VERB_HIGH("p=" << myRank 
02154         << " outgoing edge containers are " 
02155         << outgoingEdgeContainers);
02156     }
02157     catch(std::exception& e0)
02158     {
02159       reportFailure(comm());
02160       SUNDANCE_TRACE_MSG(e0, "while resolving edge ownership results");
02161     }
02162     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02163       "off-proc error detected on proc=" << myRank
02164       << " while resolving edge ownership results");
02165   }
02166   
02167 
02168   
02169   /* share the information about which edges I am aware of */
02170   
02171   Array<Array<int> > incomingEdgeContainers(comm().getNProc());
02172   try
02173   {
02174     MPIContainerComm<int>::allToAll(outgoingEdgeContainers,
02175       incomingEdgeContainers,
02176       comm()); 
02177   }
02178   catch(std::exception& e0)
02179   {
02180     reportFailure(comm());
02181     SUNDANCE_TRACE_MSG(e0, "while distributing edge resolution results");
02182   }
02183   TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02184     "off-proc error detected on proc=" << myRank
02185     << " while distributing edge ownership results");
02186 
02187   
02188 
02189 
02190 
02191   /* Process the edge data incoming to this processor */
02192   for (int q=0; q<numWaits; q++)
02193   {
02194     if (numWaits > 1 && q != myRank)
02195     {
02196       TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02197         "off-proc error detected on proc=" << myRank
02198         << " while finalizing edge ownership");
02199       continue;
02200     }
02201 
02202     try
02203     {
02204       SUNDANCE_VERB_HIGH("p=" << myRank 
02205         << " incoming edge containers are " 
02206         << incomingEdgeContainers);
02207       Set<int> resolved;
02208       for (int p=0; p<comm().getNProc(); p++)
02209       {
02210         const Array<int>& edgeContainers = incomingEdgeContainers[p];
02211               
02212         for (int c=0; c<edgeContainers.size(); c++)
02213         {
02214           int edgeLID = reqIndexToEdgeLIDMap[c];
02215           /* If the state of the edge is unknown, 
02216            * update the owner to the largest rank of all procs 
02217            * containing this edge */
02218           if (edgeContainers[c] == 0 && !resolved.contains(edgeLID)) 
02219           {
02220             /* because p is increasing in the loop, p is
02221              * equivalent to max(cellOwners[edgeLID], p) */
02222             cellOwners[edgeLID] = p;
02223           }
02224           /* If one of the processors reports it owns the edge, set
02225            * the owner and mark it as resolved so that it won't be modified 
02226            * further */
02227           else if (edgeContainers[c]==1)
02228           {
02229             cellOwners[edgeLID] = p;
02230             resolved.put(edgeLID);
02231           }
02232         }
02233       }
02234       /* Any remaining unresolved edges appear only on this processor, so 
02235        * I own them. */
02236       for (int c=0; c<reqIndexToEdgeLIDMap.size(); c++)
02237       {
02238         int edgeLID = reqIndexToEdgeLIDMap[c];
02239         if (cellOwners[edgeLID] < 0) cellOwners[edgeLID] = myRank;
02240         SUNDANCE_VERB_EXTREME("p=" << myRank 
02241           << " has decided cell "
02242           << cellToStr(cellDim, edgeLID) 
02243           << " is owned by proc=" 
02244           << cellOwners[edgeLID]);
02245       }
02246       SUNDANCE_VERB_LOW("p=" << myRank << " done finalizing ownership"); 
02247     }
02248     catch(std::exception& e0)
02249     {
02250       reportFailure(comm());
02251       SUNDANCE_TRACE_MSG(e0, "while finalizing edge ownership");
02252     }
02253     TEST_FOR_EXCEPTION(checkForFailures(comm()), RuntimeError, 
02254       "off-proc error detected on proc=" << myRank
02255       << " while finalizing edge ownership");
02256   }
02257 }
02258 
02259 string BasicSimplicialMesh::cellStr(int dim, const int* verts) const
02260 {
02261   std::string rtn="(";
02262   for (int i=0; i<dim; i++)
02263   {
02264     if (i!=0) rtn += ", ";
02265     rtn += Teuchos::toString(verts[i]);
02266   }
02267   rtn += ")";
02268   return rtn;
02269 }
02270 
02271 string BasicSimplicialMesh::cellToStr(int cellDim, int cellLID) const
02272 {
02273   TeuchosOStringStream os;
02274 
02275   if (cellDim > 0)
02276   {
02277     const ArrayOfTuples<int>* cellVerts;
02278     if (cellDim==spatialDim()) 
02279     {
02280       cellVerts = &(elemVerts_);
02281     }
02282     else
02283     {
02284       if (cellDim==2) cellVerts = &(faceVertLIDs_);
02285       else cellVerts = &(edgeVerts_);
02286     }
02287     os << "(";
02288     for (int j=0; j<cellVerts->tupleSize(); j++)
02289     {
02290       if (j!=0) os << ", ";
02291       os << mapLIDToGID(0, cellVerts->value(cellLID,j));
02292     }
02293     os << ")" << std::endl;
02294   }
02295   else
02296   {
02297     os << LIDToGIDMap_[0][cellLID] << std::endl;
02298   }
02299   return os.str();
02300 }
02301 
02302 string BasicSimplicialMesh::printCells(int cellDim) const
02303 {
02304   TeuchosOStringStream os;
02305 
02306   if (cellDim > 0)
02307   {
02308     const ArrayOfTuples<int>* cellVerts;
02309     if (cellDim==spatialDim()) 
02310     {
02311       cellVerts = &(elemVerts_);
02312     }
02313     else
02314     {
02315       if (cellDim==2) cellVerts = &(faceVertLIDs_);
02316       else cellVerts = &(edgeVerts_);
02317     }
02318 
02319     os << "printing cells for processor " << comm().getRank() << std::endl;
02320     for (int i=0; i<cellVerts->length(); i++)
02321     {
02322       os << i << " (";
02323       for (int j=0; j<cellVerts->tupleSize(); j++)
02324       {
02325         if (j!=0) os << ", ";
02326         os << mapLIDToGID(0, cellVerts->value(i,j));
02327       }
02328       os << ")" << std::endl;
02329     }
02330   }
02331   else
02332   {
02333     os << LIDToGIDMap_[0] << std::endl;
02334   }
02335   
02336   return os.str();
02337 }
02338 
02339 
02340 

Site Contact