diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/UEqn.H b/applications/solvers/compressible/rhoPorousSimpleFoam/UEqn.H
index 00a6f39bf468159df59e8de6983c4452be65c5ef..4150cd7503f41d781ce066ae50ee9acfd915e00c 100644
--- a/applications/solvers/compressible/rhoPorousSimpleFoam/UEqn.H
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/UEqn.H
@@ -35,7 +35,12 @@
     {
         pZones.addResistance(UEqn());
 
-        solve(UEqn() == -fvc::grad(p));
+        eqnResidual = solve
+        (
+            UEqn() == -fvc::grad(p)
+        ). initialResidual();
+
+        maxResidual = max(eqnResidual, maxResidual);
 
         trAU = 1.0/UEqn().A();
         trAU().rename("rAU");
diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/convergenceCheck.H b/applications/solvers/compressible/rhoPorousSimpleFoam/convergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..8958063193af348a058fd8f3baecb2547c00da3c
--- /dev/null
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/convergenceCheck.H
@@ -0,0 +1,9 @@
+// check convergence
+
+if (maxResidual < convergenceCriterion)
+{
+    Info<< "reached convergence criterion: " << convergenceCriterion << endl;
+    runTime.writeAndEnd();
+    Info<< "latestTime = " << runTime.timeName() << endl;
+}
+
diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/hEqn.H b/applications/solvers/compressible/rhoPorousSimpleFoam/hEqn.H
index e5d60199fe7638498a04749a6e3d9d9f38384de3..8eb03f95eb46b687a79f9f68c09152bbd269224a 100644
--- a/applications/solvers/compressible/rhoPorousSimpleFoam/hEqn.H
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/hEqn.H
@@ -11,7 +11,8 @@
 
     hEqn.relax();
 
-    hEqn.solve();
+    eqnResidual = hEqn.solve().initialResidual();
+    maxResidual = max(eqnResidual, maxResidual);
 
     thermo->correct();
 }
diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/initConvergenceCheck.H b/applications/solvers/compressible/rhoPorousSimpleFoam/initConvergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..b56197f22a50cfd07b04fc14d40b9a5454da8c5b
--- /dev/null
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/initConvergenceCheck.H
@@ -0,0 +1,7 @@
+// initialize values for convergence checks
+
+    scalar eqnResidual = 1, maxResidual = 0;
+    scalar convergenceCriterion = 0;
+
+    simple.readIfPresent("convergence", convergenceCriterion);
+
diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/pEqn.H b/applications/solvers/compressible/rhoPorousSimpleFoam/pEqn.H
index 558a57c86bed684ed2c4d46e194c746a485d2509..ae41da9e36fd7af8dd172b163b16dd8829a93b8b 100644
--- a/applications/solvers/compressible/rhoPorousSimpleFoam/pEqn.H
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/pEqn.H
@@ -26,7 +26,16 @@ for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
     }
 
     tpEqn().setReference(pRefCell, pRefValue);
-    tpEqn().solve();
+    // retain the residual from the first iteration
+    if (nonOrth == 0)
+    {
+        eqnResidual = tpEqn().solve().initialResidual();
+        maxResidual = max(eqnResidual, maxResidual);
+    }
+    else
+    {
+        tpEqn().solve();
+    }
 
     if (nonOrth == nNonOrthCorr)
     {
diff --git a/applications/solvers/compressible/rhoPorousSimpleFoam/rhoPorousSimpleFoam.C b/applications/solvers/compressible/rhoPorousSimpleFoam/rhoPorousSimpleFoam.C
index 4042dc43f140d34a3bc7aaf49b1293a2409f5cf1..cba0c2dce171dcef9122ced75c5c9c3e1ad35c10 100644
--- a/applications/solvers/compressible/rhoPorousSimpleFoam/rhoPorousSimpleFoam.C
+++ b/applications/solvers/compressible/rhoPorousSimpleFoam/rhoPorousSimpleFoam.C
@@ -56,6 +56,7 @@ int main(int argc, char *argv[])
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
 #       include "readSIMPLEControls.H"
+#       include "initConvergenceCheck.H"
 
         p.storePrevIter();
         rho.storePrevIter();
@@ -70,10 +71,11 @@ int main(int argc, char *argv[])
         turbulence->correct();
 
         runTime.write();
-
         Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
             << "  ClockTime = " << runTime.elapsedClockTime() << " s"
             << nl << endl;
+
+#       include "convergenceCheck.H"
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/solvers/compressible/rhoSimpleFoam/UEqn.H b/applications/solvers/compressible/rhoSimpleFoam/UEqn.H
index f1bed4d071e985d92c9057c777ca9e216b174c54..c41bc9b6c7b93cab65751d97b441f519e4b3d05f 100644
--- a/applications/solvers/compressible/rhoSimpleFoam/UEqn.H
+++ b/applications/solvers/compressible/rhoSimpleFoam/UEqn.H
@@ -9,4 +9,9 @@
 
     UEqn().relax();
 
-    solve(UEqn() == -fvc::grad(p));
+    eqnResidual = solve
+    (
+        UEqn() == -fvc::grad(p)
+    ).initialResidual();
+
+    maxResidual = max(eqnResidual, maxResidual);
diff --git a/applications/solvers/compressible/rhoSimpleFoam/convergenceCheck.H b/applications/solvers/compressible/rhoSimpleFoam/convergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..8958063193af348a058fd8f3baecb2547c00da3c
--- /dev/null
+++ b/applications/solvers/compressible/rhoSimpleFoam/convergenceCheck.H
@@ -0,0 +1,9 @@
+// check convergence
+
+if (maxResidual < convergenceCriterion)
+{
+    Info<< "reached convergence criterion: " << convergenceCriterion << endl;
+    runTime.writeAndEnd();
+    Info<< "latestTime = " << runTime.timeName() << endl;
+}
+
diff --git a/applications/solvers/compressible/rhoSimpleFoam/hEqn.H b/applications/solvers/compressible/rhoSimpleFoam/hEqn.H
index e5d60199fe7638498a04749a6e3d9d9f38384de3..8eb03f95eb46b687a79f9f68c09152bbd269224a 100644
--- a/applications/solvers/compressible/rhoSimpleFoam/hEqn.H
+++ b/applications/solvers/compressible/rhoSimpleFoam/hEqn.H
@@ -11,7 +11,8 @@
 
     hEqn.relax();
 
-    hEqn.solve();
+    eqnResidual = hEqn.solve().initialResidual();
+    maxResidual = max(eqnResidual, maxResidual);
 
     thermo->correct();
 }
diff --git a/applications/solvers/compressible/rhoSimpleFoam/initConvergenceCheck.H b/applications/solvers/compressible/rhoSimpleFoam/initConvergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..b56197f22a50cfd07b04fc14d40b9a5454da8c5b
--- /dev/null
+++ b/applications/solvers/compressible/rhoSimpleFoam/initConvergenceCheck.H
@@ -0,0 +1,7 @@
+// initialize values for convergence checks
+
+    scalar eqnResidual = 1, maxResidual = 0;
+    scalar convergenceCriterion = 0;
+
+    simple.readIfPresent("convergence", convergenceCriterion);
+
diff --git a/applications/solvers/compressible/rhoSimpleFoam/pEqn.H b/applications/solvers/compressible/rhoSimpleFoam/pEqn.H
index 87f82991efab27ed09108b586047497f87fc18ba..9f7e576919221f54f8286fa1bf0cad6ab7366c44 100644
--- a/applications/solvers/compressible/rhoSimpleFoam/pEqn.H
+++ b/applications/solvers/compressible/rhoSimpleFoam/pEqn.H
@@ -12,7 +12,16 @@ for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
     );
 
     pEqn.setReference(pRefCell, pRefValue);
-    pEqn.solve();
+    // retain the residual from the first iteration
+    if (nonOrth == 0)
+    {
+        eqnResidual = pEqn.solve().initialResidual();
+        maxResidual = max(eqnResidual, maxResidual);
+    }
+    else
+    {
+        pEqn.solve();
+    }
 
     if (nonOrth == nNonOrthCorr)
     {
diff --git a/applications/solvers/compressible/rhoSimpleFoam/rhoSimpleFoam.C b/applications/solvers/compressible/rhoSimpleFoam/rhoSimpleFoam.C
index b5b2aeb152c206980769de73809320f30ce6e144..edfe32990257558342f2fd34ec326ac365b09e0a 100644
--- a/applications/solvers/compressible/rhoSimpleFoam/rhoSimpleFoam.C
+++ b/applications/solvers/compressible/rhoSimpleFoam/rhoSimpleFoam.C
@@ -26,8 +26,7 @@ Application
     rhoSimpleFoam
 
 Description
-    Steady-state solver for turbulent flow of compressible fluids for
-    ventilation and heat-transfer.
+    Steady-state solver for turbulent flow of compressible fluids
 
 \*---------------------------------------------------------------------------*/
 
@@ -56,6 +55,7 @@ int main(int argc, char *argv[])
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
 #       include "readSIMPLEControls.H"
+#       include "initConvergenceCheck.H"
 
         p.storePrevIter();
         rho.storePrevIter();
@@ -74,6 +74,8 @@ int main(int argc, char *argv[])
         Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
             << "  ClockTime = " << runTime.elapsedClockTime() << " s"
             << nl << endl;
+
+#       include "convergenceCheck.H"
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/UEqn.H b/applications/solvers/heatTransfer/buoyantSimpleFoam/UEqn.H
index d58a70a54e4f3a533ee3f149a757ed68c0438f14..5bc4c4738ccc963dadfa1666a1886deb56cd5b5b 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleFoam/UEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/UEqn.H
@@ -9,4 +9,10 @@
 
     UEqn().relax();
 
-    solve(UEqn() == -fvc::grad(pd) - fvc::grad(rho)*gh);
+    eqnResidual = solve
+    (
+        UEqn() == -fvc::grad(pd) - fvc::grad(rho)*gh
+    ).initialResidual();
+
+    maxResidual = max(eqnResidual, maxResidual);
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/buoyantSimpleFoam.C b/applications/solvers/heatTransfer/buoyantSimpleFoam/buoyantSimpleFoam.C
index 932deb1fed6013dee7da3d3ddcf4bea8a9347989..3beb759bd717a875dc0fe8b98221a636f1d8daeb 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleFoam/buoyantSimpleFoam.C
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/buoyantSimpleFoam.C
@@ -26,8 +26,7 @@ Application
     buoyantSimpleFoam
 
 Description
-    Steady-state solver for buoyant, turbulent flow of compressible fluids for
-    ventilation and heat-transfer.
+    Steady-state solver for buoyant, turbulent flow of compressible fluids
 
 \*---------------------------------------------------------------------------*/
 
@@ -57,6 +56,7 @@ int main(int argc, char *argv[])
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
 #       include "readSIMPLEControls.H"
+#       include "initConvergenceCheck.H"
 
         pd.storePrevIter();
         rho.storePrevIter();
@@ -64,9 +64,7 @@ int main(int argc, char *argv[])
         // Pressure-velocity SIMPLE corrector
         {
 #           include "UEqn.H"
-
 #           include "hEqn.H"
-
 #           include "pEqn.H"
         }
 
@@ -77,6 +75,8 @@ int main(int argc, char *argv[])
         Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
             << "  ClockTime = " << runTime.elapsedClockTime() << " s"
             << nl << endl;
+
+#       include "convergenceCheck.H"
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/convergenceCheck.H b/applications/solvers/heatTransfer/buoyantSimpleFoam/convergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..8958063193af348a058fd8f3baecb2547c00da3c
--- /dev/null
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/convergenceCheck.H
@@ -0,0 +1,9 @@
+// check convergence
+
+if (maxResidual < convergenceCriterion)
+{
+    Info<< "reached convergence criterion: " << convergenceCriterion << endl;
+    runTime.writeAndEnd();
+    Info<< "latestTime = " << runTime.timeName() << endl;
+}
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/hEqn.H b/applications/solvers/heatTransfer/buoyantSimpleFoam/hEqn.H
index 5ff3394ac0ae9efa6878bc14da8839702b42a81e..dad078c2193a6797d2f08ed9751cdac4ca4ff157 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleFoam/hEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/hEqn.H
@@ -11,7 +11,8 @@
 
     hEqn.relax();
 
-    hEqn.solve();
+    eqnResidual = hEqn.solve().initialResidual();
+    maxResidual = max(eqnResidual, maxResidual);
 
     thermo->correct();
 }
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/initConvergenceCheck.H b/applications/solvers/heatTransfer/buoyantSimpleFoam/initConvergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..b56197f22a50cfd07b04fc14d40b9a5454da8c5b
--- /dev/null
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/initConvergenceCheck.H
@@ -0,0 +1,7 @@
+// initialize values for convergence checks
+
+    scalar eqnResidual = 1, maxResidual = 0;
+    scalar convergenceCriterion = 0;
+
+    simple.readIfPresent("convergence", convergenceCriterion);
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleFoam/pEqn.H b/applications/solvers/heatTransfer/buoyantSimpleFoam/pEqn.H
index 6f7aa582f078a471d7db384fd5d3729416277e6d..4c8d0939a8b53526a4ee07d4f91d6a5b3692a821 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleFoam/pEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleFoam/pEqn.H
@@ -13,7 +13,16 @@ for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
     );
 
     pdEqn.setReference(pdRefCell, pdRefValue);
-    pdEqn.solve();
+    // retain the residual from the first iteration
+    if (nonOrth == 0)
+    {
+        eqnResidual = pdEqn.solve().initialResidual();
+        maxResidual = max(eqnResidual, maxResidual);
+    }
+    else
+    {
+        pdEqn.solve();
+    }
 
     if (nonOrth == nNonOrthCorr)
     {
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/UEqn.H b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/UEqn.H
index d58a70a54e4f3a533ee3f149a757ed68c0438f14..5bc4c4738ccc963dadfa1666a1886deb56cd5b5b 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/UEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/UEqn.H
@@ -9,4 +9,10 @@
 
     UEqn().relax();
 
-    solve(UEqn() == -fvc::grad(pd) - fvc::grad(rho)*gh);
+    eqnResidual = solve
+    (
+        UEqn() == -fvc::grad(pd) - fvc::grad(rho)*gh
+    ).initialResidual();
+
+    maxResidual = max(eqnResidual, maxResidual);
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/buoyantSimpleRadiationFoam.C b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/buoyantSimpleRadiationFoam.C
index 034134eeb55773e5ff440cde7824068a6274db4a..4bb432d53ea832e69b95492f41fc2bef80b06ee5 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/buoyantSimpleRadiationFoam.C
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/buoyantSimpleRadiationFoam.C
@@ -58,6 +58,7 @@ int main(int argc, char *argv[])
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
 #       include "readSIMPLEControls.H"
+#       include "initConvergenceCheck.H"
 
         pd.storePrevIter();
         rho.storePrevIter();
@@ -65,9 +66,7 @@ int main(int argc, char *argv[])
         // Pressure-velocity SIMPLE corrector
         {
 #           include "UEqn.H"
-
 #           include "hEqn.H"
-
 #           include "pEqn.H"
         }
 
@@ -78,6 +77,8 @@ int main(int argc, char *argv[])
         Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
             << "  ClockTime = " << runTime.elapsedClockTime() << " s"
             << nl << endl;
+
+#       include "convergenceCheck.H"
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/convergenceCheck.H b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/convergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..8958063193af348a058fd8f3baecb2547c00da3c
--- /dev/null
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/convergenceCheck.H
@@ -0,0 +1,9 @@
+// check convergence
+
+if (maxResidual < convergenceCriterion)
+{
+    Info<< "reached convergence criterion: " << convergenceCriterion << endl;
+    runTime.writeAndEnd();
+    Info<< "latestTime = " << runTime.timeName() << endl;
+}
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/hEqn.H b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/hEqn.H
index 88094369d4107068cf0fc9eeb788322a7f0158da..31462927b94bdd60bba71db3718e6d98a7e9defb 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/hEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/hEqn.H
@@ -12,7 +12,8 @@
 
     hEqn.relax();
 
-    hEqn.solve();
+    eqnResidual = hEqn.solve().initialResidual();
+    maxResidual = max(eqnResidual, maxResidual);
 
     thermo->correct();
 
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/initConvergenceCheck.H b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/initConvergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..b56197f22a50cfd07b04fc14d40b9a5454da8c5b
--- /dev/null
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/initConvergenceCheck.H
@@ -0,0 +1,7 @@
+// initialize values for convergence checks
+
+    scalar eqnResidual = 1, maxResidual = 0;
+    scalar convergenceCriterion = 0;
+
+    simple.readIfPresent("convergence", convergenceCriterion);
+
diff --git a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/pEqn.H b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/pEqn.H
index 6f7aa582f078a471d7db384fd5d3729416277e6d..4c8d0939a8b53526a4ee07d4f91d6a5b3692a821 100644
--- a/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/pEqn.H
+++ b/applications/solvers/heatTransfer/buoyantSimpleRadiationFoam/pEqn.H
@@ -13,7 +13,16 @@ for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
     );
 
     pdEqn.setReference(pdRefCell, pdRefValue);
