diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C
index c2baec519e8cbd589e3fa986be039f9c923ae829..bf44c1cd77d86b75322959ff61a62074321ba43c 100644
--- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C
+++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C
@@ -74,30 +74,6 @@ scalarField calcCurvature(const triSurface& surf)
 
     // The rest of this function adapted from
     //     CGAL-3.7/examples/Jet_fitting_3/Mesh_estimation.cpp
-    // Licensed under CGAL-3.7/LICENSE.FREE_USE
-
-    // Copyright (c) 1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007
-    // Utrecht University (The Netherlands), ETH Zurich (Switzerland), Freie
-    // Universitaet Berlin (Germany), INRIA Sophia-Antipolis (France),
-    // Martin-Luther-University Halle-Wittenberg (Germany), Max-Planck-Institute
-    // Saarbruecken (Germany), RISC Linz (Austria), and Tel-Aviv University
-    // (Israel).  All rights reserved.
-
-    // Permission is hereby granted, free of charge, to any person obtaining a
-    // copy of this software and associated documentation files (the
-    // "Software"), to deal in the Software without restriction, including
-    // without limitation the rights to use, copy, modify, merge, publish,
-    // distribute, sublicense, and/or sell copies of the Software, and to permit
-    // persons to whom the Software is furnished to do so, subject to the
-    // following conditions:
-
-    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-    // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-    // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
-    // OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
-    // THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
      //Vertex property map, with std::map
     typedef std::map<Vertex*, int> Vertex2int_map_type;
@@ -503,358 +479,344 @@ int main(int argc, char *argv[])
         "extract and write surface features to file"
     );
     argList::noParallel();
-    argList::validArgs.append("surface");
-    argList::validArgs.append("output set");
 
     argList::addOption
     (
-        "includedAngle",
-        "degrees",
-        "construct feature set from included angle [0..180]"
+        "dict",
+        "word",
+        "name of dictionary to provide feature extraction information"
     );
-    argList::addOption
-    (
-        "set",
-        "name",
-        "use existing feature set from file"
-    );
-    argList::addOption
-    (
-        "minLen",
-        "scalar",
-        "remove features shorter than the specified cumulative length"
-    );
-    argList::addOption
-    (
-        "minElem",
-        "int",
-        "remove features with fewer than the specified number of edges"
-    );
-    argList::addOption
-    (
-        "subsetBox",
-        "((x0 y0 z0)(x1 y1 z1))",
-        "remove edges outside specified bounding box"
-    );
-    argList::addOption
-    (
-        "deleteBox",
-        "((x0 y0 z0)(x1 y1 z1))",
-        "remove edges within specified bounding box"
-    );
-    argList::addBoolOption
-    (
-        "writeObj",
-        "write extendedFeatureEdgeMesh obj files"
-    );
-    argList::addBoolOption
-    (
-        "writeVTK",
-        "write extendedFeatureEdgeMesh vtk files"
-    );
-    argList::addBoolOption
-    (
-        "closeness",
-        "span to look for surface closeness"
-    );
-    argList::addOption
-    (
-        "featureProximity",
-        "scalar",
-        "distance to look for close features"
-    );
-    argList::addBoolOption
-    (
-        "writeVTK",
-        "write surface property VTK files"
-    );
-    argList::addBoolOption
-    (
-        "manifoldEdgesOnly",
-        "remove any non-manifold (open or more than two connected faces) edges"
-    );
-    argList::addOption
+
+#   include "setRootCase.H"
+#   include "createTime.H"
+
+    word dictName
     (
-        "plane",
-        "(nx ny nz)(z0 y0 z0)",
-        "use a plane to create feature edges for 2D meshing"
+        args.optionLookupOrDefault<word>("dict", "surfaceFeatureExtractDict")
     );
 
-#   ifdef ENABLE_CURVATURE
-    argList::addBoolOption
+    Info<< "Reading " << dictName << nl << endl;
+
+    IOdictionary dict
     (
-        "curvature",
-        "calculate curvature and closeness fields"
+        IOobject
+        (
+            dictName,
+            runTime.system(),
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE,
+            false
+        )
     );
-#   endif
 
