From c7edc26dbfa77bb27b02956920c7b3cf3333def4 Mon Sep 17 00:00:00 2001
From: Andrew Heather <a.heather@opencfd.co.uk>
Date: Thu, 14 Sep 2017 12:02:03 +0100
Subject: [PATCH] ENH: Reinstated the wallBoundedStreamline function object

Note: performs its own tracking and does not rely on the base
particle::trackXXX functions, and uses a local particle position.

Look to update to barycentric tracking in the future.
---
 .../polyMeshTetDecomposition/tetIndices.H     |  20 +-
 .../polyMeshTetDecomposition/tetIndicesI.H    |  76 +++-
 src/functionObjects/field/Make/files          |   2 -
 .../field/nearWallFields/nearWallFields.C     |   9 +-
 .../wallBoundedParticle.C                     | 137 +++-----
 .../wallBoundedParticle.H                     | 137 +++-----
 .../wallBoundedParticleTemplates.C            | 332 ++++++------------
 .../wallBoundedStreamLine.C                   |  27 +-
 .../wallBoundedStreamLineParticle.C           | 153 +-------
 .../wallBoundedStreamLineParticle.H           |  33 +-
 .../wallBoundedStreamLineParticleTemplates.C  | 150 ++++++++
 src/lagrangian/basic/particle/particle.C      |  36 +-
 src/lagrangian/basic/particle/particle.H      |  21 ++
 src/lagrangian/basic/particle/particleI.H     |  18 +
 .../simpleFoam/motorBike/system/controlDict   |   1 +
 15 files changed, 544 insertions(+), 608 deletions(-)
 create mode 100644 src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticleTemplates.C

diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
index 8ab5d1e2e8..0ddf19294c 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
@@ -142,18 +142,30 @@ public:
             inline label& tetPt();
 
             //- Return the indices corresponding to the tri on the face for
-            //  this tet. The normal of the tri points out of the cell.
-            inline triFace faceTriIs(const polyMesh& mesh) const;
+            //  this tet. The normal of the tri points out of the cell
+            inline triFace faceTriIs
+            (
+                const polyMesh& mesh,
+                const bool warn = true
+            ) const;
+
+            //- Return the local indices corresponding to the tri on the face
+            //  for this tet. The normal of the tri points out of the cell
+            inline triFace triIs
+            (
+                const polyMesh& mesh,
+                const bool warn = true
+            ) const;
 
             //- Return the geometry corresponding to this tet
             inline tetPointRef tet(const polyMesh& mesh) const;
 
             //- Return the geometry corresponding to the tri on the face for
-            //  this tet. The normal of the tri points out of the cell.
+            //  this tet. The normal of the tri points out of the cell
             inline triPointRef faceTri(const polyMesh& mesh) const;
 
             //- Return the geometry corresponding to the tri on the face for
-            //  this tet using the old positions.
+            //  this tet using the old positions
             inline triPointRef oldFaceTri(const polyMesh& mesh) const;
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndicesI.H b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndicesI.H
index 70edef09b1..d09eeeefea 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndicesI.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndicesI.H
@@ -61,7 +61,11 @@ inline Foam::label& Foam::tetIndices::tetPt()
 }
 
 
-inline Foam::triFace Foam::tetIndices::faceTriIs(const polyMesh& mesh) const
+inline Foam::triFace Foam::tetIndices::faceTriIs
+(
+    const polyMesh& mesh,
+    const bool warn
+) const
 {
     const Foam::face& f = mesh.faces()[face()];
 
@@ -70,22 +74,70 @@ inline Foam::triFace Foam::tetIndices::faceTriIs(const polyMesh& mesh) const
     if (faceBasePtI < 0)
     {
         faceBasePtI = 0;
-        if (nWarnings < maxNWarnings)
+
+        if (warn)
         {
-            WarningInFunction
-                << "No base point for face " << face() << ", " << f
-                << ", produces a valid tet decomposition." << endl;
-            ++ nWarnings;
+            if (nWarnings < maxNWarnings)
+            {
+                WarningInFunction
+                    << "No base point for face " << face() << ", " << f
+                    << ", produces a valid tet decomposition." << endl;
+                ++nWarnings;
+            }
+            if (nWarnings == maxNWarnings)
+            {
+                Warning
+                    << "Suppressing any further warnings." << endl;
+                ++nWarnings;
+            }
         }
-        if (nWarnings == maxNWarnings)
+    }
+
+    label facePtI = (tetPti_ + faceBasePtI) % f.size();
+    label faceOtherPtI = f.fcIndex(facePtI);
+
+    if (mesh.faceOwner()[face()] != cell())
+    {
+        Swap(facePtI, faceOtherPtI);
+    }
+
+    return triFace(f[faceBasePtI], f[facePtI], f[faceOtherPtI]);
+}
+
+
+inline Foam::triFace Foam::tetIndices::triIs
+(
+    const polyMesh& mesh,
+    const bool warn
+) const
+{
+    const Foam::face& f = mesh.faces()[face()];
+
+    label faceBasePtI = mesh.tetBasePtIs()[face()];
+
+    if (faceBasePtI < 0)
+    {
+        faceBasePtI = 0;
+
+        if (warn)
         {
-            Warning
-                << "Suppressing any further warnings." << endl;
-            ++ nWarnings;
+            if (nWarnings < maxNWarnings)
+            {
+                WarningInFunction
+                    << "No base point for face " << face() << ", " << f
+                    << ", produces a valid tet decomposition." << endl;
+                ++nWarnings;
+            }
+            if (nWarnings == maxNWarnings)
+            {
+                Warning
+                    << "Suppressing any further warnings." << endl;
+                ++nWarnings;
+            }
         }
     }
 
-    label facePtI = (tetPt() + faceBasePtI) % f.size();
+    label facePtI = (tetPti_ + faceBasePtI) % f.size();
     label faceOtherPtI = f.fcIndex(facePtI);
 
     if (mesh.faceOwner()[face()] != cell())
@@ -93,7 +145,7 @@ inline Foam::triFace Foam::tetIndices::faceTriIs(const polyMesh& mesh) const
         Swap(facePtI, faceOtherPtI);
     }
 
-    return triFace(f[faceBasePtI], f[facePtI], f[faceOtherPtI]);
+    return triFace(faceBasePtI, facePtI, faceOtherPtI);
 }
 
 
diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files
index 3362b2dbca..b44dc3819f 100644
--- a/src/functionObjects/field/Make/files
+++ b/src/functionObjects/field/Make/files
@@ -25,12 +25,10 @@ streamLine/streamLineBase.C
 streamLine/streamLineParticle.C
 streamLine/streamLineParticleCloud.C
 
-/*
 wallBoundedStreamLine/wallBoundedStreamLine.C
 wallBoundedStreamLine/wallBoundedStreamLineParticle.C
 wallBoundedStreamLine/wallBoundedStreamLineParticleCloud.C
 wallBoundedStreamLine/wallBoundedParticle.C
-*/
 
 surfaceInterpolate/surfaceInterpolate.C
 
diff --git a/src/functionObjects/field/nearWallFields/nearWallFields.C b/src/functionObjects/field/nearWallFields/nearWallFields.C
index 681956f30f..03c1aea82b 100644
--- a/src/functionObjects/field/nearWallFields/nearWallFields.C
+++ b/src/functionObjects/field/nearWallFields/nearWallFields.C
@@ -111,11 +111,12 @@ void Foam::functionObjects::nearWallFields::calcAddressing()
                 tetPti = (startInfo.index()+1) % f.size();
 
                 start = startInfo.hitPoint();
+
                 //// Uncomment below to shift slightly in:
-                //tetIndices tet(celli, meshFacei, tetPti, mesh_);
-                //start =
-                //    (1.0-1e-6)*startInfo.hitPoint()
-                //  + 1e-6*tet.tet(mesh_).centre();
+                tetIndices tet(celli, meshFacei, tetPti);
+                start =
+                    (1.0 - 1e-6)*startInfo.hitPoint()
+                  + 1e-6*tet.tet(mesh_).centre();
             }
             else
             {
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
index 6996e1500c..8a21bba822 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
@@ -35,57 +35,6 @@ const std::size_t Foam::wallBoundedParticle::sizeofFields_
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-Foam::tetIndices Foam::wallBoundedParticle::currentTetIndices() const
-{
-    // Replacement for particle::currentTetIndices that avoids error
-    // upon invalid tetBasePtIs
-
-    const faceList& pFaces = mesh_.faces();
-    const labelList& pOwner = mesh_.faceOwner();
-
-    const Foam::face& f = pFaces[tetFacei_];
-
-    bool own = (pOwner[tetFacei_] == celli_);
-
-    label faceBasePtI = mesh_.tetBasePtIs()[tetFacei_];
-    if (faceBasePtI == -1)
-    {
-        //WarningInFunction
-        //    << "No base point for face " << tetFacei_ << ", " << f
-        //    << ", produces a decomposition that has a minimum "
-        //    << "volume greater than tolerance."
-        //    << endl;
-        faceBasePtI = 0;
-    }
-
-    label facePtI = (tetPti_ + faceBasePtI) % f.size();
-    label otherFacePtI = f.fcIndex(facePtI);
-
-    label facePtAI;
-    label facePtBI;
-    if (own)
-    {
-        facePtAI = facePtI;
-        facePtBI = otherFacePtI;
-    }
-    else
-    {
-        facePtAI = otherFacePtI;
-        facePtBI = facePtI;
-    }
-
-    return tetIndices
-    (
-        celli_,
-        tetFacei_,
-        faceBasePtI,
-        facePtAI,
-        facePtBI,
-        tetPti_
-    );
-}
-
-
 Foam::edge Foam::wallBoundedParticle::currentEdge() const
 {
     if ((meshEdgeStart_ != -1) == (diagEdge_ != -1))
@@ -99,7 +48,7 @@ Foam::edge Foam::wallBoundedParticle::currentEdge() const
             << abort(FatalError);
     }
 
-    const Foam::face& f = mesh_.faces()[tetFace()];
+    const Foam::face& f = mesh().faces()[tetFace()];
 
     if (meshEdgeStart_ != -1)
     {
@@ -107,7 +56,7 @@ Foam::edge Foam::wallBoundedParticle::currentEdge() const
     }
     else
     {
-        label faceBasePti = mesh_.tetBasePtIs()[tetFace()];
+        label faceBasePti = mesh().tetBasePtIs()[tetFace()];
         if (faceBasePti == -1)
         {
             //FatalErrorInFunction
@@ -120,7 +69,7 @@ Foam::edge Foam::wallBoundedParticle::currentEdge() const
             faceBasePti = 0;
         }
 
-        label diagPti = (faceBasePti+diagEdge_)%f.size();
+        label diagPti = (faceBasePti + diagEdge_)%f.size();
 
         return edge(f[faceBasePti], f[diagPti]);
     }
@@ -135,26 +84,24 @@ void Foam::wallBoundedParticle::crossEdgeConnectedFace
     const edge& e
 )
 {
-    const faceList& pFaces = mesh_.faces();
-    const cellList& pCells = mesh_.cells();
+    const faceList& pFaces = mesh().faces();
+    const cellList& pCells = mesh().cells();
 
     const Foam::face& f = pFaces[tetFacei];
 
     const Foam::cell& thisCell = pCells[celli];
 
-    forAll(thisCell, cFI)
+    for (const label facei : thisCell)
     {
         // Loop over all other faces of this cell and
         // find the one that shares this edge
 
-        label fI = thisCell[cFI];
-
-        if (tetFacei == fI)
+        if (tetFacei == facei)
         {
             continue;
         }
 
-        const Foam::face& otherFace = pFaces[fI];
+        const Foam::face& otherFace = pFaces[facei];
 
         label edDir = otherFace.edgeDirection(e);
 
@@ -162,7 +109,7 @@ void Foam::wallBoundedParticle::crossEdgeConnectedFace
         {
             continue;
         }
-        else if (f == pFaces[fI])
+        else if (f == pFaces[facei])
         {
             // This is a necessary condition if using duplicate baffles
             // (so coincident faces). We need to make sure we don't cross into
@@ -174,7 +121,7 @@ void Foam::wallBoundedParticle::crossEdgeConnectedFace
         else
         {
             //Found edge on other face
-            tetFacei = fI;
+            tetFacei = facei;
 
             label eIndex = -1;
 
@@ -192,7 +139,7 @@ void Foam::wallBoundedParticle::crossEdgeConnectedFace
                 eIndex = findIndex(otherFace, e.end());
             }
 
-            label tetBasePtI = mesh_.tetBasePtIs()[fI];
+            label tetBasePtI = mesh().tetBasePtIs()[facei];
 
             if (tetBasePtI == -1)
             {
@@ -246,7 +193,7 @@ void Foam::wallBoundedParticle::crossEdgeConnectedFace(const edge& meshEdge)
     face() = tetFace();
 
     // And adapt meshEdgeStart_.
-    const Foam::face& f = mesh_.faces()[tetFace()];
+    const Foam::face& f = mesh().faces()[tetFace()];
     label fp = findIndex(f, meshEdge[0]);
 
     if (f.nextLabel(fp) == meshEdge[1])
@@ -303,7 +250,7 @@ void Foam::wallBoundedParticle::crossDiagonalEdge()
             << "meshEdgeStart_:" << meshEdgeStart_ << abort(FatalError);
     }
 
-    const Foam::face& f = mesh_.faces()[tetFace()];
+    const Foam::face& f = mesh().faces()[tetFace()];
 
     // tetPti starts from 1, goes up to f.size()-2
 
@@ -340,7 +287,7 @@ Foam::scalar Foam::wallBoundedParticle::trackFaceTri
 )
 {
     // Track p from position to endPosition
-    const triFace tri(currentTetIndices().faceTriIs(mesh_));
+    const triFace tri(currentTetIndices().faceTriIs(mesh(), false));
 
     // Check which edge intersects the trajectory.
     // Project trajectory onto triangle
@@ -358,8 +305,8 @@ Foam::scalar Foam::wallBoundedParticle::trackFaceTri
     {
         label j = tri.fcIndex(i);
 
-        const point& pt0 = mesh_.points()[tri[i]];
-        const point& pt1 = mesh_.points()[tri[j]];
+        const point& pt0 = mesh().points()[tri[i]];
+        const point& pt1 = mesh().points()[tri[j]];
 
         if (edge(tri[i], tri[j]) == currentE)
         {
@@ -368,20 +315,20 @@ Foam::scalar Foam::wallBoundedParticle::trackFaceTri
         }
 
         // Outwards pointing normal
-        vector edgeNormal = (pt1-pt0)^n;
+        vector edgeNormal = (pt1 - pt0)^n;
 
-        edgeNormal /= mag(edgeNormal)+VSMALL;
+        edgeNormal /= mag(edgeNormal) + VSMALL;
 
         // Determine whether position and end point on either side of edge.
-        scalar sEnd = (endPosition-pt0)&edgeNormal;
+        scalar sEnd = (endPosition - pt0)&edgeNormal;
         if (sEnd >= 0)
         {
-            // endPos is outside triangle. position() should always be
+            // endPos is outside triangle. localPosition_ should always be
             // inside.
-            scalar sStart = (position()-pt0)&edgeNormal;
-            if (mag(sEnd-sStart) > VSMALL)
+            scalar sStart = (localPosition_ - pt0)&edgeNormal;
+            if (mag(sEnd - sStart) > VSMALL)
             {
-                scalar s = sStart/(sStart-sEnd);
+                scalar s = sStart/(sStart - sEnd);
 
                 if (s >= 0 && s < minS)
                 {
@@ -394,19 +341,19 @@ Foam::scalar Foam::wallBoundedParticle::trackFaceTri
 
     if (minEdgei != -1)
     {
-        position() += minS*(endPosition-position());
+        localPosition_ += minS*(endPosition - localPosition_);
     }
     else
     {
         // Did not hit any edge so tracked to the end position. Set position
         // without any calculation to avoid truncation errors.
-        position() = endPosition;
+        localPosition_ = endPosition;
         minS = 1.0;
     }
 
-    // Project position() back onto plane of triangle
-    const point& triPt = mesh_.points()[tri[0]];
-    position() -= ((position()-triPt)&n)*n;
+    // Project localPosition_ back onto plane of triangle
+    const point& triPt = mesh().points()[tri[0]];
+    localPosition_ -= ((localPosition_ - triPt)&n)*n;
 
     return minS;
 }
@@ -418,7 +365,7 @@ bool Foam::wallBoundedParticle::isTriAlongTrack
     const point& endPosition
 ) const
 {
-    const triFace triVerts(currentTetIndices().faceTriIs(mesh_));
+    const triFace triVerts(currentTetIndices().faceTriIs(mesh(), false));
     const edge currentE = currentEdge();
 
     if
@@ -435,13 +382,13 @@ bool Foam::wallBoundedParticle::isTriAlongTrack
     }
 
 
-    const vector dir = endPosition-position();
+    const vector dir = endPosition - localPosition_;
 
     forAll(triVerts, i)
     {
         label j = triVerts.fcIndex(i);
-        const point& pt0 = mesh_.points()[triVerts[i]];
-        const point& pt1 = mesh_.points()[triVerts[j]];
+        const point& pt0 = mesh().points()[triVerts[i]];
+        const point& pt1 = mesh().points()[triVerts[j]];
 
         if (edge(triVerts[i], triVerts[j]) == currentE)
         {
@@ -462,7 +409,7 @@ bool Foam::wallBoundedParticle::isTriAlongTrack
 Foam::wallBoundedParticle::wallBoundedParticle
 (
     const polyMesh& mesh,
-    const vector& position,
+    const point& position,
     const label celli,
     const label tetFacei,
     const label tetPti,
@@ -470,7 +417,9 @@ Foam::wallBoundedParticle::wallBoundedParticle
     const label diagEdge
 )
 :
-    particle(mesh, position, celli, tetFacei, tetPti),
+//    particle(mesh, barycentric(1, 0, 0, 0), celli, tetFacei, tetPti),
+    particle(mesh, position, celli, tetFacei, tetPti, false),
+    localPosition_(position),
     meshEdgeStart_(meshEdgeStart),
     diagEdge_(diagEdge)
 {}
@@ -490,11 +439,11 @@ Foam::wallBoundedParticle::wallBoundedParticle
     {
         if (is.format() == IOstream::ASCII)
         {
-            is  >> meshEdgeStart_ >> diagEdge_;
+            is  >> localPosition_ >> meshEdgeStart_ >> diagEdge_;
         }
         else
         {
-            is.read(reinterpret_cast<char*>(&meshEdgeStart_), sizeofFields_);
+            is.read(reinterpret_cast<char*>(&localPosition_), sizeofFields_);
         }
     }
 
@@ -508,6 +457,7 @@ Foam::wallBoundedParticle::wallBoundedParticle
 )
 :
     particle(p),
+    localPosition_(p.localPosition_),
     meshEdgeStart_(p.meshEdgeStart_),
     diagEdge_(p.diagEdge_)
 {}
@@ -524,15 +474,16 @@ Foam::Ostream& Foam::operator<<
     if (os.format() == IOstream::ASCII)
     {
         os  << static_cast<const particle&>(p)
-            << token::SPACE << p.meshEdgeStart_
-            << token::SPACE << p.diagEdge_;
+        << token::SPACE << p.localPosition_
+        << token::SPACE << p.meshEdgeStart_
+        << token::SPACE << p.diagEdge_;
     }
     else
     {
         os  << static_cast<const particle&>(p);
         os.write
         (
-            reinterpret_cast<const char*>(&p.meshEdgeStart_),
+            reinterpret_cast<const char*>(&p.localPosition_),
             wallBoundedParticle::sizeofFields_
         );
     }
@@ -568,7 +519,7 @@ Foam::Ostream& Foam::operator<<
         << "    l 2 4" << nl
         << "    l 3 4" << nl;
     os  << "    ";
-    meshTools::writeOBJ(os, p.position());
+    meshTools::writeOBJ(os, p.localPosition_);
 
     return os;
 }
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
index c648fc5c3c..52f006ca1c 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
@@ -71,10 +71,9 @@ class wallBoundedParticle
 public:
 
     //- Class used to pass tracking data to the trackToFace function
-    template<class CloudType>
-    class TrackingData
+    class trackingData
     :
-        public particle::TrackingData<CloudType>
+        public particle::trackingData
     {
 
     public:
@@ -83,16 +82,14 @@ public:
 
         // Constructors
 
-            inline TrackingData
+            template <class TrackCloudType>
+            inline trackingData
             (
-                CloudType& cloud,
+                const TrackCloudType& cloud,
                 const PackedBoolList& isWallPatch
             )
             :
-                particle::TrackingData<CloudType>
-                (
-                    cloud
-                ),
+                particle::trackingData(cloud),
                 isWallPatch_(isWallPatch)
             {}
     };
@@ -102,6 +99,10 @@ protected:
 
     // Protected data
 
+        //- Particle position is updated locally as opposed to via track
+        //  functions of the base Foam::particle class
+        point localPosition_;
+
         //- Particle is on mesh edge:
         //      const face& f = mesh.faces()[tetFace()]
         //      const edge e(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
@@ -123,10 +124,6 @@ protected:
         //- Construct current edge
         edge currentEdge() const;
 
-        //- Replacement for particle::currentTetIndices() that avoids bombing
-        //  out on invalid tet decomposition (tetBasePtIs = -1)
-        tetIndices currentTetIndices() const;
-
         //- Replacement for particle::crossEdgeConnectedFace that avoids bombing
         //  out on invalid tet decomposition (tetBasePtIs = -1)
         void crossEdgeConnectedFace
@@ -150,84 +147,6 @@ protected:
         bool isTriAlongTrack(const vector& n, 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
-        //  symmetry plane
-        template<class TrackData>
-        void hitSymmetryPlanePatch
-        (
-            const symmetryPlanePolyPatch&,
-            TrackData& td
-        );
-
-        //- Overridable function to handle the particle hitting a
-        //  symmetry patch
-        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
@@ -236,7 +155,7 @@ public:
         wallBoundedParticle
         (
             const polyMesh& c,
-            const vector& position,
+            const point& position,
             const label celli,
             const label tetFacei,
             const label tetPti,
@@ -308,14 +227,44 @@ public:
         // Track
 
             //- Equivalent of trackToFace
-            template<class TrackData>
+            template<class TrackCloudType>
             scalar trackToEdge
             (
-                TrackData& td,
+                TrackCloudType& cloud,
+                trackingData& td,
                 const vector& endPosition
             );
 
 
+            // Patch interactions
+
+                //- Do all patch interaction
+                template<class TrackCloudType>
+                void patchInteraction
+                (
+                    TrackCloudType& cloud,
+                    trackingData& td,
+                    const scalar trackFraction
+                );
+
+                //- Overridable function to handle the particle hitting a
+                //- processorPatch
+                template<class TrackCloudType>
+                void hitProcessorPatch
+                (
+                    TrackCloudType& cloud,
+                    trackingData& td
+                );
+
+                //- Overridable function to handle the particle hitting a wallPatch
+                template<class TrackCloudType>
+                void hitWallPatch
+                (
+                    TrackCloudType& cloud,
+                    trackingData& td
+                );
+
+
         // Info
 
             //- Return info proxy.
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
index b2febe5203..23f0a6044c 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
@@ -27,97 +27,44 @@ License
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-template<class TrackData>
+template<class TrackCloudType>
 void Foam::wallBoundedParticle::patchInteraction
 (
-    TrackData& td,
+    TrackCloudType& cloud,
+    trackingData& td,
     const scalar trackFraction
 )
 {
-    typedef typename TrackData::cloudType::particleType particleType;
+    typename TrackCloudType::particleType& p =
+        static_cast<typename TrackCloudType::particleType&>(*this);
+    typename TrackCloudType::particleType::trackingData& ttd =
+        static_cast<typename TrackCloudType::particleType::trackingData&>(td);
 
-    particleType& p = static_cast<particleType&>(*this);
-    p.hitFace(td);
-
-    if (!internalFace(facei_))
+    if (!mesh().isInternalFace(face()))
     {
-        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.
-
+        label origFacei = face();
+        label patchi = patch();
 
-        // 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 (face() != origFacei)
         {
-            // Did patch interaction model switch patches?
-            // Note: recalculate meshEdgeStart_, diagEdge_!
-            if (facei_ != origFacei)
-            {
-                patchi = patch(facei_);
-            }
+            patchi = patch();
+        }
 
-            const polyPatch& patch = mesh_.boundaryMesh()[patchi];
+        const polyPatch& patch = mesh().boundaryMesh()[patchi];
 
-            if (isA<wedgePolyPatch>(patch))
-            {
-                p.hitWedgePatch
-                (
-                    static_cast<const wedgePolyPatch&>(patch), td
-                );
-            }
-            else if (isA<symmetryPlanePolyPatch>(patch))
-            {
-                p.hitSymmetryPlanePatch
-                (
-                    static_cast<const symmetryPlanePolyPatch&>(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);
-            }
+        if (isA<processorPolyPatch>(patch))
+        {
+            p.hitProcessorPatch(cloud, ttd);
+        }
+        else if (isA<wallPolyPatch>(patch))
+        {
+            p.hitWallPatch(cloud, ttd);
+        }
+        else
+        {
+            td.keepParticle = false;
         }
     }
 }
@@ -125,10 +72,11 @@ void Foam::wallBoundedParticle::patchInteraction
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-template<class TrackData>
+template<class TrackCloudType>
 Foam::scalar Foam::wallBoundedParticle::trackToEdge
 (
-    TrackData& td,
+    TrackCloudType& cloud,
+    trackingData& td,
     const vector& endPosition
 )
 {
@@ -147,7 +95,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
     // - optionally meshEdgeStart_ or  diagEdge_ set (edge particle is on)
 
     //checkInside();
-    //checkOnTriangle(position());
+    //checkOnTriangle(localPosition_);
     //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
     //{
     //    checkOnEdge();
@@ -163,39 +111,36 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
 
         // 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()))
+        if (mesh().isInternalFace(tetFace()))
         {
             label nbrCelli =
             (
-                celli_ == mesh_.faceOwner()[facei_]
-              ? mesh_.faceNeighbour()[facei_]
-              : mesh_.faceOwner()[facei_]
+                cell() == mesh().faceOwner()[face()]
+              ? mesh().faceNeighbour()[face()]
+              : mesh().faceOwner()[face()]
             );
             // 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_);
+            tetIndices nbrTi(nbrCelli, tetFace(), tetPt());
 
-            bool posVol = (nbrTi.tet(mesh_).mag() > 0);
+            const bool posVol = (nbrTi.tet(mesh()).mag() > 0);
+            const vector path(endPosition - localPosition_);
 
-            if
-            (
-                posVol
-             == ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
-            )
+            if (posVol == ((nbrTi.faceTri(mesh()).normal() & path) < 0))
             {
                 // Change into nbrCell. No need to change tetFace, tetPt.
                 //Pout<< "    crossed from cell:" << celli_
                 //    << " into " << nbrCelli << endl;
-                celli_ = nbrCelli;
-                patchInteraction(td, trackFraction);
+                cell() = nbrCelli;
+                patchInteraction(cloud, td, trackFraction);
             }
             else
             {
                 // Walk to other face on edge. Changes tetFace, tetPt but not
                 // cell.
                 crossEdgeConnectedFace(meshEdge);
-                patchInteraction(td, trackFraction);
+                patchInteraction(cloud, td, trackFraction);
             }
         }
         else
@@ -203,7 +148,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
             // Walk to other face on edge. This might give loop since
             // particle should have been removed?
             crossEdgeConnectedFace(meshEdge);
-            patchInteraction(td, trackFraction);
+            patchInteraction(cloud, td, trackFraction);
         }
     }
     else
@@ -211,41 +156,42 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
         // 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()))
+        if (mesh().isInternalFace(tetFace()))
         {
             FatalErrorInFunction
                 << "Can only track on boundary faces."
                 << " Face:" << tetFace()
-                << " at:" << mesh_.faceCentres()[tetFace()]
+                << " at:" << mesh().faceCentres()[tetFace()]
                 << abort(FatalError);
         }
 
-        const triFace tri(currentTetIndices().faceTriIs(mesh_));
-        vector n = tri.normal(mesh_.points());
+        const triFace tri(currentTetIndices().faceTriIs(mesh(), false));
+        vector n = tri.normal(mesh().points());
         n /= mag(n);
 
         point projectedEndPosition = endPosition;
 
-        const bool posVol = (currentTetIndices().tet(mesh_).mag() > 0);
+        const bool posVol = (currentTetIndices().tet(mesh()).mag() > 0);
 
         if (!posVol)
         {
             // Negative tet volume. Track back by setting the end point
-            projectedEndPosition = position() - (endPosition-position());
+            projectedEndPosition =
+                localPosition_ - (endPosition - localPosition_);
 
             // Make sure to use a large enough vector to cross the negative
             // face. Bit overkill.
-            const vector d(endPosition-position());
+            const vector d(endPosition - localPosition_);
             const scalar magD(mag(d));
             if (magD > ROOTVSMALL)
             {
                 // Get overall mesh bounding box
-                treeBoundBox meshBb(mesh_.bounds());
+                treeBoundBox meshBb(mesh().bounds());
                 // Extend to make 3D
                 meshBb.inflate(ROOTSMALL);
 
                 // Create vector guaranteed to cross mesh bounds
-                projectedEndPosition = position()-meshBb.mag()*d/magD;
+                projectedEndPosition = localPosition_ - meshBb.mag()*d/magD;
 
                 // Clip to mesh bounds
                 point intPt;
@@ -253,9 +199,9 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
                 bool ok = meshBb.intersects
                 (
                     projectedEndPosition,
-                    position()-projectedEndPosition,
+                    localPosition_ - projectedEndPosition,
                     projectedEndPosition,
-                    position(),
+                    localPosition_,
                     intPt,
                     intPtBits
                 );
@@ -269,8 +215,8 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
 
         // Remove normal component
         {
-            const point& basePt = mesh_.points()[tri[0]];
-            projectedEndPosition -= ((projectedEndPosition-basePt)&n)*n;
+            const point& basePt = mesh().points()[tri[0]];
+            projectedEndPosition -= ((projectedEndPosition - basePt)&n)*n;
         }
 
 
@@ -304,7 +250,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
             }
 
             const tetIndices ti(currentTetIndices());
-
+            const triFace trif(ti.triIs(mesh(), false));
             // Triangle (faceTriIs) gets constructed from
             //    f[faceBasePtI_],
             //    f[facePtAI_],
@@ -315,21 +261,21 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
             // 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();
+            const Foam::face& f = mesh().faces()[ti.face()];
+            const label fp0 = trif[0];
 
             if (triEdgei == 0)
             {
-                if (ti.facePtA() == f.fcIndex(fp0))
+                if (trif[1] == f.fcIndex(fp0))
                 {
                     //Pout<< "Real edge." << endl;
                     diagEdge_ = -1;
                     meshEdgeStart_ = fp0;
                     //checkOnEdge();
                     crossEdgeConnectedFace(currentEdge());
-                    patchInteraction(td, trackFraction);
+                    patchInteraction(cloud, td, trackFraction);
                 }
-                else if (ti.facePtA() == f.rcIndex(fp0))
+                else if (trif[1] == f.rcIndex(fp0))
                 {
                     //Note: should not happen since boundary face so owner
                     //Pout<< "Real edge." << endl;
@@ -340,12 +286,12 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
                     meshEdgeStart_ = f.rcIndex(fp0);
                     //checkOnEdge();
                     crossEdgeConnectedFace(currentEdge());
-                    patchInteraction(td, trackFraction);
+                    patchInteraction(cloud, td, trackFraction);
                 }
                 else
                 {
                     // Get index of triangle on other side of edge.
-                    diagEdge_ = ti.facePtA()-fp0;
+                    diagEdge_ = trif[1] - fp0;
                     if (diagEdge_ < 0)
                     {
                         diagEdge_ += f.size();
@@ -359,40 +305,39 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
             {
                 //Pout<< "Real edge." << endl;
                 diagEdge_ = -1;
-                meshEdgeStart_ = ti.facePtA();
+                meshEdgeStart_ = trif[1];
                 //checkOnEdge();
                 crossEdgeConnectedFace(currentEdge());
-                patchInteraction(td, trackFraction);
+                patchInteraction(cloud, td, trackFraction);
             }
             else // if (triEdgei == 2)
             {
-                if (ti.facePtB() == f.rcIndex(fp0))
+                if (trif[2] == f.rcIndex(fp0))
                 {
                     //Pout<< "Real edge." << endl;
                     diagEdge_ = -1;
-                    meshEdgeStart_ = ti.facePtB();
+                    meshEdgeStart_ = trif[2];
                     //checkOnEdge();
                     crossEdgeConnectedFace(currentEdge());
-                    patchInteraction(td, trackFraction);
+                    patchInteraction(cloud, td, trackFraction);
                 }
-                else if (ti.facePtB() == f.fcIndex(fp0))
+                else if (trif[2] == f.fcIndex(fp0))
                 {
                     //Note: should not happen since boundary face so owner
                     //Pout<< "Real edge." << endl;
-                    FatalErrorInFunction
-                        << abort(FatalError);
+                    FatalErrorInFunction << abort(FatalError);
 
                     diagEdge_ = -1;
                     meshEdgeStart_ = fp0;
                     //checkOnEdge();
                     crossEdgeConnectedFace(currentEdge());
-                    patchInteraction(td, trackFraction);
+                    patchInteraction(cloud, td, trackFraction);
                 }
                 else
                 {
                     //Pout<< "Triangle edge." << endl;
                     // Get index of triangle on other side of edge.
-                    diagEdge_ = ti.facePtB()-fp0;
+                    diagEdge_ = trif[2] - fp0;
                     if (diagEdge_ < 0)
                     {
                         diagEdge_ += f.size();
@@ -412,7 +357,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
                 // Particle is on mesh edge so change into other face on cell
                 crossEdgeConnectedFace(currentEdge());
                 //checkOnEdge();
-                patchInteraction(td, trackFraction);
+                patchInteraction(cloud, td, trackFraction);
             }
             else
             {
@@ -430,74 +375,11 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
 }
 
 
-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::hitSymmetryPlanePatch
-(
-    const symmetryPlanePolyPatch& 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>
+template<class TrackCloudType>
 void Foam::wallBoundedParticle::hitProcessorPatch
 (
-    const processorPolyPatch& pp,
-    TrackData& td
+    TrackCloudType& cloud,
+    trackingData& td
 )
 {
     // Switch particle
@@ -508,44 +390,31 @@ void Foam::wallBoundedParticle::hitProcessorPatch
     // on the other side between 2 and 3 so edgeStart_ should be
     // f.size()-edgeStart_-1.
 
-    const Foam::face& f = mesh_.faces()[face()];
+    const Foam::face& f = mesh().faces()[face()];
 
     if (meshEdgeStart_ != -1)
     {
-        meshEdgeStart_ = f.size()-meshEdgeStart_-1;
+        meshEdgeStart_ = f.size() - meshEdgeStart_-1;
     }
     else
     {
         // diagEdge_ is relative to faceBasePt
-        diagEdge_ = f.size()-diagEdge_;
+        diagEdge_ = f.size() - diagEdge_;
     }
 }
 
 
-template<class TrackData>
+template<class TrackCloudType>
 void Foam::wallBoundedParticle::hitWallPatch
 (
-    const wallPolyPatch& wpp,
-    TrackData& td,
-    const tetIndices&
+    TrackCloudType& cloud,
+    trackingData& td
 )
 {}
 
 
-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)
+template<class TrackCloudType>
+void Foam::wallBoundedParticle::readFields(TrackCloudType& c)
 {
     if (!c.size())
     {
@@ -554,34 +423,47 @@ void Foam::wallBoundedParticle::readFields(CloudType& c)
 
     particle::readFields(c);
 
+    IOField<point> localPosition
+    (
+        c.fieldIOobject("position", IOobject::MUST_READ)
+    );
+    c.checkFieldIOobject(c, localPosition);
+
     IOField<label> meshEdgeStart
     (
         c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
     );
+    c.checkFieldIOobject(c, meshEdgeStart);
 
     IOField<label> diagEdge
     (
-        c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
+        c.fieldIOobject("diagEdge", IOobject::MUST_READ)
     );
     c.checkFieldIOobject(c, diagEdge);
 
     label i = 0;
-    forAllIter(typename CloudType, c, iter)
+    forAllIters(c, iter)
     {
+        iter().localPosition_ = localPosition[i];
         iter().meshEdgeStart_ = meshEdgeStart[i];
         iter().diagEdge_ = diagEdge[i];
-        i++;
+        ++i;
     }
 }
 
 
-template<class CloudType>
-void Foam::wallBoundedParticle::writeFields(const CloudType& c)
+template<class TrackCloudType>
+void Foam::wallBoundedParticle::writeFields(const TrackCloudType& c)
 {
     particle::writeFields(c);
 
     label np =  c.size();
 
+    IOField<point> localPosition
+    (
+        c.fieldIOobject("position", IOobject::NO_READ),
+        np
+    );
     IOField<label> meshEdgeStart
     (
         c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
@@ -594,13 +476,15 @@ void Foam::wallBoundedParticle::writeFields(const CloudType& c)
     );
 
     label i = 0;
-    forAllConstIter(typename CloudType, c, iter)
+    forAllConstIters(c, iter)
     {
+        localPosition[i] = iter().localPosition_;
         meshEdgeStart[i] = iter().meshEdgeStart_;
         diagEdge[i] = iter().diagEdge_;
-        i++;
+        ++i;
     }
 
+    localPosition.write();
     meshEdgeStart.write();
     diagEdge.write();
 }
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLine.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLine.C
index 66ff518d12..ce96d78714 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLine.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLine.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -62,10 +62,8 @@ Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
     label minTetPti = -1;
     scalar minDistSqr = sqr(GREAT);
 
-    forAll(cFaces, cFacei)
+    for (label facei : cFaces)
     {
-        label facei = cFaces[cFacei];
-
         if (isWallPatch[facei])
         {
             const face& f = mesh_.faces()[facei];
@@ -98,8 +96,7 @@ Foam::tetIndices Foam::functionObjects::wallBoundedStreamLine::findNearestTet
     (
         celli,
         minFacei,
-        minTetPti,
-        mesh_
+        minTetPti
     );
 }
 
@@ -226,7 +223,7 @@ void Foam::functionObjects::wallBoundedStreamLine::track()
     const scalar trackTime = Foam::sqrt(GREAT);
 
     // Track
-    particles.move(td, trackTime);
+    particles.move(particles, td, trackTime);
 }
 
 
@@ -265,6 +262,7 @@ bool Foam::functionObjects::wallBoundedStreamLine::read(const dictionary& dict)
         {
             // 1. Positive volume decomposition tets
             faceSet faces(mesh_, "lowQualityTetFaces", mesh_.nFaces()/100+1);
+
             if
             (
                 polyMeshTetDecomposition::checkFaceTets
@@ -287,21 +285,18 @@ bool Foam::functionObjects::wallBoundedStreamLine::read(const dictionary& dict)
 
             // 2. All edges on a cell having two faces
             EdgeMap<label> numFacesPerEdge;
-            forAll(mesh_.cells(), celli)
+            for (const cell& cFaces : mesh_.cells())
             {
-                const cell& cFaces = mesh_.cells()[celli];
-
                 numFacesPerEdge.clear();
 
-                forAll(cFaces, cFacei)
+                for (const label facei : cFaces)
                 {
-                    label facei = cFaces[cFacei];
                     const face& f = mesh_.faces()[facei];
                     forAll(f, fp)
                     {
                         const edge e(f[fp], f.nextLabel(fp));
-                        EdgeMap<label>::iterator eFnd =
-                            numFacesPerEdge.find(e);
+                        EdgeMap<label>::iterator eFnd = numFacesPerEdge.find(e);
+
                         if (eFnd != numFacesPerEdge.end())
                         {
                             eFnd()++;
@@ -313,12 +308,12 @@ bool Foam::functionObjects::wallBoundedStreamLine::read(const dictionary& dict)
                     }
                 }
 
-                forAllConstIter(EdgeMap<label>, numFacesPerEdge, iter)
+                forAllConstIters(numFacesPerEdge, iter)
                 {
                     if (iter() != 2)
                     {
                         FatalErrorInFunction
-                            << "problem cell:" << celli
+                            << "problem cell:" << cFaces
                             << abort(FatalError);
                     }
                 }
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C
index 250e4a21b1..c9ab87bf5f 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C
@@ -42,20 +42,14 @@ Foam::vector Foam::wallBoundedStreamLineParticle::interpolateFields
             << "Cell:" << celli << abort(FatalError);
     }
 
-    const tetIndices ti = currentTetIndices();
-
-    const vector U = td.vvInterp_[td.UIndex_].interpolate
-    (
-        position,
-        ti,     //celli,
-        facei
-    );
+    const vector U =
+        td.vvInterp_[td.UIndex_].interpolate(position, celli, facei);
 
     // Check if at different position
     if
     (
        !sampledPositions_.size()
-     || magSqr(sampledPositions_.last()-position) > Foam::sqr(SMALL)
+     || magSqr(sampledPositions_.last() - position) > Foam::sqr(SMALL)
     )
     {
         // Store the location
@@ -67,12 +61,7 @@ Foam::vector Foam::wallBoundedStreamLineParticle::interpolateFields
         {
             sampledScalars_[scalari].append
             (
-                td.vsInterp_[scalari].interpolate
-                (
-                    position,
-                    ti,     //celli,
-                    facei
-                )
+                td.vsInterp_[scalari].interpolate(position, celli, facei)
             );
         }
 
@@ -87,12 +76,8 @@ Foam::vector Foam::wallBoundedStreamLineParticle::interpolateFields
             }
             else
             {
-                positionU = td.vvInterp_[vectori].interpolate
-                (
-                    position,
-                    ti,     //celli,
-                    facei
-                );
+                positionU =
+                    td.vvInterp_[vectori].interpolate(position, celli, facei);
             }
             sampledVectors_[vectori].append(positionU);
         }
@@ -107,7 +92,7 @@ Foam::vector Foam::wallBoundedStreamLineParticle::sample
     trackingData& td
 )
 {
-    vector U = interpolateFields(td, position(), cell(), tetFace());
+    vector U = interpolateFields(td, localPosition_, cell(), face());
 
     if (!td.trackForward_)
     {
@@ -134,7 +119,7 @@ Foam::vector Foam::wallBoundedStreamLineParticle::sample
 Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
 (
     const polyMesh& mesh,
-    const vector& position,
+    const point& position,
     const label celli,
     const label tetFacei,
     const label tetPti,
@@ -206,128 +191,6 @@ Foam::wallBoundedStreamLineParticle::wallBoundedStreamLineParticle
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-bool Foam::wallBoundedStreamLineParticle::move
-(
-    trackingData& td,
-    const scalar trackTime
-)
-{
-    wallBoundedStreamLineParticle& p = static_cast
-    <
-        wallBoundedStreamLineParticle&
-    >(*this);
-
-
-    // Check position is inside tet
-    //checkInside();
-
-    td.switchProcessor = false;
-    td.keepParticle = true;
-
-    scalar tEnd = (1.0 - stepFraction())*trackTime;
-    scalar maxDt = mesh_.bounds().mag();
-
-    while
-    (
-        td.keepParticle
-    && !td.switchProcessor
-    && lifeTime_ > 0
-    )
-    {
-        // set the lagrangian time-step
-        scalar dt = maxDt;
-
-        --lifeTime_;
-
-        // Get sampled velocity and fields. Store if position changed.
-        vector U = sample(td);
-
-        // !user parameter!
-        if (dt < SMALL)
-        {
-            // Force removal
-            lifeTime_ = 0;
-            break;
-        }
-
-
-        if (td.trackLength_ < GREAT)
-        {
-            dt = td.trackLength_;
-        }
-
-
-        scalar fraction = trackToEdge(td, position() + dt*U);
-        dt *= fraction;
-
-        tEnd -= dt;
-        stepFraction() = 1.0 - tEnd/trackTime;
-
-
-        if (tEnd <= ROOTVSMALL)
-        {
-            // Force removal
-            lifeTime_ = 0;
-        }
-    }
-
-
-    if (!td.keepParticle || lifeTime_ == 0)
-    {
-        if (lifeTime_ == 0)
-        {
-            if (debug)
-            {
-                Pout<< "wallBoundedStreamLineParticle :"
-                    << " Removing stagnant particle:"
-                    << p.position()
-                    << " sampled positions:" << sampledPositions_.size()
-                    << endl;
-            }
-            td.keepParticle = false;
-        }
-        else
-        {
-            // Normal exit. Store last position and fields
-            sample(td);
-
-            if (debug)
-            {
-                Pout<< "wallBoundedStreamLineParticle : Removing particle:"
-                    << p.position()
-                    << " sampled positions:" << sampledPositions_.size()
-                    << endl;
-            }
-        }
-
-        // Transfer particle data into trackingData.
-        {
-            //td.allPositions_.append(sampledPositions_);
-            td.allPositions_.append(vectorList());
-            vectorList& top = td.allPositions_.last();
-            top.transfer(sampledPositions_);
-        }
-
-        forAll(sampledScalars_, i)
-        {
-            //td.allScalars_[i].append(sampledScalars_[i]);
-            td.allScalars_[i].append(scalarList());
-            scalarList& top = td.allScalars_[i].last();
-            top.transfer(sampledScalars_[i]);
-        }
-        forAll(sampledVectors_, i)
-        {
-            //td.allVectors_[i].append(sampledVectors_[i]);
-            td.allVectors_[i].append(vectorList());
-            vectorList& top = td.allVectors_[i].last();
-            top.transfer(sampledVectors_[i]);
-        }
-    }
-
-    return td.keepParticle;
-}
-
-
 void Foam::wallBoundedStreamLineParticle::readFields
 (
     Cloud<wallBoundedStreamLineParticle>& c
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.H b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.H
index 09b0b21229..406468e1cb 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.H
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -58,7 +58,7 @@ Ostream& operator<<(Ostream&, const wallBoundedStreamLineParticle&);
 
 
 /*---------------------------------------------------------------------------*\
-                 Class wallBoundedStreamLineParticle Declaration
+                Class wallBoundedStreamLineParticle Declaration
 \*---------------------------------------------------------------------------*/
 
 class wallBoundedStreamLineParticle
@@ -71,10 +71,7 @@ public:
     //- Class used to pass tracking data to the trackToEdge function
     class trackingData
     :
-        public wallBoundedParticle::TrackingData
-        <
-            Cloud<wallBoundedStreamLineParticle>
-        >
+        public wallBoundedParticle::trackingData
     {
 
     public:
@@ -93,9 +90,10 @@ public:
 
         // Constructors
 
+            template <class TrackCloudType>
             trackingData
             (
-                Cloud<wallBoundedStreamLineParticle>& cloud,
+                TrackCloudType& cloud,
                 const PtrList<interpolation<scalar>>& vsInterp,
                 const PtrList<interpolation<vector>>& vvInterp,
                 const label UIndex,
@@ -108,10 +106,7 @@ public:
                 List<DynamicList<vectorList>>& allVectors
             )
             :
-                wallBoundedParticle::TrackingData
-                <
-                    Cloud<wallBoundedStreamLineParticle>
-                >
+                wallBoundedParticle::trackingData
                 (
                     cloud,
                     isWallPatch
@@ -167,7 +162,7 @@ public:
         wallBoundedStreamLineParticle
         (
             const polyMesh& c,
-            const vector& position,
+            const point& position,
             const label celli,
             const label tetFacei,
             const label tetPti,
@@ -225,7 +220,13 @@ public:
         // Tracking
 
             //- Track all particles to their end point
-            bool move(trackingData&, const scalar trackTime);
+            template<class TrackCloudType>
+            bool move
+            (
+                TrackCloudType& cloud,
+                trackingData& td,
+                const scalar trackTime
+            );
 
 
         // I-O
@@ -256,6 +257,12 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#ifdef NoRepository
+    #include "wallBoundedStreamLineParticleTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 #endif
 
 // ************************************************************************* //
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticleTemplates.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticleTemplates.C
new file mode 100644
index 0000000000..0450866f9f
--- /dev/null
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticleTemplates.C
@@ -0,0 +1,150 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class TrackCloudType>
+bool Foam::wallBoundedStreamLineParticle::move
+(
+    TrackCloudType& cloud,
+    trackingData& td,
+    const scalar trackTime
+)
+{
+    typename TrackCloudType::particleType& p =
+        static_cast<typename TrackCloudType::particleType&>(*this);
+
+
+    // Check position is inside tet
+    //checkInside();
+
+    td.switchProcessor = false;
+    td.keepParticle = true;
+
+    scalar tEnd = (1.0 - stepFraction())*trackTime;
+    scalar maxDt = mesh().bounds().mag();
+
+    while
+    (
+        td.keepParticle
+    && !td.switchProcessor
+    && lifeTime_ > 0
+    )
+    {
+        // set the lagrangian time-step
+        scalar dt = maxDt;
+
+        --lifeTime_;
+
+        // Get sampled velocity and fields. Store if position changed.
+        vector U = p.sample(td);
+
+        // !user parameter!
+        if (dt < SMALL)
+        {
+            // Force removal
+            lifeTime_ = 0;
+            break;
+        }
+
+
+        if (td.trackLength_ < GREAT)
+        {
+            dt = td.trackLength_;
+        }
+
+
+        scalar fraction = trackToEdge(cloud, td, localPosition_ + dt*U);
+        dt *= fraction;
+
+        tEnd -= dt;
+        stepFraction() = 1.0 - tEnd/trackTime;
+
+
+        if (tEnd <= ROOTVSMALL)
+        {
+            // Force removal
+            lifeTime_ = 0;
+        }
+    }
+
+
+    if (!td.keepParticle || lifeTime_ == 0)
+    {
+        if (lifeTime_ == 0)
+        {
+            if (debug)
+            {
+                Pout<< "wallBoundedStreamLineParticle :"
+                    << " Removing stagnant particle:"
+                    << localPosition_
+                    << " sampled positions:" << sampledPositions_.size()
+                    << endl;
+            }
+            td.keepParticle = false;
+        }
+        else
+        {
+            // Normal exit. Store last position and fields
+            sample(td);
+
+            if (debug)
+            {
+                Pout<< "wallBoundedStreamLineParticle : Removing particle:"
+                    << localPosition_
+                    << " sampled positions:" << sampledPositions_.size()
+                    << endl;
+            }
+        }
+
+        // Transfer particle data into trackingData.
+        {
+            //td.allPositions_.append(sampledPositions_);
+            td.allPositions_.append(vectorList());
+            vectorList& top = td.allPositions_.last();
+            top.transfer(sampledPositions_);
+        }
+
+        forAll(sampledScalars_, i)
+        {
+            //td.allScalars_[i].append(sampledScalars_[i]);
+            td.allScalars_[i].append(scalarList());
+            scalarList& top = td.allScalars_[i].last();
+            top.transfer(sampledScalars_[i]);
+        }
+        forAll(sampledVectors_, i)
+        {
+            //td.allVectors_[i].append(sampledVectors_[i]);
+            td.allVectors_[i].append(vectorList());
+            vectorList& top = td.allVectors_[i].last();
+            top.transfer(sampledVectors_[i]);
+        }
+    }
+
+    return td.keepParticle;
+}
+
+
+// ************************************************************************* //
diff --git a/src/lagrangian/basic/particle/particle.C b/src/lagrangian/basic/particle/particle.C
index 5561ac9f15..e52ab0ba19 100644
--- a/src/lagrangian/basic/particle/particle.C
+++ b/src/lagrangian/basic/particle/particle.C
@@ -588,7 +588,7 @@ Foam::particle::particle
 )
 :
     mesh_(mesh),
-    coordinates_(- VGREAT, - VGREAT, - VGREAT, - VGREAT),
+    coordinates_(-VGREAT, -VGREAT, -VGREAT, -VGREAT),
     celli_(celli),
     tetFacei_(-1),
     tetPti_(-1),
@@ -608,6 +608,40 @@ Foam::particle::particle
 }
 
 
+Foam::particle::particle
+(
+    const polyMesh& mesh,
+    const vector& position,
+    const label celli,
+    const label tetFacei,
+    const label tetPti,
+    bool doLocate
+)
+:
+    mesh_(mesh),
+    coordinates_(-VGREAT, -VGREAT, -VGREAT, -VGREAT),
+    celli_(celli),
+    tetFacei_(tetFacei),
+    tetPti_(tetPti),
+    facei_(-1),
+    stepFraction_(0.0),
+    origProc_(Pstream::myProcNo()),
+    origId_(getNewParticleID())
+{
+    if (doLocate)
+    {
+        locate
+        (
+            position,
+            nullptr,
+            celli,
+            false,
+            "Particle initialised with a location outside of the mesh."
+        );
+    }
+}
+
+
 Foam::particle::particle(const particle& p)
 :
     mesh_(p.mesh_),
diff --git a/src/lagrangian/basic/particle/particle.H b/src/lagrangian/basic/particle/particle.H
index 9ddea7bbd7..21a8536b05 100644
--- a/src/lagrangian/basic/particle/particle.H
+++ b/src/lagrangian/basic/particle/particle.H
@@ -370,6 +370,18 @@ public:
             const label celli
         );
 
+        //- Construct from components
+        particle
+        (
+            const polyMesh& mesh,
+            const vector& position,
+            const label celli,
+            const label tetFacei,
+            const label tetPti,
+            const bool doLocate = true
+        );
+
+
         //- Construct from Istream
         particle
         (
@@ -438,12 +450,21 @@ public:
             //- Return current tet face particle is in
             inline label tetFace() const;
 
+            //- Return current tet face particle is in for manipulation
+            inline label& tetFace();
+
             //- Return current tet face particle is in
             inline label tetPt() const;
 
+            //- Return current tet face particle is in for manipulation
+            inline label& tetPt();
+
             //- Return current face particle is on otherwise -1
             inline label face() const;
 
+            //- Return current face particle is on for manipulation
+            inline label& face();
+
             //- Return the fraction of time-step completed
             inline scalar stepFraction() const;
 
diff --git a/src/lagrangian/basic/particle/particleI.H b/src/lagrangian/basic/particle/particleI.H
index d8116933ca..8c223fd876 100644
--- a/src/lagrangian/basic/particle/particleI.H
+++ b/src/lagrangian/basic/particle/particleI.H
@@ -72,18 +72,36 @@ inline Foam::label Foam::particle::tetFace() const
 }
 
 
+inline Foam::label& Foam::particle::tetFace()
+{
+    return tetFacei_;
+}
+
+
 inline Foam::label Foam::particle::tetPt() const
 {
     return tetPti_;
 }
 
 
+inline Foam::label& Foam::particle::tetPt()
+{
+    return tetPti_;
+}
+
+
 inline Foam::label Foam::particle::face() const
 {
     return facei_;
 }
 
 
+inline Foam::label& Foam::particle::face()
+{
+    return facei_;
+}
+
+
 inline Foam::scalar Foam::particle::stepFraction() const
 {
     return stepFraction_;
diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
index c767564e02..a626f4d688 100644
--- a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
+++ b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
@@ -47,6 +47,7 @@ runTimeModifiable true;
 functions
 {
     #include "streamLines"
+    #include "wallBoundedStreamLines"
     #include "cuttingPlane"
     #include "forceCoeffs"
     #include "ensightWrite"
-- 
GitLab