-    pdEqn.solve();
+    // retain the residual from the first iteration
+    if (nonOrth == 0)
+    {
+        eqnResidual = pdEqn.solve().initialResidual();
+        maxResidual = max(eqnResidual, maxResidual);
+    }
+    else
+    {
+        pdEqn.solve();
+    }
 
     if (nonOrth == nNonOrthCorr)
     {
diff --git a/applications/solvers/incompressible/simpleFoam/UEqn.H b/applications/solvers/incompressible/simpleFoam/UEqn.H
new file mode 100644
index 0000000000000000000000000000000000000000..9f9d9f6dd41457397ce54c3b69901d33b27a21c1
--- /dev/null
+++ b/applications/solvers/incompressible/simpleFoam/UEqn.H
@@ -0,0 +1,17 @@
+    // Solve the Momentum equation
+
+    tmp<fvVectorMatrix> UEqn
+    (
+        fvm::div(phi, U)
+      + turbulence->divDevReff(U)
+    );
+
+    UEqn().relax();
+
+    eqnResidual = solve
+    (
+        UEqn() == -fvc::grad(p)
+    ).initialResidual();
+
+    maxResidual = max(eqnResidual, maxResidual);
+
diff --git a/applications/solvers/incompressible/simpleFoam/convergenceCheck.H b/applications/solvers/incompressible/simpleFoam/convergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..8958063193af348a058fd8f3baecb2547c00da3c
--- /dev/null
+++ b/applications/solvers/incompressible/simpleFoam/convergenceCheck.H
@@ -0,0 +1,9 @@
+// check convergence
+
+if (maxResidual < convergenceCriterion)
+{
+    Info<< "reached convergence criterion: " << convergenceCriterion << endl;
+    runTime.writeAndEnd();
+    Info<< "latestTime = " << runTime.timeName() << endl;
+}
+
diff --git a/applications/solvers/incompressible/simpleFoam/initConvergenceCheck.H b/applications/solvers/incompressible/simpleFoam/initConvergenceCheck.H
new file mode 100644
index 0000000000000000000000000000000000000000..b56197f22a50cfd07b04fc14d40b9a5454da8c5b
--- /dev/null
+++ b/applications/solvers/incompressible/simpleFoam/initConvergenceCheck.H
@@ -0,0 +1,7 @@
+// initialize values for convergence checks
+
+    scalar eqnResidual = 1, maxResidual = 0;
+    scalar convergenceCriterion = 0;
+
+    simple.readIfPresent("convergence", convergenceCriterion);
+
diff --git a/applications/solvers/incompressible/simpleFoam/pEqn.H b/applications/solvers/incompressible/simpleFoam/pEqn.H
new file mode 100644
index 0000000000000000000000000000000000000000..dd9cae30a9c3a94d4be9c1bd3d5ab2df2d65f998
--- /dev/null
+++ b/applications/solvers/incompressible/simpleFoam/pEqn.H
@@ -0,0 +1,43 @@
+    p.boundaryField().updateCoeffs();
+
+    volScalarField AU = UEqn().A();
+    U = UEqn().H()/AU;
+    UEqn.clear();
+    phi = fvc::interpolate(U) & mesh.Sf();
+    adjustPhi(phi, U, p);
+
+    // Non-orthogonal pressure corrector loop
+    for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
+    {
+        fvScalarMatrix pEqn
+        (
+            fvm::laplacian(1.0/AU, p) == fvc::div(phi)
+        );
+
+        pEqn.setReference(pRefCell, pRefValue);
+        // retain the residual from the first iteration
+        if (nonOrth == 0)
+        {
+            eqnResidual = pEqn.solve().initialResidual();
+            maxResidual = max(eqnResidual, maxResidual);
+        }
+        else
+        {
+            pEqn.solve();
+        }
+
+        if (nonOrth == nNonOrthCorr)
+        {
+            phi -= pEqn.flux();
+        }
+    }
+
+#   include "continuityErrs.H"
+
+    // Explicitly relax pressure for momentum corrector
+    p.relax();
+
+    // Momentum corrector
+    U -= fvc::grad(p)/AU;
+    U.correctBoundaryConditions();
+
diff --git a/applications/solvers/incompressible/simpleFoam/simpleFoam.C b/applications/solvers/incompressible/simpleFoam/simpleFoam.C
index c604d95870610e1df5217879f0ba5f30fd2cc77b..7c378fe8ff714f44ddb56f898968fa607d986850 100644
--- a/applications/solvers/incompressible/simpleFoam/simpleFoam.C
+++ b/applications/solvers/incompressible/simpleFoam/simpleFoam.C
@@ -26,8 +26,7 @@ Application
     simpleFoam
 
 Description
-    Steady-state solver for incompressible, turbulent flow of non-Newtonian
-    fluids.
+    Steady-state solver for incompressible, turbulent flow
 
 \*---------------------------------------------------------------------------*/
 
@@ -41,14 +40,11 @@ int main(int argc, char *argv[])
 {
 
 #   include "setRootCase.H"
-
 #   include "createTime.H"
 #   include "createMesh.H"
 #   include "createFields.H"
 #   include "initContinuityErrs.H"
 
-    //mesh.clearPrimitives();
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
     Info<< "\nStarting time loop\n" << endl;
@@ -58,55 +54,14 @@ int main(int argc, char *argv[])
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
 #       include "readSIMPLEControls.H"
+#       include "initConvergenceCheck.H"
 
         p.storePrevIter();
 
         // Pressure-velocity SIMPLE corrector
         {
-            // Momentum predictor
-
-            tmp<fvVectorMatrix> UEqn
-            (
-                fvm::div(phi, U)
-              + turbulence->divDevReff(U)
-            );
-
-            UEqn().relax();
-
-            solve(UEqn() == -fvc::grad(p));
-
-            p.boundaryField().updateCoeffs();
-            volScalarField AU = UEqn().A();
-            U = UEqn().H()/AU;
-            UEqn.clear();
-            phi = fvc::interpolate(U) & mesh.Sf();
-            adjustPhi(phi, U, p);
-
-            // Non-orthogonal pressure corrector loop
-            for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
-            {
-                fvScalarMatrix pEqn
-                (
-                    fvm::laplacian(1.0/AU, p) == fvc::div(phi)
-                );
-
-                pEqn.setReference(pRefCell, pRefValue);
-                pEqn.solve();
-
-                if (nonOrth == nNonOrthCorr)
-                {
-                    phi -= pEqn.flux();
-                }
-            }
-
-#           include "continuityErrs.H"
-
-            // Explicitly relax pressure for momentum corrector
-            p.relax();
-
-            // Momentum corrector
-            U -= fvc::grad(p)/AU;
-            U.correctBoundaryConditions();
+#           include "UEqn.H"
+#           include "pEqn.H"
         }
 
         turbulence->correct();
@@ -116,6 +71,8 @@ int main(int argc, char *argv[])
         Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
             << "  ClockTime = " << runTime.elapsedClockTime() << " s"
             << nl << endl;
+
+#       include "convergenceCheck.H"
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/utilities/mesh/conversion/foamToStarMesh/Make/files b/applications/utilities/mesh/conversion/foamToStarMesh/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..72c388a0b8cbce1e7541433983f3418c93c47d2c
--- /dev/null
+++ b/applications/utilities/mesh/conversion/foamToStarMesh/Make/files
@@ -0,0 +1,3 @@
+foamToStarMesh.C
+
+EXE = $(FOAM_APPBIN)/foamToStarMesh
diff --git a/applications/utilities/mesh/conversion/foamToStarMesh/Make/options b/applications/utilities/mesh/conversion/foamToStarMesh/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..15672901703919f27df1928dd6c4aa1b7d5f879b
--- /dev/null
+++ b/applications/utilities/mesh/conversion/foamToStarMesh/Make/options
@@ -0,0 +1,6 @@
+EXE_INC = \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/conversion/lnInclude
+
+EXE_LIBS = \
+    -lconversion
diff --git a/applications/utilities/mesh/conversion/foamToStarMesh/foamToStarMesh.C b/applications/utilities/mesh/conversion/foamToStarMesh/foamToStarMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..fc970cd7486551dafbf08cf1d6fa760ea1565911
--- /dev/null
+++ b/applications/utilities/mesh/conversion/foamToStarMesh/foamToStarMesh.C
@@ -0,0 +1,171 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Application
+    foamToStarMesh
+
+Description
+    Reads an OpenFOAM mesh and writes a pro-STAR (v4) bnd/cel/vrt format.
+
+Usage
+    - foamToStarMesh [OPTION] \n
+    Reads an OpenFOAM mesh and writes a pro-STAR (v4) bnd/cel/vrt format.
+
+    @param -noBnd \n
+    Suppress writing the @c .bnd file
+
+    @param -scale \<factor\>\n
+    Specify an alternative geometry scaling factor.
+    The default is @b 1000 (scale @em [m] to @em [mm]).
+
+    @param -surface \n
+    Extract the surface of the volume mesh only.
+    This can be useful, for example, for surface morphing in an external
+    package.
+
+    @param -tri \n
+    Extract a triangulated surface.
+    The @b -surface options is implicitly selected.
+
+
+Note
+    The cellTable information available in the files
+    @c constant/cellTable and @c constant/polyMesh/cellTableId
+    will be used if available. Otherwise the cellZones are used when
+    creating the cellTable information.
+
+See Also
+    Foam::cellTable, Foam::meshWriter and Foam::meshWriters::STARCD
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "polyMesh.H"
+#include "STARCDMeshWriter.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+    argList::validOptions.insert("scale", "scale");
+    argList::validOptions.insert("noBnd", "");
+    argList::validOptions.insert("tri", "");
+    argList::validOptions.insert("surface", "");
+
+#   include "addTimeOptions.H"
+#   include "setRootCase.H"
+#   include "createTime.H"
+    // Get times list
+    instantList Times = runTime.times();
+
+    // set startTime and endTime depending on -time and -latestTime options
+#   include "checkTimeOptions.H"
+    runTime.setTime(Times[startTime], startTime);
+
+    bool surfaceOnly = false;
+    if (args.options().found("surface") or args.options().found("tri"))
+    {
+        surfaceOnly = true;
+    }
+
+    fileName exportName = meshWriter::defaultMeshName;
+    if (surfaceOnly)
+    {
+        exportName = meshWriter::defaultSurfaceName;
+    }
+
+    if (args.options().found("case"))
+    {
+        exportName += '-' + args.globalCaseName();
+    }
+
+    // default: rescale from [m] to [mm]
+    scalar scaleFactor = 1000;
+    if (args.options().found("scale"))
+    {
+        scaleFactor = readScalar(IStringStream(args.options()["scale"])());
+        if (scaleFactor <= 0)
+        {
+            scaleFactor = 1;
+        }
+    }
+
+#   include "createPolyMesh.H"
+
+    // bool firstCheck = true;
+
+    for (label timeI = startTime; timeI < endTime; ++timeI)
+    {
+        runTime.setTime(Times[timeI], timeI);
+
+#       include "getTimeIndex.H"
+
+        polyMesh::readUpdateState state = mesh.readUpdate();
+
+        if (timeI == startTime || state != polyMesh::UNCHANGED)
+        {
+            meshWriters::STARCD writer(mesh, scaleFactor);
+
+            if (args.options().found("noBnd"))
+            {
+                writer.noBoundary();
+            }
+
+            fileName meshName(exportName);
+            if (state != polyMesh::UNCHANGED)
+            {
+                meshName += '_' + runTime.timeName();
+            }
+
+            if (surfaceOnly)
+            {
+                if (args.options().found("tri"))
+                {
+                    writer.writeSurface(meshName, true);
+                }
+                else
+                {
+                    writer.writeSurface(meshName);
+                }
+            }
+            else
+            {
+                writer.write(meshName);
+            }
+        }
+
+        Info<< nl << endl;
+    }
+
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/conversion/foamToStarMesh/getTimeIndex.H b/applications/utilities/mesh/conversion/foamToStarMesh/getTimeIndex.H
new file mode 100644
index 0000000000000000000000000000000000000000..85a92405dda760fbbfc5931102afe41aa602b2e6
--- /dev/null
+++ b/applications/utilities/mesh/conversion/foamToStarMesh/getTimeIndex.H
@@ -0,0 +1,51 @@
+// Read time index from */uniform/time, but treat 0 and constant specially
+
+    word timeName = "0";
+
+    if
+    (
+        runTime.timeName() != "constant"
+     && runTime.timeName() != "0"
+    )
+    {
+        IOobject io
+        (
+            "time",
+            runTime.timeName(),
+            "uniform",
+            runTime,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        );
+
+        if (io.headerOk())
+        {
+            IOdictionary timeObject
+            (
+                IOobject
+                (
+                    "time",
+                    runTime.timeName(),
+                    "uniform",
+                    runTime,
+                    IOobject::MUST_READ,
+                    IOobject::NO_WRITE,
+                    false
+                )
+            );
+
+            label index;
+            timeObject.lookup("index") >> index;
+            timeName = Foam::name(index);
+        }
+        else
+        {
+            timeName = runTime.timeName();
+            // Info<< "skip ... missing entry " << io.objectPath() << endl;
+            // continue;
+        }
+    }
+
+    Info<< "\nTime [" << timeName << "] = " << runTime.timeName() << nl;
+
diff --git a/applications/utilities/mesh/conversion/star4ToFoam/Make/files b/applications/utilities/mesh/conversion/star4ToFoam/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..19355fafdd91ea78bcac3331e81d5ebb0859ace8
--- /dev/null
+++ b/applications/utilities/mesh/conversion/star4ToFoam/Make/files
@@ -0,0 +1,3 @@
+star4ToFoam.C
+
+EXE = $(FOAM_APPBIN)/star4ToFoam
diff --git a/applications/utilities/mesh/conversion/star4ToFoam/Make/options b/applications/utilities/mesh/conversion/star4ToFoam/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..15672901703919f27df1928dd6c4aa1b7d5f879b
--- /dev/null
+++ b/applications/utilities/mesh/conversion/star4ToFoam/Make/options
@@ -0,0 +1,6 @@
+EXE_INC = \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/conversion/lnInclude
+
+EXE_LIBS = \
+    -lconversion
diff --git a/applications/utilities/mesh/conversion/star4ToFoam/star4ToFoam.C b/applications/utilities/mesh/conversion/star4ToFoam/star4ToFoam.C
new file mode 100644
index 0000000000000000000000000000000000000000..a92e70913f78595c7e57bad6b9ebc45969ad8020
--- /dev/null
+++ b/applications/utilities/mesh/conversion/star4ToFoam/star4ToFoam.C
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Application
+    star4ToFoam
+
+Description
+    Converts a Star-CD (v4) pro-STAR mesh into OpenFOAM format.
+
+Usage
+    - star4ToFoam [OPTION] ccmMesh\n
+      convert pro-STAR mesh to OpenFOAM
+
+    @param -ascii \n
+    Write in ASCII format instead of binary
+
+    @param -scale \<factor\>\n
+    Specify an alternative geometry scaling factor.
+    The default is @b 0.001 (scale @em [mm] to @em [m]).
+
+    @param -solids \n
+    Treat any solid cells present just like fluid cells.
+    The default is to discard them.
+
+Note
+    - baffles are written as interfaces for later use
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "STARCDMeshReader.H"
+#include "OFstream.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+//  Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+    argList::validArgs.append("pro-STAR prefix");
+    argList::validOptions.insert("ascii", "");
+    argList::validOptions.insert("scale", "scale");
+    argList::validOptions.insert("solids", "");
+
+    argList args(argc, argv);
+    Time runTime(args.rootPath(), args.caseName());
+    stringList const& params = args.additionalArgs();
+
+    // default rescale from [mm] to [m]
+    scalar scaleFactor = 0.001;
+    if (args.options().found("scale"))
+    {
+        scaleFactor = readScalar(IStringStream(args.options()["scale"])());
+        if (scaleFactor <= 0)
+        {
+            scaleFactor = 1;
+        }
+    }
+
+    if (args.options().found("solids"))
+    {
+        meshReaders::STARCD::keepSolids = true;
+    }
+
+    // default to binary output, unless otherwise specified
+    IOstream::streamFormat format = IOstream::BINARY;
+    if (args.options().found("ascii"))
+    {
+        format = IOstream::ASCII;
+    }
+
+    // increase the precision of the points data
+    IOstream::defaultPrecision(10);
+
+    // remove extensions and/or trailing '.'
+    fileName prefix = fileName(params[0]).lessExt();
+
+    meshReaders::STARCD reader(prefix, runTime, scaleFactor);
+
+    autoPtr<polyMesh> mesh = reader.mesh(runTime);
+    reader.writeMesh(mesh, format);
+
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
index 0652ffc64694c7223ea4b2c990aa047362987804..823dae1ba76b6aafff9d4d7275878f6526e92f08 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
@@ -5,5 +5,5 @@ EXE_INC = \
 
 EXE_LIBS = \
     -lfiniteVolume \
-    -llagrangian \
-   
+    -llagrangian
+
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
index 3fa1495a909862cb4c26f90d0d1ff9ee331d5f26..7dac6294e6d6614337583d1f24021738424f151f 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
@@ -24,6 +24,15 @@ License
 
 Description
     Translates FOAM data to EnSight format
+
+Usage
+    - foamToEnsight [OPTION] \n
+    Translates OpenFOAM data to Ensight format
+
+    @param -ascii \n
+    Write Ensight data in ASCII format instead of "C Binary"
+
+Note
     Parallel support for cloud data is not supported
 
 \*---------------------------------------------------------------------------*/
@@ -74,16 +83,16 @@ bool inFileNameList
 int main(int argc, char *argv[])
 {
     argList::validOptions.insert("patches", "patch list");
-    argList::validOptions.insert("binary", "" );
+    argList::validOptions.insert("ascii", "" );
 #   include "addTimeOptions.H"
 
 #   include "setRootCase.H"
 
     // Check options
-    bool binary = false;
-    if (args.options().found("binary"))
+    bool binary = true;
+    if (args.options().found("ascii"))
     {
-        binary = true;
+        binary = false;
     }
 
 #   include "createTime.H"
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..739c971551520b88f08aac2001229792eb1031c5
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files
@@ -0,0 +1,3 @@
+foamToEnsightParts.C
+
+EXE = $(FOAM_APPBIN)/foamToEnsightParts
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/options b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..518c2a009922089cdff4de6dc662f0bb67321ce2
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/options
@@ -0,0 +1,9 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/lagrangian/basic/lnInclude \
+    -I$(LIB_SRC)/conversion/lnInclude
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -llagrangian \
+    -lconversion
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasLagrangian.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasLagrangian.H
new file mode 100644
index 0000000000000000000000000000000000000000..18f9ddf805919f9d7c1cecae9fc5daa511098aaf
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasLagrangian.H
@@ -0,0 +1,19 @@
+// check for lagrangian/positions information in the final directory
+
+bool hasLagrangian = false;
+if (timeDirs.size() > 1)
+{
+    IOobject io
+    (
+        "positions",
+        timeDirs[timeDirs.size() - 1].name(),
+        "lagrangian",
+        mesh,
+        IOobject::NO_READ
+    );
+
+    if (io.headerOk())
+    {
+        hasLagrangian = true;
+    }
+}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H
new file mode 100644
index 0000000000000000000000000000000000000000..a9367daf8eb9870b055ecb1f5a2025eb39d3cee5
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H
@@ -0,0 +1,20 @@
+// check for "points" in all of the result directories
+
+bool hasMovingMesh = false;
+if (timeDirs.size() > 1)
+{
+    hasMovingMesh = true;
+    for (label i=0; i < timeDirs.size() && hasMovingMesh; ++i)
+    {
+        IOobject io
+        (
+            "points",
+            timeDirs[i].name(),
+            polyMesh::meshSubDir,
+            mesh,
+            IOobject::NO_READ
+        );
+        
+        hasMovingMesh = io.headerOk();
+    }
+}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasSprayField.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasSprayField.H
new file mode 100644
index 0000000000000000000000000000000000000000..e6601f71911eb1abdc58d80933832c5a40e45429
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasSprayField.H
@@ -0,0 +1,15 @@
+// check that the spray variable is present for this time
+//
+bool hasSprayField = true;
+{
+    IOobject ioHeader
+    (
+        fieldName,
+        mesh.time().timeName(),
+        "lagrangian",
+        mesh,
+        IOobject::NO_READ
+    );
+
+    hasSprayField = ioHeader.headerOk();
+}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasValidField.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasValidField.H
new file mode 100644
index 0000000000000000000000000000000000000000..9973a7a5fbb682531938b5e719487ae025761325
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasValidField.H
@@ -0,0 +1,23 @@
+// check that the variable is present for all times
+//
+bool hasValidField = true;
+{
+    for (label i=0; i < timeDirs.size() && hasValidField; ++i)
+    {
+        if (fieldName.size() > 2 && fieldName(fieldName.size() - 2, 2) == "_0")
+        {
+            hasValidField = false;
+            break;
+        }
+
+        IOobject ioHeader
+        (
+            fieldName,
+            timeDirs[i].name(),
+            mesh,
+            IOobject::NO_READ
+        );
+
+        hasValidField = ioHeader.headerOk();
+    }
+}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightCaseTimes.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightCaseTimes.H
new file mode 100644
index 0000000000000000000000000000000000000000..ab7f4de5312a1cd8b7ec15e765637e17cbb16498
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightCaseTimes.H
@@ -0,0 +1,91 @@
+// write time values to case file
+{
+    scalar timeCorrection = 0;
+    if (timeDirs[0].value() < 0)
+    {
+        timeCorrection = - timeDirs[0].value();
+        Info<< "Correcting time values. Adding " << timeCorrection << endl;
+    }
+
+    caseFile.setf(ios_base::scientific, ios_base::floatfield);
+    caseFile.precision(5);
+
+    // time set 1 - geometry and volume fields
+    if (fieldFileNumbers.size())
+    {
+        caseFile
+            << "time set:        " << 1 << nl
+            << "number of steps: " << fieldFileNumbers.size() << nl
+            << "filename numbers:" << nl;
+
+        label count = 0;
+        forAll (fieldFileNumbers, i)
+        {
+            caseFile
+                << " " << setw(12) << fieldFileNumbers[i];
+
+            if (++count % 6 == 0)
+            {
+                caseFile << nl;
+            }
+        }
+
+        caseFile
+            << nl << "time values:" << nl;
+
+        count = 0;
+        forAll (fieldFileNumbers, i)
+        {
+            caseFile
+                << " " << setw(12)
+                << timeIndices[fieldFileNumbers[i]] + timeCorrection;
+
+            if (++count % 6 == 0)
+            {
+                caseFile << nl;
+            }
+        }
+        caseFile << nl << nl;
+    }
+
+    // time set 2 - lagrangian fields
+    if (hasLagrangian && sprayFileNumbers.size())
+    {
+        caseFile
+            << "time set:        " << 2 << nl
+            << "number of steps: " << sprayFileNumbers.size() << nl
+            << "filename numbers:" << nl;
+
+        label count = 0;
+        forAll (sprayFileNumbers, i)
+        {
+            caseFile
+                << " " << setw(12) << sprayFileNumbers[i];
+
+            if (++count % 6 == 0)
+            {
+                caseFile << nl;
+            }
+        }
+
+        caseFile
+            << nl << "time values:" << nl;
+
+        count = 0;
+        forAll (sprayFileNumbers, i)
+        {
+            caseFile
+                << " " << setw(12)
+                << timeIndices[sprayFileNumbers[i]] + timeCorrection;
+
+            if (++count % 6 == 0)
+            {
+                caseFile << nl;
+            }
+        }
+        caseFile << nl << nl;
+    }
+
+
+    caseFile << "# end" << nl;
+}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C
new file mode 100644
index 0000000000000000000000000000000000000000..a1b459c4a18b7c5d5840d0d7fbfbcffed56c278f
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C
@@ -0,0 +1,233 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+    $Date: 2008/04/02 11:37:10 $
+\*---------------------------------------------------------------------------*/
+
+#include "ensightOutputFunctions.H"
+
+#include "passiveParticle.H"
+#include "Cloud.H"
+#include "IOField.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+#include "OFstream.H"
+#include "IOmanip.H"
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+void ensightCaseEntry
+(
+    OFstream& caseFile,
+    const IOobject& fieldObject,
+    const fileName& dataMask,
+    bool measured
+)
+{
+    caseFile.setf(ios_base::left);
+
+    if (measured)
+    {
+        caseFile
+            << pTraits<Type>::typeName
+            << " per measured node: 2 "
+            << setw(15)
+            << ("s" + fieldObject.name()).c_str()
+            << " "
+            << (dataMask/"lagrangian"/fieldObject.name()).c_str()
+            << nl;
+    }
+    else
+    {
+        caseFile
+            << pTraits<Type>::typeName
+            << " per element:     "
+            << setw(15) << fieldObject.name()
+            << " "
+            << (dataMask/fieldObject.name()).c_str()
+            << nl;
+    }
+}
+
+
+void ensightParticlePositions
+(
+    const polyMesh& mesh,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+)
+{
+    Cloud<passiveParticle> parcels(mesh);
+
+    fileName lagrangianDir = subDir/"lagrangian";
+    fileName postFileName = lagrangianDir/"positions";
+
+    // the ITER/lagrangian subdirectory must exist
+    mkDir(dataDir/lagrangianDir);
+    ensightFile os(dataDir/postFileName, format);
+
+    // tag binary format (just like geometry files)
+    os.writeBinaryHeader();
+    os.write(postFileName);
+    os.newline();
+    os.write("particle coordinates");
+    os.newline();
+    os.write(parcels.size(), 8);	// unusual width
+    os.newline();
+
+    // binary write is Ensight6 - first ids, then positions
+    if (format == IOstream::BINARY)
+    {
+        forAll (parcels, i)
+        {
+            os.write(i+1);
+        }
+
+        forAllIter(Cloud<passiveParticle>, parcels, elmnt)
+        {
+            const vector& p = elmnt().position();
+
+            os.write(p.x());
+            os.write(p.y());
+            os.write(p.z());
+        }
+    }
+    else
+    {
+        label nParcels = 0;
+
+        forAllIter(Cloud<passiveParticle>, parcels, elmnt)
+        {
+            const vector& p = elmnt().position();
+
+            os.write(++nParcels, 8);	// unusual width
+            os.write(p.x());
+            os.write(p.y());
+            os.write(p.z());
+            os.newline();
+        }
+    }
+}
+
+
+
+template<class Type>
+void ensightSprayField
+(
+    const IOobject& fieldObject,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+)
+{
+    Info<< " " << fieldObject.name() << flush;
+
+    fileName lagrangianDir = subDir/"lagrangian";
+    fileName postFileName = lagrangianDir/fieldObject.name();
+
+    string title = postFileName + " with " + pTraits<Type>::typeName + " values";
+
+    ensightFile os(dataDir/postFileName, format);
+    os.write(title);
+    os.newline();
+
+    IOField<Type> field(fieldObject);
+
+    // 6 values per line
+    label count = 0;
+
+    forAll(field, i)
+    {
+        Type val = field[i];
+
+        if (mag(val) < 1.0e-90)
+        {
+            val = pTraits<Type>::zero;
+        }
+
+        for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; cmpt++)
+        {
+            os.write( component(val, cmpt) );
+        }
+
+        count += pTraits<Type>::nComponents;
+
+        if (count % 6 == 0)
+        {
+            os.newline();
+        }
+    }
+
+    // add final newline if required
+    if (count % 6)
+    {
+        os.newline();
+    }
+}
+
+
+//- write generalized field components
+template <class Type>
+void ensightVolField
+(
+    const ensightParts& partsList,
+    const IOobject& fieldObject,
+    const fvMesh& mesh,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+)
+{
+    Info<< " " << fieldObject.name() << flush;
+
+    fileName postFileName = subDir/fieldObject.name();
+
+    ensightFile os(dataDir/postFileName, format);
+    os.write(postFileName);
+    os.newline();
+
+    // ie, volField<Type>
+    partsList.writeField
+    (
+        os,
+        GeometricField<Type, fvPatchField, volMesh>
+        (
+            fieldObject,
+            mesh
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // end namespace Foam
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H
new file mode 100644
index 0000000000000000000000000000000000000000..e2f5ef2860102d50ef6dbe39ccbad8951a2d0f3c
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H
@@ -0,0 +1,100 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+
+    miscellaneous collection of functions and template related
+    to Ensight data
+
+SourceFiles
+    ensightOutputFunctions.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightOutputFunctions_H
+#define ensightOutputFunctions_H
+
+#include "ensightFile.H"
+#include "polyMesh.H"
+#include "IOobject.H"
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void ensightCaseEntry
+(
+    OFstream& caseFile,
+    const IOobject& fieldObject,
+    const fileName& dataMask,
+    bool measured = false
+);
+
+
+void ensightParticlePositions
+(
+    const polyMesh& mesh,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+);
+
+
+//- write spray parcels
+template<class Type>
+void ensightSprayField
+(
+    const IOobject& fieldObject,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+);
+
+//- write generalized field components
+template<class Type>
+void ensightVolField
+(
+    const ensightParts& partsList,
+    const IOobject& fieldObject,
+    const fvMesh& mesh,
+    const fileName& dataDir,
+    const fileName& subDir,
+    IOstream::streamFormat format
+);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // end namespace Foam
+
+#ifdef NoRepository
+#   include "ensightOutputFunctions.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
new file mode 100644
index 0000000000000000000000000000000000000000..65588d7dc87e54e3489d9a207e1829dbac1d54dc
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
@@ -0,0 +1,499 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Application
+    foamToEnsightParts
+
+Description
+    Translates OpenFOAM data to Ensight format.
+    An Ensight part is created for each cellZone and patch.
+
+Usage
+    - foamToEnsightParts [OPTION] \n
+    Translates OpenFOAM data to Ensight format
+
+    @param -ascii \n
+    Write Ensight data in ASCII format instead of "C Binary"
+
+    @param -zeroTime \n
+    Include the often incomplete initial conditions.
+
+Note
+    - no parallel data.
+    - writes to @a Ensight directory to avoid collisions with foamToEnsight.
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "timeSelector.H"
+
+#include "volFields.H"
+#include "OFstream.H"
+#include "IOmanip.H"
+#include "IOobjectList.H"
+#include "scalarIOField.H"
+#include "tensorIOField.H"
+
+#include "ensightParts.H"
+#include "ensightOutputFunctions.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    // with -constant and -zeroTime
+    timeSelector::addOptions(true, false);
+    argList::noParallel();
+    argList::validOptions.insert("ascii", "");
+
+    const label nTypes = 2;
+    const word fieldTypes[] =
+    {
+        volScalarField::typeName,
+        volVectorField::typeName
+    };
+
+    const label nSprayFieldTypes = 2;
+    const word sprayFieldTypes[] =
+    {
+        scalarIOField::typeName,
+        vectorIOField::typeName
+    };
+
+#   include "setRootCase.H"
+#   include "createTime.H"
+
+    // get times list
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+    // default to binary output, unless otherwise specified
+    IOstream::streamFormat format = IOstream::BINARY;
+    if (args.options().found("ascii"))
+    {
+        format = IOstream::ASCII;
+    }
+
+    fileName ensightDir = args.rootPath()/args.globalCaseName()/"Ensight";
+    fileName dataDir = ensightDir/"data";
+    fileName caseFileName = "Ensight.case";
+    fileName dataMask = fileName("data")/ensightFile::mask();
+
+    // Ensight and Ensight/data directories must exist
+    if (dir(ensightDir))
+    {
+        rmDir(ensightDir);
+    }
+    mkDir(ensightDir);
+    mkDir(dataDir);
+
+#   include "createMesh.H"
+    // Construct the list of ensight parts for the entire mesh
+    ensightParts partsList(mesh);
+
+    // write summary information
+    {
+        OFstream partsInfoFile(ensightDir/"partsInfo");
+
+        partsInfoFile
+            << "// summary of ensight parts" << nl << nl;
+        partsList.writeSummary(partsInfoFile);
+    }
+
+#   include "checkHasMovingMesh.H"
+#   include "checkHasLagrangian.H"
+
+    // only take the objects that exists at the end of the calculation
+    IOobjectList objects(mesh, timeDirs[timeDirs.size()-1].name());
+    IOobjectList sprayObjects(mesh, timeDirs[timeDirs.size()-1].name(), "lagrangian");
+
+    // write single geometry or one per time step
+    fileName geometryFileName("geometry");
+    if (hasMovingMesh)
+    {
+        geometryFileName = dataMask/geometryFileName;
+    }
+
+    // the case file is always ASCII
+    Info << "write case: " << caseFileName.c_str() << endl;
+
+    OFstream caseFile(ensightDir/caseFileName, IOstream::ASCII);
+    caseFile.setf(ios_base::left);
+    caseFile
+        << "FORMAT" << nl
+        << setw(16) << "type:" << "ensight gold" << nl << nl
+        << "GEOMETRY" << nl
+        << setw(16) << "model: 1" << geometryFileName.c_str() << nl;
+
+    if (hasLagrangian)
+    {
+        caseFile
+            << setw(16) << "measured: 2"
+            << fileName(dataMask/"lagrangian"/"positions").c_str() << nl;
+    }
+    caseFile
+        << nl << "VARIABLE" << nl;
+
+    label nFieldTime = timeDirs.size();
+    if (nFieldTime < 0)
+    {
+        nFieldTime = 0;
+    }
+
+    List<label> fieldFileNumbers(nFieldTime);
+    List<label> sprayFileNumbers(nFieldTime);
+
+    // map used times used
+    Map<scalar>  timeIndices;
+
+    nFieldTime = 0;
+    label nSprayTime = 0;
+
+    forAll(timeDirs, timeI)
+    {
+        runTime.setTime(timeDirs[timeI], timeI);
+
+#       include "getTimeIndex.H"
+
+        fieldFileNumbers[nFieldTime++] = timeIndex;
+
+        // the data/ITER subdirectory must exist
+        fileName subDir = ensightFile::subDir(timeIndex);
+        mkDir(dataDir/subDir);
+
+        // place a timestamp in the directory for future reference
+        {
+            OFstream timeStamp(dataDir/subDir/"time");
+            timeStamp
+                << "#   timestep time" << nl
+                << subDir.c_str() << " " << runTime.timeName() << nl;
+        }
+
+#       include "moveMesh.H"
+
+        if (nFieldTime == 1 || mesh.moving())
+        {
+            if (hasMovingMesh)
+            {
+                geometryFileName = dataDir/subDir/"geometry";
+            }
+            if (mesh.moving())
+            {
+                partsList.recalculate(mesh);
+            }
+
+            ensightGeoFile geoFile(ensightDir/geometryFileName, format);
+            partsList.writeGeometry(geoFile);
+            Info << nl;
+        }
+
+        Info<< "write volume field: " << flush;
+
+        for (label i=0; i < nTypes; i++)
+        {
+            wordList fieldNames = objects.names(fieldTypes[i]);
+
+            forAll (fieldNames, fieldI)
+            {
+                word fieldName = fieldNames[fieldI];
+
+#               include "checkHasValidField.H"
+
+                if (!hasValidField)
+                {
+                    continue;
+                }
+
+                IOobject fieldObject
+                (
+                    fieldName,
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::MUST_READ,
+                    IOobject::NO_WRITE
+                );
+
+                if (fieldTypes[i] == volScalarField::typeName)
+                {
+                    if (nFieldTime == 1)
+                    {
+                        ensightCaseEntry<scalar>
+                        (
+                            caseFile,
+                            fieldObject,
+                            dataMask
+                        );
+                    }
+
+                    ensightVolField<scalar>
+                    (
+                        partsList,
+                        fieldObject,
+                        mesh,
+                        dataDir,
+                        subDir,
+                        format
+                    );
+
+                }
+                else if (fieldTypes[i] == volVectorField::typeName)
+                {
+                    if (nFieldTime == 1)
+                    {
+                        ensightCaseEntry<vector>
+                        (
+                            caseFile,
+                            fieldObject,
+                            dataMask
+                        );
+                    }
+
+                    ensightVolField<vector>
+                    (
+                        partsList,
+                        fieldObject,
+                        mesh,
+                        dataDir,
+                        subDir,
+                        format
+                    );
+
+                }
+                else if (fieldTypes[i] == volSphericalTensorField::typeName)
+                {
+                    if (nFieldTime == 1)
+                    {
+                        ensightCaseEntry<sphericalTensor>
+                        (
+                            caseFile,
+                            fieldObject,
+                            dataMask
+                        );
+                    }
+
+                    ensightVolField<sphericalTensor>
+                    (
+                        partsList,
+                        fieldObject,
+                        mesh,
+                        dataDir,
+                        subDir,
+                        format
+                    );
+
+                }
+                else if (fieldTypes[i] == volSymmTensorField::typeName)
+                {
+                    if (nFieldTime == 1)
+                    {
+                        ensightCaseEntry<symmTensor>
+                        (
+                            caseFile,
+                            fieldObject,
+                            dataMask
+                        );
+                    }
+
+                    ensightVolField<symmTensor>
+                    (
+                        partsList,
+                        fieldObject,
+                        mesh,
+                        dataDir,
+                        subDir,
+                        format
+                    );
+
+                }
+                else if (fieldTypes[i] == volTensorField::typeName)
+                {
+                    if (nFieldTime == 1)
+                    {
+                        ensightCaseEntry<tensor>
+                        (
+                            caseFile,
+                            fieldObject,
+                            dataMask
+                        );
+                    }
+
+                    ensightVolField<tensor>
+                    (
+                        partsList,
+                        fieldObject,
+                        mesh,
+                        dataDir,
+                        subDir,
+                        format
+                    );
+
+                }
+            }
+        }
+        Info<< endl;
+
+
+        if (hasLagrangian)
+        {
+            // check that the positions field is present for this time
+            {
+                IOobject ioHeader
+                (
+                    "positions",
+                    mesh.time().timeName(),
+                    "lagrangian",
+                    mesh,
+                    IOobject::NO_READ
+                );
+
+                if (ioHeader.headerOk())
+                {
+                    sprayFileNumbers[nSprayTime++] = timeIndex;
+                }
+            }
+
+            Info<< "write  spray field: " << flush;
+
+            ensightParticlePositions
+            (
+                mesh,
+                dataDir,
+                subDir,
+                format
+            );
+
+            for (label i=0; i < nSprayFieldTypes; i++)
+            {
+                wordList fieldNames = sprayObjects.names(sprayFieldTypes[i]);
+
+                forAll (fieldNames, fieldI)
+                {
+                    word fieldName = fieldNames[fieldI];
+
+#                   include "checkHasSprayField.H"
+
+                    if (!hasSprayField)
+                    {
+                        continue;
+                    }
+
+                    IOobject fieldObject
+                    (
+                        fieldName,
+                        mesh.time().timeName(),
+                        "lagrangian",
+                        mesh,
+                        IOobject::MUST_READ,
+                        IOobject::NO_WRITE
+                    );
+
+                    if (sprayFieldTypes[i] == scalarIOField::typeName)
+                    {
+                        if (nSprayTime == 1)
+                        {
+                            ensightCaseEntry<scalar>
+                            (
+                                caseFile,
+                                fieldObject,
+                                dataMask,
+                                true
+                            );
+                        }
+
+                        ensightSprayField<scalar>
+                        (
+                            fieldObject,
+                            dataDir,
+                            subDir,
+                            format
+                        );
+
+                    }
+                    else if (sprayFieldTypes[i] == vectorIOField::typeName)
+                    {
+                        if (nSprayTime == 1)
+                        {
+                            ensightCaseEntry<vector>
+                            (
+                                caseFile,
+                                fieldObject,
+                                dataMask,
+                                true
+                            );
+                        }
+
+                        ensightSprayField<vector>
+                        (
+                            fieldObject,
+                            dataDir,
+                            subDir,
+                            format
+                        );
+
+                    }
+                    else if (sprayFieldTypes[i] == tensorIOField::typeName)
+                    {
+                        if (nSprayTime == 1)
+                        {
+                            ensightCaseEntry<tensor>
+                            (
+                                caseFile,
+                                fieldObject,
+                                dataMask,
+                                true
+                            );
+                        }
+
+                        ensightSprayField<tensor>
+                        (
+                            fieldObject,
+                            dataDir,
+                            subDir,
+                            format
+                        );
+
+                    }
+                }
+            }
+            Info<< endl;
+        }
+    }
+
+    fieldFileNumbers.setSize(nFieldTime);
+    sprayFileNumbers.setSize(nSprayTime);
+
+    // add time values
+    caseFile << nl << "TIME" << nl;
+#   include "ensightCaseTimes.H"
+
+    Info<< "\nEnd\n"<< endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H
new file mode 100644
index 0000000000000000000000000000000000000000..297131d1a01c1d2011cd9a6cbb2946e157b7f563
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H
@@ -0,0 +1,50 @@
+// Read time index from */uniform/time,
+// but treat 0 and constant specially
+
+    label timeIndex = 0;
+
+    if
+    (
+        runTime.timeName() != "constant"
+     && runTime.timeName() != "0"
+    )
+    {
+        IOobject io
+        (
+            "time",
+            runTime.timeName(),
+            "uniform",
+            runTime,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        );
+
+        if (io.headerOk())
+        {
+            IOdictionary timeObject
+            (
+                IOobject
+                (
+                    "time",
+                    runTime.timeName(),
+                    "uniform",
+                    runTime,
+                    IOobject::MUST_READ,
+                    IOobject::NO_WRITE,
+                    false
+                )
+            );
+
+            timeObject.lookup("index") >> timeIndex;
+        }
+        else
+        {
+            Info<< "skip ... missing entry " << io.objectPath() << endl;
+            continue;
+        }
+    }
+
+    timeIndices.insert(timeIndex, timeDirs[timeI].value());
+    Info<< "\nTime [" << timeIndex << "] = " << runTime.timeName() << nl;
+
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/moveMesh.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/moveMesh.H
new file mode 100644
index 0000000000000000000000000000000000000000..f2ca3a1a658309e723029e759bd186ee2af36331
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/moveMesh.H
@@ -0,0 +1,28 @@
+{
+    IOobject ioPoints
+    (
+        "points", 
+        runTime.timeName(),
+        polyMesh::meshSubDir,
+        mesh
+    );
+ 
+    if (ioPoints.headerOk())
+    {
+        // Reading new points
+        pointIOField newPoints
+        (
+            IOobject
+            (
+                "points",
+                mesh.time().timeName(),
+                polyMesh::meshSubDir,
+                mesh,
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            )
+        );
+        
+        mesh.movePoints(newPoints);
+    }
+}
diff --git a/bin/foamCheckSourceDeps b/bin/foamCheckSourceDeps
new file mode 100755
index 0000000000000000000000000000000000000000..5653f050d162fe41f2ffab142176f7f57501df12
--- /dev/null
+++ b/bin/foamCheckSourceDeps
@@ -0,0 +1,70 @@
+#!/bin/sh
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+#    \\/     M anipulation  |
+#-------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM.
+#
+#     OpenFOAM is free software; you can redistribute it and/or modify it
+#     under the terms of the GNU General Public License as published by the
+#     Free Software Foundation; either version 2 of the License, or (at your
+#     option) any later version.
+#
+#     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+#     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#     for more details.
+#
+#     You should have received a copy of the GNU General Public License
+#     along with OpenFOAM; if not, write to the Free Software Foundation,
+#     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Script
+#     foamCheckSourceDeps
+#
+# Description
+#     Usage: foamCheckSourceDeps [dir1 .. dirN]
+#
+#     Search for *.dep files that are without a corresponding .C or .L file.
+#     These could indicate a directory that has been moved.
+#         - print questionable directory  and dep file
+#------------------------------------------------------------------------------
+if [ "$1" = "-h" -o "$1" = "-help" ]
+then
+   cat <<USAGE 1>&2
+Usage: ${0##*/} [dir1 .. dirN]
+
+    Search for .dep files that are without a corresponding .C or .L file.
+    This could indicate a directory that has been moved.
+        - print questionable directory and file
+USAGE
+   exit 1
+fi
+
+if [ "$#" -eq 0 ]
+then
+   set -- .
+fi
+
+for checkDir
+do
+   if [ -d $checkDir ]
+   then
+      find $checkDir -name '*.dep' -print | while read depFile;
+      do
+         Cfile=$(echo $depFile | sed -e 's/\.dep$/.C/')
+         # also check flex files
+         Lfile=$(echo $depFile | sed -e 's/\.C$/.L/')
+         if [ ! -f $Cfile -a ! -f $Lfile ]
+         then
+            echo "$(dirname $Cfile)  ${depFile##*/}"
+         fi
+      done
+   fi
+done
+
+# -----------------------------------------------------------------------------
diff --git a/bin/foamSystemCheck b/bin/foamSystemCheck
index 27b7242d797e31fa0ec4cc33ca2288ea01020d98..5b8d33574a74d31c7bc75c6dd1ba84f633bac397 100755
--- a/bin/foamSystemCheck
+++ b/bin/foamSystemCheck
@@ -1,4 +1,4 @@
-#!/bin/sh -u
+#!/bin/sh
 #------------------------------------------------------------------------------
 # =========                 |
 # \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
@@ -28,37 +28,35 @@
 #
 # Description
 #     Checks the machine system and the user's
-#     personal configuration for running FOAM.
+#     personal configuration for running OpenFOAM.
 #
 #------------------------------------------------------------------------------
 
-TMPTAB=tmptab.$$
-LOG=log.$0
-HLINE="-----------------------------------------------------------------------"
+# STATIC VARIABLES
+# ~~~~~~~~~~~~~~~~
+FOAM_VERSION=1.5
 
-FATALERROR=0
-SSHRSHOK=0
-WIDTH=20
-FOAM_VERSION=1.4.1
-OS=`uname -s`
+HLINE="-----------------------------------------------------------------------"
+WIDTH=16
+unset FATALERROR
 
-#FUNCTIONS
-#~~~~~~~~~
+# FUNCTIONS
+# ~~~~~~~~~
 heading () {
-    echo ""
     echo ""
     echo "$1"
     echo "$HLINE"
 }
 
 lenBase () {
-echo $1 | tr -d " " | wc -m | tr -d " "
+    echo $1 | tr -d " " | wc -m | tr -d " "
 }
 
 length () {
-    NOCHAR=`lenBase $1`
-    NOCHAR=`expr $NOCHAR - 1`
-    if [ $NOCHAR -eq -1 ]; then
+    NOCHAR=$(lenBase $1)
+    NOCHAR=$(expr $NOCHAR - 1)
+    if [ $NOCHAR -eq -1 ]
+    then
         NOCHAR=0
     fi
     echo $NOCHAR
@@ -66,197 +64,106 @@ length () {
 
 fixlen () {
     WORD=$1
-    ONELEN=`length "$1"`
-    LDIFF=`expr $ONELEN - $2`
-    if [ $LDIFF -le 1 ]; then
-        while [ $LDIFF -lt 0 ] ; do
+    ONELEN=$(length "$1")
+    LDIFF=$(expr $ONELEN - $2)
+    if [ $LDIFF -le 1 ]
+    then
+        while [ $LDIFF -lt 0 ]
+        do
             WORD="$WORD "
-            LDIFF=`expr $LDIFF + 1`
+            LDIFF=$(expr $LDIFF + 1)
         done
         echo "$WORD"
     else
-        LDIFF=`expr $LDIFF + 4`
-        WORD=`echo "$WORD" | cut -c${LDIFF}-`
+        LDIFF=$(expr $LDIFF + 4)
+        WORD=$(echo "$WORD" | cut -c${LDIFF}-)
         echo "...${WORD}"
     fi
 }
 
+# MAIN CODE
+# ~~~~~~~~~
+heading "Checking basic system..."
 
-checkSetup () {
-cat <<EOF
-Host: $HOST_NAME
-OS: $OS
-OS_version: $OS_VERSION
-Shell: $USER_SHELL
-User: $USER_NAME
-EOF
-}
-
-checkNetworking () {
-pingTest $HOST_NAME
-pingTest localHost
-checkRsh
-checkSsh
-}
-
-pingTest () {
-case $OS in
-    SunOS)
-        if [ -x '/usr/sbin/ping' ] ; then
-            PINGTEST=`/usr/sbin/ping $1 2>&1`
-            if [ -n "`echo $PINGTEST | grep 'alive'`" ] ; then
-               RESULT="Successful"
-            elif [ -n "`echo $PINGTEST | grep 'unknown host'`" ] ; then
-               RESULT="Unknown_host"
-            else
-               RESULT="Networking_not_set"
-            fi
-        else
-            RESULT="Ping_not_installed_in_usual_path"
-        fi
-        ;;
-    *)
-        if [ -x '/bin/ping' ] ; then
-            PINGTEST=`/bin/ping -w 3 -c 1 $1 2>&1`
-            if [ -n "`echo $PINGTEST | grep '1 received'`" ] ; then
-                RESULT="Successful"
-            elif [ -n "`echo $PINGTEST | grep 'unknown host'`" ] ; then
-                RESULT='Unknown host'
-            else
-                RESULT='Networking not set'
-            fi
-        else
-            RESULT="Ping_not_installed_in_usual_path"
-        fi
-        ;;
+# check shell
+echo "$(fixlen "Shell:" $WIDTH) $SHELL"
+case "$SHELL" in
+*/csh | */tcsh)
+    USER_CONFIG_TYPE=cshrc
+    ;;
+*/bash | */ksh)
+    USER_CONFIG_TYPE=bashrc
+    ;;
+*)
+    USER_CONFIG_TYPE=""
+    echo "FATALERROR: Cannot identify the current shell."
+    echo "            OpenFOAM ${FOAM_VERSION} is compatible"
+    echo "            with csh, tcsh, ksh and bash."
+    echo
+    FATALERROR=yes
+    ;;
 esac
-echo "`fixlen "Ping_$1:" $WIDTH` $RESULT"
-if [ "$RESULT" != 'Successful' ]; then
-    FATALERROR=`expr $FATALERROR + 1`
-fi
-
-}
-
-telnetPortTest () {
-telnet -e A $1 $2 <<EOF
-A
-quit
-EOF
-}
-
-checkTelnetPort () {
-if  [ -x "/usr/bin/telnet" ] || [ -x "/bin/telnet" ] ; then
-    RESULT=`telnetPortTest $1 $2 2>&1 | egrep "onnect.* [t|r]"`
-    if [ "`echo $RESULT | grep 'Connected to'`" ] ; then
-        RESULT='Successful'
-    elif [ "`echo $RESULT | grep 'Connection refused'`" ] ;
-    then
-        RESULT='Unsuccessful, connection refused*'
-    else
-        RESULT="Not active*"
-    fi
-else
-    RESULT='No_telnet_running:_cannot_check*'
-fi
-}
-
-checkRsh () {
-checkTelnetPort $HOST_NAME 222
-echo "`fixlen "Test_rsh:" $WIDTH` $RESULT"
-if [ "$RESULT" != 'Successful' ]; then
-    SSHRSHOK=`expr $SSHRSHOK + 1`
-fi
-}
-
-checkSsh () {
-checkTelnetPort $HOST_NAME 22
-echo "`fixlen "Test_ssh:" $WIDTH` $RESULT"
-if [ "$RESULT" != 'Successful' ]; then
-    SSHRSHOK=`expr $SSHRSHOK + 1`
-fi
-}
-
-expenv () {
-    eval "echo $1"
-}
-
-#MAIN CODE
-#~~~~~~~~~
-HOST_NAME=`uname -n`
-OS=`uname -s`
-OS_VERSION=`uname -r`
-USER_SHELL=`basename $SHELL`
-USER_NAME=$LOGNAME
-#
-if [ `length $USER_NAME` -eq 0 ] ; then
-    USER_NAME=$USER
-fi
-#
-WIDTH=20
 
-heading "Checking basic system..."
-case $USER_SHELL in
-    csh|tcsh) USER_CONFIG_TYPE=cshrc
-              echo "`fixlen "Shell:" $WIDTH` $USER_SHELL"
-              ;;
-    bash|ksh) USER_CONFIG_TYPE=bashrc
-              echo "`fixlen "Shell:" $WIDTH` $USER_SHELL"
-              ;;
-    *) USER_CONFIG_TYPE=""
-       echo "`fixlen "Shell:" $WIDTH` $USER_SHELL"
-       echo "FATALERROR: Cannot identify the current shell."
-       echo "            Foam ${FOAM_VERSION} is compatible"
-       echo "            with csh, tcsh, ksh and bash."
-       echo
-       FATALERROR=`expr $FATALERROR + 1`;;
-esac
-#
-if [ `length $HOST_NAME` -eq 0 ]; then
-    echo "`fixlen "Host:" $WIDTH` ${HOST_NAME}"
+# check hostname
+HOST=$(uname -n)
+echo "$(fixlen "Host:" $WIDTH) $HOST"
+if [ $(length $HOST) -eq 0 ]
+then
     echo "FATALERROR: Cannot stat hostname."
-    echo "            Foam ${FOAM_VERSION} needs a valid hostname to function."
+    echo "            OpenFOAM ${FOAM_VERSION} needs a valid hostname to function."
     echo "            Contact your system administrator. "
     echo
-    FATALERROR=`expr $FATALERROR + 1`
-else
-    echo "`fixlen "Host:" $WIDTH` ${HOST_NAME}"
+    FATALERROR=yes
 fi
-#
-if [ "$OS" = "Linux" ] || [ "$OS" = "LinuxAMD64" ] || [ "$OS" = "SunOS" ]; then
-    echo "`fixlen "OS:" $WIDTH` ${OS} version ${OS_VERSION}"
-else
+
+# check os
+OS=$(uname -s)
+case "$OS" in
+Linux | LinuxAMD64 | SunOS )
+    echo "$(fixlen "OS:" $WIDTH) ${OS} version $(uname -r)"
+    ;;
+*)
     echo "FATALERROR: Incompatible operating system \"$OS\"."
-    echo "            Foam${FOAM_VERSION} is currently available for "
+    echo "            OpenFOAM ${FOAM_VERSION} is currently available for "
     echo "            Linux, LinuxAMD64 and SunOS only."
     echo
-    FATALERROR=`expr $FATALERROR + 1`
+    FATALERROR=yes
+    ;;
+esac
+
+
+# check user name
+USER_NAME=$LOGNAME
+if [ $(length $USER_NAME) -eq 0 ]
+then
+    USER_NAME=$USER
 fi
-#
-if [ `length $USER_NAME` -eq 0 ]; then
-    echo "`fixlen "User:" $WIDTH` ${USER_NAME}"
+
+echo "$(fixlen "User:" $WIDTH) ${USER_NAME}"
+if [ $(length $USER_NAME) -eq 0 ]
+then
     echo "FATALERROR: Cannot stat user name ${USER_NAME}."
-    echo "            Foam${FOAM_VERSION} needs a valid user name."
+    echo "            OpenFOAM ${FOAM_VERSION} needs a valid user name."
     echo "            Contact your system administrator. "
     echo ""
-    FATALERROR=`expr $FATALERROR + 1`
-else
-    echo "`fixlen "User:" $WIDTH` ${USER_NAME}"
+    FATALERROR=yes
 fi
-#
+
 
 echo ""
 echo ""
-if [ $FATALERROR -gt 0 ]; then
+if [ -n "$FATALERROR" ]
+then
     echo "System check: FAIL"
     echo "=================="
-    echo "Your system is not currently compatible with Foam installation "
+    echo "Your system is not currently compatible with OpenFOAM installation "
     echo "requirements. Review the error messages and consult the documentation"
     echo "for further instructions."
     echo
 else
     echo "System check: PASS"
     echo "=================="
-    echo "Continue Foam installation."
+    echo "Continue OpenFOAM installation."
     echo
 fi
 
diff --git a/src/OpenFOAM/fields/pointPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValuePointPatchField.C b/src/OpenFOAM/fields/pointPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValuePointPatchField.C
index 2ce7ada7ea1ce5445da016c0e5f064d13322df43..9b81fa90f8716dacdd5f5e4fe1f3d04cd9175d85 100644
--- a/src/OpenFOAM/fields/pointPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValuePointPatchField.C
+++ b/src/OpenFOAM/fields/pointPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValuePointPatchField.C
@@ -70,7 +70,7 @@ timeVaryingUniformFixedValuePointPatchField
 )
 :
     fixedValuePointPatchField<Type>(p, iF),
-    timeSeries_(this->db(), dict)
+    timeSeries_(dict)
 {
     updateCoeffs();
 }
