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

Site Contact