1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 cfMesh 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
21 You should have received a copy of the GNU General Public License
22 along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
29 #include "helperFunctionsFrontalMarking.H"
31 #include "labelPair.H"
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
48 template<class labelListType, class neiOp, class filterOp>
51 labelListType& result,
52 const label startingIndex,
53 const neiOp& neighbourCalculator,
54 const filterOp& selector
57 //- add the starting element
59 result.append(startingIndex);
61 //- add the starting element to the front
63 front.append(startingIndex);
65 //- store information which element were already visited
66 boolList alreadySelected(neighbourCalculator.size(), false);
68 //- start with frontal marking
71 const label eLabel = front.removeLastElement();
73 //- find neighbours of the current element
74 DynList<label> neighbours;
75 neighbourCalculator(eLabel, neighbours);
77 forAll(neighbours, neiI)
79 const label nei = neighbours[neiI];
83 if( alreadySelected[nei] )
88 alreadySelected[nei] = true;
99 //- const reference to VRWGraph
100 const VRWGraph& neiGroups_;
105 //- Construct from VRWGraph
106 inline graphNeiOp(const VRWGraph& neiGroups)
108 neiGroups_(neiGroups)
111 // Public member functions
112 //- return the size of the graph
113 inline label size() const
115 return neiGroups_.size();
118 //- operator for finding neighbours
119 inline void operator()(const label groupI, DynList<label>& ng) const
121 ng.setSize(neiGroups_.sizeOfRow(groupI));
122 forAllRow(neiGroups_, groupI, i)
123 ng[i] = neiGroups_(groupI, i);
127 class graphSelectorOp
130 //- const reference to VRWGraph
131 const VRWGraph& neiGroups_;
136 //- Construct from VRWGraph
137 inline graphSelectorOp(const VRWGraph& neiGroups)
139 neiGroups_(neiGroups)
142 // Public member functions
143 //- operator for selecting elements
144 inline bool operator()(const label groupI) const
146 if( (groupI < 0) || (groupI >= neiGroups_.size()) )
153 template<class labelListType, class neiOp, class filterOp>
156 labelListType& elementInGroup,
157 const neiOp& neighbourCalculator,
158 const filterOp& selector
163 elementInGroup.setSize(neighbourCalculator.size());
166 VRWGraph neighbouringGroups;
171 //nThreads = 3 * omp_get_num_procs();
174 DynList<label> nGroupsAtThread(nThreads, 0);
177 # pragma omp parallel num_threads(nThreads)
180 const label chunkSize =
181 Foam::max(1, neighbourCalculator.size() / nThreads);
184 const label threadI = omp_get_thread_num();
186 const label threadI(0);
189 LongList<std::pair<label, label> > threadCommPairs;
191 const label minEl = threadI * chunkSize;
193 label maxEl = minEl + chunkSize;
194 if( threadI == (nThreads - 1) )
195 maxEl = Foam::max(maxEl, neighbourCalculator.size());
197 label& groupI = nGroupsAtThread[threadI];
200 for(label elI=minEl;elI<maxEl;++elI)
202 if( elementInGroup[elI] != -1 )
207 elementInGroup[elI] = groupI;
211 while( front.size() )
213 const label eLabel = front.removeLastElement();
215 DynList<label> neighbours;
216 neighbourCalculator(eLabel, neighbours);
218 forAll(neighbours, neiI)
220 const label nei = neighbours[neiI];
222 if( (nei < 0) || (elementInGroup[nei] != -1) )
225 if( (nei < minEl) || (nei >= maxEl) )
227 //- this is a communication interface between
229 threadCommPairs.append(std::make_pair(elI, nei));
231 else if( selector(nei) )
233 //- this element is part of the same group
234 elementInGroup[nei] = groupI;
248 forAll(nGroupsAtThread, i)
249 nGroups += nGroupsAtThread[i];
256 for(label i=0;i<threadI;++i)
257 startGroup += nGroupsAtThread[i];
259 for(label elI=minEl;elI<maxEl;++elI)
260 elementInGroup[elI] += startGroup;
266 //- find group to neighbouring groups addressing
267 List<DynList<label> > localNeiGroups(nGroups);
268 forAll(threadCommPairs, cfI)
270 const std::pair<label, label>& lp = threadCommPairs[cfI];
271 const label groupI = elementInGroup[lp.first];
272 const label neiGroup = elementInGroup[lp.second];
274 if( (neiGroup >= nGroups) || (groupI >= nGroups) )
275 FatalError << "neiGroup " << neiGroup
276 << " groupI " << groupI << " are >= than "
277 << "nGroups " << nGroups << abort(FatalError);
281 localNeiGroups[groupI].appendIfNotIn(neiGroup);
282 localNeiGroups[neiGroup].appendIfNotIn(groupI);
287 # pragma omp critical
290 neighbouringGroups.setSize(nGroups);
292 forAll(localNeiGroups, groupI)
294 const DynList<label>& lGroups = localNeiGroups[groupI];
296 neighbouringGroups.appendIfNotIn(groupI, groupI);
299 neighbouringGroups.appendIfNotIn(groupI, lGroups[i]);
304 forAll(neighbouringGroups, i)
306 labelList helper(neighbouringGroups.sizeOfRow(i));
307 forAllRow(neighbouringGroups, i, j)
308 helper[j] = neighbouringGroups(i, j);
312 neighbouringGroups[i] = helper;
315 //- start processing connections between the group and merge the connected
316 //- ones into a new group
317 DynList<label> globalGroupLabel;
318 globalGroupLabel.setSize(nGroups);
319 globalGroupLabel = -1;
321 //- reduce the information about the groups
324 forAll(neighbouringGroups, groupI)
326 if( globalGroupLabel[groupI] != -1 )
329 DynList<label> connectedGroups;
334 graphNeiOp(neighbouringGroups),
335 graphSelectorOp(neighbouringGroups)
338 forAll(connectedGroups, gI)
339 globalGroupLabel[connectedGroups[gI]] = counter;
346 forAll(neighbouringGroups, groupI)
348 if( globalGroupLabel[groupI] != -1 )
351 forAllRow(neighbouringGroups, groupI, ngI)
352 globalGroupLabel[neighbouringGroups(groupI, ngI)] = counter;
357 if( Pstream::parRun() )
359 //- reduce the groups over processors of an MPI run
360 //- count the total number of groups over all processors
361 labelList nGroupsAtProc(Pstream::nProcs());
362 nGroupsAtProc[Pstream::myProcNo()] = nGroups;
364 Pstream::gatherList(nGroupsAtProc);
365 Pstream::scatterList(nGroupsAtProc);
367 label startGroup(0), totalNumGroups(0);
368 for(label procI=0;procI<Pstream::nProcs();++procI)
370 totalNumGroups += nGroupsAtProc[procI];
372 if( procI < Pstream::myProcNo() )
373 startGroup += nGroupsAtProc[procI];
376 //- translate group labels
377 forAll(globalGroupLabel, groupI)
378 globalGroupLabel[groupI] += startGroup;
380 //- find the neighbouring groups
381 //- collect groups on other processors
382 //- this operator implements the algorithm for exchanging data
383 //- over processors and collects information which groups
384 //- are connected over inter-processor boundaries
385 std::map<label, DynList<label> > neiGroups;
387 neighbourCalculator.collectGroups
394 //- create a graph of connections
395 List<List<labelPair> > globalNeiGroups(Pstream::nProcs());
397 DynList<labelPair> connsAtProc;
400 std::map<label, DynList<label> >::const_iterator it =
406 const DynList<label>& ng = it->second;
409 connsAtProc.append(labelPair(it->first, ng[i]));
412 //- copy the connections into the global neighbour list
413 globalNeiGroups[Pstream::myProcNo()].setSize(connsAtProc.size());
415 forAll(connsAtProc, i)
416 globalNeiGroups[Pstream::myProcNo()][i] = connsAtProc[i];
418 //- communicate partial graphs to the master processor
419 Pstream::gatherList(globalNeiGroups);
421 labelList allGroupsNewLabel;
422 if( Pstream::master() )
424 //- collect the graph of connections for the whole system
425 VRWGraph allGroups(totalNumGroups);
427 allGroups[i].append(i);
429 forAll(globalNeiGroups, procI)
431 const List<labelPair>& connections = globalNeiGroups[procI];
433 forAll(connections, i)
435 const labelPair& lp = connections[i];
437 allGroups.appendIfNotIn(lp.first(), lp.second());
438 allGroups.appendIfNotIn(lp.second(), lp.first());
442 //- assign a global label to each group
443 allGroupsNewLabel.setSize(totalNumGroups);
444 allGroupsNewLabel = -1;
447 forAll(allGroups, groupI)
449 if( allGroupsNewLabel[groupI] != -1 )
452 DynList<label> connectedGroups;
457 graphNeiOp(allGroups),
458 graphSelectorOp(allGroups)
461 forAll(connectedGroups, gI)
462 allGroupsNewLabel[connectedGroups[gI]] = counter;
470 //- broadcast group labels from the master to other processors
471 Pstream::scatter(nGroups);
472 Pstream::scatter(allGroupsNewLabel);
474 //- assign correct group labels
475 forAll(globalGroupLabel, groupI)
477 const label ngI = globalGroupLabel[groupI];
478 globalGroupLabel[groupI] = allGroupsNewLabel[ngI];
482 //- set the global group label
484 # pragma omp parallel for schedule(dynamic, 50)
486 forAll(elementInGroup, elI)
488 if( elementInGroup[elI] < 0 )
491 elementInGroup[elI] = globalGroupLabel[elementInGroup[elI]];
497 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
499 } // End namespace help
501 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
503 } // End namespace Foam
505 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //