diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
index 8166029dbd4335426cbf0b4605a6180c383e174f..02d87225606b2b92ebbe4b19bdbc0c5f047ebeae 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.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  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,6 +35,57 @@ 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))
@@ -57,6 +108,18 @@ Foam::edge Foam::wallBoundedParticle::currentEdge() const
     else
     {
         label faceBasePti = mesh_.tetBasePtIs()[tetFace()];
+        if (faceBasePti == -1)
+        {
+            //FatalErrorInFunction
+            //WarningInFunction
+            //    << "No base point for face " << tetFace() << ", " << f
+            //    << ", produces a decomposition that has a minimum "
+            //    << "volume greater than tolerance."
+            //    //<< abort(FatalError);
+            //    << endl;
+            faceBasePti = 0;
+        }
+
         label diagPti = (faceBasePti+diagEdge_)%f.size();
 
         return edge(f[faceBasePti], f[diagPti]);
@@ -66,11 +129,118 @@ Foam::edge Foam::wallBoundedParticle::currentEdge() const
 
 void Foam::wallBoundedParticle::crossEdgeConnectedFace
 (
-    const edge& meshEdge
+    const label& celli,
+    label& tetFacei,
+    label& tetPti,
+    const edge& e
 )
+{
+    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)
+    {
+        // Loop over all other faces of this cell and
+        // find the one that shares this edge
+
+        label fI = thisCell[cFI];
+
+        if (tetFacei == fI)
+        {
+            continue;
+        }
+
+        const Foam::face& otherFace = pFaces[fI];
+
+        label edDir = otherFace.edgeDirection(e);
+
+        if (edDir == 0)
+        {
+            continue;
+        }
+        else if (f == pFaces[fI])
+        {
+            // This is a necessary condition if using duplicate baffles
+            // (so coincident faces). We need to make sure we don't cross into
+            // the face with the same vertices since we might enter a tracking
+            // loop where it never exits. This test should be cheap
+            // for most meshes so can be left in for 'normal' meshes.
+            continue;
+        }
+        else
+        {
+            //Found edge on other face
+            tetFacei = fI;
+
+            label eIndex = -1;
+
+            if (edDir == 1)
+            {
+                // Edge is in the forward circulation of this face, so
+                // work with the start point of the edge
+                eIndex = findIndex(otherFace, e.start());
+            }
+            else
+            {
+                // edDir == -1, so the edge is in the reverse
+                // circulation of this face, so work with the end
+                // point of the edge
+                eIndex = findIndex(otherFace, e.end());
+            }
+
+            label tetBasePtI = mesh_.tetBasePtIs()[fI];
+
+            if (tetBasePtI == -1)
+            {
+                //FatalErrorInFunction
+                //WarningInFunction
+                //    << "No base point for face " << fI << ", " << f
+                //    << ", produces a decomposition that has a minimum "
+                //    << "volume greater than tolerance."
+                //    //<< abort(FatalError);
+                //    << endl;
+                tetBasePtI = 0;
+            }
+
+            // Find eIndex relative to the base point on new face
+            eIndex -= tetBasePtI;
+
+            if (neg(eIndex))
+            {
+                eIndex = (eIndex + otherFace.size()) % otherFace.size();
+            }
+
+            if (eIndex == 0)
+            {
+                // The point is the base point, so this is first tet
+                // in the face circulation
+                tetPti = 1;
+            }
+            else if (eIndex == otherFace.size() - 1)
+            {
+                // The point is the last before the base point, so
+                // this is the last tet in the face circulation
+                tetPti = otherFace.size() - 2;
+            }
+            else
+            {
+                tetPti = eIndex;
+            }
+
+            break;
+        }
+    }
+}
+
+
+void Foam::wallBoundedParticle::crossEdgeConnectedFace(const edge& meshEdge)
 {
     // Update tetFace, tetPt
-    particle::crossEdgeConnectedFace(cell(), tetFace(), tetPt(), meshEdge);
+    crossEdgeConnectedFace(cell(), tetFace(), tetPt(), meshEdge);
 
     // Update face to be same as tracking one
     face() = tetFace();
@@ -164,14 +334,13 @@ void Foam::wallBoundedParticle::crossDiagonalEdge()
 
 Foam::scalar Foam::wallBoundedParticle::trackFaceTri
 (
+    const vector& n,
     const vector& endPosition,
     label& minEdgei
 )
 {
     // Track p from position to endPosition
     const triFace tri(currentTetIndices().faceTriIs(mesh_));
-    vector n = tri.normal(mesh_.points());
-    n /= mag(n)+VSMALL;
 
     // Check which edge intersects the trajectory.
     // Project trajectory onto triangle
@@ -245,6 +414,7 @@ Foam::scalar Foam::wallBoundedParticle::trackFaceTri
 
 bool Foam::wallBoundedParticle::isTriAlongTrack
 (
+    const vector& n,
     const point& endPosition
 ) const
 {
@@ -267,10 +437,6 @@ bool Foam::wallBoundedParticle::isTriAlongTrack
 
     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);
@@ -382,7 +548,7 @@ Foam::Ostream& Foam::operator<<
 {
     const wallBoundedParticle& p = ip.t_;
 
-    tetPointRef tpr(p.currentTet());
+    tetPointRef tpr(p.currentTetIndices().tet(p.mesh()));
 
     os  << "    " << static_cast<const particle&>(p) << nl
         << "    tet:" << nl;
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
index a82b3f5b64cd0f50e10dd4a3e7849075ae831a9b..654ee8ae5755e4d2400bc8592b6a80ada4178ca7 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.H
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticle.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.
@@ -123,6 +123,20 @@ 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
+        (
+            const label& celli,
+            label& tetFacei,
+            label& tetPti,
+            const edge& e
+        );
+
         //- Cross mesh edge into different face on same cell
         void crossEdgeConnectedFace(const edge& meshEdge);
 
@@ -130,10 +144,10 @@ protected:
         void crossDiagonalEdge();
 
         //- Track through single triangle
-        scalar trackFaceTri(const vector& endPosition, label& minEdgei);
+        scalar trackFaceTri(const vector& n, const vector& endPosition, label&);
 
         //- Is current triangle in the track direction
-        bool isTriAlongTrack(const point& endPosition) const;
+        bool isTriAlongTrack(const vector& n, const point& endPosition) const;
 
 
     // Patch interactions
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
index e4f151fe26d9169aa57e50318231a4ebe7b26534..731c4ad0b3971a58eabda3ba0e0c943e6d64d26a 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedParticleTemplates.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  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -175,7 +175,14 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
             // 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)
+
+            bool posVol = (nbrTi.tet(mesh_).mag() > 0);
+
+            if
+            (
+                posVol
+             == ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
+            )
             {
                 // Change into nbrCell. No need to change tetFace, tetPt.
                 //Pout<< "    crossed from cell:" << celli_
@@ -213,12 +220,22 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
                 << abort(FatalError);
         }
 
+        const triFace tri(currentTetIndices().faceTriIs(mesh_));
+        vector n = tri.normal(mesh_.points());
+        n /= mag(n);
+
         point projectedEndPosition = endPosition;
+
+        const bool posVol = (currentTetIndices().tet(mesh_).mag() > 0);
+
+        if (!posVol)
+        {
+            // Negative tet volume. Track back by setting the end point
+            projectedEndPosition = position() - (endPosition-position());
+        }
+
         // 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;
         }
@@ -234,7 +251,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
         {
             // See if the current triangle has got a point on the
             // correct side of the edge.
-            doTrack = isTriAlongTrack(projectedEndPosition);
+            doTrack = isTriAlongTrack(n, projectedEndPosition);
         }
 
 
@@ -242,7 +259,7 @@ Foam::scalar Foam::wallBoundedParticle::trackToEdge
         {
             // Track across triangle. Return triangle edge crossed.
             label triEdgei = -1;
-            trackFraction = trackFaceTri(projectedEndPosition, triEdgei);
+            trackFraction = trackFaceTri(n, projectedEndPosition, triEdgei);
 
             if (triEdgei == -1)
             {
diff --git a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C
index d626c63fcb9c6d94594e597456b7ee011cef6e7a..ef914b5b3209d4d6b8cf89be194746db2e8bc54e 100644
--- a/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.C
+++ b/src/functionObjects/field/wallBoundedStreamLine/wallBoundedStreamLineParticle.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  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -120,11 +120,12 @@ Foam::vector Foam::wallBoundedStreamLineParticle::sample
     {
         // Stagnant particle. Might as well stop
         lifeTime_ = 0;
+        return vector::zero;
+    }
+    else
+    {
+        return U/magU;
     }
-
-    U /= magU;
-
-    return U;
 }
 
 
@@ -267,16 +268,6 @@ bool Foam::wallBoundedStreamLineParticle::move
             // Force removal
             lifeTime_ = 0;
         }
-
-        if
-        (
-            !td.keepParticle
-        ||  td.switchProcessor
-        ||  lifeTime_ == 0
-        )
-        {
-            break;
-        }
     }