+    forAllConstIter(dictionary, dict, iter)
+    {
+        dictionary surfaceDict = dict.subDict(iter().keyword());
 
-#   include "setRootCase.H"
-#   include "createTime.H"
+        const fileName surfFileName = iter().keyword();
+        const fileName sFeatFileName = surfFileName.lessExt().name();
 
-    bool writeVTK = args.optionFound("writeVTK");
+        Info<< "Surface            : " << surfFileName << nl << endl;
 
-    bool writeObj = args.optionFound("writeObj");
+        const Switch writeVTK =
+            surfaceDict.lookupOrAddDefault<Switch>("writeVTK", "off");
+        const Switch writeObj =
+            surfaceDict.lookupOrAddDefault<Switch>("writeObj", "off");
+        const Switch writeFeatureEdgeMesh =
+            surfaceDict.lookupOrAddDefault<Switch>
+            (
+                "writeFeatureEdgeMesh",
+                "off"
+            );
 
-    bool curvature = args.optionFound("curvature");
+        const Switch curvature =
+            surfaceDict.lookupOrAddDefault<Switch>("curvature", "off");
+        const Switch featureProximity =
+            surfaceDict.lookupOrAddDefault<Switch>("featureProximity", "off");
+        const Switch closeness =
+            surfaceDict.lookupOrAddDefault<Switch>("closeness", "off");
 
-    if (curvature && env("FOAM_SIGFPE"))
-    {
-        WarningIn(args.executable())
-            << "Detected floating point exception trapping (FOAM_SIGFPE)."
-            << " This might give" << nl
-            << "    problems when calculating curvature on straight angles"
-            << " (infinite curvature)" << nl
-            << "    Switch it off in case of problems." << endl;
-    }
+        const word extractionMethod = surfaceDict.lookup("extractionMethod");
 
 
-    Info<< "Feature line extraction is only valid on closed manifold surfaces."
-        << endl;
+#ifndef ENABLE_CURVATURE
+        if (curvature)
+        {
+            WarningIn(args.executable())
+                << "Curvature calculation has been requested but "
+                << args.executable() << " has not " << nl
+                << "    been compiled with CGAL. "
+                << "Skipping the curvature calculation." << endl;
+        }
+#else
+        if (curvature && env("FOAM_SIGFPE"))
+        {
+            WarningIn(args.executable())
+                << "Detected floating point exception trapping (FOAM_SIGFPE)."
+                << " This might give" << nl
+                << "    problems when calculating curvature on straight angles"
+                << " (infinite curvature)" << nl
+                << "    Switch it off in case of problems." << endl;
+        }
+#endif
 
-    const fileName surfFileName = args[1];
-    const fileName outFileName  = args[2];
 
-    Info<< "Surface            : " << surfFileName << nl
-        << "Output feature set : " << outFileName << nl
-        << endl;
+        Info<< nl << "Feature line extraction is only valid on closed manifold "
+            << "surfaces." << endl;
 
-    fileName sFeatFileName = surfFileName.lessExt().name();
+        // Read
+        // ~~~~
 
+        triSurface surf("constant/triSurface/" + surfFileName);
 
-    // Read
-    // ~~~~
+        Info<< "Statistics:" << endl;
+        surf.writeStats(Info);
+        Info<< endl;
 
-    triSurface surf(surfFileName);
+        faceList faces(surf.size());
 
-    Info<< "Statistics:" << endl;
-    surf.writeStats(Info);
-    Info<< endl;
+        forAll(surf, fI)
+        {
+            faces[fI] = surf[fI].triFaceFace();
+        }
 
-    faceList faces(surf.size());
 
-    forAll(surf, fI)
-    {
-        faces[fI] = surf[fI].triFaceFace();
-    }
+        // Either construct features from surface & featureAngle or read set.
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    // Either construct features from surface&featureangle or read set.
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        surfaceFeatures set(surf);
 
-    surfaceFeatures set(surf);
+        if (extractionMethod == "extractFromFile")
+        {
+            const fileName featureEdgeFile =
+                surfaceDict.subDict("extractFromFile").lookup
+                (
+                    "featureEdgeFile"
+                );
 
-    if (args.optionFound("set"))
-    {
-        const fileName setName = args["set"];
+            edgeMesh eMesh(featureEdgeFile);
 
-        Info<< "Reading existing feature set from file " << setName << endl;
+            // Sometimes duplicate edges are present. Remove them.
+            eMesh.mergeEdges();
 
-        set = surfaceFeatures(surf, setName);
-    }
-    else if (args.optionFound("includedAngle"))
-    {
-        const scalar includedAngle = args.optionRead<scalar>("includedAngle");
+            Info<< nl << "Reading existing feature edges from file "
+                << featureEdgeFile << endl;
+
+            set = surfaceFeatures(surf, eMesh.points(), eMesh.edges());
+        }
+        else if (extractionMethod == "extractFromSurface")
+        {
+            const scalar includedAngle =
+                readScalar
+                (
+                    surfaceDict.subDict("extractFromSurface").lookup
+                    (
+                        "includedAngle"
+                    )
+                );
 
-        Info<< "Constructing feature set from included angle " << includedAngle
+            Info<< nl << "Constructing feature set from included angle "
+                << includedAngle << endl;
+
+            set = surfaceFeatures(surf, includedAngle);
+        }
+        else
+        {
+            FatalErrorIn(args.executable())
+                << "No initial feature set. Provide either one"
+                << " of extractFromFile (to read existing set)" << nl
+                << " or extractFromSurface (to construct new set from angle)"
+                << exit(FatalError);
+        }
+
+        Info<< nl
+            << "Initial feature set:" << nl
+            << "    feature points : " << set.featurePoints().size() << nl
+            << "    feature edges  : " << set.featureEdges().size() << nl
+            << "    of which" << nl
+            << "        region edges   : " << set.nRegionEdges() << nl
+            << "        external edges : " << set.nExternalEdges() << nl
+            << "        internal edges : " << set.nInternalEdges() << nl
             << endl;
 
-        set = surfaceFeatures(surf, includedAngle);
 
-        // Info<< nl << "Writing initial features" << endl;
-        // set.write("initial.fSet");
-        // set.writeObj("initial");
-    }
-    else
-    {
-        FatalErrorIn(args.executable())
-            << "No initial feature set. Provide either one"
-            << " of -set (to read existing set)" << nl
-            << " or -includedAngle (to new set construct from angle)"
-            << exit(FatalError);
-    }
+        // Trim set
+        // ~~~~~~~~
 
-    Info<< nl
-        << "Initial feature set:" << nl
-        << "    feature points : " << set.featurePoints().size() << nl
-        << "    feature edges  : " << set.featureEdges().size() << nl
-        << "    of which" << nl
-        << "        region edges   : " << set.nRegionEdges() << nl
-        << "        external edges : " << set.nExternalEdges() << nl
-        << "        internal edges : " << set.nInternalEdges() << nl
-        << endl;
+        if (surfaceDict.isDict("trimFeatures"))
+        {
+            dictionary trimDict = surfaceDict.subDict("trimFeatures");
 
+            scalar minLen =
+                trimDict.lookupOrAddDefault<scalar>("minLen", -GREAT);
 
-    // Trim set
-    // ~~~~~~~~
+            label minElem = trimDict.lookupOrAddDefault<label>("minElem", 0);
 
-    scalar minLen = -GREAT;
-    if (args.optionReadIfPresent("minLen", minLen))
-    {
-        Info<< "Removing features of length < " << minLen << endl;
-    }
+            // Trim away small groups of features
+            if (minElem > 0 || minLen > 0)
+            {
+                Info<< "Removing features of length < "
+                    << minLen << endl;
+                Info<< "Removing features with number of edges < "
+                    << minElem << endl;
 
-    label minElem = 0;
-    if (args.optionReadIfPresent("minElem", minElem))
-    {
-        Info<< "Removing features with number of edges < " << minElem << endl;
-    }
+                set.trimFeatures(minLen, minElem);
+            }
+        }
 
-    // Trim away small groups of features
-    if (minElem > 0 || minLen > 0)
-    {
-        set.trimFeatures(minLen, minElem);
-        Info<< endl << "Removed small features" << endl;
-    }
 
+        // Subset
+        // ~~~~~~
 
-    // Subset
-    // ~~~~~~
+        // Convert to marked edges, points
+        List<surfaceFeatures::edgeStatus> edgeStat(set.toStatus());
 
-    // Convert to marked edges, points
-    List<surfaceFeatures::edgeStatus> edgeStat(set.toStatus());
+        if (surfaceDict.isDict("subsetFeatures"))
+        {
+            dictionary subsetDict = surfaceDict.subDict("subsetFeatures");
 
-    if (args.optionFound("subsetBox"))
-    {
-        treeBoundBox bb
-        (
-            args.optionLookup("subsetBox")()
-        );
+            if (subsetDict.found("insideBox"))
+            {
+                treeBoundBox bb(subsetDict.lookup("insideBox")());
 
-        Info<< "Removing all edges outside bb " << bb << endl;
-        dumpBox(bb, "subsetBox.obj");
+                Info<< "Removing all edges outside bb " << bb << endl;
+                dumpBox(bb, "subsetBox.obj");
 
-        deleteBox
-        (
-            surf,
-            bb,
-            false,
-            edgeStat
-        );
-    }
-    else if (args.optionFound("deleteBox"))
-    {
-        treeBoundBox bb
-        (
-            args.optionLookup("deleteBox")()
-        );
+                deleteBox
+                (
+                    surf,
+                    bb,
+                    false,
+                    edgeStat
+                );
+            }
+            else if (subsetDict.found("outsideBox"))
+            {
+                treeBoundBox bb(subsetDict.lookup("outsideBox")());
 
-        Info<< "Removing all edges inside bb " << bb << endl;
-        dumpBox(bb, "deleteBox.obj");
+                Info<< "Removing all edges inside bb " << bb << endl;
+                dumpBox(bb, "deleteBox.obj");
 
-        deleteBox
-        (
-            surf,
-            bb,
-            true,
-            edgeStat
-        );
-    }
+                deleteBox
+                (
+                    surf,
+                    bb,
+                    true,
+                    edgeStat
+                );
+            }
 
-    if (args.optionFound("manifoldEdgesOnly"))
-    {
-        Info<< "Removing all non-manifold edges" << endl;
+            const Switch manifoldEdges =
+                subsetDict.lookupOrAddDefault<Switch>("manifoldEdges", "no");
 
-        forAll(edgeStat, edgeI)
-        {
-            if (surf.edgeFaces()[edgeI].size() != 2)
+            if (manifoldEdges)
             {
-                edgeStat[edgeI] = surfaceFeatures::NONE;
+                Info<< "Removing all non-manifold edges" << endl;
+
+                forAll(edgeStat, edgeI)
+                {
+                    if (surf.edgeFaces()[edgeI].size() != 2)
+                    {
+                        edgeStat[edgeI] = surfaceFeatures::NONE;
+                    }
+                }
             }
-        }
-    }
 
-    if (args.optionFound("plane"))
-    {
-        plane cutPlane(args.optionLookup("plane")());
+            if (subsetDict.found("plane"))
+            {
+                plane cutPlane(subsetDict.lookup("plane")());
 
-        deleteEdges
-        (
-            surf,
-            cutPlane,
-            edgeStat
-        );
+                deleteEdges
+                (
+                    surf,
+                    cutPlane,
+                    edgeStat
+                );
 
-        Info<< "Only edges that intersect the plane with normal "
-            << cutPlane.normal() << " and base point " << cutPlane.refPoint()
-            << " will be included as feature edges."<< endl;
-    }
+                Info<< "Only edges that intersect the plane with normal "
+                    << cutPlane.normal()
+                    << " and base point " << cutPlane.refPoint()
+                    << " will be included as feature edges."<< endl;
+            }
+        }
 
 
-    surfaceFeatures newSet(surf);
-    newSet.setFromStatus(edgeStat);
+        surfaceFeatures newSet(surf);
+        newSet.setFromStatus(edgeStat);
 
-    //Info<< endl << "Writing trimmed features to " << outFileName << endl;
-    //newSet.write(outFileName);
+        if (writeObj)
+        {
+            newSet.writeObj("final");
+        }
 
-    // Info<< endl << "Writing edge objs." << endl;
-    // newSet.writeObj("final");
+        Info<< nl
+            << "Final feature set after trimming and subsetting:" << nl
+            << "    feature points : " << newSet.featurePoints().size() << nl
+            << "    feature edges  : " << newSet.featureEdges().size() << nl
+            << "    of which" << nl
+            << "        region edges   : " << newSet.nRegionEdges() << nl
+            << "        external edges : " << newSet.nExternalEdges() << nl
+            << "        internal edges : " << newSet.nInternalEdges() << nl
+            << endl;
 
-    Info<< nl
-        << "Final feature set:" << nl
-        << "    feature points : " << newSet.featurePoints().size() << nl
-        << "    feature edges  : " << newSet.featureEdges().size() << nl
-        << "    of which" << nl
-        << "        region edges   : " << newSet.nRegionEdges() << nl
-        << "        external edges : " << newSet.nExternalEdges() << nl
-        << "        internal edges : " << newSet.nInternalEdges() << nl
-        << endl;
+        // Extracting and writing a extendedFeatureEdgeMesh
+        extendedFeatureEdgeMesh feMesh
+        (
+            newSet,
+            runTime,
+            sFeatFileName + ".extendedFeatureEdgeMesh"
+        );
 
-    // Extracting and writing a extendedFeatureEdgeMesh
-    extendedFeatureEdgeMesh feMesh
-    (
-        newSet,
-        runTime,
-        sFeatFileName + ".extendedFeatureEdgeMesh"
-    );
+        Info<< nl << "Writing extendedFeatureEdgeMesh to "
+            << feMesh.objectPath() << endl;
 
-    Info<< nl << "Writing extendedFeatureEdgeMesh to " << feMesh.objectPath()
-        << endl;
+        if (writeObj)
+        {
+            feMesh.writeObj(surfFileName.lessExt().name());
+        }
 
-    if (writeObj)
-    {
-        feMesh.writeObj(surfFileName.lessExt().name());
-    }
+        feMesh.write();
 
-    feMesh.write();
+        // Write a featureEdgeMesh for backwards compatibility
+        if (writeFeatureEdgeMesh)
+        {
+            featureEdgeMesh bfeMesh
+            (
+                IOobject
+                (
+                    surfFileName.lessExt().name() + ".eMesh",   // name
+                    runTime.constant(),                         // instance
+                    "triSurface",
+                    runTime,                                    // registry
+                    IOobject::NO_READ,
+                    IOobject::AUTO_WRITE,
+                    false
+                ),
+                feMesh.points(),
+                feMesh.edges()
+            );
 
-    // Write a featureEdgeMesh for backwards compatibility
-    {
-        featureEdgeMesh bfeMesh
+            Info<< nl << "Writing featureEdgeMesh to "
+                << bfeMesh.objectPath() << endl;
+
+            bfeMesh.regIOobject::write();
+        }
+
+        triSurfaceMesh searchSurf
         (
             IOobject
             (
-                surfFileName.lessExt().name() + ".eMesh",   // name
-                runTime.constant(), // instance
+                sFeatFileName + ".closeness",
+                runTime.constant(),
                 "triSurface",
-                runTime,            // registry
+                runTime,
                 IOobject::NO_READ,
-                IOobject::AUTO_WRITE,
-                false
+                IOobject::NO_WRITE
             ),
-            feMesh.points(),
-            feMesh.edges()
+            surf
         );
 
-        Info<< nl << "Writing featureEdgeMesh to "
-            << bfeMesh.objectPath() << endl;
-
-        bfeMesh.regIOobject::write();
-    }
-
-    triSurfaceMesh searchSurf
-    (
-        IOobject
-        (
-            sFeatFileName + ".closeness",
-            runTime.constant(),
-            "triSurface",
-            runTime,
-            IOobject::NO_READ,
-            IOobject::NO_WRITE
-        ),
-        surf
-    );
-
     // Find close features
 
     // // Dummy trim operation to mark features
@@ -922,72 +884,59 @@ int main(int argc, char *argv[])
     //     )
     // );
 
-    if (args.optionFound("closeness"))
-    {
-        Info<< nl << "Extracting internal and external closeness of surface."
-            << endl;
-
-        // Internal and external closeness
+        if (closeness)
+        {
+            Info<< nl << "Extracting internal and external closeness of "
+                << "surface." << endl;
 
-        // Prepare start and end points for intersection tests
+            // Internal and external closeness
 
-        const vectorField& normals = searchSurf.faceNormals();
+            // Prepare start and end points for intersection tests
 
-        scalar span = searchSurf.bounds().mag();
+            const vectorField& normals = searchSurf.faceNormals();
 
-        //args.optionReadIfPresent("closeness", span);
+            scalar span = searchSurf.bounds().mag();
 
-        scalar externalAngleTolerance = 10;
-        scalar externalToleranceCosAngle = Foam::cos
-        (
-            degToRad(180 - externalAngleTolerance)
-        );
+            //args.optionReadIfPresent("closeness", span);
 
-        scalar internalAngleTolerance = 45;
-        scalar internalToleranceCosAngle = Foam::cos
-        (
-            degToRad(180 - internalAngleTolerance)
-        );
+            scalar externalAngleTolerance = 10;
+            scalar externalToleranceCosAngle =
+                Foam::cos
+                (
+                    degToRad(180 - externalAngleTolerance)
+                );
 
-        Info<< "externalToleranceCosAngle: " << externalToleranceCosAngle << nl
-            << "internalToleranceCosAngle: " << internalToleranceCosAngle
-            << endl;
+            scalar internalAngleTolerance = 45;
+            scalar internalToleranceCosAngle =
+                Foam::cos
+                (
+                    degToRad(180 - internalAngleTolerance)
+                );
 
-        // Info<< "span " << span << endl;
+            Info<< "externalToleranceCosAngle: " << externalToleranceCosAngle
+                << nl
+                << "internalToleranceCosAngle: " << internalToleranceCosAngle
+                << endl;
 
-        pointField start = searchSurf.faceCentres() - span*normals;
-        pointField end = searchSurf.faceCentres() + span*normals;
-        const pointField& faceCentres = searchSurf.faceCentres();
+            // Info<< "span " << span << endl;
 
-        List<List<pointIndexHit> > allHitInfo;
+            pointField start = searchSurf.faceCentres() - span*normals;
+            pointField end = searchSurf.faceCentres() + span*normals;
+            const pointField& faceCentres = searchSurf.faceCentres();
 
-        // Find all intersections (in order)
-        searchSurf.findLineAll(start, end, allHitInfo);
+            List<List<pointIndexHit> > allHitInfo;
 
-        scalarField internalCloseness(start.size(), GREAT);
-        scalarField externalCloseness(start.size(), GREAT);
+            // Find all intersections (in order)
+            searchSurf.findLineAll(start, end, allHitInfo);
 
-        forAll(allHitInfo, fI)
-        {
-            const List<pointIndexHit>& hitInfo = allHitInfo[fI];
+            scalarField internalCloseness(start.size(), GREAT);
+            scalarField externalCloseness(start.size(), GREAT);
 
-            if (hitInfo.size() < 1)
+            forAll(allHitInfo, fI)
             {
-                drawHitProblem(fI, surf, start, faceCentres, end, hitInfo);
+                const List<pointIndexHit>& hitInfo = allHitInfo[fI];
 
-                // FatalErrorIn(args.executable())
-                //     << "findLineAll did not hit its own face."
-                //     << exit(FatalError);
-            }
-            else if (hitInfo.size() == 1)
-            {
-                if (!hitInfo[0].hit())
-                {
-                    // FatalErrorIn(args.executable())
-                    //     << "findLineAll did not hit any face."
-                    //     << exit(FatalError);
-                }
-                else if (hitInfo[0].index() != fI)
+                if (hitInfo.size() < 1)
                 {
                     drawHitProblem(fI, surf, start, faceCentres, end, hitInfo);
 
@@ -995,283 +944,339 @@ int main(int argc, char *argv[])
                     //     << "findLineAll did not hit its own face."
                     //     << exit(FatalError);
                 }
-            }
-            else
-            {
-                label ownHitI = -1;
-
-                forAll(hitInfo, hI)
+                else if (hitInfo.size() == 1)
                 {
-                    // Find the hit on the triangle that launched the ray
-
-                    if (hitInfo[hI].index() == fI)
+                    if (!hitInfo[0].hit())
                     {
-                        ownHitI = hI;
-
-                        break;
+                        // FatalErrorIn(args.executable())
+                        //     << "findLineAll did not hit any face."
+                        //     << exit(FatalError);
                     }
-                }
-
-                if (ownHitI < 0)
-                {
-                    drawHitProblem(fI, surf, start, faceCentres, end, hitInfo);
-
-                    // FatalErrorIn(args.executable())
-                    //     << "findLineAll did not hit its own face."
-                    //     << exit(FatalError);
-                }
-                else if (ownHitI == 0)
-                {
-                    // There are no internal hits, the first hit is the closest
-                    // external hit
-
-                    if
-                    (
-                        (normals[fI] & normals[hitInfo[ownHitI + 1].index()])
-                      < externalToleranceCosAngle
-                    )
+                    else if (hitInfo[0].index() != fI)
                     {
-                        externalCloseness[fI] = mag
+                        drawHitProblem
                         (
-                            faceCentres[fI] - hitInfo[ownHitI + 1].hitPoint()
+                            fI,
+                            surf,
+                            start,
+                            faceCentres,
+                            end,
+                            hitInfo
                         );
+
+                        // FatalErrorIn(args.executable())
+                        //     << "findLineAll did not hit its own face."
+                        //     << exit(FatalError);
                     }
                 }
-                else if (ownHitI == hitInfo.size() - 1)
+                else
                 {
-                    // There are no external hits, the last but one hit is the
-                    // closest internal hit
+                    label ownHitI = -1;
 
-                    if
-                    (
-                        (normals[fI] & normals[hitInfo[ownHitI - 1].index()])
-                      < internalToleranceCosAngle
-                    )
+                    forAll(hitInfo, hI)
+                    {
+                        // Find the hit on the triangle that launched the ray
+
+                        if (hitInfo[hI].index() == fI)
+                        {
+                            ownHitI = hI;
+
+                            break;
+                        }
+                    }
+
+                    if (ownHitI < 0)
                     {
-                        internalCloseness[fI] = mag
+                        drawHitProblem
                         (
-                            faceCentres[fI] - hitInfo[ownHitI - 1].hitPoint()
+                            fI,
+                            surf,
+                            start,
+                            faceCentres,
+                            end,
+                            hitInfo
                         );
+
+                        // FatalErrorIn(args.executable())
+                        //     << "findLineAll did not hit its own face."
+                        //     << exit(FatalError);
                     }
-                }
-                else
-                {
-                    if
-                    (
-                        (normals[fI] & normals[hitInfo[ownHitI + 1].index()])
-                      < externalToleranceCosAngle
-                    )
+                    else if (ownHitI == 0)
                     {
-                        externalCloseness[fI] = mag
+                        // There are no internal hits, the first hit is the
+                        // closest external hit
+
+                        if
                         (
-                            faceCentres[fI] - hitInfo[ownHitI + 1].hitPoint()
-                        );
+                            (
+                                normals[fI]
+                              & normals[hitInfo[ownHitI + 1].index()]
+                            )
+                          < externalToleranceCosAngle
+                        )
+                        {
+                            externalCloseness[fI] =
+                                mag
+                                (
+                                    faceCentres[fI]
+                                  - hitInfo[ownHitI + 1].hitPoint()
+                                );
+                        }
                     }
+                    else if (ownHitI == hitInfo.size() - 1)
+                    {
+                        // There are no external hits, the last but one hit is
+                        // the closest internal hit
 
-                    if
-                    (
-                        (normals[fI] & normals[hitInfo[ownHitI - 1].index()])
-                      < internalToleranceCosAngle
-                    )
+                        if
+                        (
+                            (
+                                normals[fI]
+                              & normals[hitInfo[ownHitI - 1].index()]
+                            )
+                          < internalToleranceCosAngle
+                        )
+                        {
+                            internalCloseness[fI] =
+                                mag
+                                (
+                                    faceCentres[fI]
+                                  - hitInfo[ownHitI - 1].hitPoint()
+                                );
+                        }
+                    }
+                    else
                     {
-                        internalCloseness[fI] = mag
+                        if
                         (
-                            faceCentres[fI] - hitInfo[ownHitI - 1].hitPoint()
-                        );
+                            (
+                                normals[fI]
+                              & normals[hitInfo[ownHitI + 1].index()]
+                            )
+                          < externalToleranceCosAngle
+                        )
+                        {
+                            externalCloseness[fI] =
+                                mag
+                                (
+                                    faceCentres[fI]
+                                  - hitInfo[ownHitI + 1].hitPoint()
+                                );
+                        }
+
+                        if
+                        (
+                            (
+                                normals[fI]
+                              & normals[hitInfo[ownHitI - 1].index()]
+                            )
+                          < internalToleranceCosAngle
+                        )
+                        {
+                            internalCloseness[fI] =
+                                mag
+                                (
+                                    faceCentres[fI]
+                                  - hitInfo[ownHitI - 1].hitPoint()
+                                );
+                        }
                     }
                 }
             }
-        }
 
-        triSurfaceScalarField internalClosenessField
-        (
-            IOobject
+            triSurfaceScalarField internalClosenessField
             (
-                sFeatFileName + ".internalCloseness",
-                runTime.constant(),
-                "triSurface",
-                runTime,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            surf,
-            dimLength,
-            internalCloseness
-        );
+                IOobject
+                (
+                    sFeatFileName + ".internalCloseness",
+                    runTime.constant(),
+                    "triSurface",
+                    runTime,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                surf,
+                dimLength,
+                internalCloseness
+            );
 
-        internalClosenessField.write();
+            internalClosenessField.write();
 
-        triSurfaceScalarField externalClosenessField
-        (
-            IOobject
+            triSurfaceScalarField externalClosenessField
             (
-                sFeatFileName + ".externalCloseness",
-                runTime.constant(),
-                "triSurface",
-                runTime,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            surf,
-            dimLength,
-            externalCloseness
-        );
+                IOobject
+                (
+                    sFeatFileName + ".externalCloseness",
+                    runTime.constant(),
+                    "triSurface",
+                    runTime,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                surf,
+                dimLength,
+                externalCloseness
+            );
 
-        externalClosenessField.write();
+            externalClosenessField.write();
 
-        if (writeVTK)
-        {
-            vtkSurfaceWriter().write
-            (
-                runTime.constant()/"triSurface",    // outputDir
-                sFeatFileName,                      // surfaceName
-                surf.points(),
-                faces,
-                "internalCloseness",                // fieldName
-                internalCloseness,
-                false,                              // isNodeValues
-                true                                // verbose
-            );
+            if (writeVTK)
+            {
+                vtkSurfaceWriter().write
+                (
+                    runTime.constant()/"triSurface",    // outputDir
+                    sFeatFileName,                      // surfaceName
+                    surf.points(),
+                    faces,
+                    "internalCloseness",                // fieldName
+                    internalCloseness,
+                    false,                              // isNodeValues
+                    true                                // verbose
+                );
 
-            vtkSurfaceWriter().write
-            (
-                runTime.constant()/"triSurface",    // outputDir
-                sFeatFileName,                      // surfaceName
-                surf.points(),
-                faces,
-                "externalCloseness",                // fieldName
-                externalCloseness,
-                false,                              // isNodeValues
-                true                                // verbose
-            );
+                vtkSurfaceWriter().write
+                (
+                    runTime.constant()/"triSurface",    // outputDir
+                    sFeatFileName,                      // surfaceName
+                    surf.points(),
+                    faces,
+                    "externalCloseness",                // fieldName
+                    externalCloseness,
+                    false,                              // isNodeValues
+                    true                                // verbose
+                );
+            }
         }
-    }
 
 
 #ifdef ENABLE_CURVATURE
-    if (args.optionFound("curvature"))
-    {
-        Info<< nl << "Extracting curvature of surface at the points." << endl;
+        if (curvature)
+        {
+            Info<< nl << "Extracting curvature of surface at the points."
+                << endl;
 
-        scalarField k = calcCurvature(surf);
+            scalarField k = calcCurvature(surf);
 
         // Modify the curvature values on feature edges and points to be zero.
 
-    //    forAll(newSet.featureEdges(), fEI)
-    //    {
-    //        const edge& e = surf.edges()[newSet.featureEdges()[fEI]];
-    //
-    //        k[surf.meshPoints()[e.start()]] = 0.0;
-    //        k[surf.meshPoints()[e.end()]] = 0.0;
-    //    }
+        //    forAll(newSet.featureEdges(), fEI)
+        //    {
+        //        const edge& e = surf.edges()[newSet.featureEdges()[fEI]];
+        //
+        //        k[surf.meshPoints()[e.start()]] = 0.0;
+        //        k[surf.meshPoints()[e.end()]] = 0.0;
+        //    }
 
-        triSurfacePointScalarField kField
-        (
-            IOobject
+            triSurfacePointScalarField kField
             (
-                sFeatFileName + ".curvature",
-                runTime.constant(),
-                "triSurface",
-                runTime,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            surf,
-            dimLength,
-            k
-        );
+                IOobject
+                (
+                    sFeatFileName + ".curvature",
+                    runTime.constant(),
+                    "triSurface",
+                    runTime,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                surf,
+                dimLength,
+                k
+            );
 
-        kField.write();
+            kField.write();
 
-        if (writeVTK)
-        {
-            vtkSurfaceWriter().write
-            (
-                runTime.constant()/"triSurface",    // outputDir
-                sFeatFileName,                      // surfaceName
-                surf.points(),
-                faces,
-                "curvature",                        // fieldName
-                k,
-                true,                               // isNodeValues
-                true                                // verbose
-            );
+            if (writeVTK)
+            {
+                vtkSurfaceWriter().write
+                (
+                    runTime.constant()/"triSurface",    // outputDir
+                    sFeatFileName,                      // surfaceName
+                    surf.points(),
+                    faces,
+                    "curvature",                        // fieldName
+                    k,
+                    true,                               // isNodeValues
+                    true                                // verbose
+                );
+            }
         }
-    }
 #endif
 
 
-    if (args.optionFound("featureProximity"))
-    {
-        Info<< nl << "Extracting proximity of close feature points and edges "
-            << "to the surface" << endl;
+        if (featureProximity)
+        {
+            Info<< nl << "Extracting proximity of close feature points and "
+                << "edges to the surface" << endl;
 
-        const scalar searchDistance =
-            args.optionRead<scalar>("featureProximity");
+            const scalar searchDistance =
+                readScalar(surfaceDict.lookup("maxFeatureProximity"));
 
-        const scalar radiusSqr = sqr(searchDistance);
+            const scalar radiusSqr = sqr(searchDistance);
 
-        scalarField featureProximity(surf.size(), searchDistance);
+            scalarField featureProximity(surf.size(), searchDistance);
 
-        forAll(surf, fI)
-        {
-            const triPointRef& tri = surf[fI].tri(surf.points());
-            const point& triCentre = tri.circumCentre();
+            forAll(surf, fI)
+            {
+                const triPointRef& tri = surf[fI].tri(surf.points());
+                const point& triCentre = tri.circumCentre();
 
-            List<pointIndexHit> hitList;
+                List<pointIndexHit> hitList;
 
-            feMesh.allNearestFeatureEdges(triCentre, radiusSqr, hitList);
+                feMesh.allNearestFeatureEdges(triCentre, radiusSqr, hitList);
 
-            featureProximity[fI] =
-                calcProximityOfFeatureEdges
-                (
-                    feMesh,
-                    hitList,
-                    featureProximity[fI]
-                );
+                featureProximity[fI] =
+                    calcProximityOfFeatureEdges
+                    (
+                        feMesh,
+                        hitList,
+                        featureProximity[fI]
+                    );
 
-            feMesh.allNearestFeaturePoints(triCentre, radiusSqr, hitList);
+                feMesh.allNearestFeaturePoints(triCentre, radiusSqr, hitList);
 
-            featureProximity[fI] =
-                calcProximityOfFeaturePoints
-                (
-                    hitList,
-                    featureProximity[fI]
-                );
-        }
+                featureProximity[fI] =
+                    calcProximityOfFeaturePoints
+                    (
+                        hitList,
+                        featureProximity[fI]
+                    );
+            }
 
-        triSurfaceScalarField featureProximityField
-        (
-            IOobject
+            triSurfaceScalarField featureProximityField
             (
-                sFeatFileName + ".featureProximity",
-                runTime.constant(),
-                "triSurface",
-                runTime,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            surf,
-            dimLength,
-            featureProximity
-        );
+                IOobject
+                (
+                    sFeatFileName + ".featureProximity",
+                    runTime.constant(),
+                    "triSurface",
+                    runTime,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                surf,
+                dimLength,
+                featureProximity
+            );
 
-        featureProximityField.write();
+            featureProximityField.write();
 
-        if (writeVTK)
-        {
-            vtkSurfaceWriter().write
-            (
-                runTime.constant()/"triSurface",    // outputDir
-                sFeatFileName,                      // surfaceName
-                surf.points(),
-                faces,
-                "featureProximity",                // fieldName
-                featureProximity,
-                false,                              // isNodeValues
-                true                                // verbose
-            );
+            if (writeVTK)
+            {
+                vtkSurfaceWriter().write
+                (
+                    runTime.constant()/"triSurface",    // outputDir
+                    sFeatFileName,                      // surfaceName
+                    surf.points(),
+                    faces,
+                    "featureProximity",                 // fieldName
+                    featureProximity,
+                    false,                              // isNodeValues
+                    true                                // verbose
+                );
+            }
         }
+
+        Info<< endl;
     }
 
     Info<< "End\n" << endl;
diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict
new file mode 100644
index 0000000000000000000000000000000000000000..3621d64a293ffa8a1a2daf3be441818036555e92
--- /dev/null
+++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict
@@ -0,0 +1,86 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  dev                                   |
+|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      surfaceFeatureExtractDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+surface1.stl
+{
+    // extractFromFile || extractFromSurface
+    extractionMethod    extractFromFile;
+
+    extractFromFile
+    {
+        // Load from an existing feature edge file
+        featureEdgeFile "constant/triSurface/featureEdges.nas";
+    }
+    
+    trimFeatures
+    {
+        // Remove features with fewer than the specified number of edges
+        minElem         0;
+        
+        // Remove features shorter than the specified cumulative length
+        minLen          0.0;
+    }  
+    
+    subsetFeatures
+    {        
+        // Use a plane to select feature edges
+        // (normal)(basePoint)
+        plane               (1 0 0)(0 0 0);
+        
+        // Select feature edges using a box
+        // (minPt)(maxPt)
+        insideBox           (0 0 0)(1 1 1);
+        outsideBox          (0 0 0)(1 1 1);
+        
+        // Remove any non-manifold (open or > 2 connected faces) edges
+        manifoldEdges       no;
+    }
+    
+    // Output the curvature of the surface
+    curvature               no;
+    
+    // Output the proximity of feature points and edges to each other
+    featureProximity        no;
+    // The maximum search distance to use when looking for other feature
+    // points and edges
+    maxFeatureProximity     1;
+    
+    // Out put the closeness of surface elements to other surface elements.
+    closeness               no;
+
+    // Write options
+    writeVTK                no;
+    writeObj                yes;
+    writeFeatureEdgeMesh    no;
+}
+
+
+surface2.nas
+{
+    extractionMethod    extractFromSurface;
+
+    extractFromSurface
+    {
+        // Mark edges whose adjacent surface normals are at an angle less
+        // than includedAngle as features
+        // - 0  : selects no edges
+        // - 180: selects all edges
+        includedAngle   120;
+    }
+}
+
+
+// ************************************************************************* //