Report patch name instead of index in debug
[foam-extend-3.2.git] / src / foam / meshes / polyMesh / polyBoundaryMesh / polyBoundaryMesh.C
blob112fede7c3760078d30f1435d8f9016b5cd8da61
1 /*---------------------------------------------------------------------------*\
2   =========                 |
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 -------------------------------------------------------------------------------
8 License
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 "polyBoundaryMesh.H"
27 #include "polyMesh.H"
28 #include "primitiveMesh.H"
29 #include "processorPolyPatch.H"
30 #include "stringListOps.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(Foam::polyBoundaryMesh, 0);
37 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
39 Foam::labelList Foam::polyBoundaryMesh::ident(const label len)
41     labelList elems(len);
42     forAll(elems, elemI)
43     {
44         elems[elemI] = elemI;
45     }
46     return elems;
50 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
52 Foam::polyBoundaryMesh::polyBoundaryMesh
54     const IOobject& io,
55     const polyMesh& mesh
58     polyPatchList(),
59     regIOobject(io),
60     mesh_(mesh),
61     neighbourEdgesPtr_(NULL)
63     if (readOpt() == IOobject::MUST_READ)
64     {
65         polyPatchList& patches = *this;
67         // Read polyPatchList
68         Istream& is = readStream(typeName);
70         PtrList<entry> patchEntries(is);
71         patches.setSize(patchEntries.size());
73         forAll(patches, patchI)
74         {
75             patches.set
76             (
77                 patchI,
78                 polyPatch::New
79                 (
80                     patchEntries[patchI].keyword(),
81                     patchEntries[patchI].dict(),
82                     patchI,
83                     *this
84                 )
85             );
86         }
88         // Check state of IOstream
89         is.check
90         (
91             "polyBoundaryMesh::polyBoundaryMesh"
92             "(const IOobject&, const polyMesh&)"
93         );
95         close();
96     }
100 Foam::polyBoundaryMesh::polyBoundaryMesh
102     const IOobject& io,
103     const polyMesh& pm,
104     const label size
107     polyPatchList(size),
108     regIOobject(io),
109     mesh_(pm),
110     neighbourEdgesPtr_(NULL)
114 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
116 Foam::polyBoundaryMesh::~polyBoundaryMesh()
118     deleteDemandDrivenData(neighbourEdgesPtr_);
122 void Foam::polyBoundaryMesh::clearGeom()
124     forAll (*this, patchi)
125     {
126         operator[](patchi).clearGeom();
127     }
131 void Foam::polyBoundaryMesh::clearAddressing()
133     deleteDemandDrivenData(neighbourEdgesPtr_);
135     forAll (*this, patchi)
136     {
137         operator[](patchi).clearAddressing();
138     }
142 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
144 void Foam::polyBoundaryMesh::calcGeometry()
146     // Calculation of addressing, with communication
147     // HJ, 12/Jun/2011
148     forAll(*this, patchi)
149     {
150         operator[](patchi).initAddressing();
151     }
153     forAll(*this, patchi)
154     {
155         operator[](patchi).calcAddressing();
156     }
158     // Calculation of geometry with communications
159     forAll(*this, patchi)
160     {
161         operator[](patchi).initGeometry();
162     }
164     forAll(*this, patchi)
165     {
166         operator[](patchi).calcGeometry();
167     }
171 const Foam::labelPairListList&
172 Foam::polyBoundaryMesh::neighbourEdges() const
174     if (Pstream::parRun())
175     {
176         WarningIn("polyBoundaryMesh::neighbourEdges() const")
177             << "Neighbour edge addressing not correct across parallel"
178             << " boundaries." << endl;
179     }
181     if (!neighbourEdgesPtr_)
182     {
183         neighbourEdgesPtr_ = new labelPairListList(size());
184         labelPairListList& neighbourEdges = *neighbourEdgesPtr_;
186         // Initialize.
187         label nEdgePairs = 0;
188         forAll(*this, patchi)
189         {
190             const polyPatch& pp = operator[](patchi);
192             neighbourEdges[patchi].setSize(pp.nEdges() - pp.nInternalEdges());
194             forAll(neighbourEdges[patchi], i)
195             {
196                 labelPair& edgeInfo = neighbourEdges[patchi][i];
198                 edgeInfo[0] = -1;
199                 edgeInfo[1] = -1;
200             }
202             nEdgePairs += pp.nEdges() - pp.nInternalEdges();
203         }
205         // From mesh edge (expressed as a point pair so as not to construct
206         // point addressing) to patch + relative edge index.
207         HashTable<labelPair, edge, Hash<edge> > pointsToEdge(nEdgePairs);
209         forAll(*this, patchi)
210         {
211             const polyPatch& pp = operator[](patchi);
213             const edgeList& edges = pp.edges();
215             for
216             (
217                 label edgei = pp.nInternalEdges();
218                 edgei < edges.size();
219                 edgei++
220             )
221             {
222                 // Edge in patch local points
223                 const edge& e = edges[edgei];
225                 // Edge in mesh points.
226                 edge meshEdge(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]);
228                 HashTable<labelPair, edge, Hash<edge> >::iterator fnd =
229                     pointsToEdge.find(meshEdge);
231                 if (fnd == pointsToEdge.end())
232                 {
233                     // First occurrence of mesh edge. Store patch and my
234                     // local index.
235                     pointsToEdge.insert
236                     (
237                         meshEdge,
238                         labelPair
239                         (
240                             patchi,
241                             edgei - pp.nInternalEdges()
242                         )
243                     );
244                 }
245                 else
246                 {
247                     // Second occurrence. Store.
248                     const labelPair& edgeInfo = fnd();
250                     neighbourEdges[patchi][edgei - pp.nInternalEdges()] =
251                         edgeInfo;
253                     neighbourEdges[edgeInfo[0]][edgeInfo[1]]
254                          = labelPair(patchi, edgei - pp.nInternalEdges());
256                     // Found all two occurrences of this edge so remove from
257                     // hash to save space. Note that this will give lots of
258                     // problems if the polyBoundaryMesh is multiply connected.
259                     pointsToEdge.erase(meshEdge);
260                 }
261             }
262         }
264         if (pointsToEdge.size())
265         {
266             FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
267                 << "Not all boundary edges of patches match up." << nl
268                 << "Is the outside of your mesh multiply connected?"
269                 << abort(FatalError);
270         }
272         forAll(*this, patchi)
273         {
274             const polyPatch& pp = operator[](patchi);
276             const labelPairList& nbrEdges = neighbourEdges[patchi];
278             forAll(nbrEdges, i)
279             {
280                 const labelPair& edgeInfo = nbrEdges[i];
282                 if (edgeInfo[0] == -1 || edgeInfo[1] == -1)
283                 {
284                     label edgeI = pp.nInternalEdges() + i;
285                     const edge& e = pp.edges()[edgeI];
287                     FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
288                         << "Not all boundary edges of patches match up." << nl
289                         << "Edge " << edgeI << " on patch " << pp.name()
290                         << " end points " << pp.localPoints()[e[0]] << ' '
291                         << pp.localPoints()[e[1]] << " is not matched to an"
292                         << " edge on any other patch." << nl
293                         << "Is the outside of your mesh multiply connected?"
294                         << abort(FatalError);
295                 }
296             }
297         }
298     }
300     return *neighbourEdgesPtr_;
304 Foam::wordList Foam::polyBoundaryMesh::names() const
306     const polyPatchList& patches = *this;
308     wordList t(patches.size());
310     forAll (patches, patchI)
311     {
312         t[patchI] = patches[patchI].name();
313     }
315     return t;
319 Foam::wordList Foam::polyBoundaryMesh::types() const
321     const polyPatchList& patches = *this;
323     wordList t(patches.size());
325     forAll (patches, patchI)
326     {
327         t[patchI] = patches[patchI].type();
328     }
330     return t;
334 Foam::wordList Foam::polyBoundaryMesh::physicalTypes() const
336     const polyPatchList& patches = *this;
338     wordList t(patches.size());
340     forAll (patches, patchI)
341     {
342         t[patchI] = patches[patchI].physicalType();
343     }
345     return t;
349 Foam::label Foam::polyBoundaryMesh::findPatchID(const word& patchName) const
351     const polyPatchList& patches = *this;
353     forAll (patches, patchI)
354     {
355         // Check only if pointer is set.  HJ, 28/Jan/2011
356         if (patches.set(patchI))
357         {
358             if (patches[patchI].name() == patchName)
359             {
360                 return patchI;
361             }
362         }
363     }
365     // Patch not found
366     if (debug)
367     {
368         Pout<< "label polyBoundaryMesh::findPatchID(const word& "
369             << "patchName) const"
370             << "Patch named " << patchName << " not found.  "
371             << "List of available patch names: " << names() << endl;
372     }
374     // Not found, return -1
375     return -1;
379 Foam::label Foam::polyBoundaryMesh::whichPatch(const label faceIndex) const
381     // Find out which patch the current face belongs to by comparing label
382     // with patch start labels.
383     // If the face is internal, return -1;
384     // if it is off the end of the list, abort
385     if (faceIndex >= mesh().nFaces())
386     {
387         FatalErrorIn
388         (
389             "polyBoundaryMesh::whichPatch(const label faceIndex) const"
390         )   << "given label greater than the number of geometric faces"
391             << abort(FatalError);
392     }
394     if (faceIndex < mesh().nInternalFaces())
395     {
396         return -1;
397     }
399     forAll (*this, patchI)
400     {
401         const polyPatch& bp = operator[](patchI);
403         if
404         (
405             faceIndex >= bp.start()
406          && faceIndex < bp.start() + bp.size()
407         )
408         {
409             return patchI;
410         }
411     }
413     // If not in any of above, it is trouble!
414     FatalErrorIn
415     (
416         "label polyBoundaryMesh::whichPatch(const label faceIndex) const"
417     )   << "Cannot find face " << faceIndex << " in any of the patches "
418         << names() << nl
419         << "It seems your patches are not consistent with the mesh :"
420         << " internalFaces:" << mesh().nInternalFaces()
421         << "  total number of faces:" << mesh().nFaces()
422         << abort(FatalError);
424     return -1;
428 Foam::labelHashSet Foam::polyBoundaryMesh::patchSet
430     const wordList& patchNames
431 ) const
433     wordList allPatchNames = names();
434     labelHashSet ps(size());
436     forAll(patchNames, i)
437     {
438         // Treat the given patch names as wild-cards and search the set
439         // of all patch names for matches
440         labelList patchIDs = findStrings(patchNames[i], allPatchNames);
442         if (patchIDs.empty())
443         {
444             WarningIn("polyBoundaryMesh::patchSet(const wordList&)")
445                 << "Cannot find any patch names matching " << patchNames[i]
446                 << endl;
447         }
449         forAll(patchIDs, j)
450         {
451             ps.insert(patchIDs[j]);
452         }
453     }
455     return ps;
459 bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
461     if (!Pstream::parRun())
462     {
463         return false;
464     }
467     const polyBoundaryMesh& bm = *this;
469     bool boundaryError = false;
471     // Collect non-proc patches and check proc patches are last.
472     wordList names(bm.size());
473     wordList types(bm.size());
475     label nonProcI = 0;
477     forAll (bm, patchI)
478     {
479         if (!isA<processorPolyPatch>(bm[patchI]))
480         {
481             if (nonProcI != patchI)
482             {
483                 // There is processor patch inbetween normal patches.
484                 boundaryError = true;
486                 if (debug || report)
487                 {
488                     Pout<< " ***Problem with boundary patch " << patchI
489                         << " named " << bm[patchI].name()
490                         << " of type " <<  bm[patchI].type()
491                         << ". The patch seems to be preceeded by processor"
492                         << " patches. This is can give problems."
493                         << endl;
494                 }
495             }
496             else
497             {
498                 names[nonProcI] = bm[patchI].name();
499                 types[nonProcI] = bm[patchI].type();
500                 nonProcI++;
501             }
502         }
503     }
504     names.setSize(nonProcI);
505     types.setSize(nonProcI);
507     List<wordList> allNames(Pstream::nProcs());
508     allNames[Pstream::myProcNo()] = names;
509     Pstream::gatherList(allNames);
510     Pstream::scatterList(allNames);
512     List<wordList> allTypes(Pstream::nProcs());
513     allTypes[Pstream::myProcNo()] = types;
514     Pstream::gatherList(allTypes);
515     Pstream::scatterList(allTypes);
517     // Have every processor check but only master print error.
519     for (label procI = 1; procI < allNames.size(); procI++)
520     {
521         if
522         (
523             (allNames[procI] != allNames[0])
524          || (allTypes[procI] != allTypes[0])
525         )
526         {
527             boundaryError = true;
529             if (debug || (report && Pstream::master()))
530             {
531                 Info<< " ***Inconsistent patches across processors, "
532                        "processor 0 has patch names:" << allNames[0]
533                     << " patch types:" << allTypes[0]
534                     << " processor " << procI << " has patch names:"
535                     << allNames[procI]
536                     << " patch types:" << allTypes[procI]
537                     << endl;
538             }
539         }
540     }
542     return boundaryError;
546 bool Foam::polyBoundaryMesh::checkDefinition(const bool report) const
548     label nextPatchStart = mesh().nInternalFaces();
549     const polyBoundaryMesh& bm = *this;
551     bool boundaryError = false;
553     forAll (bm, patchI)
554     {
555         if (bm[patchI].start() != nextPatchStart && !boundaryError)
556         {
557             boundaryError = true;
559             Info<< " ****Problem with boundary patch " << patchI
560                 << " named " << bm[patchI].name()
561                 << " of type " <<  bm[patchI].type()
562                 << ". The patch should start on face no " << nextPatchStart
563                 << " and the patch specifies " << bm[patchI].start()
564                 << "." << endl
565                 << "Possibly consecutive patches have this same problem."
566                 << " Suppressing future warnings." << endl;
567         }
569         nextPatchStart += bm[patchI].size();
570     }
572     reduce(boundaryError, orOp<bool>());
574     if (boundaryError)
575     {
576         if (debug || report)
577         {
578             Pout << " ***Boundary definition is in error." << endl;
579         }
581         return true;
582     }
583     else
584     {
585         if (debug || report)
586         {
587             Info << "    Boundary definition OK." << endl;
588         }
590         return false;
591     }
595 void Foam::polyBoundaryMesh::movePoints(const pointField& p)
597     polyPatchList& patches = *this;
599     forAll(patches, patchi)
600     {
601         patches[patchi].initMovePoints(p);
602     }
604     forAll(patches, patchi)
605     {
606         patches[patchi].movePoints(p);
607     }
611 void Foam::polyBoundaryMesh::updateMesh()
613     deleteDemandDrivenData(neighbourEdgesPtr_);
615     polyPatchList& patches = *this;
617     forAll(patches, patchi)
618     {
619         patches[patchi].initUpdateMesh();
620     }
622     forAll(patches, patchi)
623     {
624         patches[patchi].updateMesh();
625     }
627     // Calculation of addressing, with communication
628     // HJ, 12/Jun/2011
629     forAll(*this, patchi)
630     {
631         operator[](patchi).initAddressing();
632     }
634     forAll(*this, patchi)
635     {
636         operator[](patchi).calcAddressing();
637     }
639     // Calculation of geometry with communications
640     forAll(*this, patchi)
641     {
642         operator[](patchi).initGeometry();
643     }
645     forAll(*this, patchi)
646     {
647         operator[](patchi).calcGeometry();
648     }
652 void Foam::polyBoundaryMesh::reorder(const UList<label>& oldToNew)
654     // Change order of patches
655     polyPatchList::reorder(oldToNew);
657     // Adapt indices
658     polyPatchList& patches = *this;
660     forAll(patches, patchi)
661     {
662         patches[patchi].index() = patchi;
663     }
665     updateMesh();
669 bool Foam::polyBoundaryMesh::writeData(Ostream& os) const
671     const polyPatchList& patches = *this;
673     os  << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
675     forAll(patches, patchi)
676     {
677         os  << indent << patches[patchi].name() << nl
678             << indent << token::BEGIN_BLOCK << nl
679             << incrIndent << patches[patchi] << decrIndent
680             << indent << token::END_BLOCK << endl;
681     }
683     os  << decrIndent << token::END_LIST;
685     // Check state of IOstream
686     os.check("polyBoundaryMesh::writeData(Ostream& os) const");
688     return os.good();
692 bool Foam::polyBoundaryMesh::writeObject
694     IOstream::streamFormat fmt,
695     IOstream::versionNumber ver,
696     IOstream::compressionType cmp
697 ) const
699     return regIOobject::writeObject(fmt, ver, IOstream::UNCOMPRESSED);
702 // * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * * //
704 const Foam::polyPatch& Foam::polyBoundaryMesh::operator[]
706     const word& patchName
707 ) const
709     const label patchI = findPatchID(patchName);
711     if (patchI < 0)
712     {
713         FatalErrorIn
714         (
715             "polyBoundaryMesh::operator[](const word&) const"
716         )   << "Patch named " << patchName << " not found." << nl
717             << "Available patch names: " << names() << endl
718             << abort(FatalError);
719     }
721     return operator[](patchI);
725 Foam::polyPatch& Foam::polyBoundaryMesh::operator[]
727     const word& patchName
730     const label patchI = findPatchID(patchName);
732     if (patchI < 0)
733     {
734         FatalErrorIn
735         (
736             "polyBoundaryMesh::operator[](const word&)"
737         )   << "Patch named " << patchName << " not found." << nl
738             << "Available patch names: " << names() << endl
739             << abort(FatalError);
740     }
742     return operator[](patchI);
746 // * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
748 Foam::Ostream& Foam::operator<<(Ostream& os, const polyBoundaryMesh& pbm)
750     pbm.writeData(os);
751     return os;
755 // ************************************************************************* //