1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "globalMeshData.H"
29 #include "PstreamCombineReduceOps.H"
30 #include "processorPolyPatch.H"
31 #include "demandDrivenData.H"
32 #include "globalPoints.H"
33 //#include "geomGlobalPoints.H"
34 #include "labelIOList.H"
35 #include "PackedList.H"
36 #include "mergePoints.H"
37 #include "matchPoints.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(Foam::globalMeshData, 0);
44 // Geometric matching tolerance. Factor of mesh bounding box.
45 const Foam::debug::tolerancesSwitch
46 Foam::globalMeshData::matchTol_
48 "globalMeshDataMatchTol",
53 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 // Collect processor patch addressing.
56 void Foam::globalMeshData::initProcAddr()
58 processorPatchIndices_.setSize(mesh_.boundaryMesh().size());
59 processorPatchIndices_ = -1;
61 processorPatchNeighbours_.setSize(mesh_.boundaryMesh().size());
62 processorPatchNeighbours_ = -1;
64 // Construct processor patch indexing. processorPatchNeighbours_ only
65 // set if running in parallel!
66 processorPatches_.setSize(mesh_.boundaryMesh().size());
68 label nNeighbours = 0;
70 forAll (mesh_.boundaryMesh(), patchi)
72 if (isA<processorPolyPatch>(mesh_.boundaryMesh()[patchi]))
74 processorPatches_[nNeighbours] = patchi;
75 processorPatchIndices_[patchi] = nNeighbours++;
78 processorPatches_.setSize(nNeighbours);
80 if (Pstream::parRun())
82 // Send indices of my processor patches to my neighbours
83 forAll (processorPatches_, i)
85 label patchi = processorPatches_[i];
90 refCast<const processorPolyPatch>
92 mesh_.boundaryMesh()[patchi]
96 toNeighbour << processorPatchIndices_[patchi];
99 forAll(processorPatches_, i)
101 label patchi = processorPatches_[i];
103 IPstream fromNeighbour
106 refCast<const processorPolyPatch>
108 mesh_.boundaryMesh()[patchi]
112 fromNeighbour >> processorPatchNeighbours_[patchi];
118 // Given information about locally used edges allocate global shared edges.
119 void Foam::globalMeshData::countSharedEdges
121 const HashTable<labelList, edge, Hash<edge> >& procSharedEdges,
122 HashTable<label, edge, Hash<edge> >& globalShared,
126 // Count occurrences of procSharedEdges in global shared edges table.
129 HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
130 procSharedEdges.begin();
131 iter != procSharedEdges.end();
135 const edge& e = iter.key();
137 HashTable<label, edge, Hash<edge> >::iterator globalFnd =
138 globalShared.find(e);
140 if (globalFnd == globalShared.end())
142 // First time occurrence of this edge. Check how many we are adding
143 if (iter().size() == 1)
145 // Only one edge. Mark with special value.
146 globalShared.insert(e, -1);
150 // Edge used more than once (even by local shared edges alone)
151 // so allocate proper shared edge label.
152 globalShared.insert(e, sharedEdgeI++);
157 if (globalFnd() == -1)
159 // Second time occurence of this edge. Assign proper
161 globalFnd() = sharedEdgeI++;
168 // Shared edges are shared between multiple processors. By their nature both
169 // of their endpoints are shared points. (but not all edges using two shared
170 // points are shared edges! There might e.g. be an edge between two unrelated
171 // clusters of shared points)
172 void Foam::globalMeshData::calcSharedEdges() const
174 if (nGlobalEdges_ != -1 || sharedEdgeLabelsPtr_ || sharedEdgeAddrPtr_)
176 FatalErrorIn("globalMeshData::calcSharedEdges()")
177 << "Shared edge addressing already done" << abort(FatalError);
181 const labelList& sharedPtAddr = sharedPointAddr();
182 const labelList& sharedPtLabels = sharedPointLabels();
184 // Since don't want to construct pointEdges for whole mesh create
185 // Map for all shared points.
186 Map<label> meshToShared(2*sharedPtLabels.size());
187 forAll(sharedPtLabels, i)
189 meshToShared.insert(sharedPtLabels[i], i);
192 // Find edges using shared points. Store correspondence to local edge
193 // numbering. Note that multiple local edges can have the same shared
194 // points! (for cyclics or separated processor patches)
195 HashTable<labelList, edge, Hash<edge> > localShared
197 2*sharedPtAddr.size()
200 const edgeList& edges = mesh_.edges();
204 const edge& e = edges[edgeI];
206 Map<label>::const_iterator e0Fnd = meshToShared.find(e[0]);
208 if (e0Fnd != meshToShared.end())
210 Map<label>::const_iterator e1Fnd = meshToShared.find(e[1]);
212 if (e1Fnd != meshToShared.end())
214 // Found edge which uses shared points. Probably shared.
216 // Construct the edge in shared points (or rather global
217 // indices of the shared points)
220 sharedPtAddr[e0Fnd()],
221 sharedPtAddr[e1Fnd()]
224 HashTable<labelList, edge, Hash<edge> >::iterator iter =
225 localShared.find(sharedEdge);
227 if (iter == localShared.end())
229 // First occurrence of this point combination. Store.
230 localShared.insert(sharedEdge, labelList(1, edgeI));
234 // Add this edge to list of edge labels.
235 labelList& edgeLabels = iter();
237 label sz = edgeLabels.size();
238 edgeLabels.setSize(sz+1);
239 edgeLabels[sz] = edgeI;
246 // Now we have a table on every processors which gives its edges which use
247 // shared points. Send this all to the master and have it allocate
248 // global edge numbers for it. But only allocate a global edge number for
249 // edge if it is used more than once!
250 // Note that we are now sending the whole localShared to the master whereas
251 // we only need the local count (i.e. the number of times a global edge is
252 // used). But then this only gets done once so not too bothered about the
253 // extra global communication.
255 HashTable<label, edge, Hash<edge> > globalShared(nGlobalPoints());
257 if (Pstream::master())
259 label sharedEdgeI = 0;
261 // Merge my shared edges into the global list
264 Pout<< "globalMeshData::calcSharedEdges : Merging in from proc0 : "
265 << localShared.size() << endl;
267 countSharedEdges(localShared, globalShared, sharedEdgeI);
269 // Receive data from slaves and insert
270 if (Pstream::parRun())
274 int slave=Pstream::firstSlave();
275 slave<=Pstream::lastSlave();
279 // Receive the edges using shared points from the slave.
280 IPstream fromSlave(Pstream::blocking, slave);
281 HashTable<labelList, edge, Hash<edge> > procSharedEdges
288 Pout<< "globalMeshData::calcSharedEdges : "
289 << "Merging in from proc"
290 << Foam::name(slave) << " : " << procSharedEdges.size()
293 countSharedEdges(procSharedEdges, globalShared, sharedEdgeI);
297 // Now our globalShared should have some edges with -1 as edge label
298 // These were only used once so are not proper shared edges.
301 HashTable<label, edge, Hash<edge> > oldSharedEdges(globalShared);
303 globalShared.clear();
307 HashTable<label, edge, Hash<edge> >::const_iterator iter =
308 oldSharedEdges.begin();
309 iter != oldSharedEdges.end();
315 globalShared.insert(iter.key(), iter());
320 Pout<< "globalMeshData::calcSharedEdges : Filtered "
321 << oldSharedEdges.size()
322 << " down to " << globalShared.size() << endl;
327 // Send back to slaves.
328 if (Pstream::parRun())
332 int slave=Pstream::firstSlave();
333 slave<=Pstream::lastSlave();
337 // Receive the edges using shared points from the slave.
338 OPstream toSlave(Pstream::blocking, slave);
339 toSlave << globalShared;
345 // Send local edges to master
347 OPstream toMaster(Pstream::blocking, Pstream::masterNo());
349 toMaster << localShared;
351 // Receive merged edges from master.
353 IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
355 fromMaster >> globalShared;
359 // Now use the global shared edges list (globalShared) to classify my local
360 // ones (localShared)
362 nGlobalEdges_ = globalShared.size();
364 DynamicList<label> dynSharedEdgeLabels(globalShared.size());
365 DynamicList<label> dynSharedEdgeAddr(globalShared.size());
369 HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
371 iter != localShared.end();
375 const edge& e = iter.key();
377 HashTable<label, edge, Hash<edge> >::const_iterator edgeFnd =
378 globalShared.find(e);
380 if (edgeFnd != globalShared.end())
382 // My local edge is indeed a shared one. Go through all local edge
383 // labels with this point combination.
384 const labelList& edgeLabels = iter();
386 forAll(edgeLabels, i)
388 // Store label of local mesh edge
389 dynSharedEdgeLabels.append(edgeLabels[i]);
391 // Store label of shared edge
392 dynSharedEdgeAddr.append(edgeFnd());
397 sharedEdgeLabelsPtr_ = new labelList();
398 labelList& sharedEdgeLabels = *sharedEdgeLabelsPtr_;
399 sharedEdgeLabels.transfer(dynSharedEdgeLabels);
401 sharedEdgeAddrPtr_ = new labelList();
402 labelList& sharedEdgeAddr = *sharedEdgeAddrPtr_;
403 sharedEdgeAddr.transfer(dynSharedEdgeAddr);
407 Pout<< "globalMeshData : nGlobalEdges_:" << nGlobalEdges_ << nl
408 << "globalMeshData : sharedEdgeLabels:" << sharedEdgeLabels.size()
410 << "globalMeshData : sharedEdgeAddr:" << sharedEdgeAddr.size()
416 // Helper function to count coincident faces. This part used to be
417 // in updateMesh but I've had to move it to a separate function
418 // because of aliasing optimisation errors in icc9.1 on the
420 Foam::label Foam::globalMeshData::countCoincidentFaces
423 const vectorField& separationDist
426 label nCoincident = 0;
428 forAll(separationDist, faceI)
430 if (mag(separationDist[faceI]) < tolDim)
440 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
442 // Construct from polyMesh
443 Foam::globalMeshData::globalMeshData(const polyMesh& mesh)
445 processorTopology(mesh.boundaryMesh()),
447 bb_(vector::zero, vector::zero),
451 processorPatches_(0),
452 processorPatchIndices_(0),
453 processorPatchNeighbours_(0),
455 sharedPointLabels_(0),
457 sharedPointGlobalLabelsPtr_(NULL),
459 sharedEdgeLabelsPtr_(NULL),
460 sharedEdgeAddrPtr_(NULL)
466 // Read constructor given IOobject and a polyMesh reference
467 Foam::globalMeshData::globalMeshData(const IOobject& io, const polyMesh& mesh)
469 processorTopology(mesh.boundaryMesh()),
475 processorPatches_(0),
476 processorPatchIndices_(0),
477 processorPatchNeighbours_(0),
479 sharedPointLabels_(0),
481 sharedPointGlobalLabelsPtr_(NULL),
483 sharedEdgeLabelsPtr_(NULL),
484 sharedEdgeAddrPtr_(NULL)
488 IOdictionary dict(io);
490 dict.lookup("nTotalPoints") >> nTotalPoints_;
491 dict.lookup("nTotalFaces") >> nTotalFaces_;
492 dict.lookup("nTotalCells") >> nTotalCells_;
493 dict.lookup("nGlobalPoints") >> nGlobalPoints_;
494 dict.lookup("sharedPointLabels") >> sharedPointLabels_;
495 dict.lookup("sharedPointAddr") >> sharedPointAddr_;
496 labelList sharedPointGlobalLabels(dict.lookup("sharedPointGlobalLabels"));
498 sharedPointGlobalLabelsPtr_ = new labelList(sharedPointGlobalLabels);
502 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
504 Foam::globalMeshData::~globalMeshData()
510 void Foam::globalMeshData::clearOut()
512 deleteDemandDrivenData(sharedPointGlobalLabelsPtr_);
515 deleteDemandDrivenData(sharedEdgeLabelsPtr_);
516 deleteDemandDrivenData(sharedEdgeAddrPtr_);
520 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
522 // Return shared point global labels.
523 const Foam::labelList& Foam::globalMeshData::sharedPointGlobalLabels() const
525 if (!sharedPointGlobalLabelsPtr_)
527 sharedPointGlobalLabelsPtr_ = new labelList(sharedPointLabels_.size());
528 labelList& sharedPointGlobalLabels = *sharedPointGlobalLabelsPtr_;
532 "pointProcAddressing",
533 mesh_.facesInstance()/mesh_.meshSubDir,
538 if (addrHeader.headerOk())
540 // There is a pointProcAddressing file so use it to get labels
541 // on the original mesh
542 Pout<< "globalMeshData::sharedPointGlobalLabels : "
543 << "Reading pointProcAddressing" << endl;
545 labelIOList pointProcAddressing(addrHeader);
547 forAll(sharedPointLabels_, i)
550 label pointI = sharedPointLabels_[i];
552 // Map to mesh point of original mesh
553 sharedPointGlobalLabels[i] = pointProcAddressing[pointI];
558 Pout<< "globalMeshData::sharedPointGlobalLabels :"
559 << " Setting pointProcAddressing to -1" << endl;
561 sharedPointGlobalLabels = -1;
564 return *sharedPointGlobalLabelsPtr_;
568 // Collect coordinates of shared points. (does parallel communication!)
569 Foam::pointField Foam::globalMeshData::sharedPoints() const
571 // Get all processors to send their shared points to master.
572 // (not very efficient)
574 pointField sharedPoints(nGlobalPoints_);
576 if (Pstream::master())
579 // insert my own data first
580 forAll(sharedPointLabels_, i)
582 label sharedPointI = sharedPointAddr_[i];
584 sharedPoints[sharedPointI] = mesh_.points()[sharedPointLabels_[i]];
587 // Receive data from slaves and insert
590 int slave=Pstream::firstSlave();
591 slave<=Pstream::lastSlave();
595 IPstream fromSlave(Pstream::blocking, slave);
597 labelList nbrSharedPointAddr;
598 pointField nbrSharedPoints;
599 fromSlave >> nbrSharedPointAddr >> nbrSharedPoints;
601 forAll(nbrSharedPointAddr, i)
603 label sharedPointI = nbrSharedPointAddr[i];
605 sharedPoints[sharedPointI] = nbrSharedPoints[i];
612 int slave=Pstream::firstSlave();
613 slave<=Pstream::lastSlave();
621 sharedPoints.size()*sizeof(vector::zero)
623 toSlave << sharedPoints;
631 OPstream toMaster(Pstream::blocking, Pstream::masterNo());
635 << UIndirectList<point>(mesh_.points(), sharedPointLabels_)();
638 // Receive sharedPoints
640 IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
641 fromMaster >> sharedPoints;
649 // Collect coordinates of shared points. (does parallel communication!)
650 Foam::pointField Foam::globalMeshData::geometricSharedPoints() const
652 // Get coords of my shared points
653 pointField sharedPoints(sharedPointLabels_.size());
655 forAll(sharedPointLabels_, i)
657 label meshPointI = sharedPointLabels_[i];
659 sharedPoints[i] = mesh_.points()[meshPointI];
662 // Append from all processors
663 combineReduce(sharedPoints, plusEqOp<pointField>());
666 scalar tolDim = matchTol_()*bb_.mag();
668 // And see how many are unique
670 pointField mergedPoints;
674 sharedPoints, // coordinates to merge
685 Foam::label Foam::globalMeshData::nGlobalEdges() const
687 if (nGlobalEdges_ == -1)
691 return nGlobalEdges_;
695 const Foam::labelList& Foam::globalMeshData::sharedEdgeLabels() const
697 if (!sharedEdgeLabelsPtr_)
701 return *sharedEdgeLabelsPtr_;
705 const Foam::labelList& Foam::globalMeshData::sharedEdgeAddr() const
707 if (!sharedEdgeAddrPtr_)
711 return *sharedEdgeAddrPtr_;
715 void Foam::globalMeshData::movePoints(const pointField& newPoints)
717 // Topology does not change and we don't store any geometry so nothing
722 // Update all data after morph
723 void Foam::globalMeshData::updateMesh()
725 // Clear out old data
728 // Do processor patch addressing
731 // Note: boundBox does reduce
732 bb_ = boundBox(mesh_.points());
734 scalar tolDim = matchTol_()*bb_.mag();
738 Pout<< "globalMeshData : bb_:" << bb_
739 << " merge dist:" << tolDim << endl;
743 // Option 1. Topological
745 // Calculate all shared points. This does all the hard work.
746 globalPoints parallelPoints(mesh_);
749 nGlobalPoints_ = parallelPoints.nGlobalPoints();
750 sharedPointLabels_ = parallelPoints.sharedPointLabels();
751 sharedPointAddr_ = parallelPoints.sharedPointAddr();
754 //// Option 2. Geometric
756 // // Calculate all shared points. This does all the hard work.
757 // geomGlobalPoints parallelPoints(mesh_, tolDim);
760 // nGlobalPoints_ = parallelPoints.nGlobalPoints();
761 // sharedPointLabels_ = parallelPoints.sharedPointLabels();
762 // sharedPointAddr_ = parallelPoints.sharedPointAddr();
764 // nGlobalEdges_ = parallelPoints.nGlobalEdges();
765 // sharedEdgeLabels_ = parallelPoints.sharedEdgeLabels();
766 // sharedEdgeAddr_ = parallelPoints.sharedEdgeAddr();
769 // Total number of faces. Start off from all faces. Remove coincident
770 // processor faces (on highest numbered processor) before summing.
771 nTotalFaces_ = mesh_.nFaces();
773 // Do not count processor-patch faces that are coincident.
774 forAll(processorPatches_, i)
776 label patchI = processorPatches_[i];
778 const processorPolyPatch& procPatch =
779 refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchI]);
781 if (Pstream::myProcNo() > procPatch.neighbProcNo())
783 // Uncount my faces. Handle cyclics separately.
785 if (procPatch.separated())
787 const vectorField& separationDist = procPatch.separation();
789 nTotalFaces_ -= countCoincidentFaces(tolDim, separationDist);
793 // Normal, unseparated processor patch. Remove duplicates.
794 nTotalFaces_ -= procPatch.size();
798 reduce(nTotalFaces_, sumOp<label>());
802 Pout<< "globalMeshData : nTotalFaces_:" << nTotalFaces_ << endl;
806 nTotalCells_ = mesh_.nCells();
807 reduce(nTotalCells_, sumOp<label>());
811 Pout<< "globalMeshData : nTotalCells_:" << nTotalCells_ << endl;
814 nTotalPoints_ = mesh_.nPoints();
816 // Correct points for duplicate ones. We have
817 // - points shared between 2 processor patches only. Count only on
818 // lower numbered processor. Make sure to count only once since points
819 // can be on multiple patches on the same processor.
820 // - globally shared points.
822 if (Pstream::parRun())
824 const label UNSET = 0; // not set
825 const label SHARED = 1; // globally shared
826 const label VISITED = 2; // corrected for
828 // Mark globally shared points
829 PackedList<2> pointStatus(mesh_.nPoints(), UNSET);
831 forAll(sharedPointLabels_, i)
833 label meshPointI = sharedPointLabels_[i];
835 pointStatus.set(meshPointI, SHARED);
838 // Send patch local points
839 forAll(processorPatches_, i)
841 label patchI = processorPatches_[i];
843 const processorPolyPatch& procPatch =
844 refCast<const processorPolyPatch>
846 mesh_.boundaryMesh()[patchI]
849 OPstream toNeighbour(Pstream::blocking, procPatch.neighbProcNo());
851 toNeighbour << procPatch.localPoints();
854 // Receive patch local points and uncount if coincident and not shared
855 forAll(processorPatches_, i)
857 label patchI = processorPatches_[i];
859 const processorPolyPatch& procPatch =
860 refCast<const processorPolyPatch>
862 mesh_.boundaryMesh()[patchI]
865 IPstream fromNeighbour
868 procPatch.neighbProcNo()
871 pointField nbrPoints(fromNeighbour);
873 if (Pstream::myProcNo() > procPatch.neighbProcNo())
878 procPatch.localPoints(),
880 scalarField(procPatch.nPoints(), tolDim), // tolerance
882 pMap // map from my points to nbrPoints
885 forAll(pMap, patchPointI)
887 label meshPointI = procPatch.meshPoints()[patchPointI];
889 label stat = pointStatus.get(meshPointI);
893 // Mark point as visited so if point is on multipl
894 // e processor patches it only gets uncounted once
895 pointStatus.set(meshPointI, VISITED);
897 if (pMap[patchPointI] != -1)
899 // Points share same coordinate so uncount.
907 reduce(nTotalPoints_, sumOp<label>());
910 // nTotalPoints has not been corrected yet for shared points. For these
911 // just collect all their coordinates and count unique ones.
913 label mySharedPoints = sharedPointLabels_.size();
914 reduce(mySharedPoints, sumOp<label>());
916 // Collect and merge shared points (does parallel communication)
917 pointField geomSharedPoints(geometricSharedPoints());
918 label nGeomSharedPoints = geomSharedPoints.size();
920 // Shared points merged down to mergedPoints size.
921 nTotalPoints_ -= mySharedPoints - nGeomSharedPoints;
925 Pout<< "globalMeshData : nTotalPoints_:" << nTotalPoints_ << endl;
929 // Now we have all info we wanted.
930 // Do some checking (if debug is set)
935 if (Pstream::master())
937 // We have the geometricSharedPoints already so write them.
938 // Ideally would like to write the networks of connected points as
939 // well but this is harder. (Todo)
940 Pout<< "globalMeshData : writing geometrically separated shared"
941 << " points to geomSharedPoints.obj" << endl;
943 OFstream str("geomSharedPoints.obj");
945 forAll(geomSharedPoints, i)
947 const point& pt = geomSharedPoints[i];
949 str << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z()
958 bool Foam::globalMeshData::write() const
965 mesh_.facesInstance(),
971 dict.add("nTotalPoints", nTotalPoints());
972 dict.add("nTotalFaces", nTotalFaces());
973 dict.add("nTotalCells", nTotalCells());
975 dict.add("nGlobalPoints", nGlobalPoints());
976 dict.add("sharedPointLabels", sharedPointLabels());
977 dict.add("sharedPointAddr", sharedPointAddr());
978 dict.add("sharedPointGlobalLabels", sharedPointGlobalLabels());
980 return dict.writeObject
983 IOstream::currentVersion,
984 IOstream::UNCOMPRESSED
989 // * * * * * * * * * * * * * * * Ostream Operators * * * * * * * * * * * * * //
991 Foam::Ostream& Foam::operator<<(Ostream& os, const globalMeshData& p)
993 os << "nTotalPoints " << p.nTotalPoints() << token::END_STATEMENT << nl
994 << "nTotalFaces " << p.nTotalFaces() << token::END_STATEMENT << nl
995 << "nTotalCells " << p.nTotalCells() << token::END_STATEMENT << nl
996 << "nGlobalPoints " << p.nGlobalPoints() << token::END_STATEMENT << nl
997 << "sharedPointLabels " << p.sharedPointLabels()
998 << token::END_STATEMENT << nl
999 << "sharedPointAddr " << p.sharedPointAddr()
1000 << token::END_STATEMENT << endl;
1006 // ************************************************************************* //