faMeshTopology.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2021 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "faMesh.H"
29 #include "faMeshBoundaryHalo.H"
30 #include "globalMeshData.H"
31 #include "indirectPrimitivePatch.H"
32 #include "edgeHashes.H"
33 #include "foamVtkLineWriter.H"
34 #include "foamVtkIndPatchWriter.H"
35 #include "foamVtkUIndPatchWriter.H"
36 
37 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41 
42 // Print out edges as point pairs
43 template<class PatchType>
44 static void printPatchEdges
45 (
46  Ostream& os,
47  const PatchType& p,
48  const labelList& edgeIds,
49  label maxOutput = 10
50 )
51 {
52  label nOutput = 0;
53 
54  for (const label patchEdgei : edgeIds)
55  {
56  const edge e(p.meshEdge(patchEdgei));
57 
58  os << " "
59  << p.points()[e.first()] << ' '
60  << p.points()[e.second()] << nl;
61 
62  ++nOutput;
63  if (maxOutput > 0 && nOutput >= maxOutput)
64  {
65  os << " ... suppressing further output" << nl;
66  break;
67  }
68  }
69 }
70 
71 } // End namespace Foam
72 
73 
74 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
75 
77 Foam::faMesh::getBoundaryEdgeConnections() const
78 {
79  const polyBoundaryMesh& pbm = mesh().boundaryMesh();
80 
81  const label nNonProcessor = pbm.nNonProcessor();
82 
83  const label nInternalEdges = patch().nInternalEdges();
84  const label nBoundaryEdges = patch().nBoundaryEdges();
85 
86  // The output result:
87  List<Pair<patchTuple>> bndEdgeConnections(nBoundaryEdges);
88 
89  // Map edges (mesh numbering) back to a boundary index
90  EdgeMap<label> edgeToBoundaryIndex(2*nBoundaryEdges);
91 
92  label nBadEdges(0);
93  labelHashSet badEdges(2*nBoundaryEdges);
94 
95  {
96  // Local collection structure for accounting of patch pairs.
97  // Based on 'edge' which has some hash-like insertion properties
98  // that are useful.
99  struct patchPairingType : public Foam::edge
100  {
101  label patchEdgei_ = -1;
102  label meshFacei_ = -1;
103 
104  void clear()
105  {
107  patchEdgei_ = -1;
108  meshFacei_ = -1;
109  }
110  };
111 
112  List<patchPairingType> patchPairings(nBoundaryEdges);
113 
115  << "Determining required boundary edge connections, "
116  << "resolving locally attached boundary edges." << endl;
117 
118 
119  // Pass 1:
120  // - setup lookup (edge -> bnd index)
121  // - add owner patch for each boundary edge
122  for (label bndEdgei = 0; bndEdgei < nBoundaryEdges; ++bndEdgei)
123  {
124  const label patchEdgei = (bndEdgei + nInternalEdges);
125 
126  edgeToBoundaryIndex.insert
127  (
128  patch().meshEdge(patchEdgei),
129  bndEdgei
130  );
131 
132  // The attached patch face. Should only be one!
133  const labelList& edgeFaces = patch().edgeFaces()[patchEdgei];
134 
135  if (edgeFaces.size() != 1)
136  {
137  badEdges.insert(patchEdgei);
138  continue;
139  }
140 
141  const label patchFacei = edgeFaces[0];
142  const label meshFacei = faceLabels_[patchFacei];
143  const label bndFacei = (meshFacei - mesh().nInternalFaces());
144 
146  const label patchId = pbm.patchID()[bndFacei];
147 
148  // Primary bookkeeping
149  {
150  auto& tuple = bndEdgeConnections[bndEdgei].first();
151 
152  tuple.procNo(Pstream::myProcNo());
153  tuple.faPatchi(patchId); // Tag as finiteArea patch
154  tuple.patchEdgei(patchEdgei);
155  tuple.meshFacei(meshFacei);
156  }
157 
158  // Temporary local bookkeeping
159  {
160  auto& pairing = patchPairings[bndEdgei];
161 
162  pairing.clear(); // invalidate
163  pairing.insert(patchId); // 'hash' into first location
164  pairing.patchEdgei_ = patchEdgei;
165  pairing.meshFacei_ = meshFacei;
166  }
167  }
168 
169  if ((nBadEdges = returnReduce(badEdges.size(), sumOp<label>())) > 0)
170  {
171  edgeList dumpEdges(patch().edges(), badEdges.sortedToc());
172 
173  vtk::lineWriter writer
174  (
175  patch().localPoints(),
176  dumpEdges,
177  fileName
178  (
179  mesh().time().globalPath()
180  / ("faMesh-construct.nonManifoldEdges")
181  )
182  );
183 
184  writer.writeGeometry();
185 
186  // CellData
187  writer.beginCellData();
188  writer.writeProcIDs();
189 
191  << "Boundary edges not singly connected: "
192  << nBadEdges << '/' << nBoundaryEdges << nl;
193 
195  (
196  FatalError,
197  patch(),
198  badEdges.sortedToc()
199  );
200 
202  << "(debug) wrote " << writer.output().name() << nl;
203 
205  }
206  badEdges.clear();
207 
208  // Pass 2:
209  // Add in first connecting neighbour patch for the boundary edges.
210  // Need to examine all possibly connecting (non-processor) neighbours,
211  // but only need to check their boundary edges.
212 
213  label nMissing = patchPairings.size();
214 
215  for (label patchi = 0; patchi < nNonProcessor; ++patchi)
216  {
217  if (!nMissing) break; // Early exit
218 
219  const polyPatch& pp = pbm[patchi];
220 
221  // Check boundary edges
222  for
223  (
224  label patchEdgei = pp.nInternalEdges();
225  patchEdgei < pp.nEdges();
226  ++patchEdgei
227  )
228  {
229  const label bndEdgei =
230  edgeToBoundaryIndex.lookup(pp.meshEdge(patchEdgei), -1);
231 
232  if (bndEdgei != -1)
233  {
234  // Has a matching owner boundary edge
235 
236  auto& pairing = patchPairings[bndEdgei];
237 
238  // Add neighbour (patchId, patchEdgei, meshFacei)
239  // 'hash' into the second location
240  // which does not insert the same value twice
241  if (pairing.insert(patchi))
242  {
243  // The attached patch face. Should only be one!
244  const labelList& edgeFaces = pp.edgeFaces()[patchEdgei];
245 
246  if (edgeFaces.size() != 1)
247  {
248  pairing.erase(patchi);
249  badEdges.insert(badEdges.size());
250  continue;
251  }
252 
253  const label patchFacei = edgeFaces[0];
254  const label meshFacei = patchFacei + pp.start();
255 
256  // The neighbour information
257  pairing.patchEdgei_ = patchEdgei;
258  pairing.meshFacei_ = meshFacei;
259 
260  --nMissing;
261  if (!nMissing) break; // Early exit
262  }
263  }
264  }
265  }
266 
267  if ((nBadEdges = returnReduce(badEdges.size(), sumOp<label>())) > 0)
268  {
270  << "Had " << nBadEdges
271  << " boundary edges with missing or multiple edge connections"
272  << abort(FatalError);
273  }
274 
275  // Combine local bookkeeping into final list
276  badEdges.clear();
277  for (label bndEdgei = 0; bndEdgei < nBoundaryEdges; ++bndEdgei)
278  {
279  const auto& pairing = patchPairings[bndEdgei];
280  const label nbrPatchi = pairing.second();
281  const label nbrPatchEdgei = pairing.patchEdgei_;
282  const label nbrMeshFacei = pairing.meshFacei_;
283 
284  if (nbrMeshFacei >= 0)
285  {
286  // Add into primary bookkeeping
287  auto& tuple = bndEdgeConnections[bndEdgei].second();
288 
289  tuple.procNo(Pstream::myProcNo());
290  tuple.patchi(nbrPatchi);
291  tuple.patchEdgei(nbrPatchEdgei);
292  tuple.meshFacei(nbrMeshFacei);
293  }
294  else if (!Pstream::parRun())
295  {
296  badEdges.insert(nInternalEdges + bndEdgei);
297  }
298  }
299  }
300 
301 
302  // ~~~~~~
303  // Serial - can return already
304  // ~~~~~~
305  if (!Pstream::parRun())
306  {
307  // Verbose report of missing edges - in serial
308 
309  nBadEdges = badEdges.size();
310  if (nBadEdges)
311  {
312  edgeList dumpEdges(patch().edges(), badEdges.sortedToc());
313 
314  vtk::lineWriter writer
315  (
316  patch().localPoints(),
317  dumpEdges,
318  fileName
319  (
320  mesh().time().globalPath()
321  / ("faMesh-construct.invalidEdges")
322  )
323  );
324 
325  writer.writeGeometry();
326 
327  // CellData
328  writer.beginCellData();
329  writer.writeProcIDs();
330 
332  << "Boundary edges with missing/invalid neighbours: "
333  << nBadEdges << '/' << nBoundaryEdges << nl;
334 
336  (
337  FatalError,
338  patch(),
339  badEdges.sortedToc()
340  );
341 
343  << "(debug) wrote " << writer.output().name() << nl;
344 
346  }
347 
348  // Globally consistent ordering
349  patchTuple::sort(bndEdgeConnections);
350  return bndEdgeConnections;
351  }
352 
353 
354  // ~~~~~~~~
355  // Parallel
356  // ~~~~~~~~
357 
359  << "Creating global coupling data" << endl;
360 
361  const globalMeshData& globalData = mesh().globalData();
362  const indirectPrimitivePatch& cpp = globalData.coupledPatch();
363  const mapDistribute& map = globalData.globalEdgeSlavesMap();
364  const label nCoupledEdges = cpp.nEdges();
365 
366  // Construct coupled edge usage with all data
367  List<bool> coupledEdgesUsed(map.constructSize(), false);
368 
369  // Markup finiteArea boundary edges that are coupled across processors
370  for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
371  {
372  coupledEdgesUsed[cppEdgei] =
373  edgeToBoundaryIndex.found(cpp.meshEdge(cppEdgei));
374  }
375 
377  << "Starting sync of boundary edge topology" << endl;
378 
380  (
381  coupledEdgesUsed,
382  globalData.globalEdgeSlaves(),
383  globalData.globalEdgeTransformedSlaves(), // probably not used
384  map,
385  orEqOp<bool>()
386  );
387 
388  if (debug)
389  {
390  label nAttached = 0;
391  for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
392  {
393  if (coupledEdgesUsed[cppEdgei])
394  {
395  ++nAttached;
396  }
397  }
398 
400  << "Approx "
401  << returnReduce(nAttached, sumOp<label>())
402  << " connected boundary edges (total, some duplicates)" << endl;
403  }
404 
405  // Combine information
406 
407  // Normally 0 or 2 connections
408  List<DynamicList<patchTuple, 2>> gatheredConnections(map.constructSize());
409 
410  // Map edges (mesh numbering) back to a coupled index in use
411  EdgeMap<label> edgeToCoupledIndex(2*nCoupledEdges);
412 
413  // Pass 1
414  // Look for attached boundary edges
415  // - boundary edges from this side go into gathered connections
416  // - boundary edges connected from the other side are noted for later
417 
418  for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
419  {
420  if (coupledEdgesUsed[cppEdgei])
421  {
422  const edge meshEdge(cpp.meshEdge(cppEdgei));
423 
424  const label bndEdgei =
425  edgeToBoundaryIndex.lookup(meshEdge, -1);
426 
427  if (bndEdgei != -1)
428  {
429  // A boundary finiteEdge edge (known from this side)
430 
431  auto& gathered = gatheredConnections[cppEdgei];
432  gathered.setCapacity(2);
433  gathered.resize(1);
434  auto& tuple = gathered.last();
435 
436  tuple = bndEdgeConnections[bndEdgei].first();
437  }
438  else
439  {
440  // Boundary edge connected from the other side
441  // - mark for it to be added later
442 
443  edgeToCoupledIndex.insert(meshEdge, cppEdgei);
444  }
445  }
446  }
447 
448  // Pass 2
449  // - add previously noted boundary edges (connected from other side)
450  // into gathered connections
451 
452  badEdges.clear();
453  for (label patchi = 0; patchi < nNonProcessor; ++patchi)
454  {
455  if (edgeToCoupledIndex.empty()) break; // Early exit
456 
457  const polyPatch& pp = pbm[patchi];
458 
459  // Check boundary edges
460  for
461  (
462  label patchEdgei = pp.nInternalEdges();
463  patchEdgei < pp.nEdges();
464  ++patchEdgei
465  )
466  {
467  const edge meshEdge(pp.meshEdge(patchEdgei));
468 
469  const label cppEdgei =
470  edgeToCoupledIndex.lookup(meshEdge, -1);
471 
472  if (cppEdgei != -1)
473  {
474  // A known connection
475 
476  // The attached patch face. Should only be one!
477  const labelList& edgeFaces = pp.edgeFaces()[patchEdgei];
478 
479  if (edgeFaces.size() != 1)
480  {
481  badEdges.insert(cppEdgei);
482  continue;
483  }
484 
485  const label patchFacei = edgeFaces[0];
486  const label meshFacei = patchFacei + pp.start();
487 
488  auto& gathered = gatheredConnections[cppEdgei];
489  gathered.setCapacity(2);
490  gathered.resize(1);
491  auto& tuple = gathered.last();
492 
493  tuple.procNo(Pstream::myProcNo());
494  tuple.patchi(patchi);
495  tuple.patchEdgei(patchEdgei);
496  tuple.meshFacei(meshFacei);
497 
498  // Do not consider again
499  edgeToCoupledIndex.erase(meshEdge);
500 
501  if (edgeToCoupledIndex.empty()) break; // Early exit
502  }
503  }
504  }
505 
506  if ((nBadEdges = returnReduce(badEdges.size(), sumOp<label>())) > 0)
507  {
509  << "Had " << nBadEdges << " coupled boundary edges"
510  << " with missing or multiple edge connections"
511  << abort(FatalError);
512  }
513 
515  << "Starting sync of boundary edge information" << endl;
516 
518  (
519  gatheredConnections,
520  globalData.globalEdgeSlaves(),
521  globalData.globalEdgeTransformedSlaves(), // probably not used
522  map,
523  ListOps::appendEqOp<patchTuple>()
524  );
525 
526 
528  << "Collating sync information" << endl;
529 
530  // Pick out gathered connections and add into primary bookkeeping
531  for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
532  {
533  const auto& gathered = gatheredConnections[cppEdgei];
534 
535  const label bndEdgei =
536  edgeToBoundaryIndex.lookup(cpp.meshEdge(cppEdgei), -1);
537 
538  if
539  (
540  // A boundary finiteEdge edge (known from this side)
541  bndEdgei != -1
542 
543  // Gathered a one-to-one connection
544  && gathered.size() == 2
545  )
546  {
547  const auto& a = gathered[0];
548  const auto& b = gathered[1];
549 
550  // Copy second side of connection
551  auto& connection = bndEdgeConnections[bndEdgei];
552 
553  connection.second() = (connection.first() == b) ? a : b;
554  }
555  }
556 
557  // Check missing/invalid
558  badEdges.clear();
559  for (label bndEdgei = 0; bndEdgei < nBoundaryEdges; ++bndEdgei)
560  {
561  const auto& connection = bndEdgeConnections[bndEdgei];
562 
563  if (!connection.second().valid())
564  {
565  badEdges.insert(nInternalEdges + bndEdgei);
566  }
567  }
568 
569 
570  if (debug & 8)
571  {
572  // Boundary edges
573  {
574  vtk::lineWriter writer
575  (
576  patch().localPoints(),
577  patch().boundaryEdges(),
578  fileName
579  (
580  mesh().time().globalPath()
581  / ("faMesh-construct.boundaryEdges")
582  )
583  );
584 
585  writer.writeGeometry();
586 
587  // CellData
588  writer.beginCellData();
589  writer.writeProcIDs();
590 
591  // For each boundary edge - the associate neighbour patch
592  labelList neighProc(nBoundaryEdges);
593  labelList neighPatch(nBoundaryEdges);
594  for (label bndEdgei = 0; bndEdgei < nBoundaryEdges; ++bndEdgei)
595  {
596  const auto& connection = bndEdgeConnections[bndEdgei];
597 
598  neighProc[bndEdgei] = connection.second().procNo();
599  neighPatch[bndEdgei] = connection.second().patchi();
600  }
601 
602  writer.write("neighProc", neighProc);
603  writer.write("neighPatch", neighPatch);
604  }
605 
606  // finiteArea
607  {
609  (
610  patch(),
611  fileName
612  (
613  mesh().time().globalPath()
614  / ("faMesh-construct.faPatch")
615  )
616  );
617 
618  writer.writeGeometry();
619 
620  // CellData
621  writer.beginCellData();
622  writer.writeProcIDs();
623  }
624  }
625 
626  // Verbose report of missing edges
627  if ((nBadEdges = returnReduce(badEdges.size(), sumOp<label>())) > 0)
628  {
629  edgeList dumpEdges(patch().edges(), badEdges.sortedToc());
630 
631  vtk::lineWriter writer
632  (
633  patch().localPoints(),
634  dumpEdges,
635  fileName
636  (
637  mesh().time().globalPath()
638  / ("faMesh-construct.invalidEdges")
639  )
640  );
641 
642  writer.writeGeometry();
643 
644  // CellData
645  writer.beginCellData();
646  writer.writeProcIDs();
647 
649  << "Boundary edges with missing/invalid neighbours: "
650  << nBadEdges << '/' << nBoundaryEdges << nl;
651 
653  (
654  FatalError,
655  patch(),
656  badEdges.sortedToc()
657  );
658 
660  << "(debug) wrote " << writer.output().name() << nl;
661 
663  }
664 
665 
666  // Globally consistent ordering
667  patchTuple::sort(bndEdgeConnections);
668 
670  << "Return sorted list of boundary connections" << endl;
671 
672  return bndEdgeConnections;
673 }
674 
675 
676 void Foam::faMesh::setBoundaryConnections
677 (
678  const List<Pair<patchTuple>>& bndEdgeConnections
679 ) const
680 {
681  const label nInternalEdges = patch().nInternalEdges();
682  const label nBoundaryEdges = patch().nBoundaryEdges();
683 
684  if (bndEdgeConnections.size() != nBoundaryEdges)
685  {
687  << "Sizing mismatch. Expected " << nBoundaryEdges
688  << " boundary edge connections, but had "
689  << bndEdgeConnections.size() << nl
690  << abort(FatalError);
691  }
692 
693  bndConnectPtr_.reset
694  (
695  new List<labelPair>(nBoundaryEdges, labelPair(-1,-1))
696  );
697  auto& bndConnect = *bndConnectPtr_;
698 
699  for (const auto& connection : bndEdgeConnections)
700  {
701  const auto& a = connection.first();
702  const auto& b = connection.second();
703 
704  if (a.is_finiteArea() && a.is_localProc())
705  {
706  const label bndEdgei = (a.patchEdgei() - nInternalEdges);
707 
708  bndConnect[bndEdgei].first() = b.procNo();
709  bndConnect[bndEdgei].second() = b.meshFacei();
710  }
711  else if (b.is_finiteArea() && b.is_localProc())
712  {
713  const label bndEdgei = (b.patchEdgei() - nInternalEdges);
714 
715  bndConnect[bndEdgei].first() = a.procNo();
716  bndConnect[bndEdgei].second() = a.meshFacei();
717  }
718  else
719  {
721  << "Unexpected pairing input " << connection
722  << " ... programming error" << nl
723  << abort(FatalError);
724  }
725  }
726 
727  label nInvalid = 0;
728  for (const auto& connection : bndConnect)
729  {
730  if (connection.first() < 0 || connection.second() < 0)
731  {
732  ++nInvalid;
733  }
734  }
735 
736  if (Pstream::parRun())
737  {
738  reduce(nInvalid, sumOp<label>());
739  }
740 
741  if (nInvalid)
742  {
744  << "Did not properly match " << nInvalid
745  << " boundary edges" << nl
746  << abort(FatalError);
747  }
748 }
749 
750 
751 void Foam::faMesh::calcBoundaryConnections() const
752 {
753  setBoundaryConnections(this->getBoundaryEdgeConnections());
754 }
755 
756 
757 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
758 
760 {
761  const auto& connections = this->boundaryConnections();
762 
763  labelHashSet procsUsed(2*Pstream::nProcs());
764 
765  for (const labelPair& tuple : connections)
766  {
767  procsUsed.insert(tuple.first());
768  }
769 
770  procsUsed.erase(-1); // placeholder value
771  procsUsed.erase(Pstream::myProcNo());
772 
773  return procsUsed.sortedToc();
774 }
775 
776 
778 {
779  const auto& connections = this->boundaryConnections();
780 
781  Map<label> procCount(2*Pstream::nProcs());
782 
783  for (const labelPair& tuple : connections)
784  {
785  ++procCount(tuple.first());
786  }
787  procCount.erase(-1); // placeholder value
788  procCount.erase(Pstream::myProcNo());
789 
790  // Flatten as list
791  List<labelPair> output(procCount.size());
792  label count = 0;
793  for (const label proci : procCount.sortedToc())
794  {
795  output[count].first() = proci;
796  output[count].second() = procCount[proci]; // size
797  ++count;
798  }
799 
800  return output;
801 }
802 
803 
805 {
806  if (!haloMapPtr_)
807  {
808  haloMapPtr_.reset(new faMeshBoundaryHalo(*this));
809  }
810 
811  return *haloMapPtr_;
812 }
813 
814 
815 void Foam::faMesh::calcHaloFaceGeometry() const
816 {
817  if (haloFaceCentresPtr_ || haloFaceNormalsPtr_)
818  {
820  << "Halo centres/normals already calculated"
821  << exit(FatalError);
822  }
823 
825  << "Calculating halo face centres/normals" << endl;
826 
827  const faceList& faces = mesh().faces();
828  const pointField& points = mesh().points();
829 
830  const faMeshBoundaryHalo& halo = boundaryHaloMap();
831 
832  const labelList& inputFaceIds = halo.inputMeshFaces();
833 
834  haloFaceCentresPtr_.reset(new pointField);
835  haloFaceNormalsPtr_.reset(new vectorField);
836 
837  auto& centres = *haloFaceCentresPtr_;
838  auto& normals = *haloFaceNormalsPtr_;
839 
840  centres.resize(inputFaceIds.size());
841  normals.resize(inputFaceIds.size());
842 
843  // My values
844  forAll(inputFaceIds, i)
845  {
846  const face& f = faces[inputFaceIds[i]];
847 
848  centres[i] = f.centre(points);
849  normals[i] = f.unitNormal(points);
850  }
851 
852  // Swap information and resize
853  halo.distributeSparse(centres);
854  halo.distributeSparse(normals);
855 }
856 
857 
859 {
860  if (!haloFaceCentresPtr_ || !haloFaceNormalsPtr_)
861  {
862  calcHaloFaceGeometry();
863  }
864 
865  return *haloFaceCentresPtr_;
866 }
867 
868 
870 {
871  if (!haloFaceCentresPtr_ || !haloFaceNormalsPtr_)
872  {
873  calcHaloFaceGeometry();
874  }
875 
876  return *haloFaceNormalsPtr_;
877 }
878 
879 
881 Foam::faMesh::haloFaceCentres(const label patchi) const
882 {
883  if (patchi < 0 || patchi >= boundary().size())
884  {
886  << "Patch " << patchi << " is out-of-range 0.."
887  << (boundary().size()-1) << nl
888  << exit(FatalError);
889  }
890 
891  return tmp<pointField>::New
892  (
894  (
895  boundarySubset
896  (
897  this->haloFaceCentres(),
898  boundary()[patchi].edgeLabels()
899  )
900  )
901  );
902 }
903 
904 
906 Foam::faMesh::haloFaceNormals(const label patchi) const
907 {
908  if (patchi < 0 || patchi >= boundary().size())
909  {
911  << "Patch " << patchi << " is out-of-range 0.."
912  << (boundary().size()-1) << nl
913  << exit(FatalError);
914  }
915 
916  return tmp<vectorField>::New
917  (
919  (
920  boundarySubset
921  (
922  this->haloFaceNormals(),
923  boundary()[patchi].edgeLabels()
924  )
925  )
926  );
927 }
928 
929 
930 // ************************************************************************* //
Foam::data::debug
static int debug
Debug switch.
Definition: data.H:77
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::PrimitivePatch::nBoundaryEdges
label nBoundaryEdges() const
Number of boundary edges == (nEdges() - nInternalEdges())
Definition: PrimitivePatch.C:227
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
InfoInFunction
#define InfoInFunction
Report an information message using Foam::Info.
Definition: messageStream.H:350
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::output
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:66
Foam::PrimitivePatch::edgeFaces
const labelListList & edgeFaces() const
Return edge-face addressing.
Definition: PrimitivePatch.C:262
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::List::resize
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
foamVtkIndPatchWriter.H
globalMeshData.H
foamVtkUIndPatchWriter.H
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::Map< label >
Foam::faMesh::boundaryProcSizes
List< labelPair > boundaryProcSizes() const
Definition: faMeshTopology.C:777
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:444
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
faMesh.H
Foam::HashSet< label, Hash< label > >
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::faMesh::globalData
const faGlobalMeshData & globalData() const
Return parallel info.
Definition: faMesh.C:752
Foam::faMesh::haloFaceNormals
const vectorField & haloFaceNormals() const
Face normals of boundary halo neighbours.
Definition: faMeshTopology.C:869
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::edge::clear
void clear()
'Clears' edge by setting both ends to invalid point labels.
Definition: edgeI.H:231
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::faMesh::edges
const edgeList & edges() const noexcept
Return local patch edges with reordered boundary.
Definition: faMeshI.H:92
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::Field< vector >
DebugInFunction
#define DebugInFunction
Report an information message using Foam::Info.
Definition: messageStream.H:388
Foam::faMesh::time
const Time & time() const
Return reference to time.
Definition: faMesh.C:546
Foam::sort
void sort(UList< T > &a)
Definition: UList.C:261
Foam::vtk::uindirectPatchWriter
GenericPatchWriter< uindirectPrimitivePatch > uindirectPatchWriter
Write uindirectPrimitivePatch faces/points (optionally with fields) as a vtp file or a legacy vtk fil...
Definition: foamVtkUIndPatchWriter.H:55
Foam::faMesh::nInternalEdges
label nInternalEdges() const noexcept
Number of internal faces.
Definition: faMeshI.H:68
Foam::faMesh::nBoundaryEdges
label nBoundaryEdges() const noexcept
Number of boundary edges (== nEdges - nInternalEdges)
Definition: faMeshI.H:74
Foam::globalMeshData::syncData
static void syncData(List< Type > &elems, const labelListList &slaves, const labelListList &transformedSlaves, const mapDistribute &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
Definition: globalMeshDataTemplates.C:37
Foam::faMesh::boundaryHaloMap
const faMeshBoundaryHalo & boundaryHaloMap() const
Mapping/swapping for boundary halo neighbours.
Definition: faMeshTopology.C:804
indirectPrimitivePatch.H
Foam::faMesh::mesh
const polyMesh & mesh() const
Return access to polyMesh.
Definition: faMeshI.H:31
Foam::FatalError
error FatalError
os
OBJstream os(runTime.globalPath()/outputName)
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::faMesh::boundaryProcs
labelList boundaryProcs() const
Definition: faMeshTopology.C:759
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::indirectPrimitivePatch
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Definition: indirectPrimitivePatch.H:49
Foam::PrimitivePatch::nInternalEdges
label nInternalEdges() const
Number of internal edges.
Definition: PrimitivePatch.C:214
Foam::faMeshBoundaryHalo::reset
void reset(const faMesh &mesh)
Redefine map and connectivity for a mesh.
Definition: faMeshBoundaryHalo.C:85
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1094
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
edgeHashes.H
nNonProcessor
const label nNonProcessor
Definition: printMeshSummary.H:29
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::Pair< label >
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::primitiveMesh::nInternalFaces
label nInternalFaces() const noexcept
Number of internal faces.
Definition: primitiveMeshI.H:78
Foam::UPstream::parRun
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Foam::List< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::tmp::New
static tmp< T > New(Args &&... args)
Construct tmp of T with forwarding arguments.
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
patchId
label patchId(-1)
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
foamVtkLineWriter.H
Foam::polyMesh::globalData
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1295
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
writer
vtk::internalMeshWriter writer(topoMesh, topoCells, vtk::formatType::INLINE_ASCII, runTime.path()/"blockTopology")
Foam::printPatchEdges
static void printPatchEdges(Ostream &os, const PatchType &p, const labelList &edgeIds, label maxOutput=10)
Definition: faMeshTopology.C:45
Foam::faMesh::patch
const uindirectPrimitivePatch & patch() const
Return constant reference to primitive patch.
Definition: faMeshI.H:122
boundary
faceListList boundary
Definition: createBlockMesh.H:4
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
faMeshBoundaryHalo.H
Foam::faMeshBoundaryHalo
Class for obtaining halo face data for the boundary edges. The ordering follows that natural edge ord...
Definition: faMeshBoundaryHalo.H:59
Foam::faMesh::haloFaceCentres
const pointField & haloFaceCentres() const
Face centres of boundary halo neighbours.
Definition: faMeshTopology.C:858