FreeFOAM The Cross-Platform CFD Toolkit
polyBoundaryMesh.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "polyBoundaryMesh.H"
27 #include <OpenFOAM/polyMesh.H>
28 #include <OpenFOAM/primitiveMesh.H>
30 #include <OpenFOAM/stringListOps.H>
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
35 
36 
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 
39 Foam::labelList Foam::polyBoundaryMesh::ident(const label len)
40 {
41  labelList elems(len);
42  forAll(elems, elemI)
43  {
44  elems[elemI] = elemI;
45  }
46  return elems;
47 }
48 
49 
50 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
51 
52 Foam::polyBoundaryMesh::polyBoundaryMesh
53 (
54  const IOobject& io,
55  const polyMesh& mesh
56 )
57 :
58  polyPatchList(),
59  regIOobject(io),
60  mesh_(mesh),
61  neighbourEdgesPtr_(NULL)
62 {
63  if (readOpt() == IOobject::MUST_READ)
64  {
65  polyPatchList& patches = *this;
66 
67  // Read polyPatchList
68  Istream& is = readStream(typeName);
69 
70  PtrList<entry> patchEntries(is);
71  patches.setSize(patchEntries.size());
72 
73  forAll(patches, patchI)
74  {
75  patches.set
76  (
77  patchI,
79  (
80  patchEntries[patchI].keyword(),
81  patchEntries[patchI].dict(),
82  patchI,
83  *this
84  )
85  );
86  }
87 
88  // Check state of IOstream
89  is.check
90  (
91  "polyBoundaryMesh::polyBoundaryMesh"
92  "(const IOobject&, const polyMesh&)"
93  );
94 
95  close();
96  }
97 }
98 
99 
100 Foam::polyBoundaryMesh::polyBoundaryMesh
101 (
102  const IOobject& io,
103  const polyMesh& pm,
104  const label size
105 )
106 :
107  polyPatchList(size),
108  regIOobject(io),
109  mesh_(pm),
110  neighbourEdgesPtr_(NULL)
111 {}
112 
113 
114 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
115 
117 {
118  deleteDemandDrivenData(neighbourEdgesPtr_);
119 }
120 
121 
123 {
124  forAll (*this, patchi)
125  {
126  operator[](patchi).clearGeom();
127  }
128 }
129 
130 
132 {
133  deleteDemandDrivenData(neighbourEdgesPtr_);
134 
135  forAll (*this, patchi)
136  {
137  operator[](patchi).clearAddressing();
138  }
139 }
140 
141 
142 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
143 
144 void Foam::polyBoundaryMesh::calcGeometry()
145 {
146  forAll(*this, patchi)
147  {
148  operator[](patchi).initGeometry();
149  }
150 
151  forAll(*this, patchi)
152  {
153  operator[](patchi).calcGeometry();
154  }
155 }
156 
157 
160 {
161  if (Pstream::parRun())
162  {
163  WarningIn("polyBoundaryMesh::neighbourEdges() const")
164  << "Neighbour edge addressing not correct across parallel"
165  << " boundaries." << endl;
166  }
167 
168  if (!neighbourEdgesPtr_)
169  {
170  neighbourEdgesPtr_ = new List<labelPairList>(size());
171  List<labelPairList>& neighbourEdges = *neighbourEdgesPtr_;
172 
173  // Initialize.
174  label nEdgePairs = 0;
175  forAll(*this, patchi)
176  {
177  const polyPatch& pp = operator[](patchi);
178 
179  neighbourEdges[patchi].setSize(pp.nEdges() - pp.nInternalEdges());
180 
181  forAll(neighbourEdges[patchi], i)
182  {
183  labelPair& edgeInfo = neighbourEdges[patchi][i];
184 
185  edgeInfo[0] = -1;
186  edgeInfo[1] = -1;
187  }
188 
189  nEdgePairs += pp.nEdges() - pp.nInternalEdges();
190  }
191 
192  // From mesh edge (expressed as a point pair so as not to construct
193  // point addressing) to patch + relative edge index.
194  HashTable<labelPair, edge, Hash<edge> > pointsToEdge(nEdgePairs);
195 
196  forAll(*this, patchi)
197  {
198  const polyPatch& pp = operator[](patchi);
199 
200  const edgeList& edges = pp.edges();
201 
202  for
203  (
204  label edgei = pp.nInternalEdges();
205  edgei < edges.size();
206  edgei++
207  )
208  {
209  // Edge in patch local points
210  const edge& e = edges[edgei];
211 
212  // Edge in mesh points.
213  edge meshEdge(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]);
214 
216  pointsToEdge.find(meshEdge);
217 
218  if (fnd == pointsToEdge.end())
219  {
220  // First occurrence of mesh edge. Store patch and my
221  // local index.
222  pointsToEdge.insert
223  (
224  meshEdge,
225  labelPair
226  (
227  patchi,
228  edgei - pp.nInternalEdges()
229  )
230  );
231  }
232  else
233  {
234  // Second occurrence. Store.
235  const labelPair& edgeInfo = fnd();
236 
237  neighbourEdges[patchi][edgei - pp.nInternalEdges()] =
238  edgeInfo;
239 
240  neighbourEdges[edgeInfo[0]][edgeInfo[1]]
241  = labelPair(patchi, edgei - pp.nInternalEdges());
242 
243  // Found all two occurrences of this edge so remove from
244  // hash to save space. Note that this will give lots of
245  // problems if the polyBoundaryMesh is multiply connected.
246  pointsToEdge.erase(meshEdge);
247  }
248  }
249  }
250 
251  if (pointsToEdge.size())
252  {
253  FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
254  << "Not all boundary edges of patches match up." << nl
255  << "Is the outside of your mesh multiply connected?"
256  << abort(FatalError);
257  }
258 
259  forAll(*this, patchi)
260  {
261  const polyPatch& pp = operator[](patchi);
262 
263  const labelPairList& nbrEdges = neighbourEdges[patchi];
264 
265  forAll(nbrEdges, i)
266  {
267  const labelPair& edgeInfo = nbrEdges[i];
268 
269  if (edgeInfo[0] == -1 || edgeInfo[1] == -1)
270  {
271  label edgeI = pp.nInternalEdges() + i;
272  const edge& e = pp.edges()[edgeI];
273 
274  FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
275  << "Not all boundary edges of patches match up." << nl
276  << "Edge " << edgeI << " on patch " << pp.name()
277  << " end points " << pp.localPoints()[e[0]] << ' '
278  << pp.localPoints()[e[1]] << " is not matched to an"
279  << " edge on any other patch." << nl
280  << "Is the outside of your mesh multiply connected?"
281  << abort(FatalError);
282  }
283  }
284  }
285  }
286 
287  return *neighbourEdgesPtr_;
288 }
289 
290 
292 {
293  const polyPatchList& patches = *this;
294 
295  wordList t(patches.size());
296 
297  forAll (patches, patchI)
298  {
299  t[patchI] = patches[patchI].name();
300  }
301 
302  return t;
303 }
304 
305 
307 {
308  const polyPatchList& patches = *this;
309 
310  wordList t(patches.size());
311 
312  forAll (patches, patchI)
313  {
314  t[patchI] = patches[patchI].type();
315  }
316 
317  return t;
318 }
319 
320 
322 {
323  const polyPatchList& patches = *this;
324 
325  wordList t(patches.size());
326 
327  forAll (patches, patchI)
328  {
329  t[patchI] = patches[patchI].physicalType();
330  }
331 
332  return t;
333 }
334 
335 
336 Foam::label Foam::polyBoundaryMesh::findPatchID(const word& patchName) const
337 {
338  const polyPatchList& patches = *this;
339 
340  forAll (patches, patchI)
341  {
342  if (patches[patchI].name() == patchName)
343  {
344  return patchI;
345  }
346  }
347 
348  // Patch not found
349  if (debug)
350  {
351  Pout<< "label polyBoundaryMesh::findPatchID(const word& "
352  << "patchName) const"
353  << "Patch named " << patchName << " not found. "
354  << "List of available patch names: " << names() << endl;
355  }
356 
357  // Not found, return -1
358  return -1;
359 }
360 
361 
362 Foam::label Foam::polyBoundaryMesh::whichPatch(const label faceIndex) const
363 {
364  // Find out which patch the current face belongs to by comparing label
365  // with patch start labels.
366  // If the face is internal, return -1;
367  // if it is off the end of the list, abort
368  if (faceIndex >= mesh().nFaces())
369  {
371  (
372  "polyBoundaryMesh::whichPatch(const label faceIndex) const"
373  ) << "given label greater than the number of geometric faces"
374  << abort(FatalError);
375  }
376 
377  if (faceIndex < mesh().nInternalFaces())
378  {
379  return -1;
380  }
381 
382  forAll (*this, patchI)
383  {
384  const polyPatch& bp = operator[](patchI);
385 
386  if
387  (
388  faceIndex >= bp.start()
389  && faceIndex < bp.start() + bp.size()
390  )
391  {
392  return patchI;
393  }
394  }
395 
396  // If not in any of above, it is trouble!
398  (
399  "label polyBoundaryMesh::whichPatch(const label faceIndex) const"
400  ) << "Cannot find face " << faceIndex << " in any of the patches "
401  << names() << nl
402  << "It seems your patches are not consistent with the mesh :"
403  << " internalFaces:" << mesh().nInternalFaces()
404  << " total number of faces:" << mesh().nFaces()
405  << abort(FatalError);
406 
407  return -1;
408 }
409 
410 
412 (
413  const wordList& patchNames
414 ) const
415 {
416  wordList allPatchNames = names();
417  labelHashSet ps(size());
418 
419  forAll(patchNames, i)
420  {
421  // Treat the given patch names as wild-cards and search the set
422  // of all patch names for matches
423  labelList patchIDs = findStrings(patchNames[i], allPatchNames);
424 
425  if (patchIDs.empty())
426  {
427  WarningIn("polyBoundaryMesh::patchSet(const wordList&)")
428  << "Cannot find any patch names matching " << patchNames[i]
429  << endl;
430  }
431 
432  forAll(patchIDs, j)
433  {
434  ps.insert(patchIDs[j]);
435  }
436  }
437 
438  return ps;
439 }
440 
441 
442 bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
443 {
444  if (!Pstream::parRun())
445  {
446  return false;
447  }
448 
449 
450  const polyBoundaryMesh& bm = *this;
451 
452  bool boundaryError = false;
453 
454  // Collect non-proc patches and check proc patches are last.
455  wordList names(bm.size());
456  wordList types(bm.size());
457 
458  label nonProcI = 0;
459 
460  forAll (bm, patchI)
461  {
462  if (!isA<processorPolyPatch>(bm[patchI]))
463  {
464  if (nonProcI != patchI)
465  {
466  // There is processor patch inbetween normal patches.
467  boundaryError = true;
468 
469  if (debug || report)
470  {
471  Pout<< " ***Problem with boundary patch " << patchI
472  << " named " << bm[patchI].name()
473  << " of type " << bm[patchI].type()
474  << ". The patch seems to be preceded by processor"
475  << " patches. This is can give problems."
476  << endl;
477  }
478  }
479  else
480  {
481  names[nonProcI] = bm[patchI].name();
482  types[nonProcI] = bm[patchI].type();
483  nonProcI++;
484  }
485  }
486  }
487  names.setSize(nonProcI);
488  types.setSize(nonProcI);
489 
490  List<wordList> allNames(Pstream::nProcs());
491  allNames[Pstream::myProcNo()] = names;
492  Pstream::gatherList(allNames);
493  Pstream::scatterList(allNames);
494 
495  List<wordList> allTypes(Pstream::nProcs());
496  allTypes[Pstream::myProcNo()] = types;
497  Pstream::gatherList(allTypes);
498  Pstream::scatterList(allTypes);
499 
500  // Have every processor check but only master print error.
501 
502  for (label procI = 1; procI < allNames.size(); procI++)
503  {
504  if
505  (
506  (allNames[procI] != allNames[0])
507  || (allTypes[procI] != allTypes[0])
508  )
509  {
510  boundaryError = true;
511 
512  if (debug || (report && Pstream::master()))
513  {
514  Info<< " ***Inconsistent patches across processors, "
515  "processor 0 has patch names:" << allNames[0]
516  << " patch types:" << allTypes[0]
517  << " processor " << procI << " has patch names:"
518  << allNames[procI]
519  << " patch types:" << allTypes[procI]
520  << endl;
521  }
522  }
523  }
524 
525  return boundaryError;
526 }
527 
528 
529 bool Foam::polyBoundaryMesh::checkDefinition(const bool report) const
530 {
531  label nextPatchStart = mesh().nInternalFaces();
532  const polyBoundaryMesh& bm = *this;
533 
534  bool boundaryError = false;
535 
536  forAll (bm, patchI)
537  {
538  if (bm[patchI].start() != nextPatchStart && !boundaryError)
539  {
540  boundaryError = true;
541 
542  Info<< " ****Problem with boundary patch " << patchI
543  << " named " << bm[patchI].name()
544  << " of type " << bm[patchI].type()
545  << ". The patch should start on face no " << nextPatchStart
546  << " and the patch specifies " << bm[patchI].start()
547  << "." << endl
548  << "Possibly consecutive patches have this same problem."
549  << " Suppressing future warnings." << endl;
550  }
551 
552  nextPatchStart += bm[patchI].size();
553  }
554 
555  reduce(boundaryError, orOp<bool>());
556 
557  if (boundaryError)
558  {
559  if (debug || report)
560  {
561  Pout << " ***Boundary definition is in error." << endl;
562  }
563 
564  return true;
565  }
566  else
567  {
568  if (debug || report)
569  {
570  Info << " Boundary definition OK." << endl;
571  }
572 
573  return false;
574  }
575 }
576 
577 
579 {
580  polyPatchList& patches = *this;
581 
582  forAll(patches, patchi)
583  {
584  patches[patchi].initMovePoints(p);
585  }
586 
587  forAll(patches, patchi)
588  {
589  patches[patchi].movePoints(p);
590  }
591 }
592 
593 
595 {
596  deleteDemandDrivenData(neighbourEdgesPtr_);
597 
598  polyPatchList& patches = *this;
599 
600  forAll(patches, patchi)
601  {
602  patches[patchi].initUpdateMesh();
603  }
604 
605  forAll(patches, patchi)
606  {
607  patches[patchi].updateMesh();
608  }
609 }
610 
611 
613 {
614  // Change order of patches
615  polyPatchList::reorder(oldToNew);
616 
617  // Adapt indices
618  polyPatchList& patches = *this;
619 
620  forAll(patches, patchi)
621  {
622  patches[patchi].index() = patchi;
623  }
624 
625  updateMesh();
626 }
627 
628 
630 {
631  const polyPatchList& patches = *this;
632 
633  os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
634 
635  forAll(patches, patchi)
636  {
637  os << indent << patches[patchi].name() << nl
638  << indent << token::BEGIN_BLOCK << nl
639  << incrIndent << patches[patchi] << decrIndent
640  << indent << token::END_BLOCK << endl;
641  }
642 
643  os << decrIndent << token::END_LIST;
644 
645  // Check state of IOstream
646  os.check("polyBoundaryMesh::writeData(Ostream& os) const");
647 
648  return os.good();
649 }
650 
651 
653 (
657 ) const
658 {
660 }
661 
662 
663 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
664 
666 {
667  pbm.writeData(os);
668  return os;
669 }
670 
671 
672 // ************************ vim: set sw=4 sts=4 et: ************************ //