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
30 NOTE: case must be re-constructed (if running in parallel) before use
32 \*---------------------------------------------------------------------------*/
36 #include "IOdictionary.H"
39 #include "timeSelector.H"
41 #include "passiveParticleCloud.H"
43 #include "SortableList.H"
44 #include "IOobjectList.H"
47 #include "steadyParticleTracksTemplates.H"
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
60 const List<word>& userFields,
61 const IOobjectList& cloudObjs
64 List<bool> ok(userFields.size(), false);
68 ok[i] = ok[i] || fieldOk<label>(cloudObjs, userFields[i]);
69 ok[i] = ok[i] || fieldOk<scalar>(cloudObjs, userFields[i]);
70 ok[i] = ok[i] || fieldOk<vector>(cloudObjs, userFields[i]);
71 ok[i] = ok[i] || fieldOk<sphericalTensor>(cloudObjs, userFields[i]);
72 ok[i] = ok[i] || fieldOk<symmTensor>(cloudObjs, userFields[i]);
73 ok[i] = ok[i] || fieldOk<tensor>(cloudObjs, userFields[i]);
85 Info << "\n*** Warning: user specified field '" << userFields[i]
86 << "' unavailable" << endl;
95 void writeVTK(OFstream& os, const label& value)
102 void writeVTK(OFstream& os, const scalar& value)
109 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
111 int main(int argc, char *argv[])
113 argList::noParallel();
114 timeSelector::addOptions();
115 #include "addRegionOption.H"
116 argList::validOptions.insert("dict", "");
118 #include "setRootCase.H"
120 #include "createTime.H"
121 instantList timeDirs = timeSelector::select0(runTime, args);
122 #include "createNamedMesh.H"
123 #include "createFields.H"
125 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
127 fileName vtkPath(runTime.path()/"VTK");
130 typedef HashTable<label, labelPair, labelPair::Hash<> > trackTableType;
132 forAll(timeDirs, timeI)
134 runTime.setTime(timeDirs[timeI], timeI);
135 Info<< "Time = " << runTime.timeName() << endl;
137 fileName vtkTimePath(runTime.path()/"VTK"/runTime.timeName());
140 Info<< " Reading particle positions" << endl;
142 PtrList<passiveParticle> particles(0);
144 // transfer particles to (more convenient) list
146 passiveParticleCloud ppc(mesh, cloudName);
147 Info<< "\n Read " << returnReduce(ppc.size(), sumOp<label>())
148 << " particles" << endl;
150 particles.setSize(ppc.size());
153 forAllIter(passiveParticleCloud, ppc, iter)
155 particles.set(i++, ppc.remove(&iter()));
158 // myCloud should now be empty
161 List<label> particleToTrack(particles.size());
165 trackTableType trackTable;
168 const label origProc = particles[i].origProc();
169 const label origId = particles[i].origId();
171 const trackTableType::const_iterator& iter =
172 trackTable.find(labelPair(origProc, origId));
174 if (iter == trackTable.end())
176 particleToTrack[i] = nTracks;
177 trackTable.insert(labelPair(origProc, origId), nTracks);
182 particleToTrack[i] = iter();
189 Info<< "\n No track data" << endl;
193 Info<< "\n Generating " << nTracks << " tracks" << endl;
195 // determine length of each track
196 labelList trackLengths(nTracks, 0);
197 forAll(particleToTrack, i)
199 const label trackI = particleToTrack[i];
200 trackLengths[trackI]++;
203 // particle "age" property used to sort the tracks
204 List<SortableList<scalar> > agePerTrack(nTracks);
206 forAll(trackLengths, i)
208 const label length = trackLengths[i];
209 agePerTrack[i].setSize(length);
212 // store the particle age per track
213 IOobjectList cloudObjs
217 cloud::prefix/cloudName
220 // TODO: gather age across all procs
222 tmp<scalarField> tage =
223 readParticleField<scalar>("age", cloudObjs);
224 const scalarField& age = tage();
225 List<label> trackSamples(nTracks, 0);
226 forAll(particleToTrack, i)
228 const label trackI = particleToTrack[i];
229 const label sampleI = trackSamples[trackI];
230 agePerTrack[trackI][sampleI] = age[i];
231 trackSamples[trackI]++;
237 if (Pstream::master())
239 OFstream os(vtkTimePath/"particleTracks.vtk");
241 Info<< "\n Writing particle tracks to " << os.name() << endl;
243 label nPoints = sum(trackLengths);
245 os << "# vtk DataFile Version 2.0" << nl
246 << "particleTracks" << nl
248 << "DATASET POLYDATA" << nl
249 << "POINTS " << nPoints << " float" << nl;
251 Info<< "\n Writing points" << endl;
255 forAll(agePerTrack, i)
257 agePerTrack[i].sort();
258 const labelList& ids = agePerTrack[i].indices();
262 const label localId = offset + ids[j];
263 const vector& pos = particles[localId].position();
264 os << pos.x() << ' ' << pos.y() << ' ' << pos.z()
268 offset += trackLengths[i];
273 // write track (line) connectivity to file
275 Info<< "\n Writing track lines" << endl;
276 os << "\nLINES " << nTracks << ' ' << nPoints + nTracks << nl;
278 // Write ids of track points to file
281 forAll(agePerTrack, i)
283 os << agePerTrack[i].size() << nl;
285 forAll(agePerTrack[i], j)
287 os << ' ' << globalPtI++;
288 if (((j + 1) % 10 == 0) && (j != 0))
299 const label nFields = validateFields(userFields, cloudObjs);
301 os << "POINT_DATA " << nPoints << nl
302 << "FIELD attributes " << nFields << nl;
304 Info<< "\n Processing fields" << nl << endl;
306 processFields<label>(os, agePerTrack, userFields, cloudObjs);
307 processFields<scalar>(os, agePerTrack, userFields, cloudObjs);
308 processFields<vector>(os, agePerTrack, userFields, cloudObjs);
309 processFields<sphericalTensor>
310 (os, agePerTrack, userFields, cloudObjs);
311 processFields<symmTensor>
312 (os, agePerTrack, userFields, cloudObjs);
313 processFields<tensor>(os, agePerTrack, userFields, cloudObjs);
320 Info<< "\ndone" << endl;
326 // ************************************************************************* //