From 3355c8d9eb2823c9420bfb3213a5394592e15329 Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Tue, 25 Aug 2009 12:35:48 +0100
Subject: [PATCH] initial streamlines functionobject

---
 .../postProcessing/sampling/sample/sampleDict |   1 +
 bin/tools/CleanFunctions                      |   1 +
 .../functionObjects/field/Make/files          |   6 +
 .../functionObjects/field/Make/options        |   2 +
 .../fieldValues/cell/cellSourceTemplates.C    |  17 +-
 .../field/streamLine/streamLine.C             | 620 ++++++++++++++++++
 .../field/streamLine/streamLine.H             | 219 +++++++
 .../streamLine/streamLineFunctionObject.C     |  43 ++
 .../streamLine/streamLineFunctionObject.H     |  55 ++
 .../field/streamLine/streamLineParticle.C     | 479 ++++++++++++++
 .../field/streamLine/streamLineParticle.H     | 300 +++++++++
 .../streamLine/streamLineParticleCloud.C      |  79 +++
 .../streamLine/streamLineParticleCloud.H      | 105 +++
 src/sampling/Make/files                       |   9 +-
 .../triSurfaceMeshPointSet.C                  | 177 +++++
 .../triSurfaceMeshPointSet.H                  | 119 ++++
 .../simpleFoam/pitzDaily/system/controlDict   |  62 ++
 17 files changed, 2275 insertions(+), 19 deletions(-)
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLine.C
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLine.H
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.C
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.H
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.C
 create mode 100644 src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.H
 create mode 100644 src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
 create mode 100644 src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.H

diff --git a/applications/utilities/postProcessing/sampling/sample/sampleDict b/applications/utilities/postProcessing/sampling/sample/sampleDict
index 4571c924dfb..9c288d7cbfa 100644
--- a/applications/utilities/postProcessing/sampling/sample/sampleDict
+++ b/applications/utilities/postProcessing/sampling/sample/sampleDict
@@ -63,6 +63,7 @@ fields
 //      curve               specified points, not nessecary on line, uses
 //                          tracking
 //      cloud               specified points, uses findCell
+//      triSurfaceMeshPointSet  points of triSurface
 //
 // axis: how to write point coordinate. Choice of
 // - x/y/z: x/y/z coordinate only
diff --git a/bin/tools/CleanFunctions b/bin/tools/CleanFunctions
index 4a2015febfd..5e0ea64c5ed 100644
--- a/bin/tools/CleanFunctions
+++ b/bin/tools/CleanFunctions
@@ -72,6 +72,7 @@ cleanCase ()
            constant/{cellToRegion,cellLevel*,pointLevel*} \
            constant/polyMesh/sets/ \
            VTK \
+           sets/streamLines \
            > /dev/null 2>&1
 
     for f in `find . -name "*Dict"`
diff --git a/src/postProcessing/functionObjects/field/Make/files b/src/postProcessing/functionObjects/field/Make/files
index 3766cb0ba8a..e950e4d4d5d 100644
--- a/src/postProcessing/functionObjects/field/Make/files
+++ b/src/postProcessing/functionObjects/field/Make/files
@@ -12,4 +12,10 @@ fieldValues/face/faceSourceFunctionObject.C
 fieldValues/cell/cellSource.C
 fieldValues/cell/cellSourceFunctionObject.C
 
+streamLine/streamLine.C
+streamLine/streamLineParticle.C
+streamLine/streamLineParticleCloud.C
+streamLine/streamLineFunctionObject.C
+
+
 LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects
diff --git a/src/postProcessing/functionObjects/field/Make/options b/src/postProcessing/functionObjects/field/Make/options
index 5166bcc9e32..1e254fd4bb4 100644
--- a/src/postProcessing/functionObjects/field/Make/options
+++ b/src/postProcessing/functionObjects/field/Make/options
@@ -1,9 +1,11 @@
 EXE_INC = \
     -I$(LIB_SRC)/finiteVolume/lnInclude \
     -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/lagrangian/basic/lnInclude \
     -I$(LIB_SRC)/sampling/lnInclude
 
 LIB_LIBS = \
     -lfiniteVolume \
     -lmeshTools \
+    -llagrangian \
     -lsampling
diff --git a/src/postProcessing/functionObjects/field/fieldValues/cell/cellSourceTemplates.C b/src/postProcessing/functionObjects/field/fieldValues/cell/cellSourceTemplates.C
index 0b6fa1ff03e..fe495fcca6b 100644
--- a/src/postProcessing/functionObjects/field/fieldValues/cell/cellSourceTemplates.C
+++ b/src/postProcessing/functionObjects/field/fieldValues/cell/cellSourceTemplates.C
@@ -46,11 +46,7 @@ bool Foam::fieldValues::cellSource::setFieldValues
     {
         const vf& field = obr_.lookupObject<vf>(fieldName);
 
-        forAll(values, i)
-        {
-            label cellI = cellId_[i];
-            values[i] = field[cellI];
-        }
+        values = UIndirectList<Type>(field, cellId_);
 
         return true;
     }
