Ejemplo n.º 1
0
void transform
(
    GeometricField<Type, PatchField, GeoMesh>& rtf,
    const dimensionedTensor& t,
    const GeometricField<Type, PatchField, GeoMesh>& tf
)
{
    transform(rtf.internalField(), t.value(), tf.internalField());
    transform(rtf.boundaryField(), t.value(), tf.boundaryField());
}
Ejemplo n.º 2
0
void transform
(
    GeometricField<Type, PatchField, GeoMesh>& rtf,
    const GeometricField<tensor, PatchField, GeoMesh>& trf,
    const GeometricField<Type, PatchField, GeoMesh>& tf
)
{
    transform(rtf.internalField(), trf.internalField(), tf.internalField());
    transform(rtf.boundaryField(), trf.boundaryField(), tf.boundaryField());
}
Foam::tmp<Field<Type> > Foam::tecplotWriter::getFaceField
(
    const GeometricField<Type, fvsPatchField, surfaceMesh>& sfld,
    const labelList& faceLabels
) const
{
    const polyBoundaryMesh& patches = sfld.mesh().boundaryMesh();

    tmp<Field<Type> > tfld(new Field<Type>(faceLabels.size()));
    Field<Type>& fld = tfld();

    forAll(faceLabels, i)
    {
        label faceI = faceLabels[i];

        label patchI = patches.whichPatch(faceI);

        if (patchI == -1)
        {
            fld[i] = sfld[faceI];
        }
        else
        {
            label localFaceI = faceI - patches[patchI].start();
            fld[i] = sfld.boundaryField()[patchI][localFaceI];
        }
    }
Foam::tmp<Field<Type> > Foam::tecplotWriter::getPatchField
(
    const bool nearCellValue,
    const GeometricField<Type, fvPatchField, volMesh>& vfld,
    const label patchI
) const
{
    if (nearCellValue)
    {
        return vfld.boundaryField()[patchI].patchInternalField();
    }
    else
    {
        return vfld.boundaryField()[patchI];
    }
}
void Foam::motionSmootherAlgo::checkConstraints
(
    GeometricField<Type, pointPatchField, pointMesh>& pf
)
{
    typedef GeometricField<Type, pointPatchField, pointMesh> FldType;

    const polyMesh& mesh = pf.mesh();

    const polyBoundaryMesh& bm = mesh.boundaryMesh();

    // first count the total number of patch-patch points

    label nPatchPatchPoints = 0;

    forAll(bm, patchi)
    {
        if (!isA<emptyPolyPatch>(bm[patchi]))
        {
            nPatchPatchPoints += bm[patchi].boundaryPoints().size();
        }
    }


    typename FldType::GeometricBoundaryField& bFld = pf.boundaryField();


    // Evaluate in reverse order

    forAllReverse(bFld, patchi)
    {
        bFld[patchi].initEvaluate(Pstream::blocking);   // buffered
    }
Ejemplo n.º 6
0
Foam::tmp<Foam::Field<Type> > Foam::fieldValues::faceSource::filterField
(
    const GeometricField<Type, fvPatchField, volMesh>& field,
    const bool applyOrientation
) const
{
    tmp<Field<Type> > tvalues(new Field<Type>(faceId_.size()));
    Field<Type>& values = tvalues();

    forAll(values, i)
    {
        label faceI = faceId_[i];
        label patchI = facePatchId_[i];
        if (patchI >= 0)
        {
            values[i] = field.boundaryField()[patchI][faceI];
        }
        else
        {
            FatalErrorIn
            (
                "fieldValues::faceSource::filterField"
                "("
                    "const GeometricField<Type, fvPatchField, volMesh>&"
                ") const"
            )   << type() << " " << name_ << ": "
                << sourceTypeNames_[source_] << "(" << sourceName_ << "):"
                << nl
                << "    Unable to process internal faces for volume field "
                << field.name() << nl << abort(FatalError);
        }
    }
Ejemplo n.º 7
0
tmp<GeometricField<Type, fvPatchField, volMesh> >
EulerLocalDdtScheme<Type>::fvcDdt
(
    const volScalarField& rho,
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    const objectRegistry& registry = this->mesh();

    // get access to the scalar beta[i]
    const scalarField& beta =
        registry.lookupObject<scalarField>(deltaTName_);

    volScalarField rDeltaT =
        1.0/(beta[0]*registry.lookupObject<volScalarField>(deltaTauName_));

    IOobject ddtIOobject
    (
        "ddt("+rho.name()+','+vf.name()+')',
        mesh().time().timeName(),
        mesh()
    );

    if (mesh().moving())
    {
        return tmp<GeometricField<Type, fvPatchField, volMesh> >
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                ddtIOobject,
                mesh(),
                rDeltaT.dimensions()*rho.dimensions()*vf.dimensions(),
                rDeltaT.internalField()*
                (
                    rho.internalField()*vf.internalField()
                  - rho.oldTime().internalField()
                   *vf.oldTime().internalField()*mesh().V0()/mesh().V()
                ),
                rDeltaT.boundaryField()*
                (
                    rho.boundaryField()*vf.boundaryField()
                  - rho.oldTime().boundaryField()
                   *vf.oldTime().boundaryField()
                )
            )
        );
    }
    else
    {
        return tmp<GeometricField<Type, fvPatchField, volMesh> >
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                ddtIOobject,
                rDeltaT*(rho*vf - rho.oldTime()*vf.oldTime())
            )
        );
    }
}
Ejemplo n.º 8
0
Foam::tmp<Foam::Field<Type>>
Foam::sampledPatch::sampleField
(
    const GeometricField<Type, fvPatchField, volMesh>& vField
) const
{
    // One value per face
    tmp<Field<Type>> tvalues(new Field<Type>(patchFaceLabels_.size()));
    Field<Type>& values = tvalues();
    forAll(patchFaceLabels_, i)
    {
        label patchI = patchIDs_[patchIndex_[i]];
        const Field<Type>& bField = vField.boundaryField()[patchI];
        values[i] = bField[patchFaceLabels_[i]];
    }
Ejemplo n.º 9
0
tmp<GeometricField<Type, fvPatchField, volMesh> >
average
(
    const GeometricField<Type, fvsPatchField, surfaceMesh>& ssf
)
{
    const fvMesh& mesh = ssf.mesh();

    tmp<GeometricField<Type, fvPatchField, volMesh> > taverage
    (
        new GeometricField<Type, fvPatchField, volMesh>
        (
            IOobject
            (
                "average("+ssf.name()+')',
                ssf.instance(),
                mesh,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            mesh,
            ssf.dimensions()
        )
    );

    GeometricField<Type, fvPatchField, volMesh>& av = taverage();

    av.internalField() =
    (
        surfaceSum(mesh.magSf()*ssf)/surfaceSum(mesh.magSf())
    )().internalField();

    typename GeometricField<Type, fvPatchField, volMesh>::
    GeometricBoundaryField& bav = av.boundaryField();

    forAll(bav, patchi)
    {
        bav[patchi] = ssf.boundaryField()[patchi];
    }

    av.correctBoundaryConditions();

    return taverage;
}
Ejemplo n.º 10
0
void pointPatchInterpolation::interpolate
(
    const GeometricField<Type, fvPatchField, volMesh>& vf,
    GeometricField<Type, pointPatchField, pointMesh>& pf,
    bool overrideFixedValue
) const
{
    if (debug)
    {
        Info<< "pointPatchInterpolation::interpolate("
            << "const GeometricField<Type, fvPatchField, volMesh>&, "
            << "GeometricField<Type, pointPatchField, pointMesh>&) : "
            << "interpolating field from cells to points"
            << endl;
    }

    // Interpolate patch values: over-ride the internal values for the points
    // on the patch with the interpolated point values from the faces of the
    // patch

    const fvBoundaryMesh& bm = fvMesh_.boundary();

    forAll(bm, patchi)
    {
        if (!isA<emptyFvPatch>(bm[patchi]) && !bm[patchi].coupled())
        {
            pointPatchField<Type>& ppf = pf.boundaryField()[patchi];

            // Only map the values corresponding to the points associated with
            // faces, not "lone" points due to decomposition
            ppf.setInInternalField
            (
                pf.internalField(),
                patchInterpolators_[patchi].faceToPointInterpolate
                (
                    vf.boundaryField()[patchi]
                )()
            );

            if
            (
                overrideFixedValue
             && isA
                <
                    ValuePointPatchField
                    <
                        pointPatchField,
                        pointMesh,
                        pointPatch,
                        DummyMatrix,
                        Type
                    >
                >(ppf)
            )
            {
                refCast
                <
                    ValuePointPatchField
                    <
                        pointPatchField,
                        pointMesh,
                        pointPatch,
                        DummyMatrix,
                        Type
                    >
                >(ppf) = ppf;
            }
        }
    }


    // Correct patch-patch boundary points by interpolation "around" corners
    const labelListList& PointFaces = fvMesh_.pointFaces();

    forAll(patchPatchPoints_, pointi)
    {
        const label curPoint = patchPatchPoints_[pointi];
        const labelList& curFaces = PointFaces[curPoint];

        label fI = 0;

        // Reset the boundary value before accumulation
        pf[curPoint] = pTraits<Type>::zero;

        // Go through all the faces
        forAll(curFaces, facei)
        {
            if (!fvMesh_.isInternalFace(curFaces[facei]))
            {
                label patchi =
                    fvMesh_.boundaryMesh().whichPatch(curFaces[facei]);

                if (!isA<emptyFvPatch>(bm[patchi]) && !bm[patchi].coupled())
                {
                    label faceInPatchi =
                        bm[patchi].patch().whichFace(curFaces[facei]);

                    pf[curPoint] +=
                        patchPatchPointWeights_[pointi][fI]
                       *vf.boundaryField()[patchi][faceInPatchi];

                    fI++;
                }
            }
        }
    }


    // Update coupled and constrained boundaries
    pf.correctBoundaryConditions();

    if (debug)
    {
        Info<< "pointPatchInterpolation::interpolate("
            << "const GeometricField<Type, fvPatchField, volMesh>&, "
            << "GeometricField<Type, pointPatchField, pointMesh>&) : "
            << "finished interpolating field from cells to points"
            << endl;
    }
}
tmp<GeometricField<Type, fvPatchField, volMesh> > fvMeshSubset::interpolate
(
    const GeometricField<Type, fvPatchField, volMesh>& vf,
    const fvMesh& sMesh,
    const labelList& patchMap,
    const labelList& cellMap,
    const labelList& faceMap
)
{
    // Create and map the internal-field values
    Field<Type> internalField(vf.internalField(), cellMap);

    // Create and map the patch field values
    PtrList<fvPatchField<Type> > patchFields(patchMap.size());

    forAll (patchFields, patchI)
    {
        // Set the first one by hand as it corresponds to the
        // exposed internal faces.  Additional interpolation can be put here
        // as necessary.  
        if (patchMap[patchI] == -1)
        {
            patchFields.set
            (
                patchI,
                new emptyFvPatchField<Type>
                (
                    sMesh.boundary()[patchI],
                    DimensionedField<Type, volMesh>::null()
                )
            );
        }
        else
        {
            // Construct addressing
            const fvPatch& subPatch = sMesh.boundary()[patchI];
            const fvPatch& basePatch = vf.mesh().boundary()[patchMap[patchI]];
            label baseStart = basePatch.patch().start();
            label baseSize = basePatch.size();

            labelList directAddressing(subPatch.size());

            forAll(directAddressing, i)
            {
                label baseFaceI = faceMap[subPatch.patch().start()+i];

                if (baseFaceI >= baseStart && baseFaceI < baseStart+baseSize)
                {
                    directAddressing[i] = baseFaceI-baseStart;
                }
                else
                {
                    // Mapped from internal face. Do what? Map from element
                    // 0 for now.
                    directAddressing[i] = 0;
                }
            }

            patchFields.set
            (
                patchI,
                fvPatchField<Type>::New
                (
                    vf.boundaryField()[patchMap[patchI]],
                    sMesh.boundary()[patchI],
                    DimensionedField<Type, volMesh>::null(),
                    patchFieldSubset(directAddressing)
                )
            );

            // What to do with exposed internal faces if put into this patch?
        }
    }
Foam::tmp<Foam::GeometricField<Type, Foam::pointPatchField, Foam::pointMesh> >
Foam::pointFieldDecomposer::decomposeField
(
    const GeometricField<Type, pointPatchField, pointMesh>& field
) const
{
    // Create and map the internal field values
    Field<Type> internalField(field.internalField(), pointAddressing_);

    // Create a list of pointers for the patchFields
    PtrList<pointPatchField<Type> > patchFields(boundaryAddressing_.size());

    // Create and map the patch field values
    forAll(boundaryAddressing_, patchi)
    {
        if (patchFieldDecomposerPtrs_[patchi])
        {
            patchFields.set
            (
                patchi,
                pointPatchField<Type>::New
                (
                    field.boundaryField()[boundaryAddressing_[patchi]],
                    procMesh_.boundary()[patchi],
                    DimensionedField<Type, pointMesh>::null(),
                    *patchFieldDecomposerPtrs_[patchi]
                )
            );
        }
        else
        {
            patchFields.set
            (
                patchi,
                new processorPointPatchField<Type>
                (
                    procMesh_.boundary()[patchi],
                    DimensionedField<Type, pointMesh>::null()
                )
            );
        }
    }

    // Create the field for the processor
    return tmp<GeometricField<Type, pointPatchField, pointMesh> >
    (
        new GeometricField<Type, pointPatchField, pointMesh>
        (
            IOobject
            (
                field.name(),
                procMesh_().time().timeName(),
                procMesh_(),
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            procMesh_,
            field.dimensions(),
            internalField,
            patchFields
        )
    );
}
Ejemplo n.º 13
0
tmp<GeometricField<Type, fvPatchField, volMesh>>
EulerD2dt2Scheme<Type>::fvcD2dt2
(
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    dimensionedScalar rDeltaT2 =
        4.0/sqr(mesh().time().deltaT() + mesh().time().deltaT0());

    IOobject d2dt2IOobject
    (
        "d2dt2("+vf.name()+')',
        mesh().time().timeName(),
        mesh(),
        IOobject::NO_READ,
        IOobject::NO_WRITE
    );

    scalar deltaT = mesh().time().deltaTValue();
    scalar deltaT0 = mesh().time().deltaT0Value();

    scalar coefft   = (deltaT + deltaT0)/(2*deltaT);
    scalar coefft00 = (deltaT + deltaT0)/(2*deltaT0);
    scalar coefft0  = coefft + coefft00;

    if (mesh().moving())
    {
        scalar halfRdeltaT2 = rDeltaT2.value()/2.0;

        scalarField VV0 = mesh().V() + mesh().V0();
        scalarField V0V00 = mesh().V0() + mesh().V00();

        return tmp<GeometricField<Type, fvPatchField, volMesh>>
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                d2dt2IOobject,
                mesh(),
                rDeltaT2.dimensions()*vf.dimensions(),
                halfRdeltaT2*
                (
                    coefft*VV0*vf.primitiveField()

                  - (coefft*VV0 + coefft00*V0V00)
                   *vf.oldTime().primitiveField()

                  + (coefft00*V0V00)*vf.oldTime().oldTime().primitiveField()
                )/mesh().V(),
                rDeltaT2.value()*
                (
                    coefft*vf.boundaryField()
                  - coefft0*vf.oldTime().boundaryField()
                  + coefft00*vf.oldTime().oldTime().boundaryField()
                )
            )
        );
    }
    else
    {
        return tmp<GeometricField<Type, fvPatchField, volMesh>>
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                d2dt2IOobject,
                rDeltaT2*
                (
                    coefft*vf
                  - coefft0*vf.oldTime()
                  + coefft00*vf.oldTime().oldTime()
                )
            )
        );
    }
}
Ejemplo n.º 14
0
tmp<GeometricField<Type, fvPatchField, volMesh>>
EulerD2dt2Scheme<Type>::fvcD2dt2
(
    const volScalarField& rho,
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    dimensionedScalar rDeltaT2 =
        4.0/sqr(mesh().time().deltaT() + mesh().time().deltaT0());

    IOobject d2dt2IOobject
    (
        "d2dt2("+rho.name()+','+vf.name()+')',
        mesh().time().timeName(),
        mesh(),
        IOobject::NO_READ,
        IOobject::NO_WRITE
    );

    scalar deltaT = mesh().time().deltaTValue();
    scalar deltaT0 = mesh().time().deltaT0Value();

    scalar coefft   = (deltaT + deltaT0)/(2*deltaT);
    scalar coefft00 = (deltaT + deltaT0)/(2*deltaT0);

    if (mesh().moving())
    {
        scalar halfRdeltaT2 = 0.5*rDeltaT2.value();
        scalar quarterRdeltaT2 = 0.25*rDeltaT2.value();

        const scalarField VV0rhoRho0
        (
            (mesh().V() + mesh().V0())
          * (rho.primitiveField() + rho.oldTime().primitiveField())
        );

        const scalarField V0V00rho0Rho00
        (
            (mesh().V0() + mesh().V00())
          * (
                rho.oldTime().primitiveField()
              + rho.oldTime().oldTime().primitiveField()
            )
        );

        return tmp<GeometricField<Type, fvPatchField, volMesh>>
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                d2dt2IOobject,
                mesh(),
                rDeltaT2.dimensions()*rho.dimensions()*vf.dimensions(),
                quarterRdeltaT2*
                (
                    coefft*VV0rhoRho0*vf.primitiveField()

                  - (coefft*VV0rhoRho0 + coefft00*V0V00rho0Rho00)
                   *vf.oldTime().primitiveField()

                  + (coefft00*V0V00rho0Rho00)
                   *vf.oldTime().oldTime().primitiveField()
                )/mesh().V(),
                halfRdeltaT2*
                (
                    coefft
                   *(rho.boundaryField() + rho.oldTime().boundaryField())
                   *vf.boundaryField()

                  - (
                        coefft
                       *(
                           rho.boundaryField()
                         + rho.oldTime().boundaryField()
                        )
                      + coefft00
                       *(
                           rho.oldTime().boundaryField()
                         + rho.oldTime().oldTime().boundaryField()
                        )
                    )*vf.oldTime().boundaryField()

                  + coefft00
                   *(
                       rho.oldTime().boundaryField()
                     + rho.oldTime().oldTime().boundaryField()
                    )*vf.oldTime().oldTime().boundaryField()
                )
            )
        );
    }
    else
    {
        dimensionedScalar halfRdeltaT2 = 0.5*rDeltaT2;

        const volScalarField rhoRho0(rho + rho.oldTime());
        const volScalarField rho0Rho00(rho.oldTime() +rho.oldTime().oldTime());

        return tmp<GeometricField<Type, fvPatchField, volMesh>>
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                d2dt2IOobject,
                halfRdeltaT2*
                (
                    coefft*rhoRho0*vf
                  - (coefft*rhoRho0 + coefft00*rho0Rho00)*vf.oldTime()
                  + coefft00*rho0Rho00*vf.oldTime().oldTime()
                )
            )
        );
    }
}
tmp<GeometricField<Type, tetPolyPatchField, tetPointMesh> >
tetPointFieldDecomposer::decomposeField
(
    const GeometricField<Type, tetPolyPatchField, tetPointMesh>& field
) const
{
    // Create and map the internal field values
    Field<Type> internalField(field.internalField(), directAddressing());

    // Create and map the patch field values
    PtrList<tetPolyPatchField<Type> > patchFields
    (
        boundaryAddressing_.size() + 1
    );

    forAll (boundaryAddressing_, patchI)
    {
        if (boundaryAddressing_[patchI] >= 0)
        {
            patchFields.set
            (
                patchI,
                tetPolyPatchField<Type>::New
                (
                    field.boundaryField()
                        [boundaryAddressing_[patchI]],
                    processorMesh_.boundary()[patchI],
                    DimensionedField<Type, tetPointMesh>::null(),
                    *patchFieldDecompPtrs_[patchI]
                )
            );
        }
        else
        {
            patchFields.set
            (
                patchI,
                new ProcessorPointPatchField
                <
                    tetPolyPatchField,
                    tetPointMesh,
                    tetPolyPatch,
                    processorTetPolyPatch,
                    tetFemMatrix,
                    Type
                >
                (
                    processorMesh_.boundary()[patchI],
                    DimensionedField<Type, tetPointMesh>::null()
                )
            );
        }
    }

    // Add the global patch by hand.  This needs to be present on
    // all processors
    patchFields.set
    (
        patchFields.size() - 1,
        new GlobalPointPatchField
        <
            tetPolyPatchField,
            tetPointMesh,
            tetPolyPatch,
            globalTetPolyPatch,
            tetFemMatrix,
            Type
        >
        (
            processorMesh_.boundary().globalPatch(),
            DimensionedField<Type, tetPointMesh>::null()
        )
    );

    // Create the field for the processor
    return tmp<GeometricField<Type, tetPolyPatchField, tetPointMesh> >
    (
        new GeometricField<Type, tetPolyPatchField, tetPointMesh>
        (
            IOobject
            (
                field.name(),
                processorMesh_().time().timeName(),
                processorMesh_(),
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            processorMesh_,
            field.dimensions(),
            internalField,
            patchFields
        )
    );
}
Ejemplo n.º 16
0
void ensightField
(
    const GeometricField<Type, fvPatchField, volMesh>& vf,
    const ensightMesh& eMesh,
    const fileName& postProcPath,
    const word& prepend,
    const label timeIndex,
    const bool binary,
    Ostream& ensightCaseFile
)
{
    Info<< "Converting field " << vf.name() << endl;

    word timeFile = prepend + itoa(timeIndex);

    const fvMesh& mesh = eMesh.mesh();
    const Time& runTime = mesh.time();

    const cellSets& meshCellSets = eMesh.meshCellSets();
    const List<faceSets>& boundaryFaceSets = eMesh.boundaryFaceSets();
    const wordList& allPatchNames = eMesh.allPatchNames();
    const wordHashSet& patchNames = eMesh.patchNames();
    const HashTable<ensightMesh::nFacePrimitives>&
        nPatchPrims = eMesh.nPatchPrims();
    const List<faceSets>& faceZoneFaceSets = eMesh.faceZoneFaceSets();
    const wordHashSet& faceZoneNames = eMesh.faceZoneNames();
    const HashTable<ensightMesh::nFacePrimitives>&
        nFaceZonePrims = eMesh.nFaceZonePrims();

    const labelList& tets = meshCellSets.tets;
    const labelList& pyrs = meshCellSets.pyrs;
    const labelList& prisms = meshCellSets.prisms;
    const labelList& wedges = meshCellSets.wedges;
    const labelList& hexes = meshCellSets.hexes;
    const labelList& polys = meshCellSets.polys;

    ensightStream* ensightFilePtr = NULL;
    if (Pstream::master())
    {
        // set the filename of the ensight file
        fileName ensightFileName(timeFile + "." + vf.name());

        if (binary)
        {
            ensightFilePtr = new ensightBinaryStream
            (
                postProcPath/ensightFileName,
                runTime
            );
        }
        else
        {
            ensightFilePtr = new ensightAsciiStream
            (
                postProcPath/ensightFileName,
                runTime
            );
        }
    }

    ensightStream& ensightFile = *ensightFilePtr;

    if (patchNames.empty())
    {
        eMesh.barrier();

        if (Pstream::master())
        {
            if (timeIndex == 0)
            {
                ensightCaseFile.setf(ios_base::left);

                ensightCaseFile
                    << pTraits<Type>::typeName
                    << " per element:            1       "
                    << setw(15) << vf.name()
                    << (' ' + prepend + "***." + vf.name()).c_str()
                    << nl;
            }

            ensightFile.write(pTraits<Type>::typeName);
            ensightFile.writePartHeader(1);
        }

        writeField
        (
            "hexa8",
            map(vf, hexes, wedges),
            ensightFile
        );

        writeField
        (
            "penta6",
            Field<Type>(vf, prisms),
            ensightFile
        );

        writeField
        (
            "pyramid5",
            Field<Type>(vf, pyrs),
            ensightFile
        );

        writeField
        (
            "tetra4",
            Field<Type>(vf, tets),
            ensightFile
        );

        writeField
        (
            "nfaced",
            Field<Type>(vf, polys),
            ensightFile
        );
    }

    label ensightPatchI = eMesh.patchPartOffset();

    forAll(allPatchNames, patchi)
    {
        const word& patchName = allPatchNames[patchi];

        eMesh.barrier();

        if (patchNames.empty() || patchNames.found(patchName))
        {
            if
            (
                writePatchField
                (
                    vf.boundaryField()[patchi],
                    patchi,
                    ensightPatchI,
                    boundaryFaceSets[patchi],
                    nPatchPrims.find(patchName)(),
                    ensightFile
                )
            )
            {
                ensightPatchI++;
            }
        }
    }

    // write faceZones, if requested
    if (faceZoneNames.size())
    {
        // Interpolates cell values to faces - needed only when exporting
        // faceZones...
        GeometricField<Type, fvsPatchField, surfaceMesh> sf
        (
            linearInterpolate(vf)
        );

        forAllConstIter(wordHashSet, faceZoneNames, iter)
        {
            const word& faceZoneName = iter.key();

            eMesh.barrier();

            label zoneID = mesh.faceZones().findZoneID(faceZoneName);

            const faceZone& fz = mesh.faceZones()[zoneID];

            // Prepare data to write
            label nIncluded = 0;
            forAll(fz, i)
            {
                if (eMesh.faceToBeIncluded(fz[i]))
                {
                    ++nIncluded;
                }
            }

            Field<Type> values(nIncluded);

            // Loop on the faceZone and store the needed field values
            label j = 0;
            forAll(fz, i)
            {
                label faceI = fz[i];
                if (mesh.isInternalFace(faceI))
                {
                    values[j] = sf[faceI];
                    ++j;
                }
                else
                {
                    if (eMesh.faceToBeIncluded(faceI))
                    {
                        label patchI = mesh.boundaryMesh().whichPatch(faceI);
                        const polyPatch& pp = mesh.boundaryMesh()[patchI];
                        label patchFaceI = pp.whichFace(faceI);
                        Type value = sf.boundaryField()[patchI][patchFaceI];
                        values[j] = value;
                        ++j;
                    }
                }
            }

            if
            (
                writePatchField
                (
                    values,
                    zoneID,
                    ensightPatchI,
                    faceZoneFaceSets[zoneID],
                    nFaceZonePrims.find(faceZoneName)(),
                    ensightFile
                )
            )
            {
                ensightPatchI++;
            }
        }
tmp<GeometricField<Type, fvPatchField, volMesh> > fvMeshSubset::interpolate
(
    const GeometricField<Type, fvPatchField, volMesh>& vf,
    const fvMesh& sMesh,
    const labelList& patchMap,
    const labelList& cellMap,
    const labelList& faceMap
)
{
    // 1. Create the complete field with dummy patch fields
    PtrList<fvPatchField<Type> > patchFields(patchMap.size());

    forAll(patchFields, patchI)
    {
        // Set the first one by hand as it corresponds to the
        // exposed internal faces. Additional interpolation can be put here
        // as necessary.
        if (patchMap[patchI] == -1)
        {
            patchFields.set
            (
                patchI,
                new emptyFvPatchField<Type>
                (
                    sMesh.boundary()[patchI],
                    DimensionedField<Type, volMesh>::null()
                )
            );
        }
        else
        {
            patchFields.set
            (
                patchI,
                fvPatchField<Type>::New
                (
                    calculatedFvPatchField<Type>::typeName,
                    sMesh.boundary()[patchI],
                    DimensionedField<Type, volMesh>::null()
                )
            );
        }
    }

    tmp<GeometricField<Type, fvPatchField, volMesh> > tresF
    (
        new GeometricField<Type, fvPatchField, volMesh>
        (
            IOobject
            (
                "subset"+vf.name(),
                sMesh.time().timeName(),
                sMesh,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            sMesh,
            vf.dimensions(),
            Field<Type>(vf.internalField(), cellMap),
            patchFields
        )
    );
    GeometricField<Type, fvPatchField, volMesh>& resF = tresF();


    // 2. Change the fvPatchFields to the correct type using a mapper
    //  constructor (with reference to the now correct internal field)

    typename GeometricField<Type, fvPatchField, volMesh>::
        GeometricBoundaryField& bf = resF.boundaryField();

    forAll(bf, patchI)
    {
        if (patchMap[patchI] != -1)
        {
            // Construct addressing
            const fvPatch& subPatch = sMesh.boundary()[patchI];
            const fvPatch& basePatch = vf.mesh().boundary()[patchMap[patchI]];
            const label baseStart = basePatch.start();
            const label baseSize = basePatch.size();

            labelList directAddressing(subPatch.size());

            forAll(directAddressing, i)
            {
                label baseFaceI = faceMap[subPatch.start()+i];

                if (baseFaceI >= baseStart && baseFaceI < baseStart+baseSize)
                {
                    directAddressing[i] = baseFaceI-baseStart;
                }
                else
                {
                    // Mapped from internal face. Do what? Leave up to
                    // fvPatchField
                    directAddressing[i] = -1;
                }
            }

            bf.set
            (
                patchI,
                fvPatchField<Type>::New
                (
                    vf.boundaryField()[patchMap[patchI]],
                    subPatch,
                    resF.dimensionedInternalField(),
                    directFvPatchFieldMapper(directAddressing)
                )
            );
        }
    }