advancingFrontAMIParallelOps.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) 2011-2017 OpenFOAM Foundation
9 Copyright (C) 2018-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "advancingFrontAMI.H"
30#include "mergePoints.H"
31#include "mapDistribute.H"
32#include "AABBTree.H"
33
34// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35
36Foam::label Foam::advancingFrontAMI::calcOverlappingProcs
37(
38 const List<treeBoundBoxList>& procBb,
39 const treeBoundBox& bb,
40 boolList& overlaps
41) const
42{
43 overlaps.setSize(procBb.size());
44 overlaps = false;
45
46 label nOverlaps = 0;
47
48 forAll(procBb, proci)
49 {
50 const treeBoundBoxList& bbp = procBb[proci];
51
52 for (const treeBoundBox& tbb: bbp)
53 {
54 if (tbb.overlaps(bb))
55 {
56 overlaps[proci] = true;
57 ++nOverlaps;
58 break;
59 }
60 }
61 }
62
63 return nOverlaps;
64}
65
66
67void Foam::advancingFrontAMI::distributePatches
68(
69 const mapDistribute& map,
70 const primitivePatch& pp,
71 const globalIndex& gi,
72 List<faceList>& faces,
73 List<pointField>& points,
74 List<labelList>& faceIDs
75) const
76{
77 PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
78
79 for (const int domain : Pstream::allProcs())
80 {
81 const labelList& sendElems = map.subMap()[domain];
82
83 if (domain != Pstream::myProcNo() && sendElems.size())
84 {
85 faceList subFaces(UIndirectList<face>(pp, sendElems));
86 primitivePatch subPatch
87 (
88 SubList<face>(subFaces),
89 pp.points()
90 );
91
92 if (debug & 2)
93 {
94 Pout<< "distributePatches: to processor " << domain
95 << " sending faces " << subPatch.faceCentres() << endl;
96 }
97
98 UOPstream toDomain(domain, pBufs);
99 toDomain
100 << subPatch.localFaces() << subPatch.localPoints()
101 << gi.toGlobal(sendElems);
102 }
103 }
104
105 // Start receiving
106 pBufs.finishedSends();
107
108 faces.setSize(Pstream::nProcs());
110 faceIDs.setSize(Pstream::nProcs());
111
112 {
113 // Set up 'send' to myself
114 const labelList& sendElems = map.subMap()[Pstream::myProcNo()];
115 faceList subFaces(UIndirectList<face>(pp, sendElems));
116 primitivePatch subPatch
117 (
118 SubList<face>(subFaces),
119 pp.points()
120 );
121
122 // Receive
123 if (debug & 2)
124 {
125 Pout<< "distributePatches: to processor " << Pstream::myProcNo()
126 << " sending faces " << subPatch.faceCentres() << endl;
127 }
128
129 faces[Pstream::myProcNo()] = subPatch.localFaces();
130 points[Pstream::myProcNo()] = subPatch.localPoints();
131 faceIDs[Pstream::myProcNo()] = gi.toGlobal(sendElems);
132 }
133
134 // Consume
135 for (const int domain : Pstream::allProcs())
136 {
137 const labelList& recvElems = map.constructMap()[domain];
138
139 if (domain != Pstream::myProcNo() && recvElems.size())
140 {
141 UIPstream str(domain, pBufs);
142
143 str >> faces[domain]
144 >> points[domain]
145 >> faceIDs[domain];
146 }
147 }
148}
149
150
151void Foam::advancingFrontAMI::distributeAndMergePatches
152(
153 const mapDistribute& map,
154 const primitivePatch& tgtPatch,
155 const globalIndex& gi,
156 faceList& tgtFaces,
157 pointField& tgtPoints,
158 labelList& tgtFaceIDs
159) const
160{
161 // Exchange per-processor data
162 List<faceList> allFaces;
163 List<pointField> allPoints;
164 List<labelList> allTgtFaceIDs;
165 distributePatches(map, tgtPatch, gi, allFaces, allPoints, allTgtFaceIDs);
166
167 // Renumber and flatten
168 label nFaces = 0;
169 label nPoints = 0;
170 forAll(allFaces, proci)
171 {
172 nFaces += allFaces[proci].size();
173 nPoints += allPoints[proci].size();
174 }
175
176 tgtFaces.setSize(nFaces);
177 tgtPoints.setSize(nPoints);
178 tgtFaceIDs.setSize(nFaces);
179
180 nFaces = 0;
181 nPoints = 0;
182
183 // My own data first
184 {
185 const labelList& faceIDs = allTgtFaceIDs[Pstream::myProcNo()];
186 SubList<label>(tgtFaceIDs, faceIDs.size()) = faceIDs;
187
188 const faceList& fcs = allFaces[Pstream::myProcNo()];
189 for (const face& f : fcs)
190 {
191 face& newF = tgtFaces[nFaces++];
192 newF.setSize(f.size());
193 forAll(f, fp)
194 {
195 newF[fp] = f[fp] + nPoints;
196 }
197 }
198
199 const pointField& pts = allPoints[Pstream::myProcNo()];
200 for (const point& pt: pts)
201 {
202 tgtPoints[nPoints++] = pt;
203 }
204 }
205
206
207 // Other proc data follows
208 forAll(allFaces, proci)
209 {
210 if (proci != Pstream::myProcNo())
211 {
212 const labelList& faceIDs = allTgtFaceIDs[proci];
213 SubList<label>(tgtFaceIDs, faceIDs.size(), nFaces) = faceIDs;
214
215 const faceList& fcs = allFaces[proci];
216 for (const face& f : fcs)
217 {
218 face& newF = tgtFaces[nFaces++];
219 newF.setSize(f.size());
220 forAll(f, fp)
221 {
222 newF[fp] = f[fp] + nPoints;
223 }
224 }
225
226 const pointField& pts = allPoints[proci];
227 for (const point& pt: pts)
228 {
229 tgtPoints[nPoints++] = pt;
230 }
231 }
232 }
233
234 // Merge
235 labelList oldToNew;
236 bool nChanged = Foam::inplaceMergePoints
237 (
238 tgtPoints,
239 SMALL,
240 false,
241 oldToNew
242 );
243
244 if (nChanged)
245 {
246 if (debug)
247 {
248 Pout<< "Merged from " << oldToNew.size()
249 << " down to " << tgtPoints.size() << " points" << endl;
250 }
251
252 for (face& f : tgtFaces)
253 {
254 inplaceRenumber(oldToNew, f);
255 }
256 }
257}
258
259
260Foam::autoPtr<Foam::mapDistribute> Foam::advancingFrontAMI::calcProcMap
261(
262 const primitivePatch& srcPatch,
263 const primitivePatch& tgtPatch
264) const
265{
266 // Get decomposition of patch
267 List<treeBoundBoxList> procBb(Pstream::nProcs());
268
269 if (srcPatch.size())
270 {
271 procBb[Pstream::myProcNo()] =
272 AABBTree<face>
273 (
274 srcPatch.localFaces(),
275 srcPatch.localPoints(),
276 false
277 ).boundBoxes();
278 }
279 else
280 {
282 }
283
285
286 if (debug)
287 {
288 Info<< "Determining extent of srcPatch per processor:" << nl
289 << "\tproc\tbb" << endl;
290 forAll(procBb, proci)
291 {
292 Info<< '\t' << proci << '\t' << procBb[proci] << endl;
293 }
294 }
295
296 // Determine which faces of tgtPatch overlaps srcPatch per proc
297 const faceList& faces = tgtPatch.localFaces();
298 const pointField& points = tgtPatch.localPoints();
299
300 labelListList sendMap;
301
302 {
303 // Per processor indices into all segments to send
304 List<DynamicList<label>> dynSendMap(Pstream::nProcs());
305
306 // Work array - whether processor bb overlaps the face bounds
307 boolList procBbOverlaps(Pstream::nProcs());
308
309 forAll(faces, facei)
310 {
311 if (faces[facei].size())
312 {
313 treeBoundBox faceBb(points, faces[facei]);
314
315 // Find the processor this face overlaps
316 calcOverlappingProcs(procBb, faceBb, procBbOverlaps);
317
318 forAll(procBbOverlaps, proci)
319 {
320 if (procBbOverlaps[proci])
321 {
322 dynSendMap[proci].append(facei);
323 }
324 }
325 }
326 }
327
328 // Convert dynamicList to labelList
329 sendMap.setSize(Pstream::nProcs());
330 forAll(sendMap, proci)
331 {
332 sendMap[proci].transfer(dynSendMap[proci]);
333 }
334 }
335
336 // Debug printing
337 if (debug)
338 {
339 Pout<< "Of my " << faces.size() << " I need to send to:" << nl
340 << "\tproc\tfaces" << endl;
341 forAll(sendMap, proci)
342 {
343 Pout<< '\t' << proci << '\t' << sendMap[proci].size() << endl;
344 }
345 }
346
347
348 // Send over how many faces I need to receive
349 labelListList sendSizes(Pstream::nProcs());
350 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
351 forAll(sendMap, proci)
352 {
353 sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
354 }
355 Pstream::allGatherList(sendSizes);
356
357
358 // Determine order of receiving
359 labelListList constructMap(Pstream::nProcs());
360
361 // My local segment first
362 constructMap[Pstream::myProcNo()] = identity
363 (
364 sendMap[Pstream::myProcNo()].size()
365 );
366
367 label segmentI = constructMap[Pstream::myProcNo()].size();
368 forAll(constructMap, proci)
369 {
370 if (proci != Pstream::myProcNo())
371 {
372 // What I need to receive is what other processor is sending to me
373 label nRecv = sendSizes[proci][Pstream::myProcNo()];
374 constructMap[proci].setSize(nRecv);
375
376 for (label i = 0; i < nRecv; ++i)
377 {
378 constructMap[proci][i] = segmentI++;
379 }
380 }
381 }
382
384 (
385 segmentI, // size after construction
386 std::move(sendMap),
387 std::move(constructMap)
388 );
389}
390
391
392// ************************************************************************* //
void setSize(const label n)
Alias for resize()
Definition: List.H:218
UPstream::rangeType allProcs() const noexcept
Range of ranks indices associated with PstreamBuffers.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
static void allGatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
@ nonBlocking
"nonBlocking"
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
int myProcNo() const noexcept
Return processor number.
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
const pointField & points
label nPoints
Geometric merging of points. See below.
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
List< treeBoundBox > treeBoundBoxList
List of bounding boxes.
List< bool > boolList
A List of bools.
Definition: List.H:64
label inplaceMergePoints(PointList &points, const scalar mergeTol, const bool verbose, labelList &pointToUnique)
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333