SundanceMesh.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 "SundanceMesh.hpp"
00043 #include "PlayaExceptions.hpp"
00044 #include "SundanceVerboseFieldWriter.hpp"
00045 #include "SundanceFieldWriter.hpp"
00046 #include "SundanceOut.hpp"
00047 #include "SundanceSet.hpp"
00048 #include "SundanceMap.hpp"
00049 #include "PlayaTabs.hpp"
00050 #include "PlayaMPIContainerComm.hpp"
00051 
00052 using namespace Teuchos;
00053 using namespace Sundance;
00054 using Playa::Handle;
00055 using Playa::Handleable;
00056 using Playa::MPIComm;
00057 using Playa::MPIContainerComm;
00058 
00059 
00060 IncrementallyCreatableMesh* Mesh::creatableMesh()
00061 {
00062   IncrementallyCreatableMesh* mci 
00063     = dynamic_cast<IncrementallyCreatableMesh*>(ptr().get());
00064   TEUCHOS_TEST_FOR_EXCEPTION(mci==0, std::runtime_error, 
00065                      "Mesh::creatableMesh() could not convert mesh to "
00066                      "a type deriving from IncrementallyCreatableMesh");
00067 
00068   return mci;
00069 }
00070 
00071 
00072 void Mesh::dump(const std::string& filename) const
00073 {
00074   FieldWriter w = new VerboseFieldWriter(filename);
00075   w.addMesh(*this);
00076   w.write();
00077 }
00078 
00079 bool Mesh::checkConsistency(const std::string& filename) const 
00080 {
00081   std::string f = filename;
00082 
00083   if (comm().getNProc() > 1)
00084     {
00085       f = f + "." + Teuchos::toString(comm().getRank());
00086     }
00087   std::ofstream os(f.c_str());
00088   return checkConsistency(os);
00089 }
00090 
00091 bool Mesh::checkConsistency(std::ostream& os) const 
00092 {
00093   /* eliminate the trivial serial case */
00094   if (comm().getNProc()==1) 
00095     {
00096       os << "Mesh is serial, thus it is consistent across processors" << std::endl;
00097       return true;
00098     }
00099 
00100   
00101   if (spatialDim() >= 2) 
00102     const_cast<Mesh*>(this)->assignIntermediateCellGIDs(1);
00103   if (spatialDim() >= 3)  
00104     const_cast<Mesh*>(this)->assignIntermediateCellGIDs(2);
00105   bool isOK = checkVertexConsistency(os);
00106   for (int d=1; d<=spatialDim(); d++)
00107     {
00108       isOK = checkCellConsistency(os, d) && isOK;
00109     }
00110 
00111   return isOK;
00112 }
00113 
00114 
00115 bool Mesh::checkCellConsistency(std::ostream& os, int dim) const
00116 {
00117   TEUCHOS_TEST_FOR_EXCEPTION(dim==0, std::runtime_error,
00118                      "Mesh::checkCellConsistency called for d=0. "
00119                      "checkVertexConsistency() should be called instead");
00120 
00121   int myRank = comm().getRank();
00122   int nProcs = comm().getNProc();
00123   Array<int> nFacets(dim);
00124 
00125   bool elemsAreOK = true;
00126 
00127   /* compute the amount of data associated with each element. The
00128    * first two entries are the element's GID and owner. The subsequent
00129    * entires are the GIDs for the facets of all dimensions */
00130   int dataSize = 2;
00131   for (int d=0; d<dim; d++) 
00132     {
00133       nFacets[d] = numFacets(dim, 0, d);
00134       dataSize += 2*nFacets[d];
00135       if (d > 0) dataSize += nFacets[d]*numFacets(d, 0, 0);
00136     }
00137 
00138   int nCells = numCells(dim);
00139   Array<int> elemData(dataSize*nCells);
00140 
00141   for (int c=0; c<nCells; c++)
00142     {
00143       elemData[dataSize*c] = mapLIDToGID(dim, c);
00144       elemData[dataSize*c + 1] = ownerProcID(dim, c);
00145       int base = dataSize*c + 2;
00146       int k=0;
00147       for (int d=0; d<dim; d++)
00148         {
00149           for (int f=0; f<nFacets[d]; f++)
00150             {
00151               int orientation;
00152               int lid = facetLID(dim, c, d, f, orientation);
00153               int facetGID = mapLIDToGID(d, lid);
00154               int facetOwner = ownerProcID(d, lid);
00155               elemData[base + k++] = facetGID;
00156               elemData[base + k++] = facetOwner;
00157               if (d > 0)
00158                 {
00159                   int nNodes = numFacets(d, lid, 0);
00160                   for (int v=0; v<nNodes; v++)
00161                     {
00162                       int nodeLID = facetLID(d, lid, 0, v, orientation);
00163                       int nodeGID = mapLIDToGID(0, nodeLID);
00164                       elemData[base + k++] = nodeGID;
00165                     }
00166                 }          
00167             }
00168         }
00169     }
00170 
00171   /* do an all-to-all. AllGather would be better, but we have a clean
00172    * all-to-all implemented */
00173   Array<Array<int> > outData(nProcs);
00174   for (int p=0; p<nProcs; p++)
00175     {
00176       outData[p] = elemData;
00177     }
00178 
00179   Array<Array<int> > inData(nProcs);
00180   
00181   MPIContainerComm<int>::allToAll(outData, inData, comm()); 
00182   
00183   for (int p=0; p<nProcs; p++)
00184     {
00185       Tabs tab1;
00186       if (p==myRank) continue;
00187 
00188       os << tab1 << "p=" << myRank << " testing " << dim 
00189            << "-cells from remote p=" << p << std::endl;
00190       
00191       const Array<int>& remoteData = inData[p];
00192       int nRemote = remoteData.size()/dataSize;
00193       
00194       for (int c=0; c<nRemote; c++)
00195         {
00196           Tabs tab2;
00197           int cellGID = remoteData[dataSize*c];
00198           int cellOwner = remoteData[dataSize*c+1];
00199           int cellLID = -1;
00200           bool elemIsOK = checkRemoteEntity(os, p, dim, cellGID, 
00201                                             cellOwner, false, cellLID);
00202           if (cellLID >= 0 && elemIsOK) 
00203             {
00204               int base = dataSize*c + 2;
00205               int k = 0;
00206               for (int d=0; d<dim; d++)
00207                 {
00208                   Tabs tab3;
00209                   int dir;
00210                   os << tab3 << "checking " << d << "-facets" << std::endl;
00211                   /* The facets may be stored in permuted order on the
00212                    * different processors. We can get a common ordering
00213                    * by sorting them. We define a STL map from facet GID to
00214                    * facet owner, which serves the dual purpose of sorting
00215                    * the facets by GID and preserving the pairing of.
00216                    * GIDs and owners.
00217                    */
00218                   Sundance::Map<int, int> remoteFacetToOwnerMap;
00219                   Sundance::Map<int, int> localFacetToOwnerMap;
00220                   Sundance::Map<int, Set<int> > remoteFacetToNodesMap;
00221                   Sundance::Map<int, Set<int> > localFacetToNodesMap;
00222 
00223                   for (int f=0; f<nFacets[d]; f++)
00224                     {
00225 
00226                       int lfLID = facetLID(dim, cellLID, d, f, dir); 
00227                       int lfGID = mapLIDToGID(d, lfLID);
00228                       int lfOwner = ownerProcID(d, lfLID);
00229                       localFacetToOwnerMap.put(lfGID, lfOwner);
00230                       int rfGID = remoteData[base + k++];
00231                       int rfOwner = remoteData[base + k++];
00232                       remoteFacetToOwnerMap.put(rfGID, rfOwner);
00233                       if (d > 0)
00234                         {
00235                           int numNodes = numFacets(d, 0, 0);
00236                           Sundance::Set<int> localNodes;
00237                           Sundance::Set<int> remoteNodes;
00238                            for (int v=0; v<numNodes; v++)
00239                             {
00240                               int nodeLID = facetLID(d, lfLID, 0, v, dir);
00241                               int nodeGID = mapLIDToGID(0, nodeLID);
00242                               localNodes.put(nodeGID);
00243                               int remoteNodeGID = remoteData[base + k++];
00244                               remoteNodes.put(remoteNodeGID);
00245                             }
00246                            localFacetToNodesMap.put(lfGID, localNodes);
00247                            remoteFacetToNodesMap.put(rfGID, remoteNodes);
00248                         }
00249                     }
00250                   /* Now that the facets are in sorted order, we can 
00251                    * compare them */
00252                   for (Sundance::Map<int,int>::const_iterator 
00253                          rf=remoteFacetToOwnerMap.begin(), 
00254                          lf=localFacetToOwnerMap.begin();
00255                        rf != remoteFacetToOwnerMap.end();
00256                        rf++, lf++)
00257                     {
00258                       int lfGID = lf->first;
00259                       int lfOwner = lf->second;
00260                       int rfGID = lf->first;
00261                       int rfOwner = lf->second;
00262                       Tabs tab4;
00263                       os << tab4 << " local facet GID=" << lfGID
00264                          << " remote GID=" << rfGID 
00265                          << " local Own=" << lfOwner 
00266                          << " remote Own=" << rfOwner << std::endl;
00267                       elemIsOK = testIdentity(os, rfGID, lfGID, 
00268                                               "facet GIDs") && elemIsOK;
00269                       elemIsOK = testIdentity(os, rfOwner, 
00270                                               lfOwner, 
00271                                               "facet owners") && elemIsOK;
00272                       
00273                       if (d > 0)
00274                         {
00275                           Tabs tab5;
00276                           /* compare nodes */
00277                           const Set<int>& localNodes = 
00278                             localFacetToNodesMap.get(lfGID);
00279                           const Set<int>& remoteNodes = 
00280                             remoteFacetToNodesMap.get(rfGID);
00281                           elemIsOK = testIdentity(os, localNodes.elements(),
00282                                                   remoteNodes.elements(), 
00283                                                   "facet nodes") && elemIsOK;
00284                           os << tab5 << "facet node GIDs: local=" 
00285                              << localNodes << " remote=" 
00286                              << remoteNodes << std::endl;
00287                         }
00288                     }
00289                 }
00290             }
00291 
00292           elemsAreOK = elemsAreOK && elemIsOK;
00293         }
00294     }
00295 
00296   return elemsAreOK;
00297 } 
00298 
00299 bool Mesh::testIdentity(std::ostream& os, int a, int b, const std::string& msg) const
00300 {
00301   Tabs tab;
00302   if (a != b)
00303     {
00304       os << tab << "CONFLICT in " << msg << std::endl;
00305       return false;
00306     }
00307   return true;
00308 }
00309 
00310 bool Mesh::testIdentity(std::ostream& os, 
00311                         const Array<int>& a,
00312                         const Array<int>& b, const std::string& msg) const
00313 {
00314   Tabs tab;
00315   bool ok = true;
00316   for (int i=0; i<a.size(); i++)
00317     {
00318       if (a[i] != b[i]) ok = false;
00319     }
00320   if (!ok)
00321     {
00322       os << tab << "CONFLICT in " << msg << std::endl;
00323     }
00324   return ok;
00325 }
00326 
00327 bool Mesh::checkRemoteEntity(std::ostream& os, int p, int dim, int gid, int owner,
00328                              bool mustExist, int& lid) const
00329 {
00330   Tabs tab;
00331   bool isOK = true;
00332 
00333   int myRank = comm().getRank();
00334   lid = -1;
00335   
00336   if (hasGID(dim, gid)) 
00337     {
00338       lid = mapGIDToLID(dim, gid); 
00339       os << tab << "p=" << myRank << " got " 
00340            << dim << "-cell GID=" << gid << " from proc=" << p 
00341            << ", is LID=" << lid << " locally" << std::endl;
00342     }
00343   else
00344     {
00345       os << tab << "p=" << myRank << " got " << dim << "-cell GID=" << gid 
00346            << " from proc=" << p << ", doesn't exist locally" << std::endl;
00347       if (mustExist) isOK = false;
00348     }
00349 
00350   if (lid >= 0)
00351     {
00352       int localOwner = ownerProcID(dim, lid);
00353       os << tab << dim << "-cell GID=" << gid 
00354            << " is locally LID=" << lid << " and owned by "
00355            << localOwner << std::endl;
00356       if (localOwner != owner)
00357         {
00358           os << tab << "OWNERSHIP CONFLICT: local p=" << myRank
00359                << " thinks " << dim << "-cell GID=" << gid << " is owned by "
00360                << localOwner << " but remote proc=" << p
00361                << " says it's owned by " << owner << std::endl;
00362           isOK = false;
00363         }
00364     }
00365 
00366   return isOK;
00367 
00368 }
00369 
00370 
00371 
00372 bool Mesh::checkVertexConsistency(std::ostream& os) const 
00373 {
00374   int dim = spatialDim();
00375   int myRank = comm().getRank();
00376   int nProcs = comm().getNProc();
00377   std::string pHdr = "p=" + Teuchos::toString(myRank);
00378 
00379   Out::println(pHdr + " testing consistency of vertices");
00380 
00381   int dataSize = 2;
00382   Array<int> vertData(dataSize*numCells(0));
00383   Array<double> vertPositions(numCells(0)*dim);
00384   for (int v=0; v<numCells(0); v++)
00385     {
00386       vertData[dataSize*v] = mapLIDToGID(0, v);
00387       vertData[dataSize*v + 1] = ownerProcID(0, v);
00388       Point x = nodePosition(v);
00389       for (int j=0; j<dim; j++)
00390         { 
00391           vertPositions[dim*v + j] = x[j];
00392         }
00393     }
00394 
00395   /* do an all-to-all. AllGather would be better, but we have a clean
00396    * all-to-all implemented */
00397   Array<Array<int> > outData(nProcs);
00398   Array<Array<double> > outPos(nProcs);
00399   for (int p=0; p<nProcs; p++)
00400     {
00401       outData[p] = vertData;
00402       outPos[p] = vertPositions;
00403     }
00404 
00405   Array<Array<int> > inData(nProcs);
00406   Array<Array<double> > inPos(nProcs);
00407 
00408   MPIContainerComm<int>::allToAll(outData,
00409                                   inData,
00410                                   comm()); 
00411 
00412   MPIContainerComm<double>::allToAll(outPos, inPos, comm()); 
00413 
00414   double tol = 1.0e-15;
00415 
00416   bool ok = true;
00417   bool allVertsOK = true;
00418   
00419 
00420   for (int p=0; p<nProcs; p++)
00421     {
00422       Tabs tab1;
00423       if (p==myRank) continue;
00424 
00425       os << tab1 << "p=" << myRank << " testing vertices from remote p="
00426            << p << std::endl;
00427 
00428       int nVerts = inData[p].size()/dataSize;
00429 
00430       for (int v=0; v<nVerts; v++)
00431         {
00432           Tabs tab2;
00433           int vertGID = inData[p][v*dataSize];
00434           int vertOwner = inData[p][v*dataSize+1];
00435           int vertLID = -1;
00436           bool vertIsOK = checkRemoteEntity(os, p, 0, vertGID, vertOwner,
00437                                             false, vertLID);
00438 
00439           if (vertLID >= 0)
00440             {
00441               Point localX = nodePosition(vertLID);
00442               /* copy pt to get size right */
00443               Point remoteX = localX;
00444               for (int j=0; j<dim; j++) remoteX[j] = inPos[p][dim*v + j];
00445               double dx = remoteX.distance(localX);
00446               if (dx > tol) 
00447                 {
00448                   os << tab2 << "POSITION CONFLICT: local p=" << myRank
00449                        << " thinks GID=" << vertGID << " is at xLocal="
00450                        << localX << " but remote proc=" << p
00451                        << " says it's at xRemote" << remoteX << std::endl;
00452                   os << tab2 << "distance = " << dx << std::endl;
00453                   vertIsOK = false;
00454                 }
00455             }
00456           allVertsOK = vertIsOK && allVertsOK;
00457           if (vertIsOK) 
00458             {
00459               os << tab2 << "p=" << myRank 
00460                    << " says vertex GID=" << vertGID << " is OK" << std::endl;
00461             }
00462         }
00463     }
00464 
00465   if (allVertsOK)
00466     {
00467       os << "p=" << myRank << " found all vertex data is OK" << std::endl;
00468     }
00469   else
00470     {
00471       os << "p=" << myRank << " detected conflicts in vertex data" << std::endl;
00472     }
00473 
00474   ok = allVertsOK && ok;
00475 
00476 
00477   
00478   return ok;
00479 }
00480 

Site Contact