diff --git a/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.C b/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.C
index bfb0ce9f128d21032c08b5bb3f73163bc73bf500..946041c6c3d71eb423ca02bff32a022de58b5cd9 100644
--- a/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.C
+++ b/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.C
@@ -32,20 +32,23 @@ License
 template<class Type>
 void Foam::interpolationTable<Type>::readTable()
 {
-    fileName_.expand();
+    // preserve the original (unexpanded) fileName to avoid absolute paths
+    // appearing subsequently in the write() method
+    fileName fName(fileName_);
+
+    fName.expand();
 
     // Read data from file
-    IFstream(fileName_)() >> *this;
+    IFstream(fName)() >> *this;
 
-    // Check that the data is okay
+    // Check that the data are okay
     check();
 
     if (this->size() == 0)
     {
         FatalErrorIn
         (
-            "Foam::interpolationTable<Type>::interpolationTable"
-            "(const dictionary& dict)"
+            "Foam::interpolationTable<Type>::readTable()"
         )   << "table is empty" << nl
             << exit(FatalError);
     }
@@ -58,8 +61,8 @@ template<class Type>
 Foam::interpolationTable<Type>::interpolationTable()
 :
     List<Tuple2<scalar, Type> >(),
-    boundAction_(interpolationTable::WARN),
-    fileName_("undefined_fileName")
+    boundsHandling_(interpolationTable::WARN),
+    fileName_("fileNameIsUndefined")
 {}
 
 
@@ -67,7 +70,7 @@ template<class Type>
 Foam::interpolationTable<Type>::interpolationTable(const fileName& fn)
 :
     List<Tuple2<scalar, Type> >(),
-    boundAction_(interpolationTable::WARN),
+    boundsHandling_(interpolationTable::WARN),
     fileName_(fn)
 {
     readTable();
@@ -78,7 +81,7 @@ template<class Type>
 Foam::interpolationTable<Type>::interpolationTable(const dictionary& dict)
 :
     List<Tuple2<scalar, Type> >(),
-    boundAction_(wordToBoundAction(dict.lookup("boundAction"))),
+    boundsHandling_(wordToBoundsHandling(dict.lookup("outOfBounds"))),
     fileName_(dict.lookup("fileName"))
 {
     readTable();
@@ -92,7 +95,7 @@ Foam::interpolationTable<Type>::interpolationTable
 )
 :
     List<Tuple2<scalar, Type> >(interpTable),
-    boundAction_(interpTable.boundAction_),
+    boundsHandling_(interpTable.boundsHandling_),
     fileName_(interpTable.fileName_)
 {}
 
@@ -101,9 +104,9 @@ Foam::interpolationTable<Type>::interpolationTable
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class Type>
-Foam::word Foam::interpolationTable<Type>::boundActionToWord
+Foam::word Foam::interpolationTable<Type>::boundsHandlingToWord
 (
-     const boundActions& bound
+     const boundsHandling& bound
 ) const
 {
     word enumName("warn");
@@ -137,8 +140,8 @@ Foam::word Foam::interpolationTable<Type>::boundActionToWord
 
 
 template<class Type>
-typename Foam::interpolationTable<Type>::boundActions
-Foam::interpolationTable<Type>::wordToBoundAction
+typename Foam::interpolationTable<Type>::boundsHandling
+Foam::interpolationTable<Type>::wordToBoundsHandling
 (
     const word& bound
 ) const
@@ -163,14 +166,27 @@ Foam::interpolationTable<Type>::wordToBoundAction
     {
         WarningIn
         (
-            "Foam::interpolationTable<Type>::wordToBoundAction(const word&)"
-        )   << "bad bounding specifier " << bound << " using 'warn'" << endl;
+            "Foam::interpolationTable<Type>::wordToBoundsHandling(const word&)"
+        )   << "bad outOfBounds specifier " << bound << " using 'warn'" << endl;
 
         return interpolationTable::WARN;
     }
 }
 
 
+template<class Type>
+typename Foam::interpolationTable<Type>::boundsHandling
+Foam::interpolationTable<Type>::outOfBounds
+(
+    const boundsHandling& bound
+)
+{
+    boundsHandling prev = boundsHandling_;
+    boundsHandling_ = bound;
+    return prev;
+}
+
+
 template<class Type>
 void Foam::interpolationTable<Type>::check() const
 {
@@ -197,26 +213,13 @@ void Foam::interpolationTable<Type>::check() const
 }
 
 
-template<class Type>
-typename Foam::interpolationTable<Type>::boundActions
-Foam::interpolationTable<Type>::boundAction
-(
-    const boundActions& bound
-)
-{
-    boundActions prev = boundAction_;
-    boundAction_ = bound;
-    return prev;
-}
-
-
 template<class Type>
 void Foam::interpolationTable<Type>::write(Ostream& os) const
 {
     os.writeKeyword("fileName")
         << fileName_ << token::END_STATEMENT << nl;
-    os.writeKeyword("boundAction")
-        << boundActionToWord(boundAction_) << token::END_STATEMENT << nl;
+    os.writeKeyword("outOfBounds")
+        << boundsHandlingToWord(boundsHandling_) << token::END_STATEMENT << nl;
 }
 
 
@@ -235,7 +238,7 @@ Foam::interpolationTable<Type>::operator[](const label i) const
     }
     else if (ii < 0)
     {
-        switch (boundAction_)
+        switch (boundsHandling_)
         {
             case interpolationTable::ERROR:
             {
@@ -275,7 +278,7 @@ Foam::interpolationTable<Type>::operator[](const label i) const
     }
     else if (ii >= n)
     {
-        switch (boundAction_)
+        switch (boundsHandling_)
         {
             case interpolationTable::ERROR:
             {
@@ -334,7 +337,7 @@ Type Foam::interpolationTable<Type>::operator()(const scalar value) const
 
     if (lookupValue < minLimit)
     {
-        switch (boundAction_)
+        switch (boundsHandling_)
         {
             case interpolationTable::ERROR:
             {
@@ -375,7 +378,7 @@ Type Foam::interpolationTable<Type>::operator()(const scalar value) const
     }
     else if (lookupValue >= maxLimit)
     {
-        switch (boundAction_)
+        switch (boundsHandling_)
         {
             case interpolationTable::ERROR:
             {
diff --git a/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.H b/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.H
index 77b944cda083f420ef5ff8ccf7b68080aae02345..8e00d9f5b3f92562a8dce8051f51db238a301f83 100644
--- a/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.H
+++ b/src/OpenFOAM/interpolations/interpolationTable/interpolationTable.H
@@ -29,15 +29,15 @@ Description
     A list of times and values.
     The time values must be positive and monotonically increasing.
 
-    The treatment of out-of-bounds values depends on the current setting
-    of bounding.
+    The handling of out-of-bounds values depends on the current setting
+    of @a outOfBounds.
 
-    If @a REPEAT bounding is in effect, the final time value is treated
-    as being equivalent to time=0 for the following periods.
+    If @a REPEAT is chosen for the out-of-bounds handling, the final time
+    value is treated as being equivalent to time=0 for the following periods.
 
 Note
-    - Accessing an empty list will result in an error.
-    - Accessing a list with a single element will always return the same value.
+    - Accessing an empty list results in an error.
+    - Accessing a list with a single element always returns the same value.
 
 SourceFiles
     interpolationTable.C
@@ -55,10 +55,8 @@ SourceFiles
 namespace Foam
 {
 
-class objectRegistry;
-
 /*---------------------------------------------------------------------------*\
-                      Class interpolationTable Declaration
+                    Class interpolationTable Declaration
 \*---------------------------------------------------------------------------*/
 
 template<class Type>
@@ -71,7 +69,7 @@ public:
     // Public data types
 
         //- Enumeration for handling out-of-bound values
-        enum boundActions
+        enum boundsHandling
         {
             ERROR,          /*!< Exit with a FatalError */
             WARN,           /*!< Issue warning and clamp value (default) */
@@ -85,7 +83,7 @@ private:
     // Private data
 
         //- Enumeration for handling out-of-bound values
-        boundActions boundAction_;
+        boundsHandling boundsHandling_;
 
         //- File name
         fileName fileName_;
@@ -107,7 +105,7 @@ public:
         //- Construct given the name of the file containing the table of data
         interpolationTable(const fileName& fn);
 
-        //- Construct by reading the fileName and boundAction from dictionary
+        //- Construct by reading the fileName and boundsHandling from dictionary
         //  and read the table from that file.
         //  This is a specialised constructor used by patchFields
         interpolationTable(const dictionary& dict);
@@ -118,20 +116,19 @@ public:
 
     // Member Functions
 
-        //- Return the out-of-bounds treatment as a word
-        word boundActionToWord(const boundActions& bound) const;
+        //- Return the out-of-bounds handling as a word
+        word boundsHandlingToWord(const boundsHandling& bound) const;
+
+        //- Return the out-of-bounds handling as an enumeration
+        boundsHandling wordToBoundsHandling(const word& bound) const;
 
-        //- Return the out-of-bounds treatment as an enumeration
-        boundActions wordToBoundAction(const word& bound) const;
+        //- Set the out-of-bounds handling from enum, return previous setting
+        boundsHandling outOfBounds(const boundsHandling& bound);
 
         //- Check that list is monotonically increasing
         //  Exit with a FatalError if there is a problem
         void check() const;
 
-        //- Set the out-of-bounds treatment from enum, return previous
-        //  setting
-        boundActions boundAction(const boundActions& bound);
-
         //- Write
         void write(Ostream& os) const;
 
diff --git a/src/conversion/Make/files b/src/conversion/Make/files
index 435c341cd3c800a2db6c43d24d560631c58afb43..7c5a0aa91c070a5903667e22ed7a76f864bfee0e 100644
--- a/src/conversion/Make/files
+++ b/src/conversion/Make/files
@@ -1,3 +1,24 @@
+ensight/file/ensightFile.C
+ensight/file/ensightGeoFile.C
+ensight/part/ensightPart.C
+ensight/part/ensightPartIO.C
+ensight/part/ensightPartCells.C
+ensight/part/ensightPartFaces.C
+ensight/part/ensightParts.C
+
+meshTables/boundaryRegion.C
+meshTables/cellTable.C
+
+meshReader/meshReader.C
+meshReader/meshReaderAux.C
+meshReader/calcPointCells.C
+meshReader/createPolyCells.C
+meshReader/createPolyBoundary.C
+meshReader/starcd/STARCDMeshReader.C
+
+meshWriter/meshWriter.C
+meshWriter/starcd/STARCDMeshWriter.C
+
 polyDualMesh/polyDualMesh.C
 
 LIB = $(FOAM_LIBBIN)/libconversion
diff --git a/src/conversion/Make/options b/src/conversion/Make/options
index 4b2f0a059fbac055ee17d31b510b95445907d34c..a3ae8da833177387e9eecf75b5e2675fc7b481f5 100644
--- a/src/conversion/Make/options
+++ b/src/conversion/Make/options
@@ -1,5 +1,7 @@
 EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
     -I$(LIB_SRC)/meshTools/lnInclude
 
 LIB_LIBS = \
+    -lfiniteVolume \
     -lmeshTools
diff --git a/src/conversion/ensight/file/ensightFile.C b/src/conversion/ensight/file/ensightFile.C
new file mode 100644
index 0000000000000000000000000000000000000000..88357ba435acd05896294ae6eaf1968c01b8fadf
--- /dev/null
+++ b/src/conversion/ensight/file/ensightFile.C
@@ -0,0 +1,298 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightFile.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// allow undef in results
+bool Foam::ensightFile::allowUndef_ = false;
+
+// value to represent undef in results
+Foam::scalar Foam::ensightFile::undefValue_ = Foam::floatScalarVGREAT;
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from pathname
+Foam::ensightFile::ensightFile
+(
+    const fileName& pathname,
+    IOstream::streamFormat format
+)
+:
+    OFstream(pathname, format)
+{
+    // ascii formatting specs
+    setf
+    (
+        ios_base::scientific,
+        ios_base::floatfield
+    );
+    precision(5);
+}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightFile::~ensightFile()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::ensightFile::allowUndef()
+{
+    return allowUndef_;
+}
+
+
+bool Foam::ensightFile::allowUndef(bool value)
+{
+    bool old = allowUndef_;
+    allowUndef_ = value;
+    return old;
+}
+
+
+Foam::scalar Foam::ensightFile::undefValue(const scalar& value)
+{
+    // enable its use too
+    allowUndef_ = true;
+
+    scalar old = undefValue_;
+    undefValue_ = value;
+    return old;
+}
+
+
+// binary write
+Foam::Ostream& Foam::ensightFile::write
+(
+    const char* buf,
+    std::streamsize count
+)
+{
+    stream().write(buf, count);
+    return *this;
+}
+
+
+// write string as "%80s" or as binary
+Foam::Ostream& Foam::ensightFile::write
+(
+    const string& value
+)
+{
+    char buf[80];
+
+    for (string::size_type i = 0; i < 80; ++i)
+    {
+        buf[i] = 0;
+    }
+
+    string::size_type n = value.size();
+    if (n >= 80)
+    {
+        n = 79;
+    }
+
+    for (string::size_type i = 0; i < n; ++i)
+    {
+        buf[i] = value[i];
+    }
+
+    if (format() == IOstream::BINARY)
+    {
+        write
+        (
+            reinterpret_cast<char const *>(buf),
+            sizeof(buf)
+        );
+    }
+    else
+    {
+        stream() << buf;
+    }
+
+    return *this;
+}
+
+
+// write integer as "%10d" or as binary
+Foam::Ostream& Foam::ensightFile::write
+(
+    const label& value
+)
+{
+    if (format() == IOstream::BINARY)
+    {
+        unsigned int ivalue(value);
+
+        write
+        (
+            reinterpret_cast<char const *>(&ivalue),
+            sizeof(ivalue)
+        );
+    }
+    else
+    {
+        stream().width(10);
+        stream() << value;
+    }
+
+    return *this;
+}
+
+
+// write integer with specified width or as binary
+Foam::Ostream& Foam::ensightFile::write
+(
+    const label& value,
+    const label fieldWidth
+)
+{
+    if (format() == IOstream::BINARY)
+    {
+        unsigned int ivalue(value);
+
+        write
+        (
+            reinterpret_cast<char const *>(&ivalue),
+            sizeof(ivalue)
+        );
+    }
+    else
+    {
+        stream().width(fieldWidth);
+        stream() << value;
+    }
+
+    return *this;
+}
+
+
+// write float as "%12.5e" or as binary
+Foam::Ostream& Foam::ensightFile::write
+(
+    const scalar& value
+)
+{
+    if (format() == IOstream::BINARY)
+    {
+        float fvalue(value);
+
+        write
+        (
+            reinterpret_cast<char const *>(&fvalue),
+            sizeof(fvalue)
+        );
+    }
+    else
+    {
+        stream().width(12);
+        stream() << value;
+    }
+
+    return *this;
+}
+
+
+// Add carriage return to ascii stream
+void Foam::ensightFile::newline()
+{
+    if (format() == IOstream::ASCII)
+    {
+        stream() << nl;
+    }
+}
+
+
+// write undef value
+Foam::Ostream& Foam::ensightFile::writeUndef()
+{
+    write(undefValue_);
+    return *this;
+}
+
+
+// write element keyword with trailing newline, optionally with undef
+Foam::Ostream& Foam::ensightFile::writeKeyword
+(
+    const string& key
+)
+{
+    if (allowUndef_)
+    {
+        write(key + " undef");
+        newline();
+        write(undefValue_);
+        newline();
+    }
+    else
+    {
+        write(key);
+        newline();
+    }
+    return *this;
+}
+
+
+// write "C Binary" for binary files
+Foam::Ostream& Foam::ensightFile::writeBinaryHeader()
+{
+    if (format() == IOstream::BINARY)
+    {
+        write("C Binary");
+    }
+
+    return *this;
+}
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+
+// '*' mask appropriate for subDir
+Foam::string Foam::ensightFile::mask()
+{
+    char buf[16] = "********";
+    return buf;
+}
+
+
+// consistent zero-padded numbers for subdirectories
+Foam::string Foam::ensightFile::subDir(const label n)
+{
+    char buf[16];
+
+    sprintf(buf, "%08d", n);
+    return buf;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightFile.H b/src/conversion/ensight/file/ensightFile.H
new file mode 100644
index 0000000000000000000000000000000000000000..9e0271dbf4a44fffa0d4c154b93265c2f519f6fa
--- /dev/null
+++ b/src/conversion/ensight/file/ensightFile.H
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightFile
+
+Description
+    Ensight output with specialized write() for strings, integers and floats.
+    Correctly handles binary write as well.
+
+\*---------------------------------------------------------------------------*/
+#ifndef ensightFile_H
+#define ensightFile_H
+
+#include "OFstream.H"
+#include "IOstream.H"
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class ensightFile Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightFile
+:
+    public OFstream
+{
+    //- allow undef in results
+    static bool allowUndef_;
+
+    //- value to represent undef in results
+    static scalar undefValue_;
+
+    //- Disallow default bitwise assignment
+    void operator=(const ensightFile&);
+
+    //- Disallow default copy constructor
+    ensightFile(const ensightFile&);
+
+public:
+    // Constructors
+
+        //- Construct from pathname
+        ensightFile
+        (
+            const fileName& pathname,
+            IOstream::streamFormat format=IOstream::BINARY
+        );
+
+    // Destructor
+        ~ensightFile();
+
+    // Access
+        //- Return setting for whether 'undef' values are allowed in results
+        static bool allowUndef();
+
+        //- '*' mask appropriate for subDir
+        static string mask();
+
+        //- consistent zero-padded numbers for subdirectories
+        static string subDir(const label);
+
+    // Edit
+        static bool allowUndef(bool);
+
+        //- Assign the value to represent undef in the results
+        //  Returns the previous value
+        //  NB: do not use values larger than floatScalarVGREAT
+        static scalar undefValue(const scalar&);
+
+    // Output
+
+        //- binary write
+        virtual Ostream& write(const char* buf, std::streamsize count);
+
+        //- write element keyword with trailing newline, optionally with undef
+        virtual Ostream& writeKeyword(const string& key);
+
+        //- write "C Binary" for binary files (eg, geometry/measured)
+        Ostream& writeBinaryHeader();
+
+        //- write undef value
+        Ostream& writeUndef();
+
+        //- write string as "%80s" or as binary
+        Ostream& write(const string& value);
+
+        //- write integer as "%10d" or as binary
+        Ostream& write(const label& value);
+
+        //- write integer with specified width or as binary
+        Ostream& write(const label& value, const label fieldWidth);
+
+        //- write float as "%12.5e" or as binary
+        Ostream& write(const scalar& value);
+
+        //- Add carriage return to ascii stream
+        void newline();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightGeoFile.C b/src/conversion/ensight/file/ensightGeoFile.C
new file mode 100644
index 0000000000000000000000000000000000000000..72805f553c5eda67bf782ac23a41d0859dddc514
--- /dev/null
+++ b/src/conversion/ensight/file/ensightGeoFile.C
@@ -0,0 +1,70 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightGeoFile.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+
+// Construct from pathname
+Foam::ensightGeoFile::ensightGeoFile
+(
+    const fileName& pathname,
+    IOstream::streamFormat format
+)
+:
+    ensightFile(pathname, format)
+{
+    writeBinaryHeader();
+    write("Ensight Geometry File");  newline();
+    write("=====================");  newline();
+    write("node id assign");         newline();
+    write("element id assign");      newline();
+}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightGeoFile::~ensightGeoFile()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+// write keyword with trailing newline
+Foam::Ostream& Foam::ensightGeoFile::writeKeyword
+(
+    const string& key
+)
+{
+    write(key);
+    newline();
+
+    return *this;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightGeoFile.H b/src/conversion/ensight/file/ensightGeoFile.H
new file mode 100644
index 0000000000000000000000000000000000000000..1c91fa3218e79cf93830a1590b8fce9b35b1e6e9
--- /dev/null
+++ b/src/conversion/ensight/file/ensightGeoFile.H
@@ -0,0 +1,80 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightGeoFile
+
+Description
+    Specialized Ensight output with extra geometry file header
+
+\*---------------------------------------------------------------------------*/
+#ifndef ensightGeoFile_H
+#define ensightGeoFile_H
+
+#include "ensightFile.H"
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class ensightGeoFile Declaration
+\*---------------------------------------------------------------------------*/
+class ensightGeoFile
+:
+    public ensightFile
+{
+    //- Disallow default bitwise assignment
+    void operator=(const ensightGeoFile&);
+
+    //- Disallow default copy constructor
+    ensightGeoFile(const ensightGeoFile&);
+
+public:
+    // Constructors
+
+        //- Construct from pathname
+        ensightGeoFile
+        (
+            const fileName& pathname,
+            IOstream::streamFormat format=IOstream::BINARY
+        );
+
+    // Destructor
+        ~ensightGeoFile();
+
+    // Output
+
+        //- write keyword with trailing newline
+        virtual Ostream& writeKeyword(const string& key);
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPart.C b/src/conversion/ensight/part/ensightPart.C
new file mode 100644
index 0000000000000000000000000000000000000000..7d2fab6483790a6502d7f6ee4f7699b40df564eb
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPart.C
@@ -0,0 +1,231 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "ensightPart.H"
+#include "addToRunTimeSelectionTable.H"
+#include "dictionary.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+namespace Foam
+{
+   defineTypeNameAndDebug(ensightPart, 0);
+   defineTemplateTypeNameAndDebug(IOPtrList<ensightPart>, 0);
+   defineRunTimeSelectionTable(ensightPart, istream);
+}
+
+Foam::List<Foam::word> Foam::ensightPart::elemTypes_(0);
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+//- check for fully defined fields
+bool Foam::ensightPart::isFieldDefined
+(
+    const List<scalar>& field
+) const
+{
+    forAll(elemLists_, elemI)
+    {
+        const labelList& idList = elemLists_[elemI];
+
+        forAll(idList, i)
+        {
+            label id = idList[i];
+
+            if (id >= field.size() || isnan(field[id]))
+            {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Null constructor
+Foam::ensightPart::ensightPart
+()
+:
+    number_(0),
+    name_(""),
+    elemLists_(0),
+    offset_(0),
+    size_(0),
+    isCellData_(true),
+    matId_(0),
+    meshPtr_(0)
+{}
+
+
+// Construct empty part with number and description
+Foam::ensightPart::ensightPart
+(
+    label partNumber,
+    const string& partDescription
+)
+:
+    number_(partNumber),
+    name_(partDescription),
+    elemLists_(0),
+    offset_(0),
+    size_(0),
+    isCellData_(true),
+    matId_(0),
+    meshPtr_(0)
+{}
+
+
+// Construct empty part with number and description
+Foam::ensightPart::ensightPart
+(
+    label partNumber,
+    const string& partDescription,
+    const polyMesh& pMesh
+)
+:
+    number_(partNumber),
+    name_(partDescription),
+    elemLists_(0),
+    offset_(0),
+    size_(0),
+    isCellData_(true),
+    matId_(0),
+    meshPtr_(&pMesh)
+{}
+
+
+// Construct as copy
+Foam::ensightPart::ensightPart
+(
+    const ensightPart& part
+)
+:
+    number_(part.number_),
+    name_(part.name_),
+    elemLists_(part.elemLists_),
+    offset_(part.offset_),
+    size_(part.size_),
+    isCellData_(part.isCellData_),
+    matId_(part.matId_),
+    meshPtr_(part.meshPtr_)
+{}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+// runtime selection
+Foam::autoPtr<Foam::ensightPart> Foam::ensightPart::New(Istream& is)
+{
+    word partType(is);
+
+    istreamConstructorTable::iterator cstrIter =
+        istreamConstructorTablePtr_->find(partType);
+
+    if (cstrIter == istreamConstructorTablePtr_->end())
+    {
+        FatalIOErrorIn
+        (
+            "ensightPart::New(Istream&)",
+            is
+        )   << "unknown ensightPart type " << partType << endl << endl
+            << "Valid ensightPart types are :" << endl
+            << istreamConstructorTablePtr_->toc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<ensightPart>(cstrIter()(is));
+}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightPart::~ensightPart()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+// reconstruct from Istream
+void Foam::ensightPart::reconstruct(Istream& is)
+{
+    dictionary dict(is);
+    dict.lookup("id") >> number_;
+    dict.lookup("name") >> name_;
+    dict.readIfPresent("offset", offset_);
+
+    // populate elemLists_
+    elemLists_.setSize(elementTypes().size());
+
+    forAll(elementTypes(), elemI)
+    {
+        word key(elementTypes()[elemI]);
+        if (dict.found(key))
+        {
+            dict.lookup(key) >> elemLists_[elemI];
+        }
+        else
+        {
+            elemLists_[elemI].clear();
+        }
+        size_ += elemLists_[elemI].size();
+    }
+
+    is.check("ensightPart::reconstruct(Istream&)");
+}
+
+
+// renumber elements
+void Foam::ensightPart::renumber(labelList const& origId)
+{
+    // transform to global values first
+    if (offset_)
+    {
+        forAll(elemLists_, elemI)
+        {
+            labelList& idList = elemLists_[elemI];
+            forAll(idList, i)
+            {
+                idList[i] += offset_;
+            }
+        }
+
+        offset_ = 0;
+    }
+
+    if (origId.size())
+    {
+        forAll(elemLists_, elemI)
+        {
+            inplaceRenumber(origId, elemLists_[elemI]);
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPart.H b/src/conversion/ensight/part/ensightPart.H
new file mode 100644
index 0000000000000000000000000000000000000000..b3186eb3a1281f5b077025bef305dacb8c60dcb7
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPart.H
@@ -0,0 +1,353 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightPart
+
+Description
+    Base class for ensightPartCells and ensightPartFaces
+
+SourceFiles
+    ensightPart.C
+    ensightPartIO.C
+    ensightPartI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightPart_H
+#define ensightPart_H
+
+#include "ensightFile.H"
+#include "ensightGeoFile.H"
+#include "typeInfo.H"
+#include "labelList.H"
+#include "polyMesh.H"
+#include "Field.H"
+#include "IOPtrList.H"
+#include "IOstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class ensightPart Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightPart
+{
+    // Private data
+
+        // Static data members
+        static List<word> elemTypes_;
+
+    // Private Member Functions
+
+protected:
+    // Protected data
+
+        //- part number
+        label number_;
+
+        //- part name (or description)
+        string name_;
+
+        //- simple labelList with a name
+        labelListList elemLists_;
+
+        //- start offset for elemLists_
+        label offset_;
+
+        //- number of elements in this part
+        label size_;
+
+        //- cell or face data
+        bool isCellData_;
+
+        //- material id (numeric)
+        label matId_;
+
+        //- mesh reference used
+        const polyMesh* meshPtr_;
+
+    // Protected Classes
+
+        //- track the points used by the part and map global to local indices
+        class localPoints
+        {
+        public:
+            //- number of points used
+            label nPoints;
+
+            //- map global to local indices
+            labelList list;
+
+            // null constructor
+            localPoints()
+            :
+                nPoints(0),
+                list(0)
+            {}
+
+            // construct for mesh points
+            localPoints(const polyMesh& pMesh)
+            :
+                nPoints(0),
+                list(pMesh.points().size(), -1)
+            {}
+        };
+
+
+    // Protected Member Functions
+
+        //- reconstruct contents from Istream
+        void reconstruct(Istream&);
+
+        //- check for fully defined fields
+        bool isFieldDefined(const List<scalar>&) const;
+
+        //- write the part header
+        void writeHeader(ensightFile&, bool withDescription=false) const;
+
+        //- write a scalar field for idList
+        void writeFieldList
+        (
+            ensightFile& os,
+            const List<scalar>& field,
+            const labelList& idList
+        ) const;
+
+        //- track points used
+        virtual localPoints calcLocalPoints() const
+        {
+            return localPoints();
+        }
+
+        //- write connectivities
+        virtual void writeConnectivity
+        (
+            ensightGeoFile& os,
+            const string& key,
+            const labelList& idList,
+            const labelList& pointMap
+        ) const
+        {}
+
+public:
+
+    //- Runtime type information
+    TypeName("ensightPart");
+
+    // Public data
+
+    // Constructors
+
+        //- Construct null
+        ensightPart();
+
+        //- Construct empty part with number and description
+        ensightPart(label partNumber, const string& partDescription);
+
+        //- Construct empty part with number and description
+        ensightPart
+        (
+            label partNumber,
+            const string& partDescription,
+            const polyMesh& pMesh
+        );
+
+        //- Construct as copy
+        ensightPart(const ensightPart&);
+
+
+    // Selectors
+
+        // Declare run-time constructor selection table
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            ensightPart,
+            istream,
+            (
+                Istream& is
+            ),
+            (is)
+        );
+
+        //- Construct and return clone
+        autoPtr<ensightPart> clone() const
+        {
+            return autoPtr<ensightPart>(new ensightPart(*this));
+        };
+
+        //- Construct on freestore from Istream
+        static autoPtr<ensightPart> New(Istream& is);
+
+
+    // Destructor
+
+        virtual ~ensightPart();
+
+    // Static members
+
+        virtual List<word> const& elementTypes() const
+        {
+            return elemTypes_;
+        }
+
+    // Access
+
+        //- number of elements in this part
+        label size() const
+        {
+            return size_;
+        }
+
+        //- represents cell data
+        bool isCellData() const
+        {
+            return isCellData_;
+        }
+
+        //- represents face data
+        bool isFaceData() const
+        {
+            return !isCellData_;
+        }
+
+        //- part number
+        label number() const
+        {
+            return number_;
+        }
+
+        //- part name or description
+        const string& name() const
+        {
+            return name_;
+        }
+
+        //- material id
+        label materialId() const
+        {
+            return matId_;
+        }
+
+        //- non-const access
+        void name(const string& value)
+        {
+            name_ = value;
+        }
+
+        void materialId(const label value)
+        {
+            matId_ = value;
+        }
+
+        //- offset for element ids
+        label offset() const
+        {
+            return offset_;
+        }
+
+    // Edit
+
+        //- renumber elements
+        void renumber(labelList const&);
+
+        //- write summary information about the object
+        bool writeSummary(Ostream&) const;
+
+        //- write reconstruction information for the object
+        bool writeData(Ostream&) const;
+
+        //- write geometry
+        void writeGeometry(ensightGeoFile&) const;
+
+        //- write scalar field
+        void writeScalarField
+        (
+            ensightFile&,
+            const List<scalar>& field
+        ) const;
+
+        //- write vector field components
+        void writeVectorField
+        (
+            ensightFile&,
+            const List<scalar>& field0,
+            const List<scalar>& field1,
+            const List<scalar>& field2
+        ) const;
+
+
+        //- write generalized field components
+        template <class Type>
+        void writeField
+        (
+            ensightFile&,
+            const Field<Type>&
+        ) const;
+
+
+    // Member Operators
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPart&)
+        {
+            notImplemented("ensightPart::operator=(const ensightPart&)");
+        }
+
+
+    // IOstream Operators
+
+        //- write data (reconstruction information)
+        friend Ostream& operator<<(Ostream&, const ensightPart&);
+
+        //- write geometry
+        friend ensightGeoFile& operator<<
+        (
+            ensightGeoFile&,
+            const ensightPart&
+        );
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "ensightPartI.H"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartCells.C b/src/conversion/ensight/part/ensightPartCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..acbc02665e6b3c48f20eecfdc0022e97f4d7cf70
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartCells.C
@@ -0,0 +1,454 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "ensightPartCells.H"
+#include "addToRunTimeSelectionTable.H"
+#include "IOstream.H"
+#include "IStringStream.H"
+#include "dictionary.H"
+#include "cellModeller.H"
+
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+   defineTypeNameAndDebug(ensightPartCells, 0);
+   addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream);
+}
+
+// names for addressable ensight element types
+Foam::List<Foam::word> Foam::ensightPartCells::elemTypes_
+(
+    IStringStream
+    (
+        "(tetra4 pyramid5 penta6 hexa8 nfaced)"
+    )()
+);
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// classify the cell types, track the points used
+void Foam::ensightPartCells::classify
+(
+    const labelList& idList
+)
+{
+    // References to cell shape models
+    const cellModel& tet   = *(cellModeller::lookup("tet"));
+    const cellModel& pyr   = *(cellModeller::lookup("pyr"));
+    const cellModel& prism = *(cellModeller::lookup("prism"));
+    const cellModel& hex   = *(cellModeller::lookup("hex"));
+
+    const polyMesh& mesh = *meshPtr_;
+    const cellShapeList& cellShapes = mesh.cellShapes();
+
+    offset_ = 0;
+    size_ = mesh.nCells();
+
+    bool limited = false;
+    if (&idList)
+    {
+        limited = true;
+        size_ = idList.size();
+    }
+
+    // count the shapes
+    label nTet   = 0;
+    label nPyr   = 0;
+    label nPrism = 0;
+    label nHex   = 0;
+    label nPoly  = 0;
+
+
+    // TODO: allow tet-decomposition of polyhedral cells
+#if 0
+    label nTetDecomp = 0;
+    label nPyrDecomp = 0;
+#endif
+
+    for (label listI = 0; listI < size_; ++listI)
+    {
+        label cellId = listI;
+        if (limited)
+        {
+            cellId = idList[listI];
+        }
+
+        const cellShape& cellShape = cellShapes[cellId];
+        const cellModel& cellModel = cellShape.model();
+
+        if (cellModel == tet)
+        {
+            nTet++;
+        }
+        else if (cellModel == pyr)
+        {
+            nPyr++;
+        }
+        else if (cellModel == prism)
+        {
+            nPrism++;
+        }
+        else if (cellModel == hex)
+        {
+            nHex++;
+        }
+        else
+        {
+            nPoly++;
+
+            // TODO: allow tet-decomposition of polyhedral cells
+#if 0
+            const cell& cFaces = mesh.cells()[cellI];
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                label nQuads = 0;
+                label nTris = 0;
+                f.nTrianglesQuads(mesh.points(), nTris, nQuads);
+
+                nTetDecomp += nTris;
+                nPyrDecomp += nQuads;
+            }
+
+            nAddCells--;
+            nAddPoints++;
+#endif
+        }
+    }
+
+
+    // we can avoid double looping, but at the cost of allocation
+    labelList tetCells(nTet);
+    labelList pyramidCells(nPyr);
+    labelList prismCells(nPrism);
+    labelList hexCells(nHex);
+    labelList polyCells(nPoly);
+
+    nTet   = 0,
+    nPyr   = 0;
+    nPrism = 0;
+    nHex   = 0;
+    nPoly  = 0;
+
+    // classify the shapes
+    for (label listI = 0; listI < size_; ++listI)
+    {
+        label cellId = listI;
+        if (limited)
+        {
+            cellId = idList[listI];
+        }
+
+        const cellShape& cellShape = cellShapes[cellId];
+        const cellModel& cellModel = cellShape.model();
+
+        if (cellModel == tet)
+        {
+            tetCells[nTet++] = cellId;
+        }
+        else if (cellModel == pyr)
+        {
+            pyramidCells[nPyr++] = cellId;
+        }
+        else if (cellModel == prism)
+        {
+            prismCells[nPrism++] = cellId;
+        }
+        else if (cellModel == hex)
+        {
+            hexCells[nHex++] = cellId;
+        }
+        else
+        {
+            polyCells[nPoly++] = cellId;
+
+            // TODO: allow tet-decomposition of polyhedral cells
+#if 0
+            // Mapping from additional point to cell
+            addPointCellLabels_[api] = cellId;
+
+            const cell& cFaces = mesh.cells()[cellId];
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                label nQuads = 0;
+                label nTris = 0;
+                f.nTrianglesQuads(mesh.points(), nTris, nQuads);
+
+                nTetDecomp += nTris;
+                nPyrDecomp += nQuads;
+            }
+
+            nAddCells--;
+            nAddPoints++;
+#endif
+        }
+    }
+
+
+    // MUST match with elementTypes
+    elemLists_.setSize(elementTypes().size());
+
+    elemLists_[tetra4Elements].transfer( tetCells );
+    elemLists_[pyramid5Elements].transfer( pyramidCells );
+    elemLists_[penta6Elements].transfer( prismCells );
+    elemLists_[hexa8Elements].transfer( hexCells );
+    elemLists_[nfacedElements].transfer( polyCells );
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct empty part with number and description
+Foam::ensightPartCells::ensightPartCells
+(
+    label partNumber,
+    const string& partDescription
+)
+:
+    ensightPart(partNumber, partDescription)
+{}
+
+
+// Construct from polyMesh without zones
+Foam::ensightPartCells::ensightPartCells
+(
+    label partNumber,
+    const polyMesh& pMesh
+)
+:
+    ensightPart(partNumber, "cells", pMesh)
+{
+    classify();
+}
+
+
+// Construct from polyMesh and list of (non-zoned) cells
+Foam::ensightPartCells::ensightPartCells
+(
+    label partNumber,
+    const polyMesh& pMesh,
+    const labelList& idList
+)
+:
+    ensightPart(partNumber, "cells", pMesh)
+{
+    classify(idList);
+}
+
+
+// Construct from polyMesh and cellZone
+Foam::ensightPartCells::ensightPartCells
+(
+    label partNumber,
+    const polyMesh& pMesh,
+    const cellZone& cZone
+)
+:
+    ensightPart(partNumber, cZone.name(), pMesh)
+{
+    classify(cZone);
+}
+
+
+// Construct as copy
+Foam::ensightPartCells::ensightPartCells
+(
+    const ensightPartCells& part
+)
+:
+    ensightPart(part)
+{}
+
+
+// Construct from Istream
+Foam::ensightPartCells::ensightPartCells
+(
+    Istream& is
+)
+:
+    ensightPart()
+{
+    reconstruct(is);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+
+Foam::ensightPartCells::~ensightPartCells()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// track the points used
+Foam::ensightPart::localPoints Foam::ensightPartCells::calcLocalPoints() const
+{
+    const polyMesh& mesh = *meshPtr_;
+
+    localPoints ptList(mesh);
+    labelList& usedPoints = ptList.list;
+    label nPoints = 0;
+
+    forAll(elemLists_, typeI)
+    {
+        const labelList& idList = elemLists_[typeI];
+
+        // add all points from cells
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const labelList& cFaces = mesh.cells()[id];
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                forAll(f, fp)
+                {
+                    if (usedPoints[f[fp]] == -1)
+                    {
+                        usedPoints[f[fp]] = nPoints++;
+                    }
+                }
+            }
+        }
+    }
+
+    // this is not absolutely necessary, but renumber anyhow
+    nPoints = 0;
+    forAll(usedPoints, ptI)
+    {
+        if (usedPoints[ptI] > -1)
+        {
+            usedPoints[ptI] = nPoints++;
+        }
+    }
+
+    ptList.nPoints = nPoints;
+    return ptList;
+}
+
+
+// write cell connectivities
+void Foam::ensightPartCells::writeConnectivity
+(
+    ensightGeoFile& os,
+    const string& key,
+    const labelList& idList,
+    const labelList& pointMap
+) const
+{
+    os.writeKeyword(key);
+    os.write(idList.size());
+    os.newline();
+
+    const polyMesh& mesh = *meshPtr_;
+
+    // write polyhedral
+    if (word(key) == "nfaced")
+    {
+        const faceList& meshFaces = mesh.faces();
+
+        // write the number of faces per element
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const labelList& cFace = mesh.cells()[id];
+
+            os.write( cFace.size() );
+            os.newline();
+        }
+
+        // write the number of points per element face
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const labelList& cFace = mesh.cells()[id];
+
+            forAll(cFace, faceI)
+            {
+                const face& cf = meshFaces[cFace[faceI]];
+
+                os.write( cf.size() );
+                os.newline();
+            }
+        }
+
+        // write the points describing each element face
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const labelList& cFace = mesh.cells()[id];
+
+            forAll(cFace, faceI)
+            {
+                const face& cf = meshFaces[cFace[faceI]];
+
+                forAll(cf, ptI)
+                {
+                    // convert global -> local index
+                    // (note: Ensight indices start with 1)
+                    os.write( pointMap[cf[ptI]] + 1);
+                }
+                os.newline();
+            }
+        }
+    }
+    else
+    {
+        // write primitive
+        const cellShapeList& cellShapes = mesh.cellShapes();
+
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const cellShape& cellPoints = cellShapes[id];
+
+            // convert global -> local index
+            // (note: Ensight indices start with 1)
+            forAll(cellPoints, ptI)
+            {
+                os.write( pointMap[cellPoints[ptI]] + 1 );
+            }
+            os.newline();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartCells.H b/src/conversion/ensight/part/ensightPartCells.H
new file mode 100644
index 0000000000000000000000000000000000000000..a85b2778098c3951a368ca1ab87c65aeff85a97f
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartCells.H
@@ -0,0 +1,162 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightPartCells
+
+Description
+    An implementation of ensightPart to hold volume mesh cells.
+
+SourceFiles
+    ensightPartCells.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightPartCells_H
+#define ensightPartCells_H
+
+#include "ensightPart.H"
+#include "typeInfo.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class ensightPartCells Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightPartCells
+:
+    public ensightPart
+{
+    // Private data
+
+    // Private Member Functions
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPartCells&);
+
+        //- classify the cell types
+        void classify(const labelList& idLabels = labelList::null());
+
+        //- track points used
+        virtual localPoints calcLocalPoints() const;
+
+        //- track the points used
+        // virtual void makeLocalPointMap();
+
+        //- element connectivity
+        virtual void writeConnectivity
+        (
+            ensightGeoFile& os,
+            const string& key,
+            const labelList& idList,
+            const labelList& pointMap
+        ) const;
+
+protected:
+
+    //- addressable Ensight element types
+    enum elemType
+    {
+        tetra4Elements,
+        pyramid5Elements,
+        penta6Elements,
+        hexa8Elements,
+        nfacedElements
+    };
+
+    // Static data members
+    static List<word> elemTypes_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("ensightCells");
+
+    // Constructors
+
+        //- Construct empty part with number and description
+        ensightPartCells(label partNumber, const string& partDescription);
+
+        //- Construct from polyMesh without zones
+        ensightPartCells(label partNumber, const polyMesh&);
+
+        //- Construct from polyMesh and list of (non-zoned) cells
+        ensightPartCells
+        (
+            label partNumber,
+            const polyMesh&,
+            const labelList&
+        );
+
+        //- Construct from polyMesh and cellZone
+        ensightPartCells
+        (
+            label partNumber,
+            const polyMesh&,
+            const cellZone&
+        );
+
+        //- Construct as copy
+        ensightPartCells(const ensightPartCells&);
+
+        //- Construct from Istream
+        ensightPartCells(Istream&);
+
+        //- Construct on freestore from Istream
+        static autoPtr<ensightPartCells> New(Istream& is)
+        {
+            return autoPtr<ensightPartCells>(new ensightPartCells(is));
+        }
+
+
+    // Destructor
+
+        virtual ~ensightPartCells();
+
+
+    // Member Functions
+
+        //- static listing of the element types
+        virtual List<word> const& elementTypes() const
+        {
+            return elemTypes_;
+        }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartFaces.C b/src/conversion/ensight/part/ensightPartFaces.C
new file mode 100644
index 0000000000000000000000000000000000000000..79fd6ceed0b7a204fbaebd2b49b1b8c87bff08bc
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartFaces.C
@@ -0,0 +1,263 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "ensightPartFaces.H"
+#include "addToRunTimeSelectionTable.H"
+#include "IOstreams.H"
+#include "IStringStream.H"
+#include "dictionary.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+namespace Foam
+{
+   defineTypeNameAndDebug(ensightPartFaces, 0);
+   addToRunTimeSelectionTable(ensightPart, ensightPartFaces, istream);
+}
+
+// names for addressable ensight element types
+Foam::List<Foam::word> Foam::ensightPartFaces::elemTypes_
+(
+    IStringStream
+    (
+        "(tria3 quad4 nsided)"
+    )()
+);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct empty part with number and description
+Foam::ensightPartFaces::ensightPartFaces
+(
+    label partNumber,
+    const string& partDescription
+)
+:
+    ensightPart(partNumber, partDescription)
+{
+    isCellData_ = false;
+}
+
+
+// Construct from polyMesh and polyPatch
+Foam::ensightPartFaces::ensightPartFaces
+(
+    label partNumber,
+    const polyMesh& pMesh,
+    const polyPatch& pPatch
+)
+:
+    ensightPart(partNumber, pPatch.name(), pMesh)
+{
+    isCellData_ = false;
+    offset_ = pPatch.start();
+    size_ = pPatch.size();
+
+    // count the shapes
+    label nTri  = 0;
+    label nQuad = 0;
+    label nPoly = 0;
+
+    forAll (pPatch, patchfaceI)
+    {
+        const face& f = pMesh.faces()[patchfaceI + offset_];
+
+        if (f.size() == 3)
+        {
+            nTri++;
+        }
+        else if (f.size() == 4)
+        {
+            nQuad++;
+        }
+        else
+        {
+            nPoly++;
+        }
+    }
+
+    // we can avoid double looping, but at the cost of allocation
+
+    labelList triCells(nTri);
+    labelList quadCells(nQuad);
+    labelList polygonCells(nPoly);
+
+    nTri  = 0;
+    nQuad = 0;
+    nPoly = 0;
+
+    // classify the shapes
+    forAll(pPatch, patchfaceI)
+    {
+        const face& f = pMesh.faces()[patchfaceI + offset_];
+
+        if (f.size() == 3)
+        {
+            triCells[nTri++] = patchfaceI;
+        }
+        else if (f.size() == 4)
+        {
+            quadCells[nQuad++] = patchfaceI;
+        }
+        else
+        {
+            polygonCells[nPoly++] = patchfaceI;
+        }
+    }
+
+
+    // MUST match with elementTypes
+    elemLists_.setSize(elementTypes().size());
+
+    elemLists_[tria3Elements].transfer( triCells );
+    elemLists_[quad4Elements].transfer( quadCells );
+    elemLists_[nsidedElements].transfer( polygonCells );
+}
+
+
+
+// Construct as copy
+Foam::ensightPartFaces::ensightPartFaces
+(
+    const ensightPartFaces &part
+)
+:
+    ensightPart(part)
+{}
+
+
+// Construct from Istream
+Foam::ensightPartFaces::ensightPartFaces
+(
+    Istream& is
+)
+:
+    ensightPart()
+{
+    isCellData_ = false;
+    reconstruct(is);
+}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightPartFaces::~ensightPartFaces()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+// track the points used
+Foam::ensightPart::localPoints Foam::ensightPartFaces::calcLocalPoints() const
+{
+    const polyMesh& mesh = *meshPtr_;
+
+    localPoints ptList(mesh);
+    labelList& usedPoints = ptList.list;
+    label nPoints = 0;
+
+    forAll(elemLists_, typeI)
+    {
+        const labelList& idList = elemLists_[typeI];
+
+        // add all points from faces
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const face& f = mesh.faces()[id];
+
+            forAll(f, fp)
+            {
+                if (usedPoints[f[fp]] == -1)
+                {
+                    usedPoints[f[fp]] = nPoints++;
+                }
+            }
+        }
+    }
+
+    // this is not absolutely necessary, but renumber anyhow
+    nPoints = 0;
+    forAll(usedPoints, ptI)
+    {
+        if (usedPoints[ptI] > -1)
+        {
+            usedPoints[ptI] = nPoints++;
+        }
+    }
+
+    ptList.nPoints = nPoints;
+    return ptList;
+}
+
+
+// write face connectivities
+void Foam::ensightPartFaces::writeConnectivity
+(
+    ensightGeoFile& os,
+    const string& key,
+    const labelList& idList,
+    const labelList& pointMap
+) const
+{
+    os.writeKeyword(key);
+    os.write(idList.size());
+    os.newline();
+
+    const faceList& meshFaces = meshPtr_->faces();
+
+    // write (polygon) face sizes
+    if (word(key) == "nsided")
+    {
+        // write the number of points per face
+        forAll(idList, i)
+        {
+            label id = idList[i] + offset_;
+            const face& f = meshFaces[id];
+
+            os.write( f.size() );
+            os.newline();
+        }
+    }
+
+    // write the points describing the face
+    forAll(idList, i)
+    {
+        label id = idList[i] + offset_;
+        const face& f = meshFaces[id];
+
+        // convert global -> local index
+        // (note: Ensight indices start with 1)
+        forAll(f, fp)
+        {
+            os.write( pointMap[f[fp]] + 1 );
+        }
+        os.newline();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartFaces.H b/src/conversion/ensight/part/ensightPartFaces.H
new file mode 100644
index 0000000000000000000000000000000000000000..6f00e0fb567e2815078b1ebbfa6b03d4b88d9dc3
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartFaces.H
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightPartFaces
+
+Description
+    An implementation of ensightPart to hold volume mesh faces.
+
+SourceFiles
+    ensightPartFaces.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightPartFaces_H
+#define ensightPartFaces_H
+
+#include "ensightPart.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class ensightPartFaces Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightPartFaces
+:
+    public ensightPart
+{
+    // Private data
+
+    // Private Member Functions
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPartFaces&);
+
+        //- track points used
+        virtual localPoints calcLocalPoints() const;
+
+        //- element connectivity
+        virtual void writeConnectivity
+        (
+            ensightGeoFile& os,
+            const string& key,
+            const labelList& idList,
+            const labelList& pointMap
+        ) const;
+
+protected:
+
+    //- addressable ensight element types
+    enum elemType
+    {
+        tria3Elements,
+        quad4Elements,
+        nsidedElements
+    };
+
+    // Static data members
+    static List<word> elemTypes_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("ensightFaces");
+
+    // Constructors
+
+        //- Construct empty part with number and description
+        ensightPartFaces(label partNumber, const string& partDescription);
+
+        //- Construct from polyMesh and polyPatch
+        ensightPartFaces
+        (
+            label partNumber,
+            const polyMesh&,
+            const polyPatch&
+        );
+
+        //- Construct as copy
+        ensightPartFaces(const ensightPartFaces&);
+
+        //- Construct from Istream
+        ensightPartFaces(Istream&);
+
+        //- Construct on freestore from Istream
+        static autoPtr<ensightPartFaces> New(Istream& is)
+        {
+            return autoPtr<ensightPartFaces>(new ensightPartFaces(is));
+        }
+
+
+    // Destructor
+
+        virtual ~ensightPartFaces();
+
+
+    // Member Functions
+
+        //- static listing of the element types
+        virtual List<word> const& elementTypes() const
+        {
+            return elemTypes_;
+        }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartI.H b/src/conversion/ensight/part/ensightPartI.H
new file mode 100644
index 0000000000000000000000000000000000000000..6252fdc6baad339df61749ba05885c8d1035ff3a
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartI.H
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    Template to write generalized field components
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightPart.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+// write generalized field components
+template <class Type>
+void Foam::ensightPart::writeField
+(
+    ensightFile& os,
+    const Field<Type>& field
+) const
+{
+    if (size() && field.size())
+    {
+        writeHeader(os);
+
+        forAll(elementTypes(), elemI)
+        {
+            const labelList& idList = elemLists_[elemI];
+
+            if (idList.size())
+            {
+                os.writeKeyword( elementTypes()[elemI] );
+
+                for
+                (
+                    direction cmpt=0;
+                    cmpt < pTraits<Type>::nComponents;
+                    cmpt++
+                )
+                {
+                    writeFieldList(os, field.component(cmpt), idList);
+                }
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartIO.C b/src/conversion/ensight/part/ensightPartIO.C
new file mode 100644
index 0000000000000000000000000000000000000000..7bb6b3961aa36268990c37bddedcc747dafbce5f
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartIO.C
@@ -0,0 +1,264 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    Output for ensightPart
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightPart.H"
+#include "dictionary.H"
+#include "IOstreams.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// write the part header
+void Foam::ensightPart::writeHeader
+(
+    ensightFile& os,
+    bool withDescription
+) const
+{
+    os.write("part");
+    os.newline();
+
+    os.write(number() + 1);   // Ensight starts with 1
+    os.newline();
+
+    if (withDescription)
+    {
+        os.write(name());
+        os.newline();
+    }
+}
+
+
+// write scalar field for idList
+void Foam::ensightPart::writeFieldList
+(
+    ensightFile& os,
+    const List<scalar>& field,
+    const List<label>& idList
+) const
+{
+    forAll(idList, i)
+    {
+        if (idList[i] >= field.size() || isnan(field[idList[i]]))
+        {
+            os.writeUndef();
+        }
+        else
+        {
+            os.write(field[idList[i]]);
+        }
+
+        os.newline();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// write summary information about the object
+bool Foam::ensightPart::writeSummary
+(
+    Ostream& os
+) const
+{
+    os  << indent << type() << nl
+        << indent << token::BEGIN_BLOCK << incrIndent << nl;
+
+    // Ensight starts with 1
+    os.writeKeyword("id") << (number() + 1) << token::END_STATEMENT << nl;
+    os.writeKeyword("name") << name() << token::END_STATEMENT << nl;
+    os.writeKeyword("offset") << offset() << token::END_STATEMENT << nl;
+    os.writeKeyword("size") << size() << token::END_STATEMENT << nl;
+
+    os   << decrIndent << indent << token::END_BLOCK << nl << endl;
+
+    return true;
+}
+
+
+// write reconstruction information for the object
+bool Foam::ensightPart::writeData
+(
+    Ostream& os
+) const
+{
+    os  << indent << type() << nl
+        << indent << token::BEGIN_BLOCK << incrIndent << nl;
+
+    os.writeKeyword("id") << number() << token::END_STATEMENT << nl;
+    os.writeKeyword("name") << name() << token::END_STATEMENT << nl;
+    os.writeKeyword("offset") << offset() << token::END_STATEMENT << nl;
+
+    forAll(elementTypes(), typeI)
+    {
+        word key(elementTypes()[typeI]);
+        if (elemLists_[typeI].size())
+        {
+            elemLists_[typeI].writeEntry(key, os);
+        }
+    }
+
+    os   << decrIndent << indent << token::END_BLOCK << nl << endl;
+
+    return true;
+}
+
+
+
+// write geometry by components
+void Foam::ensightPart::writeGeometry
+(
+    ensightGeoFile& os
+) const
+{
+    if (size() && meshPtr_)
+    {
+        const polyMesh& mesh = *meshPtr_;
+        const pointField& meshPoints = mesh.points();
+
+        localPoints ptList = calcLocalPoints();
+        labelList& pointMap = ptList.list;
+
+        writeHeader(os, true);
+
+        // write points
+        os.writeKeyword("coordinates");
+        os.write(ptList.nPoints);
+        os.newline();
+
+        for (direction cmpt=0; cmpt < vector::nComponents; cmpt++)
+        {
+            forAll(pointMap, ptI)
+            {
+                if (pointMap[ptI] > -1)
+                {
+                    os.write( meshPoints[ptI].component(cmpt) );
+                    os.newline();
+                }
+            }
+        }
+
+        // write parts
+        forAll(elementTypes(), elemI)
+        {
+            if (elemLists_[elemI].size())
+            {
+                writeConnectivity
+                (
+                    os,
+                    elementTypes()[elemI],
+                    elemLists_[elemI],
+                    pointMap
+                );
+            }
+        }
+    }
+}
+
+
+// write scalar field
+void Foam::ensightPart::writeScalarField
+(
+    ensightFile& os,
+    const List<scalar>& field
+) const
+{
+    if (size() && field.size() && (os.allowUndef() || isFieldDefined(field)))
+    {
+        writeHeader(os);
+
+        forAll(elementTypes(), elemI)
+        {
+            const labelList& idList = elemLists_[elemI];
+
+            if (idList.size())
+            {
+                os.writeKeyword( elementTypes()[elemI] );
+                writeFieldList(os, field, idList);
+            }
+        }
+    }
+}
+
+
+// write vector field components
+void Foam::ensightPart::writeVectorField
+(
+    ensightFile& os,
+    const List<scalar>& field0,
+    const List<scalar>& field1,
+    const List<scalar>& field2
+) const
+{
+    if (size() && field0.size() && (os.allowUndef() || isFieldDefined(field0)))
+    {
+        writeHeader(os);
+
+        forAll(elementTypes(), elemI)
+        {
+            const labelList& idList = elemLists_[elemI];
+
+            if (idList.size())
+            {
+                os.writeKeyword( elementTypes()[elemI] );
+                writeFieldList(os, field0, idList);
+                writeFieldList(os, field1, idList);
+                writeFieldList(os, field2, idList);
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const ensightPart& part
+)
+{
+    part.writeData(os);
+    return os;
+}
+
+
+Foam::ensightGeoFile& Foam::operator<<
+(
+    ensightGeoFile& os,
+    const ensightPart& part
+)
+{
+    part.writeGeometry(os);
+    return os;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightParts.C b/src/conversion/ensight/part/ensightParts.C
new file mode 100644
index 0000000000000000000000000000000000000000..464205a9c85df77749453b21caa1d74320b43e6c
--- /dev/null
+++ b/src/conversion/ensight/part/ensightParts.C
@@ -0,0 +1,342 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "ensightParts.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from polyMesh
+Foam::ensightParts::ensightParts
+(
+    const polyMesh& pMesh
+)
+:
+    partsList_()
+{
+    recalculate(pMesh);
+}
+
+
+// Construct from IOobject
+Foam::ensightParts::ensightParts
+(
+    const IOobject& ioObj
+)
+:
+    partsList_()
+{
+    IOPtrList<ensightPart> ioList(ioObj);
+    partsList_.transfer(ioList);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightParts::~ensightParts()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// clear old information and construct anew from polyMesh
+void Foam::ensightParts::recalculate
+(
+    const polyMesh& pMesh
+)
+{
+    partsList_.clear();
+
+    // extra space for unzoned cells
+    label nPart =
+    (
+        pMesh.cellZones().size()
+      + pMesh.boundaryMesh().size()
+      + 1
+    );
+
+    partsList_.setSize(nPart);
+    nPart = 0;
+
+    label nZoneCells = 0;
+
+    // do cell zones
+    forAll(pMesh.cellZones(), zoneI)
+    {
+        const cellZone& cZone = pMesh.cellZones()[zoneI];
+        nZoneCells += cZone.size();
+
+        if (cZone.size())
+        {
+            partsList_.set
+            (
+                nPart,
+                new ensightPartCells
+                (
+                    nPart,
+                    pMesh,
+                    cZone
+                )
+            );
+
+            nPart++;
+        }
+    }
+
+    // collect unzoned cells
+
+    // special case: no zones at all - do entire mesh
+    if (nZoneCells == 0)
+    {
+        partsList_.set
+        (
+            nPart,
+            new ensightPartCells
+            (
+                nPart,
+                pMesh
+            )
+        );
+
+        nPart++;
+    }
+    else if (pMesh.nCells() > nZoneCells)
+    {
+        // determine which cells are not in a cellZone
+        labelList unzoned(pMesh.nCells(), -1);
+
+        forAll(pMesh.cellZones(), zoneI)
+        {
+            const labelList& idList = pMesh.cellZones()[zoneI];
+
+            forAll(idList, i)
+            {
+                unzoned[idList[i]] = idList[i];
+            }
+        }
+
+        label nUnzoned = 0;
+        forAll(unzoned, i)
+        {
+            if (unzoned[i] < 0)
+            {
+                unzoned[nUnzoned] = i;
+                nUnzoned++;
+            }
+        }
+        unzoned.setSize(nUnzoned);
+
+        if (unzoned.size())
+        {
+            partsList_.set
+            (
+                nPart,
+                new ensightPartCells
+                (
+                    nPart,
+                    pMesh,
+                    unzoned
+                )
+            );
+
+            nPart++;
+        }
+    }
+
+
+    // do boundaries, skipping empty and processor patches
+    forAll(pMesh.boundaryMesh(), patchI)
+    {
+        const polyPatch& pPatch = pMesh.boundaryMesh()[patchI];
+        if
+        (
+            pPatch.size()
+         && typeid(pPatch) != typeid(processorPolyPatch)
+        )
+        {
+            partsList_.set
+            (
+                nPart,
+                new ensightPartFaces
+                (
+                    nPart,
+                    pMesh,
+                    pPatch
+                )
+            );
+
+            nPart++;
+        }
+    }
+
+    // truncate to correct size
+    partsList_.setSize(nPart);
+}
+
+
+// renumber elements
+void Foam::ensightParts::renumber
+(
+    const labelList& origCellId,
+    const labelList& origFaceId
+)
+{
+    forAll(partsList_, partI)
+    {
+        if (partsList_[partI].isCellData())
+        {
+            partsList_[partI].renumber(origCellId);
+        }
+        else
+        {
+            partsList_[partI].renumber(origFaceId);
+        }
+    }
+}
+
+
+// write the geometry
+void Foam::ensightParts::writeGeometry
+(
+    ensightGeoFile& os
+) const
+{
+    // with some feedback
+    Info<< "write geometry part:" << nl << flush;
+
+    forAll(partsList_, partI)
+    {
+        Info<< " " << partI << flush;
+        partsList_[partI].writeGeometry(os);
+    }
+}
+
+
+// write summary information about the objects
+bool Foam::ensightParts::writeSummary
+(
+    Ostream& os
+) const
+{
+    forAll(partsList_, partI)
+    {
+        partsList_[partI].writeSummary(os);
+    }
+
+    return true;
+}
+
+
+void Foam::ensightParts::writeData
+(
+    Ostream& os
+) const
+{
+    // Write size of list
+    os << nl << partsList_.size();
+
+    // Write beginning of contents
+    os << nl << token::BEGIN_LIST;
+
+    // Write list contents
+    forAll(partsList_, i)
+    {
+        os << nl << partsList_[i];
+    }
+
+    // Write end of contents
+    os << nl << token::END_LIST << nl;
+
+    // Check state of IOstream
+    os.check("Ostream& operator<<(Ostream&, const PtrList&)");
+}
+
+
+// write scalar field
+void Foam::ensightParts::writeScalarField
+(
+    ensightFile& os,
+    const List<scalar>& field,
+    bool useFaceData
+) const
+{
+    forAll(partsList_, partI)
+    {
+        if
+        (
+            useFaceData
+          ? partsList_[partI].isFaceData()
+          : partsList_[partI].isCellData()
+        )
+        {
+            partsList_[partI].writeScalarField(os,field);
+        }
+    }
+}
+
+
+// write vector field components
+void Foam::ensightParts::writeVectorField
+(
+    ensightFile& os,
+    const List<scalar>& field0,
+    const List<scalar>& field1,
+    const List<scalar>& field2,
+    bool useFaceData
+) const
+{
+    forAll(partsList_, partI)
+    {
+        if
+        (
+            useFaceData
+          ? partsList_[partI].isFaceData()
+          : partsList_[partI].isCellData()
+        )
+        {
+            partsList_[partI].writeVectorField(os, field0, field1, field2);
+        }
+    }
+}
+
+// * * * * * * * * * * * * * * * Member operators  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * *  IOStream operators * * * * * * * * * * * //
+
+Foam::ensightGeoFile& Foam::operator<<
+(
+    ensightGeoFile& os,
+    const ensightParts& parts
+)
+{
+    parts.writeGeometry(os);
+    return os;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightParts.H b/src/conversion/ensight/part/ensightParts.H
new file mode 100644
index 0000000000000000000000000000000000000000..f4ca32d6ff80231db1fb64378668c4be29ed553d
--- /dev/null
+++ b/src/conversion/ensight/part/ensightParts.H
@@ -0,0 +1,158 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::ensightParts
+
+Description
+    A collection of several ensightPart elements
+
+SourceFiles
+    ensightParts.C
+    ensightPartsI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightParts_H
+#define ensightParts_H
+
+#include "ensightPart.H"
+#include "ensightPartFaces.H"
+#include "ensightPartCells.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class ensightParts Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightParts
+{
+    // Private Data
+
+        //- list of parts
+        PtrList<ensightPart> partsList_;
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        ensightParts(const ensightParts&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightParts&);
+
+public:
+
+    // Constructors
+
+        //- Construct from polyMesh
+        ensightParts(const polyMesh&);
+
+        //- Construct from IOobject
+        ensightParts(const IOobject&);
+
+    // Destructor
+
+        ~ensightParts();
+
+        //- clear old information and construct anew from polyMesh
+        void recalculate(const polyMesh&);
+
+        //- renumber elements
+        void renumber
+        (
+            const labelList& origCellId,
+            const labelList& origFaceId
+        );
+
+        //- number of parts
+        label size() const
+        {
+            return partsList_.size();
+        }
+
+        //- write the geometry
+        void writeGeometry(ensightGeoFile&) const;
+
+        //- write summary information about the objects
+        bool writeSummary(Ostream&) const;
+
+        //- write the lists
+        void writeData(Ostream&) const;
+
+        //- write scalar field
+        void writeScalarField
+        (
+            ensightFile&,
+            const List<scalar>& field,
+            bool useFaceData = false
+        ) const;
+
+        //- write vector field components
+        void writeVectorField
+        (
+            ensightFile&,
+            const List<scalar>& field0,
+            const List<scalar>& field1,
+            const List<scalar>& field2,
+            bool useFaceData = false
+        ) const;
+
+
+        //- write generalized field components
+        template <class Type>
+        void writeField
+        (
+            ensightFile&,
+            const GeometricField<Type, fvPatchField, volMesh>&
+        ) const;
+
+    // Friend Operators
+
+        friend ensightGeoFile& operator<<
+        (
+            ensightGeoFile&,
+            const ensightParts&
+        );
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "ensightPartsI.H"
+#endif
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartsI.H b/src/conversion/ensight/part/ensightPartsI.H
new file mode 100644
index 0000000000000000000000000000000000000000..bb5a915dec678a2099b066a9053fe75ba3ec6533
--- /dev/null
+++ b/src/conversion/ensight/part/ensightPartsI.H
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    Template to write generalized field components
+
+\*---------------------------------------------------------------------------*/
+#include "ensightParts.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// write generalized field components
+template <class Type>
+void Foam::ensightParts::writeField
+(
+    ensightFile& os,
+    const GeometricField<Type, fvPatchField, volMesh>& field
+) const
+{
+    // find offset to patch parts (ie, the first face data)
+    label patchOffset = 0;
+    forAll(partsList_, partI)
+    {
+        if (partsList_[partI].isFaceData())
+        {
+            patchOffset = partI;
+            break;
+        }
+    }
+
+    forAll(partsList_, partI)
+    {
+        label patchI = partI - patchOffset;
+
+        if (partsList_[partI].isCellData())
+        {
+            partsList_[partI].writeField
+            (
+                os,
+                field
+            );
+        }
+        else if (patchI < field.boundaryField().size())
+        {
+            partsList_[partI].writeField
+            (
+                os,
+                field.boundaryField()[patchI]
+            );
+        }
+    }
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/README b/src/conversion/meshReader/README
new file mode 100644
index 0000000000000000000000000000000000000000..bf24eb65a181fa838c6dd9313813480f4b0439be
--- /dev/null
+++ b/src/conversion/meshReader/README
@@ -0,0 +1,95 @@
+With pro-STAR version v4, the input formats have changed radically.
+  * Easier to parse space-delimited input formats
+  * No arbitrary or integral couples
+  * No trimmed or degenerate cells
+  * Support for polyhedral cells
+  * Boundaries are directly connected to cell and faces
+
+Since the boundaries are now connected directly to the faces,
+we now must be concerned with cell face notation otherwise we perform the
+incorrect lookup.
+Fortunately, there are only 4 primitive shapes to be concerned with.
+
+Hexa:
+   Foam                  pro-STAR
+   ~~~~~~~~~~~~~~        ~~~~~~~~~~~
+   Face 0 (0 4 7 3)  ->  F5: (0 4 7 3)
+   Face 1 (1 2 6 5)  ->  F6: (1 2 6 5)
+   Face 2 (0 1 5 4)  ->  F3: (0 1 5 4)
+   Face 3 (3 7 6 2)  ->  F4: (2 3 7 6)
+   Face 4 (0 3 2 1)  ->  F1: (0 3 2 1)
+   Face 5 (4 5 6 7)  ->  F2: (4 5 6 7)
+
+
+Prism:
+   Foam                  pro-STAR
+   ~~~~~~~~~~~~~~        ~~~~~~~~~~~
+   Face 0 (0 2 1)    ->  F1: (0 2 1)
+   Face 1 (3 4 5)    ->  F2: (3 4 5)
+   Face 2 (0 3 5 2)  ->  F5: (0 3 5 2)
+   Face 3 (1 2 5 4)  ->  F6: (1 2 5 4)
+   Face 4 (0 1 4 3)  ->  F3: (0 1 4 3)
+
+
+Tetra:
+   Foam                  pro-STAR
+   ~~~~~~~~~~~~~~        ~~~~~~~~~~~
+   Face 0 (1 2 3)    ->  F6: (1 2 3)
+   Face 1 (0 3 2)    ->  F5: (0 3 2)
+   Face 2 (0 1 3)    ->  F3: (0 1 3)
+   Face 3 (0 2 1)    ->  F1: (0 2 1)
+
+
+Pyramid:
+   Foam                  pro-STAR
+   ~~~~~~~~~~~~~~        ~~~~~~~~~~~
+   Face 0 (0 3 2 1)  ->  F1: (0 3 2 1)
+   Face 1 (0 4 3)    ->  F5: (0 4 3)
+   Face 2 (3 4 2)    ->  F4: (2 3 4)
+   Face 3 (1 2 4)    ->  F6: (1 2 4)
+   Face 4 (0 1 4)    ->  F3: (0 1 4)
+
+Noting that several faces are skipped over in the pro-STAR definitions,
+simply introducing a new cell modeller will be a problem.
+Instead, subtract 1 from the pro-STAR faces and use lookup tables.
+
+
+Here are the pro-STAR macro snippets used for creating the primitive cells:
+
+! hexa
+v 10 0 0 0
+v 11 1 0 0
+v 12 1 1 0
+v 13 0 1 0
+v 14 0 0 1
+v 15 1 0 1
+v 16 1 1 1
+v 17 0 1 1
+c hexa 10 11 12 13 14 15 16 17
+
+! prism
+v 20 0 0 0
+v 21 1 0 0
+v 22 1 1 0
+v 23 0 0 1
+v 24 1 0 1
+v 25 1 1 1
+c prism 20 21 22 23 24 25
+
+! tet
+v 30 0 0 0
+v 31 1 0 0
+v 32 1 1 0
+v 33 0.75 0.75 1
+c tetra 30 31 32 33
+
+! pyramid
+v 40 0 0 0
+v 41 1 0 0
+v 42 1 1 0
+v 43 0 1 0
+v 44 0.5 0.5 1
+c pyra 40 41 42 43 44
+
+! list faces
+flist all
diff --git a/src/conversion/meshReader/calcPointCells.C b/src/conversion/meshReader/calcPointCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..1b9c673d0eb4bdd63799e4ab1faea281b5edea04
--- /dev/null
+++ b/src/conversion/meshReader/calcPointCells.C
@@ -0,0 +1,183 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    calculate point cells - ie, the cells attached to each point
+
+    - remove unused points, adjust pointCells and cellFaces accordingly
+\*---------------------------------------------------------------------------*/
+
+#include "meshReader.H"
+
+// for transition - in case someone really relied on the old behaviour
+#undef LEAVE_UNUSED_POINTS
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+void Foam::meshReader::calcPointCells() const
+{
+    const static label UNIT_POINT_CELLS = 12;
+
+    if (pointCellsPtr_)
+    {
+        FatalErrorIn("meshReader::calcPointCells() const")
+            << "pointCells already calculated"
+            << abort(FatalError);
+    }
+
+    label nPoints = points().size();
+
+    pointCellsPtr_ = new labelListList(nPoints);
+    labelListList& ptCells = *pointCellsPtr_;
+
+    forAll(ptCells, i)
+    {
+        ptCells[i].setSize(UNIT_POINT_CELLS);
+    }
+
+    // Initialize the list of labels which will hold the count of the
+    // actual number of cells per point during the analysis
+    labelList cellCount(nPoints, 0);
+
+    // Note. Unlike the standard point-cell algorithm, which asks the cell for
+    // the supporting point labels, we need to work based on the cell faces.
+    // This is because some of the faces do not come from the cell shape.
+    // It is also advantageous to remove duplicates from the point-cell
+    // addressing, because this removes a lot of waste later.
+
+    faceListList& cFaces = cellFaces();
+
+    // For each cell
+    forAll(cFaces, cellI)
+    {
+        const faceList& faces = cFaces[cellI];
+
+        forAll(faces, i)
+        {
+            // For each vertex
+            const labelList& labels = faces[i];
+
+            forAll(labels, j)
+            {
+                // Set working point label
+                label curPoint = labels[j];
+                labelList& curPointCells = ptCells[curPoint];
+                label curCount = cellCount[curPoint];
+
+                // check if the cell has been added before
+                bool found = false;
+
+                for (label f = 0; f < curCount; f++)
+                {
+                    if (curPointCells[f] == cellI)
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (!found)
+                {
+                    // If the list of pointCells is not big enough, double it
+                    if (curPointCells.size() <= curCount)
+                    {
+                        curPointCells.setSize(curPointCells.size()*2);
+                    }
+
+                    // Enter the cell label in the point's cell list
+                    curPointCells[curCount] = cellI;
+
+                    // Increment the cell count for the point addressed
+                    cellCount[curPoint]++;
+                }
+            }
+        }
+    }
+
+    // report and remove unused points
+    // - adjust points, pointCells, and cellFaces accordingly
+    label pointI = 0;
+    labelList oldToNew(nPoints, -1);
+
+    forAll(ptCells, i)
+    {
+        ptCells[i].setSize(cellCount[i]);
+        if (cellCount[i] > 0)
+        {
+            oldToNew[i] = pointI++;
+        }
+    }
+
+    // report unused points
+    if (nPoints > pointI)
+    {
+#ifdef LEAVE_UNUSED_POINTS
+        FatalErrorIn("meshReader::calcPointCells() const")
+            << "mesh has " << (nPoints - pointI)
+            << " points that were declared but not used" << endl;
+#else
+
+        Info<< "removing " << (nPoints - pointI) << " unused points" << endl;
+
+        nPoints = pointI;
+
+        // adjust points and truncate
+        inplaceReorder(oldToNew, points());
+        points().setSize(nPoints);
+
+        // adjust pointCells and truncate
+        inplaceReorder(oldToNew, ptCells);
+        ptCells.setSize(nPoints);
+
+        // adjust cellFaces - this could be faster
+        // For each cell
+        forAll(cFaces, cellI)
+        {
+            faceList& faces = cFaces[cellI];
+
+            // For each face
+            forAll(faces, i)
+            {
+                inplaceRenumber(oldToNew, faces[i]);
+            }
+        }
+#endif
+    }
+}
+
+
+const Foam::labelListList& Foam::meshReader::pointCells() const
+{
+    if (!pointCellsPtr_)
+    {
+        calcPointCells();
+    }
+
+    return *pointCellsPtr_;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/createPolyBoundary.C b/src/conversion/meshReader/createPolyBoundary.C
new file mode 100644
index 0000000000000000000000000000000000000000..e25ead64c4e680b703edf30c25b74a82a4b30810
--- /dev/null
+++ b/src/conversion/meshReader/createPolyBoundary.C
@@ -0,0 +1,450 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    boundary faces
+    - use pointCells when searching for connectivity
+    - initialize the cell connectivity with '-1'
+    - find both cell faces corresponding to the baffles and mark them
+      to prevent a connection
+    - standard connectivity checks
+
+    - added baffle and monitoring support
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshReader.H"
+#include "Time.H"
+#include "polyPatch.H"
+#include "emptyPolyPatch.H"
+#include "preservePatchTypes.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// add in boundary face
+void Foam::meshReader::addPolyBoundaryFace
+(
+    const label cellId,
+    const label cellFaceId,
+    const label nCreatedFaces
+)
+{
+#ifdef DEBUG_BOUNDARY
+    Info<< nCreatedFaces
+        << " add bnd for cell " << cellId
+        << " face " << cellFaceId
+        << " (original cell " << origCellId_[cellId] << ")"
+        << endl;
+#endif
+
+    // standard case: volume cells
+    const face& thisFace = cellFaces_[cellId][cellFaceId];
+
+    // Debugging
+    if (cellPolys_[cellId][cellFaceId] > nInternalFaces_)
+    {
+        Info<< "meshReader::createPolyBoundary(): "
+            << "Problem with face: " << thisFace << endl
+            << "Probably multiple definitions "
+            << "of a single boundary face." << endl
+            << endl;
+    }
+    else if (cellPolys_[cellId][cellFaceId] >= 0)
+    {
+        Info<< "meshReader::createPolyBoundary(): "
+            << "Problem with face: " << thisFace << endl
+            << "Probably trying to define a boundary face "
+            << "on a previously matched internal face." << endl
+            << "Internal face: "
+            << meshFaces_[cellPolys_[cellId][cellFaceId]]
+            << endl;
+    }
+
+    meshFaces_[nCreatedFaces] = thisFace;
+    cellPolys_[cellId][cellFaceId] = nCreatedFaces;
+}
+
+
+// add in boundary face
+void Foam::meshReader::addPolyBoundaryFace
+(
+    const cellFaceIdentifier& identifier,
+    const label nCreatedFaces
+)
+{
+    addPolyBoundaryFace(identifier.cell, identifier.face, nCreatedFaces);
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+void Foam::meshReader::createPolyBoundary()
+{
+    label nBoundaryFaces = 0;
+    label nMissingFaces = 0;
+    label nInterfaces = 0;
+
+    const faceListList& cFaces = cellFaces();
+
+    // determine number of non-patched faces:
+    forAll(cellPolys_, cellI)
+    {
+        cell& curCell = cellPolys_[cellI];
+
+        forAll(curCell, fI)
+        {
+            if (curCell[fI] < 0)
+            {
+                nMissingFaces++;
+            }
+        }
+    }
+
+    forAll(boundaryIds_, patchI)
+    {
+        nBoundaryFaces += boundaryIds_[patchI].size();
+    }
+
+    Info<< nl
+        << "There are " << nMissingFaces
+        << " faces to be patched and " << nBoundaryFaces
+        << " specified - collect missed boundaries to final patch" << endl;
+
+    patchStarts_.setSize(boundaryIds_.size());
+    patchSizes_.setSize(boundaryIds_.size());
+
+    label nCreatedFaces = nInternalFaces_;
+    label baffleOffset  = cFaces.size();
+    interfaces_.setSize(baffleIds_.size());
+    nBoundaryFaces = 0;
+
+    forAll(boundaryIds_, patchI)
+    {
+        const List<cellFaceIdentifier>& idList = boundaryIds_[patchI];
+
+        patchStarts_[patchI] = nCreatedFaces;
+
+        // write each baffle side separately
+        if (patchPhysicalTypes_[patchI] == "baffle")
+        {
+            label count = 0;
+
+            for (label side = 0; side < 2; ++side)
+            {
+                label position = nInterfaces;
+
+                forAll(idList, bndI)
+                {
+                    label baffleI = idList[bndI].cell - baffleOffset;
+
+                    if
+                    (
+                        baffleI >= 0
+                     && baffleI < baffleFaces_.size()
+                     && baffleIds_[baffleI].size()
+                    )
+                    {
+                        addPolyBoundaryFace
+                        (
+                            baffleIds_[baffleI][side],
+                            nCreatedFaces
+                        );
+
+                        // remove applied boundaries (2nd pass)
+                        if (side == 1)
+                        {
+                            baffleIds_[baffleI].clear();
+                        }
+
+                        interfaces_[position][side] = nCreatedFaces;
+
+                        nBoundaryFaces++;
+                        nCreatedFaces++;
+                        position++;
+                        count++;
+                    }
+                }
+            }
+
+            nInterfaces += (count - (count % 2)) / 2;
+        }
+        else if (patchPhysicalTypes_[patchI] == "monitoring")
+        {
+            // translate the "monitoring" pseudo-boundaries to face sets
+            List<label> monitoring(idList.size());
+
+            label monitorI = 0;
+            forAll(idList, bndI)
+            {
+                label cellId = idList[bndI].cell;
+                label faceId = idList[bndI].face;
+
+                // standard case: volume cells
+                if (cellId < baffleOffset)
+                {
+                    label faceNr = cellPolys_[cellId][faceId];
+                    if (faceNr >= 0)
+                    {
+                        monitoring[monitorI++] = faceNr;
+                    }
+                }
+            }
+
+            monitoringSets_.insert(patchNames_[patchI], monitoring);
+        }
+        else
+        {
+            forAll(idList, bndI)
+            {
+                // standard case: volume cells
+                if (idList[bndI].cell < baffleOffset)
+                {
+                    addPolyBoundaryFace
+                    (
+                        idList[bndI],
+                        nCreatedFaces
+                    );
+
+                    nBoundaryFaces++;
+                    nCreatedFaces++;
+                }
+            }
+        }
+
+        patchSizes_[patchI] = nCreatedFaces - patchStarts_[patchI];
+    }
+
+    // add in missing faces
+    Info<< "Missing faces added to patch after face "
+        << nCreatedFaces << ":" <<endl;
+    nMissingFaces = 0;
+
+    // look for baffles first - keep them together at the start of the patch
+    for (label side = 0; side < 2; ++side)
+    {
+        label position = nInterfaces;
+
+        forAll(baffleIds_, baffleI)
+        {
+            if (baffleIds_[baffleI].size())
+            {
+                // add each side for each baffle
+                addPolyBoundaryFace
+                (
+                    baffleIds_[baffleI][side],
+                    nCreatedFaces
+                );
+
+                interfaces_[position][side] = nCreatedFaces;
+
+                // remove applied boundaries (2nd pass)
+                if (side == 1)
+                {
+                    baffleIds_[baffleI].clear();
+                }
+
+                nMissingFaces++;
+                nCreatedFaces++;
+                position++;
+            }
+        }
+    }
+
+    nInterfaces += (nMissingFaces - (nMissingFaces % 2)) / 2;
+
+    // scan for any other missing faces
+    forAll(cellPolys_, cellI)
+    {
+        const labelList& curFaces = cellPolys_[cellI];
+
+        forAll(curFaces, cellFaceI)
+        {
+            if (curFaces[cellFaceI] < 0)
+            {
+                // just report the first few
+                if (nMissingFaces < 4)
+                {
+                    const face& thisFace = cFaces[cellI][cellFaceI];
+
+                    Info<< "  cell " << cellI << " face " << cellFaceI
+                        << " (original cell " << origCellId_[cellI] << ")"
+                        << " face: " << thisFace
+                        << endl;
+                }
+                else if (nMissingFaces == 5)
+                {
+                    Info<< "  ..." << nl << endl;
+                }
+
+                addPolyBoundaryFace(cellI, cellFaceI, nCreatedFaces);
+                nMissingFaces++;
+                nCreatedFaces++;
+            }
+        }
+    }
+
+    Info<< "Added " << nMissingFaces << " unmatched faces" << endl;
+
+    if (nMissingFaces > 0)
+    {
+        patchSizes_[patchSizes_.size() - 1] = nMissingFaces;
+    }
+    else
+    {
+        patchStarts_.setSize(patchStarts_.size() - 1);
+    }
+
+    // reset the size of the face list
+    meshFaces_.setSize(nCreatedFaces);
+
+    // check the mesh for face mismatch
+    // (faces addressed once or more than twice)
+    labelList markupFaces(meshFaces_.size(), 0);
+
+    forAll(cellPolys_, cellI)
+    {
+        const labelList& curFaces = cellPolys_[cellI];
+
+        forAll(curFaces, faceI)
+        {
+            markupFaces[curFaces[faceI]]++;
+        }
+    }
+
+    for (label i = nInternalFaces_; i < markupFaces.size(); i++)
+    {
+        markupFaces[i]++;
+    }
+
+    label nProblemFaces = 0;
+
+    forAll(markupFaces, faceI)
+    {
+        if (markupFaces[faceI] != 2)
+        {
+            const face& problemFace = meshFaces_[faceI];
+
+            Info<< "meshReader::createPolyBoundary() : "
+                << "problem with face " << faceI << ": addressed "
+                << markupFaces[faceI] << " times (should be 2!). Face: "
+                << problemFace << endl;
+
+            nProblemFaces++;
+        }
+    }
+
+    if (nProblemFaces > 0)
+    {
+        Info<< "Number of incorrectly matched faces: "
+            << nProblemFaces << endl;
+    }
+
+    // adjust for missing members
+    if (nInterfaces < interfaces_.size())
+    {
+        interfaces_.setSize(nInterfaces);
+    }
+
+    Info<< "Number of boundary faces: " << nBoundaryFaces << nl
+        << "Total number of faces: " << nCreatedFaces << nl
+        << "Number of interfaces: " << nInterfaces << endl;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+Foam::List<Foam::polyPatch*>
+Foam::meshReader::polyBoundaryPatches(const polyMesh& mesh)
+{
+    label nUsed = 0, nEmpty = 0;
+    label nPatches = patchStarts_.size();
+
+    // avoid empty patches - move to the end of the lists and truncate
+    labelList oldToNew = identity(nPatches);
+    forAll(patchSizes_, patchI)
+    {
+        if (patchSizes_[patchI] > 0)
+        {
+            oldToNew[patchI] = nUsed++;
+        }
+        else
+        {
+            nEmpty++;
+            oldToNew[patchI] = nPatches - nEmpty;
+        }
+    }
+
+    nPatches = nUsed;
+
+    if (nEmpty)
+    {
+        Info<< "Removing " << nEmpty << " empty patches" << endl;
+
+        inplaceReorder(oldToNew, patchTypes_);
+        inplaceReorder(oldToNew, patchNames_);
+        inplaceReorder(oldToNew, patchStarts_);
+        inplaceReorder(oldToNew, patchSizes_);
+    }
+
+    patchTypes_.setSize(nPatches);
+    patchNames_.setSize(nPatches);
+    patchStarts_.setSize(nPatches);
+    patchSizes_.setSize(nPatches);
+
+
+    List<polyPatch*> p(nPatches);
+
+    // Default boundary patch types
+    word defaultFacesType(emptyPolyPatch::typeName);
+
+    // we could consider dropping this entirely
+    preservePatchTypes
+    (
+        mesh,
+        mesh.instance(),
+        mesh.meshDir(),
+        patchNames_,
+        patchTypes_,
+        "defaultFaces",
+        defaultFacesType,
+        patchPhysicalTypes_
+    );
+
+    forAll(patchStarts_, patchI)
+    {
+        p[patchI] = polyPatch::New
+        (
+            patchTypes_[patchI],
+            patchNames_[patchI],
+            patchSizes_[patchI],
+            patchStarts_[patchI],
+            patchI,
+            mesh.boundaryMesh()
+        ).ptr();
+    }
+
+    return p;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/createPolyCells.C b/src/conversion/meshReader/createPolyCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..ca9622cbf2e14cf6358bc610cb902dd0e62af3e0
--- /dev/null
+++ b/src/conversion/meshReader/createPolyCells.C
@@ -0,0 +1,330 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    create cellPolys
+    - use pointCells when searching for connectivity
+    - initialize the cell connectivity with '-1'
+    - find both cell faces corresponding to the baffles and mark them
+      to prevent a connection
+    - standard connectivity checks
+
+    - added baffle support
+\*---------------------------------------------------------------------------*/
+
+#include "meshReader.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+void Foam::meshReader::createPolyCells()
+{
+    // loop through all cell faces and create connectivity. This will produce
+    // a global face list and will describe all cells as lists of face labels
+
+    const faceListList& cFaces = cellFaces();
+
+    // count the maximum number of faces and set the size of the cellPolys_
+    cellPolys_.setSize(cFaces.size());
+
+    label maxFaces = 0;
+
+    forAll(cellPolys_, cellI)
+    {
+        cellPolys_[cellI].setSize(cFaces[cellI].size(), -1);
+
+        maxFaces += cFaces[cellI].size();
+    }
+
+    Info<< "Maximum possible number of faces in mesh: " << maxFaces << endl;
+
+    meshFaces_.setSize(maxFaces);
+
+    // set reference to point-cell addressing
+    const labelListList& ptCells = pointCells();
+
+    // size the baffle lists and initialize to -1
+    baffleIds_.setSize(baffleFaces_.size());
+    forAll(baffleIds_, baffleI)
+    {
+        baffleIds_[baffleI].setSize(2);
+    }
+
+    // block off baffles first
+    //
+    // To prevent internal faces, we'll mark the cell faces
+    // with negative cell ids (offset by nCells).
+    // eg,
+    //    cellI = -(nCells + baffleI)
+    //
+    // To distinguish these from the normal '-1' marker, we require
+    //    cellI = -(nCells + baffleI) < -1
+    //
+    // This condition is met provided that nCells > 1.
+    // ie., baffles require at least 2 volume cells
+
+    label baffleOffset = cFaces.size();
+    forAll(baffleFaces_, baffleI)
+    {
+        label cellI = -(baffleOffset + baffleI);
+        const face& curFace = baffleFaces_[baffleI];
+
+        // get the list of labels
+        const labelList& curPoints = curFace;
+
+        // a baffle is a single face - only need to match one face
+        // get the list of cells sharing this point
+        const labelList& curNeighbours = ptCells[curPoints[0]];
+
+        label nNeighbours = 0;
+
+        // For all neighbours
+        forAll(curNeighbours, neiI)
+        {
+            label curNei = curNeighbours[neiI];
+
+            // get the list of search faces
+            const faceList& searchFaces = cFaces[curNei];
+
+            forAll(searchFaces, neiFaceI)
+            {
+                int cmp = face::compare(curFace, searchFaces[neiFaceI]);
+
+                if (cmp)
+                {
+                    // maintain baffle orientation
+                    // side0: baffle normal same as attached face
+                    // side1: baffle normal opposite from attached face
+                    //
+                    label side = 0;
+                    if (cmp < 0)
+                    {
+                        side = 1;
+                    }
+
+#ifdef DEBUG_FACE_ORDERING
+                    Info<< "cmp " << cmp << " matched " << curFace
+                        << " with " << searchFaces[neiFaceI]
+                        << endl;
+
+
+                    Info<< "match " << baffleI
+                        << " (" << origCellId_[baffleOffset+baffleI] << ")"
+                        << " side " << side
+                        << " against cell " << curNei
+                        << " face " << neiFaceI
+                        << " curFace " << curFace[1]
+                        << " neiFace " << searchFaces[neiFaceI][1]
+                        << endl;
+#endif
+
+                    if (baffleIds_[baffleI][side].unused())
+                    {
+                        baffleIds_[baffleI][side] = cellFaceIdentifier
+                        (
+                            curNei,
+                            neiFaceI
+                        );
+
+                        nNeighbours++;
+                    }
+                    else
+                    {
+                        Info<< "multiple matches for side " << side
+                            << " of baffle " << baffleI
+                            << " (original cell "
+                            << origCellId_[baffleOffset+baffleI] << ")"
+                            << endl;
+                    }
+                    break;
+                }
+            }
+            if (nNeighbours >= 2) break;
+        }
+
+        if (nNeighbours == 2)
+        {
+            for (label side = 0; side < nNeighbours; ++side)
+            {
+                label neiCell = baffleIds_[baffleI][side].cell;
+                label neiFace = baffleIds_[baffleI][side].face;
+
+                if (baffleIds_[baffleI][side].used())
+                {
+                    cellPolys_[neiCell][neiFace] = cellI;
+                }
+            }
+        }
+        else
+        {
+            Info<< "drop baffle " << baffleI
+                << " (original cell "
+                << origCellId_[baffleOffset+baffleI] << ")"
+                << " with " << nNeighbours << " neighbours" << endl;
+
+            baffleFaces_[baffleI].clear();
+            baffleIds_[baffleI].clear();
+        }
+    }
+
+#ifdef DEBUG_CELLPOLY
+    Info<< "cellPolys_" << cellPolys_ << endl;
+    Info<< "baffleFaces_" << baffleFaces_ << endl;
+    Info<< "baffleIds_"   << baffleIds_ << endl;
+#endif
+
+    bool found = false;
+
+    nInternalFaces_ = 0;
+
+    forAll(cFaces, cellI)
+    {
+        // Note:
+        // Insertion cannot be done in one go as the faces need to be
+        // added into the list in the increasing order of neighbour
+        // cells.  Therefore, all neighbours will be detected first
+        // and then added in the correct order.
+
+        const faceList& curFaces = cFaces[cellI];
+
+        // Record the neighbour cell
+        labelList neiCells(curFaces.size(), -1);
+
+        // Record the face of neighbour cell
+        labelList faceOfNeiCell(curFaces.size(), -1);
+
+        label nNeighbours = 0;
+
+        // For all faces ...
+        forAll(curFaces, faceI)
+        {
+            // Skip already matched faces or those tagged by baffles
+            if (cellPolys_[cellI][faceI] != -1) continue;
+
+            found = false;
+
+            const face& curFace = curFaces[faceI];
+
+            // get the list of labels
+            const labelList& curPoints = curFace;
+
+            // For all points
+            forAll(curPoints, pointI)
+            {
+                // get the list of cells sharing this point
+                const labelList& curNeighbours = ptCells[curPoints[pointI]];
+
+                // For all neighbours
+                forAll(curNeighbours, neiI)
+                {
+                    label curNei = curNeighbours[neiI];
+
+                    // reject neighbours with the lower label. This should
+                    // also reject current cell.
+                    if (curNei > cellI)
+                    {
+                        // get the list of search faces
+                        const faceList& searchFaces = cFaces[curNei];
+
+                        forAll(searchFaces, neiFaceI)
+                        {
+                            if (searchFaces[neiFaceI] == curFace)
+                            {
+                                // Record the neighbour cell and face
+                                neiCells[faceI] = curNei;
+                                faceOfNeiCell[faceI] = neiFaceI;
+                                nNeighbours++;
+#ifdef DEBUG_FACE_ORDERING
+                                Info<< " cell " << cellI
+                                    << " face " << faceI
+                                    << " point " << pointI
+                                    << " nei " << curNei
+                                    << " neiFace " << neiFaceI
+                                    << endl;
+#endif
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (found) break;
+                    }
+                    if (found) break;
+                }
+                if (found) break;
+            } // End of current points
+        } // End of current faces
+
+        // Add the faces in the increasing order of neighbours
+        for (label neiSearch = 0; neiSearch < nNeighbours; neiSearch++)
+        {
+            // Find the lowest neighbour which is still valid
+            label nextNei = -1;
+            label minNei = cellPolys_.size();
+
+            forAll(neiCells, ncI)
+            {
+                if (neiCells[ncI] > -1 && neiCells[ncI] < minNei)
+                {
+                    nextNei = ncI;
+                    minNei = neiCells[ncI];
+                }
+            }
+
+            if (nextNei > -1)
+            {
+                // Add the face to the list of faces
+                meshFaces_[nInternalFaces_] = curFaces[nextNei];
+
+                // Mark for owner
+                cellPolys_[cellI][nextNei] = nInternalFaces_;
+
+                // Mark for neighbour
+                cellPolys_[neiCells[nextNei]][faceOfNeiCell[nextNei]] =
+                    nInternalFaces_;
+
+                // Stop the neighbour from being used again
+                neiCells[nextNei] = -1;
+
+                // Increment number of faces counter
+                nInternalFaces_++;
+            }
+            else
+            {
+              FatalErrorIn("meshReader::createPolyCells()")
+                  << "Error in internal face insertion"
+                  << abort(FatalError);
+            }
+        }
+    }
+
+#ifdef DEBUG_CELLPOLY
+    Info<< "cellPolys = " << cellPolys_ << endl;
+#endif
+
+    // don't reset the size of internal faces, because more faces will be
+    // added in createPolyBoundary()
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/meshReader.C b/src/conversion/meshReader/meshReader.C
new file mode 100644
index 0000000000000000000000000000000000000000..08a8a9886abf74a05898c90b7fbf4df2c052a800
--- /dev/null
+++ b/src/conversion/meshReader/meshReader.C
@@ -0,0 +1,254 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshReader.H"
+#include "Time.H"
+#include "polyMesh.H"
+#include "faceSet.H"
+#include "emptyPolyPatch.H"
+#include "cellModeller.H"
+#include "demandDrivenData.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// Pointers to cell shape models
+const Foam::cellModel* Foam::meshReader::unknownModel = Foam::cellModeller::
+lookup
+(
+    "unknown"
+);
+
+const Foam::cellModel* Foam::meshReader::tetModel = Foam::cellModeller::
+lookup
+(
+    "tet"
+);
+
+const Foam::cellModel* Foam::meshReader::pyrModel = Foam::cellModeller::
+lookup
+(
+    "pyr"
+);
+
+const Foam::cellModel* Foam::meshReader::prismModel = Foam::cellModeller::
+lookup
+(
+    "prism"
+);
+
+const Foam::cellModel* Foam::meshReader::hexModel = Foam::cellModeller::
+lookup
+(
+    "hex"
+);
+
+// * * * * * * * * * * * * * * Static Functions  * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// attach cellZones based on the cellTable Id
+// - any other values can be extracted later from the cellTable dictionary
+void Foam::meshReader::addCellZones
+(
+    polyMesh& mesh
+) const
+{
+    cellTable_.addCellZones(mesh, cellTableId_);
+    warnDuplicates("cellZones", mesh.cellZones().names());
+}
+
+
+// attach faceZones based on the monitoring boundary conditions
+void Foam::meshReader::addFaceZones
+(
+    polyMesh& mesh
+) const
+{
+    label nZone = monitoringSets_.size();
+    mesh.faceZones().setSize(nZone);
+
+    if (!nZone)
+    {
+        return;
+    }
+
+    nZone = 0;
+    for
+    (
+        HashTable<List<label>, word, string::hash>::const_iterator
+        iter = monitoringSets_.begin();
+        iter != monitoringSets_.end();
+        ++iter
+    )
+    {
+        Info<< "faceZone " << nZone
+            << " (size: " << iter().size() << ") name: "
+            << iter.key() << endl;
+
+        mesh.faceZones().set
+        (
+            nZone,
+            new faceZone
+            (
+                iter.key(),
+                iter(),
+                List<bool>(iter().size(), false),
+                nZone,
+                mesh.faceZones()
+            )
+        );
+
+        nZone++;
+    }
+    mesh.faceZones().writeOpt() = IOobject::AUTO_WRITE;
+    warnDuplicates("faceZones", mesh.faceZones().names());
+}
+
+
+// create and access the polyMesh
+Foam::autoPtr<Foam::polyMesh> Foam::meshReader::mesh
+(
+    const objectRegistry& registry
+)
+{
+    readGeometry();
+
+    Info<< "Creating a polyMesh" << endl;
+    createPolyCells();
+
+    Info<< "Number of internal faces: " << nInternalFaces_ << endl;
+
+    createPolyBoundary();
+    clearExtraStorage();
+
+    autoPtr<polyMesh> mesh
+    (
+        new polyMesh
+        (
+            IOobject
+            (
+                polyMesh::defaultRegion,
+                "constant",
+                registry
+            ),
+            points(),
+            meshFaces_,
+            cellPolys_
+        )
+    );
+
+    // adding patches also checks the mesh
+    mesh().addPatches(polyBoundaryPatches(mesh));
+
+    warnDuplicates("boundaries", mesh().boundaryMesh().names());
+
+    addCellZones(mesh());
+    addFaceZones(mesh());
+
+    return mesh;
+}
+
+
+//- write the polyMesh
+void Foam::meshReader::writeMesh
+(
+    const polyMesh& mesh,
+    IOstream::streamFormat fmt
+) const
+{
+    fileName meshDir = mesh.objectRegistry::path()/mesh.meshDir();
+
+    // remove some directories and files - this should be easier
+    mesh.removeFiles(mesh.instance());
+    if (dir(meshDir/"sets"))
+    {
+        rmDir(meshDir/"sets");
+    }
+
+    Info<< "Writing polyMesh" << endl;
+    mesh.writeObject
+    (
+        fmt,
+        IOstream::currentVersion,
+        IOstream::UNCOMPRESSED
+    );
+    writeAux(mesh);
+}
+
+
+// Clear extra storage before creation of the mesh to reduce the memory usage
+void Foam::meshReader::clearExtraStorage()
+{
+    cellFaces_.clear();
+    baffleFaces_.clear();
+    boundaryIds_.clear();
+    baffleIds_.clear();
+
+    deleteDemandDrivenData(pointCellsPtr_);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshReader::meshReader
+(
+    const fileName& fileOrPrefix,
+    const scalar scaleFactor
+)
+    :
+    pointCellsPtr_(NULL),
+    nInternalFaces_(0),
+    patchStarts_(0),
+    patchSizes_(0),
+    interfaces_(0),
+    baffleIds_(0),
+    meshFaces_(0),
+    cellPolys_(0),
+    geometryFile_(fileOrPrefix),
+    scaleFactor_(scaleFactor),
+    points_(0),
+    origCellId_(0),
+    boundaryIds_(0),
+    patchTypes_(0),
+    patchNames_(0),
+    patchPhysicalTypes_(0),
+    cellFaces_(0),
+    baffleFaces_(0),
+    cellTableId_(0),
+    cellTable_()
+{}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::meshReader::~meshReader()
+{
+    deleteDemandDrivenData(pointCellsPtr_);
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/meshReader.H b/src/conversion/meshReader/meshReader.H
new file mode 100644
index 0000000000000000000000000000000000000000..171c547756db7cde3c09b2783059ea5115d8b83a
--- /dev/null
+++ b/src/conversion/meshReader/meshReader.H
@@ -0,0 +1,319 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Namespace
+    Foam::meshReaders
+
+Description
+    A namespace for holding various types of mesh readers.
+
+
+Class
+    Foam::meshReader
+
+Description
+    This class supports creating polyMeshes with baffles.
+
+    The derived classes are responsible for providing the protected data.
+    This implementation is somewhat messy, but could/should be restructured
+    to provide a more generalized reader (at the moment it has been written
+    for converting pro-STAR data).
+
+    The meshReader supports cellTable information (see new user's guide entry).
+
+Note
+    The boundary definitions are given as cell/face.
+
+SourceFiles
+    calcPointCells.C
+    createPolyBoundary.C
+    createPolyCells.C
+    meshReader.C
+    meshReaderAux.C
+\*---------------------------------------------------------------------------*/
+
+#ifndef meshReader_H
+#define meshReader_H
+
+#include "polyMesh.H"
+#include "HashTable.H"
+#include "IOstream.H"
+
+#include "cellTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class meshReader Declaration
+\*---------------------------------------------------------------------------*/
+
+class meshReader
+{
+protected:
+    //- identify cell faces in terms of cell Id and face Id
+    class cellFaceIdentifier
+    {
+    public:
+        //- cell Id
+        label cell;
+
+        //- face Id
+        label face;
+
+        //- Construct null
+        cellFaceIdentifier() : cell(-1), face(-1) {}
+
+        //- Construct from cell/face components
+        cellFaceIdentifier(label c, label f) : cell(c), face(f) {}
+
+        // Check
+
+        //- used if cell or face are non-negative
+        bool used() const
+        {
+            return (cell >= 0 && face >= 0);
+        }
+
+        //- unsed if cell or face are negative
+        bool unused() const
+        {
+            return (cell < 0 || face < 0);
+        }
+
+        // Member Operators
+        bool operator!=(const cellFaceIdentifier& cf) const
+        {
+            return (cell != cf.cell || face != cf.face);
+        }
+
+        bool operator==(const cellFaceIdentifier& cf) const
+        {
+            return (cell == cf.cell && face == cf.face);
+        }
+
+        // IOstream Operators
+        friend Ostream& operator<<(Ostream& os, const cellFaceIdentifier& cf)
+        {
+            os << "(" << cf.cell << "/" << cf.face << ")";
+            return os;
+        }
+    };
+
+private:
+
+    // Private data
+
+        //- Point-cell addressing. Used for topological analysis
+        // Warning. This point cell addressing list potentially contains
+        // duplicate cell entries. Use additional checking
+        mutable labelListList* pointCellsPtr_;
+
+        //- Number of internal faces for polyMesh
+        label nInternalFaces_;
+
+        //- Polyhedral mesh boundary patch start indices and dimensions
+        labelList patchStarts_;
+        labelList patchSizes_;
+
+        //- association between two faces
+        List<labelPair> interfaces_;
+
+        //- list of cells/faces id pairs for each baffle
+        List<List<cellFaceIdentifier> > baffleIds_;
+
+        //- Global face list for polyMesh
+        faceList meshFaces_;
+
+        //- Cells as polyhedra for polyMesh
+        cellList cellPolys_;
+
+        //- Face sets for monitoring
+        HashTable<List<label>, word, string::hash> monitoringSets_;
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        meshReader(const meshReader&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const meshReader&);
+
+        //- Calculate pointCells
+        void calcPointCells() const;
+
+        const labelListList& pointCells() const;
+
+        //- Make polyhedral cells and global faces if the mesh is polyhedral
+        void createPolyCells();
+
+        //- add in boundary face
+        void addPolyBoundaryFace
+        (
+            const label cellId,
+            const label cellFaceId,
+            const label nCreatedFaces
+        );
+
+        //- add in boundary face
+        void addPolyBoundaryFace
+        (
+            const cellFaceIdentifier& identifier,
+            const label nCreatedFaces
+        );
+
+        //- add cellZones based on cellTable Id
+        void addCellZones(polyMesh&) const;
+
+        //- add faceZones based on monitoring boundary conditions
+        void addFaceZones(polyMesh&) const;
+
+        //- Make polyhedral boundary from shape boundary
+        // (adds more faces to the face list)
+        void createPolyBoundary();
+
+        //- Add polyhedral boundary
+        List<polyPatch*> polyBoundaryPatches(const polyMesh&);
+
+        //- Clear extra storage before creation of the mesh to remove
+        //  a memory peak
+        void clearExtraStorage();
+
+        void writeInterfaces(const objectRegistry&) const;
+
+        // write List<label> in constant/polyMesh
+        void writeMeshLabelList
+        (
+            const objectRegistry& registry,
+            const word& propertyName,
+            const labelList& list,
+            IOstream::streamFormat fmt = IOstream::ASCII
+        ) const;
+
+        //- Return list of faces for every cell
+        faceListList& cellFaces() const
+        {
+            return const_cast<faceListList&>(cellFaces_);
+        }
+
+protected:
+    // Protected data
+
+        //- Pointers to cell shape models
+        static const cellModel* unknownModel;
+        static const cellModel* tetModel;
+        static const cellModel* pyrModel;
+        static const cellModel* prismModel;
+        static const cellModel* hexModel;
+
+        //- referenced filename
+        fileName geometryFile_;
+
+        //- geometry scaling
+        scalar scaleFactor_;
+
+        //- Points supporting the mesh
+        pointField points_;
+
+        //- lookup original Cell number for a given cell
+        labelList origCellId_;
+
+        //- identify boundary faces by cells and their faces
+        //  for each patch
+        List<List<cellFaceIdentifier> > boundaryIds_;
+
+        //- Boundary patch types
+        wordList patchTypes_;
+
+        //- Boundary patch names
+        wordList patchNames_;
+
+        //- Boundary patch physical types
+        wordList patchPhysicalTypes_;
+
+        //- List of faces for every cell
+        faceListList cellFaces_;
+
+        //- List of each baffle face
+        faceList baffleFaces_;
+
+        // cell table id for each cell
+        labelList cellTableId_;
+
+        // cell table persistent data saved as a dictionary
+        cellTable cellTable_;
+
+    // Member Functions
+
+        //- subclasses are required to supply this information
+        virtual bool readGeometry
+        (
+            const scalar scaleFactor = 1.0
+        ) = 0;
+
+        //- Return mesh points
+        pointField& points() const
+        {
+            return const_cast<pointField&>(points_);
+        }
+
+public:
+    // Static Members
+
+        //- warn about repeated names
+        static void warnDuplicates(const word& context, const wordList&);
+
+    // Constructors
+
+        //- Construct from fileName
+        meshReader(const fileName&, const scalar scaleFactor = 1.0);
+
+    // Destructor
+        virtual ~meshReader();
+
+    // Member Functions
+
+        //- create and return polyMesh
+        virtual autoPtr<polyMesh> mesh(const objectRegistry&);
+
+        //- Write auxiliary information
+        void writeAux(const objectRegistry&) const;
+
+        //- Write mesh
+        void writeMesh
+        (
+            const polyMesh&,
+            IOstream::streamFormat fmt = IOstream::BINARY
+        ) const;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/meshReaderAux.C b/src/conversion/meshReader/meshReaderAux.C
new file mode 100644
index 0000000000000000000000000000000000000000..286092594595c5136aae72332969bc1643d72728
--- /dev/null
+++ b/src/conversion/meshReader/meshReaderAux.C
@@ -0,0 +1,188 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+#include "meshReader.H"
+#include "IOMap.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * Static Functions  * * * * * * * * * * * * * //
+
+// warn about duplicate names
+void Foam::meshReader::warnDuplicates
+(
+    const word& context,
+    const wordList& list
+)
+{
+    HashTable<label> hashed(list.size());
+    bool duplicates = false;
+
+    forAll(list, listI)
+    {
+        // check duplicate name
+        HashTable<label>::iterator iter = hashed.find(list[listI]);
+        if (iter != hashed.end())
+        {
+            (*iter)++;
+            duplicates = true;
+        }
+        else
+        {
+            hashed.insert(list[listI], 1);
+        }
+    }
+
+    // warn about duplicate names
+    if (duplicates)
+    {
+        Info << nl << "WARNING: " << context << " with identical names:";
+        forAllConstIter(HashTable<label>, hashed, iter)
+        {
+            if (*iter > 1)
+            {
+                Info << "  " << iter.key();
+            }
+        }
+        Info << nl << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+
+// write interface (baffle) mapping
+void Foam::meshReader::writeInterfaces(const objectRegistry& registry) const
+{
+    // write constant/polyMesh/interface
+    IOList<labelList> ioObj
+    (
+        IOobject
+        (
+            "interfaces",
+            "constant",
+            polyMesh::meshSubDir,
+            registry,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    ioObj.note() = "as yet unsupported interfaces (baffles)";
+
+    Info<< "Writing " << ioObj.name() << " to " << ioObj.objectPath() << endl;
+
+    OFstream os(ioObj.objectPath());
+    ioObj.writeHeader(os);
+
+    os  << interfaces_
+        << "// ************************************************************************* //"
+        << endl;
+
+}
+
+
+// write List<label> in constant/polyMesh
+// this is crucial for later conversion back to ccm/starcd
+void Foam::meshReader::writeMeshLabelList
+(
+    const objectRegistry& registry,
+    const word& propertyName,
+    const labelList& list,
+    IOstream::streamFormat fmt
+) const
+{
+    // write constant/polyMesh/propertyName
+    IOList<label> ioObj
+    (
+        IOobject
+        (
+            propertyName,
+            "constant",
+            polyMesh::meshSubDir,
+            registry,
+            IOobject::NO_READ,
+            IOobject::AUTO_WRITE,
+            false
+        ),
+        list
+    );
+
+
+    ioObj.note() = "persistent data for star-cd <-> foam translation";
+    Info<< "Writing " << ioObj.name() << " to " << ioObj.objectPath() << endl;
+
+    // NOTE:
+    // the cellTableId is an integer and almost always < 1000, thus ASCII
+    // will be compacter than binary and makes external scripting easier
+    //
+    ioObj.writeObject
+    (
+        fmt,
+        IOstream::currentVersion,
+        IOstream::UNCOMPRESSED
+    );
+}
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::meshReader::writeAux(const objectRegistry& registry) const
+{
+    cellTable_.writeDict(registry);
+    writeInterfaces(registry);
+
+    // write origCellId as List<label>
+    writeMeshLabelList
+    (
+        registry,
+        "origCellId",
+        origCellId_,
+        IOstream::BINARY
+    );
+
+    // write cellTableId as List<label>
+    // this is crucial for later conversion back to ccm/starcd
+    writeMeshLabelList
+    (
+        registry,
+        "cellTableId",
+        cellTableId_,
+        IOstream::ASCII
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/starcd/STARCDMeshReader.C b/src/conversion/meshReader/starcd/STARCDMeshReader.C
new file mode 100644
index 0000000000000000000000000000000000000000..aaabca6740ecedaaef0080d0907784abab9d0ca8
--- /dev/null
+++ b/src/conversion/meshReader/starcd/STARCDMeshReader.C
@@ -0,0 +1,1105 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "STARCDMeshReader.H"
+#include "cyclicPolyPatch.H"
+#include "emptyPolyPatch.H"
+#include "wallPolyPatch.H"
+#include "symmetryPolyPatch.H"
+#include "cellModeller.H"
+#include "SortableList.H"
+#include "IFstream.H"
+#include "IOMap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// special boundary regions
+const char* Foam::meshReaders::STARCD::defaultBoundaryName =
+    "Default_Boundary_Region";
+
+const char* Foam::meshReaders::STARCD::defaultSolidBoundaryName =
+    "Default_Boundary_Solid";
+
+// keep solids
+bool Foam::meshReaders::STARCD::keepSolids = false;
+
+// face addressing from pro-STAR faces -> foam faces
+const int Foam::meshReaders::STARCD::starToFoamFaceAddr[4][6] =
+{
+    { 4, 5, 2, 3, 0, 1 },     // 11 = pro-STAR hex
+    { 0, 1, 4, -1, 2, 3 },    // 12 = pro-STAR prism
+    { 3, -1, 2, -1, 1, 0 },   // 13 = pro-STAR tetra
+    { 0, -1, 4, 2, 1, 3 }     // 14 = pro-STAR pyramid
+};
+
+// * * * * * * * * * * * * * * Static Functions  * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// read and discard to newline
+void Foam::meshReaders::STARCD::readToNewline(IFstream& is)
+{
+    char ch = '\n';
+    do
+    {
+        (is).get(ch);
+    }
+    while ((is) && ch != '\n');
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// read header
+bool Foam::meshReaders::STARCD::readHeader
+(
+    IFstream& is,
+    word fileSignature
+)
+{
+    if (!is.good())
+    {
+        FatalErrorIn("meshReaders::STARCD::readHeader()")
+            << "cannot read " << fileSignature  << "  " << is.name()
+            << abort(FatalError);
+    }
+
+    word header;
+    label majorVersion;
+
+    is >> header;
+    is >> majorVersion;
+
+    // skip the rest of the line
+    readToNewline(is);
+
+    // add other checks ...
+    if (header != fileSignature)
+    {
+        Info<< "header mismatch " << fileSignature << "  " << is.name()
+            << endl;
+    }
+
+    return true;
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// read boundaryRegion names and the cellTable information from
+// dictionaries that have been extracted from the .inp file
+void Foam::meshReaders::STARCD::readAux
+(
+    const objectRegistry& registry
+)
+{
+    boundaryRegion_.readDict(registry);
+    cellTable_.readDict(registry);
+}
+
+// read in the points from the .vrt file
+//
+/*---------------------------------------------------------------------------*\
+Line 1:
+  PROSTAR_VERTEX [newline]
+
+Line 2:
+  <version> 0 0 0 0 0 0 0 [newline]
+
+Body:
+  <vertexId>  <x>  <y>  <z> [newline]
+
+\*---------------------------------------------------------------------------*/
+void Foam::meshReaders::STARCD::readPoints
+(
+    const fileName& inputName,
+    const scalar scaleFactor
+)
+{
+    const word fileSignature = "PROSTAR_VERTEX";
+    label nPoints = 0, maxId = 0;
+
+    // Pass 1:
+    // get # points and maximum vertex label
+    {
+        IFstream is(inputName);
+        readHeader(is, fileSignature);
+
+        label lineLabel;
+        scalar x, y, z;
+
+        while ((is >> lineLabel).good())
+        {
+            nPoints++;
+            maxId = max(maxId, lineLabel);
+            is >> x >> y >> z;
+        }
+    }
+
+    Info<< "Number of points  = " << nPoints << endl;
+
+    // set sizes and reset to invalid values
+
+    points_.setSize(nPoints);
+    mapToFoamPointId_.setSize(maxId+1);
+
+    //- original Point number for a given vertex
+    // might need again in the future
+    ////     labelList origPointId(nPoints);
+    ////     origPointId = -1;
+
+    mapToFoamPointId_ = -1;
+
+    // Pass 2:
+    // construct pointList and conversion table
+    // from Star vertex numbers to Foam point labels
+    if (nPoints > 0)
+    {
+        IFstream is(inputName);
+        readHeader(is, fileSignature);
+
+        label lineLabel;
+
+        label pointI = 0;
+        while ((is >> lineLabel).good())
+        {
+            is  >> points_[pointI].x()
+                >> points_[pointI].y()
+                >> points_[pointI].z();
+
+            // might need again in the future
+            ////  origPointId[pointI] = lineLabel;
+            mapToFoamPointId_[lineLabel] = pointI;
+            pointI++;
+        }
+
+        if (nPoints > pointI)
+        {
+            nPoints = pointI;
+            points_.setSize(nPoints);
+            // might need again in the future
+            //// origPointId.setSize(nPoints);
+        }
+
+        if (scaleFactor > 1.0 + SMALL || scaleFactor < 1.0 - SMALL)
+        {
+            points_ *= scaleFactor;
+        }
+    }
+    else
+    {
+        FatalErrorIn("meshReaders::STARCD::readPoints()")
+            << "no points in file " << inputName
+            << abort(FatalError);
+    }
+
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// read in the cells from the .cel file
+//
+/*---------------------------------------------------------------------------*\
+Line 1:
+  PROSTAR_CELL [newline]
+
+Line 2:
+  <version> 0 0 0 0 0 0 0 [newline]
+
+Body:
+  <cellId>  <shapeId>  <nLabels>  <cellTableId>  <typeId> [newline]
+  <cellId>  <int1> .. <int8>
+  <cellId>  <int9> .. <int16>
+
+ with shapeId:
+ *   1 = point
+ *   2 = line
+ *   3 = shell
+ *  11 = hexa
+ *  12 = prism
+ *  13 = tetra
+ *  14 = pyramid
+ * 255 = polyhedron
+
+ with typeId
+ *   1 = fluid
+ *   2 = solid
+ *   3 = baffle
+ *   4 = shell
+ *   5 = line
+ *   6 = point
+
+For primitive cell shapes, the number of vertices will never exceed 8 (hexa)
+and corresponds to <nLabels>.
+For polyhedral, <nLabels> includess an index table comprising beg/end pairs
+for each cell face.
+
+Strictly speaking, we only need the cellModeller for adding boundaries.
+\*---------------------------------------------------------------------------*/
+
+void Foam::meshReaders::STARCD::readCells
+(
+    const fileName& inputName
+)
+{
+    const word fileSignature = "PROSTAR_CELL";
+    label nFluids = 0, nSolids = 0, nBaffles = 0, nShells = 0;
+    label maxId = 0;
+
+    bool unknownVertices = false;
+
+
+    // Pass 1:
+    // count nFluids, nSolids, nBaffle, nShell and maxId
+    // also see if polyhedral cells were used
+    {
+        IFstream is(inputName);
+        readHeader(is, fileSignature);
+
+        label lineLabel, shapeId, nLabels, cellTableId, typeId;
+
+        while ((is >> lineLabel).good())
+        {
+            label starCellId = lineLabel;
+            is  >> shapeId
+                >> nLabels
+                >> cellTableId
+                >> typeId;
+
+            // skip the rest of the line
+            readToNewline(is);
+
+            // max 8 indices per line
+            while (nLabels > 0)
+            {
+                readToNewline(is);
+                nLabels -= 8;
+            }
+
+            if (typeId == starcdFluidType)
+            {
+                nFluids++;
+                maxId = max(maxId, starCellId);
+
+                if (!cellTable_.found(cellTableId))
+                {
+                    cellTable_.setName(cellTableId);
+                    cellTable_.setMaterial(cellTableId, "fluid");
+                }
+            }
+            else if (typeId == starcdSolidType)
+            {
+                nSolids++;
+                if (keepSolids)
+                {
+                    maxId = max(maxId, starCellId);
+                }
+
+                if (!cellTable_.found(cellTableId))
+                {
+                    cellTable_.setName(cellTableId);
+                    cellTable_.setMaterial(cellTableId, "solid");
+                }
+
+            }
+            else if (typeId == starcdBaffleType)
+            {
+                // baffles have no cellTable entry
+                nBaffles++;
+                maxId = max(maxId, starCellId);
+            }
+            else if (typeId == starcdShellType)
+            {
+                nShells++;
+                if (!cellTable_.found(cellTableId))
+                {
+                    cellTable_.setName(cellTableId);
+                    cellTable_.setMaterial(cellTableId, "shell");
+                }
+            }
+
+        }
+    }
+
+    Info<< "Number of fluids  = " << nFluids << nl
+        << "Number of baffles = " << nBaffles << nl;
+    if (keepSolids)
+    {
+        Info<< "Number of solids  = " << nSolids << nl;
+    }
+    else
+    {
+        Info<< "Ignored   solids  = " << nSolids << nl;
+    }
+    Info<< "Ignored   shells  = " << nShells << endl;
+
+
+    label nCells;
+    if (keepSolids)
+    {
+        nCells = nFluids + nSolids;
+    }
+    else
+    {
+        nCells = nFluids;
+    }
+
+    cellFaces_.setSize(nCells);
+    cellShapes_.setSize(nCells);
+    cellTableId_.setSize(nCells);
+
+    // information for the interfaces
+    baffleFaces_.setSize(nBaffles);
+
+    // extra space for baffles
+    origCellId_.setSize(nCells + nBaffles);
+    mapToFoamCellId_.setSize(maxId+1);
+    mapToFoamCellId_ = -1;
+
+
+    // avoid undefined shapes for polyhedra
+    cellShape genericShape(*unknownModel, labelList(0));
+
+    // Pass 2:
+    // construct cellFaces_ and possibly cellShapes_
+    if (nCells <= 0)
+    {
+        FatalErrorIn("meshReaders::STARCD::readCells()")
+            << "no cells in file " << inputName
+            << abort(FatalError);
+    }
+    else
+    {
+        IFstream is(inputName);
+        readHeader(is, fileSignature);
+
+        labelList starLabels(64);
+        label lineLabel, shapeId, nLabels, cellTableId, typeId;
+
+        label cellI = 0;
+        label baffleI = 0;
+
+        while ((is >> lineLabel).good())
+        {
+            label starCellId = lineLabel;
+            is  >> shapeId
+                >> nLabels
+                >> cellTableId
+                >> typeId;
+
+            if (nLabels > starLabels.size())
+            {
+                starLabels.setSize(nLabels);
+            }
+            starLabels = -1;
+
+            // read indices - max 8 per line
+            for (label i = 0; i < nLabels; ++i)
+            {
+                if ((i % 8) == 0)
+                {
+                    is >> lineLabel;
+                }
+                is >> starLabels[i];
+            }
+
+            // skip solid cells
+            if (typeId == starcdSolidType && !keepSolids)
+            {
+                continue;
+            }
+
+            // determine the foam cell shape
+            const cellModel* curModelPtr = NULL;
+
+            // fluid/solid cells
+            switch (shapeId)
+            {
+                case starcdHex:
+                    curModelPtr = hexModel;
+                    break;
+                case starcdPrism:
+                    curModelPtr = prismModel;
+                    break;
+                case starcdTet:
+                    curModelPtr = tetModel;
+                    break;
+                case starcdPyr:
+                    curModelPtr = pyrModel;
+                    break;
+            }
+
+            if (curModelPtr)
+            {
+                // primitive cell - use shapes
+
+                // convert orig vertex Id to point label
+                bool isBad = false;
+                for (label i=0; i < nLabels; ++i)
+                {
+                    label pointId = mapToFoamPointId_[starLabels[i]];
+                    if (pointId < 0)
+                    {
+                        Info<< "Cells inconsistent with vertex file. "
+                            << "Star vertex " << starLabels[i]
+                            << " does not exist" << endl;
+                        isBad = true;
+                        unknownVertices = true;
+                    }
+                    starLabels[i] = pointId;
+                }
+
+                if (isBad)
+                {
+                    continue;
+                }
+
+                // record original cell number and lookup
+                origCellId_[cellI] = starCellId;
+                mapToFoamCellId_[starCellId] = cellI;
+
+                cellTableId_[cellI] = cellTableId;
+                cellShapes_[cellI] = cellShape
+                (
+                    *curModelPtr,
+                    SubList<label>(starLabels, nLabels)
+                );
+
+                cellFaces_[cellI] = cellShapes_[cellI].faces();
+                cellI++;
+            }
+            else if (shapeId == starcdPoly)
+            {
+                // polyhedral cell
+                label nFaces = starLabels[0] - 1;
+
+                // convert orig vertex id to point label
+                // start with offset (skip the index table)
+                bool isBad = false;
+                for (label i=starLabels[0]; i < nLabels; ++i)
+                {
+                    label pointId = mapToFoamPointId_[starLabels[i]];
+                    if (pointId < 0)
+                    {
+                        Info<< "Cells inconsistent with vertex file. "
+                            << "Star vertex " << starLabels[i]
+                            << " does not exist" << endl;
+                        isBad = true;
+                        unknownVertices = true;
+                    }
+                    starLabels[i] = pointId;
+                }
+
+                if (isBad)
+                {
+                    continue;
+                }
+
+                // traverse beg/end indices
+                faceList faces(nFaces);
+                label faceI = 0;
+                for (label i=0; i < nFaces; ++i)
+                {
+                    label beg = starLabels[i];
+                    label n   = starLabels[i+1] - beg;
+
+                    face f
+                    (
+                        SubList<label>(starLabels, n, beg)
+                    );
+
+                    f.collapse();
+
+                    // valid faces only
+                    if (f.size() >= 3)
+                    {
+                        faces[faceI++] = f;
+                    }
+                }
+
+                if (nFaces > faceI)
+                {
+                    Info<< "star cell " << starCellId << " has "
+                        << (nFaces - faceI)
+                        << " empty faces - could cause boundary addressing problems"
+                        << endl;
+
+                    nFaces = faceI;
+                    faces.setSize(nFaces);
+                }
+
+                if (nFaces < 4)
+                {
+                    FatalErrorIn("meshReaders::STARCD::readCells()")
+                        << "star cell " << starCellId << " has " << nFaces
+                        << abort(FatalError);
+                }
+
+                // record original cell number and lookup
+                origCellId_[cellI] = starCellId;
+                mapToFoamCellId_[starCellId] = cellI;
+
+                cellTableId_[cellI] = cellTableId;
+                cellShapes_[cellI]  = genericShape;
+                cellFaces_[cellI]   = faces;
+                cellI++;
+            }
+            else if (typeId == starcdBaffleType)
+            {
+                // baffles
+
+                // convert orig vertex id to point label
+                bool isBad = false;
+                for (label i=0; i < nLabels; ++i)
+                {
+                    label pointId = mapToFoamPointId_[starLabels[i]];
+                    if (pointId < 0)
+                    {
+                        Info<< "Baffles inconsistent with vertex file. "
+                            << "Star vertex " << starLabels[i]
+                            << " does not exist" << endl;
+                        isBad = true;
+                        unknownVertices = true;
+                    }
+                    starLabels[i] = pointId;
+                }
+
+                if (isBad)
+                {
+                    continue;
+                }
+
+
+                face f
+                (
+                    SubList<label>(starLabels, nLabels)
+                );
+
+                f.collapse();
+
+                // valid faces only
+                if (f.size() >= 3)
+                {
+                    baffleFaces_[baffleI] = f;
+                    // insert lookup addressing in normal list
+                    mapToFoamCellId_[starCellId]  = nCells + baffleI;
+                    origCellId_[nCells + baffleI] = starCellId;
+                    baffleI++;
+                }
+            }
+        }
+
+        baffleFaces_.setSize(baffleI);
+    }
+
+    if (unknownVertices)
+    {
+        FatalErrorIn("meshReaders::STARCD::readCells()")
+            << "cells with unknown vertices"
+            << abort(FatalError);
+    }
+
+    // truncate lists
+
+#ifdef DEBUG_READING
+    Info<< "CELLS READ" << endl;
+#endif
+
+    // cleanup
+    mapToFoamPointId_.clear();
+}
+
+// read in the boundaries from the .bnd file
+//
+/*---------------------------------------------------------------------------*\
+Line 1:
+  PROSTAR_BOUNDARY [newline]
+
+Line 2:
+  <version> 0 0 0 0 0 0 0 [newline]
+
+Body:
+  <boundId>  <cellId>  <cellFace>  <regionId>  0  <boundaryType> [newline]
+
+where boundaryType is truncated to 4 characters from one of the following:
+INLET
+PRESSSURE
+OUTLET
+BAFFLE
+etc,
+\*---------------------------------------------------------------------------*/
+
+void Foam::meshReaders::STARCD::readBoundary
+(
+    const fileName& inputName
+)
+{
+    const word fileSignature = "PROSTAR_BOUNDARY";
+    label nPatches = 0, nFaces = 0, nBafflePatches = 0, maxId = 0;
+    label lineLabel, starCellId, cellFaceId, starRegion, configNumber;
+    word patchType;
+
+    labelList mapToFoamPatchId(1000, -1);
+    labelList nPatchFaces(1000, 0);
+    labelList origRegion(1000, 0);
+    patchTypes_.setSize(1000);
+
+    // this is what we seem to need
+    // these MUST correspond to starToFoamFaceAddr
+    //
+    Map<label> faceLookupIndex;
+
+    faceLookupIndex.insert(hexModel->index(), 0);
+    faceLookupIndex.insert(prismModel->index(), 1);
+    faceLookupIndex.insert(tetModel->index(), 2);
+    faceLookupIndex.insert(pyrModel->index(), 3);
+
+    // Pass 1:
+    // collect
+    // no. of faces (nFaces), no. of patches (nPatches)
+    // and for each of these patches the number of faces
+    // (nPatchFaces[patchLabel])
+    //
+    // and a conversion table from Star regions to (Foam) patchLabels
+    //
+    // additionally note the no. of baffle patches (nBafflePatches)
+    // so that we sort these to the end of the patch list
+    // - this makes it easier to transfer them to an adjacent patch if reqd
+    {
+        IFstream is(inputName);
+
+        if (is.good())
+        {
+            readHeader(is, fileSignature);
+
+            while ((is >> lineLabel).good())
+            {
+                nFaces++;
+                is  >> starCellId
+                    >> cellFaceId
+                    >> starRegion
+                    >> configNumber
+                    >> patchType;
+
+                // Build translation table to convert star patch to foam patch
+                label patchLabel = mapToFoamPatchId[starRegion];
+                if (patchLabel == -1)
+                {
+                    patchLabel = nPatches;
+                    mapToFoamPatchId[starRegion] = patchLabel;
+                    origRegion[patchLabel] = starRegion;
+                    patchTypes_[patchLabel] = patchType;
+
+                    maxId = max(maxId, starRegion);
+
+                    if (patchType == "BAFF")    // should actually be case-insensitive
+                    {
+                        nBafflePatches++;
+                    }
+                    nPatches++;
+                }
+
+                nPatchFaces[patchLabel]++;
+            }
+
+            if (nPatches == 0)
+            {
+                Info<< "No boundary faces in file " << inputName << endl;
+            }
+        }
+        else
+        {
+            Info<< "Could not read boundary file " << inputName << endl;
+        }
+    }
+
+    // keep empty patch region in reserve
+    nPatches++;
+    Info<< "Number of patches = " << nPatches
+        << " (including extra for missing)" << endl;
+
+    // resize
+    origRegion.setSize(nPatches);
+    patchTypes_.setSize(nPatches);
+    patchNames_.setSize(nPatches);
+    nPatchFaces.setSize(nPatches);
+
+    // add our empty patch
+    origRegion[nPatches-1] = 0;
+    nPatchFaces[nPatches-1] = 0;
+    patchTypes_[nPatches-1] = "none";
+
+    // create names
+    // - use 'Label' entry from "constant/boundaryRegion" dictionary
+    forAll(patchTypes_, patchI)
+    {
+        bool foundName = false, foundType = false;
+
+        Map<dictionary>::const_iterator
+            iter = boundaryRegion_.find(origRegion[patchI]);
+
+        if
+        (
+            iter != boundaryRegion_.end()
+        )
+        {
+            if (iter().found("BoundaryType"))
+            {
+                iter().lookup("BoundaryType") >> patchTypes_[patchI];
+                foundType = true;
+            }
+
+            if (iter().found("Label"))
+            {
+                iter().lookup("Label") >> patchNames_[patchI];
+                foundName = true;
+            }
+        }
+
+        // consistent names, in long form and in lowercase
+        if (!foundType)
+        {
+            // transform
+            forAllIter(string, patchTypes_[patchI], i)
+            {
+                *i = tolower(*i);
+            }
+
+            if (patchTypes_[patchI] == "symp")
+            {
+                patchTypes_[patchI] = "symplane";
+            }
+            else if (patchTypes_[patchI] == "cycl")
+            {
+                patchTypes_[patchI] = "cyclic";
+            }
+            else if (patchTypes_[patchI] == "baff")
+            {
+                patchTypes_[patchI] = "baffle";
+            }
+            else if (patchTypes_[patchI] == "moni")
+            {
+                patchTypes_[patchI] = "monitoring";
+            }
+        }
+
+        // create a name if needed
+        if (!foundName)
+        {
+            patchNames_[patchI] =
+                patchTypes_[patchI] + "_" + name(origRegion[patchI]);
+        }
+    }
+
+    // enforce name "Default_Boundary_Region"
+    patchNames_[nPatches-1] = defaultBoundaryName;
+
+    // sort according to ascending region numbers, but leave
+    // Default_Boundary_Region as the last patch
+    {
+        SortableList<label> sortedOrder(SubList<label>(origRegion, nPatches-1));
+
+        labelList oldToNew = identity(nPatches);
+        forAll(sortedOrder, i)
+        {
+            oldToNew[sortedOrder.indices()[i]] = i;
+        }
+
+        inplaceReorder(oldToNew, origRegion);
+        inplaceReorder(oldToNew, patchTypes_);
+        inplaceReorder(oldToNew, patchNames_);
+        inplaceReorder(oldToNew, nPatchFaces);
+    }
+
+    // re-sort to have baffles near the end
+    nBafflePatches = 1;
+    if (nBafflePatches)
+    {
+        labelList oldToNew = identity(nPatches);
+        label newIndex = 0;
+        label baffleIndex = (nPatches-1 - nBafflePatches);
+
+        for (label i=0; i < oldToNew.size()-1; ++i)
+        {
+            if (patchTypes_[i] == "baffle")
+            {
+                oldToNew[i] = baffleIndex++;
+            }
+            else
+            {
+                oldToNew[i] = newIndex++;
+            }
+        }
+
+        inplaceReorder(oldToNew, origRegion);
+        inplaceReorder(oldToNew, patchTypes_);
+        inplaceReorder(oldToNew, patchNames_);
+        inplaceReorder(oldToNew, nPatchFaces);
+    }
+
+    mapToFoamPatchId.setSize(maxId+1, -1);
+    forAll(origRegion, patchI)
+    {
+        mapToFoamPatchId[origRegion[patchI]] = patchI;
+    }
+
+    boundaryIds_.setSize(nPatches);
+    forAll(boundaryIds_, patchI)
+    {
+        boundaryIds_[patchI].setSize(nPatchFaces[patchI]);
+        nPatchFaces[patchI] = 0;
+    }
+
+
+    // Pass 2:
+    //
+    if (nPatches > 1 && mapToFoamCellId_.size() > 1)
+    {
+        IFstream is(inputName);
+        readHeader(is, fileSignature);
+
+        while ((is >> lineLabel).good())
+        {
+            is
+                >> starCellId
+                >> cellFaceId
+                >> starRegion
+                >> configNumber
+                >> patchType;
+
+            label patchI = mapToFoamPatchId[starRegion];
+
+            // zero-based indexing
+            cellFaceId--;
+
+            label cellId = -1;
+
+            // convert to FOAM cell number
+            if (starCellId < mapToFoamCellId_.size())
+            {
+                cellId = mapToFoamCellId_[starCellId];
+            }
+
+            if (cellId < 0)
+            {
+                Info
+                    << "Boundaries inconsistent with cell file. "
+                    << "Star cell " << starCellId << " does not exist"
+                    << endl;
+            }
+            else
+            {
+                // restrict lookup to volume cells (no baffles)
+                if (cellId < cellShapes_.size())
+                {
+                    label index = cellShapes_[cellId].model().index();
+                    if (faceLookupIndex.found(index))
+                    {
+                        index = faceLookupIndex[index];
+                        cellFaceId = starToFoamFaceAddr[index][cellFaceId];
+                    }
+                }
+                else
+                {
+                    // we currently use cellId >= nCells to tag baffles,
+                    // we can also use a negative face number
+                    cellFaceId = -1;
+                }
+
+                boundaryIds_[patchI][nPatchFaces[patchI]] =
+                    cellFaceIdentifier(cellId, cellFaceId);
+
+#ifdef DEBUG_BOUNDARY
+                Info<< "bnd " << cellId << " " << cellFaceId << endl;
+#endif
+                // increment counter of faces in current patch
+                nPatchFaces[patchI]++;
+            }
+        }
+    }
+
+    // retain original information in patchPhysicalTypes_ - overwrite latter
+    patchPhysicalTypes_.setSize(patchTypes_.size());
+
+
+    forAll(boundaryIds_, patchI)
+    {
+        // resize - avoid invalid boundaries
+        if (nPatchFaces[patchI] < boundaryIds_[patchI].size())
+        {
+            boundaryIds_[patchI].setSize(nPatchFaces[patchI]);
+        }
+
+        word origType = patchTypes_[patchI];
+        patchPhysicalTypes_[patchI] = origType;
+
+        if (origType == "symplane")
+        {
+            patchTypes_[patchI] = symmetryPolyPatch::typeName;
+            patchPhysicalTypes_[patchI] = patchTypes_[patchI];
+        }
+        else if (origType == "wall")
+        {
+            patchTypes_[patchI] = wallPolyPatch::typeName;
+            patchPhysicalTypes_[patchI] = patchTypes_[patchI];
+        }
+        else if (origType == "cyclic")
+        {
+            // incorrect. should be cyclicPatch but this
+            // requires info on connected faces.
+            patchTypes_[patchI] = cyclicPolyPatch::typeName;
+            patchPhysicalTypes_[patchI] = patchTypes_[patchI];
+        }
+        else if (origType == "baffle")
+        {
+            // incorrect. tag the patch until we get proper support.
+            // set physical type to a canonical "baffle"
+            patchTypes_[patchI] = emptyPolyPatch::typeName;
+            patchPhysicalTypes_[patchI] = "baffle";
+        }
+        else
+        {
+            patchTypes_[patchI] = polyPatch::typeName;
+        }
+
+        Info<< "patch " << patchI
+            << " (region " << origRegion[patchI]
+            << ": " << origType << ") type: '" << patchTypes_[patchI]
+            << "' name: " << patchNames_[patchI] << endl;
+    }
+
+    // cleanup
+    mapToFoamCellId_.clear();
+    cellShapes_.clear();
+}
+
+
+//
+// remove unused points
+//
+void Foam::meshReaders::STARCD::cullPoints()
+{
+    label nPoints = points_.size();
+    labelList oldToNew(nPoints, -1);
+
+    // loop through cell faces and note which points are being used
+    forAll(cellFaces_, cellI)
+    {
+        const faceList& faces = cellFaces_[cellI];
+        forAll(faces, i)
+        {
+            const labelList& labels = faces[i];
+            forAll(labels, j)
+            {
+                oldToNew[labels[j]]++;
+            }
+        }
+    }
+
+    // the new ordering and the count of unused points
+    label pointI = 0;
+    forAll(oldToNew, i)
+    {
+        if (oldToNew[i] >= 0)
+        {
+            oldToNew[i] = pointI++;
+        }
+    }
+
+    // report unused points
+    if (nPoints > pointI)
+    {
+        Info<< "Unused    points  = " << (nPoints - pointI) << endl;
+        nPoints = pointI;
+
+        // adjust points and truncate
+        inplaceReorder(oldToNew, points_);
+        points_.setSize(nPoints);
+
+        // adjust cellFaces - with mesh shapes this might be faster
+        forAll(cellFaces_, cellI)
+        {
+            faceList& faces = cellFaces_[cellI];
+            forAll(faces, i)
+            {
+                inplaceRenumber(oldToNew, faces[i]);
+            }
+        }
+
+        // adjust baffles
+        forAll(baffleFaces_, faceI)
+        {
+            inplaceRenumber(oldToNew, baffleFaces_[faceI]);
+        }
+    }
+}
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+bool Foam::meshReaders::STARCD::readGeometry
+(
+    const scalar scaleFactor
+)
+{
+    // Info<< "called meshReaders::STARCD::readGeometry" << endl;
+
+    readPoints(geometryFile_ + ".vrt", scaleFactor);
+    readCells(geometryFile_ + ".cel");
+    cullPoints();
+    readBoundary(geometryFile_ + ".bnd");
+
+    return true;
+}
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from reading a file
+Foam::meshReaders::STARCD::STARCD
+(
+    const fileName& prefix,
+    const objectRegistry& registry,
+    const scalar scaleFactor
+)
+:
+    meshReader(prefix, scaleFactor),
+    cellShapes_(0),
+    mapToFoamPointId_(0),
+    mapToFoamCellId_(0)
+{
+    readAux(registry);
+}
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::meshReaders::STARCD::~STARCD()
+{}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshReader/starcd/STARCDMeshReader.H b/src/conversion/meshReader/starcd/STARCDMeshReader.H
new file mode 100644
index 0000000000000000000000000000000000000000..ce8873360875cd584f86154dcc6ac8b1985776e4
--- /dev/null
+++ b/src/conversion/meshReader/starcd/STARCDMeshReader.H
@@ -0,0 +1,176 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::meshReaders::STARCD
+
+Description
+    Read pro-STAR vrt/cel/bnd files.
+    The protected data in meshReader are filled.
+
+    Starting with pro-STAR version 4, the files have become easier to read.
+    - vertices are space-delimited.
+    - the cell format is logical.
+    - trimmed and degenerate cells are saved as polyhedral.
+    - the boundaries corresponds to cells and their faces.
+
+SourceFiles
+    STARCDMeshReader.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef STARCDMeshReader_H
+#define STARCDMeshReader_H
+
+# include "meshReader.H"
+# include "boundaryRegion.H"
+# include "cellShape.H"
+# include "IFstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace meshReaders
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class meshReaders::STARCD Declaration
+\*---------------------------------------------------------------------------*/
+
+class STARCD
+:
+    public meshReader
+{
+
+protected:
+
+    // Private Data
+        static const char* defaultBoundaryName;
+        static const char* defaultSolidBoundaryName;
+
+        //- Face addressing from pro-STAR faces -> OpenFOAM faces
+        static const int starToFoamFaceAddr[4][6];
+
+        //- Cell shapes
+        cellShapeList cellShapes_;
+
+        //- Point labels (imported Point numbering not necessarily contiguous)
+        labelList mapToFoamPointId_;
+
+        //- Cell labels (imported Cell numbering not necessarily contiguous)
+        labelList mapToFoamCellId_;
+
+        //- boundary region data
+        boundaryRegion boundaryRegion_;
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        STARCD(const STARCD&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const STARCD&);
+
+        //- Read the mesh from the file(s)
+        virtual bool readGeometry(const scalar scaleFactor = 1.0);
+
+        //- read points from file
+        void readPoints(const fileName&, const scalar scaleFactor);
+
+        //- read cell connectivities from file
+        virtual void readCells(const fileName&);
+
+        //- remove unused points
+        void cullPoints();
+
+        //- read boundary (cell/face) definitions
+        void readBoundary(const fileName&);
+
+        //- read auxiliary data from constant/{boundaryRegion,cellTable}
+        void readAux(const objectRegistry&);
+
+        //- read and discard to newline
+        static void readToNewline(IFstream&);
+
+        //- read header
+        static bool readHeader(IFstream&, word fileSignature);
+
+protected:
+
+        enum cellType
+        {
+            starcdFluidType   = 1,
+            starcdSolidType   = 2,
+            starcdBaffleType  = 3,
+            starcdShellType   = 4,
+            starcdLineType    = 5,
+            starcdPointType   = 6
+        };
+
+        enum shapeType
+        {
+            starcdPoint = 1,
+            starcdLine  = 2,
+            starcdShell = 3,
+            starcdHex   = 11,
+            starcdPrism = 12,
+            starcdTet   = 13,
+            starcdPyr   = 14,
+            starcdPoly  = 255
+        };
+
+
+public:
+
+        //- keep solids (default false)
+        static bool keepSolids;
+
+    // Constructors
+
+        //- Construct from case name
+        STARCD
+        (
+            const fileName& prefix,
+            const objectRegistry&,
+            const scalar scaleFactor = 1.0
+        );
+
+        // Destructor
+        virtual ~STARCD();
+
+    // Member Functions
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace meshReaders
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/meshTables/README b/src/conversion/meshTables/README
new file mode 100644
index 0000000000000000000000000000000000000000..56c47002412921408f0c178af6c4693bbf502ca8
--- /dev/null
+++ b/src/conversion/meshTables/README
@@ -0,0 +1,25 @@
+Star-CD uses a so-called 'cell table' to organize properties. The ccm and
+star4 converters preserve this information as a Map of dictionaries under
+"constant/cellTable" and as cell data under "constant/polyMesh/cellTableId".
+
+The combination of both files allows subsequent creating of cellSets and
+cellZones for any combination of properties (eg, porosities and solids).
+
+Additionally, the reverse converters can use this information when
+converting foam meshes back to the Star-CD formats.
+
+The names of the dictionary elements (eg, Label, MaterialType, etc) are
+chosen to match those used by the ccm-format.
+
+Here is a sample dictionary entry:
+
+<int>	                        // unique positive int
+{
+    Label           <word>;     // optional
+    MaterialType    <word>;     // optional (fluid|solid)
+    MaterialId      <int>;      // optional
+    PorosityId      <int>;      // optional
+    GroupId         <int>;      // optional
+    SpinId          <int>;      // optional
+}
+
diff --git a/src/conversion/meshTables/boundaryRegion.C b/src/conversion/meshTables/boundaryRegion.C
new file mode 100644
index 0000000000000000000000000000000000000000..8af5a0e1664e060bbc8b364b31917e19785a6463
--- /dev/null
+++ b/src/conversion/meshTables/boundaryRegion.C
@@ -0,0 +1,268 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "boundaryRegion.H"
+#include "IOMap.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::boundaryRegion::boundaryRegion()
+:
+    Map<dictionary>()
+{}
+
+
+// read constant/boundaryRegion (IOMap<dictionary>)
+Foam::boundaryRegion::boundaryRegion
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+)
+:
+    Map<dictionary>()
+{
+    readDict(registry, name, instance);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::boundaryRegion::~boundaryRegion()
+{}
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+Foam::label Foam::boundaryRegion::append(const dictionary& dict)
+{
+    label maxId = -1;
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        if (maxId < iter.key())
+        {
+            maxId = iter.key();
+        }
+    }
+
+    insert(++maxId, dict);
+    return maxId;
+}
+
+
+Foam::Map<Foam::word>
+Foam::boundaryRegion::names() const
+{
+    Map<word> lookup;
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word value = "boundaryRegion_" + Foam::name(iter.key());
+        iter().readIfPresent("Label", value);
+
+        lookup.insert(iter.key(), value);
+    }
+
+    return lookup;
+}
+
+
+Foam::Map<Foam::word>
+Foam::boundaryRegion::boundaryTypes() const
+{
+    Map<word> lookup;
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word value = "patch";
+        iter().readIfPresent("BoundaryType", value);
+        lookup.insert(iter.key(), value);
+    }
+
+    return lookup;
+}
+
+
+Foam::label Foam::boundaryRegion::findIndex(const word& name) const
+{
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word theName;
+        if (iter().readIfPresent("Label", theName))
+        {
+            if (theName == name)
+            {
+                return iter.key();
+            }
+        }
+    }
+
+    return -1;
+}
+
+
+Foam::word Foam::boundaryRegion::boundaryType(const word& name) const
+{
+    word bndType = "patch";
+
+    label id = this->findIndex(name);
+    if (id >= 0)
+    {
+        const dictionary& dict = operator[](id);
+        dict.readIfPresent("BoundaryType", bndType);
+    }
+
+    return bndType;
+}
+
+
+// read constant/boundaryRegion (IOMap<dictionary>)
+void Foam::boundaryRegion::readDict
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+)
+{
+    clear();
+
+    // read constant/dictName
+    IOMap<dictionary> ioObj
+    (
+        IOobject
+        (
+            name,
+            instance,
+            registry,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    if (ioObj.headerOk())
+    {
+        *this = ioObj;
+    }
+    else
+    {
+        Info<< "no constant/boundaryRegion information available" << endl;
+    }
+}
+
+
+// write constant/boundaryRegion for later reuse
+void Foam::boundaryRegion::writeDict
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+) const
+{
+    // write constant/dictName
+    IOMap<dictionary> ioObj
+    (
+        IOobject
+        (
+            name,
+            instance,
+            registry,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    ioObj.note() = "persistent data for thirdParty mesh <-> OpenFOAM translation";
+
+    Info<< "Writing " << ioObj.name() << " to " << ioObj.objectPath() << endl;
+
+    OFstream os(ioObj.objectPath());
+    ioObj.writeHeader(os);
+    os << *this;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+
+void Foam::boundaryRegion::operator=(const boundaryRegion& rhs)
+{
+    Map<dictionary>::operator=(rhs);
+}
+
+void Foam::boundaryRegion::operator=(const Map<dictionary>& rhs)
+{
+    Map<dictionary>::operator=(rhs);
+}
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+void Foam::boundaryRegion::rename(const dictionary& dict)
+{
+    if (!dict.size())
+    {
+        return;
+    }
+
+    Map<word> mapping;
+
+    forAllConstIter(dictionary, dict, iter)
+    {
+        word oldName(iter().stream());
+
+        label id = this->findIndex(oldName);
+        if (id >= 0)
+        {
+            mapping.insert(id, iter().keyword());
+        }
+    }
+
+    if (mapping.size())
+    {
+        forAllConstIter(Map<word>, mapping, iter)
+        {
+            label id = iter.key();
+            word oldName(operator[](id).lookup("Label"));
+            word newName(iter());
+
+            dictionary newDict(operator[](id));
+            newDict.remove("Label");
+            newDict.add("Label", newName);
+
+            this->set(id, newDict);
+            Info<< "rename patch: " << newName << " <- " << oldName << endl;
+        }
+    }
+}
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshTables/boundaryRegion.H b/src/conversion/meshTables/boundaryRegion.H
new file mode 100644
index 0000000000000000000000000000000000000000..ba5976d4a5e7cb2c441135ff3cf94afca17d3965
--- /dev/null
+++ b/src/conversion/meshTables/boundaryRegion.H
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::boundaryRegion
+
+Description
+    The boundaryRegion persistent data saved as a Map<dictionary>.
+
+    The meshReader supports boundaryRegion information.
+
+    The <tt>constant/boundaryRegion</tt> file is an @c IOMap<dictionary>
+    that is used to save the information persistently.
+    It contains the boundaryRegion information of the following form:
+
+    @verbatim
+        (
+            INT
+            {
+                BoundaryType    WORD;
+                Label           WORD;
+            }
+            ...
+        )
+    @endverbatim
+
+SourceFiles
+    boundaryRegion.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryRegion_H
+#define boundaryRegion_H
+
+#include "polyMesh.H"
+#include "Map.H"
+#include "dictionary.H"
+#include "labelList.H"
+#include "wordList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class boundaryRegion Declaration
+\*---------------------------------------------------------------------------*/
+
+class boundaryRegion
+:
+    public Map<dictionary>
+{
+    // Private data
+
+    // Private Member Functions
+
+    //- Disallow default bitwise copy construct
+    boundaryRegion(const boundaryRegion&);
+
+public:
+    // Static Members
+
+    // Constructors
+
+        //- Construct null
+        boundaryRegion();
+
+        //- Construct read from registry, name. instance
+        boundaryRegion
+        (
+            const objectRegistry&,
+            const word& name = "boundaryRegion",
+            const fileName& instance = "constant"
+        );
+
+
+    // Destructor
+        ~boundaryRegion();
+
+
+    // Member Functions
+
+        //- Append to the end, return index
+        label append(const dictionary&);
+
+        //- Return index corresponding to patch 'name'
+        //  returns -1 if not found
+        label findIndex(const word& name) const;
+
+        //- Return a Map of (id => name)
+        Map<word> names() const;
+
+        //- Return a Map of (id => type)
+        Map<word> boundaryTypes() const;
+
+        //- Return BoundaryType corresponding to patch 'name'
+        word boundaryType(const word& name) const;
+
+        //- Read constant/boundaryRegion
+        void readDict
+        (
+            const objectRegistry&,
+            const word& name = "boundaryRegion",
+            const fileName& instance = "constant"
+        );
+
+
+        //- Write constant/boundaryRegion for later reuse
+        void writeDict
+        (
+            const objectRegistry&,
+            const word& name = "boundaryRegion",
+            const fileName& instance = "constant"
+        ) const;
+
+
+    // Member Operators
+
+        //- Assignment
+        void operator=(const boundaryRegion&);
+
+        //- Assign from Map<dictionary>
+        void operator=(const Map<dictionary>&);
+
+
+    // Friend Functions
+
+        //- Rename regions
+        //  each dictionary entry is a single word:
+        //  @verbatim
+        //      newPatchName    originalName;
+        //  @endverbatim
+        void rename(const dictionary&);
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/meshTables/cellTable.C b/src/conversion/meshTables/cellTable.C
new file mode 100644
index 0000000000000000000000000000000000000000..66e39a4cb9f8d15838049c0acd65d12c6b34f94b
--- /dev/null
+++ b/src/conversion/meshTables/cellTable.C
@@ -0,0 +1,587 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+
+\*---------------------------------------------------------------------------*/
+
+#include "cellTable.H"
+#include "IOMap.H"
+#include "OFstream.H"
+#include "wordList.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const char* const Foam::cellTable::defaultMaterial_ = "fluid";
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+//- map from cellTable Id -> zone number (unmapped = -1)
+Foam::labelList Foam::cellTable::zoneMap() const
+{
+    label maxId = 0;
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        if (maxId < iter.key())
+        {
+            maxId = iter.key();
+        }
+    }
+
+    label zoneI = 0;
+    labelList list(maxId+1, -1);
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        list[iter.key()] = zoneI++;
+    }
+
+    return list;
+}
+
+
+Foam::wordList Foam::cellTable::namesList() const
+{
+    Map<word> lookup = names();
+    wordList lst(lookup.size());
+
+    label n = 0;
+    forAllConstIter(Map<word>, lookup, iter)
+    {
+        lst[n] = iter();
+    }
+
+    lst.setSize(n);
+
+    return lst;
+}
+
+
+// add required entries - MaterialType
+void Foam::cellTable::addDefaults()
+{
+    forAllIter(Map<dictionary>, *this, iter)
+    {
+        if (!iter().found("MaterialType"))
+        {
+            iter().add("MaterialType", defaultMaterial_);
+        }
+    }
+}
+
+
+void Foam::cellTable::setEntry
+(
+    const label& id,
+    const word& keyWord,
+    const word& value
+)
+{
+    dictionary dict;
+    dict.add(keyWord, value);
+
+    iterator iter = find(id);
+    if (iter != end())
+    {
+        iter().merge(dict);
+    }
+    else
+    {
+        insert(id, dict);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+
+Foam::cellTable::cellTable()
+:
+    Map<dictionary>()
+{}
+
+
+// read constant/cellTable (IOMap<dictionary>)
+Foam::cellTable::cellTable
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+)
+:
+    Map<dictionary>()
+{
+    readDict(registry, name, instance);
+}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::cellTable::~cellTable()
+{}
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+Foam::label Foam::cellTable::append(const dictionary& dict)
+{
+    label maxId = -1;
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        if (maxId < iter.key())
+        {
+            maxId = iter.key();
+        }
+    }
+
+    insert(++maxId, dict);
+    return maxId;
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::names() const
+{
+    Map<word> lookup;
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word theName = "cellTable_" + Foam::name(iter.key());
+
+        iter().readIfPresent("Label", theName);
+
+        lookup.insert(iter.key(), theName);
+    }
+
+    return lookup;
+}
+
+
+Foam::word Foam::cellTable::name(const label& id) const
+{
+    const_iterator iter = find(id);
+
+    word theName = "cellTable_" + Foam::name(id);
+    if (iter != end())
+    {
+        iter().readIfPresent("Label", theName);
+    }
+
+    return theName;
+}
+
+
+Foam::label Foam::cellTable::findIndex(const word& name) const
+{
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word theName;
+        if (iter().readIfPresent("Label", theName))
+        {
+            if (theName == name)
+            {
+                return iter.key();
+            }
+        }
+    }
+
+    return -1;
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::selectType(const word& materialType) const
+{
+    Map<word> lookup;
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word matl(defaultMaterial_);
+
+        iter().readIfPresent("MaterialType", matl);
+
+        if (matl == materialType)
+        {
+            word theName = "cellTable_" + Foam::name(iter.key());
+
+            iter().readIfPresent("Label", theName);
+
+            lookup.insert(iter.key(), theName);
+        }
+    }
+
+    return lookup;
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::fluids() const
+{
+    return selectType("fluid");
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::solids() const
+{
+    return selectType("solid");
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::shells() const
+{
+    return selectType("shell");
+}
+
+
+Foam::Map<Foam::word>
+Foam::cellTable::materialTypes() const
+{
+    Map<word> lookup;
+
+    forAllConstIter(Map<dictionary>, *this, iter)
+    {
+        word matlType(defaultMaterial_);
+
+        iter().readIfPresent("MaterialType", matlType);
+
+        lookup.insert(iter.key(), matlType);
+    }
+
+    return lookup;
+}
+
+
+//- assign material Type
+void Foam::cellTable::setMaterial(const label& id, const word& matlType)
+{
+    setEntry(id, "MaterialType", matlType);
+}
+
+
+void Foam::cellTable::setName(const label& id, const word& name)
+{
+    setEntry(id, "Label", name);
+}
+
+
+void Foam::cellTable::setName(const label& id)
+{
+    iterator iter = find(id);
+
+    if (iter == end() || !iter().found("Label"))
+    {
+        setName(id, "cellTable_" + ::Foam::name(id));
+    }
+}
+
+
+// read constant/cellTable (IOMap<dictionary>)
+void Foam::cellTable::readDict
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+)
+{
+    clear();
+
+    // read constant/dictName
+    IOMap<dictionary> ioObj
+    (
+        IOobject
+        (
+            name,
+            instance,
+            registry,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    if (ioObj.headerOk())
+    {
+        *this = ioObj;
+        addDefaults();
+    }
+    else
+    {
+        Info<< "no constant/cellTable information available" << endl;
+    }
+}
+
+
+// write constant/cellTable for later reuse
+void Foam::cellTable::writeDict
+(
+    const objectRegistry& registry,
+    const word& name,
+    const fileName& instance
+) const
+{
+    // write constant/dictName
+    IOMap<dictionary> ioObj
+    (
+        IOobject
+        (
+            name,
+            instance,
+            registry,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    ioObj.note() = "persistent data for thirdParty mesh <-> OpenFOAM translation";
+
+    Info<< "Writing " << ioObj.name() << " to " << ioObj.objectPath() << endl;
+
+    OFstream os(ioObj.objectPath());
+    ioObj.writeHeader(os);
+    os << *this;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+
+void Foam::cellTable::operator=(const cellTable& rhs)
+{
+    Map<dictionary>::operator=(rhs);
+    addDefaults();
+}
+
+void Foam::cellTable::operator=(const Map<dictionary>& rhs)
+{
+    Map<dictionary>::operator=(rhs);
+    addDefaults();
+}
+
+void Foam::cellTable::operator=(const polyMesh& mesh)
+{
+    Map<dictionary> zoneDict;
+
+    // create cellTableId and cellTable based on cellZones
+    label nZoneCells = 0;
+
+    wordList zoneNames = mesh.cellZones().names();
+    label unZonedType = zoneNames.size() + 1;
+
+    // do cell zones
+    forAll(mesh.cellZones(), zoneI)
+    {
+        const cellZone& cZone = mesh.cellZones()[zoneI];
+        nZoneCells += cZone.size();
+
+        dictionary dict;
+        dict.add("Label", zoneNames[zoneI]);
+        zoneDict.insert(zoneI + 1, dict);
+    }
+
+    // collect unzoned cells
+    // special case: no zones at all - do entire mesh
+    if (nZoneCells == 0)
+    {
+        zoneDict.clear();
+        unZonedType = 1;
+    }
+
+    if (mesh.nCells() > nZoneCells)
+    {
+        zoneDict.insert
+        (
+            unZonedType,
+            dictionary
+            (
+                IStringStream("Label cells;")()
+            )
+        );
+    }
+
+    Map<dictionary>::operator=(zoneDict);
+    addDefaults();
+}
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+
+// attach cellZones based on the cellTable Id
+// - any other values can be extracted later from the cellTable dictionary
+void Foam::cellTable::addCellZones
+(
+    polyMesh& mesh,
+    const labelList& tableIds
+) const
+{
+    labelList typeToZone = zoneMap();
+    wordList  zoneNames = namesList();
+
+    List<DynamicList<label> > zoneCells(size());
+
+    forAll(tableIds, cellI)
+    {
+        label zoneI = typeToZone[tableIds[cellI]];
+        if (zoneI >= 0)
+        {
+            zoneCells[zoneI].append(cellI);
+        }
+    }
+
+    // avoid empty zones
+    labelList zoneUsed(zoneCells.size());
+
+    label nZone = 0;
+    forAll(zoneCells, zoneI)
+    {
+        zoneCells[zoneI].shrink();
+        if (zoneCells[zoneI].size() > 0)
+        {
+            zoneUsed[nZone++] = zoneI;
+        }
+    }
+    zoneUsed.setSize(nZone);
+
+    mesh.cellZones().clear();
+    if (nZone <= 1)
+    {
+        Info<< "cellZones not used" << endl;
+        return;
+    }
+    mesh.cellZones().setSize(nZone);
+
+    forAll(zoneUsed, zoneI)
+    {
+        const label origZoneI = zoneUsed[zoneI];
+
+        Info<< "cellZone " << zoneI
+            << " (size: " << zoneCells[origZoneI].size() << ") name: "
+            << zoneNames[origZoneI] << endl;
+
+        mesh.cellZones().set
+        (
+            zoneI,
+            new cellZone
+            (
+                zoneNames[origZoneI],
+                zoneCells[origZoneI],
+                zoneI,
+                mesh.cellZones()
+            )
+        );
+    }
+    mesh.cellZones().writeOpt() = IOobject::AUTO_WRITE;
+}
+
+
+void Foam::cellTable::combine(const dictionary& dict, labelList& tableIds)
+{
+    if (!dict.size())
+    {
+        return;
+    }
+
+    bool remap = false;
+    labelList mapping(identity(max(this->toc()) + 1));
+
+    forAllConstIter (dictionary, dict, iter)
+    {
+        wordList  zoneNames(iter().stream());
+        labelList zoneIndex(zoneNames.size());
+
+        label nElem = 0;
+        forAll (zoneNames, zoneI)
+        {
+            zoneIndex[nElem] = this->findIndex(zoneNames[zoneI]);
+            if (zoneIndex[nElem] >= 0)
+            {
+                if (zoneI != nElem)
+                {
+                    zoneNames[nElem] = zoneNames[zoneI];
+                }
+                ++nElem;
+            }
+        }
+
+        zoneIndex.setSize(nElem);
+        zoneNames.setSize(nElem);
+
+        if (nElem)
+        {
+            remap = true;
+            label targetId = this->findIndex(iter().keyword());
+
+            Info<< "combine cellTable: " << iter().keyword();
+            if (targetId >= 0)
+            {
+                Info<< " += (";
+            }
+            else
+            {
+                Info<< " = (";
+            }
+            forAll (zoneNames, zoneI)
+            {
+                Info<< " " << zoneNames[zoneI];
+            }
+            Info<< " )" << endl;
+
+            // re-use the first element if possible
+            if (targetId < 0)
+            {
+                targetId = min(zoneIndex);
+                dictionary newDict(operator[](targetId));
+
+                newDict.remove("Label");
+                newDict.add("Label", iter().keyword());
+                this->set(targetId, newDict);
+            }
+
+            forAll (zoneIndex, zoneI)
+            {
+                label idx = zoneIndex[zoneI];
+                if (idx != targetId && idx >= 0)
+                {
+                    mapping[idx] = targetId;
+                    this->erase(idx);
+                }
+            }
+        }
+    }
+
+    if (remap)
+    {
+        inplaceRenumber(mapping, tableIds);
+    }
+}
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshTables/cellTable.H b/src/conversion/meshTables/cellTable.H
new file mode 100644
index 0000000000000000000000000000000000000000..a0e092c7eec6c481871d8fb811ba787051a30836
--- /dev/null
+++ b/src/conversion/meshTables/cellTable.H
@@ -0,0 +1,207 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::cellTable
+
+Description
+    The cellTable persistent data saved as a Map<dictionary>.
+
+    The meshReader supports cellTable information.
+
+    The <tt>constant/cellTable</tt> file is an @c IOMap<dictionary> that is
+    used to save the information persistently. It contains the cellTable
+    information of the following form:
+
+    @verbatim
+        (
+            ID
+            {
+                Label           WORD;
+                MaterialType    WORD;
+                MaterialId      INT;
+                PorosityId      INT;
+                ColorIdx        INT;
+                ...
+            }
+        ...
+        )
+    @endverbatim
+
+    If the @a Label is missing, a value <tt>cellTable_{ID}</tt> will be
+    inferred. If the @a MaterialType is missing, the value @a fluid will
+    be inferred.
+
+SourceFiles
+    cellTable.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef cellTable_H
+#define cellTable_H
+
+#include "polyMesh.H"
+#include "Map.H"
+#include "dictionary.H"
+#include "labelList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class cellTable Declaration
+\*---------------------------------------------------------------------------*/
+
+class cellTable
+:
+    public Map<dictionary>
+{
+    // Private data
+        static const char* const defaultMaterial_;
+
+    // Private Member Functions
+
+        //- Map from cellTable ID => zone number (unmapped = -1)
+        labelList zoneMap() const;
+
+        //- A contiguous list of cellTable names
+        List<word> namesList() const;
+
+        //- Add required entries - MaterialType
+        void addDefaults();
+
+        void setEntry(const label& id, const word& keyWord, const word& value);
+
+        //- Disallow default bitwise copy construct
+        cellTable(const cellTable&);
+
+public:
+    // Static Members
+
+    // Constructors
+
+        //- Construct null
+        cellTable();
+
+        //- Construct read from registry, name. instance
+        cellTable
+        (
+            const objectRegistry&,
+            const word& name = "cellTable",
+            const fileName& instance = "constant"
+        );
+
+
+    // Destructor
+        ~cellTable();
+
+
+    // Member Functions
+
+        //- Append to the end, return index
+        label append(const dictionary&);
+
+        //- Return index corresponding to name
+        //  returns -1 if not found
+        label findIndex(const word& name) const;
+
+        //- Return the name corresponding to id
+        //  returns cellTable_ID if not otherwise defined
+        word name(const label& id) const;
+
+        //- Return a Map of (id => name)
+        Map<word> names() const;
+
+        //- Return a Map of (id => name) for materialType (fluid | solid | shell)
+        Map<word> selectType(const word& materialType) const;
+
+        //- Return a Map of (id => name) for fluids
+        Map<word> fluids() const;
+
+        //- Return a Map of (id => name) for shells
+        Map<word> shells() const;
+
+        //- Return a Map of (id => name) for solids
+        Map<word> solids() const;
+
+        //- Return a Map of (id => fluid|solid|shell)
+        Map<word> materialTypes() const;
+
+        //- Assign material Type
+        void setMaterial(const label&, const word&);
+
+        //- Assign name
+        void setName(const label&, const word&);
+
+        //- Assign default name if not already set
+        void setName(const label&);
+
+        //- Read constant/cellTable
+        void readDict
+        (
+            const objectRegistry&,
+            const word& name = "cellTable",
+            const fileName& instance = "constant"
+        );
+
+        //- write constant/cellTable for later reuse
+        void writeDict
+        (
+            const objectRegistry&,
+            const word& name = "cellTable",
+            const fileName& instance = "constant"
+        ) const;
+
+    // Member Operators
+
+        //- Assignment
+        void operator=(const cellTable&);
+
+        //- Assign from Map<dictionary>
+        void operator=(const Map<dictionary>&);
+
+        //- Assign from cellZones
+        void operator=(const polyMesh&);
+
+
+    // Friend Functions
+
+        //- Classify tableIds into cellZones according to the cellTable
+        void addCellZones(polyMesh&, const labelList& tableIds) const;
+
+        //- Combine tableIds together
+        //  each dictionary entry is a wordList
+        void combine(const dictionary&, labelList& tableIds);
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/meshWriter/meshWriter.C b/src/conversion/meshWriter/meshWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..ca9eeb019026d2756ad5b90832394503990a7798
--- /dev/null
+++ b/src/conversion/meshWriter/meshWriter.C
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "meshWriter.H"
+#include "cellModeller.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// Pointers to cell shape models
+const Foam::cellModel* Foam::meshWriter::unknownModel = Foam::cellModeller::
+lookup
+(
+    "unknown"
+);
+const Foam::cellModel* Foam::meshWriter::tetModel = Foam::cellModeller::
+lookup
+(
+    "tet"
+);
+const Foam::cellModel* Foam::meshWriter::pyrModel = Foam::cellModeller::
+lookup
+(
+    "pyr"
+);
+const Foam::cellModel* Foam::meshWriter::prismModel = Foam::cellModeller::
+lookup
+(
+    "prism"
+);
+const Foam::cellModel* Foam::meshWriter::hexModel = Foam::cellModeller::
+lookup
+(
+    "hex"
+);
+
+
+Foam::string Foam::meshWriter::defaultMeshName = "meshExport";
+Foam::string Foam::meshWriter::defaultSurfaceName = "surfExport";
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshWriter::meshWriter
+(
+    const polyMesh& mesh,
+    const scalar scaleFactor
+)
+:
+    mesh_(mesh),
+    scaleFactor_(scaleFactor),
+    writeBoundary_(true),
+    boundaryRegion_(),
+    cellTable_(),
+    cellTableId_()
+{}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::meshWriter::~meshWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/src/conversion/meshWriter/meshWriter.H b/src/conversion/meshWriter/meshWriter.H
new file mode 100644
index 0000000000000000000000000000000000000000..866bd0072ffe4fb2671d8493b7c5c539410c827e
--- /dev/null
+++ b/src/conversion/meshWriter/meshWriter.H
@@ -0,0 +1,218 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Namespace
+    Foam::meshWriters
+
+Description
+    A namespace for holding various types of mesh writers.
+
+
+Class
+    Foam::meshWriter
+
+Description
+    write OpenFOAM meshes and/or results to another CFD format
+    - currently just STAR-CD
+
+@par Files
+
+    "constant/boundaryRegion" is an IOMap<dictionary> that contains
+    the boundary type and names. eg,
+    @verbatim
+        (
+            0
+            {
+                BoundaryType    wall;
+                Label           Default_Boundary_Region;
+            }
+
+            1
+            {
+                BoundaryType    inlet;
+                Label           inlet_1;
+            }
+
+            ...
+
+            4
+            {
+                BoundaryType    pressure;
+                Label           outlet;
+            }
+        )
+    @endverbatim
+
+
+SourceFiles
+    meshWriterI.H
+    meshWriter.C
+    meshWriterIO.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef meshWriter_H
+#define meshWriter_H
+
+#include "polyMesh.H"
+#include "boundaryRegion.H"
+#include "cellTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class meshWriter Declaration
+\*---------------------------------------------------------------------------*/
+
+class meshWriter
+{
+    // Private data
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        meshWriter(const meshWriter&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const meshWriter&);
+
+protected:
+    // Protected data
+
+        //- mesh reference
+        const polyMesh& mesh_;
+
+        //- scaling factor for points (eg, [m] -> [mm])
+        scalar scaleFactor_;
+
+        //- write bnd file
+        bool writeBoundary_;
+
+        //- boundaryRegion persistent data saved as a dictionary
+        boundaryRegion boundaryRegion_;
+
+        //- cellTable persistent data saved as a dictionary
+        cellTable cellTable_;
+
+        // cellTable IDs for each cell
+        labelList cellTableId_;
+
+        //- Pointers to cell shape models
+        static const cellModel* unknownModel;
+        static const cellModel* tetModel;
+        static const cellModel* pyrModel;
+        static const cellModel* prismModel;
+        static const cellModel* hexModel;
+
+public:
+
+    // Static data members
+
+        static string defaultMeshName;
+        static string defaultSurfaceName;
+
+
+    // Constructors
+
+        //- create a writer obejct
+        meshWriter
+        (
+            const polyMesh&,
+            const scalar scaleFactor = 1.0
+        );
+
+
+    // Selectors
+
+    // Destructor
+
+        virtual ~meshWriter();
+
+
+    // Member Functions
+
+        // Access
+
+        // Check
+
+        // Edit
+
+        //- set points scaling
+        void scaleFactor(const scalar scaling)
+        {
+            scaleFactor_ = scaling;
+        }
+
+        //- suppress writing bnd file
+        void noBoundary()
+        {
+            writeBoundary_ = false;
+        }
+
+        // Write
+
+        //- write volume mesh
+        //  subclass must to supply this method
+        virtual bool write
+        (
+            const fileName& timeName = fileName::null
+        ) const = 0;
+
+        //- write surface mesh with optional triangulation
+        //  subclass could supply this information
+        virtual bool writeSurface
+        (
+            const fileName& timeName = fileName::null,
+            const bool& triangulate = false
+        ) const
+        {
+            return false;
+        }
+
+    // Member Operators
+
+    // Friend Functions
+
+    // Friend Operators
+
+    // IOstream Operators
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// #include "meshWriterI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/meshWriter/starcd/STARCDMeshWriter.C b/src/conversion/meshWriter/starcd/STARCDMeshWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..f382f096060ab953c91032a8a20686d0bc16495a
--- /dev/null
+++ b/src/conversion/meshWriter/starcd/STARCDMeshWriter.C
@@ -0,0 +1,757 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "STARCDMeshWriter.H"
+
+#include "Time.H"
+#include "SortableList.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// special boundary regions
+const char* Foam::meshWriters::STARCD::defaultBoundaryName =
+    "Default_Boundary_Region";
+
+// face addressing from foam faces -> pro-STAR faces for primitive shapes
+const Foam::label Foam::meshWriters::STARCD::foamToStarFaceAddr[4][6] =
+{
+    { 4, 5, 2, 3, 0, 1 },     // 11 = pro-STAR hex
+    { 0, 1, 4, 5, 2, -1 },    // 12 = pro-STAR prism
+    { 5, 4, 2, 0, -1, -1 },   // 13 = pro-STAR tetra
+    { 0, 4, 3, 5, 2, -1 }     // 14 = pro-STAR pyramid
+};
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::meshWriters::STARCD::findDefaultBoundary() const
+{
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    label id = -1;
+
+    // find Default_Boundary_Region if it exists
+    forAll(patches, patchI)
+    {
+        if (defaultBoundaryName == patches[patchI].name())
+        {
+            id = patchI;
+            break;
+        }
+    }
+    return id;
+}
+
+
+void Foam::meshWriters::STARCD::getCellTable()
+{
+    // read constant/polyMesh/propertyName
+    IOList<label> ioList
+    (
+        IOobject
+        (
+            "cellTableId",
+            "constant",
+            polyMesh::meshSubDir,
+            mesh_,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    bool useCellZones = false;
+    cellTableId_.setSize(mesh_.nCells(), -1);
+
+    // get information from constant/polyMesh/cellTableId if possible
+    if (ioList.headerOk())
+    {
+        if (ioList.size() == mesh_.nCells())
+        {
+            cellTableId_.transfer(ioList);
+
+            if (!cellTable_.size())
+            {
+                Info<< "no cellTable information available" << endl;
+            }
+        }
+        else
+        {
+            WarningIn("STARCD::getCellTable()")
+                << ioList.objectPath() << " has incorrect number of cells "
+                << " - use cellZone information"
+                << endl;
+
+            ioList.clear();
+            useCellZones = true;
+        }
+    }
+    else
+    {
+        useCellZones = true;
+    }
+
+
+    if (useCellZones)
+    {
+        if (!cellTable_.size())
+        {
+            Info<< "created cellTable from cellZones" << endl;
+            cellTable_ = mesh_;
+        }
+
+        // track if there are unzoned cells
+        label nUnzoned = mesh_.nCells();
+
+        // get the cellZone <-> cellTable correspondence
+        Info<< "matching cellZones to cellTable" << endl;
+
+        forAll (mesh_.cellZones(), zoneI)
+        {
+            const cellZone& cZone = mesh_.cellZones()[zoneI];
+            if (cZone.size())
+            {
+                nUnzoned -= cZone.size();
+
+                label tableId = cellTable_.findIndex(cZone.name());
+                if (tableId < 0)
+                {
+                    dictionary dict;
+
+                    dict.add("Label", cZone.name());
+                    dict.add("MaterialType", "fluid");
+                    tableId = cellTable_.append(dict);
+                }
+
+                forAll (cZone, i)
+                {
+                    cellTableId_[cZone[i]] = tableId;
+                }
+            }
+        }
+
+        if (nUnzoned)
+        {
+            dictionary dict;
+
+            dict.add("Label", "__unZonedCells__");
+            dict.add("MaterialType", "fluid");
+            label tableId = cellTable_.append(dict);
+
+            forAll (cellTableId_, i)
+            {
+                if (cellTableId_[i] < 0)
+                {
+                    cellTableId_[i] = tableId;
+                }
+            }
+        }
+    }
+}
+
+
+// Prostar 4+ header format
+void Foam::meshWriters::STARCD::writeHeader
+(
+    Ostream& os,
+    const char* filetype
+)
+{
+    os  << "PROSTAR_" << filetype << nl
+        << 4000
+        << " " << 0
+        << " " << 0
+        << " " << 0
+        << " " << 0
+        << " " << 0
+        << " " << 0
+        << " " << 0
+        << endl;
+}
+
+
+void Foam::meshWriters::STARCD::writePoints
+(
+    const fileName& prefix
+) const
+{
+    OFstream os(prefix + ".vrt");
+    writeHeader(os, "VERTEX");
+
+    // Set the precision of the points data to 10
+    os.precision(10);
+
+    // force decimal point for Fortran input
+    os.setf(std::ios::showpoint);
+
+    const pointField& points = mesh_.points();
+
+    Info<< "Writing " << os.name() << " : "
+        << points.size() << " points" << endl;
+
+    forAll(points, ptI)
+    {
+        // convert [m] -> [mm]
+        os
+            << ptI + 1 << " "
+            << scaleFactor_ * points[ptI].x() << " "
+            << scaleFactor_ * points[ptI].y() << " "
+            << scaleFactor_ * points[ptI].z() << nl;
+    }
+    os.flush();
+
+}
+
+
+void Foam::meshWriters::STARCD::writeCells
+(
+    const fileName& prefix
+) const
+{
+    OFstream os(prefix + ".cel");
+    writeHeader(os, "CELL");
+
+    // this is what we seem to need
+    // map foam cellModeller index -> star shape
+    Map<label> shapeLookupIndex;
+    shapeLookupIndex.insert(hexModel->index(), 11);
+    shapeLookupIndex.insert(prismModel->index(), 12);
+    shapeLookupIndex.insert(tetModel->index(), 13);
+    shapeLookupIndex.insert(pyrModel->index(), 14);
+
+    const cellShapeList& shapes = mesh_.cellShapes();
+    const cellList& cells  = mesh_.cells();
+    const faceList& faces  = mesh_.faces();
+    const labelList& owner = mesh_.faceOwner();
+
+    Info<< "Writing " << os.name() << " : "
+        << cells.size() << " cells" << endl;
+
+    forAll(cells, cellId)
+    {
+        label tableId = cellTableId_[cellId];
+        label materialType  = 1;        // 1(fluid)
+        if (cellTable_.found(tableId))
+        {
+            const dictionary& dict = cellTable_[tableId];
+            if (dict.found("MaterialType"))
+            {
+                word matType;
+                dict.lookup("MaterialType") >> matType;
+                if (matType == "solid")
+                {
+                    materialType = 2;
+                }
+
+            }
+        }
+
+        const cellShape& shape = shapes[cellId];
+        label mapIndex = shape.model().index();
+
+        // a registered primitive type
+        if (shapeLookupIndex.found(mapIndex))
+        {
+            label shapeId = shapeLookupIndex[mapIndex];
+            const labelList& vrtList = shapes[cellId];
+
+            os  << cellId + 1
+                << " " << shapeId
+                << " " << vrtList.size()
+                << " " << tableId
+                << " " << materialType;
+
+            // primitives have <= 8 vertices, but prevent overrun anyhow
+            // indent following lines for ease of reading
+            label count = 0;
+            forAll(vrtList, i)
+            {
+                if ((count % 8) == 0)
+                {
+                    os  << nl
+                        << "  " << cellId + 1;
+                }
+                os << " " << vrtList[i] + 1;
+                count++;
+            }
+            os << endl;
+
+        }
+        else
+        {
+            label shapeId = 255;        // treat as general polyhedral
+            const labelList& cFaces  = cells[cellId];
+
+            // create (beg,end) indices
+            List<label> indices(cFaces.size() + 1);
+            indices[0] = indices.size();
+
+            label count = indices.size();
+            // determine the total number of vertices
+            forAll(cFaces, faceI)
+            {
+                count += faces[cFaces[faceI]].size();
+                indices[faceI+1] = count;
+            }
+
+            os  << cellId + 1
+                << " " << shapeId
+                << " " << count
+                << " " << tableId
+                << " " << materialType;
+
+            // write indices - max 8 per line
+            // indent following lines for ease of reading
+            count = 0;
+            forAll(indices, i)
+            {
+                if ((count % 8) == 0)
+                {
+                    os  << nl
+                        << "  " << cellId + 1;
+                }
+                os << " " << indices[i];
+                count++;
+            }
+
+            // write faces - max 8 per line
+            forAll(cFaces, faceI)
+            {
+                label meshFace = cFaces[faceI];
+                face f;
+
+                if (owner[meshFace] == cellId)
+                {
+                    f = faces[meshFace];
+                }
+                else
+                {
+                    f = faces[meshFace].reverseFace();
+                }
+
+                forAll(f, i)
+                {
+                    if ((count % 8) == 0)
+                    {
+                        os  << nl
+                            << "  " << cellId + 1;
+                    }
+
+                    os << " " << f[i] + 1;
+                    count++;
+                }
+            }
+
+            os << endl;
+        }
+    }
+}
+
+
+void Foam::meshWriters::STARCD::writeBoundary
+(
+    const fileName& prefix
+) const
+{
+    OFstream os(prefix + ".bnd");
+    writeHeader(os, "BOUNDARY");
+
+    const cellShapeList& shapes = mesh_.cellShapes();
+    const cellList& cells  = mesh_.cells();
+    const faceList& faces  = mesh_.faces();
+    const labelList& owner = mesh_.faceOwner();
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    // this is what we seem to need
+    // these MUST correspond to foamToStarFaceAddr
+    //
+    Map<label> faceLookupIndex;
+    faceLookupIndex.insert(hexModel->index(), 0);
+    faceLookupIndex.insert(prismModel->index(), 1);
+    faceLookupIndex.insert(tetModel->index(), 2);
+    faceLookupIndex.insert(pyrModel->index(), 3);
+
+    Info<< "Writing " << os.name() << " : "
+        << (mesh_.nFaces() - patches[0].start()) << " boundaries" << endl;
+
+
+    label defaultId = findDefaultBoundary();
+
+    //
+    // write boundary faces - skip Default_Boundary_Region entirely
+    //
+    label boundId = 0;
+    forAll(patches, patchI)
+    {
+        label regionId = patchI;
+        if (regionId == defaultId)
+        {
+            continue;	// skip - already written
+        }
+        else if (defaultId == -1 || regionId < defaultId)
+        {
+            regionId++;
+        }
+
+        label patchStart = patches[patchI].start();
+        label patchSize  = patches[patchI].size();
+        word  bndType = boundaryRegion_.boundaryType(patches[patchI].name());
+
+        for
+        (
+            label faceI = patchStart;
+            faceI < (patchStart + patchSize);
+            ++faceI
+        )
+        {
+            label cellId = owner[faceI];
+            const labelList& cFaces  = cells[cellId];
+            const cellShape& shape = shapes[cellId];
+            label cellFaceId = findIndex(cFaces, faceI);
+
+            //      Info<< "cell " << cellId + 1 << " face " << faceI
+            //          << " == " << faces[faceI]
+            //          << " is index " << cellFaceId << " from " << cFaces;
+
+            // Unfortunately, the order of faces returned by
+            //   primitiveMesh::cells() is not necessarily the same
+            //   as defined by primitiveMesh::cellShapes()
+            // Thus, for registered primitive types, do the lookup ourselves.
+            // Finally, the cellModel face number is re-mapped to the
+            // STAR-CD local face number
+
+            label mapIndex = shape.model().index();
+
+            // a registered primitive type
+            if (faceLookupIndex.found(mapIndex))
+            {
+                const faceList sFaces = shape.faces();
+                forAll(sFaces, sFaceI)
+                {
+                    if (faces[faceI] == sFaces[sFaceI])
+                    {
+                        cellFaceId = sFaceI;
+                        break;
+                    }
+                }
+
+                mapIndex = faceLookupIndex[mapIndex];
+                cellFaceId = foamToStarFaceAddr[mapIndex][cellFaceId];
+            }
+            // Info<< endl;
+
+            boundId++;
+
+            os
+                << boundId
+                << " " << cellId + 1
+                << " " << cellFaceId + 1
+                << " " << regionId
+                << " " << 0
+                << " " << bndType.c_str()
+                << endl;
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshWriters::STARCD::STARCD
+(
+    const polyMesh& mesh,
+    const scalar scaleFactor
+)
+:
+    meshWriter(mesh, scaleFactor)
+{
+    boundaryRegion_.readDict(mesh_);
+    cellTable_.readDict(mesh_);
+    getCellTable();
+}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::meshWriters::STARCD::~STARCD()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::meshWriters::STARCD::rmFiles
+(
+    const fileName& baseName
+) const
+{
+    rm(baseName + ".vrt");
+    rm(baseName + ".cel");
+    rm(baseName + ".bnd");
+    rm(baseName + ".inp");
+}
+
+
+bool Foam::meshWriters::STARCD::write
+(
+    const fileName& meshName
+) const
+{
+    fileName baseName(meshName);
+
+    if (!baseName.size())
+    {
+        baseName = meshWriter::defaultMeshName;
+
+        if
+        (
+            mesh_.time().timeName() != "0"
+         && mesh_.time().timeName() != "constant"
+        )
+        {
+            baseName += "_" + mesh_.time().timeName();
+        }
+    }
+
+    rmFiles(baseName);
+    writePoints(baseName);
+    writeCells(baseName);
+
+    if (writeBoundary_)
+    {
+        writeBoundary(baseName);
+    }
+
+    return true;
+}
+
+
+bool Foam::meshWriters::STARCD::writeSurface
+(
+    const fileName& meshName,
+    const bool& triangulate
+) const
+{
+    fileName baseName(meshName);
+
+    if (!baseName.size())
+    {
+        baseName = meshWriter::defaultSurfaceName;
+
+        if
+        (
+            mesh_.time().timeName() != "0"
+         && mesh_.time().timeName() != "constant"
+        )
+        {
+            baseName += "_" + mesh_.time().timeName();
+        }
+    }
+
+    rmFiles(baseName);
+
+    OFstream celFile(baseName + ".cel");
+    writeHeader(celFile, "CELL");
+
+    Info << "Writing " << celFile.name() << endl;
+
+    // mesh and patch info
+    const pointField& points = mesh_.points();
+    const labelList& owner = mesh_.faceOwner();
+    const faceList& meshFaces = mesh_.faces();
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    label shapeId = 3;  // shell/baffle element
+    label typeId  = 4;  // 4(shell)
+
+    // remember which points need to be written
+    labelHashSet pointHash;
+
+    // write boundary faces as normal STAR-CD mesh
+    if (triangulate)
+    {
+        // cell Id has no particular meaning - just increment
+        // use the cellTable id from the patch Number
+        label cellId = 0;
+
+        forAll(patches, patchI)
+        {
+            label patchStart = patches[patchI].start();
+            label patchSize  = patches[patchI].size();
+
+            label ctableId = patchI + 1;
+
+            for
+            (
+                label faceI = patchStart;
+                faceI < (patchStart + patchSize);
+                ++faceI
+            )
+            {
+                const face& f = meshFaces[faceI];
+
+                label nTri = f.nTriangles(points);
+                faceList triFaces;
+
+                // triangulate polygons, but not quads
+                if (nTri <= 2)
+                {
+                    triFaces.setSize(1);
+                    triFaces[0] = f;
+                }
+                else
+                {
+                    triFaces.setSize(nTri);
+                    nTri = 0;
+                    f.triangles(points, nTri, triFaces);
+                }
+
+                forAll(triFaces, faceI)
+                {
+                    const labelList& vrtList = triFaces[faceI];
+
+                    celFile
+                        << cellId + 1 << " "
+                        << shapeId << " "
+                        << vrtList.size() << " "
+                        << ctableId << " "
+                        << typeId;
+
+                    // must be 3 (triangle) but could be quad
+                    label count = 0;
+                    forAll(vrtList, i)
+                    {
+                        if ((count % 8) == 0)
+                        {
+                            celFile
+                                << nl
+                                << "  " << cellId + 1;
+                        }
+                        // remember which points we'll need to write
+                        pointHash.insert(vrtList[i]);
+                        celFile << " " << vrtList[i] + 1;
+                        count++;
+                    }
+                    celFile << endl;
+
+                    cellId++;
+                }
+            }
+        }
+    }
+    else
+    {
+        // cell Id is the OpenFOAM face Id
+        // use the cellTable id from the face owner
+        // - allows separation of parts
+        forAll(patches, patchI)
+        {
+            label patchStart = patches[patchI].start();
+            label patchSize  = patches[patchI].size();
+
+            for
+            (
+                label faceI = patchStart;
+                faceI < (patchStart + patchSize);
+                ++faceI
+            )
+            {
+                const labelList& vrtList = meshFaces[faceI];
+                label cellId = faceI;
+
+                celFile
+                    << cellId + 1 << " "
+                    << shapeId << " "
+                    << vrtList.size() << " "
+                    << cellTableId_[owner[faceI]] << " "
+                    << typeId;
+
+                // likely <= 8 vertices, but prevent overrun anyhow
+                label count = 0;
+                forAll(vrtList, i)
+                {
+                    if ((count % 8) == 0)
+                    {
+                        celFile
+                            << nl
+                            << "  " << cellId + 1;
+                    }
+                    // remember which points we'll need to write
+                    pointHash.insert(vrtList[i]);
+                    celFile << " " << vrtList[i] + 1;
+                    count++;
+                }
+                celFile << endl;
+            }
+        }
+    }
+
+    OFstream vrtFile(baseName + ".vrt");
+    writeHeader(vrtFile, "VERTEX");
+
+    vrtFile.precision(10);
+    vrtFile.setf(std::ios::showpoint);  // force decimal point for Fortran
+
+    Info << "Writing " << vrtFile.name() << endl;
+
+    // build sorted table of contents
+    SortableList<label> toc(pointHash.size());
+    {
+        label i = 0;
+        forAllConstIter(labelHashSet, pointHash, iter)
+        {
+            toc[i++] = iter.key();
+        }
+    }
+    toc.sort();
+    pointHash.clear();
+
+    // write points in sorted order
+    forAll(toc, i)
+    {
+        label vrtId = toc[i];
+        vrtFile
+            << vrtId + 1
+            << " " << scaleFactor_ * points[vrtId].x()
+            << " " << scaleFactor_ * points[vrtId].y()
+            << " " << scaleFactor_ * points[vrtId].z()
+            << endl;
+    }
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+// ************************************************************************* //
diff --git a/src/conversion/meshWriter/starcd/STARCDMeshWriter.H b/src/conversion/meshWriter/starcd/STARCDMeshWriter.H
new file mode 100644
index 0000000000000000000000000000000000000000..1bbdf7dd455642c9d294721ad2889035daba84dd
--- /dev/null
+++ b/src/conversion/meshWriter/starcd/STARCDMeshWriter.H
@@ -0,0 +1,167 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::meshWriters::STARCD
+
+Description
+    Writes polyMesh in pro-STAR (v4) bnd/cel/vrt format
+
+    Alternatively, extracts the surface of the FOAM mesh into
+    pro-STAR (v4) .cel/.vrt/ format.
+    This can be useful, for example, for surface morphing in an external
+    package.
+
+    The cellTableId and cellTable information are used (if available).
+    Otherwise the cellZones are used (if available).
+
+SourceFiles
+    STARCDMeshWriter.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef STARCDMeshWriter_H
+#define STARCDMeshWriter_H
+
+#include "meshWriter.H"
+#include "IOstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace meshWriters
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class meshWriters::STARCD Declaration
+\*---------------------------------------------------------------------------*/
+
+class STARCD
+:
+    public meshWriter
+{
+    // Private Data
+        static const char* defaultBoundaryName;
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        STARCD(const STARCD&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const STARCD&);
+
+        //- pro-STAR 4+ header format
+        static void writeHeader(Ostream&, const char* filetype);
+
+        //- write points
+        void writePoints(const fileName& baseName) const;
+
+        //- write cells
+        void writeCells(const fileName& baseName) const;
+
+        //- write boundary
+        void writeBoundary(const fileName& baseName) const;
+
+        void getCellTable();
+
+        label findDefaultBoundary() const;
+
+public:
+
+    // Static data members
+
+        //- Face addressing from OpenFOAM faces -> pro-STAR faces
+        static const label foamToStarFaceAddr[4][6];
+
+
+    // Constructors
+
+        //- open a file for writing
+        STARCD
+        (
+            const polyMesh&,
+            const scalar scaleFactor = 1.0
+        );
+
+    // Selectors
+
+    // Destructor
+
+        virtual ~STARCD();
+
+
+    // Member Functions
+
+        // Access
+
+        // Check
+
+        // Edit
+
+        // Write
+
+
+        //- Remove STAR-CD files for the baseName
+        void rmFiles(const fileName& baseName) const;
+
+        //- write volume mesh
+        virtual bool write
+        (
+            const fileName& meshName = fileName::null
+        ) const;
+
+        //- write surface mesh with optional triangulation
+        virtual bool writeSurface
+        (
+            const fileName& meshName = fileName::null,
+            const bool& triangulate = false
+        ) const;
+
+
+    // Member Operators
+
+    // Friend Functions
+
+    // Friend Operators
+
+    // IOstream Operators
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace meshWriters
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.C b/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.C
index c3427b4bded0a4c28ae931f79021ee374d885ddd..2d2f6f204c49d2e26b6f09f888bd72f3b5bf58a8 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.C
+++ b/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.C
@@ -156,8 +156,8 @@ void Foam::flowRateInletVelocityFvPatchVectorField::updateCoeffs()
         FatalErrorIn
         (
             "flowRateInletVelocityFvPatchVectorField::updateCoeffs()"
-        )   << "dimensions of phi are incorrect"
-            << "\n    on patch " << this->patch().name()
+        )   << "dimensions of " << phiName_ << " are incorrect" << nl
+            << "    on patch " << this->patch().name()
             << " of field " << this->dimensionedInternalField().name()
             << " in file " << this->dimensionedInternalField().objectPath()
             << nl << exit(FatalError);
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.H b/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.H
index b0c8de9b2f018be80b6060eb2d87eba3214d2060..ff5b0e4afc09f4d06163fc2ca9de41a080f45b6c 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/flowRateInletVelocity/flowRateInletVelocityFvPatchVectorField.H
@@ -26,12 +26,13 @@ Class
     Foam::flowRateInletVelocityFvPatchVectorField
 
 Description
-    Describes an volumetric/mass flow normal vector boundary condition by its
+    Describes a volumetric/mass flow normal vector boundary condition by its
     magnitude as an integral over its area.
+
     The basis of the patch (volumetric or mass) is determined by the
     dimensions of the flux, phi.
-    The current density is used to correct the velocity when applying the mass
-    basis.
+    The current density is used to correct the velocity when applying the
+    mass basis.
 
     Example of the boundary condition specification:
     @verbatim
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingFlowRateInletVelocity/timeVaryingFlowRateInletVelocityFvPatchVectorField.H b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingFlowRateInletVelocity/timeVaryingFlowRateInletVelocityFvPatchVectorField.H
index cbacacb4c545b205afe14eeffc82412729b7ad38..21198d936eaff29ec63932bf956f79abd57aa5af 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingFlowRateInletVelocity/timeVaryingFlowRateInletVelocityFvPatchVectorField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingFlowRateInletVelocity/timeVaryingFlowRateInletVelocityFvPatchVectorField.H
@@ -46,7 +46,7 @@ Note
     - strange behaviour with potentialFoam since the U equation is not solved
 
 See Also
-    Foam::timeSeries and Foam::flowRateInletVelocityFvPatchVectorField
+    Foam::interpolationTable and Foam::flowRateInletVelocityFvPatchVectorField
 
 SourceFiles
     timeVaryingFlowRateInletVelocityFvPatchVectorField.C
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValueFvPatchField.H b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValueFvPatchField.H
index bd073c24b1ce638b8c4d8307f4ccba9609bb3a07..b6ce246cc6d92dbfa4c2234abe7642823badb0f2 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValueFvPatchField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformFixedValue/timeVaryingUniformFixedValueFvPatchField.H
@@ -43,7 +43,7 @@ Note
     a uniformFixedValue patch.
 
 See Also
-    Foam::timeSeries and Foam::fixedValueFvPatchField
+    Foam::interpolationTable and Foam::fixedValueFvPatchField
 
 SourceFiles
     timeVaryingUniformFixedValueFvPatchField.C
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformTotalPressure/timeVaryingUniformTotalPressureFvPatchScalarField.H b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformTotalPressure/timeVaryingUniformTotalPressureFvPatchScalarField.H
index 4bfead28d1cbd105ca4cbf6753f8a463e8147be7..8d02bcefeb872cdc2906e224de235591b8295d1c 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformTotalPressure/timeVaryingUniformTotalPressureFvPatchScalarField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/timeVaryingUniformTotalPressure/timeVaryingUniformTotalPressureFvPatchScalarField.H
@@ -26,8 +26,11 @@ Class
     Foam::timeVaryingUniformTotalPressureFvPatchScalarField
 
 Description
-    See timeVaryingUniformFixedValueFvPatchField.H
-    and totalPressureFvPatchScalarField.H
+    A time-varying form of a uniform total pressure boundary condition.
+
+See Also
+    Foam::timeVaryingUniformFixedValueFvPatchField
+    and Foam::totalPressureFvPatchScalarField.H
 
 SourceFiles
     timeVaryingUniformTotalPressureFvPatchScalarField.C
diff --git a/tutorials/rhoPimpleFoam/angledDuct/0/U b/tutorials/rhoPimpleFoam/angledDuct/0/U
index f18de82fff1381139696e2a69a48a5128a71e068..54bfd05ea9389f3d0f9782ef24163eb49cdf8d6e 100644
--- a/tutorials/rhoPimpleFoam/angledDuct/0/U
+++ b/tutorials/rhoPimpleFoam/angledDuct/0/U
@@ -42,8 +42,8 @@ boundaryField
     }
     inlet
     {
-        type            massFlowRateInletVelocity;
-        massFlowRate    0.1;
+        type            flowRateInletVelocity;
+        flowRate        0.1;
         value           uniform (0 0 0);
     }
     outlet
diff --git a/tutorials/rhoPorousSimpleFoam/angledDuctImplicit/0/U b/tutorials/rhoPorousSimpleFoam/angledDuctImplicit/0/U
index e6ded2df85a075c0f57c3d5ddde201a2509a9509..afea1eb58d696c9239afc01401fc420db42598eb 100644
--- a/tutorials/rhoPorousSimpleFoam/angledDuctImplicit/0/U
+++ b/tutorials/rhoPorousSimpleFoam/angledDuctImplicit/0/U
@@ -42,8 +42,8 @@ boundaryField
     }
     inlet
     {
-        type            massFlowRateInletVelocity;
-        massFlowRate    0.1;
+        type            flowRateInletVelocity;
+        flowRate        0.1;
         value           uniform (0 0 0);
     }
     outlet