FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

globalMeshData.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "globalMeshData.H"
00027 #include <OpenFOAM/Time.H>
00028 #include <OpenFOAM/Pstream.H>
00029 #include <OpenFOAM/PstreamCombineReduceOps.H>
00030 #include <OpenFOAM/processorPolyPatch.H>
00031 #include <OpenFOAM/demandDrivenData.H>
00032 #include "globalPoints.H"
00033 //#include "geomGlobalPoints.H"
00034 #include <OpenFOAM/labelIOList.H>
00035 #include <OpenFOAM/PackedList.H>
00036 #include <OpenFOAM/mergePoints.H>
00037 #include <OpenFOAM/matchPoints.H>
00038 #include <OpenFOAM/OFstream.H>
00039 
00040 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00041 
00042 defineTypeNameAndDebug(Foam::globalMeshData, 0);
00043 
00044 // Geometric matching tolerance. Factor of mesh bounding box.
00045 const Foam::scalar Foam::globalMeshData::matchTol_ = 1E-8;
00046 
00047 
00048 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00049 
00050 // Collect processor patch addressing.
00051 void Foam::globalMeshData::initProcAddr()
00052 {
00053     processorPatchIndices_.setSize(mesh_.boundaryMesh().size());
00054     processorPatchIndices_ = -1;
00055 
00056     processorPatchNeighbours_.setSize(mesh_.boundaryMesh().size());
00057     processorPatchNeighbours_ = -1;
00058 
00059     // Construct processor patch indexing. processorPatchNeighbours_ only
00060     // set if running in parallel!
00061     processorPatches_.setSize(mesh_.boundaryMesh().size());
00062 
00063     label nNeighbours = 0;
00064 
00065     forAll (mesh_.boundaryMesh(), patchi)
00066     {
00067         if (isA<processorPolyPatch>(mesh_.boundaryMesh()[patchi]))
00068         {
00069             processorPatches_[nNeighbours] = patchi;
00070             processorPatchIndices_[patchi] = nNeighbours++;
00071         }
00072     }
00073     processorPatches_.setSize(nNeighbours);
00074 
00075 
00076     if (Pstream::parRun())
00077     {
00078         // Send indices of my processor patches to my neighbours
00079         forAll (processorPatches_, i)
00080         {
00081             label patchi = processorPatches_[i];
00082 
00083             OPstream toNeighbour
00084             (
00085                 Pstream::blocking,
00086                 refCast<const processorPolyPatch>
00087                 (
00088                     mesh_.boundaryMesh()[patchi]
00089                 ).neighbProcNo()
00090             );
00091 
00092             toNeighbour << processorPatchIndices_[patchi];
00093         }
00094 
00095         forAll(processorPatches_, i)
00096         {
00097             label patchi = processorPatches_[i];
00098             
00099             IPstream fromNeighbour
00100             (
00101                 Pstream::blocking,
00102                 refCast<const processorPolyPatch>
00103                 (
00104                     mesh_.boundaryMesh()[patchi]
00105                 ).neighbProcNo()
00106             );
00107             
00108             fromNeighbour >> processorPatchNeighbours_[patchi];
00109         }
00110     }
00111 }
00112 
00113 
00114 // Given information about locally used edges allocate global shared edges.
00115 void Foam::globalMeshData::countSharedEdges
00116 (
00117     const HashTable<labelList, edge, Hash<edge> >& procSharedEdges,
00118     HashTable<label, edge, Hash<edge> >& globalShared,
00119     label& sharedEdgeI
00120 )
00121 {
00122     // Count occurrences of procSharedEdges in global shared edges table.
00123     for
00124     (
00125         HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
00126             procSharedEdges.begin();
00127         iter != procSharedEdges.end();
00128         ++iter
00129     )
00130     {
00131         const edge& e = iter.key();
00132 
00133         HashTable<label, edge, Hash<edge> >::iterator globalFnd =
00134             globalShared.find(e);
00135 
00136         if (globalFnd == globalShared.end())
00137         {
00138             // First time occurrence of this edge. Check how many we are adding.
00139             if (iter().size() == 1)
00140             {
00141                 // Only one edge. Mark with special value.
00142                 globalShared.insert(e, -1);
00143             }
00144             else
00145             {
00146                 // Edge used more than once (even by local shared edges alone)
00147                 // so allocate proper shared edge label.
00148                 globalShared.insert(e, sharedEdgeI++);
00149             }
00150         }
00151         else
00152         {
00153             if (globalFnd() == -1)
00154             {
00155                 // Second time occurence of this edge. Assign proper
00156                 // edge label.
00157                 globalFnd() = sharedEdgeI++;
00158             }
00159         }
00160     }
00161 }
00162 
00163 
00164 // Shared edges are shared between multiple processors. By their nature both
00165 // of their endpoints are shared points. (but not all edges using two shared
00166 // points are shared edges! There might e.g. be an edge between two unrelated
00167 // clusters of shared points)
00168 void Foam::globalMeshData::calcSharedEdges() const
00169 {
00170     if (nGlobalEdges_ != -1 || sharedEdgeLabelsPtr_ || sharedEdgeAddrPtr_)
00171     {
00172         FatalErrorIn("globalMeshData::calcSharedEdges()")
00173             << "Shared edge addressing already done" << abort(FatalError);
00174     }
00175 
00176 
00177     const labelList& sharedPtAddr = sharedPointAddr();
00178     const labelList& sharedPtLabels = sharedPointLabels();
00179 
00180     // Since don't want to construct pointEdges for whole mesh create
00181     // Map for all shared points.
00182     Map<label> meshToShared(2*sharedPtLabels.size());
00183     forAll(sharedPtLabels, i)
00184     {
00185         meshToShared.insert(sharedPtLabels[i], i);
00186     }
00187 
00188     // Find edges using shared points. Store correspondence to local edge
00189     // numbering. Note that multiple local edges can have the same shared
00190     // points! (for cyclics or separated processor patches)
00191     HashTable<labelList, edge, Hash<edge> > localShared
00192     (
00193         2*sharedPtAddr.size()
00194     );
00195 
00196     const edgeList& edges = mesh_.edges();
00197 
00198     forAll(edges, edgeI)
00199     {
00200         const edge& e = edges[edgeI];
00201 
00202         Map<label>::const_iterator e0Fnd = meshToShared.find(e[0]);
00203 
00204         if (e0Fnd != meshToShared.end())
00205         {
00206             Map<label>::const_iterator e1Fnd = meshToShared.find(e[1]);
00207 
00208             if (e1Fnd != meshToShared.end())
00209             {
00210                 // Found edge which uses shared points. Probably shared.
00211 
00212                 // Construct the edge in shared points (or rather global indices
00213                 // of the shared points)
00214                 edge sharedEdge
00215                 (
00216                     sharedPtAddr[e0Fnd()],
00217                     sharedPtAddr[e1Fnd()]
00218                 );
00219 
00220                 HashTable<labelList, edge, Hash<edge> >::iterator iter =
00221                     localShared.find(sharedEdge);
00222 
00223                 if (iter == localShared.end())
00224                 {
00225                     // First occurrence of this point combination. Store.
00226                     localShared.insert(sharedEdge, labelList(1, edgeI));
00227                 }
00228                 else
00229                 {
00230                     // Add this edge to list of edge labels.
00231                     labelList& edgeLabels = iter();
00232 
00233                     label sz = edgeLabels.size();
00234                     edgeLabels.setSize(sz+1);
00235                     edgeLabels[sz] = edgeI;
00236                 }
00237             }
00238         }
00239     }
00240 
00241 
00242     // Now we have a table on every processors which gives its edges which use
00243     // shared points. Send this all to the master and have it allocate
00244     // global edge numbers for it. But only allocate a global edge number for
00245     // edge if it is used more than once!
00246     // Note that we are now sending the whole localShared to the master whereas
00247     // we only need the local count (i.e. the number of times a global edge is
00248     // used). But then this only gets done once so not too bothered about the
00249     // extra global communication.
00250 
00251     HashTable<label, edge, Hash<edge> > globalShared(nGlobalPoints());
00252 
00253     if (Pstream::master())
00254     {
00255         label sharedEdgeI = 0;
00256 
00257         // Merge my shared edges into the global list
00258         if (debug)
00259         {
00260             Pout<< "globalMeshData::calcSharedEdges : Merging in from proc0 : "
00261                 << localShared.size() << endl;
00262         }
00263         countSharedEdges(localShared, globalShared, sharedEdgeI);
00264 
00265         // Receive data from slaves and insert
00266         if (Pstream::parRun())
00267         {
00268             for
00269             (
00270                 int slave=Pstream::firstSlave();
00271                 slave<=Pstream::lastSlave();
00272                 slave++
00273             )
00274             {
00275                 // Receive the edges using shared points from the slave.
00276                 IPstream fromSlave(Pstream::blocking, slave);
00277                 HashTable<labelList, edge, Hash<edge> > procSharedEdges
00278                 (
00279                     fromSlave
00280                 );
00281 
00282                 if (debug)
00283                 {
00284                     Pout<< "globalMeshData::calcSharedEdges : "
00285                         << "Merging in from proc"
00286                         << Foam::name(slave) << " : " << procSharedEdges.size()
00287                         << endl;
00288                 }
00289                 countSharedEdges(procSharedEdges, globalShared, sharedEdgeI);
00290             }
00291         }
00292 
00293         // Now our globalShared should have some edges with -1 as edge label
00294         // These were only used once so are not proper shared edges.
00295         // Remove them.
00296         {
00297             HashTable<label, edge, Hash<edge> > oldSharedEdges(globalShared);
00298 
00299             globalShared.clear();
00300 
00301             for
00302             (
00303                 HashTable<label, edge, Hash<edge> >::const_iterator iter =
00304                     oldSharedEdges.begin();
00305                 iter != oldSharedEdges.end();
00306                 ++iter
00307             )
00308             {
00309                 if (iter() != -1)
00310                 {
00311                     globalShared.insert(iter.key(), iter());
00312                 }
00313             }
00314             if (debug)
00315             {
00316                 Pout<< "globalMeshData::calcSharedEdges : Filtered "
00317                     << oldSharedEdges.size()
00318                     << " down to " << globalShared.size() << endl;
00319             }
00320         }
00321 
00322 
00323         // Send back to slaves.
00324         if (Pstream::parRun())
00325         {
00326             for
00327             (
00328                 int slave=Pstream::firstSlave();
00329                 slave<=Pstream::lastSlave();
00330                 slave++
00331             )
00332             {
00333                 // Receive the edges using shared points from the slave.
00334                 OPstream toSlave(Pstream::blocking, slave);
00335                 toSlave << globalShared;
00336             }
00337         }
00338     }
00339     else
00340     {
00341         // Send local edges to master
00342         {
00343             OPstream toMaster(Pstream::blocking, Pstream::masterNo());
00344 
00345             toMaster << localShared;
00346         }
00347         // Receive merged edges from master.
00348         {
00349             IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
00350 
00351             fromMaster >> globalShared;
00352         }
00353     }
00354 
00355     // Now use the global shared edges list (globalShared) to classify my local
00356     // ones (localShared)
00357 
00358     nGlobalEdges_ = globalShared.size();
00359 
00360     DynamicList<label> dynSharedEdgeLabels(globalShared.size());
00361     DynamicList<label> dynSharedEdgeAddr(globalShared.size());
00362 
00363     for
00364     (
00365         HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
00366             localShared.begin();
00367         iter != localShared.end();
00368         ++iter
00369     )
00370     {
00371         const edge& e = iter.key();
00372 
00373         HashTable<label, edge, Hash<edge> >::const_iterator edgeFnd =
00374             globalShared.find(e);
00375 
00376         if (edgeFnd != globalShared.end())
00377         {
00378             // My local edge is indeed a shared one. Go through all local edge
00379             // labels with this point combination.
00380             const labelList& edgeLabels = iter();
00381 
00382             forAll(edgeLabels, i)
00383             {
00384                 // Store label of local mesh edge
00385                 dynSharedEdgeLabels.append(edgeLabels[i]);
00386 
00387                 // Store label of shared edge
00388                 dynSharedEdgeAddr.append(edgeFnd());
00389             }
00390         }
00391     }
00392 
00393     sharedEdgeLabelsPtr_ = new labelList();
00394     labelList& sharedEdgeLabels = *sharedEdgeLabelsPtr_;
00395     sharedEdgeLabels.transfer(dynSharedEdgeLabels);
00396 
00397     sharedEdgeAddrPtr_ = new labelList();
00398     labelList& sharedEdgeAddr = *sharedEdgeAddrPtr_;
00399     sharedEdgeAddr.transfer(dynSharedEdgeAddr);
00400 
00401     if (debug)
00402     {
00403         Pout<< "globalMeshData : nGlobalEdges_:" << nGlobalEdges_ << nl
00404             << "globalMeshData : sharedEdgeLabels:" << sharedEdgeLabels.size()
00405             << nl
00406             << "globalMeshData : sharedEdgeAddr:" << sharedEdgeAddr.size()
00407             << endl;
00408     }
00409 }
00410 
00411 
00412 // Helper function to count coincident faces. This part used to be
00413 // in updateMesh but I've had to move it to a separate function
00414 // because of aliasing optimisation errors in icc9.1 on the
00415 // Itanium.
00416 Foam::label Foam::globalMeshData::countCoincidentFaces
00417 (
00418     const scalar tolDim,
00419     const vectorField& separationDist
00420 )
00421 {
00422     label nCoincident = 0;
00423 
00424     forAll(separationDist, faceI)
00425     {
00426         if (mag(separationDist[faceI]) < tolDim)
00427         {
00428             // Faces coincide
00429             nCoincident++;
00430         }
00431     }
00432     return nCoincident;
00433 }
00434 
00435 
00436 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00437 
00438 // Construct from polyMesh
00439 Foam::globalMeshData::globalMeshData(const polyMesh& mesh)
00440 :
00441     processorTopology(mesh.boundaryMesh()),
00442     mesh_(mesh),
00443     bb_(vector::zero, vector::zero),
00444     nTotalPoints_(-1),
00445     nTotalFaces_(-1),
00446     nTotalCells_(-1),
00447     processorPatches_(0),
00448     processorPatchIndices_(0),
00449     processorPatchNeighbours_(0),
00450     nGlobalPoints_(-1),
00451     sharedPointLabels_(0),
00452     sharedPointAddr_(0),
00453     sharedPointGlobalLabelsPtr_(NULL),
00454     nGlobalEdges_(-1),
00455     sharedEdgeLabelsPtr_(NULL),
00456     sharedEdgeAddrPtr_(NULL)
00457 {
00458     updateMesh();
00459 }
00460 
00461 
00462 // Read constructor given IOobject and a polyMesh reference
00463 Foam::globalMeshData::globalMeshData(const IOobject& io, const polyMesh& mesh)
00464 :
00465     processorTopology(mesh.boundaryMesh()),
00466     mesh_(mesh),
00467     bb_(mesh.points()),
00468     nTotalPoints_(-1),
00469     nTotalFaces_(-1),
00470     nTotalCells_(-1),
00471     processorPatches_(0),
00472     processorPatchIndices_(0),
00473     processorPatchNeighbours_(0),
00474     nGlobalPoints_(-1),
00475     sharedPointLabels_(0),
00476     sharedPointAddr_(0),
00477     sharedPointGlobalLabelsPtr_(NULL),
00478     nGlobalEdges_(-1),
00479     sharedEdgeLabelsPtr_(NULL),
00480     sharedEdgeAddrPtr_(NULL)
00481 {
00482     initProcAddr();
00483 
00484     IOdictionary dict(io);
00485 
00486     dict.lookup("nTotalPoints") >> nTotalPoints_;
00487     dict.lookup("nTotalFaces") >> nTotalFaces_;
00488     dict.lookup("nTotalCells") >> nTotalCells_;
00489     dict.lookup("nGlobalPoints") >> nGlobalPoints_;
00490     dict.lookup("sharedPointLabels") >> sharedPointLabels_;
00491     dict.lookup("sharedPointAddr") >> sharedPointAddr_;
00492     labelList sharedPointGlobalLabels(dict.lookup("sharedPointGlobalLabels"));
00493 
00494     sharedPointGlobalLabelsPtr_ = new labelList(sharedPointGlobalLabels);
00495 }
00496 
00497 
00498 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
00499 
00500 Foam::globalMeshData::~globalMeshData()
00501 {
00502     clearOut();
00503 }
00504 
00505 
00506 void Foam::globalMeshData::clearOut()
00507 {
00508     deleteDemandDrivenData(sharedPointGlobalLabelsPtr_);
00509     // Edge
00510     nGlobalPoints_ = -1;
00511     deleteDemandDrivenData(sharedEdgeLabelsPtr_);
00512     deleteDemandDrivenData(sharedEdgeAddrPtr_);
00513 }
00514 
00515 
00516 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00517 
00518 // Return shared point global labels.
00519 const Foam::labelList& Foam::globalMeshData::sharedPointGlobalLabels() const
00520 {
00521     if (!sharedPointGlobalLabelsPtr_)
00522     {
00523         sharedPointGlobalLabelsPtr_ = new labelList(sharedPointLabels_.size());
00524         labelList& sharedPointGlobalLabels = *sharedPointGlobalLabelsPtr_;
00525 
00526         IOobject addrHeader
00527         (
00528             "pointProcAddressing",
00529             mesh_.facesInstance()/mesh_.meshSubDir,
00530             mesh_,
00531             IOobject::MUST_READ
00532         );
00533 
00534         if (addrHeader.headerOk())
00535         {
00536             // There is a pointProcAddressing file so use it to get labels
00537             // on the original mesh
00538             Pout<< "globalMeshData::sharedPointGlobalLabels : "
00539                 << "Reading pointProcAddressing" << endl;
00540 
00541             labelIOList pointProcAddressing(addrHeader);
00542 
00543             forAll(sharedPointLabels_, i)
00544             {
00545                 // Get my mesh point
00546                 label pointI = sharedPointLabels_[i];
00547 
00548                 // Map to mesh point of original mesh
00549                 sharedPointGlobalLabels[i] = pointProcAddressing[pointI];
00550             }
00551         }
00552         else
00553         {
00554             Pout<< "globalMeshData::sharedPointGlobalLabels :"
00555                 << " Setting pointProcAddressing to -1" << endl;
00556 
00557             sharedPointGlobalLabels = -1;
00558         }
00559     }
00560     return *sharedPointGlobalLabelsPtr_;
00561 }
00562 
00563 
00564 // Collect coordinates of shared points. (does parallel communication!)
00565 Foam::pointField Foam::globalMeshData::sharedPoints() const
00566 {
00567     // Get all processors to send their shared points to master.
00568     // (not very efficient)
00569 
00570     pointField sharedPoints(nGlobalPoints_);
00571 
00572     if (Pstream::master())
00573     {
00574         // Master:
00575         // insert my own data first
00576         forAll(sharedPointLabels_, i)
00577         {
00578             label sharedPointI = sharedPointAddr_[i];
00579 
00580             sharedPoints[sharedPointI] = mesh_.points()[sharedPointLabels_[i]];
00581         }
00582 
00583         // Receive data from slaves and insert
00584         for
00585         (
00586             int slave=Pstream::firstSlave();
00587             slave<=Pstream::lastSlave();
00588             slave++
00589         )
00590         {
00591             IPstream fromSlave(Pstream::blocking, slave);
00592 
00593             labelList nbrSharedPointAddr;
00594             pointField nbrSharedPoints;
00595             fromSlave >> nbrSharedPointAddr >> nbrSharedPoints;
00596 
00597             forAll(nbrSharedPointAddr, i)
00598             {
00599                 label sharedPointI = nbrSharedPointAddr[i];
00600 
00601                 sharedPoints[sharedPointI] = nbrSharedPoints[i];
00602             }
00603         }
00604 
00605         // Send back
00606         for
00607         (
00608             int slave=Pstream::firstSlave();
00609             slave<=Pstream::lastSlave();
00610             slave++
00611         )
00612         {
00613             OPstream toSlave
00614             (
00615                 Pstream::blocking,
00616                 slave,
00617                 sharedPoints.size()*sizeof(vector::zero)
00618             );
00619             toSlave << sharedPoints;
00620         }
00621     }
00622     else
00623     {
00624         // Slave:
00625         // send points
00626         {
00627             OPstream toMaster(Pstream::blocking, Pstream::masterNo());
00628 
00629             toMaster
00630                 << sharedPointAddr_ 
00631                 << UIndirectList<point>(mesh_.points(), sharedPointLabels_)();
00632         }
00633 
00634         // Receive sharedPoints
00635         {
00636             IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
00637             fromMaster >> sharedPoints;
00638         }
00639     }
00640 
00641     return sharedPoints;
00642 }
00643 
00644 
00645 // Collect coordinates of shared points. (does parallel communication!)
00646 Foam::pointField Foam::globalMeshData::geometricSharedPoints() const
00647 {
00648     // Get coords of my shared points
00649     pointField sharedPoints(sharedPointLabels_.size());
00650 
00651     forAll(sharedPointLabels_, i)
00652     {
00653         label meshPointI = sharedPointLabels_[i];
00654 
00655         sharedPoints[i] = mesh_.points()[meshPointI];
00656     }
00657 
00658     // Append from all processors
00659     combineReduce(sharedPoints, plusEqOp<pointField>());
00660 
00661     // Merge tolerance
00662     scalar tolDim = matchTol_ * bb_.mag();
00663 
00664     // And see how many are unique
00665     labelList pMap;
00666     pointField mergedPoints;
00667 
00668     mergePoints
00669     (
00670         sharedPoints,   // coordinates to merge
00671         tolDim,         // tolerance
00672         false,          // verbosity
00673         pMap,
00674         mergedPoints
00675     );
00676 
00677     return mergedPoints;
00678 }
00679 
00680 
00681 Foam::label Foam::globalMeshData::nGlobalEdges() const
00682 {
00683     if (nGlobalEdges_ == -1)
00684     {
00685         calcSharedEdges();
00686     }
00687     return nGlobalEdges_;
00688 }
00689 
00690 
00691 const Foam::labelList& Foam::globalMeshData::sharedEdgeLabels() const
00692 {
00693     if (!sharedEdgeLabelsPtr_)
00694     {
00695         calcSharedEdges();
00696     }
00697     return *sharedEdgeLabelsPtr_;
00698 }
00699 
00700 
00701 const Foam::labelList& Foam::globalMeshData::sharedEdgeAddr() const
00702 {
00703     if (!sharedEdgeAddrPtr_)
00704     {
00705         calcSharedEdges();
00706     }
00707     return *sharedEdgeAddrPtr_;
00708 }
00709 
00710 
00711 void Foam::globalMeshData::movePoints(const pointField& newPoints)
00712 {
00713     // Topology does not change and we don't store any geometry so nothing
00714     // needs to be done.
00715 }
00716 
00717 
00718 // Update all data after morph
00719 void Foam::globalMeshData::updateMesh()
00720 {
00721     // Clear out old data
00722     clearOut();
00723 
00724     // Do processor patch addressing
00725     initProcAddr();
00726 
00727     // Note: boundBox does reduce
00728     bb_ = boundBox(mesh_.points());
00729 
00730     scalar tolDim = matchTol_ * bb_.mag();
00731 
00732     if (debug)
00733     {
00734         Pout<< "globalMeshData : bb_:" << bb_
00735             << " merge dist:" << tolDim << endl;
00736     }
00737 
00738 
00739     // Option 1. Topological
00740     {
00741         // Calculate all shared points. This does all the hard work.
00742         globalPoints parallelPoints(mesh_);
00743 
00744         // Copy data out.
00745         nGlobalPoints_ = parallelPoints.nGlobalPoints();
00746         sharedPointLabels_ = parallelPoints.sharedPointLabels();
00747         sharedPointAddr_ = parallelPoints.sharedPointAddr();
00748     }
00750     //{
00751     //    // Calculate all shared points. This does all the hard work.
00752     //    geomGlobalPoints parallelPoints(mesh_, tolDim);
00753     //
00754     //    // Copy data out.
00755     //    nGlobalPoints_ = parallelPoints.nGlobalPoints();
00756     //    sharedPointLabels_ = parallelPoints.sharedPointLabels();
00757     //    sharedPointAddr_ = parallelPoints.sharedPointAddr();
00758     //
00759     //    nGlobalEdges_ = parallelPoints.nGlobalEdges();
00760     //    sharedEdgeLabels_ = parallelPoints.sharedEdgeLabels();
00761     //    sharedEdgeAddr_ = parallelPoints.sharedEdgeAddr();
00762     //}
00763 
00764     // Total number of faces. Start off from all faces. Remove coincident
00765     // processor faces (on highest numbered processor) before summing.
00766     nTotalFaces_ = mesh_.nFaces();
00767 
00768     // Do not count processor-patch faces that are coincident.
00769     forAll(processorPatches_, i)
00770     {
00771         label patchI = processorPatches_[i];
00772 
00773         const processorPolyPatch& procPatch =
00774             refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchI]);
00775 
00776         if (Pstream::myProcNo() > procPatch.neighbProcNo())
00777         {
00778             // Uncount my faces. Handle cyclics separately.
00779 
00780             if (procPatch.separated())
00781             {
00782                 const vectorField& separationDist = procPatch.separation();
00783 
00784                 nTotalFaces_ -= countCoincidentFaces(tolDim, separationDist);
00785             }
00786             else
00787             {
00788                 // Normal, unseparated processor patch. Remove duplicates.
00789                 nTotalFaces_ -= procPatch.size();
00790             }
00791         }
00792     }
00793     reduce(nTotalFaces_, sumOp<label>());
00794 
00795     if (debug)
00796     {
00797         Pout<< "globalMeshData : nTotalFaces_:" << nTotalFaces_ << endl;
00798     }
00799 
00800 
00801     nTotalCells_ = mesh_.nCells();
00802     reduce(nTotalCells_, sumOp<label>());
00803 
00804     if (debug)
00805     {
00806         Pout<< "globalMeshData : nTotalCells_:" << nTotalCells_ << endl;
00807     }
00808 
00809     nTotalPoints_ = mesh_.nPoints();
00810 
00811     // Correct points for duplicate ones. We have
00812     // - points shared between 2 processor patches only. Count only on
00813     //   lower numbered processor. Make sure to count only once since points
00814     //   can be on multiple patches on the same processor.
00815     // - globally shared points.
00816 
00817     if (Pstream::parRun())
00818     {
00819         const label UNSET = 0;      // not set
00820         const label SHARED = 1;     // globally shared
00821         const label VISITED = 2;    // corrected for
00822 
00823         // Mark globally shared points
00824         PackedList<2> pointStatus(mesh_.nPoints(), UNSET);
00825 
00826         forAll(sharedPointLabels_, i)
00827         {
00828             label meshPointI = sharedPointLabels_[i];
00829 
00830             pointStatus.set(meshPointI, SHARED);
00831         }
00832 
00833         // Send patch local points
00834         forAll(processorPatches_, i)
00835         {
00836             label patchI = processorPatches_[i];
00837 
00838             const processorPolyPatch& procPatch =
00839                 refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchI]);
00840 
00841             OPstream toNeighbour(Pstream::blocking, procPatch.neighbProcNo());
00842 
00843             toNeighbour << procPatch.localPoints();
00844         }
00845 
00846         // Receive patch local points and uncount if coincident (and not shared)
00847         forAll(processorPatches_, i)
00848         {
00849             label patchI = processorPatches_[i];
00850 
00851             const processorPolyPatch& procPatch =
00852                 refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchI]);
00853 
00854             IPstream fromNeighbour(Pstream::blocking, procPatch.neighbProcNo());
00855 
00856             pointField nbrPoints(fromNeighbour);
00857 
00858             if (Pstream::myProcNo() > procPatch.neighbProcNo())
00859             {
00860                 labelList pMap;
00861                 matchPoints
00862                 (
00863                     procPatch.localPoints(),
00864                     nbrPoints,
00865                     scalarField(procPatch.nPoints(), tolDim),   // tolerance
00866                     false,      // verbosity
00867                     pMap        // map from my points to nbrPoints
00868                 );
00869 
00870                 forAll(pMap, patchPointI)
00871                 {
00872                     label meshPointI = procPatch.meshPoints()[patchPointI];
00873 
00874                     label stat = pointStatus.get(meshPointI);
00875 
00876                     if (stat == UNSET)
00877                     {
00878                         // Mark point as visited so if point is on multiple proc
00879                         // patches it only gets uncounted once.
00880                         pointStatus.set(meshPointI, VISITED);
00881 
00882                         if (pMap[patchPointI] != -1)
00883                         {
00884                             // Points share same coordinate so uncount.
00885                             nTotalPoints_--;
00886                         }
00887                     }
00888                 }
00889             }
00890         }
00891         // Sum all points
00892         reduce(nTotalPoints_, sumOp<label>());
00893     }
00894 
00895     // nTotalPoints has not been corrected yet for shared points. For these
00896     // just collect all their coordinates and count unique ones.
00897 
00898     label mySharedPoints = sharedPointLabels_.size();
00899     reduce(mySharedPoints, sumOp<label>());
00900 
00901     // Collect and merge shared points (does parallel communication)
00902     pointField geomSharedPoints(geometricSharedPoints());
00903     label nGeomSharedPoints = geomSharedPoints.size();
00904 
00905     // Shared points merged down to mergedPoints size.
00906     nTotalPoints_ -= mySharedPoints - nGeomSharedPoints;
00907 
00908     if (debug)
00909     {
00910         Pout<< "globalMeshData : nTotalPoints_:" << nTotalPoints_ << endl;
00911     }
00912 
00913     //
00914     // Now we have all info we wanted.
00915     // Do some checking (if debug is set)
00916     //
00917 
00918     if (debug)
00919     {
00920         if (Pstream::master())
00921         {
00922             // We have the geometricSharedPoints already so write them.
00923             // Ideally would like to write the networks of connected points as
00924             // well but this is harder. (Todo)
00925             Pout<< "globalMeshData : writing geometrically separated shared"
00926                 << " points to geomSharedPoints.obj" << endl;
00927 
00928             OFstream str("geomSharedPoints.obj");
00929 
00930             forAll(geomSharedPoints, i)
00931             {
00932                 const point& pt = geomSharedPoints[i];
00933 
00934                 str << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z()
00935                     << nl;
00936             }
00937         }
00938     }
00939 }
00940 
00941 
00942 // Write data
00943 bool Foam::globalMeshData::write() const
00944 {
00945     IOdictionary dict
00946     (
00947         IOobject
00948         (
00949             "parallelData",
00950             mesh_.facesInstance(),
00951             mesh_.meshSubDir,
00952             mesh_
00953         )
00954     );
00955 
00956     dict.add("nTotalPoints", nTotalPoints());
00957     dict.add("nTotalFaces", nTotalFaces());
00958     dict.add("nTotalCells", nTotalCells());
00959 
00960     dict.add("nGlobalPoints", nGlobalPoints());
00961     dict.add("sharedPointLabels", sharedPointLabels());
00962     dict.add("sharedPointAddr", sharedPointAddr());
00963     dict.add("sharedPointGlobalLabels", sharedPointGlobalLabels());
00964 
00965     return dict.writeObject
00966     (
00967         IOstream::ASCII,
00968         IOstream::currentVersion,
00969         IOstream::UNCOMPRESSED
00970     );
00971 }
00972 
00973 
00974 // * * * * * * * * * * * * * * * Ostream Operators * * * * * * * * * * * * * //
00975 
00976 Foam::Ostream& Foam::operator<<(Ostream& os, const globalMeshData& p)
00977 {
00978     os  << "nTotalPoints " << p.nTotalPoints() << token::END_STATEMENT << nl
00979         << "nTotalFaces " << p.nTotalFaces() << token::END_STATEMENT << nl
00980         << "nTotalCells " << p.nTotalCells() << token::END_STATEMENT << nl
00981         << "nGlobalPoints " << p.nGlobalPoints() << token::END_STATEMENT << nl
00982         << "sharedPointLabels " << p.sharedPointLabels()
00983         << token::END_STATEMENT << nl
00984         << "sharedPointAddr " << p.sharedPointAddr()
00985         << token::END_STATEMENT << endl;
00986 
00987     return os;
00988 }
00989 
00990 
00991 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines