FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

ParSortableList.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "ParSortableList.H"
00027 #include "SortableList.H"
00028 #include <OpenFOAM/Pstream.H>
00029 #include <OpenFOAM/ListListOps.H>
00030 #include <OpenFOAM/PstreamReduceOps.H>
00031 
00032 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00033 
00034 template <class Type>
00035 void Foam::ParSortableList<Type>::write
00036 (
00037     const List<Type>& elems,
00038     Ostream& os
00039 ) const
00040 {
00041     os << '(';
00042 
00043     forAll(elems, elemI)
00044     {
00045         os << ' ' << elems[elemI];
00046     }
00047     os << ')';
00048 }
00049 
00050 
00051 // Copy src, starting at destI into dest.
00052 template <class Type>
00053 void Foam::ParSortableList<Type>::copyInto
00054 (
00055     const List<Type>& values,
00056     const labelList& indices,
00057     const label fromProcNo,
00058     label& destI,
00059     List<taggedValue>& dest
00060 ) const
00061 {
00062     forAll(values, elemI)
00063     {
00064         taggedValue& tagVal = dest[destI];
00065 
00066         tagVal.value() = values[elemI];
00067         tagVal.index() = indices[elemI];
00068         tagVal.procID() = fromProcNo;
00069 
00070         destI++;
00071     }
00072 }
00073 
00074 
00075 template <class Type>
00076 void Foam::ParSortableList<Type>::getPivots
00077 (
00078     const List<Type>& elems,
00079     List<Type>& pivots
00080 ) const
00081 {
00082     pivots.setSize(Pstream::nProcs());
00083 
00084     label pivotPos = 0;
00085 
00086     forAll(pivots, pivotI)
00087     {
00088         pivots[pivotI] = elems[pivotPos];
00089 
00090         pivotPos += elems.size()/Pstream::nProcs();
00091     }
00092 }
00093 
00094 
00095 template <class Type>
00096 void Foam::ParSortableList<Type>::checkAndSend
00097 (
00098     List<Type>& values,
00099     labelList& indices,
00100     const label bufSize,
00101     const label destProcI
00102 ) const
00103 {
00104     if (destProcI != Pstream::myProcNo())
00105     {
00106         values.setSize(bufSize);
00107         indices.setSize(bufSize);
00108 
00109         if (debug)
00110         {
00111             Pout<<  "Sending to " << destProcI << " elements:" << values
00112                 << endl;
00113         }
00114 
00115         {
00116             OPstream toSlave(Pstream::blocking, destProcI);
00117             toSlave << values << indices;
00118         }
00119     }
00120 }
00121 
00122 
00123 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00124 
00125 // Construct from List, sorting the elements
00126 template <class Type>
00127 Foam::ParSortableList<Type>::ParSortableList(const UList<Type>& values)
00128 :
00129     List<Type>(values),
00130     indices_(0),
00131     procs_(0)
00132 {
00133     sort();
00134 }
00135 
00136 
00137 // Construct given size. Sort later on.
00138 template <class Type>
00139 Foam::ParSortableList<Type>::ParSortableList(const label size)
00140 :
00141     List<Type>(size),
00142     indices_(0),
00143     procs_(0)
00144 {}
00145 
00146 
00147 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00148 
00149 // Sort
00150 template <class Type>
00151 void Foam::ParSortableList<Type>::sort()
00152 {
00153     //
00154     // 0. Get total size of dataset.
00155     //
00156 
00157     label n = this->size();
00158 
00159     reduce(n, sumOp<label>());
00160 
00161 
00162     // 1. Sort list locally
00163     SortableList<Type> sorted(*this);
00164 
00165     // Collect elements at pivot points
00166     labelListList sortedGatherList(Pstream::nProcs());
00167 
00168     labelList& pivots = sortedGatherList[Pstream::myProcNo()];
00169 
00170     getPivots(sorted, pivots);
00171 
00172     if (debug)
00173     {
00174         Pout<< "pivots:";
00175         write(pivots, Pout);
00176         Pout<< endl;
00177     }
00178 
00179 
00180     //
00181     // 2. Combine pivotlist per processor onto master, sort, get pivots.
00182     //
00183 
00184     Pstream::gatherList(sortedGatherList);
00185 
00186     if (Pstream::master())
00187     {
00188         labelList allPivots =
00189             ListListOps::combine<labelList>
00190             (
00191                 sortedGatherList,
00192                 accessOp<labelList>()
00193             );
00194 
00195         SortableList<Type> sortedPivots(allPivots);
00196 
00197         if (debug)
00198         {
00199             Pout<< "allPivots:";
00200             write(allPivots, Pout);
00201             Pout<< endl;
00202         }
00203 
00204         getPivots(sortedPivots, pivots);
00205     }
00206     Pstream::scatter(pivots);
00207 
00208     if (debug)
00209     {
00210         Pout<< "new pivots:";
00211         write(pivots, Pout);
00212         Pout<< endl;
00213     }
00214 
00215 
00216     //
00217     // 3. Distribute pivots & distribute.
00218     //
00219 
00220     label pivotI = 1;
00221     label destProcI = 0;
00222 
00223     // Buffer for my own data. Keep original index together with value.
00224     labelList ownValues(sorted.size());
00225     labelList ownIndices(sorted.size());
00226     label ownI = 0;
00227 
00228     // Buffer for sending data
00229     labelList sendValues(sorted.size());
00230     labelList sendIndices(sorted.size());
00231     label sendI = 0;
00232 
00233     forAll(sorted, sortedI)
00234     {
00235         if ((pivotI < Pstream::nProcs()) && (sorted[sortedI] > pivots[pivotI]))
00236         {
00237             checkAndSend(sendValues, sendIndices, sendI, destProcI);
00238 
00239             // Reset buffer.
00240             sendValues.setSize(sorted.size());
00241             sendIndices.setSize(sorted.size());
00242             sendI = 0;
00243 
00244             pivotI++;
00245             destProcI++;
00246         }
00247 
00248         if (destProcI != Pstream::myProcNo())
00249         {
00250             sendValues[sendI] = sorted[sortedI];
00251             sendIndices[sendI] = sorted.indices()[sortedI];
00252             sendI++;
00253         }
00254         else
00255         {
00256             ownValues[ownI] = sorted[sortedI];
00257             ownIndices[ownI] = sorted.indices()[sortedI];
00258             ownI++;
00259         }
00260     }
00261 
00262 
00263     // Handle trailing send buffer
00264     if (sendI != 0)
00265     {
00266         checkAndSend(sendValues, sendIndices, sendI, destProcI);
00267     }
00268 
00269     // Print ownValues
00270     ownValues.setSize(ownI);
00271     ownIndices.setSize(ownI);
00272 
00273     if (debug & 2)
00274     {
00275         Pout<< "Not sending (to myself) elements "
00276             << ownValues << endl;
00277     }
00278 
00279     //
00280     // 4. Combine pieces from all processors & sort. Use indices() from
00281     // SortableList to remember source processor number.
00282     //
00283 
00284     // Allocate receive buffer. Acc. to paper upper bound is 2*n/p
00285     // (n=total size, p=nProcs). Resize later on.
00286     List<taggedValue> combinedValues(2 * n/Pstream::nProcs());
00287 
00288     label combinedI = 0;
00289 
00290     for (label procI = 0; procI < Pstream::nProcs(); procI++)
00291     {
00292         if (procI == Pstream::myProcNo())
00293         {
00294             if (debug & 2)
00295             {
00296                 Pout<< "Copying from own:" << ownValues << endl;
00297             }
00298 
00299             // Copy ownValues,ownIndices into combined buffer
00300             copyInto(ownValues, ownIndices, procI, combinedI, combinedValues);
00301         }
00302         else
00303         {
00304             labelList recValues;
00305             labelList recIndices;
00306 
00307             {
00308                 if (debug)
00309                 {
00310                     Pout<< "Receiving from " << procI << endl;
00311                 }
00312 
00313                 IPstream fromSlave(Pstream::blocking, procI);
00314 
00315                 fromSlave >> recValues >> recIndices;
00316 
00317                 if (debug & 2)
00318                 {
00319                     Pout<< "Received from " << procI
00320                         << " elements:" << recValues << endl;
00321                 }
00322             }
00323 
00324             if (debug)
00325             {
00326                 Pout<< "Copying starting at:" << combinedI << endl;
00327             }
00328             copyInto(recValues, recIndices, procI, combinedI, combinedValues);
00329         }
00330     }
00331     combinedValues.setSize(combinedI);
00332 
00333     // Sort according to values
00334     Foam::sort(combinedValues);
00335 
00336     // Copy into *this
00337     this->setSize(combinedI);
00338     indices_.setSize(combinedI);
00339     procs_.setSize(combinedI);
00340 
00341     forAll(combinedValues, elemI)
00342     {
00343         this->operator[](elemI) = combinedValues[elemI].value();
00344         indices_[elemI] = combinedValues[elemI].index();
00345         procs_[elemI] = combinedValues[elemI].procID();
00346     }
00347 }
00348 
00349 
00350 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines