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 "helperFunctionsPar.H"
31 #include "labelPair.H"
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
48 template<class sendOp, class combineOp, class T, class ListType>
49 void combineData(const sendOp& sop, combineOp& cop)
51 std::map<label, LongList<T> > sMap;
56 exchangeMap(sMap, data);
61 template<class T, class ListType, class scatterOp, class gatherOp>
62 void whisperReduce(const ListType& neis, const scatterOp& sop, gatherOp& gop)
64 DynList<label> below, above;
67 if( neis[i] < Pstream::myProcNo() )
69 above.append(neis[i]);
71 else if( neis[i] > Pstream::myProcNo() )
73 below.append(neis[i]);
77 //- receive the data from the processors above
82 IPstream fromOtherProc(Pstream::blocking, above[aboveI]);
83 fromOtherProc >> receivedData;
88 //- send the data to the processors below
91 const label neiProc = below[belowI];
97 OPstream toOtherProc(Pstream::blocking, neiProc, dts.byteSize());
101 //- gather the data from the processors below to the processors above
102 //- receive the data from the processors below
103 forAllReverse(below, belowI)
106 List<T> receivedData;
107 IPstream fromOtherProc(Pstream::blocking, below[belowI]);
108 fromOtherProc >> receivedData;
113 //- send the data to the processors below
114 forAllReverse(above, aboveI)
116 const label neiProc = above[aboveI];
122 OPstream toOtherProc(Pstream::blocking, neiProc, dts.byteSize());
127 template<class T, class ListType>
130 const std::map<label, ListType>& m,
132 const Pstream::commsTypes commsType
137 if( !contiguous<T>() )
138 FatalError << "Data is not contiguous" << exit(FatalError);
140 typename std::map<label, ListType>::const_iterator iter;
142 //- check which processors shall exchange the data and which ones shall not
143 labelHashSet receiveData;
144 for(iter=m.begin();iter!=m.end();++iter)
146 OPstream toOtherProc(Pstream::blocking, iter->first, sizeof(label));
148 toOtherProc << iter->second.size();
151 for(iter=m.begin();iter!=m.end();++iter)
153 IPstream fromOtherProc(Pstream::blocking, iter->first, sizeof(label));
159 receiveData.insert(iter->first);
162 if( commsType == Pstream::blocking )
164 //- start with blocking type of send and received operation
166 //- send data to other processors
167 for(iter=m.begin();iter!=m.end();++iter)
169 const ListType& dts = iter->second;
171 if( dts.size() == 0 )
183 //- receive data from other processors
184 for(iter=m.begin();iter!=m.end();++iter)
186 if( !receiveData.found(iter->first) )
189 IPstream fromOtherProc(Pstream::blocking, iter->first);
190 data.appendFromStream(fromOtherProc);
193 else if( commsType == Pstream::scheduled )
195 //- start with scheduled data transfer
196 //- this type of transfer is intended for long messages because
197 //- it does not require any buffer
199 //- receive data from processors with lower ids
200 for(iter=m.begin();iter!=m.end();++iter)
202 if( iter->first >= Pstream::myProcNo() )
204 if( !receiveData.found(iter->first) )
208 IPstream fromOtherProc(Pstream::scheduled, iter->first);
209 //fromOtherProc >> receive;
210 data.appendFromStream(fromOtherProc);
213 // data.append(receive[i]);
216 //- send data to processors with greater ids
217 for(iter=m.begin();iter!=m.end();++iter)
219 if( iter->first <= Pstream::myProcNo() )
222 const ListType& dts = iter->second;
224 if( dts.size() == 0 )
237 //- receive data from processors with greater ids
238 typename std::map<label, ListType>::const_reverse_iterator riter;
239 for(riter=m.rbegin();riter!=m.rend();++riter)
241 if( riter->first <= Pstream::myProcNo() )
243 if( !receiveData.found(riter->first) )
246 IPstream fromOtherProc(Pstream::scheduled, riter->first);
248 //fromOtherProc >> receive;
249 data.appendFromStream(fromOtherProc);
252 // data.append(receive[i]);
255 //- send data to processors with lower ids
256 for(riter=m.rbegin();riter!=m.rend();++riter)
258 if( riter->first >= Pstream::myProcNo() )
261 const ListType& dts = riter->second;
263 if( dts.size() == 0 )
280 "template<class T, class ListType>"
282 "(const std::map<label, ListType>& m, LongList<T>& data,"
283 " const Pstream::commsTypes commsType)"
284 ) << "Unknown communication type" << exit(FatalError);
287 # ifdef DEBUGExchangeMap
288 labelList nReceived(Pstream::nProcs(), 0);
289 for(iter=m.begin();iter!=m.end();++iter)
290 nReceived[iter->first] += iter->second.size();
292 reduce(nReceived, sumOp<labelList>());
294 if( nReceived[Pstream::myProcNo()] != data.size() )
295 FatalError << "Invalid data read!" << abort(FatalError);
299 template<class T, class ListType>
302 const std::map<label, ListType>& m,
303 std::map<label, List<T> >&mOut
308 if( !contiguous<T>() )
309 FatalError << "Data is not contigous" << exit(FatalError);
311 typename std::map<label, ListType>::const_iterator iter;
313 //- send data to other processors
314 for(iter=m.begin();iter!=m.end();++iter)
316 const ListType& dataToSend = iter->second;
322 dataToSend.byteSize()
324 toOtherProc << dataToSend;
327 //- receive data from other processors
328 for(iter=m.begin();iter!=m.end();++iter)
330 mOut.insert(std::make_pair(iter->first, List<T>()));
331 List<T>& dataToReceive = mOut[iter->first];
333 IPstream fromOtherProc(Pstream::blocking, iter->first);
334 fromOtherProc >> dataToReceive;
338 template<class RowType, template<class ListTypeArg> class GraphType>
339 void reverseAddressingSMP
341 const GraphType<RowType>& addr,
342 GraphType<RowType>& reverseAddr
345 reverseAddr.setSize(0);
346 labelList nAppearances;
348 label minRow(INT_MAX), maxRow(0);
349 DynList<std::map<label, DynList<labelPair, 64> > > dataForOtherThreads;
352 # pragma omp parallel
355 //- find min and max entry in the graph
356 //- they are used for assigning ranges of values local for each process
357 label localMinRow(minRow), localMaxRow(0);
359 # pragma omp for schedule(guided)
363 const RowType& row = addr[rowI];
367 localMaxRow = Foam::max(localMaxRow, row[i]);
368 localMinRow = Foam::min(localMinRow, row[i]);
375 # pragma omp critical
378 minRow = Foam::min(minRow, localMinRow);
379 maxRow = Foam::max(maxRow, localMaxRow);
385 //- allocate the rows of the transposed graph
390 dataForOtherThreads.setSize(omp_get_num_threads());
392 dataForOtherThreads.setSize(1);
394 nAppearances.setSize(maxRow);
395 reverseAddr.setSize(maxRow);
399 const label nProcs = omp_get_num_threads();
400 const label procNo = omp_get_thread_num();
402 const label nProcs = 1;
403 const label procNo = 0;
409 //- initialise appearances
412 for(label i=0;i<maxRow;++i)
415 const label range = (maxRow - minRow) / nProcs + 1;
416 const label localMin = minRow + procNo * range;
417 const label localMax = Foam::min(localMin + range, maxRow);
419 //- find the number of appearances of each element in the original graph
425 const RowType& row = addr[rowI];
429 const label entryI = row[j];
431 const label procI = (entryI - minRow) / range;
432 if( procI != procNo )
434 dataForOtherThreads[procNo][procI].append
436 labelPair(entryI, rowI)
441 ++nAppearances[entryI];
450 //- count the appearances which are not local to the processor
451 for(label i=0;i<nProcs;++i)
453 const std::map<label, DynList<labelPair, 64> >& data =
454 dataForOtherThreads[i];
456 std::map<label, DynList<labelPair, 64> >::const_iterator it =
459 if( it != data.end() )
461 const DynList<labelPair, 64>& entries = it->second;
464 ++nAppearances[entries[j].first()];
472 //- allocate reverse matrix
473 for(label i=localMin;i<localMax;++i)
475 reverseAddr[i].setSize(nAppearances[i]);
479 //- start filling reverse addressing graph
480 //- update data from processors with smaller labels
481 for(label i=0;i<procNo;++i)
483 const std::map<label, DynList<labelPair, 64> >& data =
484 dataForOtherThreads[i];
485 std::map<label, DynList<labelPair, 64> >::const_iterator it =
488 if( it != data.end() )
490 const DynList<labelPair, 64>& entries = it->second;
494 const label entryI = entries[j].first();
495 reverseAddr[entryI][nAppearances[entryI]++] =
501 //- update data local to the processor
507 const RowType& row = addr[rowI];
511 const label entryI = row[j];
513 if( (entryI >= localMin) && (entryI < localMax) )
515 reverseAddr[entryI][nAppearances[entryI]++] = rowI;
520 //- update data from the processors with higher labels
521 for(label i=procNo+1;i<nProcs;++i)
523 const std::map<label, DynList<labelPair, 64> >& data =
524 dataForOtherThreads[i];
525 std::map<label, DynList<labelPair, 64> >::const_iterator it =
528 if( it != data.end() )
530 const DynList<labelPair, 64>& entries = it->second;
534 const label entryI = entries[j].first();
535 reverseAddr[entryI][nAppearances[entryI]++] =
543 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
545 } // End namespace help
547 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
549 } // End namespace Foam
551 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //