1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
28 Generates a VTK file of particle tracks for cases that were computed using
29 a tracked-parcel-type cloud
31 \*---------------------------------------------------------------------------*/
35 #include "IOdictionary.H"
38 #include "timeSelector.H"
40 #include "passiveParticleCloud.H"
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
46 int main(int argc, char *argv[])
48 timeSelector::addOptions();
49 #include "addRegionOption.H"
51 #include "setRootCase.H"
53 #include "createTime.H"
54 instantList timeDirs = timeSelector::select0(runTime, args);
55 #include "createNamedMesh.H"
56 #include "createFields.H"
58 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
60 fileName vtkPath(runTime.path()/"VTK");
63 Info<< "Scanning times to determine track data for cloud " << cloudName
66 labelList maxIds(Pstream::nProcs(), -1);
67 forAll(timeDirs, timeI)
69 runTime.setTime(timeDirs[timeI], timeI);
70 Info<< "Time = " << runTime.timeName() << endl;
72 Info<< " Reading particle positions" << endl;
73 passiveParticleCloud myCloud(mesh, cloudName);
74 Info<< " Read " << returnReduce(myCloud.size(), sumOp<label>())
75 << " particles" << endl;
77 forAllConstIter(passiveParticleCloud, myCloud, iter)
79 label origId = iter().origId();
80 label origProc = iter().origProc();
82 maxIds[origProc] = max(maxIds[origProc], origId);
85 Pstream::listCombineGather(maxIds, maxEqOp<label>());
86 Pstream::listCombineScatter(maxIds);
88 labelList numIds = maxIds + 1;
90 Info<< nl << "Particle statistics:" << endl;
93 Info<< " Found " << numIds[procI] << " particles originating"
94 << " from processor " << procI << endl;
99 // calc starting ids for particles on each processor
100 List<label> startIds(numIds.size(), 0);
101 for (label i = 0; i < numIds.size()-1; i++)
103 startIds[i+1] += startIds[i] + numIds[i];
105 label nParticle = startIds.last() + numIds[startIds.size()-1];
109 // number of tracks to generate
110 label nTracks = nParticle/sampleFrequency;
112 // storage for all particle tracks
113 List<DynamicList<vector> > allTracks(nTracks);
115 Info<< "\nGenerating " << nTracks << " particle tracks for cloud "
116 << cloudName << nl << endl;
118 forAll(timeDirs, timeI)
120 runTime.setTime(timeDirs[timeI], timeI);
121 Info<< "Time = " << runTime.timeName() << endl;
123 List<pointField> allPositions(Pstream::nProcs());
124 List<labelField> allOrigIds(Pstream::nProcs());
125 List<labelField> allOrigProcs(Pstream::nProcs());
127 // Read particles. Will be size 0 if no particles.
128 Info<< " Reading particle positions" << endl;
129 passiveParticleCloud myCloud(mesh, cloudName);
131 // collect the track data on all processors that have positions
132 allPositions[Pstream::myProcNo()].setSize
137 allOrigIds[Pstream::myProcNo()].setSize(myCloud.size(), 0);
138 allOrigProcs[Pstream::myProcNo()].setSize(myCloud.size(), 0);
141 forAllConstIter(passiveParticleCloud, myCloud, iter)
143 allPositions[Pstream::myProcNo()][i] = iter().position();
144 allOrigIds[Pstream::myProcNo()][i] = iter().origId();
145 allOrigProcs[Pstream::myProcNo()][i] = iter().origProc();
149 // collect the track data on the master processor
150 Pstream::gatherList(allPositions);
151 Pstream::gatherList(allOrigIds);
152 Pstream::gatherList(allOrigProcs);
154 Info<< " Constructing tracks" << nl << endl;
155 if (Pstream::master())
157 forAll(allPositions, procI)
159 forAll(allPositions[procI], i)
162 startIds[allOrigProcs[procI][i]]
163 + allOrigIds[procI][i];
165 if (globalId % sampleFrequency == 0)
167 label trackId = globalId/sampleFrequency;
168 if (allTracks[trackId].size() < maxPositions)
170 allTracks[trackId].append
172 allPositions[procI][i]
181 if (Pstream::master())
183 OFstream vtkTracks(vtkPath/"particleTracks.vtk");
185 Info<< "\nWriting particle tracks to " << vtkTracks.name()
188 // Total number of points in tracks + 1 per track
190 forAll(allTracks, trackI)
192 nPoints += allTracks[trackI].size();
196 << "# vtk DataFile Version 2.0" << nl
197 << "particleTracks" << nl
199 << "DATASET POLYDATA" << nl
200 << "POINTS " << nPoints << " float" << nl;
202 // Write track points to file
203 forAll(allTracks, trackI)
205 forAll(allTracks[trackI], i)
207 const vector& pt = allTracks[trackI][i];
208 vtkTracks << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
212 // write track (line) connectivity to file
213 vtkTracks << "LINES " << nTracks << ' ' << nPoints+nTracks << nl;
215 // Write ids of track points to file
217 forAll(allTracks, trackI)
219 vtkTracks << allTracks[trackI].size();
221 forAll(allTracks[trackI], i)
223 vtkTracks << ' ' << globalPtI;
230 Info<< "end" << endl;
237 // ************************************************************************* //