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

particleTracks.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) 2008-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 Application
00025     particleTracks
00026 
00027 Description
00028     Generates a VTK file of particle tracks for cases that were computed using
00029     a tracked-parcel-type cloud.
00030 
00031 Usage
00032     - particleTracks [OPTION]
00033 
00034     @param -region <name>\n
00035     Only apply to named mesh region.
00036 
00037     @param -noZero \n
00038     Ignore timestep 0.
00039 
00040     @param -constant \n
00041     Include the constant directory.
00042 
00043     @param -time <time>\n
00044     Apply only to specific time.
00045 
00046     @param -latestTime \n
00047     Only apply to latest time step.
00048 
00049     @param -case <dir> \n
00050     Specify the case directory
00051 
00052     @param -parallel \n
00053     Run the case in parallel
00054 
00055     @param -help \n
00056     Display short usage message
00057 
00058     @param -doc \n
00059     Display Doxygen documentation page
00060 
00061     @param -srcDoc \n
00062     Display source code
00063 
00064 \*---------------------------------------------------------------------------*/
00065 
00066 #include <OpenFOAM/argList.H>
00067 #include <lagrangian/Cloud.H>
00068 #include <OpenFOAM/IOdictionary.H>
00069 #include <finiteVolume/fvMesh.H>
00070 #include <OpenFOAM/Time.H>
00071 #include <OpenFOAM/timeSelector.H>
00072 #include <OpenFOAM/OFstream.H>
00073 #include <lagrangian/passiveParticleCloud.H>
00074 
00075 using namespace Foam;
00076 
00077 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00078 
00079 int main(int argc, char *argv[])
00080 {
00081     timeSelector::addOptions();
00082     #include <OpenFOAM/addRegionOption.H>
00083 
00084     #include <OpenFOAM/setRootCase.H>
00085 
00086     #include <OpenFOAM/createTime.H>
00087     instantList timeDirs = timeSelector::select0(runTime, args);
00088     #include <OpenFOAM/createNamedMesh.H>
00089     #include "createFields.H"
00090 
00091     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00092 
00093     fileName vtkPath(runTime.path()/"VTK");
00094     mkDir(vtkPath);
00095 
00096     Info<< "Scanning times to determine track data for cloud " << cloudName
00097         << nl << endl;
00098 
00099     labelList maxIds(Pstream::nProcs(), -1);
00100     forAll(timeDirs, timeI)
00101     {
00102         runTime.setTime(timeDirs[timeI], timeI);
00103         Info<< "Time = " << runTime.timeName() << endl;
00104 
00105         Info<< "    Reading particle positions" << endl;
00106         passiveParticleCloud myCloud(mesh, cloudName);
00107         Info<< "    Read " << returnReduce(myCloud.size(), sumOp<label>())
00108             << " particles" << endl;
00109 
00110         forAllConstIter(passiveParticleCloud, myCloud, iter)
00111         {
00112             label origId = iter().origId();
00113             label origProc = iter().origProc();
00114 
00115             maxIds[origProc] = max(maxIds[origProc], origId);
00116         }
00117     }
00118     Pstream::listCombineGather(maxIds, maxEqOp<label>());
00119     Pstream::listCombineScatter(maxIds);
00120 
00121     labelList numIds = maxIds + 1;
00122 
00123     Info<< nl << "Particle statistics:" << endl;
00124     forAll(maxIds, procI)
00125     {
00126         Info<< "    Found " << numIds[procI] << " particles originating"
00127             << " from processor " << procI << endl;
00128     }
00129     Info<< nl << endl;
00130 
00131 
00132     // calc starting ids for particles on each processor
00133     List<label> startIds(numIds.size(), 0);
00134     for (label i = 0; i < numIds.size()-1; i++)
00135     {
00136         startIds[i+1] += startIds[i] + numIds[i];
00137     }
00138     label nParticle = startIds[startIds.size()-1] + numIds[startIds.size()-1];
00139 
00140 
00141 
00142     // number of tracks to generate
00143     label nTracks = nParticle/sampleFrequency;
00144 
00145     // storage for all particle tracks
00146     List<DynamicList<vector> > allTracks(nTracks);
00147 
00148     Info<< "\nGenerating " << nTracks << " particle tracks for cloud "
00149         << cloudName << nl << endl;
00150 
00151     forAll(timeDirs, timeI)
00152     {
00153         runTime.setTime(timeDirs[timeI], timeI);
00154         Info<< "Time = " << runTime.timeName() << endl;
00155 
00156         List<pointField> allPositions(Pstream::nProcs());
00157         List<labelField> allOrigIds(Pstream::nProcs());
00158         List<labelField> allOrigProcs(Pstream::nProcs());
00159 
00160         // Read particles. Will be size 0 if no particles.
00161         Info<< "    Reading particle positions" << endl;
00162         passiveParticleCloud myCloud(mesh, cloudName);
00163 
00164         // collect the track data on all processors that have positions
00165         allPositions[Pstream::myProcNo()].setSize
00166         (
00167             myCloud.size(),
00168             point::zero
00169         );
00170         allOrigIds[Pstream::myProcNo()].setSize(myCloud.size(), 0);
00171         allOrigProcs[Pstream::myProcNo()].setSize(myCloud.size(), 0);
00172 
00173         label i = 0;
00174         forAllConstIter(passiveParticleCloud, myCloud, iter)
00175         {
00176             allPositions[Pstream::myProcNo()][i] = iter().position();
00177             allOrigIds[Pstream::myProcNo()][i] = iter().origId();
00178             allOrigProcs[Pstream::myProcNo()][i] = iter().origProc();
00179             i++;
00180         }
00181 
00182         // collect the track data on the master processor
00183         Pstream::gatherList(allPositions);
00184         Pstream::gatherList(allOrigIds);
00185         Pstream::gatherList(allOrigProcs);
00186 
00187         Info<< "    Constructing tracks" << nl << endl;
00188         if (Pstream::master())
00189         {
00190             forAll(allPositions, procI)
00191             {
00192                 forAll(allPositions[procI], i)
00193                 {
00194                     label globalId =
00195                         startIds[allOrigProcs[procI][i]]
00196                       + allOrigIds[procI][i];
00197 
00198                     if (globalId % sampleFrequency == 0)
00199                     {
00200                         label trackId = globalId/sampleFrequency;
00201                         if (allTracks[trackId].size() < maxPositions)
00202                         {
00203                             allTracks[trackId].append
00204                             (
00205                                 allPositions[procI][i]
00206                             );
00207                         }
00208                     }
00209                 }
00210             }
00211         }
00212     }
00213 
00214     if (Pstream::master())
00215     {
00216         OFstream vtkTracks(vtkPath/"particleTracks.vtk");
00217 
00218         Info<< "\nWriting particle tracks to " << vtkTracks.name()
00219             << nl << endl;
00220 
00221         // Total number of points in tracks + 1 per track
00222         label nPoints = 0;
00223         forAll(allTracks, trackI)
00224         {
00225             nPoints += allTracks[trackI].size();
00226         }
00227 
00228         vtkTracks
00229             << "# vtk DataFile Version 2.0" << nl
00230             << "particleTracks" << nl
00231             << "ASCII" << nl
00232             << "DATASET POLYDATA" << nl
00233             << "POINTS " << nPoints << " float" << nl;
00234 
00235         // Write track points to file
00236         forAll(allTracks, trackI)
00237         {
00238             forAll(allTracks[trackI], i)
00239             {
00240                 const vector& pt = allTracks[trackI][i];
00241                 vtkTracks << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
00242             }
00243         }
00244 
00245         // write track (line) connectivity to file
00246         vtkTracks << "LINES " << nTracks << ' ' << nPoints+nTracks << nl;
00247 
00248         // Write ids of track points to file
00249         label globalPtI = 0;
00250         forAll(allTracks, trackI)
00251         {
00252             vtkTracks << allTracks[trackI].size();
00253 
00254             forAll(allTracks[trackI], i)
00255             {
00256                 vtkTracks << ' ' << globalPtI;
00257                 globalPtI++;
00258             }
00259 
00260             vtkTracks << nl;
00261         }
00262 
00263         Info<< "end" << endl;
00264     }
00265 
00266     return 0;
00267 }
00268 
00269 
00270 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines