const vectorField& localVertices = tlocalVertices();

    // Determine triangulation
    List<vector2D> localVertices2D(localVertices.size());
    forAll(localVertices, i)
    {
        localVertices2D[i][0] = localVertices[i][0];
        localVertices2D[i][1] = localVertices[i][1];
    }

    triSurface s(triSurfaceTools::delaunay2D(localVertices2D));

    tmp<pointField> localFaceCentres
    (
        referenceCS().localPosition
        (
            this->patch().patch().faceCentres()
        )
    );

    if (debug)
    {
        Pout<< "readSamplePoints :"
            <<" Dumping triangulated surface to triangulation.stl" << endl;
        s.write(this->db().time().path()/"triangulation.stl");

        OFstream str(this->db().time().path()/"localFaceCentres.obj");
        Pout<< "readSamplePoints :"
            << " Dumping face centres to " << str.name() << endl;

        forAll(localFaceCentres(), i)
        {
void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()
{
    // Read the sample points

    pointIOField samplePoints
    (
        IOobject
        (
            "points",
            this->db().time().constant(),
            "boundaryData"/this->patch().name(),
            this->db(),
            IOobject::MUST_READ,
            IOobject::AUTO_WRITE,
            false
        )
    );

    const fileName samplePointsFile = samplePoints.filePath();

    if (debug)
    {
        Info<< "timeVaryingMappedFixedValueFvPatchField :"
            << " Read " << samplePoints.size() << " sample points from "
            << samplePointsFile << endl;
    }

    // Determine coordinate system from samplePoints

    if (samplePoints.size() < 3)
    {
        FatalErrorIn
        (
            "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
        )   << "Only " << samplePoints.size() << " points read from file "
            << samplePoints.objectPath() << nl
            << "Need at least three non-colinear samplePoints"
            << " to be able to interpolate."
            << "\n    on patch " << this->patch().name()
            << " of field " << this->dimensionedInternalField().name()
            << " in file " << this->dimensionedInternalField().objectPath()
            << exit(FatalError);
    }

    const point& p0 = samplePoints[0];

    // Find point separate from p0
    vector e1;
    label index1 = -1;

    for (label i = 1; i < samplePoints.size(); i++)
    {
        e1 = samplePoints[i] - p0;

        scalar magE1 = mag(e1);

        if (magE1 > SMALL)
        {
            e1 /= magE1;
            index1 = i;
            break;
        }
    }

    // Find point that makes angle with n1
    label index2 = -1;
    vector e2;
    vector n;

    for (label i = index1+1; i < samplePoints.size(); i++)
    {
        e2 = samplePoints[i] - p0;

        scalar magE2 = mag(e2);

        if (magE2 > SMALL)
        {
            e2 /= magE2;

            n = e1^e2;

            scalar magN = mag(n);

            if (magN > SMALL)
            {
                index2 = i;
                n /= magN;
                break;
            }
        }
    }

    if (index2 == -1)
    {
        FatalErrorIn
        (
            "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
        )   << "Cannot find points that make valid normal." << nl
            << "Need at least three sample points which are not in a line."
            << "\n    on patch " << this->patch().name()
            << " of field " << this->dimensionedInternalField().name()
            << " in file " << this->dimensionedInternalField().objectPath()
            << exit(FatalError);
    }

    if (debug)
    {
        Info<< "timeVaryingMappedFixedValueFvPatchField :"
            << " Used points " << p0 << ' ' << samplePoints[index1]
            << ' ' << samplePoints[index2]
            << " to define coordinate system with normal " << n << endl;
    }

    referenceCS_.reset
    (
        new cartesianCS
        (
            "reference",
            p0,             // origin
            n,              // normal
            e1              // 0-axis
        )
    );

    tmp<vectorField> tlocalVertices
    (
        referenceCS().localPosition(samplePoints)
    );
    const vectorField& localVertices = tlocalVertices();

    // Determine triangulation
    List<vector2D> localVertices2D(localVertices.size());
    forAll(localVertices, i)
    {
        localVertices2D[i][0] = localVertices[i][0];
        localVertices2D[i][1] = localVertices[i][1];
    }
void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()
{
    // Read the sample points

    pointIOField samplePoints
    (
        IOobject
        (
            "points",
            this->db().time().constant(),
            "boundaryData"/this->patch().name(),
            this->db(),
            IOobject::MUST_READ,
            IOobject::AUTO_WRITE,
            false
        )
    );

    const fileName samplePointsFile = samplePoints.filePath();

    if (debug)
    {
        Info<< "timeVaryingMappedFixedValueFvPatchField :"
            << " Read " << samplePoints.size() << " sample points from "
            << samplePointsFile << endl;
    }

    // Determine coordinate system from samplePoints

    if (samplePoints.size() < 3)
    {
        FatalErrorIn
        (
            "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
        )   << "Only " << samplePoints.size() << " points read from file "
            << samplePoints.objectPath() << nl
            << "Need at least three non-colinear samplePoints"
            << " to be able to interpolate."
            << "\n    on patch " << this->patch().name()
            << " of points " << samplePoints.name()
            << " in file " << samplePoints.objectPath()
            << exit(FatalError);
    }

    const point& p0 = samplePoints[0];

    // Find furthest away point
    vector e1;
    label index1 = -1;
    scalar maxDist = -GREAT;

    for (label i = 1; i < samplePoints.size(); i++)
    {
        const vector d = samplePoints[i] - p0;
        scalar magD = mag(d);

        if (magD > maxDist)
        {
            e1 = d/magD;
            index1 = i;
            maxDist = magD;
        }
    }
    // Find point that is furthest away from line p0-p1
    const point& p1 = samplePoints[index1];

    label index2 = -1;
    maxDist = -GREAT;
    for (label i = 1; i < samplePoints.size(); i++)
    {
        if (i != index1)
        {
            const point& p2 = samplePoints[i];
            vector e2(p2 - p0);
            e2 -= (e2&e1)*e1;
            scalar magE2 = mag(e2);

            if (magE2 > maxDist)
            {
                index2 = i;
                maxDist = magE2;
            }
        }
    }
    if (index2 == -1)
    {
        FatalErrorIn
        (
            "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
        )   << "Cannot find points that make valid normal." << nl
            << "Have so far points " << p0 << " and " << p1
            << "Need at least three sample points which are not in a line."
            << "\n    on patch " << this->patch().name()
            << " of points " << samplePoints.name()
            << " in file " << samplePoints.objectPath()
            << exit(FatalError);
    }

    vector n = e1^(samplePoints[index2]-p0);
    n /= mag(n);

    if (debug)
    {
        Info<< "timeVaryingMappedFixedValueFvPatchField :"
            << " Used points " << p0 << ' ' << samplePoints[index1]
            << ' ' << samplePoints[index2]
            << " to define coordinate system with normal " << n << endl;
    }

    referenceCS_.reset
    (
        new coordinateSystem
        (
            "reference",
            p0,  // origin
            n,   // normal
            e1   // 0-axis
        )
    );

    tmp<vectorField> tlocalVertices
    (
        referenceCS().localPosition(samplePoints)
    );
    vectorField& localVertices = tlocalVertices();

    const boundBox bb(localVertices, true);
    const point bbMid(bb.midpoint());

    if (debug)
    {
        Info<< "timeVaryingMappedFixedValueFvPatchField :"
            << " Perturbing points with " << perturb_
            << " fraction of a random position inside " << bb
            << " to break any ties on regular meshes."
            << nl << endl;
    }

    Random rndGen(123456);
    forAll(localVertices, i)
    {
        localVertices[i] +=
            perturb_
           *(rndGen.position(bb.min(), bb.max())-bbMid);
    }