00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #include "SundanceMap.hpp"
00032 #include "PlayaTabs.hpp"
00033 #include "SundanceOut.hpp"
00034 #include "SundanceOrderedTuple.hpp"
00035 #include "SundanceInhomogeneousNodalDOFMap.hpp"
00036 #include "SundanceLagrange.hpp"
00037 #include "PlayaMPIContainerComm.hpp"
00038 #include "Teuchos_TimeMonitor.hpp"
00039 
00040 using namespace Sundance;
00041 using namespace Teuchos;
00042 using Playa::MPIComm;
00043 using Playa::MPIContainerComm;
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_MSG4(setupVerb, "func set to domain map " << funcSetToDomainMap);
00069 
00070   
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   
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   
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_MSG4(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   
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     int funcComboIndex;
00169     if (!fsToFSIndexMap.containsKey(f)) 
00170     {
00171       funcComboIndex = nodalFuncSets_.size();
00172       fsToFSIndexMap.put(f, funcComboIndex);
00173       nodalFuncSets_.append(f);
00174       funcSetNodeCounts.append(1);
00175       nodeToOffsetMap_[n] = 0;
00176     }
00177     else
00178     {
00179       funcComboIndex = fsToFSIndexMap.get(f);
00180       nodeToOffsetMap_[n] = f.size() * funcSetNodeCounts[funcComboIndex];
00181       funcSetNodeCounts[funcComboIndex]++;
00182     }
00183     nodeToFuncSetIndexMap_[n] = funcComboIndex;
00184   }
00185 
00186   SUNDANCE_MSG2(setupVerb, "nodal func sets = " << nodalFuncSets_);
00187 
00188   nodeDofs_.resize(nodalFuncSets_.size());
00189   nodeStructure_.resize(nodalFuncSets_.size());
00190   funcIndexWithinNodeFuncSet_.resize(nodalFuncSets_.size());
00191 
00192   for (int f=0; f<nodalFuncSets_.size(); f++)
00193   {
00194     Array<int> funcs = nodalFuncSets_[f].elements();
00195     int nFuncs = funcs.size();
00196     funcIndexWithinNodeFuncSet_[f].resize(nTotalFuncs_, -1);
00197     for (int i=0; i<nFuncs; i++)
00198     {
00199       funcIndexWithinNodeFuncSet_[f][funcs[i]] = i;
00200     }
00201     nodeDofs_[f].resize(nFuncs * funcSetNodeCounts[f], -1);
00202     Array<RCP<BasisDOFTopologyBase> > nodeBases = tuple(basis_);
00203     Array<Array<int> > nodeFuncs = tuple(nodalFuncSets_[f].elements());
00204     nodeStructure_[f] = rcp(new MapStructure(nTotalFuncs_, 
00205         nodeBases, nodeFuncs));
00206   }
00207 
00208 
00209 
00210   
00211   int nextDOF = 0;
00212   Array<int> hasProcessedNode(nNodes);
00213   Array<Array<int> > remoteNodes(mesh.comm().getNProc());
00214 
00215   for (int r=0; r<subdomains.size(); r++)
00216   {
00217     int d = subdomains[r].dimension(mesh);
00218 
00219     if (cellLIDs[r].size()==0) continue; 
00220 
00221     if (d==0)
00222     {
00223       for (int c=0; c<cellLIDs[r].size(); c++)
00224       {
00225         int fLID = cellLIDs[r][c];
00226         int funcSetIndex = nodeToFuncSetIndexMap_[fLID];
00227         int nFuncs = nodalFuncSets_[funcSetIndex].size();
00228         int dofOffset = nodeToOffsetMap_[fLID];
00229         if (!hasProcessedNode[fLID])
00230         {
00231           assignNode(fLID, funcSetIndex, dofOffset, nFuncs,
00232             remoteNodes, hasProcessedNode, nextDOF);
00233         }
00234       }
00235     }
00236     else
00237     {
00238       Array<int>& facetLID = facetLIDs[r];
00239       int nFacets = mesh.numFacets(d, cellLIDs[r][0], 0);      
00240       for (int c=0; c<cellLIDs[r].size(); c++)
00241       {
00242         for (int f=0; f<nFacets; f++)
00243         {
00244           int fLID = facetLID[c*nFacets+f];
00245           int funcSetIndex = nodeToFuncSetIndexMap_[fLID];
00246           int dofOffset = nodeToOffsetMap_[fLID];
00247           int nFuncs = nodalFuncSets_[funcSetIndex].size();
00248           if (!hasProcessedNode[fLID])
00249           {
00250             assignNode(fLID, funcSetIndex, dofOffset, nFuncs,
00251               remoteNodes, hasProcessedNode, nextDOF);
00252           }
00253         }
00254       }
00255     }
00256   }
00257 
00258 
00259   
00260   int localCount = nextDOF;
00261   computeOffsets(localCount);
00262   
00263   
00264   shareRemoteDOFs(remoteNodes);
00265 
00266   
00267   elemDofs_.resize(maxSubdomains.size());
00268   int count = 0;
00269   Array<Array<int> > elemFuncArrays;
00270   
00271   funcDomains_.resize(nTotalFuncs_);
00272 
00273   for (int r=0; r<subdomains.size(); r++)
00274   {
00275     int d = subdomains[r].dimension(mesh);
00276     if (d != dim_) continue;
00277     if (cellLIDs[r].size()==0) continue; 
00278     int nFacets = mesh.numFacets(d, cellLIDs[r][0], 0);      
00279     Array<int>& facetLID = facetLIDs[r];
00280     Array<Array<int> > dofs(1);
00281     dofs[0].resize(funcArrays[r].size() * cellLIDs[r].size() * nFacets);
00282     getFunctionDofs(d, cellLIDs[r], facetLID, funcArrays[r], dofs);
00283     elemDofs_[count] = dofs[0];
00284     elemFuncArrays.append(funcArrays[r]);
00285     Array<RCP<BasisDOFTopologyBase> > elemBases = tuple(basis_);
00286     Array<Array<int> > elemFuncs = tuple(elemFuncSets_[count].elements());
00287     elemStructure_.append(rcp(new MapStructure(nTotalFuncs_, 
00288           elemBases, elemFuncs)));
00289     for (int c=0; c<cellLIDs[r].size(); c++)
00290     {
00291       elemToFuncSetIndexMap_[cellLIDs[r][c]] = count;
00292     }
00293     for (int i=0; i<elemFuncs[0].size(); i++)
00294     {
00295       funcDomains_[elemFuncs[0][i]] = funcDomains_[elemFuncs[0][i]] + subdomains[r];
00296     }
00297     count++;
00298   }
00299   
00300 }
00301 
00302 
00303 void InhomogeneousNodalDOFMap::getFunctionDofs(int cellDim,
00304   const Array<int>& cellLID,
00305   const Array<int>& facetLID,
00306   const Array<int>& funcs,
00307   Array<Array<int> >& dofs) const
00308 {
00309   Array<int>& dofChunk = dofs[0];
00310   dofChunk.clear();
00311 
00312   if (cellDim != 0)
00313   {
00314     int nFacets = mesh().numFacets(cellDim, cellLID[0], 0);
00315     dofChunk.resize(funcs.size() * cellLID.size() * nFacets, -1);
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           if (funcIndex >= 0)
00329           {
00330             dofChunk[(c*funcs.size()+i)*nFacets + f] 
00331             = nodeDofs_[fci][nodeOffset+funcIndex];
00332         
00333           }
00334         }
00335       }
00336     }
00337   }
00338   else
00339   {
00340     dofChunk.resize(funcs.size() * cellLID.size(), -1);
00341 
00342     for (int c=0; c<cellLID.size(); c++)
00343     {
00344       int fci = nodeToFuncSetIndexMap_[cellLID[c]];
00345       int nodeOffset = nodeToOffsetMap_[cellLID[c]];
00346       for (int i=0; i<funcs.size(); i++)
00347       {
00348         int funcIndex = funcIndexWithinNodeFuncSet_[fci][funcs[i]];
00349         if (funcIndex >= 0)
00350         {
00351           dofChunk[c*funcs.size()+ i] 
00352             = nodeDofs_[fci][nodeOffset+funcIndex];
00353         }
00354       }
00355     }
00356   }
00357 }
00358 
00359 void InhomogeneousNodalDOFMap::assignNode(int fLID,
00360   int funcSetIndex,
00361   int dofOffset,
00362   int nFuncs,
00363   Array<Array<int> >& remoteNodes,
00364   Array<int>& hasProcessedCell,
00365   int& nextDOF)
00366 {
00367   
00368   int owner;
00369   if (isRemote(0, fLID, owner))
00370   {
00371     int facetGID 
00372       = mesh().mapLIDToGID(0, fLID);
00373     remoteNodes[owner].append(facetGID);
00374       
00375   }
00376   else 
00377   {
00378     
00379     Array<int>& myDofs = nodeDofs_[funcSetIndex];
00380     for (int i=0; i<nFuncs; i++)
00381     {
00382       myDofs[dofOffset + i] = nextDOF;
00383       nextDOF++;
00384     }
00385   }
00386   hasProcessedCell[fLID] = 1;
00387 }
00388 
00389 void InhomogeneousNodalDOFMap::computeOffsets(int localCount)
00390 {
00391   TEUCHOS_TEST_FOR_EXCEPTION(mesh().comm().getNProc() != 1,
00392     std::runtime_error,
00393     "parallel inhomogeneous DOF maps not yet supported");
00394   
00395   int totalDOFCount = localCount;
00396   int myOffset = 0;
00397   setLowestLocalDOF(myOffset);
00398   setNumLocalDOFs(localCount);
00399   setTotalNumDOFs(totalDOFCount);
00400 }
00401 
00402 void InhomogeneousNodalDOFMap::shareRemoteDOFs(const Array<Array<int> >& remoteNodes)
00403 {
00404   TEUCHOS_TEST_FOR_EXCEPTION(mesh().comm().getNProc() != 1,
00405     std::runtime_error,
00406     "parallel inhomogeneous DOF maps not yet supported");
00407 }
00408 
00409 RCP<const Set<int> >
00410 InhomogeneousNodalDOFMap::allowedFuncsOnCellBatch(int cellDim,
00411   const Array<int>& cellLID) const 
00412 {
00413   Set<int> rtn;
00414 
00415   if (cellDim==0)
00416   {
00417     rtn = nodalFuncSets_[nodeToFuncSetIndexMap_[cellLID[0]]];
00418     for (int c=0; c<cellLID.size(); c++) 
00419     {
00420       const Set<int>& s = nodalFuncSets_[nodeToFuncSetIndexMap_[cellLID[c]]];
00421       rtn = rtn.intersection(s);
00422     }
00423   }
00424   else if (cellDim==dim_)
00425   {
00426     rtn = elemFuncSets_[elemToFuncSetIndexMap_[cellLID[0]]];
00427     for (int c=0; c<cellLID.size(); c++) 
00428     {
00429       const Set<int>& s = elemFuncSets_[elemToFuncSetIndexMap_[cellLID[c]]];
00430       rtn = rtn.intersection(s);
00431     }
00432   }
00433   else
00434   {
00435     Array<int> facetLID;
00436     Array<int> facetOrientations;
00437     mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00438     rtn = nodalFuncSets_[nodeToFuncSetIndexMap_[facetLID[0]]];
00439     for (int f=0; f<facetLID.size(); f++)
00440     {
00441       const Set<int>& s = nodalFuncSets_[nodeToFuncSetIndexMap_[facetLID[f]]];
00442       rtn = rtn.intersection(s);
00443     }
00444   }
00445   return rcp(new Set<int>(rtn));
00446 }
00447 
00448 
00449 RCP<const MapStructure> 
00450 InhomogeneousNodalDOFMap::getDOFsForCellBatch(int cellDim,
00451   const Array<int>& cellLID,
00452   const Set<int>& requestedFuncSet,
00453   Array<Array<int> >& dofs,
00454   Array<int>& nNodes,
00455   int verb) const 
00456 {
00457   TimeMonitor timer(batchedDofLookupTimer());
00458   Tabs tab0;
00459 
00460   SUNDANCE_MSG2(verb, tab0 << "in InhomNodalDOFMap::getDOFsForCellBatch()");
00461 
00462   if (cellDim==0)
00463   {
00464     Tabs tab1;
00465     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00466     bool isHomogeneous = true;
00467     int firstFuncSet = nodeToFuncSetIndexMap_[cellLID[0]];
00468     for (int c=0; c<cellLID.size(); c++)
00469     {
00470       if (nodeToFuncSetIndexMap_[cellLID[c]] != firstFuncSet) 
00471       {
00472         isHomogeneous = false;
00473         break;
00474       }
00475     }
00476 
00477     dofs.resize(1);
00478     nNodes.resize(1);
00479     nNodes[0] = 1;
00480     Array<int> dummyFacets;
00481 
00482     if (isHomogeneous)
00483     {
00484       const Set<int>& funcSet = nodalFuncSets_[firstFuncSet];
00485       TEUCHOS_TEST_FOR_EXCEPT(requestedFuncSet.setDifference(funcSet).size() != 0);
00486       Array<int> funcs = funcSet.elements();
00487       getFunctionDofs(cellDim, cellLID, dummyFacets, funcs, dofs);
00488       return nodeStructure_[firstFuncSet];
00489     }
00490     else
00491     {
00492       Array<int> funcs = requestedFuncSet.elements();
00493       getFunctionDofs(cellDim, cellLID, dummyFacets, funcs, dofs);
00494       RCP<const MapStructure> rtn 
00495         = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00496       return rtn;
00497     }
00498   }
00499   else if (cellDim==dim_)
00500   {
00501     Tabs tab1;
00502     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00503     bool isHomogeneous = true;
00504     int firstFuncSet = elemToFuncSetIndexMap_[cellLID[0]];
00505     SUNDANCE_MSG2(verb, tab1 << "first func set = " << firstFuncSet);
00506     for (int c=0; c<cellLID.size(); c++)
00507     {
00508       if (elemToFuncSetIndexMap_[cellLID[c]] != firstFuncSet) 
00509       {
00510         isHomogeneous = false;
00511         break;
00512       }
00513     }
00514 
00515     dofs.resize(1);
00516     nNodes.resize(1);
00517     nNodes[0] = mesh().numFacets(cellDim, cellLID[0], 0);
00518 
00519     if (isHomogeneous)
00520     {
00521       Tabs tab2;
00522       Array<int> facetLID;
00523       Array<int> facetOrientations;
00524       mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00525       if (verb >= 2)
00526       {
00527         Out::os() << tab2 << "cellLID = " << cellLID << std::endl;
00528         Out::os() << tab2 << "facetLID = " << facetLID << std::endl;
00529         Out::os() << tab2 << "elem func sets = " << elemFuncSets_ << std::endl;
00530       }
00531       const Set<int>& funcSet = elemFuncSets_[firstFuncSet];
00532       TEUCHOS_TEST_FOR_EXCEPT(requestedFuncSet.setDifference(funcSet).size() != 0);
00533       Array<int> funcs = funcSet.elements();
00534       getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00535       return elemStructure_[firstFuncSet];
00536     }
00537     else
00538     {
00539       Array<int> facetLID;
00540       Array<int> facetOrientations;
00541       mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00542       Array<int> funcs = requestedFuncSet.elements();
00543       getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00544       RCP<const MapStructure> rtn 
00545         = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00546       return rtn;
00547     }
00548   }
00549   else
00550   {
00551     Tabs tab1;
00552     SUNDANCE_MSG2(verb, tab1 << "cell dim = " << cellDim);
00553     Array<int> facetLID;
00554     Array<int> facetOrientations;
00555     mesh().getFacetLIDs(cellDim, cellLID, 0, facetLID, facetOrientations);
00556     dofs.resize(1);
00557     nNodes.resize(1);
00558     nNodes[0] = mesh().numFacets(cellDim, cellLID[0], 0);
00559 
00560     Array<int> funcs = requestedFuncSet.elements();
00561 
00562     getFunctionDofs(cellDim, cellLID, facetLID, funcs, dofs);
00563     RCP<const MapStructure> rtn 
00564       = rcp(new MapStructure(nTotalFuncs_, basis_, tuple(funcs)));
00565     return rtn;
00566   }
00567 }
00568 
00569 
00570 
00571 void InhomogeneousNodalDOFMap::print(std::ostream& os) const
00572 {
00573   Tabs tab0;
00574   std::cout << tab0 << "dof map: " << std::endl;
00575   for (int d=0; d<=dim_; d++)
00576   {
00577     Tabs tab1;
00578     std::cout << tab1 << d << "-cells: " << std::endl;
00579     for (int n=0; n<mesh().numCells(d); n++)
00580     {
00581       Tabs tab2;
00582       std::cout << tab2 << "d=" << d << " cell=" << n << std::endl;
00583       RCP<const Set<int> > funcs = allowedFuncsOnCellBatch(d, tuple(n));
00584       for (Set<int>::const_iterator f=funcs->begin(); f!=funcs->end(); f++)
00585       {
00586         Tabs tab3;
00587         Array<int> dofs;
00588         getDOFsForCell(d, n, *f, dofs);
00589         std::cout << tab3 << " f=" << *f << " dofs=" << dofs << std::endl;
00590       }
00591     }
00592   }
00593 }