diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/files b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..b72bc1ae83da9b895fed8288b167d6c091038688 --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/files @@ -0,0 +1,3 @@ +steadyParticleTracks.C + +EXE = $(FOAM_APPBIN)/steadyParticleTracks diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options new file mode 100644 index 0000000000000000000000000000000000000000..004f0474b8f682bfba1ee2725cacf8198cafef9e --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options @@ -0,0 +1,9 @@ +EXE_INC = \ + -I$(LIB_SRC)/lagrangian/basic/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/finiteVolume/lnInclude + +EXE_LIBS = \ + -llagrangian \ + -lmeshTools \ + -lfiniteVolume diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/createFields.H b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/createFields.H new file mode 100644 index 0000000000000000000000000000000000000000..24854ab6b60d038d41997f97de85c4433d0cddde --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/createFields.H @@ -0,0 +1,16 @@ +word dictName(args.optionLookupOrDefault<word>("dict", "particleTrackDict")); + +IOdictionary propsDict +( + IOobject + ( + dictName, + runTime.constant(), + mesh, + IOobject::MUST_READ_IF_MODIFIED + ) +); + +word cloudName(propsDict.lookup("cloudName")); + +List<word> userFields(propsDict.lookup("fields")); \ No newline at end of file diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/particleTrackDict b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/particleTrackDict new file mode 100644 index 0000000000000000000000000000000000000000..32c50127d5e1e7a74b30604557b8d4635869b23e --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/particleTrackDict @@ -0,0 +1,23 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: dev | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object particleTrackDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +cloudName reactingCloud1Tracks; + +fields ( d U T ); + +// ************************************************************************* // + diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracks.C b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracks.C new file mode 100644 index 0000000000000000000000000000000000000000..050395a86fc190151174fa7e04f867e2d367ba7c --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracks.C @@ -0,0 +1,327 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2008-2010 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Application + steadyParticleTracks + +Description + Generates a VTK file of particle tracks for cases that were computed using + a steady-state cloud + NOTE: case must be re-constructed (if running in parallel) before use + +\*---------------------------------------------------------------------------*/ + +#include "argList.H" +#include "Cloud.H" +#include "IOdictionary.H" +#include "fvMesh.H" +#include "Time.H" +#include "timeSelector.H" +#include "OFstream.H" +#include "passiveParticleCloud.H" + +#include "SortableList.H" +#include "IOobjectList.H" +#include "PtrList.H" +#include "Field.H" +#include "steadyParticleTracksTemplates.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +using namespace Foam; + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +label validateFields +( + const List<word>& userFields, + const IOobjectList& cloudObjs +) +{ + List<bool> ok(userFields.size(), false); + + forAll(userFields, i) + { + ok[i] = ok[i] || fieldOk<label>(cloudObjs, userFields[i]); + ok[i] = ok[i] || fieldOk<scalar>(cloudObjs, userFields[i]); + ok[i] = ok[i] || fieldOk<vector>(cloudObjs, userFields[i]); + ok[i] = ok[i] || fieldOk<sphericalTensor>(cloudObjs, userFields[i]); + ok[i] = ok[i] || fieldOk<symmTensor>(cloudObjs, userFields[i]); + ok[i] = ok[i] || fieldOk<tensor>(cloudObjs, userFields[i]); + } + + label nOk = 0; + forAll(ok, i) + { + if (ok[i]) + { + nOk++; + } + else + { + Info << "\n*** Warning: user specified field '" << userFields[i] + << "' unavailable" << endl; + } + } + + return nOk; +} + + +template<> +void writeVTK(OFstream& os, const label& value) +{ + os << value; +} + + +template<> +void writeVTK(OFstream& os, const scalar& value) +{ + os << value; +} + +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +int main(int argc, char *argv[]) +{ + argList::noParallel(); + timeSelector::addOptions(); + #include "addRegionOption.H" + argList::validOptions.insert("dict", ""); + + #include "setRootCase.H" + + #include "createTime.H" + instantList timeDirs = timeSelector::select0(runTime, args); + #include "createNamedMesh.H" + #include "createFields.H" + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + fileName vtkPath(runTime.path()/"VTK"); + mkDir(vtkPath); + + typedef HashTable<label, labelPair, labelPair::Hash<> > trackTableType; + + forAll(timeDirs, timeI) + { + runTime.setTime(timeDirs[timeI], timeI); + Info<< "Time = " << runTime.timeName() << endl; + + fileName vtkTimePath(runTime.path()/"VTK"/runTime.timeName()); + mkDir(vtkTimePath); + + Info<< " Reading particle positions" << endl; + + PtrList<passiveParticle> particles(0); + + // transfer particles to (more convenient) list + { + passiveParticleCloud ppc(mesh, cloudName); + Info<< "\n Read " << returnReduce(ppc.size(), sumOp<label>()) + << " particles" << endl; + + particles.setSize(ppc.size()); + + label i = 0; + forAllIter(passiveParticleCloud, ppc, iter) + { + particles.set(i++, ppc.remove(&iter())); + } + + // myCloud should now be empty + } + + List<label> particleToTrack(particles.size()); + label nTracks = 0; + + { + trackTableType trackTable; + forAll(particles, i) + { + const label origProc = particles[i].origProc(); + const label origId = particles[i].origId(); + + const trackTableType::const_iterator& iter = + trackTable.find(labelPair(origProc, origId)); + + if (iter == trackTable.end()) + { + particleToTrack[i] = nTracks; + trackTable.insert(labelPair(origProc, origId), nTracks); + nTracks++; + } + else + { + particleToTrack[i] = iter(); + } + } + } + + if (nTracks == 0) + { + Info<< "\n No track data" << endl; + } + else + { + Info<< "\n Generating " << nTracks << " tracks" << endl; + + // determine length of each track + labelList trackLengths(nTracks, 0); + forAll(particleToTrack, i) + { + const label trackI = particleToTrack[i]; + trackLengths[trackI]++; + } + + // particle "age" property used to sort the tracks + List<SortableList<scalar> > agePerTrack(nTracks); + + forAll(trackLengths, i) + { + const label length = trackLengths[i]; + agePerTrack[i].setSize(length); + } + + // store the particle age per track + IOobjectList cloudObjs + ( + mesh, + runTime.timeName(), + cloud::prefix/cloudName + ); + + // TODO: gather age across all procs + { + tmp<scalarField> tage = + readParticleField<scalar>("age", cloudObjs); + const scalarField& age = tage(); + List<label> trackSamples(nTracks, 0); + forAll(particleToTrack, i) + { + const label trackI = particleToTrack[i]; + const label sampleI = trackSamples[trackI]; + agePerTrack[trackI][sampleI] = age[i]; + trackSamples[trackI]++; + } + tage.clear(); + } + + + if (Pstream::master()) + { + OFstream os(vtkTimePath/"particleTracks.vtk"); + + Info<< "\n Writing particle tracks to " << os.name() << endl; + + label nPoints = sum(trackLengths); + + os << "# vtk DataFile Version 2.0" << nl + << "particleTracks" << nl + << "ASCII" << nl + << "DATASET POLYDATA" << nl + << "POINTS " << nPoints << " float" << nl; + + Info<< "\n Writing points" << endl; + + { + label offset = 0; + forAll(agePerTrack, i) + { + agePerTrack[i].sort(); + const labelList& ids = agePerTrack[i].indices(); + + forAll(ids, j) + { + const label localId = offset + ids[j]; + const vector& pos = particles[localId].position(); + os << pos.x() << ' ' << pos.y() << ' ' << pos.z() + << nl; + } + + offset += trackLengths[i]; + } + } + + + // write track (line) connectivity to file + + Info<< "\n Writing track lines" << endl; + os << "\nLINES " << nTracks << ' ' << nPoints + nTracks << nl; + + // Write ids of track points to file + { + label globalPtI = 0; + forAll(agePerTrack, i) + { + os << agePerTrack[i].size() << nl; + + forAll(agePerTrack[i], j) + { + os << ' ' << globalPtI++; + if (((j + 1) % 10 == 0) && (j != 0)) + { + os << nl; + } + } + + os << nl; + } + } + + + const label nFields = validateFields(userFields, cloudObjs); + + os << "POINT_DATA " << nPoints << nl + << "FIELD attributes " << nFields << nl; + + Info<< "\n Processing fields" << nl << endl; + + processFields<label>(os, agePerTrack, userFields, cloudObjs); + processFields<scalar>(os, agePerTrack, userFields, cloudObjs); + processFields<vector>(os, agePerTrack, userFields, cloudObjs); + processFields<sphericalTensor> + (os, agePerTrack, userFields, cloudObjs); + processFields<symmTensor> + (os, agePerTrack, userFields, cloudObjs); + processFields<tensor>(os, agePerTrack, userFields, cloudObjs); + + } + } + Info<< endl; + } + + Info<< "\ndone" << endl; + + return 0; +} + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..c5292b25c2cf4ada479c1f76f476b34eab8654cf --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C @@ -0,0 +1,188 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2010-2010 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "steadyParticleTracksTemplates.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class Type> +bool fieldOk(const IOobjectList& cloudObjs, const word& name) +{ + IOobjectList objects(cloudObjs.lookupClass(IOField<Type>::typeName)); + + return (objects.lookup(name) != NULL); +} + + +template<class Type> +tmp<Field<Type> > readParticleField +( + const word& name, + const IOobjectList cloudObjs +) +{ + IOobjectList objects(cloudObjs.lookupClass(IOField<Type>::typeName)); + + const IOobject* obj = objects.lookup(name); + if (obj != NULL) + { + IOField<Type> newField(*obj); + return tmp<Field<Type> >(new Field<Type>(newField.xfer())); + } + + Info<< "error: cloud field name " << name << " not found" << endl; + + return Field<Type>::null(); +} + + +template<class Type> +PtrList<List<Type> > readFields +( + PtrList<List<Type> >& values, + const List<word>& fields, + const IOobjectList& cloudObjs +) +{ + IOobjectList objects(cloudObjs.lookupClass(IOField<Type>::typeName)); + + label fieldI = 0; + forAllConstIter(IOobjectList, objects, iter) + { + const IOobject& obj = *iter(); + forAll(fields, j) + { + if (obj.name() == fields[j]) + { + Info<< " reading field " << obj.name() << endl; + IOField<Type> newField(obj); + values.set(fieldI++, new List<Type>(newField.xfer())); + break; + } + } + } + + return values; +} + + +template<class Type> +void writeVTK(OFstream& os, const Type& value) +{ + os << value.component(0); + for (label i=1; i<pTraits<Type>::nComponents; i++) + { + os << ' ' << value.component(i); + } +} + + +template<class Type> +void writeVTKFields +( + OFstream& os, + const PtrList<List<Type> >& values, + const List<SortableList<scalar> >& agePerTrack, + const List<word>& fieldNames +) +{ + label step = max(floor(8/pTraits<Type>::nComponents), 1); + + forAll(values, fieldI) + { + Info<< " writing field " << fieldNames[fieldI] << endl; + os << nl << fieldNames[fieldI] << ' ' << pTraits<Type>::nComponents << ' ' + << values[fieldI].size() << " float" << nl; + label offset = 0; + forAll(agePerTrack, trackI) + { + const List<label> ids = agePerTrack[trackI].indices() + offset; + + List<Type> data(UIndirectList<Type>(values[fieldI], ids)); + label nData = data.size() - 1; + forAll(data, i) + { + writeVTK<Type>(os, data[i]); + if (((i + 1) % step == 0) || (i == nData)) + { + os << nl; + } + else + { + os << ' '; + } + } + offset += ids.size(); + } + } +} + + +template<class Type> +void processFields +( + OFstream& os, + const List<SortableList<scalar> >& agePerTrack, + const List<word>& userFieldNames, + const IOobjectList& cloudObjs +) +{ + IOobjectList objects(cloudObjs.lookupClass(IOField<Type>::typeName)); + + if (objects.size()) + { + DynamicList<word> fieldNames(objects.size()); + forAll(userFieldNames, i) + { + IOobject* obj = objects.lookup(userFieldNames[i]); + if (obj != NULL) + { + fieldNames.append(obj->name()); + } + } + fieldNames.shrink(); + + PtrList<List<Type> > values(fieldNames.size()); + readFields<Type>(values, fieldNames, cloudObjs); + + writeVTKFields<Type> + ( + os, + values, + agePerTrack, + fieldNames.xfer() + ); + } +} + +} // End namespace Foam + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.H b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.H new file mode 100644 index 0000000000000000000000000000000000000000..68d80b97cc58a1bf24dce8ed25e9143655332a90 --- /dev/null +++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.H @@ -0,0 +1,94 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2010-2010 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#ifndef steadyParticleTracksTemplates_H +#define steadyParticleTracksTemplates_H + +#include "OFstream.H" +#include "SortableList.H" +#include "IOobjectList.H" +#include "PtrList.H" +#include "Field.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + bool fieldOk(const IOobjectList& cloudObjs, const word& name); + + template<class Type> + tmp<Field<Type> > readParticleField + ( + const word& name, + const IOobjectList cloudObjs + ); + + template<class Type> + PtrList<List<Type> > readFields + ( + PtrList<List<Type> >& values, + const List<word>& fields, + const IOobjectList& cloudObjs + ); + + template<class Type> + void writeVTK(OFstream& os, const Type& value); + + template<class Type> + void writeVTKFields + ( + OFstream& os, + const PtrList<List<Type> >& values, + const List<SortableList<scalar> >& agePerTrack, + const List<word>& fieldNames + ); + + void processFields + ( + OFstream& os, + const List<SortableList<scalar> >& agePerTrack, + const List<word>& userFieldNames, + const IOobjectList& cloudObjs + ); + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "steadyParticleTracksTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* //