SundanceInhomogeneousNodalDOFMap.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 "SundanceMap.hpp"
00032 #include "SundanceTabs.hpp"
00033 #include "SundanceOut.hpp"
00034 #include "SundanceOrderedTuple.hpp"
00035 #include "SundanceInhomogeneousNodalDOFMap.hpp"
00036 #include "SundanceLagrange.hpp"
00037 #include "Teuchos_MPIContainerComm.hpp"
00038 #include "Teuchos_TimeMonitor.hpp"
00039 
00040 using namespace Sundance;
00041 using namespace Sundance;
00042 using namespace Sundance;
00043 using namespace Teuchos;
00044 
00045 
00046 InhomogeneousNodalDOFMap
00047 ::InhomogeneousNodalDOFMap(const Mesh& mesh, 
00048   const Array<Map<Set<int>, CellFilter> >& funcSetToDomainMap,
00049   int setupVerb)
00050   : DOFMapBase(mesh, setupVerb),
00051     dim_(mesh.spatialDim()),
00052     basis_(rcp(new Lagrange(1))),
00053     nTotalFuncs_(),
00054     funcDomains_(),
00055     nodeDofs_(),
00056     elemDofs_(),
00057     nodeToFuncSetIndexMap_(mesh.numCells(0)),
00058     elemToFuncSetIndexMap_(mesh.numCells(dim_)),
00059     elemFuncSets_(),
00060     nodalFuncSets_(),
00061     nodeToOffsetMap_(mesh.numCells(0)),
00062     elemToOffsetMap_(mesh.numCells(0)),
00063     funcIndexWithinNodeFuncSet_(),
00064     elemStructure_(),
00065     nodeStructure_()
00066 {
00067   SUNDANCE_MSG1(setupVerb, "in InhomogeneousNodalDOFMap ctor");
00068   SUNDANCE_MSG2(setupVerb, "func set to domain map " << funcSetToDomainMap);
00069 
00070   /* count the total number of functions across all subdomains */
00071   Set<int> allFuncs;
00072   for (int d=dim_; d>=0; d--)
00073   {
00074     for (Map<Set<int>, CellFilter>::const_iterator 
00075            i=funcSetToDomainMap[d].begin(); i!=funcSetToDomainMap[d].end(); i++)
00076     {
00077       allFuncs.merge(i->first);
00078     }
00079   }
00080 
00081   
00082   nTotalFuncs_ = allFuncs.size();
00083   SUNDANCE_MSG2(setupVerb, "found " << nTotalFuncs_ << " functions");
00084   
00085 
00086   /* get flat arrays of subdomains and function arrays */
00087   Array<CellFilter> subdomains;
00088   Array<CellFilter> maxSubdomains;
00089   Array<Array<int> > funcArrays;
00090   Array<Set<int> > funcSets;
00091 
00092   for (int d=dim_; d>=0; d--)
00093   {
00094     for (Map<Set<int>, CellFilter>::const_iterator 
00095            i=funcSetToDomainMap[d].begin(); i!=funcSetToDomainMap[d].end(); i++)
00096     {
00097       subdomains.append(i->second);
00098       if (d==dim_) 
00099       {
00100         elemFuncSets_.append(i->first);
00101         maxSubdomains.append(i->second);
00102       }
00103 
00104       Array<int> myFuncs = i->first.elements();
00105       funcArrays.append(myFuncs);
00106       funcSets.append(i->first);
00107     }
00108   }
00109 
00110 
00111   /* determine the functions appearing at each node */
00112 
00113 
00114 
00115   Array<Array<int> > cellLIDs(subdomains.size());
00116   Array<Array<int> > facetLIDs(subdomains.size());
00117   Array<Array<int> > facetOrientations(subdomains.size());
00118   Array<Set<int> > nodeToFuncSetMap(mesh.numCells(0));
00119 
00120   for (int r=0; r<subdomains.size(); r++)
00121   {
00122     int d = subdomains[r].dimension(mesh);
00123     CellSet cells = subdomains[r].getCells(mesh);
00124     SUNDANCE_MSG2(setupVerb, "domain " << subdomains[r] << " has functions "
00125       << funcSets[r]);
00126       
00127     for (CellIterator c=cells.begin(); c!=cells.end(); c++)
00128     {
00129       int cellLID = *c;
00130       cellLIDs[r].append(cellLID);
00131     }
00132     if (cellLIDs[r].size()==0) continue; 
00133     int nFacets = mesh.numFacets(d, cellLIDs[r][0], 0);
00134     if (d==0)
00135     {
00136       for (int c=0; c<cellLIDs[r].size(); c++)
00137       {
00138         int fLID = cellLIDs[r][c];
00139         nodeToFuncSetMap[fLID].merge(funcSets[r]);
00140       }
00141     }
00142     else
00143     {
00144       Array<int>& facetLID = facetLIDs[r];
00145       facetLID.resize(nFacets*cellLIDs[r].size());
00146       facetOrientations[r].resize(nFacets*cellLIDs[r].size());
00147       mesh.getFacetLIDs(d, cellLIDs[r], 0, facetLID, facetOrientations[r]);
00148       for (int c=0; c<cellLIDs[r].size(); c++)
00149       {
00150         for (int f=0; f<nFacets; f++)
00151         {
00152           int fLID = facetLID[c*nFacets+f];
00153           nodeToFuncSetMap[fLID].merge(funcSets[r]);
00154         }
00155       }
00156     }
00157   }
00158 
00159   /* find the distinct combinations of functions at the nodes */
00160 
00161   Map<Set<int>, int> fsToFSIndexMap;
00162   Array<int> funcSetNodeCounts;
00163   int nNodes = mesh.numCells(0);
00164 
00165   for (int n=0; n<nNodes; n++)
00166   {
00167     const Set<int>& f = nodeToFuncSetMap[n];
00168     if (f.size()==0) continue;
00169     int funcComboIndex;
00170     if (!fsToFSIndexMap.containsKey(f)) 
00171     {
00172       funcComboIndex = nodalFuncSets_.size();
00173       fsToFSIndexMap.put(f, funcComboIndex);
00174       nodalFuncSets_.append(f);
00175       funcSetNodeCounts.append(1);
00176       nodeToOffsetMap_[n] = 0;
00177     }
00178     else
00179     {
00180       funcComboIndex = fsToFSIndexMap.get(f);
00181       nodeToOffsetMap_[n] = f.size() * funcSetNodeCounts[funcComboIndex];
00182       funcSetNodeCounts[funcComboIndex]++;
00183     }
00184     nodeToFuncSetIndexMap_[n] = funcComboIndex;
00185   }
00186 
00187   SUNDANCE_MSG2(setupVerb, "nodal func sets = " << nodalFuncSets_);
00188 
00189   nodeDofs_.resize(nodalFuncSets_.size());
00190   nodeStructure_.resize(nodalFuncSets_.size());
00191   funcIndexWithinNodeFuncSet_.resize(nodalFuncSets_.size());
00192 
00193   for (int f=0; f<nodalFuncSets_.size(); f++)
00194   {
00195     Array<int> funcs = nodalFuncSets_[f].elements();
00196     int nFuncs = funcs.size();
00197     funcIndexWithinNodeFuncSet_[f] = Array<int>(nTotalFuncs_, -1);
00198     for (int i=0; i<nFuncs; i++)
00199     {
00200       funcIndexWithinNodeFuncSet_[f][funcs[i]] = i;
00201     }
00202     nodeDofs_[f].resize(nFuncs * funcSetNodeCounts[f]);
00203     Array<RCP<BasisDOFTopologyBase> > nodeBases = tuple(basis_);
00204     Array<Array<int> > nodeFuncs = tuple(nodalFuncSets_[f].elements());
00205     nodeStructure_[f] = rcp(new MapStructure(nTotalFuncs_, 
00206         nodeBases, nodeFuncs));
00207   }
00208 
00209 
00210 
00211   /* second pass to assign node DOFs */
00212   int nextDOF = 0;
00213   Array<int> hasProcessedNode(nNodes);
00214   Array<Array<int> > remoteNodes(mesh.comm().getNProc());
00215 
00216   for (int r=0; r<subdomains.size(); r++)
00217   {
00218     int d = subdomains[r].dimension(mesh);
00219 
00220     if (cellLIDs[r].size()==0) continue; 
00221 
00222     if (d==0)
00223     {
00224       for (int c=0; c<cellLIDs[r].size(); c++)
00225       {
00226         int fLID = cellLIDs[r][c];
00227         int funcSetIndex = nodeToFuncSetIndexMap_[fLID];
00228         int nFuncs = nodalFuncSets_[funcSetIndex].size();
00229         int dofOffset = nodeToOffsetMap_[fLID];
00230         if (!hasProcessedNode[fLID])
00231         {
00232           assignNode(fLID, funcSetIndex, dofOffset, nFuncs,
00233             remoteNodes, hasProcessedNode, nextDOF);
00234         }
00235       }
00236     }
00237     else
00238     {
00239       Array<int>& facetLID = facetLIDs[r];
00240       int nFacets = mesh.numFacets(d, cellLIDs[r][0], 0);      
00241       for (int c=0; c<cellLIDs[r].size(); c++)
00242       {
00243         for (int f=0; f<nFacets; f++)
00244         {
00245           int fLID = facetLID[c*nFacets+f];
00246           int funcSetIndex = nodeToFuncSetIndexMap_[fLID];
00247           int dofOffset = nodeToOffsetMap_[fLID];
00248           int nFuncs = nodalFuncSets_[funcSetIndex].size();
00249           if (!hasProcessedNode[fLID])
00250           {
00251             assignNode(fLID, funcSetIndex, dofOffset, nFuncs,
00252               remoteNodes, hasProcessedNode, nextDOF);
00253           }
00254         }
00255       }
00256     }
00257   }
00258 
00259 
00260   /* Compute offsets for each processor */
00261   int localCount = nextDOF;
00262   computeOffsets(localCount);
00263   
00264   /* Resolve remote DOF numbers */
00265   shareRemoteDOFs(remoteNodes);
00266 
00267   /* Build dof tables for elements */
00268   elemDofs_.resize(maxSubdomains.size());
00269   int count = 0;
00270   Array<Array<int> > elemFuncArrays;
00271   
00272   funcDomains_.resize(nTotalFuncs_);
00273 
00274   for (int r=0; r<subdomains.size(); r++)
00275   {
00276     int d = subdomains[r].dimension(mesh);
00277     if (d != dim_) continue;
00278     if (cellLIDs[r].size()==0) continue; 
00279     int nFacets = mesh.numFacets(d, cellLIDs[r][0], 0);      
00280     Array<int>& facetLID = facetLIDs[r];
00281     Array<Array<int> > dofs(1);
00282     dofs[0].resize(funcArrays[r].size() * cellLIDs[r].size() * nFacets);
00283     getFunctionDofs(d, cellLIDs[r], facetLID, funcArrays[r], dofs);
00284     elemDofs_[count] = dofs[0];
00285     elemFuncArrays.append(funcArrays[r]);
00286     Array<RCP<BasisDOFTopologyBase> > elemBases = tuple(basis_);
00287     Array<Array<int> > elemFuncs = tuple(elemFuncSets_[count].elements());
00288     elemStructure_.append(rcp(new MapStructure(nTotalFuncs_, 
00289           elemBases, elemFuncs)));
00290     for (int c=0; c<cellLIDs[r].size(); c++)
00291     {
00292       elemToFuncSetIndexMap_[cellLIDs[r][c]] = count;
00293     }
00294     for (int i=0; i<elemFuncs[0].size(); i++)
00295     {
00296       funcDomains_[elemFuncs[0][i]] = funcDomains_[elemFuncs[0][i]] + subdomains[r];
00297     }
00298     count++;
00299   }
00300   
00301 }
00302 
00303 
00304 void InhomogeneousNodalDOFMap::getFunctionDofs(int cellDim,
00305   const Array<int>& cellLID,
00306   const Array<int>& facetLID,
00307   const Array<int>& funcs,
00308   Array<Array<int> >& dofs) const
00309 {
00310   Array<int>& dofChunk = dofs[0];
00311 
00312   if (cellDim != 0)
00313   {
00314     int nFacets = mesh().numFacets(cellDim, cellLID[0], 0);
00315     dofChunk.resize(funcs.size() * cellLID.size() * nFacets);
00316       
00317       
00318     for (int c=0; c<cellLID.size(); c++)
00319     {
00320       for (int f=0; f<nFacets; f++)
00321       {
00322         int fLID = facetLID[c*nFacets + f];
00323         int fci = nodeToFuncSetIndexMap_[fLID];
00324         int nodeOffset = nodeToOffsetMap_[fLID];
00325         for (int i=0; i<funcs.size(); i++)
00326         {
00327           int funcIndex = funcIndexWithinNodeFuncSet_[fci][funcs[i]];
00328           dofChunk[(c*funcs.size()+i)*nFacets + f] 
00329             = nodeDofs_[fci][nodeOffset+funcIndex];
00330         }
00331       }
00332     }
00333   }
00334   else
00335   {
00336     dofChunk.resize(funcs.size() * cellLID.size());
00337 
00338     for (int c=0; c<cellLID.size(); c++)
00339     {
00340       int fci = nodeToFuncSetIndexMap_[cellLID[c]];
00341       int nodeOffset = nodeToOffsetMap_[cellLID[c]];
00342       for (int i=0; i<funcs.size(); i++)
00343       {
00344         int funcIndex = funcIndexWithinNodeFuncSet_[fci][funcs[i]];
00345         dofChunk[c*funcs.size()+ i] 
00346           = nodeDofs_[fci][nodeOffset+funcIndex];
00347       }
00348     }
00349   }
00350 }
00351 
00352 void InhomogeneousNodalDOFMap::assignNode(int fLID,
00353   int funcSetIndex,
00354   int dofOffset,
00355   int nFuncs,
00356   Array<Array<int> >& remoteNodes,
00357   Array<int>& hasProcessedCell,
00358   int& nextDOF)
00359 {
00360   /* the facet may be owned by another processor */
00361   int owner;
00362   if (isRemote(0, fLID, owner))
00363   {
00364     int facetGID 
00365       = mesh().mapLIDToGID(0, fLID);
00366     remoteNodes[owner].append(facetGID);
00367       
00368   }
00369   else /* we can assign a DOF locally */
00370   {
00371     /* assign DOFs */
00372     Array<int>& myDofs = nodeDofs_[funcSetIndex];
00373     for (int i=0; i<nFuncs; i++)
00374     {
00375       myDofs[dofOffset + i] = nextDOF;
00376       nextDOF++;
00377     }
00378   }
00379   hasProcessedCell[fLID] = 1;
00380 }
00381 
00382 void InhomogeneousNodalDOFMap::computeOffsets(int localCount)
00383 {
00384   TEST_FOR_EXCEPTION(mesh().comm().getNProc() != 1,
00385     RuntimeError,
00386     "parallel inhomogeneous DOF maps not yet supported");
00387   
00388   int totalDOFCount = localCount;
00389   int myOffset = 0;
00390   setLowestLocalDOF(myOffset);
00391   setNumLocalDOFs(localCount);
00392   setTotalNumDOFs(totalDOFCount);
00393 }
00394 
00395 void InhomogeneousNodalDOFMap::shareRemoteDOFs(const Array<Array<int> >& remoteNodes)
00396 {
00397   TEST_FOR_EXCEPTION(mesh().comm().getNProc() != 1,
00398     RuntimeError,
00399     "parallel inhomogeneous DOF maps not yet supported");
00400 }
00401 
00402 RCP<const Set<int> >
00403 InhomogeneousNodalDOFMap::allowedFuncsOnCellBatch(int cellDim,
00404   const Array<int>& cellLID) const 
00405 {
00406   Set<int> rtn;
00407 
00408   if (cellDim==0)
00409   {
00410     rtn = nodalFuncSets_[nodeToFuncSetIndexMap_[cellLID[0]]];
00411     for (int c=0; c<cellLID.size(); c++) 
00412     {
00413       const Set<int>& s = nodalFuncSets_[nodeToFuncSetIndexMap_[cellLID[c]]];
00414       rtn = rtn.intersection(s);
00415     }
00416   }
00417   else if (cellDim==dim_)
00418   {
00419     rtn = elemFuncSets_[elemToFuncSetIndexMap_[cellLID[0]]];
00420     for (int c=0; c<cellLID.size(); c++) 
00421     {
00422       const Set<int>& s = elemFuncSets_[elemToFuncSetIndexMap_[cellLID[c]]];
00423       rtn = rtn.intersection(s);
00424     }
00425   }
00426   else
00427   {
00428     Array<int> facetLID;
00429     Array<int> facetOrientations;
00430     mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00431     rtn = nodalFuncSets_[nodeToFuncSetIndexMap_[facetLID[0]]];
00432     for (int f=0; f<facetLID.size(); f++)
00433     {
00434       const Set<int>& s = nodalFuncSets_[nodeToFuncSetIndexMap_[facetLID[f]]];
00435       rtn = rtn.intersection(s);
00436     }
00437   }
00438   return rcp(new Set<int>(rtn));
00439 }
00440 
00441 
00442 RCP<const MapStructure> 
00443 InhomogeneousNodalDOFMap::getDOFsForCellBatch(int cellDim,
00444   const Array<int>& cellLID,
00445   const Set<int>& requestedFuncSet,
00446   Array<Array<int> >& dofs,
00447   Array<int>& nNodes,
00448   int verb) const 
00449 {
00450   TimeMonitor timer(batchedDofLookupTimer());
00451   Tabs tab0;
00452 
00453   SUNDANCE_MSG2(verb, tab0 << "in InhomNodalDOFMap::getDOFsForCellBatch()");
00454 
00455   if (cellDim==0)
00456   {
00457     Tabs tab1;
00458     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00459     bool isHomogeneous = true;
00460     int firstFuncSet = nodeToFuncSetIndexMap_[cellLID[0]];
00461     for (int c=0; c<cellLID.size(); c++)
00462     {
00463       if (nodeToFuncSetIndexMap_[cellLID[c]] != firstFuncSet) 
00464       {
00465         isHomogeneous = false;
00466         break;
00467       }
00468     }
00469 
00470     dofs.resize(1);
00471     nNodes.resize(1);
00472     nNodes[0] = 1;
00473     Array<int> dummyFacets;
00474 
00475     if (isHomogeneous)
00476     {
00477       const Set<int>& funcSet = nodalFuncSets_[firstFuncSet];
00478       TEST_FOR_EXCEPT(requestedFuncSet.setDifference(funcSet).size() != 0);
00479       Array<int> funcs = funcSet.elements();
00480       getFunctionDofs(cellDim, cellLID, dummyFacets, funcs, dofs);
00481       return nodeStructure_[firstFuncSet];
00482     }
00483     else
00484     {
00485       Array<int> funcs = requestedFuncSet.elements();
00486       getFunctionDofs(cellDim, cellLID, dummyFacets, funcs, dofs);
00487       RCP<const MapStructure> rtn 
00488         = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00489       return rtn;
00490     }
00491   }
00492   else if (cellDim==dim_)
00493   {
00494     Tabs tab1;
00495     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00496     bool isHomogeneous = true;
00497     int firstFuncSet = elemToFuncSetIndexMap_[cellLID[0]];
00498     SUNDANCE_MSG2(verb, tab1 << "first func set = " << firstFuncSet);
00499     for (int c=0; c<cellLID.size(); c++)
00500     {
00501       if (elemToFuncSetIndexMap_[cellLID[c]] != firstFuncSet) 
00502       {
00503         isHomogeneous = false;
00504         break;
00505       }
00506     }
00507 
00508     dofs.resize(1);
00509     nNodes.resize(1);
00510     nNodes[0] = mesh().numFacets(cellDim, cellLID[0], 0);
00511 
00512     if (isHomogeneous)
00513     {
00514       Tabs tab2;
00515       Array<int> facetLID;
00516       Array<int> facetOrientations;
00517       mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00518       if (verb >= 2)
00519       {
00520         Out::os() << tab2 << "cellLID = " << cellLID << std::endl;
00521         Out::os() << tab2 << "facetLID = " << facetLID << std::endl;
00522         Out::os() << tab2 << "elem func sets = " << elemFuncSets_ << std::endl;
00523       }
00524       const Set<int>& funcSet = elemFuncSets_[firstFuncSet];
00525       TEST_FOR_EXCEPT(requestedFuncSet.setDifference(funcSet).size() != 0);
00526       Array<int> funcs = funcSet.elements();
00527       getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00528       return elemStructure_[firstFuncSet];
00529     }
00530     else
00531     {
00532       Array<int> facetLID;
00533       Array<int> facetOrientations;
00534       mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00535       Array<int> funcs = requestedFuncSet.elements();
00536       getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00537       RCP<const MapStructure> rtn 
00538         = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00539       return rtn;
00540     }
00541   }
00542   else
00543   {
00544     Tabs tab1;
00545     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00546     Array<int> facetLID;
00547     Array<int> facetOrientations;
00548     mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00549     dofs.resize(1);
00550     nNodes.resize(1);
00551     nNodes[0] = mesh().numFacets(cellDim, cellLID[0], 0);
00552 
00553     Array<int> funcs = requestedFuncSet.elements();
00554 
00555     getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00556     RCP<const MapStructure> rtn 
00557       = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00558     return rtn;
00559   }
00560 }
00561 
00562 
00563 
00564 void InhomogeneousNodalDOFMap::print(std::ostream& os) const
00565 {
00566   Tabs tab0;
00567   std::cout << tab0 << "dof map: " << std::endl;
00568   for (int d=0; d<=dim_; d++)
00569   {
00570     Tabs tab1;
00571     std::cout << tab1 << d << "-cells: " << std::endl;
00572     for (int n=0; n<mesh().numCells(d); n++)
00573     {
00574       Tabs tab2;
00575       std::cout << tab2 << "d=" << d << " cell=" << n << std::endl;
00576       RCP<const Set<int> > funcs = allowedFuncsOnCellBatch(d, tuple(n));
00577       for (Set<int>::const_iterator f=funcs->begin(); f!=funcs->end(); f++)
00578       {
00579         Tabs tab3;
00580         Array<int> dofs;
00581         getDOFsForCell(d, n, *f, dofs);
00582         std::cout << tab3 << " f=" << *f << " dofs=" << dofs << std::endl;
00583       }
00584     }
00585   }
00586 }

Site Contact