diff --git a/src/finiteVolume/Make/files b/src/finiteVolume/Make/files
index 0ff3e598d92c04f3f82ab75041d9cffa49df23a4..f8aac2551b9f9565a3f80789b8d2ab1fcf526a15 100644
--- a/src/finiteVolume/Make/files
+++ b/src/finiteVolume/Make/files
@@ -352,6 +352,7 @@ general = cfdTools/general
 $(general)/findRefCell/findRefCell.C
 $(general)/adjustPhi/adjustPhi.C
 $(general)/bound/bound.C
+$(general)/pimpleControl/pimpleControl.C
 
 porousMedia = $(general)/porousMedia
 $(porousMedia)/porousZone.C
diff --git a/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.C b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.C
new file mode 100644
index 0000000000000000000000000000000000000000..77ae648eac1d73ae7f7868f91d1eee65690dcbca
--- /dev/null
+++ b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.C
@@ -0,0 +1,191 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2011 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 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 "pimpleControl.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(pimpleControl, 0);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::pimpleControl::applyToField(const word& fieldName) const
+{
+    forAll(residualControl_, i)
+    {
+        if (residualControl_[i].name.match(fieldName))
+        {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+
+bool Foam::pimpleControl::criteriaSatisfied()
+{
+    if ((corr_ == 0) || residualControl_.empty() || finalIter())
+    {
+        return false;
+    }
+
+    bool firstIter = corr_ == 1;
+
+    bool achieved = true;
+    const dictionary& solverDict = mesh_.solverPerformanceDict();
+
+    forAllConstIter(dictionary, solverDict, iter)
+    {
+        const word& variableName = iter().keyword();
+        label fieldI = applyToField(variableName);
+        if (fieldI != -1)
+        {
+            const List<lduMatrix::solverPerformance> sp(iter().stream());
+            const scalar residual = sp.last().initialResidual();
+
+            if (firstIter)
+            {
+                residualControl_[fieldI].initialResidual =
+                    sp.first().initialResidual();
+            }
+
+            bool absCheck = residual < residualControl_[fieldI].absTol;
+
+            bool relCheck = false;
+
+            scalar relative = 0.0;
+            if (!firstIter)
+            {
+                scalar iniRes =
+                    residualControl_[fieldI].initialResidual
+                  + ROOTVSMALL;
+
+                relative = residual/iniRes;
+
+                relCheck = relative < residualControl_[fieldI].relTol;
+            }
+
+            achieved = achieved && (absCheck || relCheck);
+
+            if (debug)
+            {
+                Info<< "PIMPLE loop statistics:" << endl;
+
+                Info<< "    " << variableName << " iter " << corr_
+                    << ": ini res = "
+                    << residualControl_[fieldI].initialResidual
+                    << ", abs tol = " << residual
+                    << " (" << residualControl_[fieldI].absTol << ")"
+                    << ", rel tol = " << relative
+                    << " (" << residualControl_[fieldI].relTol << ")"
+                    << endl;
+            }
+        }
+    }
+
+    return achieved;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::pimpleControl::pimpleControl(fvMesh& mesh)
+:
+    mesh_(mesh),
+    nCorr_(0),
+    corr_(0),
+    residualControl_()
+{
+    read();
+
+    if (residualControl_.size() > 0)
+    {
+        Info<< "PIMPLE: max iterations = " << nCorr_ << endl;
+        forAll(residualControl_, i)
+        {
+            Info<< "    field " << residualControl_[i].name << token::TAB
+                << ": relTol " << residualControl_[i].relTol
+                << ", absTol " << residualControl_[i].absTol
+                << nl;
+        }
+        Info<< endl;
+    }
+    else
+    {
+        Info<< "No PIMPLE residual control data found. "
+            << "Calculations will employ a fixed number of corrector loops"
+            << nl << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::pimpleControl::~pimpleControl()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::pimpleControl::read()
+{
+    const dictionary& dict = mesh_.solutionDict().subDict("PIMPLE");
+    nCorr_ = dict.lookupOrDefault<label>("nOuterCorrectors", 1);
+    const dictionary residualDict(dict.subOrEmptyDict("residualControl"));
+    DynamicList<fieldData> data(residualDict.toc().size());
+    wordHashSet fieldNames;
+    forAllConstIter(dictionary, residualDict, iter)
+    {
+        if (fieldNames.insert(iter().keyword()))
+        {
+            fieldData fd;
+            fd.name = iter().keyword().c_str();
+            if (iter().isDict())
+            {
+                const dictionary& fieldDict(iter().dict());
+                fd.relTol = readScalar(fieldDict.lookup("relTol"));
+                fd.absTol = readScalar(fieldDict.lookup("absTol"));
+                fd.initialResidual = 0.0;
+                data.append(fd);
+            }
+            else
+            {
+                FatalErrorIn("bool Foam::pimpleControl::read()")
+                    << "Residual data for " << iter().keyword()
+                    << " must be specified as a dictionary";
+            }
+        }
+    }
+
+    residualControl_.transfer(data);
+}
+
+
+// ************************************************************************* //
diff --git a/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.H b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.H
new file mode 100644
index 0000000000000000000000000000000000000000..2538658d880d5094876c83dc3a0291215a4755a8
--- /dev/null
+++ b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControl.H
@@ -0,0 +1,141 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2011 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 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::pimpleControl
+
+Description
+    PIMPLE control class to supply convergence information/checks for
+    the PIMPLE loop.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef pimpleControl_H
+#define pimpleControl_H
+
+#include "fvMesh.H"
+//#include "className.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class pimpleControl Declaration
+\*---------------------------------------------------------------------------*/
+
+class pimpleControl
+{
+    struct fieldData
+    {
+        wordRe name;
+        scalar relTol;
+        scalar absTol;
+        scalar initialResidual;
+    };
+
+
+    // Private data
+
+        //- Reference to the mesh database
+        fvMesh& mesh_;
+
+        //- Maximum number of PIMPLE correctors
+        int nCorr_;
+
+        //- Current PIMPLE corrector
+        int corr_;
+
+        //- List of residual data per field
+        List<fieldData> residualControl_;
+
+
+    // Private Member Functions
+
+        //- Return index of field in residualControl_ if present
+        label applyToField(const word& fieldName) const;
+
+        //- Return true if all convergence checks are satified
+        bool criteriaSatisfied();
+
+        //- Disallow default bitwise copy construct
+        pimpleControl(const pimpleControl&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const pimpleControl&);
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("pimpleControl");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        pimpleControl(fvMesh& mesh);
+
+
+    //- Destructor
+    virtual ~pimpleControl();
+
+
+    // Member Functions
+
+        //- Read constrols from fvSolution dictionary
+        void read();
+
+        //- Loop start
+        bool start();
+
+        //- Loop loop
+        bool loop();
+
+        //- Helper function to identify final iteration
+        bool finalIter() const;
+
+
+    // Member Operators
+
+        void operator++(int);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "pimpleControlI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControlI.H b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControlI.H
new file mode 100644
index 0000000000000000000000000000000000000000..bef9dd016403e3ce5f077667242c95f0d7ab085a
--- /dev/null
+++ b/src/finiteVolume/cfdTools/general/pimpleControl/pimpleControlI.H
@@ -0,0 +1,82 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2011 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 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  * * * * * * * * * * * * * //
+
+inline bool Foam::pimpleControl::start()
+{
+    corr_ = 0;
+
+    return true;
+}
+
+
+inline bool Foam::pimpleControl::loop()
+{
+    if (criteriaSatisfied())
+    {
+        Info<< "PIMPLE loop converged in " << corr_ << " iterations" << endl;
+        return false;
+    }
+    else
+    {
+        if (finalIter())
+        {
+            mesh_.data::add("finalIteration", true);
+        }
+
+        if (corr_ < nCorr_)
+        {
+            Info<< "PIMPLE iteration " << corr_ + 1 << endl;
+            return true;
+        }
+        else
+        {
+            Info<< "PIMPLE loop not converged within " << nCorr_
+                << " iterations" << endl;
+            return false;
+        }
+    }
+}
+
+
+inline bool Foam::pimpleControl::finalIter() const
+{
+    return corr_ == nCorr_-1;
+}
+
+
+inline void Foam::pimpleControl::operator++(int)
+{
+    if (finalIter())
+    {
+        mesh_.data::remove("finalIteration");
+    }
+
+    corr_++;
+}
+
+
+// ************************************************************************* //