diff --git a/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
new file mode 100644
index 0000000000000000000000000000000000000000..e73f4e72f4884857614ab45c4aca569ce215a760
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
@@ -0,0 +1,659 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+     \\/     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 3 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, see <http://www.gnu.org/licenses/>.
+
+\*----------------------------------------------------------------------------*/
+
+#include "wallBoundedParticle.H"
+#include "vectorFieldIOField.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+//    defineParticleTypeNameAndDebug(wallBoundedParticle, 0);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+//// Check position is inside tet
+//void Foam::wallBoundedParticle::checkInside() const
+//{
+//    const tetIndices ti(currentTetIndices());
+//    const tetPointRef tpr(ti.tet(mesh_));
+//    if (!tpr.inside(position()))
+//    {
+//        FatalErrorIn("wallBoundedParticle::checkInside(..)")
+//            << "Particle:" //<< static_cast<const particle&>(*this)
+//            << info()
+//            << "is not inside " << tpr
+//            << abort(FatalError);
+//    }
+//}
+//
+//
+//void Foam::wallBoundedParticle::checkOnEdge() const
+//{
+//    // Check that edge (as indicated by meshEdgeStart_, diagEdge_) is
+//    // indeed one that contains the position.
+//    const edge e = currentEdge();
+//
+//    linePointRef ln(e.line(mesh_.points()));
+//
+//    pointHit ph(ln.nearestDist(position()));
+//
+//    if (ph.distance() > 1E-6)
+//    {
+//        FatalErrorIn
+//        (
+//            "wallBoundedParticle::checkOnEdge()"
+//        )   << "Problem :"
+//            << " particle:" //<< static_cast<const particle&>(*this)
+//            << info()
+//            << "edge:" << e
+//            << " at:" << ln
+//            << " distance:" << ph.distance()
+//            << abort(FatalError);
+//    }
+//}
+//
+//
+//void Foam::wallBoundedParticle::checkOnTriangle(const point& p)
+//const
+//{
+//    const triFace tri(currentTetIndices().faceTriIs(mesh_));
+//    pointHit ph = tri.nearestPoint(p, mesh_.points());
+//    if (ph.distance() > 1e-9)
+//    {
+//        FatalErrorIn
+//        (
+//            "wallBoundedParticle::checkOnTriangle(const point&)"
+//        )   << "Problem :"
+//            << " particle:" //<< static_cast<const particle&>(*this)
+//            << info()
+//            << "point:" << p
+//            << " distance:" << ph.distance()
+//            << abort(FatalError);
+//    }
+//}
+
+
+// Construct the edge the particle is on (according to meshEdgeStart_,
+// diagEdge_)
+Foam::edge Foam::wallBoundedParticle::currentEdge() const
+{
+    if ((meshEdgeStart_ != -1) == (diagEdge_ != -1))
+    {
+        FatalErrorIn("wallBoundedParticle::currentEdge() const")
+            << "Particle:" //<< static_cast<const particle&>(*this)
+            << info()
+            << "cannot both be on a mesh edge and a face-diagonal edge."
+            << " meshEdgeStart_:" << meshEdgeStart_
+            << " diagEdge_:" << diagEdge_
+            << abort(FatalError);
+    }
+
+    const Foam::face& f = mesh_.faces()[tetFace()];
+
+    if (meshEdgeStart_ != -1)
+    {
+        return edge(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
+    }
+    else
+    {
+        label faceBasePtI = mesh_.tetBasePtIs()[tetFace()];
+        label diagPtI = (faceBasePtI+diagEdge_)%f.size();
+        return edge(f[faceBasePtI], f[diagPtI]);
+    }
+}
+
+
+void Foam::wallBoundedParticle::crossEdgeConnectedFace
+(
+    const edge& meshEdge
+)
+{
+    //label oldFaceI = tetFace();
+
+    // Update tetFace, tetPt
+    particle::crossEdgeConnectedFace(cell(), tetFace(), tetPt(), meshEdge);
+
+    // Update face to be same as tracking one
+    face() = tetFace();
+
+
+    // And adapt meshEdgeStart_.
+    const Foam::face& f = mesh_.faces()[tetFace()];
+    label fp = findIndex(f, meshEdge[0]);
+
+    if (f.nextLabel(fp) == meshEdge[1])
+    {
+        meshEdgeStart_ = fp;
+    }
+    else
+    {
+        label fpMin1 = f.rcIndex(fp);
+
+        if (f[fpMin1] == meshEdge[1])
+        {
+            meshEdgeStart_ = fpMin1;
+        }
+        else
+        {
+            FatalErrorIn
+            (
+                "wallBoundedParticle::crossEdgeConnectedFace"
+                "(const edge&)"
+            )   << "Problem :"
+                << " particle:" //<< static_cast<const particle&>(*this)
+                << info()
+                << "face:" << tetFace()
+                << " verts:" << f
+                << " meshEdge:" << meshEdge
+                << abort(FatalError);
+        }
+    }
+
+    diagEdge_ = -1;
+
+    //Pout<< "    crossed meshEdge "
+    //    << meshEdge.line(mesh().points())
+    //    << " from face:" << oldFaceI
+    //    << " to face:" << tetFace() << endl;
+
+
+    // Check that still on same mesh edge
+
+    const edge eNew(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
+    if (eNew != meshEdge)
+    {
+        FatalErrorIn
+        (
+            "wallBoundedParticle::crossEdgeConnectedFace"
+            "(const edge&)"
+        )   << "Problem" << abort(FatalError);
+    }
+
+
+    // Check that edge (as indicated by meshEdgeStart_) is indeed one that
+    // contains the position.
+    //checkOnEdge();
+}
+
+
+void Foam::wallBoundedParticle::crossDiagonalEdge()
+{
+    if (diagEdge_ == -1)
+    {
+        FatalErrorIn("wallBoundedParticle::crossDiagonalEdge()")
+            << "Particle:" //<< static_cast<const particle&>(*this)
+            << info()
+            << "not on a diagonal edge" << abort(FatalError);
+    }
+    if (meshEdgeStart_ != -1)
+    {
+        FatalErrorIn("wallBoundedParticle::crossDiagonalEdge()")
+            << "Particle:" //<< static_cast<const particle&>(*this)
+            << info()
+            << "meshEdgeStart_:" << meshEdgeStart_ << abort(FatalError);
+    }
+
+    //label oldTetPt = tetPt();
+
+    const Foam::face& f = mesh_.faces()[tetFace()];
+
+    // tetPtI starts from 1, goes up to f.size()-2
+
+    if (tetPt() == diagEdge_)
+    {
+        tetPt() = f.rcIndex(tetPt());
+    }
+    else
+    {
+        label nextTetPt = f.fcIndex(tetPt());
+        if (diagEdge_ == nextTetPt)
+        {
+            tetPt() = nextTetPt;
+        }
+        else
+        {
+            FatalErrorIn("wallBoundedParticle::crossDiagonalEdge()")
+                << "Particle:" //<< static_cast<const particle&>(*this)
+                << info()
+                << "tetPt:" << tetPt()
+                << " diagEdge:" << diagEdge_ << abort(FatalError);
+        }
+    }
+
+    meshEdgeStart_ = -1;
+
+    //Pout<< "    crossed diagonalEdge "
+    //    << currentEdge().line(mesh().points())
+    //    << " from tetPt:" << oldTetPt
+    //    << " to tetPt:" << tetPt() << endl;
+}
+
+
+//- Track through a single triangle.
+// Gets passed tet+triangle the particle is in. Updates position() but nothing
+// else. Returns the triangle edge the particle is now on.
+Foam::scalar Foam::wallBoundedParticle::trackFaceTri
+(
+    const vector& endPosition,
+    label& minEdgeI
+)
+{
+    // Track p from position to endPosition
+    const triFace tri(currentTetIndices().faceTriIs(mesh_));
+    vector n = tri.normal(mesh_.points());
+    //if (mag(n) < sqr(SMALL))
+    //{
+    //    FatalErrorIn("wallBoundedParticle::trackFaceTri(..)")
+    //        << "Small triangle." //<< static_cast<const particle&>(*this)
+    //        << info()
+    //        << "n:" << n
+    //        << abort(FatalError);
+    //}
+    n /= mag(n)+VSMALL;
+
+    // Check which edge intersects the trajectory.
+    // Project trajectory onto triangle
+    minEdgeI = -1;
+    scalar minS = 1;        // end position
+
+    //const point oldPosition(position());
+
+
+    edge currentE(-1, -1);
+    if (meshEdgeStart_ != -1 || diagEdge_ != -1)
+    {
+        currentE = currentEdge();
+    }
+
+    // Determine path along line position+s*d to see where intersections
+    // are.
+
+    forAll(tri, i)
+    {
+        label j = tri.fcIndex(i);
+
+        const point& pt0 = mesh_.points()[tri[i]];
+        const point& pt1 = mesh_.points()[tri[j]];
+
+        if (edge(tri[i], tri[j]) == currentE)
+        {
+            // Do not check particle is on
+            continue;
+        }
+
+        // Outwards pointing normal
+        vector edgeNormal = (pt1-pt0)^n;
+
+        //if (mag(edgeNormal) < SMALL)
+        //{
+        //    FatalErrorIn("wallBoundedParticle::trackFaceTri(..)")
+        //        << "Edge not perpendicular to triangle."
+        //        //<< static_cast<const particle&>(*this)
+        //        << info()
+        //        << "triangle n:" << n
+        //        << " edgeNormal:" << edgeNormal
+        //        << " on tri:" << tri
+        //        << " at:" << pt0
+        //        << " at:" << pt1
+        //        << abort(FatalError);
+        //}
+
+
+        edgeNormal /= mag(edgeNormal)+VSMALL;
+
+        // Determine whether position and end point on either side of edge.
+        scalar sEnd = (endPosition-pt0)&edgeNormal;
+        if (sEnd >= 0)
+        {
+            // endPos is outside triangle. position() should always be
+            // inside.
+            scalar sStart = (position()-pt0)&edgeNormal;
+            if (mag(sEnd-sStart) > VSMALL)
+            {
+                scalar s = sStart/(sStart-sEnd);
+
+                if (s >= 0 && s < minS)
+                {
+                    minS = s;
+                    minEdgeI = i;
+                }
+            }
+        }
+    }
+
+    if (minEdgeI != -1)
+    {
+        position() += minS*(endPosition-position());
+    }
+    else
+    {
+        // Did not hit any edge so tracked to the end position. Set position
+        // without any calculation to avoid truncation errors.
+        position() = endPosition;
+        minS = 1.0;
+    }
+
+    // Project position() back onto plane of triangle
+    const point& triPt = mesh_.points()[tri[0]];
+    position() -= ((position()-triPt)&n)*n;
+
+
+    //Pout<< "    tracked from:" << oldPosition << " to:" << position()
+    //    << " projectedEnd:" << endPosition
+    //    << " at s:" << minS << endl;
+    //if (minEdgeI != -1)
+    //{
+    //    Pout<< "    on edge:" << minEdgeI
+    //        << " on edge:"
+    //        << mesh_.points()[tri[minEdgeI]]
+    //        << mesh_.points()[tri[tri.fcIndex(minEdgeI)]]
+    //        << endl;
+    //}
+
+    return minS;
+}
+
+
+// See if the current triangle has got a point on the
+// correct side of the edge.
+bool Foam::wallBoundedParticle::isTriAlongTrack
+(
+    const point& endPosition
+) const
+{
+    const triFace triVerts(currentTetIndices().faceTriIs(mesh_));
+    const edge currentE = currentEdge();
+
+    //if (debug)
+    {
+        if
+        (
+            currentE[0] == currentE[1]
+         || findIndex(triVerts, currentE[0]) == -1
+         || findIndex(triVerts, currentE[1]) == -1
+        )
+        {
+            FatalErrorIn
+            (
+                "wallBoundedParticle::isTriAlongTrack"
+                "(const point&)"
+            )   << "Edge " << currentE << " not on triangle " << triVerts
+                << info()
+                << abort(FatalError);
+        }
+    }
+
+
+    const vector dir = endPosition-position();
+
+    // Get normal of currentE
+    vector n = triVerts.normal(mesh_.points());
+    n /= mag(n);
+
+    forAll(triVerts, i)
+    {
+        label j = triVerts.fcIndex(i);
+        const point& pt0 = mesh_.points()[triVerts[i]];
+        const point& pt1 = mesh_.points()[triVerts[j]];
+
+        if (edge(triVerts[i], triVerts[j]) == currentE)
+        {
+            vector edgeNormal = (pt1-pt0)^n;
+            return (dir&edgeNormal) < 0;
+        }
+    }
+
+    FatalErrorIn
+    (
+        "wallBoundedParticle::isTriAlongTrack"
+        "(const point&)"
+    )   << "Problem" << abort(FatalError);
+
+    return false;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::wallBoundedParticle::wallBoundedParticle
+(
+    const polyMesh& mesh,
+    const vector& position,
+    const label cellI,
+    const label tetFaceI,
+    const label tetPtI,
+    const label meshEdgeStart,
+    const label diagEdge
+)
+:
+    particle(mesh, position, cellI, tetFaceI, tetPtI),
+    meshEdgeStart_(meshEdgeStart),
+    diagEdge_(diagEdge)
+{
+    //checkInside();
+
+    //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
+    //{
+    //    checkOnEdge();
+    //}
+
+    // Unfortunately have no access to trackdata so cannot check if particle
+    // is on a wallPatch or has an mesh edge set (either of which is
+    // a requirement).
+}
+
+
+Foam::wallBoundedParticle::wallBoundedParticle
+(
+    const polyMesh& mesh,
+    Istream& is,
+    bool readFields
+)
+:
+    particle(mesh, is, readFields)
+{
+    if (readFields)
+    {
+        is  >> meshEdgeStart_ >> diagEdge_;
+    }
+
+    // Check state of Istream
+    is.check
+    (
+        "wallBoundedParticle::wallBoundedParticle"
+        "(const Cloud<wallBoundedParticle>&, Istream&, bool)"
+    );
+}
+
+
+Foam::wallBoundedParticle::wallBoundedParticle
+(
+    const wallBoundedParticle& p
+)
+:
+    particle(p),
+    meshEdgeStart_(p.meshEdgeStart_),
+    diagEdge_(p.diagEdge_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+//void Foam::wallBoundedParticle::readFields
+//(
+//    Cloud<wallBoundedParticle>& c
+//)
+//{
+//    if (!c.size())
+//    {
+//        return;
+//    }
+//
+//    particle::readFields(c);
+//
+//    IOField<label> meshEdgeStart
+//    (
+//        c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
+//    );
+//
+//    IOField<label> diagEdge
+//    (
+//        c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
+//    );
+//    c.checkFieldIOobject(c, diagEdge);
+//
+//    label i = 0;
+//    forAllIter(Cloud<wallBoundedParticle>, c, iter)
+//    {
+//        iter().meshEdgeStart_ = meshEdgeStart[i];
+//        iter().diagEdge_ = diagEdge[i];
+//        i++;
+//    }
+//}
+//
+//
+//void Foam::wallBoundedParticle::writeFields
+//(
+//    const Cloud<wallBoundedParticle>& c
+//)
+//{
+//    particle::writeFields(c);
+//
+//    label np =  c.size();
+//
+//    IOField<label> meshEdgeStart
+//    (
+//        c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
+//        np
+//    );
+//    IOField<label> diagEdge
+//    (
+//        c.fieldIOobject("diagEdge", IOobject::NO_READ),
+//        np
+//    );
+//
+//    label i = 0;
+//    forAllConstIter(Cloud<wallBoundedParticle>, c, iter)
+//    {
+//        meshEdgeStart[i] = iter().meshEdgeStart_;
+//        diagEdge[i] = iter().diagEdge_;
+//        i++;
+//    }
+//
+//    meshEdgeStart.write();
+//    diagEdge.write();
+//}
+
+void Foam::wallBoundedParticle::write(Ostream& os, bool writeFields) const
+{
+    const particle& p = static_cast<const particle&>(*this);
+
+    if (os.format() == IOstream::ASCII)
+    {
+        // Write base particle
+        p.write(os, writeFields);
+
+        if (writeFields)
+        {
+            // Write the additional entries
+            os  << token::SPACE << meshEdgeStart_
+                << token::SPACE << diagEdge_;
+        }
+    }
+    else
+    {
+        // Write base particle
+        p.write(os, writeFields);
+
+        // Write additional entries
+        if (writeFields)
+        {
+            os.write
+            (
+                reinterpret_cast<const char*>(&meshEdgeStart_),
+                sizeof(meshEdgeStart_)
+              + sizeof(diagEdge_)
+            );
+        }
+    }
+
+    // Check state of Ostream
+    os.check("wallBoundedParticle::write(Ostream& os, bool) const");
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const wallBoundedParticle& p
+)
+{
+    // Write all data
+    p.write(os, true);
+
+    return os;
+}
+
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const InfoProxy<wallBoundedParticle>& ip
+)
+{
+    const wallBoundedParticle& p = ip.t_;
+
+    tetPointRef tpr(p.currentTet());
+
+    os  << "    " << static_cast<const particle&>(p) << nl
+        << "    tet:" << nl;
+    os  << "    ";
+    meshTools::writeOBJ(os, tpr.a());
+    os  << "    ";
+    meshTools::writeOBJ(os, tpr.b());
+    os  << "    ";
+    meshTools::writeOBJ(os, tpr.c());
+    os  << "    ";
+    meshTools::writeOBJ(os, tpr.d());
+    os  << "    l 1 2" << nl
+        << "    l 1 3" << nl
+        << "    l 1 4" << nl
+        << "    l 2 3" << nl
+        << "    l 2 4" << nl
+        << "    l 3 4" << nl;
+    os  << "    ";
+    meshTools::writeOBJ(os, p.position());
+
+    return os;
+}
+
+
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
new file mode 100644
index 0000000000000000000000000000000000000000..df93215be1a6d53747591f5c8e162239be34a405
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
@@ -0,0 +1,345 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+     \\/     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 3 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, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::wallBoundedParticle
+
+Description
+    Particle class that tracks on triangles of boundary faces. Use
+    trackToEdge similar to trackToFace on particle.
+
+SourceFiles
+    wallBoundedParticle.C
+    wallBoundedParticleTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef wallBoundedParticle_H
+#define wallBoundedParticle_H
+
+#include "particle.H"
+#include "autoPtr.H"
+#include "InfoProxy.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class wallBoundedParticle Declaration
+\*---------------------------------------------------------------------------*/
+
+class wallBoundedParticle
+:
+    public particle
+{
+
+public:
+
+    //- Class used to pass tracking data to the trackToFace function
+    template<class CloudType>
+    class TrackingData
+    :
+        public particle::TrackingData<CloudType>
+    {
+
+    public:
+
+        const PackedBoolList& isWallPatch_;
+
+        // Constructors
+
+            inline TrackingData
+            (
+                CloudType& cloud,
+                const PackedBoolList& isWallPatch
+            )
+            :
+                particle::TrackingData<CloudType>
+                (
+                    cloud
+                ),
+                isWallPatch_(isWallPatch)
+            {}
+    };
+
+
+protected:
+
+    // Protected data
+
+        //- Particle is on mesh edge:
+        //      const face& f = mesh.faces()[tetFace()]
+        //      const edge e(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
+        //  Note that this real edge
+        //  is also one of the edges of the face-triangle (from
+        //  tetFace()+tetPt()).
+        label meshEdgeStart_;
+
+        //- Particle is on diagonal edge:
+        //      const face& f = mesh.faces()[tetFace()]
+        //      label faceBasePtI = mesh.tetBasePtIs()[faceI];
+        //      label diagPtI = (faceBasePtI+diagEdge_)%f.size();
+        //      const edge e(f[faceBasePtI], f[diagPtI]);
+        label diagEdge_;
+
+
+    // Protected Member Functions
+
+        //- Construct current edge
+        edge currentEdge() const;
+
+        //- Check if inside current tet
+        //void checkInside() const;
+
+        //- Check if on current edge
+        //void checkOnEdge() const;
+
+        //- Check if point on triangle
+        //void checkOnTriangle(const point&) const;
+
+        //- Cross mesh edge into different face on same cell
+        void crossEdgeConnectedFace(const edge& meshEdge);
+
+        //- Cross diagonal edge into different triangle on same face,cell
+        void crossDiagonalEdge();
+
+        //- Track through single triangle
+        scalar trackFaceTri(const vector& endPosition, label& minEdgeI);
+
+        //- Is current triangle in the track direction
+        bool isTriAlongTrack(const point& endPosition) const;
+
+
+    // Patch interactions
+
+        //- Do all patch interaction
+        template<class TrackData>
+        void patchInteraction(TrackData& td, const scalar trackFraction);
+
+        //- Overridable function to handle the particle hitting a patch
+        //  Executed before other patch-hitting functions
+        template<class TrackData>
+        bool hitPatch
+        (
+            const polyPatch&,
+            TrackData& td,
+            const label patchI,
+            const scalar trackFraction,
+            const tetIndices& tetIs
+        );
+
+        //- Overridable function to handle the particle hitting a wedge
+        template<class TrackData>
+        void hitWedgePatch
+        (
+            const wedgePolyPatch&,
+            TrackData& td
+        );
+
+        //- Overridable function to handle the particle hitting a
+        //  symmetryPlane
+        template<class TrackData>
+        void hitSymmetryPatch
+        (
+            const symmetryPolyPatch&,
+            TrackData& td
+        );
+
+        //- Overridable function to handle the particle hitting a cyclic
+        template<class TrackData>
+        void hitCyclicPatch
+        (
+            const cyclicPolyPatch&,
+            TrackData& td
+        );
+
+        //- Overridable function to handle the particle hitting a
+        //- processorPatch
+        template<class TrackData>
+        void hitProcessorPatch
+        (
+            const processorPolyPatch&,
+            TrackData& td
+        );
+
+        //- Overridable function to handle the particle hitting a wallPatch
+        template<class TrackData>
+        void hitWallPatch
+        (
+            const wallPolyPatch&,
+            TrackData& td,
+            const tetIndices&
+        );
+
+        //- Overridable function to handle the particle hitting a polyPatch
+        template<class TrackData>
+        void hitPatch
+        (
+            const polyPatch&,
+            TrackData& td
+        );
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        wallBoundedParticle
+        (
+            const polyMesh& c,
+            const vector& position,
+            const label cellI,
+            const label tetFaceI,
+            const label tetPtI,
+            const label meshEdgeStart,
+            const label diagEdge
+        );
+
+        //- Construct from Istream
+        wallBoundedParticle
+        (
+            const polyMesh& c,
+            Istream& is,
+            bool readFields = true
+        );
+
+        //- Construct copy
+        wallBoundedParticle(const wallBoundedParticle& p);
+
+        //- Construct and return a clone
+        autoPtr<particle> clone() const
+        {
+            return autoPtr<particle>(new wallBoundedParticle(*this));
+        }
+
+        //- Factory class to read-construct particles used for
+        //  parallel transfer
+        class iNew
+        {
+            const polyMesh& mesh_;
+
+        public:
+
+            iNew(const polyMesh& mesh)
+            :
+                mesh_(mesh)
+            {}
+
+            autoPtr<wallBoundedParticle> operator()
+            (
+                Istream& is
+            ) const
+            {
+                return autoPtr<wallBoundedParticle>
+                (
+                    new wallBoundedParticle(mesh_, is, true)
+                );
+            }
+        };
+
+
+    // Member Functions
+
+        // Access
+
+            //- -1 or label of mesh edge
+            inline label meshEdgeStart() const
+            {
+                return meshEdgeStart_;
+            }
+
+            //- -1 or diagonal edge
+            inline label diagEdge() const
+            {
+                return diagEdge_;
+            }
+
+
+        // Track
+
+            //- Equivalent of trackToFace
+            template<class TrackData>
+            scalar trackToEdge
+            (
+                TrackData& td,
+                const vector& endPosition
+            );
+
+
+        // Info
+
+            //- Return info proxy.
+            //  Used to print particle information to a stream
+            inline InfoProxy<wallBoundedParticle> info() const
+            {
+                return *this;
+            }
+
+
+        // I-O
+
+            //- Read
+            template<class CloudType>
+            static void readFields(CloudType&);
+
+            //- Write
+            template<class CloudType>
+            static void writeFields(const CloudType&);
+
+            //- Write the particle data
+            void write(Ostream& os, bool writeFields) const;
+
+
+    // Ostream Operator
+
+        friend Ostream& operator<<
+        (
+            Ostream&,
+            const wallBoundedParticle&
+        );
+
+        friend Ostream& operator<<
+        (
+            Ostream&,
+            const InfoProxy<wallBoundedParticle>&
+        );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "wallBoundedParticleTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..f79d964c7be03dd594752ea04c613a6c099fddd4
--- /dev/null
+++ b/src/postProcessing/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
@@ -0,0 +1,543 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+     \\/     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 3 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, see <http://www.gnu.org/licenses/>.
+
+\*----------------------------------------------------------------------------*/
+
+#include "wallBoundedParticle.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class TrackData>
+void Foam::wallBoundedParticle::patchInteraction
+(
+    TrackData& td,
+    const scalar trackFraction
+)
+{
+//    typedef TrackData::CloudType cloudType;
+    typedef typename TrackData::cloudType::particleType particleType;
+
+    particleType& p = static_cast<particleType&>(*this);
+    p.hitFace(td);
+
+    if (!internalFace(faceI_))
+    {
+        label origFaceI = faceI_;
+        label patchI = patch(faceI_);
+
+        // No action taken for tetPtI_ for tetFaceI_ here, handled by
+        // patch interaction call or later during processor transfer.
+
+
+        // Dummy tet indices. What to do here?
+        tetIndices faceHitTetIs;
+
+        if
+        (
+            !p.hitPatch
+            (
+                mesh_.boundaryMesh()[patchI],
+                td,
+                patchI,
+                trackFraction,
+                faceHitTetIs
+            )
+        )
+        {
+            // Did patch interaction model switch patches?
+            // Note: recalculate meshEdgeStart_, diagEdge_!
+            if (faceI_ != origFaceI)
+            {
+                patchI = patch(faceI_);
+            }
+
+            const polyPatch& patch = mesh_.boundaryMesh()[patchI];
+
+            if (isA<wedgePolyPatch>(patch))
+            {
+                p.hitWedgePatch
+                (
+                    static_cast<const wedgePolyPatch&>(patch), td
+                );
+            }
+            else if (isA<symmetryPolyPatch>(patch))
+            {
+                p.hitSymmetryPatch
+                (
+                    static_cast<const symmetryPolyPatch&>(patch), td
+                );
+            }
+            else if (isA<cyclicPolyPatch>(patch))
+            {
+                p.hitCyclicPatch
+                (
+                    static_cast<const cyclicPolyPatch&>(patch), td
+                );
+            }
+            else if (isA<processorPolyPatch>(patch))
+            {
+                p.hitProcessorPatch
+                (
+                    static_cast<const processorPolyPatch&>(patch), td
+                );
+            }
+            else if (isA<wallPolyPatch>(patch))
+            {
+                p.hitWallPatch
+                (
+                    static_cast<const wallPolyPatch&>(patch), td, faceHitTetIs
+                );
+            }
+            else
+            {
+                p.hitPatch(patch, td);
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+//- Track particle to a given position and returns 1.0 if the
+//  trajectory is completed without hitting a face otherwise
+//  stops at the face and returns the fraction of the trajectory
+//  completed.
+//  on entry 'stepFraction()' should be set to the fraction of the
+//  time-step at which the tracking starts.
+template<class TrackData>
+Foam::scalar Foam::wallBoundedParticle::trackToEdge
+(
+    TrackData& td,
+    const vector& endPosition
+)
+{
+    // Are we on a track face? If not we do a topological walk.
+
+    // Particle:
+    // - cell_              always set
+    // - tetFace_, tetPt_   always set (these identify tet particle is in)
+    // - optionally meshEdgeStart_ or  diagEdge_ set (edge particle is on)
+
+    //checkInside();
+    //checkOnTriangle(position());
+    //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
+    //{
+    //    checkOnEdge();
+    //}
+
+    scalar trackFraction = 0.0;
+
+    if (!td.isWallPatch_[tetFace()])
+    {
+        // Don't track across face. Just walk in cell. Particle is on
+        // mesh edge (as indicated by meshEdgeStart_).
+        const edge meshEdge(currentEdge());
+
+        // If internal face check whether to go to neighbour cell or just
+        // check to the other internal tet on the edge.
+        if (mesh_.isInternalFace(tetFace()))
+        {
+            label nbrCellI =
+            (
+                cellI_ == mesh_.faceOwner()[faceI_]
+              ? mesh_.faceNeighbour()[faceI_]
+              : mesh_.faceOwner()[faceI_]
+            );
+            // Check angle to nbrCell tet. Is it in the direction of the
+            // endposition? I.e. since volume of nbr tet is positive the
+            // tracking direction should be into the tet.
+            tetIndices nbrTi(nbrCellI, tetFaceI_, tetPtI_, mesh_);
+            if ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
+            {
+                // Change into nbrCell. No need to change tetFace, tetPt.
+                //Pout<< "    crossed from cell:" << cellI_
+                //    << " into " << nbrCellI << endl;
+                cellI_ = nbrCellI;
+                patchInteraction(td, trackFraction);
+            }
+            else
+            {
+                // Walk to other face on edge. Changes tetFace, tetPt but not
+                // cell.
+                crossEdgeConnectedFace(meshEdge);
+                patchInteraction(td, trackFraction);
+            }
+        }
+        else
+        {
+            // Walk to other face on edge. This might give loop since
+            // particle should have been removed?
+            crossEdgeConnectedFace(meshEdge);
+            patchInteraction(td, trackFraction);
+        }
+    }
+    else
+    {
+        // We're inside a tet on the wall. Check if the current tet is
+        // the one to cross. If not we cross into the neighbouring triangle.
+
+        if (mesh_.isInternalFace(tetFace()))
+        {
+            FatalErrorIn
+            (
+                "wallBoundedParticle::trackToEdge"
+                "(TrackData&, const vector&)"
+            )   << "Can only track on boundary faces."
+                << " Face:" << tetFace()
+                << " at:" << mesh_.faceCentres()[tetFace()]
+                << abort(FatalError);
+        }
+
+        point projectedEndPosition = endPosition;
+        // Remove normal component
+        {
+            const triFace tri(currentTetIndices().faceTriIs(mesh_));
+            vector n = tri.normal(mesh_.points());
+            n /= mag(n);
+            const point& basePt = mesh_.points()[tri[0]];
+            projectedEndPosition -= ((projectedEndPosition-basePt)&n)*n;
+        }
+
+
+        bool doTrack = false;
+        if (meshEdgeStart_ == -1 && diagEdge_ == -1)
+        {
+            // We're starting and not yet on an edge.
+            doTrack = true;
+        }
+        else
+        {
+            // See if the current triangle has got a point on the
+            // correct side of the edge.
+            doTrack = isTriAlongTrack(projectedEndPosition);
+        }
+
+
+        if (doTrack)
+        {
+            // Track across triangle. Return triangle edge crossed.
+            label triEdgeI = -1;
+            trackFraction = trackFaceTri(projectedEndPosition, triEdgeI);
+
+            if (triEdgeI == -1)
+            {
+                // Reached endpoint
+                //checkInside();
+                diagEdge_ = -1;
+                meshEdgeStart_ = -1;
+                return trackFraction;
+            }
+
+            const tetIndices ti(currentTetIndices());
+
+            // Triangle (faceTriIs) gets constructed from
+            //    f[faceBasePtI_],
+            //    f[facePtAI_],
+            //    f[facePtBI_]
+            //
+            // So edge indices are:
+            // 0 : edge between faceBasePtI_ and facePtAI_
+            // 1 : edge between facePtAI_ and facePtBI_ (is always a real edge)
+            // 2 : edge between facePtBI_ and faceBasePtI_
+
+            const Foam::face& f = mesh_.faces()[ti.face()];
+            const label fp0 = ti.faceBasePt();
+
+            if (triEdgeI == 0)
+            {
+                if (ti.facePtA() == f.fcIndex(fp0))
+                {
+                    //Pout<< "Real edge." << endl;
+                    diagEdge_ = -1;
+                    meshEdgeStart_ = fp0;
+                    //checkOnEdge();
+                    crossEdgeConnectedFace(currentEdge());
+                    patchInteraction(td, trackFraction);
+                }
+                else if (ti.facePtA() == f.rcIndex(fp0))
+                {
+                    //Note: should not happen since boundary face so owner
+                    //Pout<< "Real edge." << endl;
+                    FatalErrorIn("shold not happend") << info()
+                        << abort(FatalError);
+
+                    diagEdge_ = -1;
+                    meshEdgeStart_ = f.rcIndex(fp0);
+                    //checkOnEdge();
+                    crossEdgeConnectedFace(currentEdge());
+                    patchInteraction(td, trackFraction);
+                }
+                else
+                {
+                    // Get index of triangle on other side of edge.
+                    diagEdge_ = ti.facePtA()-fp0;
+                    if (diagEdge_ < 0)
+                    {
+                        diagEdge_ += f.size();
+                    }
+                    meshEdgeStart_ = -1;
+                    //checkOnEdge();
+                    crossDiagonalEdge();
+                }
+            }
+            else if (triEdgeI == 1)
+            {
+                //Pout<< "Real edge." << endl;
+                diagEdge_ = -1;
+                meshEdgeStart_ = ti.facePtA();
+                //checkOnEdge();
+                crossEdgeConnectedFace(currentEdge());
+                patchInteraction(td, trackFraction);
+            }
+            else // if (triEdgeI == 2)
+            {
+                if (ti.facePtB() == f.rcIndex(fp0))
+                {
+                    //Pout<< "Real edge." << endl;
+                    diagEdge_ = -1;
+                    meshEdgeStart_ = ti.facePtB();
+                    //checkOnEdge();
+                    crossEdgeConnectedFace(currentEdge());
+                    patchInteraction(td, trackFraction);
+                }
+                else if (ti.facePtB() == f.fcIndex(fp0))
+                {
+                    //Note: should not happen since boundary face so owner
+                    //Pout<< "Real edge." << endl;
+                    FatalErrorIn("shold not happend") << info()
+                        << abort(FatalError);
+
+                    diagEdge_ = -1;
+                    meshEdgeStart_ = fp0;
+                    //checkOnEdge();
+                    crossEdgeConnectedFace(currentEdge());
+                    patchInteraction(td, trackFraction);
+                }
+                else
+                {
+                    //Pout<< "Triangle edge." << endl;
+                    // Get index of triangle on other side of edge.
+                    diagEdge_ = ti.facePtB()-fp0;
+                    if (diagEdge_ < 0)
+                    {
+                        diagEdge_ += f.size();
+                    }
+                    meshEdgeStart_ = -1;
+                    //checkOnEdge();
+                    crossDiagonalEdge();
+                }
+            }
+        }
+        else
+        {
+            // Current tet is not the right one. Check the neighbour tet.
+
+            if (meshEdgeStart_ != -1)
+            {
+                // Particle is on mesh edge so change into other face on cell
+                crossEdgeConnectedFace(currentEdge());
+                //checkOnEdge();
+                patchInteraction(td, trackFraction);
+            }
+            else
+            {
+                // Particle is on diagonal edge so change into the other
+                // triangle.
+                crossDiagonalEdge();
+                //checkOnEdge();
+            }
+        }
+    }
+
+    //checkInside();
+
+    return trackFraction;
+}
+
+
+template<class TrackData>
+bool Foam::wallBoundedParticle::hitPatch
+(
+    const polyPatch&,
+    TrackData& td,
+    const label patchI,
+    const scalar trackFraction,
+    const tetIndices& tetIs
+)
+{
+    // Disable generic patch interaction
+    return false;
+}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitWedgePatch
+(
+    const wedgePolyPatch& pp,
+    TrackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitSymmetryPatch
+(
+    const symmetryPolyPatch& pp,
+    TrackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitCyclicPatch
+(
+    const cyclicPolyPatch& pp,
+    TrackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitProcessorPatch
+(
+    const processorPolyPatch& pp,
+    TrackData& td
+)
+{
+    // Switch particle
+    td.switchProcessor = true;
+
+    // Adapt edgeStart_ for other side.
+    // E.g. if edgeStart_ is 1 then the edge is between vertex 1 and 2 so
+    // on the other side between 2 and 3 so edgeStart_ should be
+    // f.size()-edgeStart_-1.
+
+    const Foam::face& f = mesh_.faces()[face()];
+
+    if (meshEdgeStart_ != -1)
+    {
+        meshEdgeStart_ = f.size()-meshEdgeStart_-1;
+    }
+    else
+    {
+        // diagEdge_ is relative to faceBasePt
+        diagEdge_ = f.size()-diagEdge_;
+    }
+}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitWallPatch
+(
+    const wallPolyPatch& wpp,
+    TrackData& td,
+    const tetIndices&
+)
+{}
+
+
+template<class TrackData>
+void Foam::wallBoundedParticle::hitPatch
+(
+    const polyPatch& wpp,
+    TrackData& td
+)
+{
+    // Remove particle
+    td.keepParticle = false;
+}
+
+
+template<class CloudType>
+void Foam::wallBoundedParticle::readFields(CloudType& c)
+{
+    if (!c.size())
+    {
+        return;
+    }
+
+    particle::readFields(c);
+
+    IOField<label> meshEdgeStart
+    (
+        c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
+    );
+
+    IOField<label> diagEdge
+    (
+        c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
+    );
+    c.checkFieldIOobject(c, diagEdge);
+
+    label i = 0;
+    forAllIter(typename CloudType, c, iter)
+    {
+        iter().meshEdgeStart_ = meshEdgeStart[i];
+        iter().diagEdge_ = diagEdge[i];
+        i++;
+    }
+}
+
+
+template<class CloudType>
+void Foam::wallBoundedParticle::writeFields(const CloudType& c)
+{
+    particle::writeFields(c);
+
+    label np =  c.size();
+
+    IOField<label> meshEdgeStart
+    (
+        c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
+        np
+    );
+    IOField<label> diagEdge
+    (
+        c.fieldIOobject("diagEdge", IOobject::NO_READ),
+        np
+    );
+
+    label i = 0;
+    forAllConstIter(typename CloudType, c, iter)
+    {
+        meshEdgeStart[i] = iter().meshEdgeStart_;
+        diagEdge[i] = iter().diagEdge_;
+        i++;
+    }
+
+    meshEdgeStart.write();
+    diagEdge.write();
+}
+
+
+// ************************************************************************* //