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

Site Contact