42 template<
class PatchType>
53 for (
const label patchEdgei : edgeIds)
55 const edge e(
p.meshEdge(patchEdgei));
58 <<
p.points()[
e.first()] <<
' ' 59 <<
p.points()[
e.second()] <<
nl;
62 if (maxOutput > 0 && nOutput >= maxOutput)
64 os <<
" ... suppressing further output" <<
nl;
76 Foam::faMesh::getBoundaryEdgeConnections()
const 100 label patchEdgei_ = -1;
101 label meshFacei_ = -1;
114 <<
"Determining required boundary edge connections, " 115 <<
"resolving locally attached boundary edges." <<
endl;
125 edgeToBoundaryIndex.insert
127 patch().meshEdge(patchEdgei),
134 if (edgeFaces.size() != 1)
136 badEdges.insert(patchEdgei);
140 const label patchFacei = edgeFaces[0];
141 const label meshFacei = faceLabels_[patchFacei];
145 const label
patchId = pbm.patchID()[bndFacei];
149 auto& tuple = bndEdgeConnections[bndEdgei].first();
153 tuple.patchEdgei(patchEdgei);
154 tuple.meshFacei(meshFacei);
159 auto& pairing = patchPairings[bndEdgei];
163 pairing.patchEdgei_ = patchEdgei;
164 pairing.meshFacei_ = meshFacei;
168 if ((nBadEdges =
returnReduce(badEdges.size(), sumOp<label>())) != 0)
174 patch().localPoints(),
179 / (
"faMesh-construct.nonManifoldEdges")
190 <<
"Boundary edges not singly connected: " 201 <<
"(debug) wrote " <<
writer.output().name() <<
nl;
212 label nMissing = patchPairings.size();
214 for (label patchi = 0; patchi < nNonProcessor; ++patchi)
216 if (!nMissing)
break;
218 const polyPatch& pp = pbm[patchi];
223 label patchEdgei = pp.nInternalEdges();
224 patchEdgei < pp.nEdges();
228 const label bndEdgei =
229 edgeToBoundaryIndex.lookup(pp.meshEdge(patchEdgei), -1);
235 auto& pairing = patchPairings[bndEdgei];
240 if (pairing.insert(patchi))
243 const labelList& edgeFaces = pp.edgeFaces()[patchEdgei];
245 if (edgeFaces.size() != 1)
247 pairing.erase(patchi);
248 badEdges.insert(badEdges.size());
252 const label patchFacei = edgeFaces[0];
253 const label meshFacei = patchFacei + pp.start();
256 pairing.patchEdgei_ = patchEdgei;
257 pairing.meshFacei_ = meshFacei;
260 if (!nMissing)
break;
266 if ((nBadEdges =
returnReduce(badEdges.size(), sumOp<label>())) != 0)
269 <<
"Had " << nBadEdges
270 <<
" boundary edges with missing or multiple edge connections" 278 const auto& pairing = patchPairings[bndEdgei];
279 const label nbrPatchi = pairing.second();
280 const label nbrPatchEdgei = pairing.patchEdgei_;
281 const label nbrMeshFacei = pairing.meshFacei_;
283 if (nbrMeshFacei >= 0)
286 auto& tuple = bndEdgeConnections[bndEdgei].second();
289 tuple.patchi(nbrPatchi);
290 tuple.patchEdgei(nbrPatchEdgei);
291 tuple.meshFacei(nbrMeshFacei);
308 nBadEdges = badEdges.size();
315 patch().localPoints(),
320 / (
"faMesh-construct.invalidEdges")
331 <<
"Boundary edges with missing/invalid neighbours: " 342 <<
"(debug) wrote " <<
writer.output().name() <<
nl;
349 return bndEdgeConnections;
358 <<
"Creating global coupling data" <<
endl;
362 const mapDistribute& map =
globalData.globalEdgeSlavesMap();
363 const label nCoupledEdges = cpp.nEdges();
366 List<bool> coupledEdgesUsed(map.constructSize(),
false);
369 for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
371 coupledEdgesUsed[cppEdgei] =
372 edgeToBoundaryIndex.found(cpp.meshEdge(cppEdgei));
376 <<
"Starting sync of boundary edge topology" <<
endl;
390 for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
392 if (coupledEdgesUsed[cppEdgei])
401 <<
" connected boundary edges (total, some duplicates)" <<
endl;
407 List<DynamicList<patchTuple, 2>> gatheredConnections(map.constructSize());
410 EdgeMap<label> edgeToCoupledIndex(2*nCoupledEdges);
417 for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
419 if (coupledEdgesUsed[cppEdgei])
421 const edge meshEdge(cpp.meshEdge(cppEdgei));
423 const label bndEdgei =
424 edgeToBoundaryIndex.lookup(meshEdge, -1);
430 auto& gathered = gatheredConnections[cppEdgei];
431 gathered.setCapacity(2);
433 auto& tuple = gathered.last();
435 tuple = bndEdgeConnections[bndEdgei].first();
442 edgeToCoupledIndex.insert(meshEdge, cppEdgei);
452 for (label patchi = 0; patchi < nNonProcessor; ++patchi)
454 if (edgeToCoupledIndex.empty())
break;
456 const polyPatch& pp = pbm[patchi];
461 label patchEdgei = pp.nInternalEdges();
462 patchEdgei < pp.nEdges();
466 const edge meshEdge(pp.meshEdge(patchEdgei));
468 const label cppEdgei =
469 edgeToCoupledIndex.lookup(meshEdge, -1);
476 const labelList& edgeFaces = pp.edgeFaces()[patchEdgei];
478 if (edgeFaces.size() != 1)
480 badEdges.insert(cppEdgei);
484 const label patchFacei = edgeFaces[0];
485 const label meshFacei = patchFacei + pp.start();
487 auto& gathered = gatheredConnections[cppEdgei];
488 gathered.setCapacity(2);
490 auto& tuple = gathered.last();
493 tuple.patchi(patchi);
494 tuple.patchEdgei(patchEdgei);
495 tuple.meshFacei(meshFacei);
498 edgeToCoupledIndex.erase(meshEdge);
500 if (edgeToCoupledIndex.empty())
break;
505 if ((nBadEdges =
returnReduce(badEdges.size(), sumOp<label>())) != 0)
508 <<
"Had " << nBadEdges <<
" coupled boundary edges" 509 <<
" with missing or multiple edge connections" 514 <<
"Starting sync of boundary edge information" <<
endl;
522 ListOps::appendEqOp<patchTuple>()
527 <<
"Collating sync information" <<
endl;
530 for (label cppEdgei = 0; cppEdgei < nCoupledEdges; ++cppEdgei)
532 const auto& gathered = gatheredConnections[cppEdgei];
534 const label bndEdgei =
535 edgeToBoundaryIndex.lookup(cpp.meshEdge(cppEdgei), -1);
543 && gathered.size() == 2
546 const auto& a = gathered[0];
547 const auto&
b = gathered[1];
550 auto& connection = bndEdgeConnections[bndEdgei];
552 connection.second() = (connection.first() ==
b) ? a :
b;
560 const auto& connection = bndEdgeConnections[bndEdgei];
562 if (!connection.second().valid())
575 patch().localPoints(),
576 patch().boundaryEdges(),
580 / (
"faMesh-construct.boundaryEdges")
595 const auto& connection = bndEdgeConnections[bndEdgei];
597 neighProc[bndEdgei] = connection.second().procNo();
598 neighPatch[bndEdgei] = connection.second().patchi();
601 writer.write(
"neighProc", neighProc);
602 writer.write(
"neighPatch", neighPatch);
613 / (
"faMesh-construct.faPatch")
626 if ((nBadEdges =
returnReduce(badEdges.size(), sumOp<label>())) != 0)
632 patch().localPoints(),
637 / (
"faMesh-construct.invalidEdges")
648 <<
"Boundary edges with missing/invalid neighbours: " 659 <<
"(debug) wrote " <<
writer.output().name() <<
nl;
669 <<
"Return sorted list of boundary connections" <<
endl;
671 return bndEdgeConnections;
675 void Foam::faMesh::setBoundaryConnections
677 const List<Pair<patchTuple>>& bndEdgeConnections
680 const label nInternalEdges =
patch().nInternalEdges();
681 const label nBoundaryEdges =
patch().nBoundaryEdges();
683 if (bndEdgeConnections.size() != nBoundaryEdges)
686 <<
"Sizing mismatch. Expected " << nBoundaryEdges
687 <<
" boundary edge connections, but had " 688 << bndEdgeConnections.size() <<
nl 694 new List<labelPair>(nBoundaryEdges,
labelPair(-1,-1))
696 auto& bndConnect = *bndConnectPtr_;
698 for (
const auto& connection : bndEdgeConnections)
700 const auto& a = connection.first();
701 const auto&
b = connection.second();
703 if (a.is_finiteArea() && a.is_localProc())
705 const label bndEdgei = (a.patchEdgei() - nInternalEdges);
707 bndConnect[bndEdgei].first() =
b.procNo();
708 bndConnect[bndEdgei].second() =
b.meshFacei();
710 else if (
b.is_finiteArea() &&
b.is_localProc())
712 const label bndEdgei = (
b.patchEdgei() - nInternalEdges);
714 bndConnect[bndEdgei].first() = a.procNo();
715 bndConnect[bndEdgei].second() = a.meshFacei();
720 <<
"Unexpected pairing input " << connection
721 <<
" ... programming error" <<
nl 727 for (
const auto& connection : bndConnect)
729 if (connection.first() < 0 || connection.second() < 0)
737 reduce(nInvalid, sumOp<label>());
743 <<
"Did not properly match " << nInvalid
744 <<
" boundary edges" <<
nl 750 void Foam::faMesh::calcBoundaryConnections()
const 752 setBoundaryConnections(this->getBoundaryEdgeConnections());
760 const auto& connections = this->boundaryConnections();
764 for (
const labelPair& tuple : connections)
766 procsUsed.insert(tuple.first());
772 return procsUsed.sortedToc();
778 const auto& connections = this->boundaryConnections();
782 for (
const labelPair& tuple : connections)
784 ++procCount(tuple.first());
792 for (
const label proci : procCount.
sortedToc())
807 haloMapPtr_.
reset(
new faMeshBoundaryHalo(*
this));
814 void Foam::faMesh::calcHaloFaceGeometry()
const 816 if (haloFaceCentresPtr_ || haloFaceNormalsPtr_)
819 <<
"Halo centres/normals already calculated" 824 <<
"Calculating halo face centres/normals" <<
endl;
829 const faMeshBoundaryHalo& halo = boundaryHaloMap();
831 const labelList& inputFaceIds = halo.inputMeshFaces();
836 auto& centres = *haloFaceCentresPtr_;
837 auto& normals = *haloFaceNormalsPtr_;
839 centres.
resize(inputFaceIds.size());
840 normals.resize(inputFaceIds.size());
845 const face&
f = faces[inputFaceIds[i]];
848 normals[i] =
f.unitNormal(
points);
852 halo.distributeSparse(centres);
853 halo.distributeSparse(normals);
859 if (!haloFaceCentresPtr_ || !haloFaceNormalsPtr_)
861 calcHaloFaceGeometry();
864 return *haloFaceCentresPtr_;
870 if (!haloFaceCentresPtr_ || !haloFaceNormalsPtr_)
872 calcHaloFaceGeometry();
875 return *haloFaceNormalsPtr_;
882 if (patchi < 0 || patchi >=
boundary().size())
885 <<
"Patch " << patchi <<
" is out-of-range 0.." 896 this->haloFaceCentres(),
907 if (patchi < 0 || patchi >=
boundary().size())
910 <<
"Patch " << patchi <<
" is out-of-range 0.." 921 this->haloFaceNormals(),
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
void size(const label n)
Older name for setAddressableSize.
static int debug
Debug switch.
errorManipArg< error, int > exit(error &err, const int errNo=1)
void resize(const label len)
Adjust allocated size of list.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
const Time & time() const
Return reference to time.
constexpr char nl
The newline '\n' character (0x0a)
const pointField & haloFaceCentres() const
Face centres of boundary halo neighbours.
List< face > faceList
A List of faces.
Ostream & endl(Ostream &os)
Add newline and flush stream.
static bool & parRun() noexcept
Test if this a parallel run.
label nInternalEdges() const
Number of internal edges.
label size() const noexcept
The number of elements in table.
const faGlobalMeshData & globalData() const
Return parallel info.
static void printPatchEdges(Ostream &os, const PatchType &p, const labelList &edgeIds, label maxOutput=10)
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
labelList boundaryProcs() const
Boundary edge neighbour processors (does not include own proc)
virtual const pointField & points() const
Return raw points.
#define forAll(list, i)
Loop across all elements in list.
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.
const uindirectPrimitivePatch & patch() const
Return constant reference to primitive patch.
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
void clear()
'Clears' edge by setting both ends to invalid point labels.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
List< labelPair > boundaryProcSizes() const
List of proc/size for the boundary edge neighbour processors (does not include own proc) ...
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
vectorField pointField
pointField is a vectorField.
const dimensionedScalar e
Elementary charge.
List< edge > edgeList
A List of edges.
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
#define DebugInFunction
Report an information message using Foam::Info.
void sort(UList< T > &list)
Sort the list.
const faMeshBoundaryHalo & boundaryHaloMap() const
Mapping/swapping for boundary halo neighbours.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
const vectorField & haloFaceNormals() const
Face unit-normals of boundary halo neighbours.
const labelListList & edgeFaces() const
Return edge-face addressing.
const globalMeshData & globalData() const
Return parallel info.
GenericPatchWriter< uindirectPrimitivePatch > uindirectPatchWriter
Write uindirectPrimitivePatch faces/points (optionally with fields) as a vtp file or a legacy vtk fil...
label nInternalFaces() const noexcept
Number of internal faces.
virtual const faceList & faces() const
Return raw faces.
label nBoundaryEdges() const
Number of boundary edges == (nEdges() - nInternalEdges())
errorManip< error > abort(error &err)
An Ostream is an abstract base class for all output systems (streams, files, token lists...
void reset(const faMesh &mesh)
Redefine map and connectivity for a mesh.
const edgeList & edges() const noexcept
Return local edges with reordered boundary.
Pair< label > labelPair
A pair of labels.
vtk::internalMeshWriter writer(topoMesh, topoCells, vtk::formatType::INLINE_ASCII, runTime.path()/"blockTopology")
OBJstream os(runTime.globalPath()/outputName)
const polyMesh & mesh() const
Return access to polyMesh.
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
label nInternalEdges() const noexcept
Number of internal faces.
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
const std::string patch
OpenFOAM patch number as a std::string.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
static Ostream & output(Ostream &os, const IntRange< T > &range)
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< label > labelList
A List of labels.
A class for managing temporary objects.
label nBoundaryEdges() const noexcept
Number of boundary edges (== nEdges - nInternalEdges)
label nNonProcessor() const
The number of patches before the first processor patch.
Class for obtaining halo face data for the boundary edges. The ordering follows that natural edge ord...
#define InfoInFunction
Report an information message using Foam::Info.