SundanceMixedDOFMap.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 #include "SundanceMixedDOFMap.hpp"
00043 #include "SundanceBasisDOFTopologyBase.hpp"
00044 #include "SundanceCellFilter.hpp"
00045 #include "SundanceMaximalCellFilter.hpp"
00046 #include "PlayaMPIContainerComm.hpp"
00047 #include "SundanceOut.hpp"
00048 #include "PlayaTabs.hpp"
00049 #include "Teuchos_Time.hpp"
00050 #include "Teuchos_TimeMonitor.hpp"
00051 
00052 
00053 using namespace Sundance;
00054 using namespace Teuchos;
00055 using Playa::MPIComm;
00056 using Playa::MPIContainerComm;
00057 using Playa::MPIDataType;
00058 using Playa::MPIOp;
00059 
00060 
00061 static Time& mixedDOFCtorTimer() 
00062 {
00063   static RCP<Time> rtn 
00064     = TimeMonitor::getNewTimer("mixed DOF map init"); 
00065   return *rtn;
00066 }
00067 static Time& maxDOFBuildTimer() 
00068 {
00069   static RCP<Time> rtn 
00070     = TimeMonitor::getNewTimer("max-cell dof table init"); 
00071   return *rtn;
00072 }
00073 
00074 MixedDOFMap::MixedDOFMap(const Mesh& mesh, 
00075   const Array<RCP<BasisDOFTopologyBase> >& basis,
00076   const CellFilter& maxCells,
00077   int setupVerb)
00078   : SpatiallyHomogeneousDOFMapBase(mesh, basis.size(), setupVerb), 
00079     maxCells_(maxCells),
00080     dim_(mesh.spatialDim()),
00081     dofs_(mesh.spatialDim()+1),
00082     maximalDofs_(),
00083     haveMaximalDofs_(false),
00084     localNodePtrs_(),
00085     nNodesPerCell_(),
00086     totalNNodesPerCell_(),
00087     cellHasAnyDOFs_(dim_+1),
00088     numFacets_(mesh.spatialDim()+1),
00089     originalFacetOrientation_(2),
00090     hasBeenAssigned_(mesh.spatialDim()+1),
00091     structure_(),
00092     nFuncs_()
00093 {
00094   TimeMonitor timer(mixedDOFCtorTimer());
00095   Tabs tab;
00096   SUNDANCE_MSG1(setupVerb, tab << "building mixed DOF map");
00097 
00098   Sundance::Map<OrderedHandle<BasisDOFTopologyBase>, int> basisToChunkMap;
00099   Array<RCP<BasisDOFTopologyBase> > chunkBases;
00100   Array<Array<int> > chunkFuncs;
00101   
00102   int chunk = 0;
00103   int nBasis = basis.size();
00104   for (int i=0; i<nBasis; i++)
00105   {
00106     OrderedHandle<BasisDOFTopologyBase> bh = basis[i];
00107     if (!basisToChunkMap.containsKey(bh))
00108     {
00109       chunkBases.append(basis[i]);
00110       basisToChunkMap.put(bh, chunk);
00111       chunkFuncs.append(tuple(i));
00112       chunk++;
00113     }
00114     else
00115     {
00116       int b = basisToChunkMap.get(bh);
00117       chunkFuncs[b].append(i);
00118     }
00119   }
00120 
00121   Tabs tab1;
00122   SUNDANCE_MSG2(setupVerb, tab1 << "basis to chunk map = " << basisToChunkMap);
00123 
00124 
00125   structure_ = rcp(new MapStructure(basis.size(), chunkBases, chunkFuncs));
00126 
00127   nFuncs_.resize(chunkBases.size());
00128   for (int i=0; i<nFuncs_.size(); i++) 
00129     nFuncs_[i] = chunkFuncs[i].size();
00130 
00131   allocate(mesh);
00132 
00133   initMap();
00134 
00135   buildMaximalDofTable();
00136 
00137   /* do a sanity check */
00138   checkTable();
00139 
00140   SUNDANCE_MSG1(setupVerb, tab << "done building mixed DOF map");
00141 }
00142 
00143 
00144 void MixedDOFMap::allocate(const Mesh& mesh)
00145 {
00146   Tabs tab;
00147 
00148   /* gather functions into chunks sharing identical basis functions */
00149   SUNDANCE_MSG1(setupVerb(), tab << "grouping like basis functions");
00150   
00151 
00152   /* now that we know the number of basis chunks, allocate arrays */
00153   localNodePtrs_.resize(nBasisChunks());
00154   nNodesPerCell_.resize(nBasisChunks());
00155   totalNNodesPerCell_.resize(nBasisChunks());
00156   nDofsPerCell_.resize(nBasisChunks());
00157   totalNDofsPerCell_.resize(nBasisChunks());
00158   maximalDofs_.resize(nBasisChunks());
00159 
00160   for (int b=0; b<nBasisChunks(); b++)
00161   {
00162     localNodePtrs_[b].resize(mesh.spatialDim()+1);
00163     nNodesPerCell_[b].resize(mesh.spatialDim()+1);
00164     totalNNodesPerCell_[b].resize(mesh.spatialDim()+1);
00165     nDofsPerCell_[b].resize(mesh.spatialDim()+1);
00166     totalNDofsPerCell_[b].resize(mesh.spatialDim()+1);
00167   }
00168   
00169 
00170   /* compute node counts for each cell dimension and each basis type */
00171   SUNDANCE_MSG1(setupVerb(), tab << "working out DOF map node counts");
00172   
00173   numFacets_.resize(dim_+1);
00174 
00175   for (int d=0; d<=dim_; d++)
00176   {
00177     Tabs tab1;
00178     SUNDANCE_MSG2(setupVerb(), tab << "allocating maps for cell dim=" << d);
00179     /* record the number of facets for each cell type so we're
00180      * not making a bunch of mesh calls */
00181     numFacets_[d].resize(d);
00182     for (int fd=0; fd<d; fd++) numFacets_[d][fd]=mesh.numFacets(d, 0, fd);
00183     SUNDANCE_MSG3(setupVerb(), tab1 << "num facets for dimension " << d << " is " 
00184       << numFacets_[d]);
00185 
00186     cellHasAnyDOFs_[d] = false;
00187     dofs_[d].resize(nBasisChunks());
00188 
00189     int numCells = mesh.numCells(d);
00190     hasBeenAssigned_[d].resize(numCells);
00191 
00192     for (int b=0; b<nBasisChunks(); b++)
00193     {
00194       Tabs tab2;
00195       SUNDANCE_MSG2(setupVerb(), tab1 << "basis chunk=" << b);
00196       SUNDANCE_MSG2(setupVerb(), tab2 << "basis=" << basis(b)->description());
00197       int nNodes = basis(b).ptr()->nReferenceDOFsWithFacets(mesh.cellType(dim_), mesh.cellType(d));
00198       SUNDANCE_MSG2(setupVerb(), tab2 << "nNodes per cell=" << nNodes);
00199       if (nNodes == 0)
00200       {
00201         nNodesPerCell_[b][d] = 0;
00202         nDofsPerCell_[b][d] = 0;
00203       }
00204       else
00205       {
00206         /* look up the node pointer for this cell and for all of its
00207          * facets */
00208         basis(b).ptr()->getReferenceDOFs(mesh.cellType(dim_),
00209           mesh.cellType(d), 
00210           localNodePtrs_[b][d]);
00211               
00212               
00213         SUNDANCE_MSG3(setupVerb(), tab2 << "node ptrs are " 
00214           << localNodePtrs_[b][d]);
00215               
00216         /* with the node pointers in hand, we can work out the number
00217          * of nodes per cell in this dimension for this basis */
00218         if (localNodePtrs_[b][d][d].size() > 0) 
00219         {
00220           nNodesPerCell_[b][d] = localNodePtrs_[b][d][d][0].size();
00221           if (nNodesPerCell_[b][d] > 0) cellHasAnyDOFs_[d] = true;
00222         }
00223         else
00224         {
00225           nNodesPerCell_[b][d] = 0;
00226         }
00227         nDofsPerCell_[b][d] = nNodesPerCell_[b][d] * nFuncs(b);
00228       }
00229 
00230       /* if the cell is of intermediate dimension and it has DOFs, we
00231        * need to assign GIDs for the cells of this dimension. Otherwise,
00232        * we can skip intermediate GID assignment, saving some parallel
00233        * communication */
00234       if (nDofsPerCell_[b][d] > 0 && d > 0 && d < mesh.spatialDim())
00235       {
00236         Mesh& tmpMesh = const_cast<Mesh&>(mesh);
00237         tmpMesh.assignIntermediateCellGIDs(d);
00238       }
00239           
00240       SUNDANCE_MSG3(setupVerb(), tab2 << 
00241         "num nodes is " 
00242         << nNodesPerCell_[b][d]);
00243 
00244       totalNNodesPerCell_[b][d] = nNodesPerCell_[b][d];
00245       for (int dd=0; dd<d; dd++) 
00246       {
00247         totalNNodesPerCell_[b][d] 
00248           += numFacets_[d][dd]*nNodesPerCell_[b][dd];
00249       }
00250       totalNDofsPerCell_[b][d] = totalNNodesPerCell_[b][d] * nFuncs(b);
00251       SUNDANCE_MSG3(setupVerb(), tab2 << "totalNDofsPerCell " << totalNDofsPerCell_[b][d]);
00252 
00253       if (nNodes > 0)
00254       {
00255         /* allocate the DOFs array for this dimension */
00256         dofs_[d][b].resize(nDofsPerCell_[b][d] * numCells);
00257               
00258         /* set all DOFs to a marker value */
00259         int nDof = dofs_[d][b].size();
00260         Array<int>& dofs = dofs_[d][b];
00261         int marker = uninitializedVal();
00262         for (int i=0; i<nDof; i++) 
00263         {
00264           dofs[i] = marker;
00265         }
00266       }
00267       /* allocate the maximal dof array */
00268       if (d==dim_)
00269       {
00270         maximalDofs_[b].resize(totalNDofsPerCell_[b][d]*numCells);
00271       }
00272     }
00273 
00274     /* allocate the array of original facet orientations */
00275     if (d > 0 && d < dim_) 
00276     {
00277       originalFacetOrientation_[d-1].resize(numCells);
00278     }
00279       
00280   }
00281   SUNDANCE_MSG1(setupVerb(), tab << "done allocating DOF map");
00282 }
00283 
00284 void MixedDOFMap::initMap()
00285 {
00286   Tabs tab;
00287   SUNDANCE_MSG1(setupVerb(), tab << "initializing DOF map");
00288   /* start the DOF count at zero. */
00289   int nextDOF = 0;
00290 
00291   /* Space in which to keep a list of remote cells needed by each processor
00292    * for each dimension. The first index is dimension, the second proc, the
00293    * third cell number. */
00294   Array<Array<Array<int> > > remoteCells(mesh().spatialDim()+1);
00295 
00296   for (int d=0; d<remoteCells.size(); d++) 
00297     remoteCells[d].resize(mesh().comm().getNProc());
00298   
00299   /* Loop over maximal cells in the order specified by the cell iterator.
00300    * This might be reordered relative to the mesh. 
00301    *
00302    * At each maximal cell, we'll run through the facets and 
00303    * assign DOFs. That will take somewhat more work, but gives much 
00304    * better cache locality for the matrix because all the DOFs for
00305    * each maximal element and its facets are grouped together. */
00306   
00307   CellSet cells = maxCells_.getCells(mesh());
00308   CellIterator iter;
00309   for (iter=cells.begin(); iter != cells.end(); iter++)
00310   {
00311     /* first assign any DOFs associated with the maximal cell */
00312     int cellLID = *iter;
00313     int owner;
00314       
00315     if (cellHasAnyDOFs_[dim_])
00316     {
00317       /* if the maximal cell is owned by another processor,
00318        * put it in the list of cells for which we need to request 
00319        * DOF information from another processor */
00320       if (isRemote(dim_, cellLID, owner))
00321       {
00322         int cellGID = mesh().mapLIDToGID(dim_, cellLID);
00323         SUNDANCE_MSG4(setupVerb(), "proc=" << comm().getRank() 
00324           << " thinks d-" << dim_ 
00325           << " cell GID=" << cellGID
00326           << " is owned remotely by p=" 
00327           << owner);
00328         remoteCells[dim_][owner].append(cellGID); 
00329       }
00330       else /* the cell is locally owned, so we can 
00331             * set its DOF numbers now */
00332       {
00333         for (int b=0; b<nBasisChunks(); b++)
00334         {
00335           setDOFs(b, dim_, cellLID, nextDOF);
00336         }
00337       }
00338     }
00339 
00340     /* Now assign any DOFs associated with the facets. */
00341     for (int d=0; d<dim_; d++)
00342     {
00343       if (cellHasAnyDOFs_[d])
00344       {
00345         int nf = numFacets_[dim_][d];
00346         Array<int> facetLID(nf);
00347         Array<int> facetOrientations(nf);
00348         /* look up the LIDs of the facets */
00349         mesh().getFacetArray(dim_, cellLID, d, 
00350           facetLID, facetOrientations);
00351         /* for each facet, process its DOFs */
00352         for (int f=0; f<nf; f++)
00353         {
00354           /* if the facet's DOFs have been assigned already,
00355            * we're done */
00356           if (!hasBeenAssigned(d, facetLID[f]))
00357           {
00358             markAsAssigned(d, facetLID[f]);
00359             /* the facet may be owned by another processor */
00360             if (isRemote(d, facetLID[f], owner))
00361             {
00362               int facetGID 
00363                 = mesh().mapLIDToGID(d, facetLID[f]);
00364               SUNDANCE_MSG4(setupVerb(), "proc=" << comm().getRank() 
00365                 << " thinks d-" << d 
00366                 << " cell GID=" << facetGID
00367                 << " is owned remotely by p=" << owner);
00368               remoteCells[d][owner].append(facetGID);
00369             }
00370             else /* we can assign a DOF locally */
00371             {
00372               /* assign DOF */
00373               for (int b=0; b<nBasisChunks(); b++)
00374               {
00375                 setDOFs(b, d, facetLID[f], nextDOF);
00376               }
00377               /* record the orientation wrt the maximal cell */
00378               if (d > 0) 
00379               {
00380                 originalFacetOrientation_[d-1][facetLID[f]] 
00381                   = facetOrientations[f];
00382               }
00383             }
00384           }
00385         }
00386       }
00387     }
00388   }
00389     
00390 
00391   /* Done with first pass, in which we have assigned DOFs for all
00392    * local processors. We now have to share DOF information between
00393    * processors */
00394 
00395   int numLocalDOFs = nextDOF;
00396   if (mesh().comm().getNProc() > 1)
00397   {
00398     for (int d=0; d<=dim_; d++)
00399     {
00400       if (cellHasAnyDOFs_[d])
00401       {
00402         computeOffsets(d, numLocalDOFs);
00403         shareDOFs(d, remoteCells[d]);
00404       }
00405     }
00406   }
00407   else
00408   {
00409     setLowestLocalDOF(0);
00410     setNumLocalDOFs(numLocalDOFs);
00411     setTotalNumDOFs(numLocalDOFs);
00412   }
00413   SUNDANCE_MSG1(setupVerb(), tab << "done initializing DOF map");
00414 }
00415 
00416 void MixedDOFMap::shareDOFs(int cellDim,
00417   const Array<Array<int> >& outgoingCellRequests)
00418 {
00419   int np = mesh().comm().getNProc();
00420   int rank = mesh().comm().getRank();
00421 
00422   Array<Array<int> > incomingCellRequests;
00423   Array<Array<int> > outgoingDOFs(np);
00424   Array<Array<int> > incomingDOFs;
00425 
00426   SUNDANCE_MSG2(setupVerb(),  
00427     "p=" << mesh().comm().getRank()
00428     << "synchronizing DOFs for cells of dimension " << cellDim);
00429   SUNDANCE_MSG2(setupVerb(),  
00430     "p=" << mesh().comm().getRank()
00431     << " sending cell reqs d=" << cellDim << " GID=" << outgoingCellRequests);
00432 
00433   /* share the cell requests */
00434   MPIContainerComm<int>::allToAll(outgoingCellRequests, 
00435     incomingCellRequests,
00436     mesh().comm());
00437   
00438   /* we send the following information in response:
00439    * (1) The first DOF for each chunk for the requested cell
00440    * (2) The orientation if the cell is an edge or face 
00441    */
00442   int blockSize = 0;
00443   bool sendOrientation = false;
00444   for (int b=0; b<nBasisChunks(); b++)
00445   {
00446     int nDofs = nDofsPerCell_[b][cellDim];
00447     if (nDofs > 0) blockSize++;
00448     if (nDofs > 1 && cellDim > 0 && cellDim < dim_) sendOrientation = true;
00449   }
00450   blockSize += sendOrientation;
00451 
00452   SUNDANCE_MSG2(setupVerb(),  
00453     "p=" << rank
00454     << "recvd DOF requests for cells of dimension " << cellDim
00455     << " GID=" << incomingCellRequests);
00456 
00457   /* get orientations and DOF numbers for the first node of every cell that's been 
00458    * requested by someone else */
00459   for (int p=0; p<np; p++)
00460   {
00461     if (p==rank) continue;
00462     const Array<int>& requestsFromProc = incomingCellRequests[p];
00463     int nReq = requestsFromProc.size();
00464 
00465     SUNDANCE_MSG4(setupVerb(), "p=" << mesh().comm().getRank() 
00466       << " recv'd from proc=" << p
00467       << " reqs for DOFs for cells " 
00468       << requestsFromProc);
00469 
00470     outgoingDOFs[p].resize(nReq * blockSize);
00471 
00472     for (int c=0; c<nReq; c++)
00473     {
00474       int GID = requestsFromProc[c];
00475       SUNDANCE_MSG3(setupVerb(),  
00476         "p=" << rank
00477         << " processing cell with d=" << cellDim 
00478         << " GID=" << GID);
00479       int LID = mesh().mapGIDToLID(cellDim, GID);
00480       SUNDANCE_MSG3(setupVerb(),  
00481         "p=" << rank
00482         << " LID=" << LID << " dofs=" << dofs_[cellDim]);
00483       int blockOffset = 0;
00484       for (int b=0; b<nBasisChunks(); b++)
00485       {
00486         if (nDofsPerCell_[b][cellDim] == 0) continue;
00487         outgoingDOFs[p][blockSize*c+blockOffset] 
00488           = getInitialDOFForCell(cellDim, LID, b);
00489         blockOffset++;
00490       }
00491       if (sendOrientation)
00492       {
00493         outgoingDOFs[p][blockSize*(c+1) - 1] 
00494           = originalFacetOrientation_[cellDim-1][LID];
00495       }
00496       SUNDANCE_MSG3(setupVerb(),  
00497         "p=" << rank
00498         << " done processing cell with GID=" << GID);
00499     }
00500   }
00501  
00502 
00503   SUNDANCE_MSG2(setupVerb(),  
00504     "p=" << mesh().comm().getRank()
00505     << "answering DOF requests for cells of dimension " << cellDim);
00506 
00507   /* share the DOF numbers */
00508   MPIContainerComm<int>::allToAll(outgoingDOFs,
00509     incomingDOFs,
00510     mesh().comm());
00511 
00512   SUNDANCE_MSG2(setupVerb(),  
00513     "p=" << mesh().comm().getRank()
00514     << "communicated DOF answers for cells of dimension " << cellDim);
00515 
00516   
00517   /* now assign the DOFs from the other procs */
00518 
00519   for (int p=0; p<mesh().comm().getNProc(); p++)
00520   {
00521     if (p==mesh().comm().getRank()) continue;
00522     const Array<int>& dofsFromProc = incomingDOFs[p];
00523     int numCells = dofsFromProc.size()/blockSize;
00524     for (int c=0; c<numCells; c++)
00525     {
00526       int cellGID = outgoingCellRequests[p][c];
00527       int cellLID = mesh().mapGIDToLID(cellDim, cellGID);
00528       int blockOffset = 0;
00529       for (int b=0; b<nBasisChunks(); b++)
00530       {
00531         if (nDofsPerCell_[b][cellDim] == 0) continue;
00532         int dof = dofsFromProc[blockSize*c+blockOffset];
00533         setDOFs(b, cellDim, cellLID, dof, true);
00534         blockOffset++;
00535       }
00536       if (sendOrientation) 
00537       {
00538         originalFacetOrientation_[cellDim-1][cellLID] 
00539           = dofsFromProc[blockSize*(c+1)-1];
00540       }
00541     }
00542   }
00543   
00544 }
00545 
00546 
00547 
00548 void MixedDOFMap::setDOFs(int basisChunk, int cellDim, int cellLID, 
00549   int& nextDOF, bool isRemote)
00550 {
00551   Tabs tab;
00552   SUNDANCE_MSG3(setupVerb(), tab << "setting DOFs for " << cellDim 
00553     << "-cell " << cellLID);
00554   int nDofs = nDofsPerCell_[basisChunk][cellDim];
00555   if (nDofs==0) return;
00556 
00557   int* ptr = getInitialDOFPtrForCell(cellDim, cellLID, basisChunk);
00558   
00559   if (isRemote)
00560   {
00561     for (int i=0; i<nDofs; i++, nextDOF++) 
00562     {
00563       ptr[i] = nextDOF;;
00564       addGhostIndex(nextDOF);
00565     }
00566   }
00567   else
00568   {
00569     for (int i=0; i<nDofs; i++,nextDOF++) 
00570     {
00571       ptr[i] = nextDOF;
00572     }
00573   }
00574 }
00575 
00576 
00577 
00578 RCP<const MapStructure> MixedDOFMap
00579 ::getDOFsForCellBatch(int cellDim,
00580   const Array<int>& cellLID,
00581   const Set<int>& requestedFuncSet,
00582   Array<Array<int> >& dofs,
00583   Array<int>& nNodes,
00584   int verbosity) const 
00585 {
00586   TimeMonitor timer(batchedDofLookupTimer());
00587 
00588   Tabs tab;
00589   SUNDANCE_MSG3(verbosity, 
00590     tab << "getDOFsForCellBatch(): cellDim=" << cellDim
00591     << " cellLID=" << cellLID);
00592 
00593   dofs.resize(nBasisChunks());
00594   nNodes.resize(nBasisChunks());
00595 
00596   int nCells = cellLID.size();
00597 
00598   if (cellDim == dim_)
00599   {
00600     Tabs tab1;
00601 
00602     if (!haveMaximalDofs_) 
00603     {
00604       buildMaximalDofTable();
00605     }
00606 
00607     SUNDANCE_MSG4(verbosity, tab1 << "getting dofs for maximal cells");
00608 
00609     for (int b=0; b<nBasisChunks(); b++)
00610     {
00611       nNodes[b] = totalNNodesPerCell_[b][cellDim];
00612       dofs[b].resize(nNodes[b]*nFuncs(b)*nCells);
00613       int dofsPerCell = nFuncs(b)*nNodes[b];
00614       Array<int>& chunkDofs = dofs[b];
00615       for (int c=0; c<nCells; c++)
00616       {
00617         for (int i=0; i<dofsPerCell; i++)
00618         {
00619           chunkDofs[c*dofsPerCell + i] 
00620             = maximalDofs_[b][cellLID[c]*dofsPerCell+i];
00621         }
00622       }
00623     }
00624   }
00625   else
00626   {
00627     Tabs tab1;
00628     SUNDANCE_MSG4(verbosity, tab1 << "getting dofs for non-maximal cells");
00629   
00630     static Array<Array<int> > facetLID(3);
00631     static Array<Array<int> > facetOrientations(3);
00632     static Array<int> numFacets(3);
00633 
00634     for (int d=0; d<cellDim; d++) 
00635     {
00636       numFacets[d] = mesh().numFacets(cellDim, cellLID[0], d);
00637       mesh().getFacetLIDs(cellDim, cellLID, d, facetLID[d], 
00638         facetOrientations[d]);
00639     }
00640 
00641     for (int b=0; b<nBasisChunks(); b++)
00642     {
00643       nNodes[b] = totalNNodesPerCell_[b][cellDim];
00644       dofs[b].resize(nNodes[b]*nFuncs(b)*nCells);
00645       int dofsPerCell = nFuncs(b)*nNodes[b];
00646           
00647       Array<int>& toPtr = dofs[b];
00648       int nf = nFuncs(b);
00649 
00650       for (int c=0; c<nCells; c++)
00651       {
00652         Tabs tab2;
00653         SUNDANCE_MSG4(verbosity, tab2 << "cell=" << c);
00654         int offset = dofsPerCell*c;
00655 
00656         /* first get the DOFs for the nodes associated with 
00657          * the cell's interior */
00658         SUNDANCE_MSG4(verbosity, tab2 << "doing interior nodes");
00659         int nInteriorNodes = nNodesPerCell_[b][cellDim];
00660         //              int nInteriorNodes = localNodePtrs_[b][cellDim][cellDim][0].size();
00661         if (nInteriorNodes > 0)
00662         {
00663           if (cellDim==0 || nInteriorNodes <= 1) /* orientation-independent */
00664           {
00665             // const int* fromPtr 
00666             //                        = getInitialDOFPtrForCell(cellDim, cellLID[c], b);
00667 
00668             for (int func=0; func<nf; func++)
00669             {
00670               for (int n=0; n<nInteriorNodes; n++)
00671               {
00672                 int ptr = localNodePtrs_[b][cellDim][cellDim][0][n];
00673                 toPtr[offset + func*nNodes[b] + ptr] 
00674                   = dofs_[cellDim][b][cellLID[c]*nDofsPerCell_[b][cellDim]+func*nNodesPerCell_[b][cellDim]+n];
00675                 //                                = fromPtr[func*nNodes[b] + n];
00676               }
00677             }
00678           }
00679           else
00680           {
00681             int sign = originalFacetOrientation_[cellDim-1][cellLID[c]];
00682             int nInteriorNodes = localNodePtrs_[b][cellDim][cellDim][0].size();
00683             //     const int* fromPtr 
00684             //                        = getInitialDOFPtrForCell(cellDim, cellLID[c], b);
00685                  
00686             for (int func=0; func<nf; func++)
00687             {
00688               for (int m=0; m<nInteriorNodes; m++)
00689               {
00690                 int n = m;
00691                 if (sign<0) n = nInteriorNodes-1-m;
00692                 int ptr = localNodePtrs_[b][cellDim][cellDim][0][m];
00693                 toPtr[offset + func*nNodes[b] + ptr]  = dofs_[cellDim][b][cellLID[c]*nDofsPerCell_[b][cellDim]+func*nNodesPerCell_[b][cellDim]+n];
00694                 //    = fromPtr[func*nNodes[b] + n];
00695               }
00696             }
00697           }
00698         }
00699 
00700         /* now do the facets */
00701         for (int d=0; d<cellDim; d++)
00702         {
00703           Tabs tab2;
00704           SUNDANCE_MSG4(verbosity, tab2 << "facet dim=" << d);
00705           if (nNodesPerCell_[b][d] == 0) continue;
00706           for (int f=0; f<numFacets[d]; f++)
00707           {
00708             Tabs tab3;
00709             int facetID = facetLID[d][c*numFacets[d]+f];
00710             SUNDANCE_MSG4(verbosity, tab2 << "f=" << f << " facetLID=" << facetID);
00711             if (localNodePtrs_[b][cellDim].size()==0) continue;
00712             int nFacetNodes = localNodePtrs_[b][cellDim][d][f].size();
00713             //const int* fromPtr = getInitialDOFPtrForCell(d, facetID, b);
00714             int* toPtr1 = &(dofs[b][dofsPerCell*c]);
00715             const int* nodePtr = &(localNodePtrs_[b][cellDim][d][f][0]);
00716             for (int func=0; func<nf; func++)
00717             {
00718               if (d == 0 || nFacetNodes <= 1) /* orientation-independent */
00719               {
00720                 for (int n=0; n<nFacetNodes; n++)
00721                 {
00722                   int ptr = nodePtr[n];
00723                   toPtr1[func*nNodes[b] + ptr] //= fromPtr[func*nNodes[b] + n];
00724                     = dofs_[d][b][facetID*nDofsPerCell_[b][d]+func*nNodesPerCell_[b][d]+n];
00725                 }
00726               }
00727               else /* orientation-dependent */
00728               {
00729                 int facetOrientation = facetOrientations[d][c*numFacets[d]+f]
00730                   * originalFacetOrientation_[d-1][facetID];
00731                 for (int m=0; m<nFacetNodes; m++)
00732                 {
00733                   int n = m;
00734                   if (facetOrientation<0) n = nFacetNodes-1-m;
00735                   int ptr = nodePtr[n];
00736                   toPtr1[func*nNodes[b]+ptr] 
00737                     = dofs_[d][b][facetID*nDofsPerCell_[b][d]+func*nNodesPerCell_[b][d]+n];
00738                   //                                    = fromPtr[func*nNodes[b]+n];
00739                 }
00740               }
00741             }
00742           }
00743         }
00744       }
00745     }
00746   }
00747   return structure_;
00748 }    
00749 
00750 void MixedDOFMap::buildMaximalDofTable() const
00751 {
00752   TimeMonitor timer(maxDOFBuildTimer());
00753   Tabs tab;
00754   int cellDim = dim_;
00755   int nCells = mesh().numCells(dim_);
00756 
00757   SUNDANCE_MSG2(setupVerb(), tab << "building dofs for maximal cells");
00758 
00759   Array<Array<int> > facetLID(3);
00760   Array<Array<int> > facetOrientations(3);
00761   Array<int> numFacets(3);
00762 
00763   Array<int> cellLID(nCells);
00764 
00765   for (int c=0; c<nCells; c++) cellLID[c]=c;
00766   
00767   for (int d=0; d<cellDim; d++) 
00768   {
00769     numFacets[d] = mesh().numFacets(cellDim, cellLID[0], d);
00770     mesh().getFacetLIDs(cellDim, cellLID, d, 
00771       facetLID[d], facetOrientations[d]);
00772   }
00773 
00774   Array<int> nInteriorNodes(nBasisChunks());
00775   Array<int> nNodes(nBasisChunks());
00776   for (int b = 0; b<nBasisChunks(); b++)
00777   {
00778     if (localNodePtrs_[b][cellDim].size() != 0)
00779     {
00780       nInteriorNodes[b] = localNodePtrs_[b][cellDim][cellDim][0].size();
00781     }
00782     else 
00783     {
00784       nInteriorNodes[b] = 0;
00785     }
00786     nNodes[b] = totalNNodesPerCell_[b][cellDim];
00787   }
00788 
00789   for (int c=0; c<nCells; c++)
00790   {
00791     Tabs tab1;
00792     SUNDANCE_MSG4(setupVerb(), tab1 << "working on cell=" << c 
00793       << " LID=" << cellLID[c]);
00794     /* first get the DOFs for the nodes associated with 
00795      * the cell's interior */
00796     SUNDANCE_MSG4(setupVerb(), tab1 << "doing interior nodes");
00797     for (int b=0; b<nBasisChunks(); b++)
00798     {
00799       SUNDANCE_MSG4(setupVerb(), tab1 << "basis chunk=" << b); 
00800       if (nInteriorNodes[b]>0)
00801       {
00802         SUNDANCE_MSG4(setupVerb(), tab1<< "nInteriorNodes = " <<nInteriorNodes[b]);
00803         //const int* fromPtr = getInitialDOFPtrForCell(dim_, cellLID[c], b);
00804         int* toPtr = &(maximalDofs_[b][nNodes[b]*nFuncs(b)*cellLID[c]]);
00805         int nf = nFuncs(b);
00806         for (int func=0; func<nf; func++)
00807         {
00808           for (int n=0; n<nInteriorNodes[b]; n++)
00809           {
00810                       
00811             int ptr = localNodePtrs_[b][cellDim][cellDim][0][n];
00812             toPtr[func*nNodes[b] + ptr] = //fromPtr[func*nNodes[b] + n];
00813               dofs_[cellDim][b][cellLID[c]*nDofsPerCell_[b][cellDim]+func*nNodesPerCell_[b][cellDim]+n];
00814           }
00815         }
00816       }
00817     }
00818       
00819     SUNDANCE_MSG4(setupVerb(), tab1 << "doing facet nodes");
00820     /* now get the DOFs for the nodes on the facets */
00821     for (int d=0; d<cellDim; d++)
00822     {
00823       Tabs tab2;
00824       SUNDANCE_MSG4(setupVerb(), tab2 << "facet dim=" << d);
00825 
00826       for (int f=0; f<numFacets[d]; f++)
00827       {
00828         Tabs tab3;
00829         int facetID = facetLID[d][c*numFacets[d]+f];
00830         SUNDANCE_MSG4(setupVerb(), tab2 << "f=" << f << " facetLID=" << facetID);
00831 
00832         for (int b=0; b<nBasisChunks(); b++)
00833         {
00834           Tabs tab4;
00835           SUNDANCE_MSG4(setupVerb(), tab4 << "basis chunk=" << b); 
00836           SUNDANCE_MSG4(setupVerb(), tab4 << "num nodes per cell=" << nNodesPerCell_[b][d]); 
00837           int nf = nFuncs(b);
00838           if (nDofsPerCell_[b][d]==0) continue;
00839           int nFacetNodes = 0;
00840           if (localNodePtrs_[b][cellDim].size()!=0)
00841             nFacetNodes = localNodePtrs_[b][cellDim][d][f].size();
00842           if (nFacetNodes == 0) continue;
00843           //  const int* fromPtr = getInitialDOFPtrForCell(d, facetID, b);
00844           SUNDANCE_MSG4(setupVerb(), tab4 << "dof table size=" << maximalDofs_[b].size()); 
00845           int* toPtr = &(maximalDofs_[b][nNodes[b]*nFuncs(b)*cellLID[c]]);
00846           const int* nodePtr = &(localNodePtrs_[b][cellDim][d][f][0]);
00847           for (int func=0; func<nf; func++)
00848           {
00849             Tabs tab5;
00850             SUNDANCE_MSG4(setupVerb(), tab5 << "func=" << func); 
00851             if (d == 0 || nFacetNodes <= 1) /* orientation-independent */
00852             {
00853               Tabs tab6;
00854               for (int n=0; n<nFacetNodes; n++)
00855               {
00856                 SUNDANCE_MSG4(setupVerb(), tab5 << "n=" << n); 
00857                 int ptr = nodePtr[n];
00858                 SUNDANCE_MSG4(setupVerb(), tab6 << "ptr=" << ptr); 
00859 
00860                 toPtr[func*nNodes[b] + ptr] 
00861                   = dofs_[d][b][facetID*nDofsPerCell_[b][d]+func*nNodesPerCell_[b][d]+n];
00862                 //= fromPtr[func*nNodes[b] + n];
00863               }
00864             }
00865             else /* orientation-dependent */
00866             {
00867               int facetOrientation = facetOrientations[d][c*numFacets[d]+f]
00868                 * originalFacetOrientation_[d-1][facetID];
00869               for (int m=0; m<nFacetNodes; m++)
00870               {
00871                 int n = m;
00872                 if (facetOrientation<0) n = nFacetNodes-1-m;
00873                 int ptr = nodePtr[m];
00874                 toPtr[func*nNodes[b]+ptr] 
00875                   = dofs_[d][b][facetID*nDofsPerCell_[b][d]+func*nNodesPerCell_[b][d]+n];
00876                 //= fromPtr[func*nNodes[b]+n];
00877               }
00878             }
00879           }
00880         }
00881       }
00882     }
00883   }
00884 
00885   haveMaximalDofs_ = true;
00886 
00887   SUNDANCE_MSG2(setupVerb(), tab << "done building dofs for maximal cells");
00888 }
00889 
00890 
00891 
00892 
00893 
00894 void MixedDOFMap::computeOffsets(int dim, int localCount)
00895 {
00896   if (setupVerb() > 2)
00897   {
00898     comm().synchronize();
00899     comm().synchronize();
00900     comm().synchronize();
00901     comm().synchronize();
00902   }
00903   SUNDANCE_MSG2(setupVerb(), 
00904     "p=" << mesh().comm().getRank()
00905     << " sharing offsets for DOF numbering for dim=" << dim);
00906 
00907   SUNDANCE_MSG2(setupVerb(), 
00908     "p=" << mesh().comm().getRank()
00909     << " I have " << localCount << " cells");
00910 
00911   Array<int> dofOffsets;
00912   int totalDOFCount;
00913   MPIContainerComm<int>::accumulate(localCount, dofOffsets, totalDOFCount,
00914     mesh().comm());
00915   int myOffset = dofOffsets[mesh().comm().getRank()];
00916 
00917   SUNDANCE_MSG2(setupVerb(), 
00918     "p=" << mesh().comm().getRank()
00919     << " back from MPI accumulate");
00920 
00921   if (setupVerb() > 2)
00922   {
00923     comm().synchronize();
00924     comm().synchronize();
00925     comm().synchronize();
00926     comm().synchronize();
00927   }
00928 
00929   for (int chunk=0; chunk<dofs_[dim].size(); chunk++)
00930   {
00931     for (int n=0; n<dofs_[dim][chunk].size(); n++)
00932     {
00933       if (dofs_[dim][chunk][n] >= 0) dofs_[dim][chunk][n] += myOffset;
00934     }
00935   }
00936 
00937   setLowestLocalDOF(myOffset);
00938   setNumLocalDOFs(localCount);
00939   setTotalNumDOFs(totalDOFCount);
00940 
00941   SUNDANCE_MSG2(setupVerb(), 
00942     "p=" << mesh().comm().getRank() 
00943     << " done sharing offsets for DOF numbering for dim=" << dim);
00944   if (setupVerb() > 2)
00945   {
00946     comm().synchronize();
00947     comm().synchronize();
00948     comm().synchronize();
00949     comm().synchronize();
00950   }
00951 
00952 }                           
00953 
00954 
00955 
00956 void MixedDOFMap::checkTable() const 
00957 {
00958   int bad = 0;
00959   for (int d=0; d<dofs_.size(); d++)
00960   {
00961     for (int chunk=0; chunk<dofs_[d].size(); chunk++)
00962     {
00963       const Array<int>& dofs = dofs_[d][chunk];
00964       for (int n=0; n<dofs.size(); n++)
00965       {
00966         if (dofs[n] < 0) bad = 1;
00967       }
00968     }
00969   }
00970   
00971   int anyBad = bad;
00972   comm().allReduce((void*) &bad, (void*) &anyBad, 1, 
00973     MPIDataType::intType(), MPIOp::sumOp());
00974   TEUCHOS_TEST_FOR_EXCEPTION(anyBad > 0, std::runtime_error, "invalid DOF map");
00975 }

Site Contact