diff --git a/src/sampling/Make/files b/src/sampling/Make/files
index 5dc8a0ac8fb363f2bc107dd79e1608a2d3fbdd8e..747097a781c5c26d52c5ae82c95b484bed4cd0ae 100644
--- a/src/sampling/Make/files
+++ b/src/sampling/Make/files
@@ -59,5 +59,8 @@ $(meshToMesh)/meshToMesh.C
 $(meshToMesh)/calculateMeshToMeshAddressing.C
 $(meshToMesh)/calculateMeshToMeshWeights.C
 
+meshToMeshNew = meshToMeshInterpolation/meshToMeshNew
+$(meshToMeshNew)/meshToMeshNew.C
+$(meshToMeshNew)/meshToMeshNewParallelOps.C
 
 LIB = $(FOAM_LIBBIN)/libsampling
diff --git a/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.C b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.C
new file mode 100644
index 0000000000000000000000000000000000000000..b71e768f428c7dfea79b1dc15d3210009ef087ec
--- /dev/null
+++ b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.C
@@ -0,0 +1,955 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012-2013 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshToMeshNew.H"
+#include "OFstream.H"
+#include "Time.H"
+#include "globalIndex.H"
+#include "mergePoints.H"
+#include "treeBoundBox.H"
+#include "tetOverlapVolume.H"
+#include "indexedOctree.H"
+#include "treeDataCell.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(meshToMeshNew, 0);
+}
+
+Foam::scalar Foam::meshToMeshNew::tolerance_ = 1e-6;
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::meshToMeshNew::writeConnectivity
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const labelListList& srcToTargetAddr
+) const
+{
+    Pout<< "Source size = " << src.nCells() << endl;
+    Pout<< "Target size = " << tgt.nCells() << endl;
+
+    word fName("addressing_" + src.name() + "_to_" + tgt.name());
+
+    if (Pstream::parRun())
+    {
+        fName = fName +  "_proc" + Foam::name(Pstream::myProcNo());
+    }
+
+    OFstream os(src.time().path()/fName + ".obj");
+
+    label vertI = 0;
+    forAll(srcToTargetAddr, i)
+    {
+        const labelList& tgtAddress = srcToTargetAddr[i];
+        forAll(tgtAddress, j)
+        {
+            label tgtI = tgtAddress[j];
+            const vector& c0 = src.cellCentres()[i];
+
+            const cell& c = tgt.cells()[tgtI];
+            const pointField pts(c.points(tgt.faces(), tgt.points()));
+            forAll(pts, j)
+            {
+                const point& p = pts[j];
+                os  << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
+                vertI++;
+                os  << "v " << c0.x() << ' ' << c0.y() << ' ' << c0.z()
+                    << nl;
+                vertI++;
+                os  << "l " << vertI - 1 << ' ' << vertI << nl;
+            }
+        }
+    }
+}
+
+
+Foam::labelList Foam::meshToMeshNew::maskCells
+(
+    const polyMesh& src,
+    const polyMesh& tgt
+) const
+{
+    boundBox intersectBb
+    (
+        max(src.bounds().min(), tgt.bounds().min()),
+        min(src.bounds().max(), tgt.bounds().max())
+    );
+
+    intersectBb.inflate(0.01);
+
+    const cellList& srcCells = src.cells();
+    const faceList& srcFaces = src.faces();
+    const pointField& srcPts = src.points();
+
+    DynamicList<label> cells(src.size());
+    forAll(srcCells, srcI)
+    {
+        boundBox cellBb(srcCells[srcI].points(srcFaces, srcPts), false);
+        if (intersectBb.overlaps(cellBb))
+        {
+            cells.append(srcI);
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "participating source mesh cells: " << cells.size() << endl;
+    }
+
+    return cells;
+}
+
+
+bool Foam::meshToMeshNew::findInitialSeeds
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const labelList& srcCellIDs,
+    const boolList& mapFlag,
+    const label startSeedI,
+    label& srcSeedI,
+    label& tgtSeedI
+) const
+{
+    const cellList& srcCells = src.cells();
+    const faceList& srcFaces = src.faces();
+    const pointField& srcPts = src.points();
+
+    for (label i = startSeedI; i < srcCellIDs.size(); i++)
+    {
+        label srcI = srcCellIDs[i];
+
+        if (mapFlag[srcI])
+        {
+            const pointField
+                pts(srcCells[srcI].points(srcFaces, srcPts).xfer());
+
+            forAll(pts, ptI)
+            {
+                const point& pt = pts[ptI];
+                label tgtI = tgt.cellTree().findInside(pt);
+
+                if (tgtI != -1 && intersect(src, tgt, srcI, tgtI))
+                {
+                    srcSeedI = srcI;
+                    tgtSeedI = tgtI;
+
+                    return true;
+                }
+            }
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "could not find starting seed" << endl;
+    }
+
+    return false;
+}
+
+
+void Foam::meshToMeshNew::appendToDirectSeeds
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    boolList& mapFlag,
+    labelList& srcTgtSeed,
+    DynamicList<label>& srcSeeds,
+    label& srcSeedI,
+    label& tgtSeedI
+) const
+{
+    const labelList& srcNbr = src.cellCells()[srcSeedI];
+    const labelList& tgtNbr = tgt.cellCells()[tgtSeedI];
+
+    const vectorField& srcCentre = src.cellCentres();
+
+    forAll(srcNbr, i)
+    {
+        label srcI = srcNbr[i];
+
+        if (mapFlag[srcI] && (srcTgtSeed[srcI] == -1))
+        {
+            // source cell srcI not yet mapped
+
+            // identfy if target cell exists for source cell srcI
+            bool found = false;
+            forAll(tgtNbr, j)
+            {
+                label tgtI = tgtNbr[j];
+
+                if (tgt.pointInCell(srcCentre[srcI], tgtI))
+                {
+                    // new match - append to lists
+                    found = true;
+
+                    srcTgtSeed[srcI] = tgtI;
+                    srcSeeds.append(srcI);
+
+                    break;
+                }
+            }
+
+            if (!found)
+            {
+                // no match available for source cell srcI
+                mapFlag[srcI] = false;
+            }
+        }
+    }
+
+    if (srcSeeds.size())
+    {
+        srcSeedI = srcSeeds.remove();
+        tgtSeedI = srcTgtSeed[srcSeedI];
+    }
+    else
+    {
+        srcSeedI = -1;
+        tgtSeedI = -1;
+    }
+}
+
+
+void Foam::meshToMeshNew::calcDirect
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const label srcSeedI,
+    const label tgtSeedI
+)
+{
+    // store a list of src cells already mapped
+    boolList srcSeedFlag(src.nCells(), true);
+    labelList srcTgtSeed(src.nCells(), -1);
+
+    List<DynamicList<label> > srcToTgt(src.nCells());
+    List<DynamicList<label> > tgtToSrc(tgt.nCells());
+
+    DynamicList<label> srcSeeds;
+
+    const scalarField& srcVc = src.cellVolumes();
+
+    label srcCellI = srcSeedI;
+    label tgtCellI = tgtSeedI;
+
+    do
+    {
+        // store src/tgt cell pair
+        srcToTgt[srcCellI].append(tgtCellI);
+        tgtToSrc[tgtCellI].append(srcCellI);
+
+        // mark source cell srcSeedI as matched
+        srcSeedFlag[srcCellI] = false;
+
+        // accumulate intersection volume
+        V_ += srcVc[srcCellI];
+
+        // find new source seed cell
+        appendToDirectSeeds
+        (
+            src,
+            tgt,
+            srcSeedFlag,
+            srcTgtSeed,
+            srcSeeds,
+            srcCellI,
+            tgtCellI
+        );
+
+    }
+    while (srcCellI >= 0);
+
+    // transfer addressing into persistent storage
+    forAll(srcToTgtCellAddr_, i)
+    {
+        srcToTgtCellAddr_[i].transfer(srcToTgt[i]);
+        srcToTgtCellWght_[i] = scalarList(srcToTgtCellAddr_[i].size(), 1.0);
+    }
+
+    forAll(tgtToSrcCellAddr_, i)
+    {
+        tgtToSrcCellAddr_[i].transfer(tgtToSrc[i]);
+        tgtToSrcCellWght_[i] = scalarList(tgtToSrcCellAddr_[i].size(), 1.0);
+    }
+}
+
+
+void Foam::meshToMeshNew::normaliseWeights
+(
+    const word& descriptor,
+    const scalarField& cellVolumes,
+    const labelListList& addr,
+    scalarListList& wght
+) const
+{
+    const label nCell = returnReduce(wght.size(), sumOp<label>());
+
+    if (nCell > 0)
+    {
+        scalar minW = GREAT;
+        scalar maxW = -GREAT;
+
+        forAll(wght, cellI)
+        {
+            scalarList& w = wght[cellI];
+            scalar s = sum(w);
+            scalar Vc = cellVolumes[cellI];
+
+            forAll(w, i)
+            {
+                w[i] /= Vc;
+            }
+
+            minW = min(minW, s/Vc);
+            maxW = max(maxW, s/Vc);
+        }
+
+        Info<< type() << ": " << descriptor << " weights min/max = "
+            << returnReduce(minW, minOp<scalar>()) << ", "
+            << returnReduce(maxW, maxOp<scalar>()) << endl;
+    }
+}
+
+
+void Foam::meshToMeshNew::appendNbrTgtCells
+(
+    const label tgtCellI,
+    const polyMesh& tgt,
+    const DynamicList<label>& visitedTgtCells,
+    DynamicList<label>& nbrTgtCellIDs
+) const
+{
+    const labelList& nbrCells = tgt.cellCells()[tgtCellI];
+
+    // filter out cells already visited from cell neighbours
+    forAll(nbrCells, i)
+    {
+        label nbrCellI = nbrCells[i];
+
+        if
+        (
+            (findIndex(visitedTgtCells, nbrCellI) == -1)
+         && (findIndex(nbrTgtCellIDs, nbrCellI) == -1)
+        )
+        {
+            nbrTgtCellIDs.append(nbrCellI);
+        }
+    }
+}
+
+
+void Foam::meshToMeshNew::setNextCells
+(
+    label& startSeedI,
+    label& srcCellI,
+    label& tgtCellI,
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const labelList& srcCellIDs,
+    const boolList& mapFlag,
+    const DynamicList<label>& visitedCells,
+    labelList& seedCells
+) const
+{
+    const labelList& srcNbrCells = src.cellCells()[srcCellI];
+
+    // set possible seeds for later use by querying all src cell neighbours
+    // with all visited target cells
+    bool valuesSet = false;
+    forAll(srcNbrCells, i)
+    {
+        label cellS = srcNbrCells[i];
+
+        if (mapFlag[cellS] && seedCells[cellS] == -1)
+        {
+            forAll(visitedCells, j)
+            {
+                label cellT = visitedCells[j];
+
+                if (intersect(src, tgt, cellS, cellT))
+                {
+                    seedCells[cellS] = cellT;
+
+                    if (!valuesSet)
+                    {
+                        srcCellI = cellS;
+                        tgtCellI = cellT;
+                        valuesSet = true;
+                    }
+                }
+            }
+        }
+    }
+
+    // set next src and tgt cells if not set above
+    if (valuesSet)
+    {
+        return;
+    }
+    else
+    {
+        // try to use existing seed
+        bool foundNextSeed = false;
+        for (label i = startSeedI; i < srcCellIDs.size(); i++)
+        {
+            label cellS = srcCellIDs[i];
+
+            if (mapFlag[cellS])
+            {
+                if (!foundNextSeed)
+                {
+                    startSeedI = i;
+                    foundNextSeed = true;
+                }
+
+                if (seedCells[cellS] != -1)
+                {
+                    srcCellI = cellS;
+                    tgtCellI = seedCells[cellS];
+
+                    return;
+                }
+            }
+        }
+
+        // perform new search to find match
+        if (debug)
+        {
+            Pout<< "Advancing front stalled: searching for new "
+                << "target cell" << endl;
+        }
+
+        bool restart =
+            findInitialSeeds
+            (
+                src,
+                tgt,
+                srcCellIDs,
+                mapFlag,
+                startSeedI,
+                srcCellI,
+                tgtCellI
+            );
+
+        if (restart)
+        {
+            // successfully found new starting seed-pair
+            return;
+        }
+    }
+
+    // if we have got to here, there are no more src/tgt cell intersections
+    srcCellI = -1;
+    tgtCellI = -1;
+}
+
+
+bool Foam::meshToMeshNew::intersect
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const label srcCellI,
+    const label tgtCellI
+) const
+{
+    scalar threshold = tolerance_*src.cellVolumes()[srcCellI];
+
+    tetOverlapVolume overlapEngine;
+
+    treeBoundBox bbTgtCell
+    (
+        pointField
+        (
+            tgt.points(),
+            tgt.cellPoints()[tgtCellI]
+        )
+    );
+
+    return overlapEngine.cellCellOverlapMinDecomp
+    (
+        src,
+        srcCellI,
+        tgt,
+        tgtCellI,
+        bbTgtCell,
+        threshold
+    );
+}
+
+
+Foam::scalar Foam::meshToMeshNew::interVol
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const label srcCellI,
+    const label tgtCellI
+) const
+{
+    tetOverlapVolume overlapEngine;
+
+    treeBoundBox bbTgtCell
+    (
+        pointField
+        (
+            tgt.points(),
+            tgt.cellPoints()[tgtCellI]
+        )
+    );
+
+    scalar vol = overlapEngine.cellCellOverlapVolumeMinDecomp
+    (
+        src,
+        srcCellI,
+        tgt,
+        tgtCellI,
+        bbTgtCell
+    );
+
+    return vol;
+}
+
+
+void Foam::meshToMeshNew::calcIndirect
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const label srcSeedI,
+    const label tgtSeedI,
+    const labelList& srcCellIDs,
+    boolList& mapFlag,
+    label& startSeedI
+)
+{
+    label srcCellI = srcSeedI;
+    label tgtCellI = tgtSeedI;
+
+    List<DynamicList<label> > srcToTgtAddr(src.nCells());
+    List<DynamicList<scalar> > srcToTgtWght(src.nCells());
+
+    List<DynamicList<label> > tgtToSrcAddr(tgt.nCells());
+    List<DynamicList<scalar> > tgtToSrcWght(tgt.nCells());
+
+    // list of tgt cell neighbour cells
+    DynamicList<label> nbrTgtCells(10);
+
+    // list of tgt cells currently visited for srcCellI to avoid multiple hits
+    DynamicList<label> visitedTgtCells(10);
+
+    // list to keep track of tgt cells used to seed src cells
+    labelList seedCells(src.nCells(), -1);
+    seedCells[srcCellI] = tgtCellI;
+
+    const scalarField& srcVol = src.cellVolumes();
+
+    do
+    {
+        nbrTgtCells.clear();
+        visitedTgtCells.clear();
+
+        // append initial target cell and neighbours
+        nbrTgtCells.append(tgtCellI);
+        appendNbrTgtCells(tgtCellI, tgt, visitedTgtCells, nbrTgtCells);
+
+        do
+        {
+            tgtCellI = nbrTgtCells.remove();
+            visitedTgtCells.append(tgtCellI);
+
+            scalar vol = interVol(src, tgt, srcCellI, tgtCellI);
+
+            // accumulate addressing and weights for valid intersection
+            if (vol/srcVol[srcCellI] > tolerance_)
+            {
+                // store src/tgt cell pair
+                srcToTgtAddr[srcCellI].append(tgtCellI);
+                srcToTgtWght[srcCellI].append(vol);
+
+                tgtToSrcAddr[tgtCellI].append(srcCellI);
+                tgtToSrcWght[tgtCellI].append(vol);
+
+                appendNbrTgtCells(tgtCellI, tgt, visitedTgtCells, nbrTgtCells);
+
+                // accumulate intersection volume
+                V_ += vol;
+            }
+        }
+        while (!nbrTgtCells.empty());
+
+        mapFlag[srcCellI] = false;
+
+        // find new source seed cell
+        setNextCells
+        (
+            startSeedI,
+            srcCellI,
+            tgtCellI,
+            src,
+            tgt,
+            srcCellIDs,
+            mapFlag,
+            visitedTgtCells,
+            seedCells
+        );
+    }
+    while (srcCellI != -1);
+
+    // transfer addressing into persistent storage
+    forAll(srcToTgtCellAddr_, i)
+    {
+        srcToTgtCellAddr_[i].transfer(srcToTgtAddr[i]);
+        srcToTgtCellWght_[i].transfer(srcToTgtWght[i]);
+    }
+
+    forAll(tgtToSrcCellAddr_, i)
+    {
+        tgtToSrcCellAddr_[i].transfer(tgtToSrcAddr[i]);
+        tgtToSrcCellWght_[i].transfer(tgtToSrcWght[i]);
+    }
+}
+
+
+void Foam::meshToMeshNew::calcAddressing
+(
+    const polyMesh& src,
+    const polyMesh& tgt
+)
+{
+    srcToTgtCellAddr_.setSize(src.nCells());
+    srcToTgtCellWght_.setSize(src.nCells());
+
+    tgtToSrcCellAddr_.setSize(tgt.nCells());
+    tgtToSrcCellWght_.setSize(tgt.nCells());
+
+    if (!src.nCells() || !tgt.nCells())
+    {
+        if (debug)
+        {
+            Pout<< "mesh interpolation: cells not on processor: Source cells = "
+                << src.nCells() << ", target cells = " << tgt.nCells()
+                << endl;
+        }
+    }
+
+    if (!src.nCells())
+    {
+        return;
+    }
+    else if (!tgt.nCells())
+    {
+        if (debug)
+        {
+            Pout<< "mesh interpolation: hhave " << src.nCells() << " source "
+                << " cells but no target cells" << endl;
+        }
+
+        return;
+    }
+
+    // (potentially) participating source mesh cells
+    const labelList srcCellIDs = maskCells(src, tgt);
+
+    // list to keep track of whether src cell can be mapped
+    boolList mapFlag(src.nCells(), false);
+    UIndirectList<bool>(mapFlag, srcCellIDs) = true;
+
+    // find initial point in tgt mesh
+    label srcSeedI = -1;
+    label tgtSeedI = -1;
+    label startSeedI = 0;
+
+    bool startWalk =
+        findInitialSeeds
+        (
+            src,
+            tgt,
+            srcCellIDs,
+            mapFlag,
+            startSeedI,
+            srcSeedI,
+            tgtSeedI
+        );
+
+    if (!startWalk)
+    {
+        // if meshes are collocated, after inflating the source mesh bounding
+        // box tgt mesh cells may be transferred, but may still not overlap
+        // with the source mesh
+        return;
+    }
+
+
+    if (directMapping_)
+    {
+        calcDirect(src, tgt, srcSeedI, tgtSeedI);
+    }
+    else
+    {
+        calcIndirect
+        (
+            src,
+            tgt,
+            srcSeedI,
+            tgtSeedI,
+            srcCellIDs,
+            mapFlag,
+            startSeedI
+        );
+    }
+
+
+    if (debug)
+    {
+        writeConnectivity(src, tgt, srcToTgtCellAddr_);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshToMeshNew::meshToMeshNew
+(
+    const polyMesh& src,
+    const polyMesh& tgt,
+    const bool directMapping
+)
+:
+    srcRegionName_(src.name()),
+    tgtRegionName_(tgt.name()),
+    srcToTgtCellAddr_(),
+    tgtToSrcCellAddr_(),
+    srcToTgtCellWght_(),
+    tgtToSrcCellWght_(),
+    V_(0.0),
+    singleMeshProc_(-1),
+    srcMapPtr_(NULL),
+    tgtMapPtr_(NULL),
+    directMapping_(directMapping)
+{
+    Info<< "Creating mesh-to-mesh addressing for " << src.name()
+        << " and " << tgt.name() << " regions" << endl;
+
+    singleMeshProc_ = calcDistribution(src, tgt);
+
+    if (singleMeshProc_ == -1)
+    {
+        // create global indexing for src and tgt meshes
+        globalIndex globalSrcCells(src.nCells());
+        globalIndex globalTgtCells(tgt.nCells());
+
+        // Create processor map of overlapping cells. This map gets
+        // (possibly remote) cells from the tgt mesh such that they (together)
+        // cover all of the src mesh
+        autoPtr<mapDistribute> mapPtr = calcProcMap(src, tgt);
+        const mapDistribute& map = mapPtr();
+
+        pointField newTgtPoints;
+        faceList newTgtFaces;
+        labelList newTgtFaceOwners;
+        labelList newTgtFaceNeighbours;
+        labelList newTgtCellIDs;
+
+        distributeAndMergeCells
+        (
+            map,
+            tgt,
+            globalTgtCells,
+            newTgtPoints,
+            newTgtFaces,
+            newTgtFaceOwners,
+            newTgtFaceNeighbours,
+            newTgtCellIDs
+        );
+
+
+        // create a new target mesh
+        polyMesh newTgt
+        (
+            IOobject
+            (
+                "newTgt::" + Foam::name(Pstream::myProcNo()),
+                tgt.time().timeName(),
+                tgt.time(),
+                IOobject::NO_READ
+            ),
+            xferMove(newTgtPoints),
+            xferMove(newTgtFaces),
+            xferMove(newTgtFaceOwners),
+            xferMove(newTgtFaceNeighbours),
+            false                                   // no parallel comms
+        );
+
+        // create some dummy patch info
+        List<polyPatch*> patches(1);
+        patches[0] = new polyPatch
+        (
+            "defaultFaces",
+            newTgt.nFaces() - newTgt.nInternalFaces(),
+            newTgt.nInternalFaces(),
+            0,
+            newTgt.boundaryMesh(),
+            word::null
+        );
+
+        newTgt.addPatches(patches);
+
+        // force calculation of tet-base points used for point-in-cell
+        (void)newTgt.tetBasePtIs();
+
+        // force construction of cell tree
+//        (void)newTgt.cellTree();
+
+        if (debug)
+        {
+            Pout<< "Created newTgt mesh:" << nl
+                << " old cells = " << tgt.nCells()
+                << ", new cells = " << newTgt.nCells() << nl
+                << " old faces = " << tgt.nFaces()
+                << ", new faces = " << newTgt.nFaces() << endl;
+
+            if (debug > 1)
+            {
+                Pout<< "Writing newTgt mesh: " << newTgt.name() << endl;
+                newTgt.write();
+            }
+        }
+
+        calcAddressing(src, newTgt);
+
+        // per source cell the target cell address in newTgt mesh
+        forAll(srcToTgtCellAddr_, i)
+        {
+            labelList& addressing = srcToTgtCellAddr_[i];
+            forAll(addressing, addrI)
+            {
+                addressing[addrI] = newTgtCellIDs[addressing[addrI]];
+            }
+        }
+
+        // convert target addresses in newTgtMesh into global cell numbering
+        forAll(tgtToSrcCellAddr_, i)
+        {
+            labelList& addressing = tgtToSrcCellAddr_[i];
+            forAll(addressing, addrI)
+            {
+                addressing[addrI] = globalSrcCells.toGlobal(addressing[addrI]);
+            }
+        }
+
+        // set up as a reverse distribute
+        mapDistribute::distribute
+        (
+            Pstream::nonBlocking,
+            List<labelPair>(),
+            tgt.nCells(),
+            map.constructMap(),
+            map.subMap(),
+            tgtToSrcCellAddr_,
+            ListPlusEqOp<label>(),
+            labelList()
+        );
+
+        // set up as a reverse distribute
+        mapDistribute::distribute
+        (
+            Pstream::nonBlocking,
+            List<labelPair>(),
+            tgt.nCells(),
+            map.constructMap(),
+            map.subMap(),
+            tgtToSrcCellWght_,
+            ListPlusEqOp<scalar>(),
+            scalarList()
+        );
+
+        // weights normalisation
+        normaliseWeights
+        (
+            "source",
+            src.cellVolumes(),
+            srcToTgtCellAddr_,
+            srcToTgtCellWght_
+        );
+
+        normaliseWeights
+        (
+            "target",
+            tgt.cellVolumes(),
+            tgtToSrcCellAddr_,
+            tgtToSrcCellWght_
+        );
+
+        // cache maps and reset addresses
+        List<Map<label> > cMap;
+        srcMapPtr_.reset
+        (
+            new mapDistribute(globalSrcCells, tgtToSrcCellAddr_, cMap)
+        );
+        tgtMapPtr_.reset
+        (
+            new mapDistribute(globalTgtCells, srcToTgtCellAddr_, cMap)
+        );
+
+        // collect volume intersection contributions
+        reduce(V_, sumOp<scalar>());
+    }
+    else
+    {
+        calcAddressing(src, tgt);
+
+        normaliseWeights
+        (
+            "source",
+            src.cellVolumes(),
+            srcToTgtCellAddr_,
+            srcToTgtCellWght_
+        );
+
+        normaliseWeights
+        (
+            "target",
+            tgt.cellVolumes(),
+            tgtToSrcCellAddr_,
+            tgtToSrcCellWght_
+        );
+    }
+
+    Info<< "    Overlap volume: " << V_ << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::meshToMeshNew::~meshToMeshNew()
+{}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.H b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.H
new file mode 100644
index 0000000000000000000000000000000000000000..6b5211ef43da846289f3a274ff7e5bbc3f4e7ae8
--- /dev/null
+++ b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNew.H
@@ -0,0 +1,494 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012-2013 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::meshToMeshNew
+
+Description
+    Class to calculate the cell-addressing between two overlapping meshes
+
+SourceFiles
+    meshToMeshNew.C
+    meshToMeshNewTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef meshToMeshNew_H
+#define meshToMeshNew_H
+
+#include "polyMesh.H"
+#include "boundBox.H"
+#include "mapDistribute.H"
+#include "volFieldsFwd.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class meshToMeshNew Declaration
+\*---------------------------------------------------------------------------*/
+
+class meshToMeshNew
+{
+    // Private data
+
+        //- Name of source mesh region
+        const word srcRegionName_;
+
+        //- Name of target mesh region
+        const word tgtRegionName_;
+
+        //- Source to target cell addressing
+        labelListList srcToTgtCellAddr_;
+
+        //- Target to source cell addressing
+        labelListList tgtToSrcCellAddr_;
+
+        //- Source to target cell interplation weights
+        scalarListList srcToTgtCellWght_;
+
+        //- Target to source cell interpolation weights
+        scalarListList tgtToSrcCellWght_;
+
+        //- Cell total volume in overlap region [m3]
+        scalar V_;
+
+        //- Index of processor that holds all of both sides. -1 in all other
+        //  cases
+        label singleMeshProc_;
+
+        //- Source map pointer - parallel running only
+        autoPtr<mapDistribute> srcMapPtr_;
+
+        //- Target map pointer - parallel running only
+        autoPtr<mapDistribute> tgtMapPtr_;
+
+        //- Flag to indicate that direct (one-to-one) mapping should be applied
+        bool directMapping_;
+
+        //- Tolerance used in volume overlap calculations
+        static scalar tolerance_;
+
+
+    // Private Member Functions
+
+        //- Helper function to add a constant offset to a list
+        template<class Type>
+        void add(UList<Type>& fld, const label offset) const;
+
+        //- Write the connectivity (debugging)
+        void writeConnectivity
+        (
+            const polyMesh& src,
+            const polyMesh& tgt,
+            const labelListList& srcToTargetAddr
+        ) const;
+
+        //- Return src cell IDs for the overlap region
+        labelList maskCells(const polyMesh& src, const polyMesh& tgt) const;
+
+        //- Find indices of overlapping cells in src and tgt meshes - returns
+        //  true if found a matching pair
+        bool findInitialSeeds
+        (
+            const polyMesh& src,
+            const polyMesh& tgt,
+            const labelList& srcCellIDs,
+            const boolList& mapFlag,
+            const label startSeedI,
+            label& srcSeedI,
+            label& tgtSeedI
+        ) const;
+
+
+        // Direct (one-to-one) mapping
+
+            //- Append to list of src mesh seed indices
+            void appendToDirectSeeds
+            (
+                const polyMesh& src,
+                const polyMesh& tgt,
+                boolList& mapFlag,
+                labelList& srcTgtSeed,
+                DynamicList<label>& srcSeeds,
+                label& srcSeedI,
+                label& tgtSeedI
+            ) const;
+
+            //- Main driver routine for direct mapping
+            void calcDirect
+            (
+                const polyMesh& src,
+                const polyMesh& tgt,
+                const label srcSeedI,
+                const label tgtSeedI
+            );
+
+
+        // Indirect (non-conformal) mapping
+
+            //- Normalise the interpolation weights
+            void normaliseWeights
+            (
+                const word& descriptor,
+                const scalarField& cellVolumes,
+                const labelListList& addr,
+                scalarListList& wght
+            ) const;
+
+            //- Append target cell neihgbour cells to cellIDs list
+            void appendNbrTgtCells
+            (
+                const label tgtCellI,
+                const polyMesh& tgt,
+                const DynamicList<label>& visitedTgtCells,
+                DynamicList<label>& nbrTgtCellIDs
+            ) const;
+
+            //- Set the next cells in the advancing front algorithm
+            void setNextCells
+            (
+                label& startSeedI,
+                label& srcCellI,
+                label& tgtCellI,
+                const polyMesh& src,
+                const polyMesh& tgt,
+                const labelList& srcCellIDs,
+                const boolList& mapFlag,
+                const DynamicList<label>& visitedCells,
+                labelList& seedCells
+            ) const;
+
+            //- Return the true if cells intersect
+            bool intersect
+            (
+                const polyMesh& src,
+                const polyMesh& tgt,
+                const label srcCellI,
+                const label tgtCellI
+            ) const;
+
+            //- Return the intersection volume between two cells
+            scalar interVol
+            (
+                const polyMesh& src,
+                const polyMesh& tgt,
+                const label srcCellI,
+                const label tgtCellI
+            ) const;
+
+            //- Main driver routine for indirect mapping
+            void calcIndirect
+            (
+                const polyMesh& src,
+                const polyMesh& tgt,
+                const label srcSeedI,
+                const label tgtSeedI,
+                const labelList& srcCellIDs,
+                boolList& mapFlag,
+                label& startSeedI
+            );
+
+
+        //- Calculate the addressing between overalping regions of src and tgt
+        //  meshes - main driver function
+        void calcAddressing(const polyMesh& src, const polyMesh& tgt);
+
+
+        // Parallel operations
+
+            //- Determine whether the meshes are split across multiple pocessors
+            label calcDistribution
+            (
+                const polyMesh& src,
+                const polyMesh& tgt
+            ) const;
+
+            //- Determine which processor bounding-boxes overlap
+            label calcOverlappingProcs
+            (
+                const List<boundBox>& procBb,
+                const boundBox& bb,
+                boolList& overlaps
+            ) const;
+
+            //- Calculate the mapping between processors
+            autoPtr<mapDistribute> calcProcMap
+            (
+                const polyMesh& src,
+                const polyMesh& tgt
+            ) const;
+
+            //- Distribute mesh info from 'my' processor to others
+            void distributeCells
+            (
+                const mapDistribute& map,
+                const polyMesh& tgtMesh,
+                const globalIndex& globalI,
+                List<pointField>& points,
+                List<label>& nInternalFaces,
+                List<faceList>& faces,
+                List<labelList>& faceOwner,
+                List<labelList>& faceNeighbour,
+                List<labelList>& cellIDs,
+                List<labelList>& nbrProcIDs,
+                List<labelList>& procLocalFaceIDs
+            ) const;
+
+            //- Collect pieces of tgt mesh from other procssors and restructure
+            void distributeAndMergeCells
+            (
+                const mapDistribute& map,
+                const polyMesh& tgt,
+                const globalIndex& globalI,
+                pointField& tgtPoints,
+                faceList& tgtFaces,
+                labelList& tgtFaceOwners,
+                labelList& tgtFaceNeighbours,
+                labelList& tgtCellIDs
+            ) const;
+
+
+        //- Disallow default bitwise copy construct
+        meshToMeshNew(const meshToMeshNew&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const meshToMeshNew&);
+
+
+public:
+
+    //- Run-time type information
+    TypeName("meshToMeshNew");
+
+
+    //- Construct from source and target meshes
+    meshToMeshNew
+    (
+        const polyMesh& src,
+        const polyMesh& tgt,
+        const bool directMapping
+    );
+
+
+    //- Destructor
+    virtual ~meshToMeshNew();
+
+
+    // Member Functions
+
+        // Access
+
+            //- Return const access to the source to target cell addressing
+            inline const labelListList& srcToTgtCellAddr() const;
+
+            //- Return const access to the target to source cell addressing
+            inline const labelListList& tgtToSrcCellAddr() const;
+
+            //- Return const access to the source to target cell weights
+            inline const scalarListList& srcToTgtCellWght() const;
+
+            //- Return const access to the target to source cell weights
+            inline const scalarListList& tgtToSrcCellWght() const;
+
+            //- Return const access to the overlap volume
+            inline scalar V() const;
+
+
+        // Evaluation
+
+            // Source-to-target field mapping
+
+                //- Map field from src to tgt mesh with defined operation
+                //  Values passed in via 'result' are used to initialise the
+                //  return value
+                template<class Type, class CombineOp>
+                void mapSrcToTgt
+                (
+                    const UList<Type>& srcFld,
+                    const CombineOp& cop,
+                    List<Type>& result
+                ) const;
+
+                //- Return the src field mapped to the tgt mesh with a defined
+                //  operation.  Initial values of the result are set to zero
+                template<class Type, class CombineOp>
+                tmp<Field<Type> > mapSrcToTgt
+                (
+                    const Field<Type>& srcFld,
+                    const CombineOp& cop
+                ) const;
+
+                //- Convenience function to map a tmp field to the tgt mesh
+                //  with a defined operation
+                template<class Type, class CombineOp>
+                tmp<Field<Type> > mapSrcToTgt
+                (
+                    const tmp<Field<Type> >& tsrcFld,
+                    const CombineOp& cop
+                ) const;
+
+                //- Convenience function to map a field to the tgt mesh with a
+                //  default operation (plusEqOp)
+                template<class Type>
+                tmp<Field<Type> > mapSrcToTgt
+                (
+                    const Field<Type>& srcFld
+                ) const;
+
+                //- Convenience function to map a tmp field to the tgt mesh
+                //  with a default operation (plusEqOp)
+                template<class Type>
+                tmp<Field<Type> > mapSrcToTgt
+                (
+                    const tmp<Field<Type> >& tsrcFld
+                ) const;
+
+
+            // Target-to-source field mapping
+
+                //- Map field from tgt to src mesh with defined operation
+                //  Values passed in via 'result' are used to initialise the
+                //  return value
+                template<class Type, class CombineOp>
+                void mapTgtToSrc
+                (
+                    const UList<Type>& tgtFld,
+                    const CombineOp& cop,
+                    List<Type>& result
+                ) const;
+
+                //- Return the tgt field mapped to the src mesh with a defined
+                //  operation.  Initial values of the result are set to zero
+                template<class Type, class CombineOp>
+                tmp<Field<Type> > mapTgtToSrc
+                (
+                    const Field<Type>& tgtFld,
+                    const CombineOp& cop
+                ) const;
+
+                //- Convenience function to map a tmp field to the src mesh
+                //  with a defined operation
+                template<class Type, class CombineOp>
+                tmp<Field<Type> > mapTgtToSrc
+                (
+                    const tmp<Field<Type> >& ttgtFld,
+                    const CombineOp& cop
+                ) const;
+
+                //- Convenience function to map a field to the src mesh with a
+                //  default operation (plusEqOp)
+                template<class Type>
+                tmp<Field<Type> > mapTgtToSrc
+                (
+                    const Field<Type>& tgtFld
+                ) const;
+
+                //- Convenience function to map a tmp field to the src mesh
+                //  with a default operation (plusEqOp)
+                template<class Type>
+                tmp<Field<Type> > mapTgtToSrc
+                (
+                    const tmp<Field<Type> >& ttgtFld
+                ) const;
+
+
+            // Volume field mapping
+
+                //- Interpolare a field with a defined operation.  Values
+                //  passed in via 'result' are used to initialise the return
+                //  value.  Optionally interpolate patch values
+                template<class Type, class CombineOp>
+                void interpolate
+                (
+                    const GeometricField<Type, fvPatchField, volMesh>& field,
+                    const CombineOp& cop,
+                    GeometricField<Type, fvPatchField, volMesh>& result,
+                    const bool interpPatches = true
+                ) const;
+
+                //- Interpolare a field with a defined operation.  The initial
+                //  values of the result are set to zero.  Optionally
+                //  interpolate patch values
+                template<class Type, class CombineOp>
+                tmp<GeometricField<Type, fvPatchField, volMesh> > interpolate
+                (
+                    const GeometricField<Type, fvPatchField, volMesh>& field,
+                    const CombineOp& cop,
+                    const bool interpPatches = true
+                ) const;
+
+                //- Interpolare a tmp field with a defined operation.  The
+                //  initial values of the result are set to zero.  Optionally
+                //  interpolate patch values
+                template<class Type, class CombineOp>
+                tmp<GeometricField<Type, fvPatchField, volMesh> > interpolate
+                (
+                    const tmp<GeometricField<Type, fvPatchField, volMesh> >&
+                        tfield,
+                    const CombineOp& cop,
+                    const bool interpPatches = true
+                ) const;
+
+                //- Convenience function to map a field with a default
+                //  operation (plusEqOp).  Optionally interpolate patch values
+                template<class Type>
+                tmp<GeometricField<Type, fvPatchField, volMesh> > interpolate
+                (
+                    const GeometricField<Type, fvPatchField, volMesh>& field,
+                    const bool interpPatches = true
+                ) const;
+
+                //- Convenience function to map a tmp field with a default
+                //  operation (plusEqOp).  Optionally interpolate patch values
+                template<class Type>
+                tmp<GeometricField<Type, fvPatchField, volMesh> > interpolate
+                (
+                    const tmp<GeometricField<Type, fvPatchField, volMesh> >&
+                        tfield,
+                    const bool interpPatches = true
+                ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "meshToMeshNewI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "meshToMeshNewTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewI.H b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewI.H
new file mode 100644
index 0000000000000000000000000000000000000000..41068e8c455e4e9f5b8d7737acc2fde589df618c
--- /dev/null
+++ b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewI.H
@@ -0,0 +1,64 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012-2013 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshToMeshNew.H"
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+inline const Foam::labelListList&
+Foam::meshToMeshNew::srcToTgtCellAddr() const
+{
+    return srcToTgtCellAddr_;
+}
+
+
+inline const Foam::labelListList&
+Foam::meshToMeshNew::tgtToSrcCellAddr() const
+{
+    return tgtToSrcCellAddr_;
+}
+
+
+inline const Foam::scalarListList&
+Foam::meshToMeshNew::srcToTgtCellWght() const
+{
+    return srcToTgtCellWght_;
+}
+
+
+inline const Foam::scalarListList&
+Foam::meshToMeshNew::tgtToSrcCellWght() const
+{
+    return tgtToSrcCellWght_;
+}
+
+
+inline Foam::scalar Foam::meshToMeshNew::V() const
+{
+    return V_;
+}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewParallelOps.C b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewParallelOps.C
new file mode 100644
index 0000000000000000000000000000000000000000..3cb9d0597d84988b6550b8589f1dde97d94e485a
--- /dev/null
+++ b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewParallelOps.C
@@ -0,0 +1,884 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012-2013 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshToMeshNew.H"
+#include "OFstream.H"
+#include "Time.H"
+#include "globalIndex.H"
+#include "mergePoints.H"
+#include "processorPolyPatch.H"
+#include "SubField.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::meshToMeshNew::calcDistribution
+(
+    const polyMesh& src,
+    const polyMesh& tgt
+) const
+{
+    label procI = 0;
+
+    if (Pstream::parRun())
+    {
+        List<label> cellsPresentOnProc(Pstream::nProcs(), 0);
+        if ((src.nCells() > 0) || (tgt.nCells() > 0))
+        {
+            cellsPresentOnProc[Pstream::myProcNo()] = 1;
+        }
+        else
+        {
+            cellsPresentOnProc[Pstream::myProcNo()] = 0;
+        }
+
+        Pstream::gatherList(cellsPresentOnProc);
+        Pstream::scatterList(cellsPresentOnProc);
+
+        label nHaveCells = sum(cellsPresentOnProc);
+
+        if (nHaveCells > 1)
+        {
+            procI = -1;
+            if (debug)
+            {
+                Info<< "meshToMeshNew::calcDistribution: "
+                    << "Meshes split across multiple processors" << endl;
+            }
+        }
+        else if (nHaveCells == 1)
+        {
+            procI = findIndex(cellsPresentOnProc, 1);
+            if (debug)
+            {
+                Info<< "meshToMeshNew::calcDistribution: "
+                    << "Meshes local to processor" << procI << endl;
+            }
+        }
+    }
+
+    return procI;
+}
+
+
+Foam::label Foam::meshToMeshNew::calcOverlappingProcs
+(
+    const List<boundBox>& procBb,
+    const boundBox& bb,
+    boolList& overlaps
+) const
+{
+    overlaps = false;
+
+    label nOverlaps = 0;
+
+    forAll(procBb, procI)
+    {
+        const boundBox& bbp = procBb[procI];
+
+        if (bbp.overlaps(bb))
+        {
+            overlaps[procI] = true;
+            nOverlaps++;
+        }
+    }
+
+    return nOverlaps;
+}
+
+
+Foam::autoPtr<Foam::mapDistribute> Foam::meshToMeshNew::calcProcMap
+(
+    const polyMesh& src,
+    const polyMesh& tgt
+) const
+{
+    // get decomposition of cells on src mesh
+    List<boundBox> procBb(Pstream::nProcs());
+
+    if (src.nCells() > 0)
+    {
+        // bounding box for my mesh - do not parallel reduce
+        procBb[Pstream::myProcNo()] = boundBox(src.points(), false);
+
+        // slightly increase size of bounding boxes to allow for cases where
+        // bounding boxes are perfectly alligned
+        procBb[Pstream::myProcNo()].inflate(0.01);
+    }
+    else
+    {
+        procBb[Pstream::myProcNo()] = boundBox();
+    }
+
+
+    Pstream::gatherList(procBb);
+    Pstream::scatterList(procBb);
+
+
+    if (debug)
+    {
+        Info<< "Determining extent of src mesh per processor:" << nl
+            << "\tproc\tbb" << endl;
+        forAll(procBb, procI)
+        {
+            Info<< '\t' << procI << '\t' << procBb[procI] << endl;
+        }
+    }
+
+
+    // determine which cells of tgt mesh overlaps src mesh per proc
+    const cellList& cells = tgt.cells();
+    const faceList& faces = tgt.faces();
+    const pointField& points = tgt.points();
+
+    labelListList sendMap;
+
+    {
+        // per processor indices into all segments to send
+        List<DynamicList<label> > dynSendMap(Pstream::nProcs());
+        label iniSize = floor(tgt.nCells()/Pstream::nProcs());
+
+        forAll(dynSendMap, procI)
+        {
+            dynSendMap[procI].setCapacity(iniSize);
+        }
+
+        // work array - whether src processor bb overlaps the tgt cell bounds
+        boolList procBbOverlaps(Pstream::nProcs());
+        forAll(cells, cellI)
+        {
+            const cell& c = cells[cellI];
+
+            // determine bounding box of tgt cell
+            boundBox cellBb(point::max, point::min);
+            forAll(c, faceI)
+            {
+                const face& f = faces[c[faceI]];
+                forAll(f, fp)
+                {
+                    cellBb.min() = min(cellBb.min(), points[f[fp]]);
+                    cellBb.max() = max(cellBb.max(), points[f[fp]]);
+                }
+            }
+
+            // find the overlapping tgt cells on each src processor
+            (void)calcOverlappingProcs(procBb, cellBb, procBbOverlaps);
+
+            forAll(procBbOverlaps, procI)
+            {
+                if (procBbOverlaps[procI])
+                {
+                    dynSendMap[procI].append(cellI);
+                }
+            }
+        }
+
+        // convert dynamicList to labelList
+        sendMap.setSize(Pstream::nProcs());
+        forAll(sendMap, procI)
+        {
+            sendMap[procI].transfer(dynSendMap[procI]);
+        }
+    }
+
+    // debug printing
+    if (debug)
+    {
+        Pout<< "Of my " << cells.size() << " target cells I need to send to:"
+            << nl << "\tproc\tcells" << endl;
+        forAll(sendMap, procI)
+        {
+            Pout<< '\t' << procI << '\t' << sendMap[procI].size() << endl;
+        }
+    }
+
+
+    // send over how many tgt cells I need to receive from each processor
+    labelListList sendSizes(Pstream::nProcs());
+    sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
+    forAll(sendMap, procI)
+    {
+        sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
+    }
+    Pstream::gatherList(sendSizes);
+    Pstream::scatterList(sendSizes);
+
+
+    // determine order of receiving
+    labelListList constructMap(Pstream::nProcs());
+
+    label segmentI = 0;
+    forAll(constructMap, procI)
+    {
+        // what I need to receive is what other processor is sending to me
+        label nRecv = sendSizes[procI][Pstream::myProcNo()];
+        constructMap[procI].setSize(nRecv);
+
+        for (label i = 0; i < nRecv; i++)
+        {
+            constructMap[procI][i] = segmentI++;
+        }
+    }
+
+    autoPtr<mapDistribute> mapPtr
+    (
+        new mapDistribute
+        (
+            segmentI,       // size after construction
+            sendMap.xfer(),
+            constructMap.xfer()
+        )
+    );
+
+    return mapPtr;
+}
+
+
+void Foam::meshToMeshNew::distributeCells
+(
+    const mapDistribute& map,
+    const polyMesh& tgtMesh,
+    const globalIndex& globalI,
+    List<pointField>& points,
+    List<label>& nInternalFaces,
+    List<faceList>& faces,
+    List<labelList>& faceOwner,
+    List<labelList>& faceNeighbour,
+    List<labelList>& cellIDs,
+    List<labelList>& nbrProcIDs,
+    List<labelList>& procLocalFaceIDs
+) const
+{
+    PstreamBuffers pBufs(Pstream::nonBlocking);
+
+    points.setSize(Pstream::nProcs());
+    nInternalFaces.setSize(Pstream::nProcs(), 0);
+    faces.setSize(Pstream::nProcs());
+    faceOwner.setSize(Pstream::nProcs());
+    faceNeighbour.setSize(Pstream::nProcs());
+    cellIDs.setSize(Pstream::nProcs());
+
+    nbrProcIDs.setSize(Pstream::nProcs());;
+    procLocalFaceIDs.setSize(Pstream::nProcs());;
+
+
+    for (label domain = 0; domain < Pstream::nProcs(); domain++)
+    {
+        const labelList& sendElems = map.subMap()[domain];
+
+        if (sendElems.size())
+        {
+            // reverse cell map
+            labelList reverseCellMap(tgtMesh.nCells(), -1);
+            forAll(sendElems, subCellI)
+            {
+                reverseCellMap[sendElems[subCellI]] = subCellI;
+            }
+
+            DynamicList<face> subFaces(tgtMesh.nFaces());
+            DynamicList<label> subFaceOwner(tgtMesh.nFaces());
+            DynamicList<label> subFaceNeighbour(tgtMesh.nFaces());
+
+            DynamicList<label> subNbrProcIDs(tgtMesh.nFaces());
+            DynamicList<label> subProcLocalFaceIDs(tgtMesh.nFaces());
+
+            label nInternal = 0;
+
+            // internal faces
+            forAll(tgtMesh.faceNeighbour(), faceI)
+            {
+                label own = tgtMesh.faceOwner()[faceI];
+                label nbr = tgtMesh.faceNeighbour()[faceI];
+                label subOwn = reverseCellMap[own];
+                label subNbr = reverseCellMap[nbr];
+
+                if (subOwn != -1 && subNbr != -1)
+                {
+                    nInternal++;
+
+                    if (subOwn < subNbr)
+                    {
+                        subFaces.append(tgtMesh.faces()[faceI]);
+                        subFaceOwner.append(subOwn);
+                        subFaceNeighbour.append(subNbr);
+                        subNbrProcIDs.append(-1);
+                        subProcLocalFaceIDs.append(-1);
+                    }
+                    else
+                    {
+                        subFaces.append(tgtMesh.faces()[faceI].reverseFace());
+                        subFaceOwner.append(subNbr);
+                        subFaceNeighbour.append(subOwn);
+                        subNbrProcIDs.append(-1);
+                        subProcLocalFaceIDs.append(-1);
+                    }
+                }
+            }
+
+            // boundary faces for new region
+            forAll(tgtMesh.faceNeighbour(), faceI)
+            {
+                label own = tgtMesh.faceOwner()[faceI];
+                label nbr = tgtMesh.faceNeighbour()[faceI];
+                label subOwn = reverseCellMap[own];
+                label subNbr = reverseCellMap[nbr];
+
+                if (subOwn != -1 && subNbr == -1)
+                {
+                    subFaces.append(tgtMesh.faces()[faceI]);
+                    subFaceOwner.append(subOwn);
+                    subFaceNeighbour.append(subNbr);
+                    subNbrProcIDs.append(-1);
+                    subProcLocalFaceIDs.append(-1);
+                }
+                else if (subOwn == -1 && subNbr != -1)
+                {
+                    subFaces.append(tgtMesh.faces()[faceI].reverseFace());
+                    subFaceOwner.append(subNbr);
+                    subFaceNeighbour.append(subOwn);
+                    subNbrProcIDs.append(-1);
+                    subProcLocalFaceIDs.append(-1);
+                }
+            }
+
+            // boundary faces of existing region
+            forAll(tgtMesh.boundaryMesh(), patchI)
+            {
+                const polyPatch& pp = tgtMesh.boundaryMesh()[patchI];
+
+                label nbrProcI = -1;
+
+                // store info for faces on processor patches
+                if (isA<processorPolyPatch>(pp))
+                {
+                    const processorPolyPatch& ppp =
+                        dynamic_cast<const processorPolyPatch&>(pp);
+
+                    nbrProcI = ppp.neighbProcNo();
+                }
+
+                forAll(pp, i)
+                {
+                    label faceI = pp.start() + i;
+                    label own = tgtMesh.faceOwner()[faceI];
+
+                    if (reverseCellMap[own] != -1)
+                    {
+                        subFaces.append(tgtMesh.faces()[faceI]);
+                        subFaceOwner.append(reverseCellMap[own]);
+                        subFaceNeighbour.append(-1);
+                        subNbrProcIDs.append(nbrProcI);
+                        subProcLocalFaceIDs.append(i);
+                    }
+                }
+            }
+
+            // reverse point map
+            labelList reversePointMap(tgtMesh.nPoints(), -1);
+            DynamicList<point> subPoints(tgtMesh.nPoints());
+            forAll(subFaces, subFaceI)
+            {
+                face& f = subFaces[subFaceI];
+                forAll(f, fp)
+                {
+                    label pointI = f[fp];
+                    if (reversePointMap[pointI] == -1)
+                    {
+                        reversePointMap[pointI] = subPoints.size();
+                        subPoints.append(tgtMesh.points()[pointI]);
+                    }
+
+                    f[fp] = reversePointMap[pointI];
+                }
+            }
+
+            // tgt cells into global numbering
+            labelList globalElems(sendElems.size());
+            forAll(sendElems, i)
+            {
+                if (debug)
+                {
+                    Pout<< "tgtProc:" << Pstream::myProcNo()
+                        << " sending tgt cell " << sendElems[i]
+                        << "[" << globalI.toGlobal(sendElems[i]) << "]"
+                        << " to srcProc " << domain << endl;
+                }
+
+                globalElems[i] = globalI.toGlobal(sendElems[i]);
+            }
+
+            // pass data
+            if (domain == Pstream::myProcNo())
+            {
+                // allocate my own data
+                points[Pstream::myProcNo()] = subPoints;
+                nInternalFaces[Pstream::myProcNo()] = nInternal;
+                faces[Pstream::myProcNo()] = subFaces;
+                faceOwner[Pstream::myProcNo()] = subFaceOwner;
+                faceNeighbour[Pstream::myProcNo()] = subFaceNeighbour;
+                cellIDs[Pstream::myProcNo()] = globalElems;
+                nbrProcIDs[Pstream::myProcNo()] = subNbrProcIDs;
+                procLocalFaceIDs[Pstream::myProcNo()] = subProcLocalFaceIDs;
+            }
+            else
+            {
+                // send data to other processor domains
+                UOPstream toDomain(domain, pBufs);
+
+                toDomain
+                    << subPoints
+                    << nInternal
+                    << subFaces
+                    << subFaceOwner
+                    << subFaceNeighbour
+                    << globalElems
+                    << subNbrProcIDs
+                    << subProcLocalFaceIDs;
+            }
+        }
+    }
+
+    // Start receiving
+    pBufs.finishedSends();
+
+    // Consume
+    for (label domain = 0; domain < Pstream::nProcs(); domain++)
+    {
+        const labelList& recvElems = map.constructMap()[domain];
+
+        if (domain != Pstream::myProcNo() && recvElems.size())
+        {
+            UIPstream str(domain, pBufs);
+
+            str >> points[domain]
+                >> nInternalFaces[domain]
+                >> faces[domain]
+                >> faceOwner[domain]
+                >> faceNeighbour[domain]
+                >> cellIDs[domain]
+                >> nbrProcIDs[domain]
+                >> procLocalFaceIDs[domain];
+        }
+
+        if (debug)
+        {
+            Pout<< "Target mesh send sizes[" << domain << "]"
+                << ": points="<< points[domain].size()
+                << ", faces=" << faces[domain].size()
+                << ", nInternalFaces=" << nInternalFaces[domain]
+                << ", faceOwn=" << faceOwner[domain].size()
+                << ", faceNbr=" << faceNeighbour[domain].size()
+                << ", cellIDs=" << cellIDs[domain].size() << endl;
+        }
+    }
+}
+
+
+void Foam::meshToMeshNew::distributeAndMergeCells
+(
+    const mapDistribute& map,
+    const polyMesh& tgt,
+    const globalIndex& globalI,
+    pointField& tgtPoints,
+    faceList& tgtFaces,
+    labelList& tgtFaceOwners,
+    labelList& tgtFaceNeighbours,
+    labelList& tgtCellIDs
+) const
+{
+    // Exchange per-processor data
+    List<pointField> allPoints;
+    List<label> allNInternalFaces;
+    List<faceList> allFaces;
+    List<labelList> allFaceOwners;
+    List<labelList> allFaceNeighbours;
+    List<labelList> allTgtCellIDs;
+
+    // Per target mesh face the neighbouring proc and index in
+    // processor patch (all -1 for normal boundary face)
+    List<labelList> allNbrProcIDs;
+    List<labelList> allProcLocalFaceIDs;
+
+    distributeCells
+    (
+        map,
+        tgt,
+        globalI,
+        allPoints,
+        allNInternalFaces,
+        allFaces,
+        allFaceOwners,
+        allFaceNeighbours,
+        allTgtCellIDs,
+        allNbrProcIDs,
+        allProcLocalFaceIDs
+    );
+
+    // Convert lists into format that can be used to generate a valid polyMesh
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    //
+    // Points and cells are collected into single flat lists:
+    // - i.e. proc0, proc1 ... procN
+    //
+    // Faces need to be sorted after collection to that internal faces are
+    // contiguous, followed by all boundary faces
+    //
+    // Processor patch faces between included cells on neighbouring processors
+    // are converted into internal faces
+    //
+    // Face list structure:
+    // - Per processor:
+    //   - internal faces
+    //   - processor faces that have been converted into internal faces
+    // - Followed by all boundary faces
+    //   - from 'normal' boundary faces
+    //   - from singularly-sided processor patch faces
+
+
+    // Number of internal+coupled faces
+    labelList allNIntCoupledFaces(allNInternalFaces);
+
+    // Starting offset for points
+    label nPoints = 0;
+    labelList pointOffset(Pstream::nProcs(), 0);
+    forAll(allPoints, procI)
+    {
+        pointOffset[procI] = nPoints;
+        nPoints += allPoints[procI].size();
+    }
+
+    // Starting offset for cells
+    label nCells = 0;
+    labelList cellOffset(Pstream::nProcs(), 0);
+    forAll(allTgtCellIDs, procI)
+    {
+        cellOffset[procI] = nCells;
+        nCells += allTgtCellIDs[procI].size();
+    }
+
+    // Count any coupled faces
+    typedef FixedList<label, 3> label3;
+    typedef HashTable<label, label3, label3::Hash<> > procCoupleInfo;
+    procCoupleInfo procFaceToGlobalCell;
+
+    forAll(allNbrProcIDs, procI)
+    {
+        const labelList& nbrProcI = allNbrProcIDs[procI];
+        const labelList& localFaceI = allProcLocalFaceIDs[procI];
+
+        forAll(nbrProcI, i)
+        {
+            if (nbrProcI[i] != -1 && localFaceI[i] != -1)
+            {
+                label3 key;
+                key[0] = min(procI, nbrProcI[i]);
+                key[1] = max(procI, nbrProcI[i]);
+                key[2] = localFaceI[i];
+
+                procCoupleInfo::const_iterator fnd =
+                    procFaceToGlobalCell.find(key);
+
+                if (fnd == procFaceToGlobalCell.end())
+                {
+                    procFaceToGlobalCell.insert(key, -1);
+                }
+                else
+                {
+                    if (debug)
+                    {
+                        Pout<< "Additional internal face between procs:"
+                            << key[0] << " and " << key[1]
+                            << " across local face " << key[2] << endl;
+                    }
+
+                    allNIntCoupledFaces[procI]++;
+                }
+            }
+        }
+    }
+
+
+    // Starting offset for internal faces
+    label nIntFaces = 0;
+    label nFacesTotal = 0;
+    labelList internalFaceOffset(Pstream::nProcs(), 0);
+    forAll(allNIntCoupledFaces, procI)
+    {
+        label nCoupledFaces =
+            allNIntCoupledFaces[procI] - allNInternalFaces[procI];
+
+        internalFaceOffset[procI] = nIntFaces;
+        nIntFaces += allNIntCoupledFaces[procI];
+        nFacesTotal += allFaceOwners[procI].size() - nCoupledFaces;
+    }
+
+    tgtPoints.setSize(nPoints);
+    tgtFaces.setSize(nFacesTotal);
+    tgtFaceOwners.setSize(nFacesTotal);
+    tgtFaceNeighbours.setSize(nFacesTotal);
+    tgtCellIDs.setSize(nCells);
+
+    // Insert points
+    forAll(allPoints, procI)
+    {
+        const pointField& pts = allPoints[procI];
+        SubList<point>(tgtPoints, pts.size(), pointOffset[procI]).assign(pts);
+    }
+
+    // Insert cellIDs
+    forAll(allTgtCellIDs, procI)
+    {
+        const labelList& cellIDs = allTgtCellIDs[procI];
+        SubList<label>(tgtCellIDs, cellIDs.size(), cellOffset[procI]).assign
+        (
+            cellIDs
+        );
+    }
+
+
+    // Insert internal faces (from internal faces)
+    forAll(allFaces, procI)
+    {
+        const faceList& fcs = allFaces[procI];
+        const labelList& faceOs = allFaceOwners[procI];
+        const labelList& faceNs = allFaceNeighbours[procI];
+
+        SubList<face> slice
+        (
+            tgtFaces,
+            allNInternalFaces[procI],
+            internalFaceOffset[procI]
+        );
+        slice.assign(SubList<face>(fcs, allNInternalFaces[procI]));
+        forAll(slice, i)
+        {
+            add(slice[i], pointOffset[procI]);
+        }
+
+        SubField<label> ownSlice
+        (
+            tgtFaceOwners,
+            allNInternalFaces[procI],
+            internalFaceOffset[procI]
+        );
+        ownSlice.assign(SubField<label>(faceOs, allNInternalFaces[procI]));
+        add(ownSlice, cellOffset[procI]);
+
+        SubField<label> nbrSlice
+        (
+            tgtFaceNeighbours,
+            allNInternalFaces[procI],
+            internalFaceOffset[procI]
+        );
+        nbrSlice.assign(SubField<label>(faceNs, allNInternalFaces[procI]));
+        add(nbrSlice, cellOffset[procI]);
+
+        internalFaceOffset[procI] += allNInternalFaces[procI];
+    }
+
+
+    // Insert internal faces (from coupled face-pairs)
+    forAll(allNbrProcIDs, procI)
+    {
+        const labelList& nbrProcI = allNbrProcIDs[procI];
+        const labelList& localFaceI = allProcLocalFaceIDs[procI];
+        const labelList& faceOs = allFaceOwners[procI];
+        const faceList& fcs = allFaces[procI];
+
+        forAll(nbrProcI, i)
+        {
+            if (nbrProcI[i] != -1 && localFaceI[i] != -1)
+            {
+                label3 key;
+                key[0] = min(procI, nbrProcI[i]);
+                key[1] = max(procI, nbrProcI[i]);
+                key[2] = localFaceI[i];
+
+                procCoupleInfo::iterator fnd = procFaceToGlobalCell.find(key);
+
+                if (fnd != procFaceToGlobalCell.end())
+                {
+                    label tgtFaceI = fnd();
+                    if (tgtFaceI == -1)
+                    {
+                        // on first visit store the new cell on this side
+                        fnd() = cellOffset[procI] + faceOs[i];
+                    }
+                    else
+                    {
+                        // get owner and neighbour in new cell numbering
+                        label newOwn = cellOffset[procI] + faceOs[i];
+                        label newNbr = fnd();
+                        label tgtFaceI = internalFaceOffset[procI]++;
+
+                        if (debug)
+                        {
+                            Pout<< "    proc " << procI
+                                << "\tinserting face:" << tgtFaceI
+                                << " connection between owner " << newOwn
+                                << " and neighbour " << newNbr
+                                << endl;
+                        }
+
+                        if (newOwn < newNbr)
+                        {
+                            // we have correct orientation
+                            tgtFaces[tgtFaceI] = fcs[i];
+                            tgtFaceOwners[tgtFaceI] = newOwn;
+                            tgtFaceNeighbours[tgtFaceI] = newNbr;
+                        }
+                        else
+                        {
+                            // reverse orientation
+                            tgtFaces[tgtFaceI] = fcs[i].reverseFace();
+                            tgtFaceOwners[tgtFaceI] = newNbr;
+                            tgtFaceNeighbours[tgtFaceI] = newOwn;
+                        }
+
+                        add(tgtFaces[tgtFaceI], pointOffset[procI]);
+
+                        // mark with unique value
+                        fnd() = -2;
+                    }
+                }
+            }
+        }
+    }
+
+
+    forAll(allNbrProcIDs, procI)
+    {
+        const labelList& nbrProcI = allNbrProcIDs[procI];
+        const labelList& localFaceI = allProcLocalFaceIDs[procI];
+        const labelList& faceOs = allFaceOwners[procI];
+        const labelList& faceNs = allFaceNeighbours[procI];
+        const faceList& fcs = allFaces[procI];
+
+        forAll(nbrProcI, i)
+        {
+            // coupled boundary face
+            if (nbrProcI[i] != -1 && localFaceI[i] != -1)
+            {
+                label3 key;
+                key[0] = min(procI, nbrProcI[i]);
+                key[1] = max(procI, nbrProcI[i]);
+                key[2] = localFaceI[i];
+
+                label tgtFaceI = procFaceToGlobalCell[key];
+
+                if (tgtFaceI == -1)
+                {
+                    FatalErrorIn
+                    (
+                        "void Foam::meshToMeshNew::"
+                        "distributeAndMergeCells"
+                        "("
+                            "const mapDistribute&, "
+                            "const polyMesh&, "
+                            "const globalIndex&, "
+                            "pointField&, "
+                            "faceList&, "
+                            "labelList&, "
+                            "labelList&, "
+                            "labelList&"
+                        ") const"
+                    )
+                        << "Unvisited " << key
+                        << abort(FatalError);
+                }
+                else if (tgtFaceI != -2)
+                {
+                    label newOwn = cellOffset[procI] + faceOs[i];
+                    label tgtFaceI = nIntFaces++;
+
+                    if (debug)
+                    {
+                        Pout<< "    proc " << procI
+                            << "\tinserting boundary face:" << tgtFaceI
+                            << " from coupled face " << key
+                            << endl;
+                    }
+
+                    tgtFaces[tgtFaceI] = fcs[i];
+                    add(tgtFaces[tgtFaceI], pointOffset[procI]);
+
+                    tgtFaceOwners[tgtFaceI] = newOwn;
+                    tgtFaceNeighbours[tgtFaceI] = -1;
+                }
+            }
+            // normal boundary face
+            else
+            {
+                label own = faceOs[i];
+                label nbr = faceNs[i];
+                if ((own != -1) && (nbr == -1))
+                {
+                    label newOwn = cellOffset[procI] + faceOs[i];
+                    label tgtFaceI = nIntFaces++;
+
+                    tgtFaces[tgtFaceI] = fcs[i];
+                    add(tgtFaces[tgtFaceI], pointOffset[procI]);
+
+                    tgtFaceOwners[tgtFaceI] = newOwn;
+                    tgtFaceNeighbours[tgtFaceI] = -1;
+                }
+            }
+        }
+    }
+
+
+    if (debug)
+    {
+        // only merging points in debug mode
+
+        labelList oldToNew;
+        pointField newTgtPoints;
+        bool hasMerged = mergePoints
+        (
+            tgtPoints,
+            SMALL,
+            false,
+            oldToNew,
+            newTgtPoints
+        );
+
+        if (hasMerged)
+        {
+            if (debug)
+            {
+                Pout<< "Merged from " << tgtPoints.size()
+                    << " down to " << newTgtPoints.size() << " points" << endl;
+            }
+
+            tgtPoints.transfer(newTgtPoints);
+            forAll(tgtFaces, i)
+            {
+                inplaceRenumber(oldToNew, tgtFaces[i]);
+            }
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewTemplates.C b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..4587b8ea60a0be63cc6cfcf467403ce4209eed13
--- /dev/null
+++ b/src/sampling/meshToMeshInterpolation/meshToMeshNew/meshToMeshNewTemplates.C
@@ -0,0 +1,537 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2012-2013 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "fvMesh.H"
+#include "volFields.H"
+//#include "ops.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //- Helper class for list
+    template<class Type>
+    class ListPlusEqOp
+    {
+        public:
+        void operator()(List<Type>& x, const List<Type> y) const
+        {
+            if (y.size())
+            {
+                if (x.size())
+                {
+                    label sz = x.size();
+                    x.setSize(sz + y.size());
+                    forAll(y, i)
+                    {
+                        x[sz++] = y[i];
+                    }
+                }
+                else
+                {
+                    x = y;
+                }
+            }
+        }
+    };
+
+    //- Combine operator for maps/interpolations
+    template<class Type, class CombineOp>
+    class combineBinaryOp
+    {
+        const CombineOp& cop_;
+
+        public:
+
+            combineBinaryOp(const CombineOp& cop)
+            :
+                cop_(cop)
+            {}
+
+            void operator()
+            (
+                Type& x,
+                const label faceI,
+                const Type& y,
+                const scalar weight
+            ) const
+            {
+                cop_(x, weight*y);
+            }
+    };
+}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::meshToMeshNew::add
+(
+    UList<Type>& fld,
+    const label offset
+) const
+{
+    forAll(fld, i)
+    {
+        fld[i] += offset;
+    }
+}
+
+
+template<class Type, class CombineOp>
+void Foam::meshToMeshNew::mapSrcToTgt
+(
+    const UList<Type>& srcField,
+    const CombineOp& cop,
+    List<Type>& result
+) const
+{
+    if (result.size() != tgtToSrcCellAddr_.size())
+    {
+        FatalErrorIn
+        (
+            "void Foam::meshToMeshNew::mapSrcToTgt"
+            "("
+                "const UList<Type>&, "
+                "const CombineOp&, "
+                "List<Type>&"
+            ") const"
+        )   << "Supplied field size is not equal to target mesh size" << nl
+            << "    source mesh   = " << srcToTgtCellAddr_.size() << nl
+            << "    target mesh   = " << tgtToSrcCellAddr_.size() << nl
+            << "    supplied field = " << result.size()
+            << abort(FatalError);
+    }
+
+    combineBinaryOp<Type, CombineOp> cbop(cop);
+
+    if (singleMeshProc_ == -1)
+    {
+        const mapDistribute& map = srcMapPtr_();
+
+        List<Type> work(srcField);
+        map.distribute(work);
+
+        forAll(result, cellI)
+        {
+            const labelList& srcAddress = tgtToSrcCellAddr_[cellI];
+            const scalarList& srcWeight = tgtToSrcCellWght_[cellI];
+
+            if (srcAddress.size())
+            {
+//                result[cellI] = pTraits<Type>::zero;
+                result[cellI] *= (1.0 - sum(srcWeight));
+                forAll(srcAddress, i)
+                {
+                    label srcI = srcAddress[i];
+                    scalar w = srcWeight[i];
+                    cbop(result[cellI], cellI, work[srcI], w);
+                }
+            }
+        }
+    }
+    else
+    {
+        forAll(result, cellI)
+        {
+            const labelList& srcAddress = tgtToSrcCellAddr_[cellI];
+            const scalarList& srcWeight = tgtToSrcCellWght_[cellI];
+
+            if (srcAddress.size())
+            {
+//                result[cellI] = pTraits<Type>::zero;
+                result[cellI] *= (1.0 - sum(srcWeight));
+                forAll(srcAddress, i)
+                {
+                    label srcI = srcAddress[i];
+                    scalar w = srcWeight[i];
+                    cbop(result[cellI], cellI, srcField[srcI], w);
+                }
+            }
+        }
+    }
+}
+
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapSrcToTgt
+(
+    const Field<Type>& srcField,
+    const CombineOp& cop
+) const
+{
+    tmp<Field<Type> > tresult
+    (
+        new Field<Type>
+        (
+            tgtToSrcCellAddr_.size(),
+            pTraits<Type>::zero
+        )
+    );
+
+    mapSrcToTgt(srcField, cop, tresult());
+
+    return tresult;
+}
+
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapSrcToTgt
+(
+    const tmp<Field<Type> >& tsrcField,
+    const CombineOp& cop
+) const
+{
+    return mapSrcToTgt(tsrcField(), cop);
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapSrcToTgt
+(
+    const Field<Type>& srcField
+) const
+{
+    return mapSrcToTgt(srcField, plusEqOp<Type>());
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapSrcToTgt
+(
+    const tmp<Field<Type> >& tsrcField
+) const
+{
+    return mapSrcToTgt(tsrcField());
+}
+
+
+template<class Type, class CombineOp>
+void Foam::meshToMeshNew::mapTgtToSrc
+(
+    const UList<Type>& tgtField,
+    const CombineOp& cop,
+    List<Type>& result
+) const
+{
+    if (result.size() != srcToTgtCellAddr_.size())
+    {
+        FatalErrorIn
+        (
+            "void Foam::meshToMeshNew::mapTgtToSrc"
+            "("
+                "const UList<Type>&, "
+                "const CombineOp&, "
+                "List<Type>&"
+            ") const"
+        )   << "Supplied field size is not equal to source mesh size" << nl
+            << "    source mesh   = " << srcToTgtCellAddr_.size() << nl
+            << "    target mesh   = " << tgtToSrcCellAddr_.size() << nl
+            << "    supplied field = " << result.size()
+            << abort(FatalError);
+    }
+
+    combineBinaryOp<Type, CombineOp> cbop(cop);
+
+    if (singleMeshProc_ == -1)
+    {
+        const mapDistribute& map = tgtMapPtr_();
+
+        List<Type> work(tgtField);
+        map.distribute(work);
+
+        forAll(result, cellI)
+        {
+            const labelList& tgtAddress = srcToTgtCellAddr_[cellI];
+            const scalarList& tgtWeight = srcToTgtCellWght_[cellI];
+
+            if (tgtAddress.size())
+            {
+//                result[cellI] = pTraits<Type>::zero;
+                result[cellI] *= (1.0 - sum(tgtWeight));
+                forAll(tgtAddress, i)
+                {
+                    label tgtI = tgtAddress[i];
+                    scalar w = tgtWeight[i];
+                    cbop(result[cellI], cellI, work[tgtI], w);
+                }
+            }
+        }
+    }
+    else
+    {
+        forAll(result, cellI)
+        {
+            const labelList& tgtAddress = srcToTgtCellAddr_[cellI];
+            const scalarList& tgtWeight = srcToTgtCellWght_[cellI];
+
+            if (tgtAddress.size())
+            {
+//                result[cellI] = pTraits<Type>::zero;
+                result[cellI] *= (1.0 - sum(tgtWeight));
+                forAll(tgtAddress, i)
+                {
+                    label tgtI = tgtAddress[i];
+                    scalar w = tgtWeight[i];
+                    cbop(result[cellI], cellI, tgtField[tgtI], w);
+                }
+            }
+        }
+    }
+}
+
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapTgtToSrc
+(
+    const Field<Type>& tgtField,
+    const CombineOp& cop
+) const
+{
+    tmp<Field<Type> > tresult
+    (
+        new Field<Type>
+        (
+            srcToTgtCellAddr_.size(),
+            pTraits<Type>::zero
+        )
+    );
+
+    mapTgtToSrc(tgtField, cop, tresult());
+
+    return tresult;
+}
+
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapTgtToSrc
+(
+    const tmp<Field<Type> >& ttgtField,
+    const CombineOp& cop
+) const
+{
+    return mapTgtToSrc(ttgtField(), cop);
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapTgtToSrc
+(
+    const Field<Type>& tgtField
+) const
+{
+    return mapTgtToSrc(tgtField, plusEqOp<Type>());
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type> > Foam::meshToMeshNew::mapTgtToSrc
+(
+    const tmp<Field<Type> >& ttgtField
+) const
+{
+    return mapTgtToSrc(ttgtField(), plusEqOp<Type>());
+}
+
+
+template<class Type, class CombineOp>
+void Foam::meshToMeshNew::interpolate
+(
+    const GeometricField<Type, fvPatchField, volMesh>& field,
+    const CombineOp& cop,
+    GeometricField<Type, fvPatchField, volMesh>& result,
+    const bool interpPatches
+) const
+{
+    const fvMesh& mesh = field.mesh();
+
+    if (mesh.name() == srcRegionName_)
+    {
+        mapSrcToTgt(field, cop, result.internalField());
+    }
+    else if (mesh.name() == tgtRegionName_)
+    {
+        mapTgtToSrc(field, cop, result.internalField());
+    }
+    else
+    {
+        FatalErrorIn
+        (
+            "void Foam::meshToMeshNew::interpolate"
+            "("
+                "const GeometricField<Type, fvPatchField, volMesh>&, "
+                "const CombineOp&, "
+                "GeometricField<Type, fvPatchField, volMesh>&, "
+                "const bool"
+            ") const"
+        )
+            << "Supplied field " << field.name() << " did not originate from "
+            << "either the source or target meshes used to create this "
+            << "interpolation object"
+            << abort(FatalError);
+    }
+
+    if (interpPatches)
+    {
+        if (directMapping_)
+        {
+            result.boundaryField() == field.boundaryField();
+        }
+        else
+        {
+            notImplemented
+            (
+                "void Foam::meshToMeshNew::interpolate"
+                "("
+                    "const GeometricField<Type, fvPatchField, volMesh>&, "
+                    "const CombineOp&, "
+                    "GeometricField<Type, fvPatchField, volMesh>&, "
+                    "const bool"
+                ") const - non-conformal patches"
+            )
+
+            // do something...
+        }
+    }
+}
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh> >
+Foam::meshToMeshNew::interpolate
+(
+    const GeometricField<Type, fvPatchField, volMesh>& field,
+    const CombineOp& cop,
+    const bool interpPatches
+) const
+{
+    typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
+
+    const fvMesh& mesh = field.mesh();
+
+    tmp<fieldType> tresult;
+
+    if (mesh.name() == srcRegionName_)
+    {
+        const fvMesh& tgtMesh =
+            mesh.time().lookupObject<fvMesh>(tgtRegionName_);
+
+        tresult =
+            new fieldType
+            (
+                IOobject
+                (
+                    type() + "::interpolate(" + field.name() + ")",
+                    tgtMesh.time().timeName(),
+                    tgtMesh,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                tgtMesh,
+                dimensioned<Type>
+                (
+                    "zero",
+                    field.dimensions(),
+                    pTraits<Type>::zero
+                )
+            );
+
+         interpolate(field, cop, tresult(), interpPatches);
+    }
+    else if (mesh.name() == tgtRegionName_)
+    {
+        const fvMesh& srcMesh =
+            mesh.time().lookupObject<fvMesh>(srcRegionName_);
+
+        tresult =
+            new fieldType
+            (
+                IOobject
+                (
+                    type() + "::interpolate(" + field.name() + ")",
+                    srcMesh.time().timeName(),
+                    srcMesh,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                srcMesh,
+                dimensioned<Type>
+                (
+                    "zero",
+                    field.dimensions(),
+                    pTraits<Type>::zero
+                )
+            );
+
+         interpolate(field, cop, tresult(), interpPatches);
+    }
+
+    return tresult;
+}
+
+
+template<class Type, class CombineOp>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh> >
+Foam::meshToMeshNew::interpolate
+(
+    const tmp<GeometricField<Type, fvPatchField, volMesh> >& tfield,
+    const CombineOp& cop,
+    const bool interpPatches
+) const
+{
+    return
+        interpolate
+        (
+            tfield(),
+            combineBinaryOp<Type, CombineOp>(cop),
+            interpPatches
+        );
+}
+
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh> >
+Foam::meshToMeshNew::interpolate
+(
+    const GeometricField<Type, fvPatchField, volMesh>& field,
+    const bool interpPatches
+) const
+{
+    return interpolate(field, plusEqOp<Type>(), interpPatches);
+}
+
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh> >
+Foam::meshToMeshNew::interpolate
+(
+    const tmp<GeometricField<Type, fvPatchField, volMesh> >& tfield,
+    const bool interpPatches
+) const
+{
+    return interpolate(tfield(), plusEqOp<Type>(), interpPatches);
+}
+
+
+// ************************************************************************* //