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

Site Contact