void ReadAndMapFields
(
    const fvMesh& mesh,
    const IOobjectList& objects,
    const fvMesh& tetDualMesh,
    const labelList& map,
    const typename MappedGeoField::value_type& nullValue,
    PtrList<MappedGeoField>& tetFields
)
{
    typedef typename MappedGeoField::value_type Type;

    // Search list of objects for wanted type
    IOobjectList fieldObjects(objects.lookupClass(ReadGeoField::typeName));

    tetFields.setSize(fieldObjects.size());

    label i = 0;
    forAllConstIter(IOobjectList, fieldObjects, iter)
    {
        Info<< "Converting " << ReadGeoField::typeName << ' ' << iter.key()
            << endl;

        ReadGeoField readField(*iter(), mesh);

        tetFields.set
        (
            i,
            new MappedGeoField
            (
                IOobject
                (
                    readField.name(),
                    readField.instance(),
                    readField.local(),
                    tetDualMesh,
                    IOobject::NO_READ,
                    IOobject::AUTO_WRITE,
                    readField.registerObject()
                ),
                pointMesh::New(tetDualMesh),
                dimensioned<Type>
                (
                    "zero",
                    readField.dimensions(),
                    pTraits<Type>::zero
                )
            )
        );

        Field<Type>& fld = tetFields[i].internalField();

        // Map from read field. Set unmapped entries to nullValue.
        fld.setSize(map.size(), nullValue);
        forAll(map, pointI)
        {
            label index = map[pointI];

            if (index > 0)
            {
                label cellI = index-1;
                fld[pointI] = readField[cellI];
            }
            else if (index < 0)
            {
                label faceI = -index-1;
                label bFaceI = faceI - mesh.nInternalFaces();
                if (bFaceI >= 0)
                {
                    label patchI = mesh.boundaryMesh().patchID()[bFaceI];
                    label localFaceI = mesh.boundaryMesh()[patchI].whichFace
                    (
                        faceI
                    );
                    fld[pointI] = readField.boundaryField()[patchI][localFaceI];
                }
                //else
                //{
                //    FatalErrorIn("ReadAndMapFields(..)")
                //        << "Face " << faceI << " from index " << index
                //        << " is not a boundary face." << abort(FatalError);
                //}

            }
            //else
            //{
            //    WarningIn("ReadAndMapFields(..)")
            //        << "Point " << pointI << " at "
            //        << tetDualMesh.points()[pointI]
            //        << " has no dual correspondence." << endl;
            //}
        }
Foam::quadraticFitSnGradData::quadraticFitSnGradData
(
    const fvMesh& mesh,
    const scalar cWeight
)
:
    MeshObject<fvMesh, quadraticFitSnGradData>(mesh),
    centralWeight_(cWeight),
    #ifdef SPHERICAL_GEOMETRY
        dim_(2),
    #else
        dim_(mesh.nGeometricD()),
    #endif
    minSize_
    (
        dim_ == 1 ? 3 :
        dim_ == 2 ? 6 :
        dim_ == 3 ? 9 : 0
    ),
    stencil_(mesh),
    fit_(mesh.nInternalFaces())
{
    if (debug)
    {
        Info << "Contructing quadraticFitSnGradData" << endl;
    }

    // check input
    if (centralWeight_ < 1 - SMALL)
    {
        FatalErrorIn("quadraticFitSnGradData::quadraticFitSnGradData")
            << "centralWeight requested = " << centralWeight_
            << " should not be less than one"
            << exit(FatalError);
    }

    if (minSize_ == 0)
    {
        FatalErrorIn("quadraticFitSnGradData")
            << " dimension must be 1,2 or 3, not" << dim_ << exit(FatalError);
    }

    // store the polynomial size for each face to write out
    surfaceScalarField snGradPolySize
    (
        IOobject
        (
            "quadraticFitSnGradPolySize",
            "constant",
            mesh,
            IOobject::NO_READ,
            IOobject::NO_WRITE
        ),
        mesh,
        dimensionedScalar("quadraticFitSnGradPolySize", dimless, scalar(0))
    );

    // Get the cell/face centres in stencil order.
    // Centred face stencils no good for triangles of tets. Need bigger stencils
    List<List<point> > stencilPoints(stencil_.stencil().size());
    stencil_.collectData
    (
        mesh.C(),
        stencilPoints
    );

    // find the fit coefficients for every face in the mesh

    for(label faci = 0; faci < mesh.nInternalFaces(); faci++)
    {
        snGradPolySize[faci] = calcFit(stencilPoints[faci], faci);
    }

    if (debug)
    {
        snGradPolySize.write();
        Info<< "quadraticFitSnGradData::quadraticFitSnGradData() :"
            << "Finished constructing polynomialFit data"
            << endl;
    }
}