SundanceSerialPartitionerBase.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 
00043 #include "SundanceSerialPartitionerBase.hpp"
00044 #include "SundanceMap.hpp"
00045 #include "SundanceBasicSimplicialMeshType.hpp"
00046 
00047 using namespace Sundance;
00048 using namespace Sundance;
00049 
00050 using namespace Teuchos;
00051 using namespace Sundance;
00052 
00053 using std::max;
00054 using std::min;
00055 using std::endl;
00056 using std::cout;
00057 using std::cerr;
00058 
00059 
00060 
00061 Set<int> SerialPartitionerBase::arrayToSet(const Array<int>& a) const
00062 {
00063   Set<int> rtn;
00064   for (int i=0; i<a.size(); i++) 
00065   {
00066     rtn.put(a[i]);
00067   }
00068   return rtn;
00069 }
00070 
00071 int SerialPartitionerBase::max(const Set<int>& s) const
00072 {
00073   return *(s.rbegin());
00074 }
00075 
00076 void SerialPartitionerBase::getNeighbors(const Mesh& mesh, 
00077   Array<Array<int> >& neighbors, int& nEdges) const
00078 {
00079   int dim = mesh.spatialDim();
00080   int nElems = mesh.numCells(dim);
00081   int nVerts = mesh.numCells(0);
00082 
00083   neighbors.resize(nElems);
00084   nEdges = 0;
00085 
00086   elemVerts_.resize(nElems);
00087   elemEdgewiseNbors_.resize(nElems);
00088   vertElems_.resize(nVerts);
00089 
00090   
00091   for (int c=0; c<nElems; c++)
00092   {
00093     Array<int> facetLID;
00094     Array<int> facetDir;
00095     /* Find the vertices associated with this element */
00096     mesh.getFacetArray(dim, c, 0, facetLID, facetDir);
00097     elemVerts_[c] = arrayToSet(facetLID);
00098 
00099     /* Find the neighboring elements that share an edge. Needed for Rivara refinement */
00100     facetLID.resize(0);
00101     facetDir.resize(0);
00102     mesh.getFacetArray(dim, c, 1, facetLID, facetDir);
00103     Set<int> adjElems;
00104     for (int f=0; f<facetLID.size(); f++)
00105     {
00106       Array<int> maxCofs;
00107       mesh.getCofacets(1, facetLID[f], dim, maxCofs);
00108       for (int cf=0; cf<maxCofs.size(); cf++)
00109       {
00110         if (maxCofs[cf] != c) adjElems.put(maxCofs[cf]);
00111       }
00112     }
00113     elemEdgewiseNbors_[c] = adjElems;
00114   }    
00115 
00116   for (int v=0; v<nVerts; v++)
00117   {
00118     Array<int> cofacetLID;
00119     mesh.getCofacets(0, v, dim, cofacetLID);
00120     vertElems_[v] = arrayToSet(cofacetLID);
00121   }    
00122 
00123 
00124   for (int i=0; i<nElems; i++)
00125   {
00126     Set<int> allNbors;
00127     const Set<int>& ev = elemVerts_[i];
00128     for (Set<int>::const_iterator v=ev.begin(); v!=ev.end(); v++)
00129     {
00130       allNbors = allNbors.setUnion(vertElems_[*v]);
00131     }
00132     allNbors.erase(i);
00133     
00134     Array<int> fullNbors;
00135     for (Set<int>::const_iterator j=allNbors.begin(); j!=allNbors.end(); j++)
00136     {
00137       Set<int> numCommonNodes = elemVerts_[i].intersection(elemVerts_[*j]);
00138       if ((int) numCommonNodes.size() == dim) fullNbors.append(*j);
00139     }
00140     nEdges += fullNbors.size();
00141     neighbors[i] = fullNbors;
00142   }
00143 
00144   nEdges = nEdges/2;
00145 }
00146 
00147 
00148 void SerialPartitionerBase::getNodeAssignments(int nProc, 
00149   const Array<int>& elemAssignments,
00150   Array<int>& nodeAssignments,
00151   Array<int>& nodeOwnerElems,
00152   Array<int>& nodesPerProc) const
00153 {
00154   nodesPerProc.resize(nProc);
00155   nodeAssignments.resize(vertElems_.size());
00156   nodeOwnerElems.resize(vertElems_.size());
00157 
00158   for (int i=0; i<nodesPerProc.size(); i++) nodesPerProc[i] = 0;
00159 
00160   for (int v=0; v<vertElems_.size(); v++)
00161   {
00162     /* assign the vertex to the highest-numbered cofacet */
00163     int ownerElem = max(vertElems_[v]);
00164     nodeOwnerElems[v] = ownerElem;
00165     nodeAssignments[v] = elemAssignments[ownerElem];
00166     nodesPerProc[nodeAssignments[v]]++;
00167   }
00168 }
00169 
00170 void SerialPartitionerBase::getElemsPerProc(int nProc, 
00171   const Array<int>& elemAssignments,
00172   Array<int>& elemsPerProc) const 
00173 {
00174   elemsPerProc.resize(nProc);
00175   for (int i=0; i<elemsPerProc.size(); i++) elemsPerProc[i] = 0;
00176 
00177   for (int e=0; e<elemAssignments.size(); e++)
00178   {
00179     elemsPerProc[elemAssignments[e]]++;
00180   }
00181 }
00182 
00183 void SerialPartitionerBase::remapEntities(const Array<int>& assignments, 
00184   int nProc,
00185   Array<int>& entityMap) const 
00186 {
00187   Array<Array<int> > procBuckets(nProc);
00188   entityMap.resize(assignments.size());
00189 
00190   for (int i=0; i<assignments.size(); i++)
00191   {
00192     procBuckets[assignments[i]].append(i);
00193   }
00194 
00195   int g = 0;
00196   
00197   for (int p=0; p<nProc; p++)
00198   {
00199     for (int i=0; i<procBuckets[p].size(); i++)
00200     {
00201       int lid = procBuckets[p][i];
00202       entityMap[lid] = g++;
00203     }
00204   }
00205 }
00206 
00207 
00208 void SerialPartitionerBase::getOffProcData(int p, 
00209   const Array<int>& elemAssignments,
00210   const Array<int>& nodeAssignments,
00211   Set<int>& offProcNodes,
00212   Set<int>& offProcElems) const
00213 {
00214   Out::root() << "ignore ghosts = " << ignoreGhosts_ << endl;
00215   /* first pass: find off-proc nodes and elems required by on-proc elems */
00216   for (int e=0; e<elemAssignments.size(); e++)
00217   {
00218     if (elemAssignments[e] != p) continue;
00219     for (Set<int>::const_iterator v=elemVerts_[e].begin(); v!=elemVerts_[e].end(); v++)
00220     {
00221       if (nodeAssignments[*v]!=p) offProcNodes.put(*v);
00222     }
00223     if (!ignoreGhosts_)
00224     {
00225       for (Set<int>::const_iterator 
00226              n=elemEdgewiseNbors_[e].begin(); n!=elemEdgewiseNbors_[e].end(); n++)
00227       {
00228         if (elemAssignments[*n]!=p) offProcElems.put(*n);
00229       }
00230     }
00231   }
00232 
00233   if (!ignoreGhosts_)
00234   {
00235     /* second pass: find off-proc elems required by the on-proc nodes */
00236     for (int v=0; v<nodeAssignments.size(); v++)
00237     {
00238       if (nodeAssignments[v] != p) continue;
00239       const Set<int>& v2e = vertElems_[v];
00240       for (Set<int>::const_iterator e=v2e.begin(); e!=v2e.end(); e++)
00241       {
00242         if (elemAssignments[*e] != p) offProcElems.put(*e);
00243       }
00244     }
00245 
00246     /* third pass: find the additional nodes required by the off-proc
00247      * elems found in the previous step */
00248     for (Set<int>::const_iterator e=offProcElems.begin(); e!=offProcElems.end(); e++)
00249     {
00250       for (Set<int>::const_iterator v=elemVerts_[*e].begin(); v!=elemVerts_[*e].end(); v++)
00251       {
00252         if (nodeAssignments[*v]!=p) offProcNodes.put(*v);
00253       }
00254     }
00255   }  
00256 }
00257 
00258 
00259 Array<Mesh> SerialPartitionerBase::makeMeshParts(const Mesh& mesh, int np,
00260   Array<Sundance::Map<int, int> >& oldElemLIDToNewLIDMaps,
00261   Array<Sundance::Map<int, int> >& oldVertLIDToNewLIDMaps) const 
00262 {
00263   int dim = mesh.spatialDim();
00264 
00265   Array<int> elemAssignments;
00266   Array<int> nodeAssignments;
00267   Array<int> nodeOwnerElems;
00268   Array<int> nodesPerProc;
00269   
00270   getAssignments(mesh, np, elemAssignments);
00271 
00272   getNodeAssignments(np, elemAssignments, nodeAssignments, nodeOwnerElems,
00273     nodesPerProc);
00274 
00275   Array<Array<int> > offProcNodes(np);
00276   Array<Array<int> > offProcElems(np);
00277 
00278   Array<Set<int> > offProcNodeSet(np);
00279   Array<Set<int> > offProcElemSet(np);
00280 
00281   Array<Array<int> > procNodes(np);
00282   Array<Array<int> > procElems(np);
00283 
00284   for (int p=0; p<np; p++)
00285   {
00286     getOffProcData(p, elemAssignments, nodeAssignments, 
00287       offProcNodeSet[p], offProcElemSet[p]);
00288     offProcNodes[p] = offProcNodeSet[p].elements();
00289     offProcElems[p] = offProcElemSet[p].elements();
00290     procElems[p].reserve(elemAssignments.size()/np);
00291     procNodes[p].reserve(nodeAssignments.size()/np);
00292   }
00293 
00294   Array<int> remappedElems;
00295   Array<int> remappedNodes;
00296 
00297   remapEntities(elemAssignments, np, remappedElems);
00298   remapEntities(nodeAssignments, np, remappedNodes);
00299 
00300   for (int e=0; e<elemAssignments.size(); e++)
00301   {
00302     procElems[elemAssignments[e]].append(e);
00303   }
00304 
00305   for (int n=0; n<nodeAssignments.size(); n++)
00306   {
00307     procNodes[nodeAssignments[n]].append(n);
00308   }
00309 
00310   /* Now we make NP submeshes */
00311   Array<Mesh> rtn(np);
00312   oldVertLIDToNewLIDMaps.resize(np);
00313   oldElemLIDToNewLIDMaps.resize(np);
00314   for (int p=0; p<np; p++)
00315   {
00316     Sundance::Map<int, int>& oldVertLIDToNewLIDMap 
00317       = oldVertLIDToNewLIDMaps[p];
00318     Sundance::Map<int, int>& oldElemLIDToNewLIDMap 
00319       = oldElemLIDToNewLIDMaps[p];
00320     MeshType type = new BasicSimplicialMeshType();
00321     rtn[p] = type.createEmptyMesh(mesh.spatialDim(), MPIComm::world());
00322 
00323     Set<int> unusedVertGID;
00324 
00325     /* add the on-processor nodes */
00326     for (int n=0; n<procNodes[p].size(); n++)
00327     {
00328       int oldLID = procNodes[p][n];
00329       int newGID = remappedNodes[oldLID];
00330       unusedVertGID.put(newGID);
00331       int newLID = rtn[p].addVertex(newGID, mesh.nodePosition(oldLID), p, 0);
00332       oldVertLIDToNewLIDMap.put(oldLID, newLID);
00333     }
00334 
00335     /* add the off-processor nodes */
00336     for (int n=0; n<offProcNodes[p].size(); n++)
00337     {
00338       int oldLID = offProcNodes[p][n];
00339       int nodeOwnerProc = nodeAssignments[oldLID];
00340       int newGID = remappedNodes[oldLID];
00341       unusedVertGID.put(newGID);
00342       int newLID = rtn[p].addVertex(newGID, mesh.nodePosition(oldLID), nodeOwnerProc, 0);
00343       oldVertLIDToNewLIDMap.put(oldLID, newLID);
00344     }
00345     
00346     /* add the on-processor elements */
00347     for (int e=0; e<procElems[p].size(); e++)
00348     {
00349       int oldLID = procElems[p][e];
00350       int newGID = remappedElems[oldLID];
00351       Array<int> vertGIDs;
00352       Array<int> orientations;
00353       mesh.getFacetArray(dim, oldLID, 0, vertGIDs, orientations);
00354       for (int v=0; v<vertGIDs.size(); v++)
00355       {
00356         vertGIDs[v] = remappedNodes[vertGIDs[v]];
00357         if (unusedVertGID.contains(vertGIDs[v])) unusedVertGID.erase(newGID);
00358       }
00359       int newLID = rtn[p].addElement(newGID, vertGIDs, p, 1);
00360       oldElemLIDToNewLIDMap.put(oldLID, newLID);
00361     }
00362     
00363     /* add the off-processor elements */
00364     for (int e=0; e<offProcElems[p].size(); e++)
00365     {
00366       int oldLID = offProcElems[p][e];
00367       int newGID = remappedElems[oldLID];
00368       int elemOwnerProc = elemAssignments[oldLID];
00369       Array<int> vertGIDs;
00370       Array<int> orientations;
00371       mesh.getFacetArray(dim, oldLID, 0, vertGIDs, orientations);
00372       for (int v=0; v<vertGIDs.size(); v++)
00373       {
00374         vertGIDs[v] = remappedNodes[vertGIDs[v]];
00375         if (unusedVertGID.contains(vertGIDs[v])) unusedVertGID.erase(newGID);
00376       }
00377       int newLID = rtn[p].addElement(newGID, vertGIDs, elemOwnerProc, 1);
00378       oldElemLIDToNewLIDMap.put(oldLID, newLID);
00379 
00380 //      TEUCHOS_TEST_FOR_EXCEPTION(unusedVertGID.size() != 0, std::logic_error,
00381 //        "unused vertices=" << unusedVertGID);
00382     }
00383 
00384     /* Now, propagate the labels of any intermediate-dimension cells
00385      * to the submesh */
00386     for (int d=1; d<dim; d++)
00387     {
00388       Set<int> labels = mesh.getAllLabelsForDimension(d);
00389       for (Set<int>::const_iterator i=labels.begin(); i!=labels.end(); i++)
00390       {
00391         Array<int> labeledCells;
00392         int label = *i;
00393         if (label == 0) continue;
00394         mesh.getLIDsForLabel(d, label, labeledCells);
00395         for (int c=0; c<labeledCells.size(); c++)
00396         {
00397           int lid = labeledCells[c];
00398           Array<int> cofacets;
00399           mesh.getCofacets(d, lid, dim, cofacets);
00400           for (int n=0; n<cofacets.size(); n++)
00401           {
00402             int cofLID = cofacets[n];
00403             if (elemAssignments[cofLID]==p 
00404               || offProcElemSet[p].contains(cofLID))
00405             {
00406               /* at this point we need to find the facet index of the side
00407                * relative to the new element. */
00408               
00409               /* find vertices of old cell */
00410               Array<int> oldVerts;
00411               Array<int> newVerts;
00412               Array<int> orientation;
00413               mesh.getFacetArray(d, lid, 0, oldVerts, orientation);
00414               for (int v=0; v<oldVerts.size(); v++)
00415               {
00416                 newVerts.append(remappedNodes[oldVerts[v]]);
00417               }
00418               /* Put the vertices in a set. This will let us compare to the
00419                * vertex sets in the new submesh. */
00420               Set<int> newVertSet = arrayToSet(newVerts);
00421               
00422               /* Find the cofacet in the new submesh */
00423               int newElemLID = oldElemLIDToNewLIDMap.get(cofLID);
00424 
00425               /* Get the d-facets of the element in the new submesh */
00426               Array<int> submeshFacets;
00427               rtn[p].getFacetArray(dim, newElemLID, d, 
00428                 submeshFacets, orientation);
00429               int facetIndex = -1;
00430               for (int df=0; df<submeshFacets.size(); df++)
00431               {
00432                 /* Get the vertices of this d-facet */
00433                 int facetLID = submeshFacets[df];
00434                 Array<int> verts;
00435                 rtn[p].getFacetArray(d, facetLID, 0, verts, orientation);
00436                 Array<int> vertGID(verts.size());
00437                 for (int v=0; v<verts.size(); v++)
00438                 {
00439                   vertGID[v] = rtn[p].mapLIDToGID(0, verts[v]);
00440                 }
00441                 Set<int> subVertSet = arrayToSet(vertGID);
00442                 if (subVertSet==newVertSet)
00443                 {
00444                   facetIndex = df;
00445                   break;
00446                 }
00447               }
00448               TEUCHOS_TEST_FOR_EXCEPTION(facetIndex==-1, std::logic_error,
00449                 "couldn't match new " << d << "-cell in submesh to old " << d
00450                 << "cell. This should never happen");
00451 
00452               /* OK, now we have the d-cell's facet index relative to one
00453                * of its cofacets existing on the new submesh. We now
00454                * find the LID of the d-cell so we can set its label */
00455               int o;  // dummy orientation variable; not needed here
00456               int newFacetLID = rtn[p].facetLID(dim, newElemLID, d, 
00457                 facetIndex, o);
00458               /* Set the label, finally! */
00459               rtn[p].setLabel(d, newFacetLID, label);
00460               break; /* no need to continue the loop over cofacets once 
00461                       * we've set the label */
00462             }
00463             else
00464             {
00465             }
00466           }
00467         }
00468       }
00469     }
00470   }
00471 
00472   return rtn;
00473 }
00474 
00475 

Site Contact