diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C
new file mode 100644
index 0000000000..03f6355870
--- /dev/null
+++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C
@@ -0,0 +1,339 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "AMIMethod.H"
+#include "meshTools.H"
+#include "mapDistribute.H"
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+template
+void Foam::AMIMethod::checkPatches() const
+{
+ if (debug && (!srcPatch_.size() || !tgtPatch_.size()))
+ {
+ Pout<< "AMI: Patches not on processor: Source faces = "
+ << srcPatch_.size() << ", target faces = " << tgtPatch_.size()
+ << endl;
+ }
+
+
+ const scalar maxBoundsError = 0.05;
+
+ // check bounds of source and target
+ boundBox bbSrc(srcPatch_.points(), srcPatch_.meshPoints(), true);
+ boundBox bbTgt(tgtPatch_.points(), tgtPatch_.meshPoints(), true);
+
+ boundBox bbTgtInf(bbTgt);
+ bbTgtInf.inflate(maxBoundsError);
+
+ if (!bbTgtInf.contains(bbSrc))
+ {
+ WarningIn("AMIMethod::checkPatches()")
+ << "Source and target patch bounding boxes are not similar" << nl
+ << " source box span : " << bbSrc.span() << nl
+ << " target box span : " << bbTgt.span() << nl
+ << " source box : " << bbSrc << nl
+ << " target box : " << bbTgt << nl
+ << " inflated target box : " << bbTgtInf << endl;
+ }
+}
+
+
+template
+bool Foam::AMIMethod::initialise
+(
+ labelListList& srcAddress,
+ scalarListList& srcWeights,
+ labelListList& tgtAddress,
+ scalarListList& tgtWeights,
+ label& srcFaceI,
+ label& tgtFaceI
+)
+{
+ // set initial sizes for weights and addressing - must be done even if
+ // returns false below
+ srcAddress.setSize(srcPatch_.size());
+ srcWeights.setSize(srcPatch_.size());
+ tgtAddress.setSize(tgtPatch_.size());
+ tgtWeights.setSize(tgtPatch_.size());
+
+ // check that patch sizes are valid
+ if (!srcPatch_.size())
+ {
+ return false;
+ }
+ else if (!tgtPatch_.size())
+ {
+ WarningIn
+ (
+ "void Foam::AMIMethod::initialise"
+ "("
+ "label&, "
+ "label&"
+ ")"
+ )
+ << srcPatch_.size() << " source faces but no target faces" << endl;
+
+ return false;
+ }
+
+ // reset the octree
+ resetTree();
+
+ // find initial face match using brute force/octree search
+ if ((srcFaceI == -1) || (tgtFaceI == -1))
+ {
+ srcFaceI = 0;
+ tgtFaceI = 0;
+ bool foundFace = false;
+ forAll(srcPatch_, faceI)
+ {
+ tgtFaceI = findTargetFace(faceI);
+ if (tgtFaceI >= 0)
+ {
+ srcFaceI = faceI;
+ foundFace = true;
+ break;
+ }
+ }
+
+ if (!foundFace)
+ {
+ FatalErrorIn
+ (
+ "void Foam::AMIMethod::initialise"
+ "("
+ "label&, "
+ "label&"
+ ")"
+ ) << "Unable to find initial target face" << abort(FatalError);
+ }
+ }
+
+ if (debug)
+ {
+ Pout<< "AMI: initial target face = " << tgtFaceI << endl;
+ }
+
+ return true;
+}
+
+
+template
+void Foam::AMIMethod::writeIntersectionOBJ
+(
+ const scalar area,
+ const face& f1,
+ const face& f2,
+ const pointField& f1Points,
+ const pointField& f2Points
+) const
+{
+ static label count = 1;
+
+ const pointField f1pts = f1.points(f1Points);
+ const pointField f2pts = f2.points(f2Points);
+
+ Pout<< "Face intersection area (" << count << "):" << nl
+ << " f1 face = " << f1 << nl
+ << " f1 pts = " << f1pts << nl
+ << " f2 face = " << f2 << nl
+ << " f2 pts = " << f2pts << nl
+ << " area = " << area
+ << endl;
+
+ OFstream os("areas" + name(count) + ".obj");
+
+ forAll(f1pts, i)
+ {
+ meshTools::writeOBJ(os, f1pts[i]);
+ }
+ os<< "l";
+ forAll(f1pts, i)
+ {
+ os<< " " << i + 1;
+ }
+ os<< " 1" << endl;
+
+
+ forAll(f2pts, i)
+ {
+ meshTools::writeOBJ(os, f2pts[i]);
+ }
+ os<< "l";
+ forAll(f2pts, i)
+ {
+ os<< " " << f1pts.size() + i + 1;
+ }
+ os<< " " << f1pts.size() + 1 << endl;
+
+ count++;
+}
+
+
+template
+void Foam::AMIMethod::resetTree()
+{
+ // Clear the old octree
+ treePtr_.clear();
+
+ treeBoundBox bb(tgtPatch_.points());
+ bb.inflate(0.01);
+
+ if (!treePtr_.valid())
+ {
+ treePtr_.reset
+ (
+ new indexedOctree
+ (
+ treeType(false, tgtPatch_),
+ bb, // overall search domain
+ 8, // maxLevel
+ 10, // leaf size
+ 3.0 // duplicity
+ )
+ );
+ }
+}
+
+
+template
+Foam::label Foam::AMIMethod::findTargetFace
+(
+ const label srcFaceI
+) const
+{
+ label targetFaceI = -1;
+
+ const pointField& srcPts = srcPatch_.points();
+ const face& srcFace = srcPatch_[srcFaceI];
+ const point srcPt = srcFace.centre(srcPts);
+ const scalar srcFaceArea = srcMagSf_[srcFaceI];
+
+ pointIndexHit sample = treePtr_->findNearest(srcPt, 10.0*srcFaceArea);
+
+
+ if (debug)
+ {
+ Pout<< "Source point = " << srcPt << ", Sample point = "
+ << sample.hitPoint() << ", Sample index = " << sample.index()
+ << endl;
+ }
+
+ if (sample.hit())
+ {
+ targetFaceI = sample.index();
+ }
+
+ return targetFaceI;
+}
+
+
+template
+void Foam::AMIMethod::appendNbrFaces
+(
+ const label faceI,
+ const TargetPatch& patch,
+ const DynamicList