@@ -158,16 +154,7 @@ Foam::tmp<Foam::Field<Type> > Foam::fieldValues::cellSource::filterField
     const Field<Type>& field
 ) const
 {
-    tmp<Field<Type> > tvalues(new Field<Type>(cellId_.size()));
-    Field<Type>& values = tvalues();
-
-    forAll(values, i)
-    {
-        label cellI = cellId_[i];
-        values[i] = field[cellI];
-    }
-
-    return tvalues;
+    return tmp<Field<Type> >(new Field<Type>(field, cellId_));
 }
 
 
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLine.C b/src/postProcessing/functionObjects/field/streamLine/streamLine.C
new file mode 100644
index 00000000000..b82041966f3
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLine.C
@@ -0,0 +1,620 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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 "Pstream.H"
+#include "functionObjectList.H"
+#include "streamLine.H"
+#include "fvMesh.H"
+#include "streamLineParticleCloud.H"
+#include "ReadFields.H"
+#include "meshSearch.H"
+#include "sampledSet.H"
+#include "globalIndex.H"
+#include "mapDistribute.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(Foam::streamLine, 0);
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::streamLine::track()
+{
+    const Time& runTime = const_cast<Time&>(obr_.time());
+    const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
+
+    IDLList<streamLineParticle> initialParticles;
+    streamLineParticleCloud particles
+    (
+        mesh,
+        cloudName_,
+        initialParticles
+    );
+
+    //Pout<< "Seeding particles." << endl;
+
+    const sampledSet& seedPoints = sampledSetPtr_();
+    forAll(seedPoints, i)
+    {
+        //Pout<< "Seeded particle at " << seedPoints[i]
+        //    << " at cell:" << seedPoints.cells()[i]
+        //    << endl;
+
+        particles.addParticle
+        (
+            new streamLineParticle
+            (
+                particles,
+                seedPoints[i],
+                seedPoints.cells()[i],
+                lifeTime_               // lifetime
+            )
+        );
+    }
+    label nSeeds = returnReduce(particles.size(), sumOp<label>());
+    Info<< "Seeded " << nSeeds
+        << " particles." << nl << endl;
+
+
+    // Read or lookup fields
+    PtrList<volScalarField> vsFlds;
+    PtrList<interpolationCellPoint<scalar> > vsInterp;
+    PtrList<volVectorField> vvFlds;
+    PtrList<interpolationCellPoint<vector> > vvInterp;
+
+
+    label UIndex = -1;
+
+    if (loadFromFiles_)
+    {
+        IOobjectList allObjects(mesh, runTime.timeName());
+
+        IOobjectList objects(2*fields_.size());
+        forAll(fields_, i)
+        {
+            objects.add(*allObjects[fields_[i]]);
+        }
+
+        ReadFields(mesh, objects, vsFlds);
+        vsInterp.setSize(vsFlds.size());
+        forAll(vsFlds, i)
+        {
+            vsInterp.set(i, new interpolationCellPoint<scalar>(vsFlds[i]));
+        }
+        ReadFields(mesh, objects, vvFlds);
+        vvInterp.setSize(vvFlds.size());
+        forAll(vvFlds, i)
+        {
+            vvInterp.set(i, new interpolationCellPoint<vector>(vvFlds[i]));
+        }
+    }
+    else
+    {
+        label nScalar = 0;
+        label nVector = 0;
+
+        forAll(fields_, i)
+        {
+            if (mesh.foundObject<volScalarField>(fields_[i]))
+            {
+                nScalar++;
+            }
+            else if (mesh.foundObject<volVectorField>(fields_[i]))
+            {
+                nVector++;
+            }
+            else
+            {
+                FatalErrorIn("streamLine::execute()")
+                    << "Cannot find field " << fields_[i] << endl
+                    << "Valid scalar fields are:"
+                    << mesh.names(volScalarField::typeName) << endl
+                    << "Valid vector fields are:"
+                    << mesh.names(volVectorField::typeName)
+                    << exit(FatalError);
+            }
+        }
+        vsInterp.setSize(nScalar);
+        nScalar = 0;
+        vvInterp.setSize(nVector);
+        nVector = 0;
+
+        forAll(fields_, i)
+        {
+            if (mesh.foundObject<volScalarField>(fields_[i]))
+            {
+                const volScalarField& f = mesh.lookupObject<volScalarField>
+                (
+                    fields_[i]
+                );
+                vsInterp.set
+                (
+                    nScalar++,
+                    new interpolationCellPoint<scalar>(f)
+                );
+            }
+            else if (mesh.foundObject<volVectorField>(fields_[i]))
+            {
+                const volVectorField& f = mesh.lookupObject<volVectorField>
+                (
+                    fields_[i]
+                );
+
+                if (f.name() == UName_)
+                {
+                    UIndex = nVector;
+                }
+
+                vvInterp.set
+                (
+                    nVector++,
+                    new interpolationCellPoint<vector>(f)
+                );
+            }
+        }
+    }
+
+    // Store the names
+    scalarNames_.setSize(vsInterp.size());
+    forAll(vsInterp, i)
+    {
+        scalarNames_[i] = vsInterp[i].psi().name();
+    }
+    vectorNames_.setSize(vvInterp.size());
+    forAll(vvInterp, i)
+    {
+        vectorNames_[i] = vvInterp[i].psi().name();
+    }
+
+
+    // Check that we know the index of U in the interpolators.
+
+    if (UIndex == -1)
+    {
+        FatalErrorIn("streamLine::execute()")
+            << "Cannot find field to move particles with : " << UName_
+            << endl
+            << "This field has to be present in the sampled fields "
+            << fields_
+            << " and in the objectRegistry." << endl
+            << exit(FatalError);
+    }
+
+
+
+    // Sampled data
+    // ~~~~~~~~~~~~
+
+    // Size to maximum expected sizes.
+    allTracks_.clear();
+    allTracks_.setCapacity(nSeeds);
+    allScalars_.setSize(vsInterp.size());
+    forAll(allScalars_, i)
+    {
+        allScalars_[i].clear();
+        allScalars_[i].setCapacity(nSeeds);
+    }
+    allVectors_.setSize(vvInterp.size());
+    forAll(allVectors_, i)
+    {
+        allVectors_[i].clear();
+        allVectors_[i].setCapacity(nSeeds);
+    }
+
+    // additional particle info
+    streamLineParticle::trackData td
+    (
+        particles,
+        vsInterp,
+        vvInterp,
+        UIndex,         // index of U in vvInterp
+        trackForward_,  // track in +u direction
+        allTracks_,
+        allScalars_,
+        allVectors_
+    );
+
+    // Track
+    //Pout<< "Tracking particles." << endl;
+    particles.move(td);
+    //Pout<< "Finished tracking particles." << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::streamLine::streamLine
+(
+    const word& name,
+    const objectRegistry& obr,
+    const dictionary& dict,
+    const bool loadFromFiles
+)
+:
+    dict_(dict),
+    name_(name),
+    obr_(obr),
+    loadFromFiles_(loadFromFiles),
+    active_(true)
+{
+    // Only active if a fvMesh is available
+    if (isA<fvMesh>(obr_))
+    {
+        read(dict_);
+    }
+    else
+    {
+        active_ = false;
+        WarningIn
+        (
+            "streamLine::streamLine\n"
+            "(\n"
+                "const word&,\n"
+                "const objectRegistry&,\n"
+                "const dictionary&,\n"
+                "const bool\n"
+            ")"
+        )   << "No fvMesh available, deactivating."
+            << nl << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::streamLine::~streamLine()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::streamLine::read(const dictionary& dict)
+{
+    if (active_)
+    {
+        //dict_ = dict;
+        dict.lookup("fields") >> fields_;
+        UName_ = dict.lookupOrDefault<word>("U", "U");
+        dict.lookup("trackForward") >> trackForward_;
+        dict.lookup("lifeTime") >> lifeTime_;
+        cloudName_ = dict.lookupOrDefault<word>("cloudName", "streamLine");
+        dict.lookup("seedSampleSet") >> seedSet_;
+
+        const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
+
+        meshSearchPtr_.reset(new meshSearch(mesh, false));
+
+        const dictionary& coeffsDict = dict.subDict(seedSet_ + "Coeffs");
+        sampledSetPtr_ = sampledSet::New
+        (
+            seedSet_,
+            mesh,
+            meshSearchPtr_(),
+            coeffsDict
+        );
+        coeffsDict.lookup("axis") >> sampledSetAxis_;
+
+        scalarFormatterPtr_ = writer<scalar>::New(dict.lookup("setFormat"));
+        vectorFormatterPtr_ = writer<vector>::New(dict.lookup("setFormat"));
+    }
+}
+
+
+void Foam::streamLine::execute()
+{
+//    const Time& runTime = const_cast<Time&>(obr_.time());
+//
+//    bool isOutputTime = false;
+//
+//    const functionObjectList& fobs = runTime.functionObjects();
+//
+//    forAll(fobs, i)
+//    {
+//        if (isA<streamLineFunctionObject>(fobs[i]))
+//        {
+//            const streamLineFunctionObject& fo =
+//                dynamic_cast<const streamLineFunctionObject&>(fobs[i]);
+//
+//            if (fo.name() == name_)
+//            {
+//                Pout<< "found me:" << i << endl;
+//                if (fo.outputControl().output())
+//                {
+//                    isOutputTime = true;
+//                    break;
+//                }
+//            }
+//        }
+//    }
+//
+//
+//    if (active_ && isOutputTime)
+//    {
+//        track();
+//    }
+}
+
+
+void Foam::streamLine::end()
+{
+}
+
+
+void Foam::streamLine::write()
+{
+    if (active_)
+    {
+        const Time& runTime = const_cast<Time&>(obr_.time());
+        const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
+
+
+        // Do all injection and tracking
+        track();
+
+
+        if (Pstream::parRun())
+        {
+            // Append slave tracks to master ones
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+            globalIndex globalTrackIDs(allTracks_.size());
+
+            // Construct a distribution map to pull all to the master.
+            labelListList sendMap(Pstream::nProcs());
+            labelListList recvMap(Pstream::nProcs());
+
+            if (Pstream::master())
+            {
+                // Master: receive all. My own first, then consecutive
+                // processors.
+                label trackI = 0;
+
+                forAll(recvMap, procI)
+                {
+                    labelList& fromProc = recvMap[procI];
+                    fromProc.setSize(globalTrackIDs.localSize(procI));
+                    forAll(fromProc, i)
+                    {
+                        fromProc[i] = trackI++;
+                    }
+                }
+            }
+
+            labelList& toMaster = sendMap[0];
+            toMaster.setSize(globalTrackIDs.localSize());
+            forAll(toMaster, i)
+            {
+                toMaster[i] = i;
+            }
+
+            const mapDistribute distMap
+            (
+                globalTrackIDs.size(),
+                sendMap.xfer(),
+                recvMap.xfer()
+            );
+
+
+            // Distribute the track positions
+            mapDistribute::distribute
+            (
+                Pstream::scheduled,
+                distMap.schedule(),
+                distMap.constructSize(),
+                distMap.subMap(),
+                distMap.constructMap(),
+                allTracks_
+            );
+
+            // Distribute the scalars
+            forAll(allScalars_, scalarI)
+            {
+                mapDistribute::distribute
+                (
+                    Pstream::scheduled,
+                    distMap.schedule(),
+                    distMap.constructSize(),
+                    distMap.subMap(),
+                    distMap.constructMap(),
+                    allScalars_[scalarI]
+                );
+            }
+            // Distribute the vectors
+            forAll(allVectors_, vectorI)
+            {
+                mapDistribute::distribute
+                (
+                    Pstream::scheduled,
+                    distMap.schedule(),
+                    distMap.constructSize(),
+                    distMap.subMap(),
+                    distMap.constructMap(),
+                    allVectors_[vectorI]
+                );
+            }
+        }
+
+
+        label n = 0;
+        forAll(allTracks_, trackI)
+        {
+            n += allTracks_[trackI].size();
+        }
+
+        Info<< "Tracks:" << allTracks_.size()
+            << "  total samples:" << n << endl;
+
+
+        // Massage into form suitable for writers
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        if (Pstream::master() && allTracks_.size())
+        {
+            // Make output directory
+
+            fileName vtkPath
+            (
+                Pstream::parRun()
+              ? runTime.path()/".."/"sets"/name()
+              : runTime.path()/"sets"/name()
+            );
+            if (mesh.name() != fvMesh::defaultRegion)
+            {
+                vtkPath = vtkPath/mesh.name();
+            }
+            vtkPath = vtkPath/mesh.time().timeName();
+
+            mkDir(vtkPath);
+
+
+            // Convert track positions
+
+            PtrList<coordSet> tracks(allTracks_.size());
+            forAll(allTracks_, trackI)
+            {
+                tracks.set
+                (
+                    trackI,
+                    new coordSet
+                    (
+                        "track" + Foam::name(trackI),
+                        sampledSetAxis_                 //"xyz"
+                    )
+                );
+                tracks[trackI].transfer(allTracks_[trackI]);
+            }
+
+
+
+            // Convert scalar values
+
+            if (allScalars_.size() > 0)
+            {
+                List<List<scalarField> > scalarValues(allScalars_.size());
+
+                forAll(allScalars_, scalarI)
+                {
+                    DynamicList<scalarList>& allTrackVals =
+                        allScalars_[scalarI];
+                    scalarValues[scalarI].setSize(allTrackVals.size());
+
+                    forAll(allTrackVals, trackI)
+                    {
+                        scalarList& trackVals = allTrackVals[trackI];
+                        scalarValues[scalarI][trackI].transfer(trackVals);
+                    }
+                }
+
+                fileName vtkFile
+                (
+                    vtkPath
+                  / scalarFormatterPtr_().getFileName
+                    (
+                        tracks[0],
+                        scalarNames_
+                    )
+                );
+
+                Info<< "Writing data to " << vtkFile.path() << endl;
+
+                scalarFormatterPtr_().write
+                (
+                    true,           // writeTracks
+                    tracks,
+                    scalarNames_,
+                    scalarValues,
+                    OFstream(vtkFile)()
+                );
+            }
+
+            // Convert vector values
+
+            if (allVectors_.size() > 0)
+            {
+                List<List<vectorField> > vectorValues(allVectors_.size());
+
+                forAll(allVectors_, vectorI)
+                {
+                    DynamicList<vectorList>& allTrackVals =
+                        allVectors_[vectorI];
+                    vectorValues[vectorI].setSize(allTrackVals.size());
+
+                    forAll(allTrackVals, trackI)
+                    {
+                        vectorList& trackVals = allTrackVals[trackI];
+                        vectorValues[vectorI][trackI].transfer(trackVals);
+                    }
+                }
+
+                fileName vtkFile
+                (
+                    vtkPath
+                  / vectorFormatterPtr_().getFileName
+                    (
+                        tracks[0],
+                        vectorNames_
+                    )
+                );
+
+                //Info<< "Writing vector data to " << vtkFile << endl;
+
+                vectorFormatterPtr_().write
+                (
+                    true,           // writeTracks
+                    tracks,
+                    vectorNames_,
+                    vectorValues,
+                    OFstream(vtkFile)()
+                );
+            }
+        }
+    }
+}
+
+
+void Foam::streamLine::updateMesh(const mapPolyMesh&)
+{
+    read(dict_);
+}
+
+
+void Foam::streamLine::movePoints(const pointField&)
+{
+    // Moving mesh affects the search tree
+    read(dict_);
+}
+
+
+//void Foam::streamLine::readUpdate(const polyMesh::readUpdateState state)
+//{
+//    if (state != UNCHANGED)
+//    {
+//        read(dict_);
+//    }
+//}
+
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLine.H b/src/postProcessing/functionObjects/field/streamLine/streamLine.H
new file mode 100644
index 00000000000..8f814ff0e5a
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLine.H
@@ -0,0 +1,219 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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
+
+Class
+    Foam::streamLine
+
+Description
+    Generation of streamlines. Samples along track of passive particle.
+
+SourceFiles
+    streamLine.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef streamLine_H
+#define streamLine_H
+
+#include "volFieldsFwd.H"
+#include "pointFieldFwd.H"
+#include "Switch.H"
+#include "DynamicList.H"
+#include "scalarList.H"
+#include "vectorList.H"
+#include "polyMesh.H"
+#include "writer.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class objectRegistry;
+class dictionary;
+class mapPolyMesh;
+class meshSearch;
+class sampledSet;
+
+/*---------------------------------------------------------------------------*\
+                         Class streamLine Declaration
+\*---------------------------------------------------------------------------*/
+
+class streamLine
+{
+    // Private data
+
+        //- Input dictionary
+        dictionary dict_;
+
+        //- Name of this set of field averages.
+        word name_;
+
+        //- Database this class is registered to
+        const objectRegistry& obr_;
+
+        //- Load fields from files (not from objectRegistry)
+        bool loadFromFiles_;
+
+        //- On/off switch
+        bool active_;
+
+
+        //- List of fields to sample
+        wordList fields_;
+
+        //- Field to transport particle with
+        word UName_;
+
+        //- Whether to use +u or -u
+        bool trackForward_;
+
+        //- Maximum lifetime (= number of cells) of particle
+        label lifeTime_;
+
+        //- Optional specified name of particles
+        word cloudName_;
+
+        //- Type of seed
+        word seedSet_;
+
+        //- Names of scalar fields
+        wordList scalarNames_;
+
+        //- Names of vector fields
+        wordList vectorNames_;
+
+
+
+        // Demand driven
+
+            //- Mesh searching enigne
+            autoPtr<meshSearch> meshSearchPtr_;
+
+            //- Seed set engine
+            autoPtr<sampledSet> sampledSetPtr_;
+
+            //- Axis of the sampled points to output
+            word sampledSetAxis_;
+
+            //- File output writer
+            autoPtr<writer<scalar> > scalarFormatterPtr_;
+
+            autoPtr<writer<vector> > vectorFormatterPtr_;
+
+
+        // Generated data
+
+            //- All tracks. Per particle the points it passed through
+            DynamicList<List<point> > allTracks_;
+
+            //- Per scalarField, per particle, the sampled value.
+            List<DynamicList<scalarList> > allScalars_;
+
+            //- Per scalarField, per particle, the sampled value.
+            List<DynamicList<vectorList> > allVectors_;
+
+
+
+        //- Do all seeding and tracking
+        void track();
+
+        //- Disallow default bitwise copy construct
+        streamLine(const streamLine&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const streamLine&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("streamLine");
+
+
+    // Constructors
+
+        //- Construct for given objectRegistry and dictionary.
+        //  Allow the possibility to load fields from files
+        streamLine
+        (
+            const word& name,
+            const objectRegistry&,
+            const dictionary&,
+            const bool loadFromFiles = false
+        );
+
+
+    //- Destructor
+
+        virtual ~streamLine();
+
+
+    // Member Functions
+
+        //- Return name of the set of field averages
+        virtual const word& name() const
+        {
+            return name_;
+        }
+
+        //- Read the field average data
+        virtual void read(const dictionary&);
+
+        //- Execute the averaging
+        virtual void execute();
+
+        //- Execute the averaging at the final time-loop, currently does nothing
+        virtual void end();
+
+        //- Calculate the field average data and write
+        virtual void write();
+
+        //- Update for changes of mesh
+        virtual void updateMesh(const mapPolyMesh&);
+
+        //- Update for mesh point-motion
+        virtual void movePoints(const pointField&);
+
+        ////- Update for changes of mesh due to readUpdate
+        //virtual void readUpdate(const polyMesh::readUpdateState state);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//#ifdef NoRepository
+//#   include "streamLineTemplates.C"
+//#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.C b/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.C
new file mode 100644
index 00000000000..ce240018d22
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.C
@@ -0,0 +1,43 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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 "streamLineFunctionObject.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineNamedTemplateTypeNameAndDebug(streamLineFunctionObject, 0);
+
+    addToRunTimeSelectionTable
+    (
+        functionObject,
+        streamLineFunctionObject,
+        dictionary
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.H b/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.H
new file mode 100644
index 00000000000..051299d8755
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineFunctionObject.H
@@ -0,0 +1,55 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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
+
+Typedef
+    Foam::streamLineFunctionObject
+
+Description
+    FunctionObject wrapper around streamLines to allow them to be created via
+    the functions list within controlDict.
+
+SourceFiles
+    streamLineFunctionObject.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef streamLineFunctionObject_H
+#define streamLineFunctionObject_H
+
+#include "streamLine.H"
+#include "OutputFilterFunctionObject.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    typedef OutputFilterFunctionObject<streamLine>
+        streamLineFunctionObject;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C
new file mode 100644
index 00000000000..e4d954ec2cf
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C
@@ -0,0 +1,479 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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 "streamLineParticle.H"
+
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(streamLineParticle, 0);
+    defineParticleTypeNameAndDebug(streamLineParticle, 0);
+    defineTemplateTypeNameAndDebugWithName
+    (
+        IOField<vectorField>,
+        "vectorFieldField",
+        0
+    );
+};
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::vector Foam::streamLineParticle::interpolateFields
+(
+    const streamLineParticle::trackData& td,
+    const point& position,
+    const label cellI
+)
+{
+    if (cellI == -1)
+    {
+        FatalErrorIn("streamLineParticle::interpolateFields(..)")
+            << "Cell:" << cellI << abort(FatalError);
+    }
+
+    sampledScalars_.setSize(td.vsInterp_.size());
+    forAll(td.vsInterp_, scalarI)
+    {
+        sampledScalars_[scalarI].append
+        (
+            td.vsInterp_[scalarI].interpolate
+            (
+                position,
+                cellI
+            )
+        );
+    }
+
+    sampledVectors_.setSize(td.vvInterp_.size());
+    forAll(td.vvInterp_, vectorI)
+    {
+        sampledVectors_[vectorI].append
+        (
+            td.vvInterp_[vectorI].interpolate
+            (
+                position,
+                cellI
+            )
+        );
+    }
+
+    const DynamicList<vector>& U = sampledVectors_[td.UIndex_];
+
+    return U[U.size()-1];
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+//- Construct from components
+Foam::streamLineParticle::streamLineParticle
+(
+    const Cloud<streamLineParticle>& c,
+    const vector& position,
+    const label celli,
+    const label lifeTime
+)
+:
+    Particle<streamLineParticle>(c, position, celli),
+    lifeTime_(lifeTime)
+{}
+
+
+//- Construct from Istream
+Foam::streamLineParticle::streamLineParticle
+(
+    const Cloud<streamLineParticle>& c,
+    Istream& is,
+    bool readFields
+)
+:
+    Particle<streamLineParticle>(c, is, readFields)
+{
+    if (readFields)
+    {
+        //if (is.format() == IOstream::ASCII)
+        List<scalarList> sampledScalars;
+        List<vectorList> sampledVectors;
+
+        is  >> lifeTime_ >> sampledPositions_ >> sampledScalars
+            >> sampledVectors;
+
+        sampledScalars_.setSize(sampledScalars.size());
+        forAll(sampledScalars, i)
+        {
+            sampledScalars_[i].transfer(sampledScalars[i]);
+        }
+        sampledVectors_.setSize(sampledVectors.size());
+        forAll(sampledVectors, i)
+        {
+            sampledVectors_[i].transfer(sampledVectors[i]);
+        }
+    }
+
+    // Check state of Istream
+    is.check
+    (
+        "streamLineParticle::streamLineParticle"
+        "(const Cloud<streamLineParticle>&, Istream&, bool)"
+    );
+}
+
+
+// Construct copy
+Foam::streamLineParticle::streamLineParticle
+(
+    const streamLineParticle& c
+)
+:
+    Particle<streamLineParticle>(c),
+    lifeTime_(c.lifeTime_),
+    sampledPositions_(c.sampledPositions_),
+    sampledScalars_(c.sampledScalars_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::streamLineParticle::move(streamLineParticle::trackData& td)
+{
+    td.switchProcessor = false;
+    td.keepParticle = true;
+
+    scalar deltaT = GREAT;  //cloud().pMesh().time().deltaT().value();
+    scalar tEnd = (1.0 - stepFraction())*deltaT;
+    scalar dtMax = tEnd;
+
+    while
+    (
+        td.keepParticle
+    && !td.switchProcessor
+    && lifeTime_ > 0
+    && tEnd > ROOTVSMALL
+    )
+    {
+        // set the lagrangian time-step
+        scalar dt = min(dtMax, tEnd);
+
+        // Store current position and sampled velocity.
+        --lifeTime_;
+        sampledPositions_.append(position());
+        vector U = interpolateFields(td, position(), cell());
+
+        if (!td.trackForward_)
+        {
+            U = -U;
+        }
+
+        dt *= trackToFace(position()+dt*U, td);
+
+        tEnd -= dt;
+        stepFraction() = 1.0 - tEnd/deltaT;
+    }
+
+    if (!td.keepParticle || lifeTime_ == 0)
+    {
+        if (lifeTime_ == 0)
+        {
+            //Pout<< "Removing stagnant particle:"
+            //    << static_cast<Particle<streamLineParticle> >(*this)
+            //    << " sampled positions:" << sampledPositions_.size()
+            //    << endl;
+            td.keepParticle = false;
+        }
+        else
+        {
+            // Normal exit. Store last position and fields
+            sampledPositions_.append(position());
+            interpolateFields(td, position(), cell());
+
+            //Pout<< "Removing particle:"
+            //    << static_cast<Particle<streamLineParticle> >(*this)
+            //    << " sampled positions:" << sampledPositions_.size()
+            //    << endl;
+        }
+
+        // Transfer particle data into trackData.
+        //td.allPositions_.append(sampledPositions_);
+        td.allPositions_.append(vectorList());
+        vectorList& top = td.allPositions_[td.allPositions_.size()-1];
+        top.transfer(sampledPositions_);
+
+        forAll(sampledScalars_, i)
+        {
+            //td.allScalars_[i].append(sampledScalars_[i]);
+            td.allScalars_[i].append(scalarList());
+            scalarList& top = td.allScalars_[i][td.allScalars_[i].size()-1];
+            top.transfer(sampledScalars_[i]);
+        }
+        forAll(sampledVectors_, i)
+        {
+            //td.allVectors_[i].append(sampledVectors_[i]);
+            td.allVectors_[i].append(vectorList());
+            vectorList& top = td.allVectors_[i][td.allVectors_[i].size()-1];
+            top.transfer(sampledVectors_[i]);
+        }
+    }
+
+    return td.keepParticle;
+}
+
+
+bool Foam::streamLineParticle::hitPatch
+(
+    const polyPatch&,
+    streamLineParticle::trackData& td,
+    const label patchI
+)
+{
+    // Disable generic patch interaction
+    return false;
+}
+
+
+bool Foam::streamLineParticle::hitPatch
+(
+    const polyPatch&,
+    int&,
+    const label
+)
+{
+    // Disable generic patch interaction
+    return false;
+}
+
+
+void Foam::streamLineParticle::hitWedgePatch
+(
+    const wedgePolyPatch& pp,
+    streamLineParticle::trackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+void Foam::streamLineParticle::hitWedgePatch
+(
+    const wedgePolyPatch&,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::hitSymmetryPatch
+(
+    const symmetryPolyPatch& pp,
+    streamLineParticle::trackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+void Foam::streamLineParticle::hitSymmetryPatch
+(
+    const symmetryPolyPatch&,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::hitCyclicPatch
+(
+    const cyclicPolyPatch& pp,
+    streamLineParticle::trackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+void Foam::streamLineParticle::hitCyclicPatch
+(
+    const cyclicPolyPatch&,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::hitProcessorPatch
+(
+    const processorPolyPatch&,
+    streamLineParticle::trackData& td
+)
+{
+    // Switch particle
+    td.switchProcessor = true;
+}
+
+
+void Foam::streamLineParticle::hitProcessorPatch
+(
+    const processorPolyPatch&,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::hitWallPatch
+(
+    const wallPolyPatch& wpp,
+    streamLineParticle::trackData& td
+)
+{
+    // Keep particle
+}
+
+
+void Foam::streamLineParticle::hitWallPatch
+(
+    const wallPolyPatch& wpp,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::hitPatch
+(
+    const polyPatch& wpp,
+    streamLineParticle::trackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+void Foam::streamLineParticle::hitPatch
+(
+    const polyPatch& wpp,
+    int&
+)
+{}
+
+
+void Foam::streamLineParticle::readFields
+(
+    Cloud<streamLineParticle>& c
+)
+{
+    if (!c.size())
+    {
+        return;
+    }
+
+    IOField<label> lifeTime
+    (
+        c.fieldIOobject("lifeTime", IOobject::MUST_READ)
+    );
+    c.checkFieldIOobject(c, lifeTime);
+
+    IOField<pointField> sampledPositions
+    (
+        c.fieldIOobject("sampledPositions", IOobject::MUST_READ)
+    );
+    c.checkFieldIOobject(c, sampledPositions);
+
+//    IOField<pointField> sampleVelocity
+//    (
+//        c.fieldIOobject("sampleVelocity", IOobject::MUST_READ)
+//    );
+//    c.checkFieldIOobject(c, sampleVelocity);
+
+    label i = 0;
+    forAllIter(Cloud<streamLineParticle>, c, iter)
+    {
+        iter().lifeTime_ = lifeTime[i];
+        iter().sampledPositions_.transfer(sampledPositions[i]);
+//        iter().sampleVelocity_.transfer(sampleVelocity[i]);
+        i++;
+    }
+}
+
+
+void Foam::streamLineParticle::writeFields
+(
+    const Cloud<streamLineParticle>& c
+)
+{
+    Particle<streamLineParticle>::writeFields(c);
+
+    label np =  c.size();
+
+    IOField<label> lifeTime
+    (
+        c.fieldIOobject("lifeTime", IOobject::NO_READ),
+        np
+    );
+    IOField<pointField> sampledPositions
+    (
+        c.fieldIOobject("sampledPositions", IOobject::NO_READ),
+        np
+    );
+//    IOField<pointField> sampleVelocity
+//    (
+//        c.fieldIOobject("sampleVelocity", IOobject::NO_READ),
+//        np
+//    );
+
+    label i = 0;
+    forAllConstIter(Cloud<streamLineParticle>, c, iter)
+    {
+        lifeTime[i] = iter().lifeTime_;
+        sampledPositions[i] = iter().sampledPositions_;
+//        sampleVelocity[i] = iter().sampleVelocity_;
+        i++;
+    }
+
+    lifeTime.write();
+    sampledPositions.write();
+//    sampleVelocity.write();
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<(Ostream& os, const streamLineParticle& p)
+{
+    os  << static_cast<const Particle<streamLineParticle>&>(p)
+        << token::SPACE << p.lifeTime_
+        << token::SPACE << p.sampledPositions_
+        << token::SPACE << p.sampledScalars_
+        << token::SPACE << p.sampledVectors_;
+
+    // Check state of Ostream
+    os.check("Ostream& operator<<(Ostream&, const streamLineParticle&)");
+
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H
new file mode 100644
index 00000000000..7740819ddda
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H
@@ -0,0 +1,300 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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
+
+Class
+    Foam::streamLineParticle
+
+Description
+    Particle class that samples fields as it passes through. Used in streamline
+    calculation.
+
+SourceFiles
+    streamLineParticle.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef streamLineParticle_H
+#define streamLineParticle_H
+
+#include "Particle.H"
+#include "autoPtr.H"
+#include "interpolationCellPoint.H"
+#include "vectorList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class streamLineParticleCloud;
+
+/*---------------------------------------------------------------------------*\
+                           Class streamLineParticle Declaration
+\*---------------------------------------------------------------------------*/
+
+class streamLineParticle
+:
+    public Particle<streamLineParticle>
+{
+
+public:
+
+    //- Class used to pass tracking data to the trackToFace function
+    class trackData
+    :
+        public Particle<streamLineParticle>::trackData
+    {
+
+    public:
+
+
+        const PtrList<interpolationCellPoint<scalar> >& vsInterp_;
+        const PtrList<interpolationCellPoint<vector> >& vvInterp_;
+        const label UIndex_;
+        const bool trackForward_;
+
+        DynamicList<vectorList>& allPositions_;
+        List<DynamicList<scalarList> >& allScalars_;
+        List<DynamicList<vectorList> >& allVectors_;
+
+
+        // Constructors
+
+            trackData
+            (
+                Cloud<streamLineParticle>& cloud,
+                const PtrList<interpolationCellPoint<scalar> >& vsInterp,
+                const PtrList<interpolationCellPoint<vector> >& vvInterp,
+                const label UIndex,
+                const bool trackForward,
+                DynamicList<List<point> >& allPositions,
+                List<DynamicList<scalarList> >& allScalars,
+                List<DynamicList<vectorList> >& allVectors
+            )
+            :
+                Particle<streamLineParticle>::trackData(cloud),
+                vsInterp_(vsInterp),
+                vvInterp_(vvInterp),
+                UIndex_(UIndex),
+                trackForward_(trackForward),
+                allPositions_(allPositions),
+                allScalars_(allScalars),
+                allVectors_(allVectors)
+            {}
+    };
+
+
+private:
+
+    // Private data
+
+        //- Lifetime of particle. Particle dies when reaches 0.
+        label lifeTime_;
+
+        //- sampled positions
+        DynamicList<point> sampledPositions_;
+
+        //- sampled scalars
+        List<DynamicList<scalar> > sampledScalars_;
+
+        //- sampled vectors
+        List<DynamicList<vector> > sampledVectors_;
+
+
+    // Private Member Functions
+
+        //- Interpolate all quantities; return interpolated velocity.
+        vector interpolateFields
+        (
+            const streamLineParticle::trackData&,
+            const point&,
+            const label cellI
+        );
+
+
+public:
+
+    //- Run-time type information
+    TypeName("streamLineParticle");
+
+
+
+    // Constructors
+
+        //- Construct from components
+        streamLineParticle
+        (
+            const Cloud<streamLineParticle>& c,
+            const vector& position,
+            const label celli,
+            const label lifeTime
+        );
+
+        //- Construct from Istream
+        streamLineParticle
+        (
+            const Cloud<streamLineParticle>& c,
+            Istream& is,
+            bool readFields = true
+        );
+
+        //- Construct copy
+        streamLineParticle(const streamLineParticle& c);
+
+        //- Construct and return a clone
+        autoPtr<streamLineParticle> clone() const
+        {
+            return autoPtr<streamLineParticle>
+            (
+                new streamLineParticle(*this)
+            );
+        }
+
+
+    // Member Functions
+
+
+
+        // Tracking
+
+            //- Track all particles to their end point
+            bool move(trackData&);
+
+
+            //- Overridable function to handle the particle hitting a patch
+            //  Executed before other patch-hitting functions
+            bool hitPatch
+            (
+                const polyPatch&,
+                streamLineParticle::trackData& td,
+                const label patchI
+            );
+            bool hitPatch
+            (
+                const polyPatch&,
+                int&,
+                const label patchI
+           );
+
+            //- Overridable function to handle the particle hitting a wedge
+            void hitWedgePatch
+            (
+                const wedgePolyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitWedgePatch
+            (
+                const wedgePolyPatch&,
+                int&
+            );
+
+            //- Overridable function to handle the particle hitting a
+            //  symmetryPlane
+            void hitSymmetryPatch
+            (
+                const symmetryPolyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitSymmetryPatch
+            (
+                const symmetryPolyPatch&,
+                int&
+            );
+
+            //- Overridable function to handle the particle hitting a cyclic
+            void hitCyclicPatch
+            (
+                const cyclicPolyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitCyclicPatch
+            (
+                const cyclicPolyPatch&,
+                int&
+            );
+
+            //- Overridable function to handle the particle hitting a
+            //- processorPatch
+            void hitProcessorPatch
+            (
+                const processorPolyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitProcessorPatch
+            (
+                const processorPolyPatch&,
+                int&
+            );
+
+            //- Overridable function to handle the particle hitting a wallPatch
+            void hitWallPatch
+            (
+                const wallPolyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitWallPatch
+            (
+                const wallPolyPatch&,
+                int&
+            );
+
+            //- Overridable function to handle the particle hitting a polyPatch
+            void hitPatch
+            (
+                const polyPatch&,
+                streamLineParticle::trackData& td
+            );
+            void hitPatch
+            (
+                const polyPatch&,
+                int&
+            );
+
+
+        // I-O
+
+            //- Read
+            static void readFields(Cloud<streamLineParticle>&);
+
+            //- Write
+            static void writeFields(const Cloud<streamLineParticle>&);
+
+
+    // Ostream Operator
+
+        friend Ostream& operator<<(Ostream&, const streamLineParticle&);
+
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.C b/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.C
new file mode 100644
index 00000000000..95a92d024ac
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.C
@@ -0,0 +1,79 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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 "streamLineParticleCloud.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTemplateTypeNameAndDebug(Cloud<streamLineParticle>, 0);
+
+};
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::streamLineParticleCloud::streamLineParticleCloud
+(
+    const polyMesh& mesh,
+    const word& cloudName
+)
+:
+    Cloud<streamLineParticle>(mesh, cloudName, false)
+{
+    readFields();
+}
+
+
+Foam::streamLineParticleCloud::streamLineParticleCloud
+(
+    const polyMesh& mesh,
+    const word& cloudName,
+    const IDLList<streamLineParticle>& particles
+)
+:
+    Cloud<streamLineParticle>(mesh, cloudName, particles)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::streamLineParticleCloud::readFields()
+{
+    streamLineParticle::readFields(*this);
+}
+
+
+void Foam::streamLineParticleCloud::writeFields() const
+{
+    streamLineParticle::writeFields(*this);
+}
+
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.H b/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.H
new file mode 100644
index 00000000000..40171fca9d3
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticleCloud.H
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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
+
+Class
+    Foam::streamLineCloud
+
+Description
+    A Cloud of streamLine particles
+
+SourceFiles
+    streamLineCloud.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef streamLineCloud_H
+#define streamLineCloud_H
+
+#include "Cloud.H"
+#include "streamLineParticle.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class streamLineCloud Declaration
+\*---------------------------------------------------------------------------*/
+
+class streamLineParticleCloud
+:
+    public Cloud<streamLineParticle>
+{
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        streamLineParticleCloud(const streamLineParticleCloud&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const streamLineParticleCloud&);
+
+
+public:
+
+    //- Type of parcel the cloud was instantiated for
+    typedef streamLineParticle parcelType;
+
+    // Constructors
+
+        //- Construct given mesh
+        streamLineParticleCloud
+        (
+            const polyMesh&,
+            const word& cloudName = "defaultCloud"
+        );
+
+        //- Construct from mesh, cloud name, and a list of particles
+        streamLineParticleCloud
+        (
+            const polyMesh& mesh,
+            const word& cloudName,
+            const IDLList<streamLineParticle>& particles
+        );
+
+
+    // Member Functions
+
+        //- Read fields
+        virtual void readFields();
+
+        //- Write fields
+        virtual void writeFields() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/sampling/Make/files b/src/sampling/Make/files
index a6d16a0f1ef..34428890699 100644
--- a/src/sampling/Make/files
+++ b/src/sampling/Make/files
@@ -1,16 +1,17 @@
 probes/probes.C
 probes/probesFunctionObject.C
 
-sampledSet/coordSet/coordSet.C
-sampledSet/sampledSet/sampledSet.C
 sampledSet/cloud/cloudSet.C
-sampledSet/face/faceOnlySet.C
+sampledSet/coordSet/coordSet.C
 sampledSet/curve/curveSet.C
-sampledSet/uniform/uniformSet.C
+sampledSet/face/faceOnlySet.C
 sampledSet/midPoint/midPointSet.C
 sampledSet/midPointAndFace/midPointAndFaceSet.C
+sampledSet/sampledSet/sampledSet.C
 sampledSet/sampledSets/sampledSets.C
 sampledSet/sampledSetsFunctionObject/sampledSetsFunctionObject.C
+sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
+sampledSet/uniform/uniformSet.C
 
 setWriters = sampledSet/writers
 
diff --git a/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C b/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
new file mode 100644
index 00000000000..30971292b3f
--- /dev/null
+++ b/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
@@ -0,0 +1,177 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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 "triSurfaceMeshPointSet.H"
+#include "meshSearch.H"
+#include "DynamicList.H"
+#include "polyMesh.H"
+#include "addToRunTimeSelectionTable.H"
+#include "triSurfaceMesh.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(triSurfaceMeshPointSet, 0);
+    addToRunTimeSelectionTable(sampledSet, triSurfaceMeshPointSet, word);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::triSurfaceMeshPointSet::calcSamples
+(
+    DynamicList<point>& samplingPts,
+    DynamicList<label>& samplingCells,
+    DynamicList<label>& samplingFaces,
+    DynamicList<label>& samplingSegments,
+    DynamicList<scalar>& samplingCurveDist
+) const
+{
+    forAll(sampleCoords_, sampleI)
+    {
+        label cellI = searchEngine().findCell(sampleCoords_[sampleI]);
+
+        if (cellI != -1)
+        {
+            samplingPts.append(sampleCoords_[sampleI]);
+            samplingCells.append(cellI);
+            samplingFaces.append(-1);
+            samplingSegments.append(0);
+            samplingCurveDist.append(1.0 * sampleI);
+        }
+    }
+}
+
+
+void Foam::triSurfaceMeshPointSet::genSamples()
+{
+    // Storage for sample points
+    DynamicList<point> samplingPts;
+    DynamicList<label> samplingCells;
+    DynamicList<label> samplingFaces;
+    DynamicList<label> samplingSegments;
+    DynamicList<scalar> samplingCurveDist;
+
+    calcSamples
+    (
+        samplingPts,
+        samplingCells,
+        samplingFaces,
+        samplingSegments,
+        samplingCurveDist
+    );
+
+    samplingPts.shrink();
+    samplingCells.shrink();
+    samplingFaces.shrink();
+    samplingSegments.shrink();
+    samplingCurveDist.shrink();
+
+    setSamples
+    (
+        samplingPts,
+        samplingCells,
+        samplingFaces,
+        samplingSegments,
+        samplingCurveDist
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::triSurfaceMeshPointSet::triSurfaceMeshPointSet
+(
+    const word& name,
+    const polyMesh& mesh,
+    meshSearch& searchEngine,
+    const dictionary& dict
+)
+:
+    sampledSet(name, mesh, searchEngine, dict),
+    surface_(dict.lookup("surface"))
+{
+    // Load surface.
+    if (mesh.time().foundObject<triSurfaceMesh>(surface_))
+    {
+        // Note: should use localPoints() instead of points() but assume
+        // trisurface is compact.
+        sampleCoords_ = mesh.time().lookupObject<triSurfaceMesh>
+        (
+            surface_
+        ).points();
+    }
+    else
+    {
+        sampleCoords_ = triSurfaceMesh
+        (
+            IOobject
+            (
+                surface_,
+                mesh.time().constant(),     // instance
+                "triSurface",               // local
+                mesh.time(),
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE,
+                false
+            )
+        ).points();
+    }
+
+    genSamples();
+
+    if (debug)
+    {
+        write(Info);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::triSurfaceMeshPointSet::~triSurfaceMeshPointSet()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::point Foam::triSurfaceMeshPointSet::getRefPoint(const List<point>& pts)
+ const
+{
+    if (pts.size())
+    {
+        // Use first samplePt as starting point
+        return pts[0];
+    }
+    else
+    {
+        return vector::zero;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.H b/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.H
new file mode 100644
index 00000000000..21102e8ca5b
--- /dev/null
+++ b/src/sampling/sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.H
@@ -0,0 +1,119 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2009 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
+
+Class
+    Foam::triSurfaceMeshPointSet
+
+Description
+    sampleSet from all points of a triSurfaceMesh.
+
+SourceFiles
+    triSurfaceMeshPointSet.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef triSurfaceMeshPointSet_H
+#define triSurfaceMeshPointSet_H
+
+#include "sampledSet.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+
+/*---------------------------------------------------------------------------*\
+                           Class triSurfaceMeshPointSet Declaration
+\*---------------------------------------------------------------------------*/
+
+class triSurfaceMeshPointSet
+:
+    public sampledSet
+{
+    // Private data
+
+        //- Name of triSurfaceMesh
+        const word surface_;
+
+
+        //- Sampling points
+        List<point> sampleCoords_;
+
+
+    // Private Member Functions
+
+        //- Samples all points in sampleCoords.
+        void calcSamples
+        (
+            DynamicList<point>& samplingPts,
+            DynamicList<label>& samplingCells,
+            DynamicList<label>& samplingFaces,
+            DynamicList<label>& samplingSegments,
+            DynamicList<scalar>& samplingCurveDist
+        ) const;
+
+        //- Uses calcSamples to obtain samples. Copies them into *this.
+        void genSamples();
+
+public:
+
+    //- Runtime type information
+    TypeName("triSurfaceMeshPointSet");
+
+
+    // Constructors
+
+        //- Construct from dictionary
+        triSurfaceMeshPointSet
+        (
+            const word& name,
+            const polyMesh& mesh,
+            meshSearch& searchEngine,
+            const dictionary& dict
+        );
+
+
+    // Destructor
+
+        virtual ~triSurfaceMeshPointSet();
+
+
+    // Member Functions
+
+        //- Get reference point
+        virtual point getRefPoint(const List<point>&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict b/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict
index 7bb078570d7..c2f8d5f887d 100644
--- a/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict
+++ b/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict
@@ -45,5 +45,67 @@ timePrecision   6;
 
 runTimeModifiable yes;
 
+functions
+(
+    streamLines
+    {
+        type streamLine;
+
+        // Where to load it from (if not already in solver)
+        functionObjectLibs ("libOpenFOAM.so" "libfieldFunctionObjects.so");
+
+        // Output every
+        outputControl outputTime;
+        //outputInterval 10;
+
+        setFormat vtk;//gnuplot;//xmgr; //raw;  //gnuplot;  //jplot;
+
+        // Velocity field to use for tracking.
+        U U;
+
+        // Tracked forwards (+U) or backwards (-U)
+        trackForward true;
+
+        // Names of fields to sample. Should contain above velocity field!
+        fields (p k U);
+
+        // Cells particles can travel before being removed
+        lifeTime 1000;
+
+        // Cloud name to use
+        cloudName particleTracks;
+
+        // Seeding method. See the sampleSets in sampleDict.
+        seedSampleSet uniform;  //cloud;//triSurfaceMeshPointSet;
+
+        uniformCoeffs
+        {
+            type        uniform;
+            axis        x;  //distance;
+
+            start       (-0.0205 0.001  0.00001);
+            end         (-0.0205 0.0251 0.00001);
+            nPoints     10;
+        }
+
+//        cloudCoeffs
+//        {
+//            type        cloud;
+//            axis        x;
+//
+//            points
+//            (
+//                (-0.0205936225239282 0.0144729199524163 0.00001)
+//            );
+//        }
+
+//        triSurfaceMeshPointSetCoeffs
+//        {
+//            type        triSurfaceMeshPointSet;
+//            axis        distance;
+//            surface     twoTri.stl;
+//        }
+    }
+);
 
 // ************************************************************************* //
-- 
GitLab