diff --git a/applications/utilities/preProcessing/createZeroDirectory/Make/files b/applications/utilities/preProcessing/createZeroDirectory/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..379802af212b085610fcc077f9da4444e55d9bc6
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/Make/files
@@ -0,0 +1,7 @@
+boundaryInfo.C
+boundaryTemplates.C
+caseInfo.C
+solverTemplate.C
+createZeroDirectory.C
+
+EXE = $(FOAM_APPBIN)/createZeroDirectory
diff --git a/applications/utilities/preProcessing/createZeroDirectory/Make/options b/applications/utilities/preProcessing/createZeroDirectory/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..e3f71c9a4143544cdf3979ccd351492d4bf02ba7
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/Make/options
@@ -0,0 +1,12 @@
+EXE_INC = \
+    -DFULLDEBUG -g -O0 \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/dynamicMesh/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/regionModels/regionModel/lnInclude
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -ldynamicMesh \
+    -lmeshTools \
+    -lregionModels
diff --git a/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C
new file mode 100644
index 0000000000000000000000000000000000000000..ced18bce1df2b7b745d7dc4811c956bcc3bf6ed1
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C
@@ -0,0 +1,126 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "boundaryInfo.H"
+#include "Time.H"
+#include "IOPtrList.H"
+#include "polyMesh.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::boundaryInfo::boundaryInfo(const Time& runTime, const word& regionName)
+:
+    names_(),
+    types_(),
+    constraint_(),
+    groups_(),
+    allGroupNames_()
+{
+    // read the mesh boundaries for the current region
+    Info<< "    Reading mesh boundaries" << endl;
+
+    const_cast<word&>(IOPtrList<entry>::typeName) = word::null;
+    IOPtrList<entry> boundaryPatchList
+    (
+        IOobject
+        (
+            "boundary",
+            runTime.constant(),
+            regionName/polyMesh::meshSubDir,
+            runTime,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        )
+    );
+
+    names_.setSize(boundaryPatchList.size());
+    types_.setSize(boundaryPatchList.size());
+    constraint_.setSize(boundaryPatchList.size(), false);
+    groups_.setSize(boundaryPatchList.size());
+
+
+    forAll(boundaryPatchList, patchI)
+    {
+        const dictionary& dict = boundaryPatchList[patchI].dict();
+
+        names_[patchI] = dict.dictName();
+        dict.lookup("type") >> types_[patchI];
+        if (polyPatch::constraintType(types_[patchI]))
+        {
+            constraint_[patchI] = true;
+        }
+
+        if (dict.found("inGroups"))
+        {
+            dict.lookup("inGroups") >> groups_[patchI];
+            allGroupNames_.insert(groups_[patchI]);
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const Foam::wordList& Foam::boundaryInfo::names() const
+{
+    return names_;
+}
+
+
+const Foam::wordList& Foam::boundaryInfo::types() const
+{
+    return types_;
+}
+
+
+const Foam::boolList& Foam::boundaryInfo::constraint() const
+{
+    return constraint_;
+}
+
+
+const Foam::List<Foam::wordList>& Foam::boundaryInfo::groups() const
+{
+    return groups_;
+}
+
+
+const Foam::wordHashSet& Foam::boundaryInfo::allGroupNames() const
+{
+    return allGroupNames_;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.H b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.H
new file mode 100644
index 0000000000000000000000000000000000000000..eba0761d8629c0fb721c28ffe4535fb206f80f47
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.H
@@ -0,0 +1,103 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::boundaryInfo
+
+Description
+    Class to interrogate the polyMesh/boundary file to provide mesh patching
+    information, without the need to read the mesh.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryInfo_H
+#define boundaryInfo_H
+
+#include "boolList.H"
+#include "wordList.H"
+#include "HashSet.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class Time;
+
+/*---------------------------------------------------------------------------*\
+                        Class boundaryInfo Declaration
+\*---------------------------------------------------------------------------*/
+
+class boundaryInfo
+{
+    // Private data
+
+        //- Patch names
+        wordList names_;
+
+        //- Patch types
+        wordList types_;
+
+        //- Constraint flag
+        boolList constraint_;
+
+        //- Groups per patch
+        List<wordList> groups_;
+
+        //- Set of all group names
+        wordHashSet allGroupNames_;
+
+
+public:
+
+    //- Constructor
+    boundaryInfo(const Time& runTime, const word& regionName);
+
+
+    // Public member functions
+
+        //- Patch names
+        const wordList& names() const;
+
+        //- Patch types
+        const wordList& types() const;
+
+        //- Constraint flag
+        const boolList& constraint() const;
+
+        //- Groups
+        const List<wordList>& groups() const;
+
+        //- Set of all group names
+        const wordHashSet& allGroupNames() const;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.C b/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..1c894d02a656593a9b4177925b59cbfee2db3a0c
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.C
@@ -0,0 +1,463 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "boundaryTemplates.H"
+#include "Time.H"
+#include "IFstream.H"
+#include "OStringStream.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::boundaryTemplates::boundaryTemplates
+(
+    const fileName& baseDir,
+    const Time& runTime,
+    const word& solverType
+)
+:
+    templates_(dictionary::null),
+    options_(dictionary::null)
+{
+    Info<< "    Reading boundary templates" << endl;
+
+    fileName BCDir(baseDir/"boundaryConditions");
+
+    IOdictionary regionBCs
+    (
+        IOobject
+        (
+            fileName(BCDir/"boundaries"),
+            runTime,
+            IOobject::MUST_READ
+        )
+    );
+
+    forAllConstIter(dictionary, regionBCs, iter)
+    {
+        const word& regionType = iter().keyword();
+        wordList patchTypes(regionBCs.lookup(regionType));
+
+        dictionary regionTemplate = dictionary::null;
+        dictionary regionOptions = dictionary::null;
+
+        // read general boundary types
+        forAll(patchTypes, i)
+        {
+            IOdictionary dict
+            (
+                IOobject
+                (
+                    fileName(BCDir/regionType/patchTypes[i]),
+                    runTime,
+                    IOobject::MUST_READ
+                )
+            );
+
+            regionTemplate.add(patchTypes[i], dictionary(dict));
+        }
+
+        // add solver type boundary types
+        forAll(patchTypes, i)
+        {
+            IOobject io
+            (
+                fileName(BCDir/regionType/solverType/patchTypes[i]),
+                runTime,
+                IOobject::MUST_READ
+            );
+
+            if (io.headerOk())
+            {
+                IOdictionary dict(io);
+                regionTemplate.subDict(patchTypes[i]).merge(dict);
+            }
+        }
+
+        // read general boundary options
+        forAll(patchTypes, i)
+        {
+            IOobject io
+            (
+                fileName(BCDir/regionType/patchTypes[i] + "Options"),
+                runTime,
+                IOobject::MUST_READ
+            );
+
+            if (io.headerOk())
+            {
+                IOdictionary dict(io);
+                regionOptions.add(patchTypes[i], dictionary(dict));
+            }
+        }
+
+        // add solver type boundary options
+        forAll(patchTypes, i)
+        {
+            IOobject io
+            (
+                fileName(BCDir/regionType/solverType/patchTypes[i] + "Options"),
+                runTime,
+                IOobject::MUST_READ
+            );
+
+            if (io.headerOk())
+            {
+                IOdictionary dict(io);
+                regionOptions.subDict(patchTypes[i]).merge(dict);
+            }
+        }
+
+        templates_.add(regionType, regionTemplate);
+        options_.add(regionType, regionOptions);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const Foam::dictionary& Foam::boundaryTemplates::templates() const
+{
+    return templates_;
+}
+
+
+Foam::dictionary Foam::boundaryTemplates::generatePatchDict
+(
+    const word& regionPrefix,
+    const word& fieldName,
+    const word& condition,
+    const word& category,
+    const word& patchType,
+    const dictionary& conditionOptions
+) const
+{
+    const dictionary& regionTemplates = templates_.subDict(regionPrefix);
+
+    // look for inlet, outlet, wall etc
+    if (regionTemplates.found(category))
+    {
+        const dictionary& categoryDict(regionTemplates.subDict(category));
+
+        // look for subSonic, slip etc
+        if (categoryDict.found(patchType))
+        {
+            dictionary patchDict = categoryDict.subDict(patchType);
+
+            // add any options
+            if (patchDict.found("OPTIONS"))
+            {
+                const dictionary& regionOptions =
+                    options_.subDict(regionPrefix);
+
+                if (!regionOptions.found(category))
+                {
+                    FatalError<< "No options available for category "
+                        << category << exit(FatalError);
+                }
+
+                const dictionary& dict = regionOptions.subDict(category);
+
+                const wordList requiredOptions(patchDict.lookup("OPTIONS"));
+
+                forAll(requiredOptions, i)
+                {
+                    const word& option = requiredOptions[i];
+
+                    word selected;
+                    if (!conditionOptions.readIfPresent(option, selected))
+                    {
+                        FatalErrorIn
+                        (
+                            "Foam::dictionary "
+                            "Foam::boundaryTemplates::generatePatchDict"
+                            "("
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const dictionary&"
+                            ") const"
+                        )
+                            << "Condition " << condition << ": "
+                            << "No option '" << option
+                            << "' available for category '" << category
+                            << "' and patch type '" << patchType
+                            << "'.  Valid options are: "
+                            << conditionOptions.toc()
+                            << exit(FatalError);
+                    }
+
+                    if (!dict.found(option))
+                    {
+                        FatalErrorIn
+                        (
+                            "Foam::dictionary "
+                            "Foam::boundaryTemplates::generatePatchDict"
+                            "("
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const dictionary&"
+                            ") const"
+                        )
+                            << "Condition " << condition << ": "
+                            << "No option '" << option
+                            << "' available for category '" << category
+                            << "' and patch type '" << patchType
+                            << "'.  Valid options are " << dict.toc()
+                            << exit(FatalError);
+                    }
+
+                    const dictionary& optionDict = dict.subDict(option);
+
+                    if (!optionDict.found(selected))
+                    {
+                        FatalErrorIn
+                        (
+                            "Foam::dictionary "
+                            "Foam::boundaryTemplates::generatePatchDict"
+                            "("
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const word&, "
+                                "const dictionary&"
+                            ") const"
+                        )
+                            << "Condition " << condition << ": "
+                            << "No option '" << selected
+                            << "' available for category '" << category
+                            << "' and patch type '" << patchType
+                            << "'.  Valid options are " << optionDict.toc()
+                            << exit(FatalError);
+                    }
+
+                    const dictionary& dict = optionDict.subDict(selected);
+
+                    patchDict.merge(dict);
+                }
+            }
+
+            // look for field name
+            if (patchDict.found(fieldName))
+            {
+                dictionary dict(dictionary::null);
+                const dictionary& fieldDict(patchDict.subDict(fieldName));
+
+                forAllConstIter(IDLList<entry>, fieldDict, iter)
+                {
+                    OStringStream oss;
+                    oss << iter();
+                    string s(oss.str());
+                    s.replace(iter().keyword(), "");
+                    s.replace
+                    (
+                        "VALUE",
+                        "boundaryConditions." + condition + ".values"
+                    );
+                    dict.add(iter().keyword(), s.c_str());
+                }
+
+                return dict;
+            }
+            else
+            {
+                FatalErrorIn
+                (
+                    "Foam::dictionary "
+                    "Foam::boundaryTemplates::generatePatchDict"
+                    "("
+                        "const word&, "
+                        "const word&, "
+                        "const word&, "
+                        "const word&, "
+                        "const word&, "
+                        "const dictionary&"
+                    ") const"
+                )
+                    << "Condition " << condition << ": "
+                    << "No '" << patchType
+                    << "' condition found for field '" << fieldName
+                    << "' in category type '" << category << "'"
+                    << exit(FatalError);
+            }
+        }
+        else
+        {
+            FatalErrorIn
+            (
+                "Foam::dictionary "
+                "Foam::boundaryTemplates::generatePatchDict"
+                "("
+                    "const word&, "
+                    "const word&, "
+                    "const word&, "
+                    "const word&, "
+                    "const word&, "
+                    "const dictionary&"
+                ") const"
+            )
+                << "Condition " << condition << ": "
+                << "No '" << patchType << "' boundary types defined in "
+                << categoryDict.dictName() << " templates.  "
+                << "Available types are: " << categoryDict.toc()
+                << exit(FatalError);
+        }
+    }
+    else
+    {
+        FatalErrorIn
+        (
+            "Foam::dictionary "
+            "Foam::boundaryTemplates::generatePatchDict"
+            "("
+                "const word&, "
+                "const word&, "
+                "const word&, "
+                "const word&, "
+                "const word&, "
+                "const dictionary&"
+            ") const"
+        )
+            << "Condition " << condition << ": "
+            << "Invalid boundary condition type '" << patchType
+            << "'.  Valid types are:" << regionTemplates.toc()
+            << exit(FatalError);
+    }
+
+    return dictionary::null;
+}
+
+
+void Foam::boundaryTemplates::checkPatch
+(
+    const word& regionPrefix,
+    const word& condition,
+    const word& category,
+    const word& patchType
+) const
+{
+    const dictionary& regionTemplates = templates_.subDict(regionPrefix);
+
+    if (!regionTemplates.found(category))
+    {
+        FatalErrorIn
+        (
+            "void Foam::boundaryTemplates::checkPatch"
+            "("
+                "const word&, "
+                "const word&"
+            ") const"
+        )
+            << "Condition " << condition << ": "
+            << "Unknown category '" << category
+            << "'.  Valid categories are: " << regionTemplates.toc()
+            << exit(FatalError);
+    }
+
+    const dictionary& categoryDict = regionTemplates.subDict(category);
+
+    if (!categoryDict.found(patchType))
+    {
+        FatalErrorIn
+        (
+            "void Foam::boundaryTemplates::checkPatch"
+            "("
+                "const word&, "
+                "const word&"
+            ") const"
+        )
+            << "Condition " << condition << ": "
+            << "Unknown type '" << patchType << "' in category '"
+            << category << "'.  Valid types are: " << categoryDict.toc()
+            << exit(FatalError);
+    }
+}
+
+
+bool Foam::boundaryTemplates::optionsRequired
+(
+    const word& regionPrefix,
+    const word& category,
+    const word& patchType
+) const
+{
+    const dictionary& regionTemplates = templates_.subDict(regionPrefix);
+
+    if (regionTemplates.found(category))
+    {
+        const dictionary& categoryDict(regionTemplates.subDict(category));
+
+        if (categoryDict.found(patchType))
+        {
+            const dictionary& patchDict = categoryDict.subDict(patchType);
+
+            if (patchDict.found("OPTIONS"))
+            {
+                return true;
+            }
+        }
+        else
+        {
+            FatalErrorIn
+            (
+                "bool Foam::boundaryTemplates::optionsRequired"
+                "("
+                    "const word&, "
+                    "const word&"
+                ") const"
+            )
+                << "No type '" << patchType << "' found in category '"
+                << category << "'.  Valid types are "
+                << categoryDict.toc()
+                << exit(FatalError);
+        }
+    }
+    else
+    {
+        FatalErrorIn
+        (
+            "bool Foam::boundaryTemplates::optionsRequired"
+            "("
+                "const word&, "
+                "const word&"
+            ") const"
+        )
+            << "No category '" << category << "' found in templates.  "
+            << "Valid categories are " << templates_.toc()
+            << exit(FatalError);
+    }
+
+    return false;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.H b/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.H
new file mode 100644
index 0000000000000000000000000000000000000000..8ab0e3350375a741508779caa12300e905b6282c
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/boundaryTemplates.H
@@ -0,0 +1,118 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::boundaryTemplates
+
+Description
+    Class to store boundary template specifications
+
+    Templates are typically stored centrally, and constructed in a hierarchical
+    manner.  The main use is to convert the (user) specified conditions into
+    a form which can be inserted into each field file as dictionary entries.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryTemplates_H
+#define boundaryTemplates_H
+
+#include "dictionary.H"
+#include "wordList.H"
+#include "wordReList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class Time;
+
+/*---------------------------------------------------------------------------*\
+                      Class boundaryTemplates Declaration
+\*---------------------------------------------------------------------------*/
+
+class boundaryTemplates
+{
+    // Private data
+
+        //- Dictionary of boundary templates
+        dictionary templates_;
+
+        //- Dictionary of boundary template options
+        dictionary options_;
+
+
+public:
+
+    //- Constructor
+    boundaryTemplates
+    (
+        const fileName& baseDir,
+        const Time& runTime,
+        const word& solverType
+    );
+
+
+    // Public member functions
+
+        //- Return the dictionary of boundary templates
+        const dictionary& templates() const;
+
+        //- Generate a dictionary representation of patch boundary condition
+        dictionary generatePatchDict
+        (
+            const word& regionPrefix,
+            const word& fieldName,
+            const word& condition,
+            const word& category,
+            const word& patchType,
+            const dictionary& conditionOptions
+        ) const;
+
+        //- Check that user supplied patch info is valid
+        void checkPatch
+        (
+            const word& regionPrefix,
+            const word& condition,
+            const word& category,
+            const word& patchType
+        ) const;
+
+        //- Return true if condition requires additional user options
+        bool optionsRequired
+        (
+            const word& regionPrefix,
+            const word& category,
+            const word& patchType
+        ) const;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/caseInfo.C b/applications/utilities/preProcessing/createZeroDirectory/caseInfo.C
new file mode 100644
index 0000000000000000000000000000000000000000..579c2889f06dece280085043f91e66de65237ba5
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/caseInfo.C
@@ -0,0 +1,261 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "caseInfo.H"
+#include "Time.H"
+#include "boundaryInfo.H"
+#include "boundaryTemplates.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::caseInfo::findPatchConditionID
+(
+    const label patchI,
+    const word& patchName
+) const
+{
+    // 1. explicit patch names
+    forAll(patchNames_, i)
+    {
+        const wordReList& p = patchNames_[i];
+        forAll(p, j)
+        {
+            if (!p[j].isPattern() && p[j] == patchName)
+            {
+                return i;
+            }
+        }
+    }
+
+    // 2. patch groups using non-wildcard entries
+    const wordList& patchGroups = boundaryInfo_.groups()[patchI];
+    forAll(patchNames_, i)
+    {
+        const wordReList& p = patchNames_[i];
+        forAll(p, j)
+        {
+            if (!p[j].isPattern())
+            {
+                forAll(patchGroups, groupI)
+                {
+                    if (p[j] == patchGroups[groupI])
+                    {
+                        return i;
+                    }
+                }
+            }
+        }
+    }
+
+    // 3. wildcard overrides
+    forAll(patchNames_, i)
+    {
+        const wordReList& p = patchNames_[i];
+        forAll(p, j)
+        {
+            if (p[j].match(patchName))
+            {
+                return i;
+            }
+        }
+    }
+
+    FatalErrorIn
+    (
+        "Foam::label Foam::caseInfo::findPatchConditionID"
+        "("
+            "const label, "
+            "const word&"
+        ") const"
+    )
+        << "Boundary patch " << patchName << " not defined"
+        << exit(FatalError);
+
+    return -1;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::caseInfo::caseInfo(const Time& runTime, const word& regionName)
+:
+    properties_
+    (
+        IOobject
+        (
+            "caseProperties",
+            runTime.system(),
+            regionName,
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        )
+    ),
+    boundaryInfo_(runTime, regionName),
+    bcDict_(properties_.subDict("boundaryConditions")),
+    conditionNames_(bcDict_.toc()),
+    patchNames_(conditionNames_.size()),
+    patchCategories_(conditionNames_.size()),
+    patchTypes_(conditionNames_.size())
+{
+    // read the (user-supplied) boundary condition information
+    Info<< "    Reading case properties" << endl;
+
+    forAll(conditionNames_, i)
+    {
+        const dictionary& dict = bcDict_.subDict(conditionNames_[i]);
+        dict.lookup("category") >> patchCategories_[i];
+        dict.lookup("type") >> patchTypes_[i];
+        dict.lookup("patches") >> patchNames_[i];
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::caseInfo::checkPatches
+(
+    const word& regionPrefix,
+    const boundaryTemplates& bcTemplates
+) const
+{
+    // check that all conditions have been specified correctly wrt templates
+    forAll(conditionNames_, i)
+    {
+        bcTemplates.checkPatch
+        (
+            regionPrefix,
+            conditionNames_[i],
+            patchCategories_[i],
+            patchTypes_[i]
+        );
+    }
+}
+
+
+const Foam::List<Foam::wordReList>& Foam::caseInfo::patchNames() const
+{
+    return patchNames_;
+}
+
+
+const Foam::word& Foam::caseInfo::conditionName(const label patchI) const
+{
+    return conditionNames_[patchI];
+}
+
+
+const Foam::word& Foam::caseInfo::patchCategory(const label patchI) const
+{
+    return patchCategories_[patchI];
+}
+
+
+const Foam::word& Foam::caseInfo::patchType(const label patchI) const
+{
+    return patchTypes_[patchI];
+}
+
+
+Foam::dictionary Foam::caseInfo::generateBoundaryField
+(
+    const word& regionPrefix,
+    const word& fieldName,
+    const boundaryTemplates& bcTemplates
+) const
+{
+    dictionary boundaryField = dictionary::null;
+
+    forAll(boundaryInfo_.names(), j)
+    {
+        const word& patchName = boundaryInfo_.names()[j];
+
+        if (boundaryInfo_.constraint()[j])
+        {
+            dictionary patchDict = dictionary::null;
+            patchDict.add("type", boundaryInfo_.types()[j]);
+
+            // add value for processor patches
+            patchDict.add("value", "${:internalField}");
+            boundaryField.add(patchName.c_str(), patchDict);
+        }
+        else
+        {
+            // condition ID to apply to mesh boundary boundaryPatchName
+            const label conditionI = findPatchConditionID(j, patchName);
+
+            if (conditionI == -1)
+            {
+                FatalErrorIn
+                (
+                    "Foam::dictionary Foam::caseInfo::generateBoundaryField"
+                    "("
+                        "const word&, "
+                        "const word&, "
+                        "const boundaryTemplates&"
+                    ") const"
+                )
+                    << "Unable to find patch " << patchName
+                    << " in list of boundary conditions"
+                    << exit(FatalError);
+            }
+
+            const word& condition = conditionNames_[conditionI];
+
+            const word& category = patchCategories_[conditionI];
+
+            const word& patchType = patchTypes_[conditionI];
+
+            dictionary optionDict = dictionary::null;
+            if (bcTemplates.optionsRequired(regionPrefix, category, patchType))
+            {
+                optionDict = bcDict_.subDict(condition).subDict("options");
+            }
+
+            // create the patch dictionary entry
+            dictionary patchDict
+            (
+                bcTemplates.generatePatchDict
+                (
+                    regionPrefix,
+                    fieldName,
+                    condition,
+                    category,
+                    patchType,
+                    optionDict
+                )
+            );
+
+            boundaryField.add(patchName.c_str(), patchDict);
+        }
+    }
+
+    return boundaryField;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/caseInfo.H b/applications/utilities/preProcessing/createZeroDirectory/caseInfo.H
new file mode 100644
index 0000000000000000000000000000000000000000..bf335530eaeada7269c6246abaea30778ad4b394
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/caseInfo.H
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::caseInfo
+
+Description
+    Class to hold information related to the simaulation case.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef caseInfo_H
+#define caseInfo_H
+
+#include "boolList.H"
+#include "labelList.H"
+#include "wordList.H"
+#include "HashSet.H"
+#include "wordReList.H"
+#include "IOdictionary.H"
+#include "boundaryInfo.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class Time;
+class boundaryTemplates;
+
+/*---------------------------------------------------------------------------*\
+                          Class caseInfo Declaration
+\*---------------------------------------------------------------------------*/
+
+class caseInfo
+{
+    // Private data
+
+        //- Properties dictionary
+        IOdictionary properties_;
+
+        //- Mesh boundary information (read from mesh boundary file)
+        boundaryInfo boundaryInfo_;
+
+        //- Boundary conditions dictionary
+        const dictionary& bcDict_;
+
+        //- List of condition names
+        wordList conditionNames_;
+
+
+        // Per-condition information
+
+            //- List of patch names
+            List<wordReList> patchNames_;
+
+            //- Patch category
+            wordList patchCategories_;
+
+            //- Patch type
+            wordList patchTypes_;
+
+
+public:
+
+    //- Constructor
+    caseInfo(const Time& runTime, const word& regionName);
+
+
+    // Public member functions
+
+        //- Check patches
+        void checkPatches
+        (
+            const word& regionPrefix,
+            const boundaryTemplates& bcTemplates
+        ) const;
+
+        //- Return the list of patch names
+        const List<wordReList>& patchNames() const;
+
+        //- Return the condition name for patch with index patchI
+        const word& conditionName(const label patchI) const;
+
+        //- Return the category name for patch with index patchI
+        const word& patchCategory(const label patchI) const;
+
+        //- Return the type name for patch with index patchI
+        const word& patchType(const label patchI) const;
+
+        //- Return the condition ID for a boundary patch
+        label findPatchConditionID
+        (
+            const label patchI,
+            const word& patchName
+        ) const;
+
+        //- Generate boundary field (dictionary)
+        dictionary generateBoundaryField
+        (
+            const word& regionPrefix,
+            const word& fieldName,
+            const boundaryTemplates& bcTemplates
+        ) const;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C b/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C
new file mode 100644
index 0000000000000000000000000000000000000000..8b63c6957330e7affbebe814b0d79e6eb96135ca
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C
@@ -0,0 +1,274 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Application
+    createZeroDirectory
+
+Description
+    Creates a zero directory with fields appropriate for the chosen solver and
+    turbulence model. Operates on both single and multi-region cases.
+
+Usage
+    The set-up is configured using a 'caseProperties' dictionary, located under
+    the $FOAM_CASE/system (or system/regionName if multi-region) directory.
+    This consists of a lists of initial and boundary conditions, e.g.
+
+    \beginverbatim
+    initialConditions
+    {
+        U           uniform (0 0 0);
+        p           uniform 0;
+    }
+
+    boundaryConditions
+    {
+        topWall
+        {
+            category        wall;
+            patches         (movingWall);
+            type            noSlip;
+            options
+            {
+                wallFunction    highReynolds;
+                motion          moving;
+            };
+            values
+            {
+                U           uniform (1 0 0);
+            }
+        }
+
+        walls
+        {
+            category        wall;
+            patches         (fixedWalls);
+            type            noSlip;
+            options
+            {
+                wallFunction    highReynolds;
+                motion          stationary;
+            };
+        }
+    }
+    \endverbatim
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "volFields.H"
+#include "IOdictionary.H"
+#include "boundaryInfo.H"
+#include "caseInfo.H"
+#include "boundaryTemplates.H"
+#include "solverTemplate.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+const word getClassType(const word& pType)
+{
+    if (pType == pTraits<scalar>::typeName)
+    {
+        return GeometricField<scalar, fvPatchField, volMesh>::typeName;
+    }
+    else if (pType == pTraits<vector>::typeName)
+    {
+        return GeometricField<vector, fvPatchField, volMesh>::typeName;
+    }
+    else if (pType == pTraits<sphericalTensor>::typeName)
+    {
+        return GeometricField<sphericalTensor, fvPatchField, volMesh>::typeName;
+    }
+    else if (pType == pTraits<symmTensor>::typeName)
+    {
+        return GeometricField<symmTensor, fvPatchField, volMesh>::typeName;
+    }
+    else if (pType == pTraits<tensor>::typeName)
+    {
+        return GeometricField<tensor, fvPatchField, volMesh>::typeName;
+    }
+    else
+    {
+        // error
+        return word::null;
+    }
+}
+
+
+void createFieldFiles
+(
+    const Time& runTime,
+    const word& regionName,
+    const word& regionPrefix,
+    const wordList& fieldNames,
+    const wordList& fieldTypes,
+    const PtrList<dimensionSet>& fieldDimensions,
+    const caseInfo& cInfo,
+    const boundaryTemplates& bcTemplates
+)
+{
+    Info<< "    Generating field files" << nl << endl;
+
+    // create files
+    mkDir(runTime.path()/"0"/regionName);
+    forAll(fieldNames, i)
+    {
+        const_cast<word&>(IOdictionary::typeName) =
+            getClassType(fieldTypes[i]);
+
+        IOdictionary field
+        (
+            IOobject
+            (
+                fieldNames[i],
+                "0",
+                regionName,
+                runTime,
+                IOobject::NO_READ
+            )
+        );
+
+        word regionPath = "/";
+
+        if (regionName != word::null)
+        {
+            regionPath += regionName + '/';
+        }
+
+        field.add
+        (
+            "#include",
+            string
+            (
+                "${FOAM_CASE}/system" + regionPath + "caseProperties"
+            )
+        );
+
+        field.add("dimensions", fieldDimensions[i]);
+
+        string iField("${:initialConditions." + fieldNames[i] + '}');
+        field.add("internalField", iField.c_str());
+
+        dictionary boundaryField =
+            cInfo.generateBoundaryField
+            (
+                regionPrefix,
+                fieldNames[i],
+                bcTemplates
+            );
+
+        field.add("boundaryField", boundaryField);
+
+        field.regIOobject::writeObject
+        (
+            IOstream::ASCII,
+            IOstream::currentVersion,
+            IOstream::UNCOMPRESSED
+        );
+    }
+}
+
+
+// Main program:
+int main(int argc, char *argv[])
+{
+    // keep variable substitutions
+    entry::disableFunctionEntries = 1;
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+
+    Info<< "Reading controlDict" << nl << endl;
+
+    IOdictionary controlDict
+    (
+        IOobject
+        (
+            "controlDict",
+            runTime.system(),
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        )
+    );
+
+    fileName baseDir("${WM_PROJECT_USER_DIR}/etc/templates");
+    baseDir.expand();
+
+    // read the solver
+    const word& solverName = controlDict.lookup("application");
+
+    // generate solver template
+    const solverTemplate solver(runTime, solverName);
+
+    // read the boundary condition templates
+    const boundaryTemplates bcTemplates
+    (
+        baseDir,
+        runTime,
+        solver.type()
+    );
+
+    Info<< endl;
+
+    const label nRegion = solver.nRegion();
+    for (label regionI = 0; regionI < nRegion; regionI++)
+    {
+        const word& regionName = solver.regionName(regionI);
+
+        if (regionName == word::null)
+        {
+            Info<< "Region: " << polyMesh::defaultRegion << " (default)"
+                << endl;
+        }
+        else
+        {
+            Info<< "Region: " << regionName << endl;
+        }
+
+        // read the case set-up info for the current region
+        const caseInfo cInfo(runTime, regionName);
+
+        cInfo.checkPatches(solver.regionType(regionI), bcTemplates);
+
+        createFieldFiles
+        (
+            runTime,
+            regionName,
+            solver.regionType(regionI),
+            solver.fieldNames(regionI),
+            solver.fieldTypes(regionI),
+            solver.fieldDimensions(regionI),
+            cInfo,
+            bcTemplates
+        );
+    }
+
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.C b/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.C
new file mode 100644
index 0000000000000000000000000000000000000000..f5a4e8328aaac175aa7d47211deb7a0cfc32662d
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.C
@@ -0,0 +1,450 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "solverTemplate.H"
+#include "Time.H"
+#include "IOPtrList.H"
+#include "polyMesh.H"
+#include "regionProperties.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    template<>
+    const char* Foam::NamedEnum<Foam::solverTemplate::solverType, 4>::names[] =
+    {
+        "compressible",
+        "incompressible",
+        "buoyant",
+        "unknown"
+    };
+}
+
+const Foam::NamedEnum<Foam::solverTemplate::solverType, 4>
+    Foam::solverTemplate::solverTypeNames_;
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::word Foam::solverTemplate::readFromDict
+(
+    IOobject& dictHeader,
+    const word& entryName
+) const
+{
+    if (!dictHeader.headerOk())
+    {
+        FatalErrorIn
+        (
+            "Foam::word Foam::solverTemplate::readFromDict"
+            "("
+                "IOobject&, "
+                "const word&"
+            ") const"
+        )
+            << "Unable to open file "
+            << dictHeader.objectPath()
+            << exit(FatalError);
+    }
+
+    IOdictionary dict(dictHeader);
+    return dict.lookup(entryName);
+}
+
+
+Foam::dictionary Foam::solverTemplate::readFluidFieldTemplates
+(
+    const word& regionName,
+    const fileName& baseDir,
+    const dictionary& solverDict,
+    const Time& runTime
+) const
+{
+    Info<< "    Reading fluid field templates";
+
+    if (regionName == word::null)
+    {
+        Info<< endl;
+    }
+    else
+    {
+        Info<< " for region " << regionName << endl;
+    }
+
+    dictionary fieldTemplates = solverDict.subDict("fluidFields");
+
+    const fileName turbModelDir(baseDir/"models"/"turbulence");
+    word turbulenceModel("laminar"); // default to laminar
+
+    const dictionary fieldModels(solverDict.subDict("fluidModels"));
+
+    word turbulenceType = "none";
+    if (fieldModels.readIfPresent("turbulenceModel", turbulenceType))
+    {
+        word simulationType(word::null);
+
+        IOobject RASHeader
+        (
+            "RASProperties",
+            runTime.constant(),
+            regionName,
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        );
+
+        IOobject LESHeader
+        (
+            "LESProperties",
+            runTime.constant(),
+            regionName,
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        );
+
+
+        if (turbulenceType == "turbulenceModel")
+        {
+            IOobject turbulencePropertiesHeader
+            (
+                "turbulenceProperties",
+                runTime.constant(),
+                regionName,
+                runTime,
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            );
+
+            if (turbulencePropertiesHeader.headerOk())
+            {
+                const IOdictionary turbulenceProperties
+                (
+                    turbulencePropertiesHeader
+                );
+
+                turbulenceProperties.lookup("simulationType") >> simulationType;
+
+                if (simulationType == "RASModel")
+                {
+                    turbulenceModel = readFromDict(RASHeader, "RASModel");
+                }
+                else if (simulationType == "LESModel")
+                {
+                    turbulenceModel = readFromDict(LESHeader, "LESModel");
+                }
+            }
+            else
+            {
+                FatalError<< "Unable to open file "
+                    << turbulencePropertiesHeader.objectPath()
+                    << exit(FatalError);
+            }
+        }
+        else if (turbulenceType == "RASModel")
+        {
+            turbulenceModel = readFromDict(RASHeader, "RASModel");
+        }
+        else if (turbulenceType == "LESModel")
+        {
+            turbulenceModel = readFromDict(LESHeader, "LESModel");
+        }
+        else
+        {
+            FatalErrorIn
+            (
+                "Foam::dictionary Foam::solverTemplate::readFluidFieldTemplates"
+                "("
+                    "const word&, "
+                    "const fileName&, "
+                    "const dictionary&, "
+                    "const Time&"
+                ") const"
+            )
+                << "Unhandled turbulence model option"
+                << abort(FatalError);
+        }
+    }
+
+    IOdictionary turbModelDict
+    (
+        IOobject
+        (
+            fileName(turbModelDir/turbulenceModel),
+            runTime,
+            IOobject::MUST_READ
+        )
+    );
+
+    switch (solverType_)
+    {
+        case stIncompressible:
+        {
+            fieldTemplates.merge(turbModelDict.subDict("incompressibleFields"));
+            break;
+        }
+        case stCompressible:
+        case stBuoyant:
+        {
+            fieldTemplates.merge(turbModelDict.subDict("compressibleFields"));
+            break;
+        }
+        default:
+        {
+            // do nothing
+        }
+    }
+
+    return fieldTemplates;
+}
+
+
+Foam::dictionary Foam::solverTemplate::readSolidFieldTemplates
+(
+    const word& regionName,
+    const dictionary& solverDict
+) const
+{
+    Info<< "    Reading solid field templates for region " << regionName
+        << endl;
+
+    // nothing more to do for solids
+    return solverDict.subDict("solidFields");
+}
+
+
+void Foam::solverTemplate::setRegionProperties
+(
+    const dictionary& fieldDict,
+    const word& regionType,
+    const word& regionName,
+    const label regionI
+)
+{
+    regionTypes_[regionI] = regionType,
+    regionNames_[regionI] = regionName,
+    fieldNames_[regionI] = fieldDict.toc();
+    fieldTypes_[regionI].setSize(fieldNames_[regionI].size());
+    fieldDimensions_[regionI].setSize(fieldNames_[regionI].size());
+
+    forAll(fieldNames_[regionI], i)
+    {
+        const word& fieldName = fieldNames_[regionI][i];
+        const dictionary& dict = fieldDict.subDict(fieldName);
+
+        dict.lookup("type") >> fieldTypes_[regionI][i];
+        fieldDimensions_[regionI].set
+        (
+            i,
+            new dimensionSet(dict.lookup("dimensions"))
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::solverTemplate::solverTemplate
+(
+    const Time& runTime,
+    const word& solverName
+)
+:
+    solverType_(stUnknown),
+    multiRegion_(false),
+    regionTypes_(),
+    fieldNames_(),
+    fieldTypes_(),
+    fieldDimensions_()
+{
+    fileName baseDir("${WM_PROJECT_USER_DIR}/etc/templates");
+    baseDir.expand();
+
+    IOdictionary solverDict
+    (
+        IOobject
+        (
+            fileName(baseDir/"solvers"/solverName),
+            runTime,
+            IOobject::MUST_READ
+        )
+    );
+
+    Info<< "Selecting " << solverName << ": ";
+
+    solverType_ = solverTypeNames_.read(solverDict.lookup("solverType"));
+    Info<< solverTypeNames_[solverType_];
+
+    multiRegion_ = readBool(solverDict.lookup("multiRegion"));
+    if (multiRegion_)
+    {
+        Info<< ", multi-region";
+    }
+    else
+    {
+        Info<< ", single-region";
+    }
+
+    Info<< " case" << endl;
+
+    if (multiRegion_)
+    {
+        // read regionProperties
+        regionProperties rp(runTime);
+
+        const wordList fluidNames(rp["fluid"]);
+        const wordList solidNames(rp["solid"]);
+
+        const label nRegion = fluidNames.size() + solidNames.size();
+
+        regionTypes_.setSize(nRegion);
+        regionNames_.setSize(nRegion);
+        fieldNames_.setSize(nRegion);
+        fieldTypes_.setSize(nRegion);
+        fieldDimensions_.setSize(nRegion);
+
+        // read templates for solver lists of avaliable
+        // - fields and dimensions required for the solver
+        // - models
+        label regionI = 0;
+        forAll(fluidNames, i)
+        {
+            const dictionary fieldDict
+            (
+                readFluidFieldTemplates
+                (
+                    fluidNames[i],
+                    baseDir,
+                    solverDict,
+                    runTime
+                )
+            );
+
+            setRegionProperties(fieldDict, "fluid", fluidNames[i], regionI++);
+        }
+
+        forAll(solidNames, i)
+        {
+            const dictionary fieldDict
+            (
+                readSolidFieldTemplates
+                (
+                    solidNames[i],
+                    solverDict
+                )
+            );
+            setRegionProperties(fieldDict, "solid", solidNames[i], regionI++);
+        }
+    }
+    else
+    {
+        regionTypes_.setSize(1);
+        regionNames_.setSize(1);
+        fieldNames_.setSize(1);
+        fieldTypes_.setSize(1);
+        fieldDimensions_.setSize(1);
+
+        // read templates for solver lists of avaliable
+        // - fields and dimensions required for the solver
+        // - models
+        const dictionary fieldDict
+        (
+            readFluidFieldTemplates
+            (
+                word::null, // use region = null for single-region cases
+                baseDir,
+                solverDict,
+                runTime
+            )
+        );
+
+        setRegionProperties(fieldDict, "fluid", word::null, 0);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::word Foam::solverTemplate::type() const
+{
+    return solverTypeNames_[solverType_];
+}
+
+
+bool Foam::solverTemplate::multiRegion() const
+{
+    return multiRegion_;
+}
+
+
+label Foam::solverTemplate::nRegion() const
+{
+    return regionTypes_.size();
+}
+
+
+const Foam::word& Foam::solverTemplate::regionType(const label regionI) const
+{
+    return regionTypes_[regionI];
+}
+
+
+const Foam::word& Foam::solverTemplate::regionName(const label regionI) const
+{
+    return regionNames_[regionI];
+}
+
+
+const Foam::wordList& Foam::solverTemplate::fieldNames
+(
+    const label regionI
+) const
+{
+    return fieldNames_[regionI];
+}
+
+
+const Foam::wordList& Foam::solverTemplate::fieldTypes
+(
+    const label regionI
+) const
+{
+    return fieldTypes_[regionI];
+}
+
+
+const Foam::PtrList<Foam::dimensionSet>& Foam::solverTemplate::fieldDimensions
+(
+    const label regionI
+) const
+{
+    return fieldDimensions_[regionI];
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.H b/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.H
new file mode 100644
index 0000000000000000000000000000000000000000..d78ac533a174e1972c054bc7889da5a005f3f91f
--- /dev/null
+++ b/applications/utilities/preProcessing/createZeroDirectory/solverTemplate.H
@@ -0,0 +1,182 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2014 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::solverTemplate
+
+Description
+    Class to store solver template specifications
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef solverTemplate_H
+#define solverTemplate_H
+
+#include "boolList.H"
+#include "wordList.H"
+#include "dimensionSet.H"
+#include "IOobject.H"
+#include "NamedEnum.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class Time;
+
+/*---------------------------------------------------------------------------*\
+                       Class solverTemplate Declaration
+\*---------------------------------------------------------------------------*/
+
+class solverTemplate
+{
+public:
+
+    // Public enumerations
+
+        //- Solver type
+        enum solverType
+        {
+            stCompressible,
+            stIncompressible,
+            stBuoyant,
+            stUnknown
+        };
+
+        //- Solver type names
+        static const NamedEnum<solverType, 4> solverTypeNames_;
+
+
+private:
+
+    // Private data
+
+        //- Solver type
+        solverType solverType_;
+
+        //- Multi-region flag
+        bool multiRegion_;
+
+
+        // Per-region info
+
+            //- Region types
+            wordList regionTypes_;
+
+            //- Region names
+            wordList regionNames_;
+
+            //- Field names
+            List<wordList> fieldNames_;
+
+            //- Field types
+            List<wordList> fieldTypes_;
+
+            //- Field dimensions
+            List<PtrList<dimensionSet> > fieldDimensions_;
+
+
+    // Public member functions
+
+        //- Read a word from a dictionary (offers some protection...)
+        word readFromDict
+        (
+            IOobject& dictHeader,
+            const word& entryName
+        ) const;
+
+        //- Read fluid region templates
+        dictionary readFluidFieldTemplates
+        (
+            const word& regionName,
+            const fileName& baseDir,
+            const dictionary& solverDict,
+            const Time& runTime
+        ) const;
+
+        //- Read solid region templates
+        dictionary readSolidFieldTemplates
+        (
+            const word& regionName,
+            const dictionary& solverDict
+        ) const;
+
+        //- Set the properties for region with index regionI
+        void setRegionProperties
+        (
+            const dictionary& dict,
+            const word& regionType,
+            const word& regionName,
+            const label regionI
+        );
+
+
+public:
+
+    //- Constructor
+    solverTemplate(const Time& runTime, const word& regionName);
+
+
+    // Public member functions
+
+        //- Solver type name
+        word type() const;
+
+        //- Return the multi-region flag
+        bool multiRegion() const;
+
+        //- Return the number of regions
+        label nRegion() const;
+
+
+        // Per-region info
+
+            //- Return the region type
+            const word& regionType(const label regionI) const;
+
+            //- Return the region name
+            const word& regionName(const label regionI) const;
+
+            //- Return the field names
+            const wordList& fieldNames(const label regionI) const;
+
+            //- Return the field types
+            const wordList& fieldTypes(const label regionI) const;
+
+            //- Return the field dimensions
+            const PtrList<dimensionSet>& fieldDimensions
+            (
+                const label regionI
+            ) const;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //