diff --git a/Geo/FFace.cpp b/Geo/FFace.cpp
index 043191f86dac5cc0e2d4881a2ca1c105fb8a9b1a..5f391f5742962cfa73cf4693d6bd01b69a1827a2 100644
--- a/Geo/FFace.cpp
+++ b/Geo/FFace.cpp
@@ -38,6 +38,23 @@ SPoint2 FFace::parFromPoint(const SPoint3 &p) const
   double u, v, x, y, z;
   x = p.x(); y = p.y(); z = p.z();
   face->Inverse(x,y,z,u,v);
+  printf("per : %d %d\n",face->IsPeriodic(0),face->IsPeriodic(1));
+  if (face->IsPeriodic(0)) {
+    double s,e;
+    printf("\tper : %d %d\n",face->GetEdge(0)->GetCurveExtent(s,e),
+	   face->GetEdge(1)->GetCurveExtent(s,e));
+    if (face->GetEdge(0)->GetCurveExtent(s,e)) {
+      printf("%g %g %g\n",u,s,e);
+      u -= floor(u - s);
+      printf("%g %g %g\n\n",u,s,e);
+    }
+  }
+  if (face->IsPeriodic(1)) {
+    double s,e;
+    if (face->GetEdge(1)->GetCurveExtent(s,e)) {
+      v -= floor(v - s);
+    } 
+  }
   return SPoint2(u, v);
 }
 
@@ -71,4 +88,15 @@ GEntity::GeomType FFace::geomType() const
   return  GEntity::ParametricSurface;
 }
 
+bool FFace::surfPeriodic(int dim) const
+{
+  return face->IsPeriodic(dim);
+}
+
+double FFace::period(int dir) const
+{
+    return 1.;
+}
+
+
 #endif
diff --git a/Geo/FFace.h b/Geo/FFace.h
index fcdf396c077f76c5f7aaa2ecc60427feb84b7a8d..452d26142d2c6efdfd45f240ea06be4a4f11ac55 100644
--- a/Geo/FFace.h
+++ b/Geo/FFace.h
@@ -13,7 +13,6 @@
 class FFace : public GFace {
  protected:
   FM_Face *face;
-  bool _periodic[2];
  public:
   FFace(GModel *m, FM_Face *face_, int tag, std::list<GEdge*> l_edges_);
 
@@ -37,10 +36,10 @@ class FFace : public GFace {
   virtual bool continuous(int dim) const { return true; }
   virtual bool periodic(int dim) const { return false; }
   virtual bool degenerate(int dim) const { return false; }
-  virtual double period(int dir) const {throw;}
+  virtual double period(int dir) const;
   ModelType getNativeType() const { return FourierModel; }
   void * getNativePtr() const {throw;} 
-  virtual bool surfPeriodic(int dim) const {throw;}
+  virtual bool surfPeriodic(int dim) const;
 };
 
 #endif
diff --git a/Geo/FProjectionFace.cpp b/Geo/FProjectionFace.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..84bc943c36a2583020d2caab7d238af89e100228
--- /dev/null
+++ b/Geo/FProjectionFace.cpp
@@ -0,0 +1,67 @@
+#include "FProjectionFace.h"
+
+#if defined(HAVE_FOURIER_MODEL)
+
+FProjectionFace::FProjectionFace(GModel *m, int num) 
+  : GFace(m,num), ps_(0) {}
+
+FProjectionFace::
+FProjectionFace(GModel *m, int num, ProjectionSurface* ps)
+  : GFace(m,num), ps_(ps) {}
+
+FProjectionFace::~FProjectionFace() {}
+
+/*
+void FProjectionFace::ResetProjectionSurface(int type)
+{
+  if (ps_->GetTag() != type) {
+    delete ps_;
+    if (type == 1)
+      ps_ = new RevolvedParabolaProjectionSurface(type);
+    else
+      ps_ = new CylindricalProjectionSurface(type);
+  }
+}
+*/
+
+GPoint FProjectionFace::point(double par1, double par2) const
+{
+  SVector3 p;
+
+  ps_->F(par1,par2,p[0],p[1],p[2]);
+  
+  return GPoint(p[0],p[1],p[2]);
+}
+
+SPoint2 FProjectionFace::parFromPoint(const SPoint3 &p) const
+{  
+  double u,v;
+  ps_->Inverse(p[0],p[1],p[2],u,v);
+  return SPoint2(u,v);
+}
+
+Pair<SVector3,SVector3> FProjectionFace::firstDer
+(const SPoint2 &param) const
+{
+  SVector3 du;
+  SVector3 dv;
+  
+  ps_->Dfdu(param.x(),param.y(),du[0],du[1],du[2]);
+  ps_->Dfdv(param.x(),param.y(),dv[0],dv[1],dv[2]);
+  
+  return Pair<SVector3,SVector3>(du,dv);
+} 
+
+SVector3 FProjectionFace::normal(const SPoint2 &param) const
+{	
+  double x,y,z;
+  ps_->GetUnitNormal(param.x(),param.y(),x,y,z);
+  return SVector3(x,y,z);
+}
+
+Range<double> FProjectionFace::parBounds(int i) const
+{
+  return Range<double>(0, 1);
+}
+
+#endif
diff --git a/Geo/FProjectionFace.h b/Geo/FProjectionFace.h
new file mode 100644
index 0000000000000000000000000000000000000000..2afd96b2750988089563ffb6ee403f2a1fa2ce0d
--- /dev/null
+++ b/Geo/FProjectionFace.h
@@ -0,0 +1,51 @@
+#ifndef _F_PROJECTION_FACE_H_
+#define _F_PROJECTION_FACE_H_
+
+#include "GModel.h"
+#include "Range.h"
+#include "projectionFace.h"
+#include "CylindricalProjectionSurface.h"
+#include "RevolvedParabolaProjectionSurface.h"
+
+#if defined(HAVE_FOURIER_MODEL)
+
+#include "ProjectionSurface.h"
+
+class FProjectionFace : public GFace {
+ protected:
+  ProjectionSurface* ps_;
+
+ public:
+  FProjectionFace(GModel *m, int num);
+  FProjectionFace(GModel *m, int num, ProjectionSurface* ps);
+  ~FProjectionFace();
+
+  Range<double> parBounds(int i) const;
+  GPoint point(double par1, double par2) const; 
+  SVector3 normal(const SPoint2 &param) const; 
+  Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const; 
+  SPoint2 parFromPoint(const SPoint3 &) const;
+
+  virtual int paramDegeneracies(int dir, double *par) { return 0; }
+  virtual GPoint closestPoint(const SPoint3 & queryPoint) const {throw;}
+  virtual int containsPoint(const SPoint3 &pt) const {throw;}  
+  virtual int containsParam(const SPoint2 &pt) const {throw;}
+  virtual GEntity::GeomType geomType() const 
+  { return GEntity::ProjectionFace; }
+  virtual int geomDirection() const { return 1; }
+  virtual bool continuous(int dim) const { return true; }
+  virtual bool periodic(int dim) const { return false; }
+  virtual bool degenerate(int dim) const { return false; }
+  virtual double period(int dir) const {throw;}
+  ModelType getNativeType() const { return UnknownModel; }
+  void * getNativePtr() const {throw;} 
+  virtual bool surfPeriodic(int dim) const {throw;}
+
+  inline ProjectionSurface* GetProjectionSurface() { return ps_; }
+
+  //virtual void ResetProjectionSurface(int type);
+};
+
+#endif
+
+#endif
diff --git a/Geo/GEdge.cpp b/Geo/GEdge.cpp
index ae4dc268764e02d18980f4bae99a7e67b066dd02..0a45583fcceb29af4a9ae5c34d32ac866674253b 100644
--- a/Geo/GEdge.cpp
+++ b/Geo/GEdge.cpp
@@ -1,4 +1,4 @@
-// $Id: GEdge.cpp,v 1.29 2007-05-24 14:44:06 remacle Exp $
+// $Id: GEdge.cpp,v 1.30 2007-07-26 16:28:27 anand Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
diff --git a/Geo/GEntity.h b/Geo/GEntity.h
index 50ad8d0e8999d961b8f27e4d8816d04e338ae6f6..9eceb2938aaaabfac4a194013f2eeffeafa309c3 100644
--- a/Geo/GEntity.h
+++ b/Geo/GEntity.h
@@ -82,7 +82,7 @@ class GEntity {
     Torus,
     RuledSurface,
     ParametricSurface,
-    ProjectionSurface,
+    ProjectionFace,
     BSplineSurface,
     BoundaryLayerSurface,
     DiscreteSurface,
diff --git a/Geo/Makefile b/Geo/Makefile
index 6c85273c8d60bdb78424d68842e60506a1943e74..d2360106031956e6cb4fe546eb757b29f4766bf7 100644
--- a/Geo/Makefile
+++ b/Geo/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.149 2007-07-09 13:54:36 geuzaine Exp $
+# $Id: Makefile,v 1.150 2007-07-26 16:28:27 anand Exp $
 #
 # Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 #
@@ -32,7 +32,7 @@ SRC = GEntity.cpp\
       gmshVertex.cpp gmshEdge.cpp gmshFace.cpp gmshRegion.cpp gmshSurface.cpp\
       OCCVertex.cpp OCCEdge.cpp OCCFace.cpp OCCRegion.cpp\
       FEdge.cpp FFace.cpp\
-      projectionFace.cpp\
+      FProjectionFace.cpp\
       GModel.cpp\
         GModelIO_Geo.cpp\
         GModelIO_Mesh.cpp\
@@ -70,213 +70,3 @@ depend:
 	rm -f Makefile.new
 
 # DO NOT DELETE THIS LINE
-GEntity.o: GEntity.cpp GEntity.h Range.h SPoint3.h SBoundingBox3d.h \
-  ../Common/GmshDefines.h MRep.h GEdge.h GVertex.h MVertex.h GPoint.h \
-  SPoint2.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/VertexArray.h ../Common/Message.h ../Common/OS.h
-GVertex.o: GVertex.cpp GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GFace.h GEdgeLoop.h GEdge.h SVector3.h MElement.h MEdge.h \
-  ../Common/Hash.h MFace.h ../Numeric/Numeric.h ../Common/Context.h \
-  ../DataStr/List.h ExtrudeParams.h ../Common/SmoothData.h Pair.h
-GEdge.o: GEdge.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h
-GEdgeLoop.o: GEdgeLoop.cpp GEdgeLoop.h GEdge.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h GVertex.h MVertex.h \
-  GPoint.h SPoint2.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h ../Common/Message.h
-GFace.o: GFace.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/Message.h
-GRegion.o: GRegion.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h
-gmshVertex.o: gmshVertex.cpp GFace.h GPoint.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h GEdgeLoop.h GEdge.h GVertex.h \
-  MVertex.h SPoint2.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h Pair.h gmshVertex.h Geo.h \
-  gmshSurface.h ../DataStr/Tree.h ../DataStr/avl.h GeoInterpolation.h \
-  ../Common/Message.h
-gmshEdge.o: gmshEdge.cpp GFace.h GPoint.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h GEdgeLoop.h GEdge.h GVertex.h \
-  MVertex.h SPoint2.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h Pair.h gmshEdge.h Geo.h \
-  gmshSurface.h ../DataStr/Tree.h ../DataStr/avl.h gmshVertex.h \
-  GeoInterpolation.h ../Common/Message.h
-gmshFace.o: gmshFace.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h gmshVertex.h Geo.h gmshSurface.h ../DataStr/Tree.h \
-  ../DataStr/avl.h gmshEdge.h gmshFace.h GeoInterpolation.h \
-  ../Common/Message.h
-gmshRegion.o: gmshRegion.cpp GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h gmshFace.h Geo.h gmshSurface.h ../DataStr/Tree.h \
-  ../DataStr/avl.h gmshVertex.h gmshRegion.h ../Common/Message.h
-gmshSurface.o: gmshSurface.cpp gmshSurface.h Pair.h Range.h SPoint2.h \
-  SPoint3.h SVector3.h SBoundingBox3d.h ../Common/Message.h
-OCCVertex.o: OCCVertex.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h OCCVertex.h OCCIncludes.h OCCEdge.h OCCFace.h
-OCCEdge.o: OCCEdge.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/Message.h OCCEdge.h OCCVertex.h OCCIncludes.h \
-  OCCFace.h
-OCCFace.o: OCCFace.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h OCCVertex.h OCCIncludes.h OCCEdge.h OCCFace.h \
-  ../Common/Message.h
-OCCRegion.o: OCCRegion.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h OCCVertex.h OCCIncludes.h OCCEdge.h OCCFace.h OCCRegion.h \
-  ../Common/Message.h
-FEdge.o: FEdge.cpp ../Common/Message.h FEdge.h GEdge.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h GVertex.h MVertex.h \
-  GPoint.h SPoint2.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GModel.h GFace.h GEdgeLoop.h \
-  Pair.h GRegion.h FVertex.h
-FFace.o: FFace.cpp FVertex.h GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h FFace.h FEdge.h ../Common/Message.h
-projectionFace.o: projectionFace.cpp projectionFace.h GFace.h GPoint.h \
-  GEntity.h Range.h SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h \
-  GEdgeLoop.h GEdge.h GVertex.h MVertex.h SPoint2.h SVector3.h MElement.h \
-  MEdge.h ../Common/Hash.h MFace.h ../Numeric/Numeric.h \
-  ../Common/Context.h ../DataStr/List.h ExtrudeParams.h \
-  ../Common/SmoothData.h Pair.h
-GModel.o: GModel.cpp GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h \
-  GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h gmshSurface.h ../Mesh/Field.h ../Post/Views.h \
-  ../Post/ColorTable.h ../Common/VertexArray.h ../Post/AdaptiveViews.h \
-  ../Common/GmshMatrix.h ../Geo/Geo.h ../Geo/gmshSurface.h \
-  ../DataStr/Tree.h ../DataStr/avl.h ../Geo/SPoint2.h \
-  ../Geo/ExtrudeParams.h ../Geo/GEdge.h ../Post/OctreePost.h \
-  ../Common/Octree.h ../Common/OctreeInternals.h MRep.h \
-  ../Common/Message.h ../Common/OS.h ../Mesh/BackgroundMesh.h
-GModelIO_Geo.o: GModelIO_Geo.cpp GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h Geo.h gmshSurface.h ../DataStr/Tree.h ../DataStr/avl.h \
-  ../Parser/OpenFile.h ../DataStr/Tools.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../Common/Message.h gmshVertex.h gmshFace.h \
-  gmshEdge.h gmshRegion.h ../Parser/Parser.h
-GModelIO_Mesh.o: GModelIO_Mesh.cpp ../Common/Message.h \
-  ../Common/GmshDefines.h GModel.h GVertex.h GEntity.h Range.h SPoint3.h \
-  SBoundingBox3d.h MVertex.h GPoint.h SPoint2.h GEdge.h SVector3.h \
-  MElement.h MEdge.h ../Common/Hash.h MFace.h ../Numeric/Numeric.h \
-  ../Common/Context.h ../DataStr/List.h ExtrudeParams.h \
-  ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h GRegion.h \
-  gmshRegion.h Geo.h gmshSurface.h ../DataStr/Tree.h ../DataStr/avl.h \
-  gmshFace.h gmshVertex.h gmshEdge.h
-GModelIO_OCC.o: GModelIO_OCC.cpp GModelIO_OCC.h GModel.h GVertex.h \
-  GEntity.h Range.h SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h \
-  MVertex.h GPoint.h SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h \
-  ../Common/Hash.h MFace.h ../Numeric/Numeric.h ../Common/Context.h \
-  ../DataStr/List.h ExtrudeParams.h ../Common/SmoothData.h GFace.h \
-  GEdgeLoop.h Pair.h GRegion.h OCCIncludes.h ../Common/Message.h \
-  OCCVertex.h OCCEdge.h OCCFace.h OCCRegion.h
-GModelIO_F.o: GModelIO_F.cpp GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/Message.h ../Post/Views.h ../Post/ColorTable.h \
-  ../Common/VertexArray.h ../Post/AdaptiveViews.h ../Common/GmshMatrix.h \
-  FFace.h FEdge.h FVertex.h ../Mesh/meshGFace.h GModelIO_F.h
-GModelIO_CGNS.o: GModelIO_CGNS.cpp GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/Message.h MNeighbour.h
-GModelIO_MED.o: GModelIO_MED.cpp GModel.h GVertex.h GEntity.h Range.h \
-  SPoint3.h SBoundingBox3d.h ../Common/GmshDefines.h MVertex.h GPoint.h \
-  SPoint2.h GEdge.h SVector3.h MElement.h MEdge.h ../Common/Hash.h \
-  MFace.h ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
-  ExtrudeParams.h ../Common/SmoothData.h GFace.h GEdgeLoop.h Pair.h \
-  GRegion.h ../Common/Message.h
-ExtrudeParams.o: ExtrudeParams.cpp ../Common/Gmsh.h ../Common/Message.h \
-  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
-  ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
-  Geo.h ../Common/GmshDefines.h gmshSurface.h Pair.h Range.h SPoint2.h \
-  SPoint3.h SVector3.h SBoundingBox3d.h ExtrudeParams.h \
-  ../Common/SmoothData.h ../Numeric/Numeric.h
-Geo.o: Geo.cpp ../Common/Gmsh.h ../Common/Message.h ../DataStr/Malloc.h \
-  ../DataStr/List.h ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h \
-  ../DataStr/List.h ../DataStr/Tree.h ../Numeric/Numeric.h Geo.h \
-  ../Common/GmshDefines.h gmshSurface.h Pair.h Range.h SPoint2.h \
-  SPoint3.h SVector3.h SBoundingBox3d.h ExtrudeParams.h \
-  ../Common/SmoothData.h GModel.h GVertex.h GEntity.h MVertex.h GPoint.h \
-  GEdge.h MElement.h MEdge.h ../Common/Hash.h MFace.h ../Common/Context.h \
-  GFace.h GEdgeLoop.h GRegion.h GeoInterpolation.h
-GeoStringInterface.o: GeoStringInterface.cpp ../Common/Gmsh.h \
-  ../Common/Message.h ../DataStr/Malloc.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../Numeric/Numeric.h Geo.h ../Common/GmshDefines.h \
-  gmshSurface.h Pair.h Range.h SPoint2.h SPoint3.h SVector3.h \
-  SBoundingBox3d.h ExtrudeParams.h ../Common/SmoothData.h \
-  GeoStringInterface.h ../Parser/Parser.h ../Parser/OpenFile.h \
-  ../Common/Context.h GModel.h GVertex.h GEntity.h MVertex.h GPoint.h \
-  GEdge.h MElement.h MEdge.h ../Common/Hash.h MFace.h GFace.h GEdgeLoop.h \
-  GRegion.h
-GeoInterpolation.o: GeoInterpolation.cpp ../Common/Gmsh.h \
-  ../Common/Message.h ../DataStr/Malloc.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h \
-  ../DataStr/Tree.h Geo.h ../Common/GmshDefines.h gmshSurface.h Pair.h \
-  Range.h SPoint2.h SPoint3.h SVector3.h SBoundingBox3d.h ExtrudeParams.h \
-  ../Common/SmoothData.h ../Numeric/Numeric.h GeoInterpolation.h \
-  GeoStringInterface.h
-findLinks.o: findLinks.cpp ../Common/Gmsh.h ../Common/Message.h \
-  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
-  ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
-  GModel.h GVertex.h GEntity.h Range.h SPoint3.h SBoundingBox3d.h \
-  ../Common/GmshDefines.h MVertex.h GPoint.h SPoint2.h GEdge.h SVector3.h \
-  MElement.h MEdge.h ../Common/Hash.h MFace.h ../Numeric/Numeric.h \
-  ../Common/Context.h ExtrudeParams.h ../Common/SmoothData.h GFace.h \
-  GEdgeLoop.h Pair.h GRegion.h
-MVertex.o: MVertex.cpp MVertex.h SPoint3.h
-MElement.o: MElement.cpp MElement.h ../Common/GmshDefines.h MVertex.h \
-  SPoint3.h MEdge.h SVector3.h ../Common/Hash.h MFace.h \
-  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h GEntity.h \
-  Range.h SBoundingBox3d.h ../Common/Message.h
diff --git a/Geo/projectionFace.cpp b/Geo/projectionFace.cpp
deleted file mode 100644
index 5add1da1d1d3c65e1f62881a0118b37dd489e35e..0000000000000000000000000000000000000000
--- a/Geo/projectionFace.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-#include "projectionFace.h"
-
-SVector3 scalePoint(SVector3 p, SVector3 s)
-{
-  double x = p[0]*s[0];
-  double y = p[1]*s[1];
-  double z = p[2]*s[2];
-  SVector3 result(x,y,z);
-  return result;
-}
-
-SVector3 rotatePoint(SVector3 p, SVector3 r)
-{
-  double rot[16];
-  double x = r[0] * Pi / 180.;
-  double y = r[1] * Pi / 180.;
-  double z = r[2] * Pi / 180.;
-  double A = cos(x);
-  double B = sin(x);
-  double C = cos(y);
-  double D = sin(y);
-  double E = cos(z);
-  double F = sin(z);
-  double AD = A * D;
-  double BD = B * D;
-  rot[0] = C*E; rot[1] = BD*E+A*F; rot[2] =-AD*E+B*F; rot[3] = 0.;
-  rot[4] =-C*F; rot[5] =-BD*F+A*E; rot[6] = AD*F+B*E; rot[7] = 0.;
-  rot[8] = D;   rot[9] =-B*C;	     rot[10] = A*C;     rot[11] = 0.;
-  rot[12] = 0.; rot[13] = 0.;      rot[14] = 0.;      rot[15] = 1.;
-  
-  x = p[0]*rot[0] + p[1]*rot[1] + p[2]*rot[2];
-  y = p[0]*rot[4] + p[1]*rot[5] + p[2]*rot[6];
-  z = p[0]*rot[8] + p[1]*rot[9] + p[2]*rot[10];
-  
-  SVector3 result(x,y,z);
-  return result;
-}
-
-void projectionFace::rotate(SVector3 rot)
-{
-  rotation = rot + rotation;
-}
-
-void projectionFace::translate(SVector3 trans)
-{
-  translation = trans + translation;
-}
-
-void projectionFace::scale(SVector3 sc)
-{
-  scaleFactor[0] *= sc[0];
-  scaleFactor[1] *= sc[1];
-  scaleFactor[2] *= sc[2];
-}
-
-void projectionFace::setScale(SVector3 sc)
-{
-  scaleFactor[0] = sc[0];
-  scaleFactor[1] = sc[1];
-  scaleFactor[2] = sc[2];
-}
-
-void projectionFace::setRotation(SVector3 r)
-{
-  rotation[0] = r[0];
-  rotation[1] = r[1];
-  rotation[2] = r[2];  
-}
-
-void projectionFace::setTranslation(SVector3 t)
-{
-  translation = t;
-}
-
-projectionFace::projectionFace(GModel *m,int num) : GFace(m,num)
-{
-  for(int j = 0; j<3; j++){
-    translation[j] = 0;
-    rotation[j] = 0;
-  }
-}
-
-projectionFace::~projectionFace()
-{
-}
-
-parabolicCylinder::parabolicCylinder(GModel *m, int num) : projectionFace(m,num)
-{
-  focalPoint = 1;
-  scaleFactor[0] = 1;
-  scaleFactor[1] = 1;
-  scaleFactor[2] = 1;
-}
-
-parabolicCylinder::~parabolicCylinder()
-{
-}
-
-GPoint parabolicCylinder::point(double par1, double par2) const
-{
-  //first let's find the vertex
-  //SPoint3 k = focalPoint - directrixPoint;
-  //k.setPosition(k.x/2,k.y/2,k.z/2);
-  //double f = sqrt(k.x^2 + k.y^2 + k.z^2);
-  //SPoint3 vertex = directrixPoint + k;
-  par1 -= .5;  //I need these to make sure the 'vertex' occurs at the parameter point (.5,.5)
-  par2 -= .5;
-  
-  SVector3 p(par1, (1/(4*focalPoint))*pow(par1,2.0), par2);
-  
-  //now we have to do the necessary transformations
-  p = scalePoint(p,scaleFactor);	//LOCAL SCALING
-  p = rotatePoint(p,rotation);
-  p = translation + p;
-  
-  GPoint gp(p[0],p[1],p[2]);	
-  return gp;
-}
-
-SPoint2 parabolicCylinder::parFromPoint(const SPoint3 &p) const
-{
-  // ok...first we need to untranslate, unrotate and unscale it
-  SVector3 trans(-translation[0], -translation[1], -translation[2]);
-  SVector3 rot(-rotation[0],-rotation[1],-rotation[2]);
-  SVector3 scalar(1/scaleFactor[0],1/scaleFactor[1],1/scaleFactor[2]);	//LOCAL SCALING?
-  
-  SVector3 pos(p[0],p[1],p[2]);
-  pos = trans + pos;
-  pos = rotatePoint(pos,rot);
-  pos = scalePoint(pos, scalar);
-  
-  SPoint2 q(pos[0],pos[1]);	
-  return q;
-}
-
-// du/dx, du/dy, du/dz; dv/dx, dv/dy, dv/dz
-// v - (1/4f)*u^2 = 0
-
-Pair<SVector3,SVector3> parabolicCylinder::firstDer(const SPoint2 &param) const
-{
-  SVector3 du;
-  SVector3 dv;
-  
-  du[0] = 1;
-  du[1] = -(1/(2*focalPoint))*(param[0]-.5);
-  du[2] = 0;
-  
-  dv[0] = 0;
-  dv[1] = 0;
-  dv[2] = 1;
-
-  //ok, now we need to scale and rotate...hmm
-  du = scalePoint(du, scaleFactor);
-  dv = scalePoint(dv, scaleFactor);
-  du = rotatePoint(du, rotation);
-  dv = rotatePoint(dv, rotation);
-  //yeah...that "might" work
-  
-  Pair<SVector3,SVector3> result(du,dv);
-  return result;
-} 
-
-// By convention, we're going to return the normal facing the interior
-// of the parabola
-SVector3 parabolicCylinder::normal(const SPoint2 &param) const
-{	
-  SVector3 n; 
-  Pair<SVector3,SVector3> result = firstDer(param);
-  
-  const SVector3 left = result.left();
-  const SVector3 right = result.right();
-  n = crossprod(left, right);
-  n.normalize();
-  return n;
-}
-
-Range<double> parabolicCylinder::parBounds(int i) const
-{
-  return Range<double>(0, 1);
-}
diff --git a/Geo/projectionFace.h b/Geo/projectionFace.h
deleted file mode 100644
index 251bec9da07373f0c8aebae5688f7574e63a2460..0000000000000000000000000000000000000000
--- a/Geo/projectionFace.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef _PROJECTION_FACE_H_
-#define _PROJECTION_FACE_H_
-
-#include "GFace.h"
-
-/* Specific to the derived classes, we're going to need functions
-   which can be used to easily adjust the parameters of the functions.
-   plus, we're going to have to implement all that stuff in GFace
-   eventually. */
-SVector3 scalePoint(SVector3 p, SVector3 s);
-SVector3 rotatePoint(SVector3 p, SVector3 r);
-
-class projectionFace : public GFace {
- protected:
-  SVector3 rotation; //this vector holds the euler angles at which the surface is rotated
-  SVector3 translation; //this vector holds the location of the reference point in xyz space
-  SVector3 scaleFactor; //this vector holds the scaling factors w.r.t x,y,z
- public:
-  projectionFace(GModel *m, int num);
-  ~projectionFace();
-
-  void rotate(SVector3 rot); //rotates the surface by the euler angles rot
-  void translate(SVector3 trans); //translates the surface by trans
-  void scale(SVector3 sc); //scales the surface along the (local?) x,y,z axes by sc
-  void setScale(SVector3 sc);
-  void setRotation(SVector3 r);
-  void setTranslation(SVector3 t);
-  
-  Range<double> parBounds(int i) const {throw;} 
-  virtual int paramDegeneracies(int dir, double *par) { return 0; }
-  virtual GPoint point(double par1, double par2) const {throw;} 
-  virtual GPoint closestPoint(const SPoint3 & queryPoint) const {throw;}
-  virtual int containsPoint(const SPoint3 &pt) const {throw;}  
-  virtual int containsParam(const SPoint2 &pt) const {throw;} 
-  virtual SVector3 normal(const SPoint2 &param) const {throw;} 
-  virtual Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const {throw;} 
-  virtual GEntity::GeomType geomType() const { return GEntity::ProjectionSurface; }
-  virtual int geomDirection() const { return 1; }
-  virtual bool continuous(int dim) const { return true; }
-  virtual bool periodic(int dim) const { return false; }
-  virtual bool degenerate(int dim) const { return false; }
-  virtual double period(int dir) const {throw;}
-  ModelType getNativeType() const { return UnknownModel; }
-  void * getNativePtr() const {throw;} 
-  virtual bool surfPeriodic(int dim) const {throw;}
-  virtual SPoint2 parFromPoint(const SPoint3 &) const {throw;}  
-};
-
-class parabolicCylinder : public projectionFace {
- protected:
-  double focalPoint; //the length from the vertex to the focal point
- public:
-  parabolicCylinder(GModel *m, int num);
-  ~parabolicCylinder();
-  Range<double> parBounds(int i) const;
-  GPoint point(double par1, double par2) const; 
-  SVector3 normal(const SPoint2 &param) const; 
-  Pair<SVector3,SVector3> firstDer(const SPoint2 &param) const; 
-  SPoint2 parFromPoint(const SPoint3 &) const;
-};
-
-#endif
diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp
index 9af8287a10317241a9aee58a0d02960db980bdfd..dfe90a6d644801a8d70cf229623c2349a594b4f0 100644
--- a/Graphics/Geom.cpp
+++ b/Graphics/Geom.cpp
@@ -1,4 +1,4 @@
-// $Id: Geom.cpp,v 1.130 2007-02-26 08:25:38 geuzaine Exp $
+// $Id: Geom.cpp,v 1.131 2007-07-26 16:28:27 anand Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -408,7 +408,7 @@ public :
 
     if(f->geomType() == GEntity::Plane)
       _drawPlaneGFace(f);
-    else if(f->geomType() == GEntity::ProjectionSurface)
+    else if(f->geomType() == GEntity::ProjectionFace)
       _drawProjectionGFace(f);
     else
       _drawNonPlaneGFace(f);
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 87fb78f7514996ff9fe11107c6afdf3befa0732b..2d61c1af1a9e78ed323ad14339f71d72e4d9df13 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGFace.cpp,v 1.81 2007-07-22 15:47:46 geuzaine Exp $
+// $Id: meshGFace.cpp,v 1.82 2007-07-26 16:28:27 anand Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -811,17 +811,17 @@ bool gmsh2DMeshGenerator ( GFace *gf , bool debug = true)
   // and compute characteristic lenghts using mesh edge spacing
 
   BDS_GeomEntity CLASS_F (1,2);
-   
+
   it = edges.begin();
   while(it != edges.end())
     {
-    if(!(*it)->is_mesh_degenerated()){
-      if (!recover_medge ( m, *it))
-	{
-	  Msg(GERROR,"Face not meshed");
-	  return false;
-	}
-    }
+      if(!(*it)->is_mesh_degenerated()){
+	if (!recover_medge ( m, *it))
+	  {
+	    Msg(GERROR,"Face not meshed");
+	    return false;
+	  }
+      }
       ++it;
     }
   //  Msg(INFO,"Boundary Edges recovered for surface %d",gf->tag());
@@ -1530,7 +1530,7 @@ void meshGFace::operator() (GFace *gf)
 {  
   if(gf->geomType() == GEntity::DiscreteSurface) return;
   if(gf->geomType() == GEntity::BoundaryLayerSurface) return;
-  if(gf->geomType() == GEntity::ProjectionSurface) return;
+  if(gf->geomType() == GEntity::ProjectionFace) return;
 
   // destroy the mesh if it exists
   deMeshGFace dem;
@@ -1602,7 +1602,7 @@ bool shouldRevert(MEdge &reference, std::vector<T*> &elements)
 
 void orientMeshGFace::operator()(GFace *gf)
 {
-  if(gf->geomType() == GEntity::ProjectionSurface) return;
+  if(gf->geomType() == GEntity::ProjectionFace) return;
 
   // surface orientions in OCC are not consistent with the orientation
   // of the bounding edges, so just leave them unchanged:
diff --git a/contrib/FourierModel/BlendOperator.cpp b/contrib/FourierModel/BlendOperator.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..acaafd96013a5e06e53a579c9f8b92c538b0f1df
--- /dev/null
+++ b/contrib/FourierModel/BlendOperator.cpp
@@ -0,0 +1,451 @@
+#include "BlendOperator.h"
+
+bool BlendOperator::GetPointOnPatch_
+(int i, double u, double v, int j, double &x, double &y, double &z)
+{
+  double h = 1.e-8;
+  double tol = 1.e-12;
+
+  u = GetPatch(i)->RescaleU(u);
+  v = GetPatch(i)->RescaleV(v);
+
+  double P[3], d[3];
+  GetPatch(i)->GetProjectionSurface()->F(u,v,P[0],P[1],P[2]);
+  GetPatch(i)->GetProjectionSurface()->GetUnitNormal(u,v,d[0],d[1],d[2]);
+
+  u = GetPatch(i)->UnscaleU(u);
+  v = GetPatch(i)->UnscaleV(v);
+
+  double e1[3],e2[3];
+
+  if (std::abs(1.-std::abs(d[0])) < tol) {
+    e1[0] = 0.;
+    e1[1] = 1.;
+    e1[2] = 0.;
+  }
+  else if (std::abs(1.-std::abs(d[1])) < tol) {
+    e1[0] = 0.;
+    e1[1] = 0.;
+    e1[2] = 1.;
+  }
+  else if (std::abs(1.-std::abs(d[2])) < tol) {
+    e1[0] = 1.;
+    e1[1] = 0.;
+    e1[2] = 0.;
+  }
+  else {
+    e1[0] = - d[1] * d[2];
+    e1[1] = 2 * d[2] * d[0];
+    e1[2] = - d[0] * d[1];
+  }
+  double value = 0.;
+  for (int l=0;l<3;l++)
+    value += e1[l] * e1[l];
+  value = sqrt(value);
+  for (int l=0;l<3;l++)
+    e1[l] /= value;
+
+  e2[0] = d[1] * e1[2] - d[2] * e1[1];
+  e2[1] = d[2] * e1[0] - d[0] * e1[2];
+  e2[2] = d[0] * e1[1] - d[1] * e1[0];
+
+  bool converged = false;
+
+  double R[3];
+  GetPatch(i)->F(u,v,R[0],R[1],R[2]);
+
+  double Qu,Qv;
+  GetPatch(j)->GetProjectionSurface()->
+    OrthoProjectionOnSurface(R[0],R[1],R[2],Qu,Qv);
+
+  Qu = GetPatch(j)->UnscaleU(Qu);
+  Qv = GetPatch(j)->UnscaleV(Qv);
+
+  double Q[3];
+  GetPatch(j)->F(Qu,Qv,Q[0],Q[1],Q[2]);
+
+  int maxTotalIteration = 10;
+  int totalIterationCounter = 0;
+
+  while ((!converged) && (totalIterationCounter < maxTotalIteration)) {
+    totalIterationCounter++;
+    double QminusP[3];
+    for (int l=0;l<3;l++)
+      QminusP[l] = Q[l] - P[l];
+
+    double f[2];
+    f[0] = (QminusP[0] * e1[0] + QminusP[1] * e1[1] + QminusP[2] * e1[2]);
+    f[1] = (QminusP[0] * e2[0] + QminusP[1] * e2[1] + QminusP[2] * e2[2]);
+
+    //printf("(%g,%g) :: f = (%g,%g)\n",u,v,f[0],f[1]);
+
+    if ((std::abs(f[0]) < tol) && (std::abs(f[1]) < tol)) {
+      //bool IsGood = true;
+      
+      bool IsGood = GetPatch(i)->GetProjectionSurface()->
+      OrthoProjectionOnSurface(Q[0],Q[1],Q[2],u,v);
+      if (IsGood) {
+	double RR[3];
+	//printf("(u,v) = (%g,%g); (Qu,Qv) = (%g,%g)\n",u,v,Qu,Qv);
+	u = GetPatch(i)->UnscaleU(u);
+	v = GetPatch(i)->UnscaleV(v);
+	GetPatch(i)->F(u,v,RR[0],RR[1],RR[2]);
+	double dist = 0.;
+	for (int l=0;l<3;l++)
+	  dist += (RR[l] - R[l]) * (RR[l] - R[l]);
+	dist = sqrt(dist);
+	if (dist > 1.e-2)
+	  break;
+	else {
+	  //printf("R = (%g,%g,%g); RR = (%g,%g,%g)\n\n",
+	  // R[0],R[1],R[2],RR[0],RR[1],RR[2]);
+	  converged = true;
+	  x = Q[0]; y = Q[1]; z = Q[2];
+	}
+	converged = true;
+	x = Q[0]; y = Q[1]; z = Q[2];
+      }
+      else
+	break;
+    }
+    else {
+      double QuPlus = Qu + h;
+      double QvPlus = Qv + h;
+      if (GetPatch(j)->_PI->periodic[0] == 1)
+	QuPlus -= std::floor(QuPlus);
+      if (GetPatch(j)->_PI->periodic[1] == 1)
+	QvPlus -= std::floor(QvPlus);
+
+      double QplusU[3], QplusV[3];
+      GetPatch(j)->F(QuPlus,Qv,QplusU[0],QplusU[1],QplusU[2]);
+      GetPatch(j)->F(Qu,QvPlus,QplusV[0],QplusV[1],QplusV[2]);
+
+      double QplusUminusP[3], QplusVminusP[3];
+      for (int l=0;l<3;l++) {
+	QplusUminusP[l] = QplusU[l] - P[l];
+	QplusVminusP[l] = QplusV[l] - P[l];
+      }
+
+      double fuPlus[2], fvPlus[2];
+      fuPlus[0] = (QplusUminusP[0] * e1[0] + QplusUminusP[1] * e1[1] + 
+		   QplusUminusP[2] * e1[2]);
+      fuPlus[1] = (QplusUminusP[0] * e2[0] + QplusUminusP[1] * e2[1] + 
+		   QplusUminusP[2] * e2[2]);
+      fvPlus[0] = (QplusVminusP[0] * e1[0] + QplusVminusP[1] * e1[1] + 
+		   QplusVminusP[2] * e1[2]);
+      fvPlus[1] = (QplusVminusP[0] * e2[0] + QplusVminusP[1] * e2[1] + 
+		   QplusVminusP[2] * e2[2]);
+
+      double D[2][2];
+      D[0][0] = (fuPlus[0] - f[0]) / h;
+      D[0][1] = (fvPlus[0] - f[0]) / h;
+      D[1][0] = (fuPlus[1] - f[1]) / h;
+      D[1][1] = (fvPlus[1] - f[1]) / h;
+
+      double det = D[0][0] * D[1][1] - D[0][1] * D[1][0];
+      double update[2];
+      update[0] = (D[1][1] * f[0] - D[0][1] * f[1]) / det;
+      update[1] = (D[0][0] * f[1] - D[1][0] * f[0]) / det;
+
+      //printf("update = (%g,%g)\n",update[0],update[1]);
+
+      Qu -= update[0];
+      Qv -= update[1];
+
+      //printf("Q1 = (%g,%g)\n",Qu,Qv);
+
+      if (GetPatch(j)->_PI->periodic[0] == 1)
+	Qu -= std::floor(Qu);
+      if (GetPatch(j)->_PI->periodic[1] == 1)
+	Qv -= std::floor(Qv);
+
+      //printf("Q2 = (%g,%g)\n",Qu,Qv);
+
+      GetPatch(j)->F(Qu,Qv,Q[0],Q[1],Q[2]);
+    }
+  }
+    
+  return converged;
+}
+
+bool BlendOperator::E
+(int i, int j, double u, double v, double &x, double &y, double &z)
+{
+  bool found = false;
+
+  if (DoPatchesOverlap(i,j)) {
+    GetPatch(i)->F(u,v,x,y,z);
+    //if (1) {
+    if (IsPointInIntersectionBoundingBox(i,j,x,y,z)) {
+      if (GetPatch(i)->GetProjectionSurface()->GetTag() == 
+	  GetPatch(j)->GetProjectionSurface()->GetTag()) {
+	found = GetPatch(j)->Inverse(x,y,z,u,v);
+      }
+      else {
+	int tag = GetProjectionSurfaceTagForOverlap(i,j);
+	if (GetPatch(i)->GetProjectionSurface()->GetTag() == tag) {
+	  found = GetPointOnPatch_(i,u,v,j,x,y,z);
+	  if (!GetPatch(j)->Inverse(x,y,z,u,v))
+	    found = false;
+	}
+	else if (GetPatch(j)->GetProjectionSurface()->GetTag() == tag) {
+	  found = GetPatch(j)->GetProjectionSurface()->
+	    OrthoProjectionOnSurface(x,y,z,u,v);
+	  if (found) {
+	    u = GetPatch(j)->UnscaleU(u);
+	    v = GetPatch(j)->UnscaleV(v);
+	    double tol = 1.e-12;
+	    if ((u > - tol)&&(u < 1. + tol)&&(v > - tol)&&(v < 1. + tol)) {
+	      found = true;
+	      GetPatch(j)->F(u,v,x,y,z);
+	    }
+	    else
+	      found = false;
+	  }
+	}
+	else {
+	  found = E(i,tag,u,v,x,y,z);
+	  if (found) {
+	    found = GetPatch(tag)->Inverse(x,y,z,u,v);
+	    if (found)
+	      found = E(tag,j,u,v,x,y,z);
+	  }
+	}
+      }
+    }
+  }
+  return found;
+}
+
+double BlendOperator::GetBlendingPou
+(int patchTag, double u, double v)
+{
+  double x,y,z;
+  double pouNumerator = GetPatch(patchTag)->GetPou(u,v);
+
+  double pouDenominator = 0.;
+  for (int otherPatchTag = 0;otherPatchTag < patch_.size();otherPatchTag++) {
+    if (E(patchTag,otherPatchTag,u,v,x,y,z)) {
+      double uu,vv;
+      GetPatch(otherPatchTag)->Inverse(x,y,z,uu,vv);
+      if (GetPatch(otherPatchTag)->Inverse(x,y,z,uu,vv)) {
+	pouDenominator += GetPatch(otherPatchTag)->GetPou(uu,vv);
+      }
+    }
+  }
+  if (pouDenominator)
+    return pouNumerator / pouDenominator;
+  else {
+    printf("%d(%g,%g) :: %g %g\n",patchTag,u,v,pouNumerator,pouDenominator);
+    return 1.;
+  }
+}
+
+Patch* BlendOperator::GetPatch
+(int tag) {
+  for (int i=0;i<patch_.size();i++) {
+    if (patch_[i]->GetTag() == tag)
+      return patch_[i];
+  }
+}
+
+ProjectionSurface* BlendOperator::GetProjectionSurface
+(int tag) {
+  for (int i=0;i<ps_.size();i++) {
+    if (ps_[i]->GetTag() == tag)
+      return ps_[i];
+  }
+}
+
+bool BlendOperator::DoPatchesOverlap
+(int patchTag1, int patchTag2) {
+  bool result;
+  if (overlapChart_[patchTag1][patchTag2]->doesIntersect)
+    result = true;
+  else 
+    result = false;
+  
+  return result;
+}
+
+int BlendOperator::GetProjectionSurfaceTagForOverlap
+(int patchTag1, int patchTag2) {
+  return overlapChart_[patchTag1][patchTag2]->psTag;
+}
+
+bool BlendOperator::IsPointInIntersectionBoundingBox
+(int patchTag1, int patchTag2, double x, double y, double z) {
+  bool result = true;
+  double tol = 1.e-2;
+  double xMin = overlapChart_[patchTag1][patchTag2]->xMin - tol;
+  double xMax = overlapChart_[patchTag1][patchTag2]->xMax + tol;
+  double yMin = overlapChart_[patchTag1][patchTag2]->yMin - tol;
+  double yMax = overlapChart_[patchTag1][patchTag2]->yMax + tol;
+  double zMin = overlapChart_[patchTag1][patchTag2]->zMin - tol;
+  double zMax = overlapChart_[patchTag1][patchTag2]->zMax + tol;
+
+  //printf("%d %d :: %g %g %g :: %g %g %g :: %g %g %g\n",
+  // patchTag1,patchTag2, xMin,x,xMax,yMin,y,yMax,zMin,z,zMax);
+
+  if ((x < xMin)||(x > xMax)||(y < yMin)||(y > yMax)||(z < zMin)||(z > zMax))
+    result = false;
+
+  return result;
+}
+
+int BlendOperator::GetNumPatches
+() { 
+  return patch_.size();
+}
+
+bool BlendOperator::GetPointOnPatch
+(int patchTag, double d[3], double &x, double &y, double &z)
+{
+  double h = 1.e-6;
+  double tol = 1.e-12;
+
+  double P[3], R[3];
+  P[0] = R[0] = x; 
+  P[1] = R[1] = y; 
+  P[2] = R[2] = z;
+
+  double e1[3],e2[3];
+
+  if (std::abs(1.-std::abs(d[0])) < tol) {
+    e1[0] = 0.;
+    e1[1] = 1.;
+    e1[2] = 0.;
+  }
+  else if (std::abs(1.-std::abs(d[1])) < tol) {
+    e1[0] = 0.;
+    e1[1] = 0.;
+    e1[2] = 1.;
+  }
+  else if (std::abs(1.-std::abs(d[2])) < tol) {
+    e1[0] = 1.;
+    e1[1] = 0.;
+    e1[2] = 0.;
+  }
+  else {
+    e1[0] = - d[1] * d[2];
+    e1[1] = 2 * d[2] * d[0];
+    e1[2] = - d[0] * d[1];
+  }
+  double value = 0.;
+  for (int l=0;l<3;l++)
+    value += e1[l] * e1[l];
+  value = sqrt(value);
+  for (int l=0;l<3;l++)
+    e1[l] /= value;
+
+  e2[0] = d[1] * e1[2] - d[2] * e1[1];
+  e2[1] = d[2] * e1[0] - d[0] * e1[2];
+  e2[2] = d[0] * e1[1] - d[1] * e1[0];
+
+  bool converged = false;
+
+  double Qu,Qv;
+  GetPatch(patchTag)->GetProjectionSurface()->
+    OrthoProjectionOnSurface(P[0],P[1],P[2],Qu,Qv);
+
+
+  //printf("Q1 = (%g,%g)\n",Qu,Qv);
+
+  Qu = GetPatch(patchTag)->UnscaleU(Qu);
+  Qv = GetPatch(patchTag)->UnscaleV(Qv);
+
+  if (Qu < 0.)
+    Qu = 0.;
+  if (Qu > 1.)
+    Qu = 1.;
+
+  if (Qv < 0.)
+    Qv = 0.;
+  if (Qv > 1.)
+    Qv = 1.;
+
+  double Q[3];
+  GetPatch(patchTag)->F(Qu,Qv,Q[0],Q[1],Q[2]);
+      
+  int maxTotalIteration = 10;
+  int totalIterationCounter = 0;
+
+  while ((!converged) && (totalIterationCounter < maxTotalIteration)) {
+    totalIterationCounter++;
+    double QminusP[3];
+    for (int l=0;l<3;l++)
+      QminusP[l] = Q[l] - P[l];
+
+    double f[2];
+    f[0] = (QminusP[0] * e1[0] + QminusP[1] * e1[1] + QminusP[2] * e1[2]);
+    f[1] = (QminusP[0] * e2[0] + QminusP[1] * e2[1] + QminusP[2] * e2[2]);
+
+    //printf("Q2 = (%g,%g) -> %g -> %g\n",Qu,Qv,f[0],f[1]);
+
+    if ((std::abs(f[0]) < tol) && (std::abs(f[1]) < tol)) {
+      //printf("here too\n");
+      converged = true;
+      for (int l=0;l<3;l++)
+	R[l] = Q[l];
+    }
+    else {
+      double QuPlus = Qu + h;
+      double QvPlus = Qv + h;
+      if (GetPatch(patchTag)->_PI->periodic[0] == 1)
+	QuPlus -= std::floor(QuPlus);
+      if (GetPatch(patchTag)->_PI->periodic[1] == 1)
+	QvPlus -= std::floor(QvPlus);
+      
+      double QplusU[3], QplusV[3];
+      GetPatch(patchTag)->F(QuPlus,Qv,QplusU[0],QplusU[1],QplusU[2]);
+      GetPatch(patchTag)->F(Qu,QvPlus,QplusV[0],QplusV[1],QplusV[2]);
+      
+      double QplusUminusP[3], QplusVminusP[3];
+      for (int l=0;l<3;l++) {
+	QplusUminusP[l] = QplusU[l] - P[l];
+	QplusVminusP[l] = QplusV[l] - P[l];
+      }
+      
+      double fuPlus[2], fvPlus[2];
+      fuPlus[0] = (QplusUminusP[0] * e1[0] + QplusUminusP[1] * e1[1] + 
+		   QplusUminusP[2] * e1[2]);
+      fuPlus[1] = (QplusUminusP[0] * e2[0] + QplusUminusP[1] * e2[1] + 
+		   QplusUminusP[2] * e2[2]);
+      fvPlus[0] = (QplusVminusP[0] * e1[0] + QplusVminusP[1] * e1[1] + 
+		   QplusVminusP[2] * e1[2]);
+      fvPlus[1] = (QplusVminusP[0] * e2[0] + QplusVminusP[1] * e2[1] + 
+		   QplusVminusP[2] * e2[2]);
+      
+      double D[2][2];
+      D[0][0] = (fuPlus[0] - f[0]) / h;
+      D[0][1] = (fvPlus[0] - f[0]) / h;
+      D[1][0] = (fuPlus[1] - f[1]) / h;
+      D[1][1] = (fvPlus[1] - f[1]) / h;
+      
+      double det = D[0][0] * D[1][1] - D[0][1] * D[1][0];
+      double update[2];
+      update[0] = (D[1][1] * f[0] - D[0][1] * f[1]) / det;
+      update[1] = (D[0][0] * f[1] - D[1][0] * f[0]) / det;
+      
+      //printf("update = (%g,%g)\n",update[0],update[1]);
+      
+      Qu -= update[0];
+      Qv -= update[1];
+      
+      //printf("Q1 = (%g,%g)\n",Qu,Qv);
+      
+      //if (GetPatch(patchTag)->_PI->periodic[0] == 1)
+      //Qu -= std::floor(Qu);
+      //if (GetPatch(patchTag)->_PI->periodic[1] == 1)
+      //Qv -= std::floor(Qv);
+      
+      //printf("Q2 = (%g,%g)\n",Qu,Qv);
+      
+      GetPatch(patchTag)->F(Qu,Qv,Q[0],Q[1],Q[2]);
+    }
+  }
+  x = R[0];
+  y = R[1];
+  z = R[2];
+  return converged;
+}
diff --git a/contrib/FourierModel/BlendOperator.h b/contrib/FourierModel/BlendOperator.h
new file mode 100755
index 0000000000000000000000000000000000000000..db8b1f593a254c4687102b0a26b942ab5df13401
--- /dev/null
+++ b/contrib/FourierModel/BlendOperator.h
@@ -0,0 +1,56 @@
+#ifndef _BLEND_OPERATOR_H_
+#define _BLEND_OPERATOR_H_
+
+#include <vector>
+#include "FM_Info.h"
+#include "Patch.h"
+#include "ProjectionSurface.h"
+
+class BlendOperator {
+ private:
+  std::vector<Patch*> patch_;
+  std::vector<ProjectionSurface*> ps_;
+  std::vector<std::vector<OverlapInfo*> > overlapChart_;
+  
+  bool GetPointOnPatch_
+    (int i, double u, double v, int j, double &x, double &y, double &z);
+  
+ protected:
+
+ public:
+  BlendOperator
+    (std::vector<Patch*> patch,std::vector<ProjectionSurface*> ps,
+     std::vector<std::vector<OverlapInfo*> > overlapChart) :
+      patch_(patch), ps_(ps), overlapChart_(overlapChart) {}
+
+  ~BlendOperator() {}
+
+  int GetNumPatches
+    ();
+
+  Patch* GetPatch
+    (int tag);
+
+  ProjectionSurface* GetProjectionSurface
+    (int tag);
+
+  bool DoPatchesOverlap
+    (int patchTag1, int patchTag2);
+
+  int GetProjectionSurfaceTagForOverlap
+    (int patchTag1, int patchTag2);
+
+  bool IsPointInIntersectionBoundingBox
+    (int patchTag1, int patchTag2, double x, double y, double z);
+
+  bool E
+    (int i, int j, double u, double v, double &x, double &y, double &z);
+
+  double GetBlendingPou
+    (int patchTag, double u, double v);
+
+  bool GetPointOnPatch
+    (int patchTag, double d[3], double &x, double &y, double &z);
+};
+
+#endif
diff --git a/contrib/FourierModel/BlendedPatch.cpp b/contrib/FourierModel/BlendedPatch.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..ecfeb0e323c64d4673239b3d04fa1e442c1309aa
--- /dev/null
+++ b/contrib/FourierModel/BlendedPatch.cpp
@@ -0,0 +1,878 @@
+#include "BlendedPatch.h"
+
+BlendedPatch::BlendedPatch
+(Patch* patch, BlendOperator* blendOp) 
+  : _coeffData(0),_coeffDerivU(0),_coeffDerivV(0),
+    _coeffDerivUU(0),_coeffDerivVV(0),_coeffDerivUV(0)
+{
+  patch_ = patch;
+  blendOp_ = blendOp;
+
+  patchTag_ = patch_->GetTag();
+  nPatches_ = blendOp_->GetNumPatches();
+
+  _derivative = patch_->GetDerivativeBitField();
+
+  _uM = patch_->GetUModes();
+  _vM = patch_->GetVModes();
+ 
+  _periodU = patch_->IsUPeriodic() ? 1. : 2.;
+  _periodV = patch_->IsVPeriodic() ? 1. : 2.;
+
+  IsUPeriodic = false;
+  IsVPeriodic = false;
+
+  _uM = 32;
+  _vM = 32;
+
+  //printf("%d %d\n",_uM,_vM);
+
+  if (IsUPeriodic) {
+    if ((_uM % 2) == 0) {
+      _uMLower = - _uM/2;
+      _uMUpper = _uM/2 - 1;
+    }
+    else {
+      _uMLower = - (_uM - 1)/2;
+      _uMUpper = (_uM - 1)/2;
+    }
+  }
+  else {
+    _uMLower = 0;
+    _uMUpper = _uM;
+  }
+  if (IsVPeriodic) {
+    if ((_vM % 2) == 0) {
+      _vMLower = - _vM/2;
+      _vMUpper = _vM/2 - 1;
+    }
+    else {
+      _vMLower = - (_vM - 1)/2;
+      _vMUpper = (_vM - 1)/2;
+    }
+  }
+  else {
+    _vMLower = 0;
+    _vMUpper = _vM;    
+  }
+
+  if (_derivative)
+    _ProcessSeriesCoeff();
+
+  /*
+  for (int j = 0; j < _uM; j++) {
+    for (int k = 0; k < _vM; k++)
+      printf("%g ",_coeffData[j][k].real());
+    printf("\n\n");
+  }
+  printf("\n");
+  */
+
+  // Check if we need to interpolate the derivative(s)
+  if(_derivative){
+    // Initialize _fineDeriv and _fineDeriv2 to zero
+    if(_derivative & 1){
+      _coeffDerivU = new std::complex<double>*[_uM];
+      _coeffDerivV = new std::complex<double>*[_uM];
+      for(int j = 0; j < _uM; j++){
+        _coeffDerivU[j] = new std::complex<double>[_vM];
+        _coeffDerivV[j] = new std::complex<double>[_vM];
+        for(int k = 0; k < _vM; k++){
+          _coeffDerivU[j][k] = 0.;
+          _coeffDerivV[j][k] = 0.;
+        }
+      }
+    }
+
+    if(_derivative & 2){
+      _coeffDerivUU = new std::complex<double>*[_uM];
+      _coeffDerivVV = new std::complex<double>*[_uM];
+      _coeffDerivUV = new std::complex<double>*[_uM];
+      for(int j = 0; j < _uM; j++){
+        _coeffDerivUU[j] = new std::complex<double>[_vM];
+        _coeffDerivVV[j] = new std::complex<double>[_vM];
+        _coeffDerivUV[j] = new std::complex<double>[_vM];
+        for(int k = 0; k < _vM; k++){
+          _coeffDerivUU[j][k] = 0.;
+          _coeffDerivVV[j][k] = 0.;
+          _coeffDerivUV[j][k] = 0.;
+        }
+      }
+    }
+
+    // Copy the Fourier coefficients into _coeffDeriv and _coeffDeriv2
+    std::complex<double> I(0., 1.);
+    for(int j = _uM - 1; j >= 0; j--){
+      for(int k = _vM - 1; k >= 0; k--){
+        if(_derivative & 1){
+	  if (IsUPeriodic) {
+	    int J = j+_uMLower;
+	    _coeffDerivU[j][k] = (2 * M_PI * J * I / _periodU) *
+	      _coeffData[j][k];
+	  }
+	  else {
+	    if (j == _uM - 1)
+	      _coeffDerivU[j][k] = 0.;
+	    else if (j == _uM - 2)
+	      _coeffDerivU[j][k] = 2. * (double)(j + 1) * _coeffData[j + 1][k];
+	    else
+	      _coeffDerivU[j][k] = _coeffDerivU[j + 2][k] +
+		2. * (double)(j + 1) * _coeffData[j + 1][k];
+	    //if (j != 0)
+	    //_coeffDerivU[j][k] *= 2.;
+	  }
+	  if (IsVPeriodic) {
+	    int K = k+_vMLower;
+	    _coeffDerivV[j][k] = (2 * M_PI * K * I / _periodV) *
+	      _coeffData[j][k];
+	  }
+	  else {
+	    if (k == _vM - 1)
+	      _coeffDerivV[j][k] = 0.;
+	    else if (k == _vM - 2)
+	      _coeffDerivV[j][k] = 2. * (double)(k + 1) * _coeffData[j][k + 1];
+	    else
+	      _coeffDerivV[j][k] = _coeffDerivV[j][k + 2] +
+		2. * (double)(k + 1) * _coeffData[j][k + 1];
+	    //if (k != 0)
+	    //_coeffDerivV[j][k] *= 2.;
+	  }
+        }
+      }
+    }
+    for (int j = 0; j < _uM; j++) {
+      for (int k = 0; k < _vM; k++) {
+	if (_derivative & 1) {
+	  if (!IsUPeriodic) {
+	    if (j != 0) {
+	      _coeffDerivU[j][k] *= 2.;
+	    }
+	  }
+	  if (!IsVPeriodic) {
+	    if (k != 0) {
+	      _coeffDerivV[j][k] *= 2.;
+	    }
+	  }
+	}
+      }
+    }
+    for(int j = _uM - 1; j >= 0; j--) {
+      for(int k = _vM - 1; k >= 0; k--) {
+        if(_derivative & 2) {
+	  if (IsUPeriodic) {
+	    int J = j+_uMLower;
+	    _coeffDerivUU[j][k] = (2 * M_PI * J * I / _periodU) * 
+	      _coeffDerivU[j][k];
+	  }
+	  else {
+	    if (j == _uM - 1)
+	      _coeffDerivUU[j][k] = 0.;
+	    else if (j == _uM - 2)
+	      _coeffDerivUU[j][k] = 2. * (double)(j + 1) * 
+		_coeffDerivU[j + 1][k];
+	    else
+	      _coeffDerivUU[j][k] = _coeffDerivUU[j + 2][k] +
+		2. * (double)(j + 1) * _coeffDerivU[j + 1][k];
+	    //if (j != 0)
+	    //_coeffDerivUU[j][k] *= 2.;
+	  }
+	  if (IsVPeriodic) {
+	    int K = k+_vMLower;
+	    _coeffDerivVV[j][k] = (2 * M_PI * K * I / _periodV) * 
+	      _coeffDerivV[j][k];
+	    _coeffDerivUV[j][k] = (2 * M_PI * K * I / _periodV) * 
+	      _coeffDerivU[j][k];
+	  }
+	  else {
+	    if (k == _vM - 1) {
+	      _coeffDerivVV[j][k] = 0.;
+	      _coeffDerivUV[j][k] = 0.;
+	    }
+	    else if (k == _vM - 2) {
+	      _coeffDerivVV[j][k] = 2. * (double)(k + 1) * 
+		_coeffDerivV[j][k + 1];
+	      _coeffDerivUV[j][k] = 2. * (double)(k + 1) * 
+		_coeffDerivU[j][k + 1];
+	    }
+	    else {
+	      _coeffDerivVV[j][k] = _coeffDerivVV[j][k + 2] +
+		2. * (double)(k + 1) * _coeffDerivV[j][k + 1];
+	      _coeffDerivUV[j][k] = _coeffDerivUV[j][k + 2] +
+		2. * (double)(k + 1) * _coeffDerivU[j][k + 1];
+	      //if (k != 0) {
+	      //_coeffDerivVV[j][k] *= 2.;
+	      //_coeffDerivUV[j][k] *= 2.;
+	      //}
+	    }
+	  }
+        }
+      }
+    }
+    for (int j = 0; j < _uM; j++) {
+      for (int k = 0; k < _vM; k++) {
+	if (_derivative & 2) {
+	  if (!IsUPeriodic && IsVPeriodic) {
+	    if (j != 0) {
+	      _coeffDerivUU[j][k] *= 2.;
+	    }
+	  }
+	  if (IsUPeriodic && !IsVPeriodic) {
+	    if (k != 0) {
+	      _coeffDerivVV[j][k] *= 2.;
+	      _coeffDerivUV[j][k] *= 2.;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  // Initialize interpolation variables
+  _tmpCoeff = std::vector< std::complex<double> >(_vM);
+  _tmpInterp = std::vector< std::complex<double> >(_uM);
+}
+
+BlendedPatch::~BlendedPatch()
+{
+  for(int j = 0; j < _uM; j++)
+    delete [] _coeffData[j];
+  delete [] _coeffData;
+
+  if(_coeffDerivU){
+    for(int j = 0; j < _uM; j++)
+      delete [] _coeffDerivU[j];
+    delete [] _coeffDerivU;
+  }
+  if(_coeffDerivV){
+    for(int j = 0; j < _uM; j++)
+      delete [] _coeffDerivV[j];
+    delete [] _coeffDerivV;
+  }
+  if(_coeffDerivUU){
+    for(int j = 0; j < _uM; j++)
+      delete [] _coeffDerivUU[j];
+    delete [] _coeffDerivUU;
+  }
+  if(_coeffDerivVV){
+    for(int j = 0; j < _uM; j++)
+      delete [] _coeffDerivVV[j];
+    delete [] _coeffDerivVV;
+  }
+  if(_coeffDerivUV){
+    for(int j = 0; j < _uM; j++)
+      delete [] _coeffDerivUV[j];
+    delete [] _coeffDerivUV;
+  }
+}
+
+int BlendedPatch::_forwardSize = 0;
+int BlendedPatch::_backwardSize = 0;
+fftw_plan BlendedPatch::_forwardPlan;
+fftw_plan BlendedPatch::_backwardPlan;
+fftw_complex *BlendedPatch::_forwardData = 0;
+fftw_complex *BlendedPatch::_backwardData = 0;
+
+void BlendedPatch::_SetForwardPlan(int n)
+{
+  if(n != _forwardSize){
+    if(_forwardSize){
+      fftw_destroy_plan(_forwardPlan);
+      fftw_free(_forwardData);
+    }
+    _forwardSize = n;
+    _forwardData = 
+      (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * _forwardSize);
+    _forwardPlan = 
+      fftw_plan_dft_1d(_forwardSize, _forwardData, _forwardData,
+		       FFTW_FORWARD, FFTW_ESTIMATE);
+  }
+}
+
+void BlendedPatch::_SetBackwardPlan(int n)
+{
+  if(n != _backwardSize){
+    if(_backwardSize){
+      fftw_destroy_plan(_backwardPlan);
+      fftw_free(_backwardData);
+    }
+    _backwardSize = n;
+    _backwardData = 
+      (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * _backwardSize);
+    _backwardPlan = 
+      fftw_plan_dft_1d(_backwardSize, _backwardData, _backwardData,
+		       FFTW_BACKWARD, FFTW_ESTIMATE);
+  }
+}
+
+void BlendedPatch::_ForwardFft(int n, std::complex<double> *fftData)
+{
+  // Initialize fftw plan and array (ignoring the last element of
+  // fftData, which should just be the periodic extension)
+  _SetForwardPlan(n - 1);
+  for(int i = 0; i < n - 1; i++){
+    _forwardData[i][0] = fftData[i].real();
+    _forwardData[i][1] = fftData[i].imag();
+  }
+
+  // Perform forward FFT
+  fftw_execute(_forwardPlan);
+
+  // Copy data back into fftData and scale by 1/(n - 1)
+  double s = 1. / (double)(n - 1);
+  for(int i = 0; i < n - 1; i++)
+    fftData[i] = 
+      s * std::complex<double>(_forwardData[i][0], _forwardData[i][1]);
+}
+
+void BlendedPatch::_BackwardFft(int n, std::complex<double> *fftData)
+{
+  // Initialize fftw plan and array (ignoring last element of fftData)
+  _SetBackwardPlan(n - 1);
+  for(int i = 0; i < n - 1; i++){
+    _backwardData[i][0] = fftData[i].real();
+    _backwardData[i][1] = fftData[i].imag();
+  }
+
+  // Perform backward FFT
+  fftw_execute(_backwardPlan);
+
+  // Copy data back into fftData
+  for(int i = 0; i < n - 1; i++)
+    fftData[i] = 
+      std::complex<double>(_backwardData[i][0], _backwardData[i][1]);
+
+  // Fill in last element with copy of first element
+  fftData[n - 1] = fftData[0];
+}
+
+void BlendedPatch::_ProcessSeriesCoeff()
+{
+  _coeffData = new std::complex<double>*[_uM];
+  for(int j = 0; j < _uM; j++) {
+    _coeffData[j] = new std::complex<double>[_vM];
+    for(int k = 0; k < _vM; k++)
+      _coeffData[j][k] = 0.;
+  }
+  if (IsUPeriodic) {
+    std::vector<double> u(_uM), v(_vM + 1);
+    for (int j = 0; j < _uM; j++)
+      u[j] = (double)j / (double)(_uM-1);
+    for (int j = 0; j < _vM + 1; j++)
+      v[j] = (double)j / (double)_vM;
+
+    std::complex<double> **dataU = new std::complex<double> *[_vM];
+    for (int k = 0; k < _vM; k++)
+      dataU[k] = new std::complex<double> [_uM];
+    std::complex<double> *dataV = new std::complex<double>[2*_vM + 1];
+    for (int j = 0; j < _uM - 1; j++) {
+      for (int k = 0; k < _vM + 1; k++) {
+	
+	double X,Y,Z,pX,pY,pZ,nX,nY,nZ;
+	F(u[j],0.5 * cos(M_PI * v[k]) + 0.5,X,Y,Z);
+	patch_->GetProjectionSurface()->
+	  F(patch_->RescaleU(u[j]),
+	    patch_->RescaleV(0.5 * cos(M_PI * v[k]) + 0.5),pX,pY,pZ);
+	patch_->GetProjectionSurface()->GetUnitNormal
+	  (patch_->RescaleU(u[j]),
+	   patch_->RescaleV(0.5 * cos(M_PI * v[k]) + 0.5),nX,nY,nZ);
+	dataV[k] = (X-pX)*nX + (Y-pY)*nY + (Z-pZ)*nZ;
+	
+	//dataV[k] = (0.5 * cos(M_PI * u[j]) + 0.5) * 
+	//(0.5 * cos(M_PI * v[k]) + 0.5);
+     }
+
+      for (int k = 1; k < _vM+1; k++)
+	dataV[_vM + k] = dataV[_vM -k];
+      _BackwardFft(2*_vM + 1, dataV);
+      dataU[0][j] = 0.5 * dataV[0] / (double)_vM;
+      for (int k=1; k<_vM-1; k++)
+	dataU[k][j] = dataV[k] / (double)_vM;
+      dataU[_vM-1][j] = 0.5 * dataV[_vM-1] / (double)_vM;
+    }
+    
+    for (int k = 0; k < _vM; k++) {
+      dataU[k][_uM - 1] = dataU[k][0];
+      _ForwardFft(_uM, dataU[k]);
+    }
+
+    for (int j = _uMLower; j <= _uMUpper; j++) {
+      for (int k = 0; k < _vM; k++)
+	if ((j == _uMLower) || (j == _uMUpper))
+	  _coeffData[_uMUpper + j][k] = dataU[k][_uMUpper] / 2.;
+	else if ((j >= 0) && (j < _uMUpper))
+	  _coeffData[_uMUpper + j][k] = dataU[k][j];
+	else
+	  _coeffData[_uMUpper + j][k] = dataU[k][_uM + j -1];
+    }
+    for (int k = 0; k < _vM; k++)
+      delete [] dataU[k];
+    delete [] dataU;
+    delete [] dataV;
+  }
+  else if (IsVPeriodic) {
+    std::vector<double> u(_uM + 1), v(_vM);
+    for (int j = 0; j < _uM + 1; j++)
+      u[j] = (double)j / (double)_uM;
+    for (int j = 0; j < _vM; j++)
+      v[j] = (double)j / (double)(_vM-1);
+
+    std::complex<double> **dataV = new std::complex<double> *[_uM];
+    for (int j = 0; j < _uM; j++)
+      dataV[j] = new std::complex<double> [_vM];
+    std::complex<double> *dataU = new std::complex<double>[2*_uM + 1];
+    for (int k = 0; k < _vM - 1; k++) {
+      for (int j = 0; j < _uM + 1; j++) {
+	double X,Y,Z,pX,pY,pZ,nX,nY,nZ;
+	F(0.5 * cos(M_PI * u[j]) + 0.5,v[k],X,Y,Z);
+	patch_->GetProjectionSurface()->
+	  F(patch_->RescaleU(0.5 * cos(M_PI * u[j]) + 0.5),
+	    patch_->RescaleV(v[k]),pX,pY,pZ);
+	patch_->GetProjectionSurface()->GetUnitNormal
+	  (patch_->RescaleU(u[j]),
+	   patch_->RescaleV(0.5 * cos(M_PI * v[k]) + 0.5),nX,nY,nZ);
+	dataU[j] = (X-pX)*nX + (Y-pY)*nY + (Z-pZ)*nZ;
+      }
+      for (int j = 1; j < _uM+1; j++)
+	dataU[_uM + j] = dataU[_uM -j];
+      _BackwardFft(2*_uM + 1, dataU);
+      dataV[0][k] = 0.5 * dataU[0] / (double)_uM;
+      for (int j=1; j<_uM-1; j++)
+	dataV[j][k] = dataU[j] / (double)_uM;
+      dataV[_uM-1][k] = 0.5 * dataU[_uM-1] / (double)_uM;
+    }
+    for (int j = 0; j < _uM; j++) {
+      dataV[j][_uM - 1] = dataV[j][0];
+      _ForwardFft(_vM, dataV[j]);
+    }
+    for (int k = _vMLower; k <= _vMUpper; k++) {
+      //for (int j = 0; j < _uM - 1; j++) {
+      for (int j = 0; j < _uM; j++)
+	if ((k == _vMLower) || (k == _vMUpper))
+	  _coeffData[j][_vMUpper + k] = dataV[j][_vMUpper] / 2.;
+	else if ((j >= 0) && (j < _vMUpper))
+	  _coeffData[j][_uMUpper + k] = dataV[j][k];
+	else
+	  _coeffData[j][_uMUpper + k] = dataV[j][_uM + k -1];
+    }
+    for (int j = 0; j < _uM; j++)
+      delete [] dataV[j];
+    delete [] dataV;
+    delete [] dataU;
+  }
+  else {
+    std::vector<double> u(_uM + 1), v(_vM + 1);
+    for (int j = 0; j < _uM + 1; j++)
+      u[j] = (double)j / (double)_uM;
+    for (int j = 0; j < _vM + 1; j++)
+      v[j] = (double)j / (double)_vM;
+
+    std::complex<double> **dataU = new std::complex<double> *[_vM];
+    for (int k = 0; k < _vM; k++)
+      dataU[k] = new std::complex<double> [2*_uM + 1];
+
+    std::complex<double> *dataV = new std::complex<double>[2*_vM + 1];
+    for (int j = 0; j < _uM + 1; j++) {
+      for (int k = 0; k < _vM + 1; k++) {
+	/*
+	double X,Y,Z,pX,pY,pZ,nX,nY,nZ;
+	_F(0.5 * cos(M_PI * u[j]) + 0.5,0.5 * cos(M_PI * v[k]) + 0.5,X,Y,Z);
+	patch_->GetProjectionSurface()->
+	  F(patch_->RescaleU(0.5 * cos(M_PI * u[j]) + 0.5),
+	    patch_->RescaleV(0.5 * cos(M_PI * v[k]) + 0.5),pX,pY,pZ);
+	patch_->GetProjectionSurface()->GetUnitNormal
+	  (patch_->RescaleU(0.5 * cos(M_PI * u[j]) + 0.5),
+	   patch_->RescaleV(0.5 * cos(M_PI * v[k]) + 0.5),nX,nY,nZ);
+	dataV[k] = (X-pX)*nX + (Y-pY)*nY + (Z-pZ)*nZ;
+	*/
+	//dataV[k] = (0.5 * cos(M_PI * u[j]) + 0.5) * 
+	//(0.5 * cos(M_PI * v[k]) + 0.5);
+	dataV[k] = (0.5 * cos(M_PI * v[k]) + 0.5);
+      }
+      for (int k = 1; k < _vM+1; k++)
+	dataV[_vM + k] = dataV[_vM - k];
+      _BackwardFft(2*_vM + 1, dataV);
+      dataU[0][j] = 0.5 * dataV[0] / (double)_vM;
+      for (int k=1; k<_vM-1; k++)
+	dataU[k][j] = dataV[k] / (double)_vM;
+      dataU[_vM-1][j] = 0.5 * dataV[_vM-1] / (double)_vM;
+    }
+
+    /*
+    for (int k = 0; k < _vM; k++)
+      for (int j = 0; j < _uM + 1; j++)
+	printf("%d %d -> %g %g\n",k,j,dataU[k][j].real(),dataU[k][j].imag());
+    */
+
+    for (int k = 0; k < _vM; k++) {
+      for (int j = 1; j < _uM+1; j++) {
+	dataU[k][_uM + j] = dataU[k][_uM - k];
+      }
+      _BackwardFft(2*_uM + 1, dataU[k]);
+    }
+
+    for (int j = 0; j < _uM; j++) {
+      for (int k = 0; k < _vM; k++) {
+	if ((j == 0) || (j == _uM - 1))
+	  _coeffData[j][k] = 0.5 * dataU[k][j]/ (double)_uM;
+	else
+	  _coeffData[j][k] = dataU[k][j]/ (double)_uM;
+      }
+    }
+    for (int k = 0; k < _vM; k++)
+      delete [] dataU[k];
+    delete [] dataU;
+    delete [] dataV;
+  }
+}
+
+std::complex<double> BlendedPatch::
+_PolyEval(std::vector< std::complex<double> > _coeff, std::complex<double> x)
+{
+  int _polyOrder = _coeff.size()-1;
+  std::complex<double> out = 0.;
+
+  out = x * _coeff[_polyOrder];
+  for (int i = _polyOrder - 1; i > 0; i--)
+    out = x * (out + _coeff[i]);
+  out = out + _coeff[0];
+
+  return out;
+}
+
+std::complex<double> BlendedPatch::
+  _Interpolate(double u, double v, int uDer, int vDer)
+{
+  //Msg::Info("%d %d %d",uDer,vDer,_derivative);
+  if (((uDer==2 || vDer==2 || (uDer==1 && vDer==1)) && !(_derivative & 2) ) ||
+      ((uDer==1 || vDer==1) && !(_derivative & 1)) ||
+      (uDer<0 || uDer>2 || vDer<0 || vDer>2) ) {
+    Msg::Error("Derivative data not available: check contructor call %d %d %d",
+               uDer,vDer,_derivative);
+    return 0.;
+  }
+
+  double epsilon = 1e-12;
+  if (u < 0. - epsilon || u > 1. + epsilon) {
+    Msg::Error("Trying to interpolate outside interval: (u,v)=(%.16g,%.16g) "
+               "not in [%g,%g]x[%g,%g]", u, v, 0., 1., 0., 1.); 
+  }
+  std::vector<double> uT(_uM,0.);
+  std::vector<double> vT(_vM,0.);
+  if (!IsUPeriodic) {
+    for (int j = 0; j < _uM; j++)
+      if (j == 0)
+	uT[j] = 1.;
+      else if (j == 1)
+	uT[j] = 2. * u - 1;
+      else
+	uT[j] = 2. * uT[1] * uT[j-1] - uT[j-2];
+  }
+  if (!IsVPeriodic) {
+    for (int k = 0; k < _vM; k++)
+      if (k == 0)
+	vT[k] = 1.;
+      else if (k == 1)
+	vT[k] = 2. * v - 1.;
+      else
+	vT[k] = 2. * vT[1] * vT[k-1] - vT[k-2];
+  }
+  // Interpolate to find value at (u,v)
+  for(int j = 0; j < _uM; j++){
+    _tmpInterp[j] = 0.;
+    for(int k = 0; k < _vM; k++){
+      std::complex<double> tmp;
+      if(uDer == 0 && vDer == 0)
+	tmp = _coeffData[j][k];
+      else if(uDer == 1 && vDer == 0)
+	tmp = _coeffDerivU[j][k];
+      else if(uDer == 0 && vDer == 1)
+	tmp = _coeffDerivV[j][k];
+      else if(uDer == 2 && vDer == 0)
+	tmp = _coeffDerivUU[j][k];
+      else if(uDer == 0 && vDer == 2)
+	tmp = _coeffDerivVV[j][k];
+      else
+	tmp = _coeffDerivUV[j][k];
+      _tmpCoeff[k] = tmp;
+    }
+    if (IsVPeriodic) {
+      std::complex<double> y(cos(2 * M_PI * v / _periodV),
+			     sin(2 * M_PI * v / _periodV));
+      _tmpInterp[j] = _PolyEval(_tmpCoeff, y);
+      _tmpInterp[j] *= std::complex<double>
+	(cos(2 * M_PI * _vMLower * v / _periodV),
+	 sin(2 * M_PI * _vMLower * v / _periodV));
+    }
+    else {
+      //printf("i was here 0\n");
+      for(int k = 0; k < _vM; k++)
+	_tmpInterp[j] += _tmpCoeff[k] * vT[k];
+    }
+  }
+  if (IsUPeriodic) {
+    std::complex<double> x(cos(2 * M_PI * u / _periodU),
+			   sin(2 * M_PI * u / _periodU));
+    return _PolyEval(_tmpInterp, x) * std::complex<double>
+      (cos(2 * M_PI * _uMLower * u / _periodU),
+       sin(2 * M_PI * _uMLower * u / _periodU));
+  }
+  else {
+    std::complex<double> tmp = 0.;
+    for(int j = 0; j < _uM; j++)
+      tmp += _tmpInterp[j] * uT[j];
+    return tmp;
+  }
+}
+
+void BlendedPatch::F
+(double u, double v, double &x, double &y, double &z)
+{
+  x = y = z = 0.;
+
+  for (int otherPatchTag_ = 0;otherPatchTag_ < nPatches_; otherPatchTag_++) {
+    double xx, yy, zz;
+    if (blendOp_->E(patchTag_,otherPatchTag_,u,v,xx,yy,zz)) {
+      double uu,vv;
+      blendOp_->GetPatch(otherPatchTag_)->Inverse(xx,yy,zz,uu,vv);
+      double lambda = blendOp_->GetBlendingPou(otherPatchTag_,uu,vv);
+      x += lambda * xx;
+      y += lambda * yy;
+      z += lambda * zz;
+    }
+  }
+}
+
+bool BlendedPatch::Inverse
+(double x, double y, double z, double &u, double &v)
+{
+  bool found = false;
+  int projectionSurfaceTag_;
+  for (int otherPatchTag_ = 0;otherPatchTag_ < nPatches_; otherPatchTag_++) {
+    if (otherPatchTag_ != patchTag_) {
+      if (blendOp_->DoPatchesOverlap(patchTag_,otherPatchTag_)) {
+	if (blendOp_->
+	    IsPointInIntersectionBoundingBox(patchTag_,otherPatchTag_,x,y,z)) {
+	  projectionSurfaceTag_ = blendOp_->
+	    GetProjectionSurfaceTagForOverlap(patchTag_,otherPatchTag_);
+	  found = true;
+	  break;
+	}
+      }
+    }
+  }
+  if (found) {
+    found = blendOp_->GetProjectionSurface(projectionSurfaceTag_)->
+      OrthoProjectionOnSurface(x,y,z,u,v);
+    double xx,yy,zz;
+    blendOp_->GetProjectionSurface(projectionSurfaceTag_)->F(u,v,xx,yy,zz);
+    double d[3];
+    d[0] = x - xx;
+    d[1] = y - yy;
+    d[2] = z - zz;
+    double abs_d = 0.;
+    for (int l=0;l<3;l++)
+      abs_d += d[l] * d[l];
+    abs_d = std::sqrt(abs_d);
+    for (int l=0;l<3;l++)
+      d[l] /= abs_d;
+    found = blendOp_->GetPointOnPatch(patchTag_,d,x,y,z);
+  }
+  found = blendOp_->GetPatch(patchTag_)->Inverse(x,y,z,u,v);
+}
+
+/*
+void BlendedPatch::F
+(double u, double v, double &x, double &y, double &z)
+{
+  if (_derivative) {
+    double px, py, pz, nx, ny, nz, d;
+    
+    u = patch_->RescaleU(u);
+    v = patch_->RescaleV(v);
+    
+    patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+    patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+
+    u = patch_->UnscaleU(u);
+    v = patch_->UnscaleV(v);
+
+    d = _Interpolate(u, v).real();
+    
+    x = px + d * nx;
+    y = py + d * ny;
+    z = pz + d * nz;
+  }
+  else
+    _F(u,v,x,y,z);
+}
+
+bool BlendedPatch::
+Inverse(double x,double y,double z,double &u,double &v)
+{
+  bool result;
+
+  if (_derivative) {
+    result = patch_->GetProjectionSurface()->
+      OrthoProjectionOnSurface(x,y,z,u,v);
+    
+    u = patch_->UnscaleU(u);
+    v = patch_->UnscaleV(v);
+    
+    double tol = 1.e-12;
+    if ((u > - tol) && (u < 1. + tol) && (v > - tol) && (v < 1. + tol))
+      result = true;
+    else
+      result = false;
+  }
+  else
+    result = _Inverse(x,y,z,u,v);
+
+  return result;
+}
+*/
+
+void BlendedPatch::
+Dfdu(double u, double v, double &x, double &y, double &z)
+{
+  double px, py, pz, nx, ny, nz, d;
+  double pxu, pyu, pzu, nxu, nyu, nzu, du;
+
+  u = patch_->RescaleU(u);
+  v = patch_->RescaleV(v);
+
+  patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+  patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+  patch_->GetProjectionSurface()->Dfdu(u,v,pxu,pyu,pzu);
+  patch_->GetProjectionSurface()->Dndu(u,v,nxu, nyu, nzu);
+
+  d = _Interpolate(u, v, 0, 0).real();
+  du = _Interpolate(u, v, 1, 0).real();
+
+  x = pxu + du * nx + d * nxu;
+  y = pyu + du * ny + d * nyu;
+  z = pzu + du * nz + d * nzu;
+}
+
+void BlendedPatch::
+Dfdv(double u, double v, double &x, double &y, double &z)
+{
+  double px, py, pz, nx, ny, nz, d;
+  double pxv, pyv, pzv, nxv, nyv, nzv, dv;
+
+  u = patch_->RescaleU(u);
+  v = patch_->RescaleV(v);
+
+  patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+  patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+  patch_->GetProjectionSurface()->Dfdv(u,v,pxv,pyv,pzv);
+  patch_->GetProjectionSurface()->Dndv(u,v,nxv,nyv,nzv);
+
+  d = _Interpolate(u, v, 0, 0).real();
+  dv = _Interpolate(u, v, 0, 1).real();
+
+  x = pxv + dv * nx + d * nxv;
+  y = pyv + dv * ny + d * nyv;
+  z = pzv + dv * nz + d * nzv;
+}
+
+void BlendedPatch::
+Dfdfdudu(double u, double v, double &x, double &y, double &z)
+{
+  double px, py, pz, nx, ny, nz, d;
+  double pxu, pyu, pzu, nxu, nyu, nzu, du;
+  double pxuu, pyuu, pzuu, nxuu, nyuu, nzuu, duu;
+
+  u = patch_->RescaleU(u);
+  v = patch_->RescaleV(v);
+
+  patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+  patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+  patch_->GetProjectionSurface()->Dfdu(u,v,pxu,pyu,pzu);
+  patch_->GetProjectionSurface()->Dndu(u,v,nxu,nyu,nzu);
+  patch_->GetProjectionSurface()->Dfdfdudu(u,v,pxuu,pyuu,pzuu);
+  patch_->GetProjectionSurface()->Dndndudu(u,v,nxuu,nyuu,nzuu);
+
+  d = _Interpolate(u, v, 0, 0).real();
+  du = _Interpolate(u, v, 1, 0).real();
+  duu = _Interpolate(u, v, 2, 0).real();
+
+  x = pxuu + duu * nx + du * nxu + du * nxu + d * nxuu;
+  y = pyuu + duu * ny + du * nyu + du * nyu + d * nyuu;
+  z = pzuu + duu * nz + du * nzu + du * nzu + d * nzuu;
+}
+
+void BlendedPatch::
+Dfdfdvdv(double u, double v, double &x, double &y, double &z)
+{
+  double px, py, pz, nx, ny, nz, d;
+  double pxv, pyv, pzv, nxv, nyv, nzv, dv;
+  double pxvv, pyvv, pzvv, nxvv, nyvv, nzvv, dvv;
+
+  u = patch_->RescaleU(u);
+  v = patch_->RescaleV(v);
+
+  patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+  patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+  patch_->GetProjectionSurface()->Dfdv(u,v,pxv,pyv,pzv);
+  patch_->GetProjectionSurface()->Dndv(u,v,nxv,nyv,nzv);
+  patch_->GetProjectionSurface()->Dfdfdvdv(u,v,pxvv,pyvv,pzvv);
+  patch_->GetProjectionSurface()->Dndndvdv(u,v,nxvv,nyvv,nzvv);
+
+  d = _Interpolate(u, v, 0, 0).real();
+  dv = _Interpolate(u, v, 0, 1).real();
+  dvv = _Interpolate(u, v, 0, 2).real();
+
+  x = pxvv + dvv * nx + dv * nxv + dv * nxv + d * nxvv;
+  y = pyvv + dvv * ny + dv * nyv + dv * nyv + d * nyvv;
+  z = pzvv + dvv * nz + dv * nzv + dv * nzv + d * nzvv;
+}
+
+void BlendedPatch::
+Dfdfdudv(double u, double v, double &x, double &y, double &z)
+{
+  double px, py, pz, nx, ny, nz, d;
+  double pxu, pyu, pzu, nxu, nyu, nzu, du;
+  double pxv, pyv, pzv, nxv, nyv, nzv, dv;
+  double pxuv, pyuv, pzuv, nxuv, nyuv, nzuv, duv;
+
+  u = patch_->RescaleU(u);
+  v = patch_->RescaleV(v);
+
+  patch_->GetProjectionSurface()->F(u,v,px,py,pz);
+  patch_->GetProjectionSurface()->GetUnitNormal(u,v,nx,ny,nz);
+  patch_->GetProjectionSurface()->Dfdu(u,v,pxu,pyu,pzu);
+  patch_->GetProjectionSurface()->Dndu(u,v,nxu,nyu,nzu);
+  patch_->GetProjectionSurface()->Dfdv(u,v,pxv,pyv,pzv);
+  patch_->GetProjectionSurface()->Dndv(u,v,nxv,nyv,nzv);
+  patch_->GetProjectionSurface()->Dfdfdudv(u,v,pxuv,pyuv,pzuv);
+  patch_->GetProjectionSurface()->Dndndudv(u,v,nxuv,nyuv,nzuv);
+
+  d = _Interpolate(u, v, 0, 0).real();
+  du = _Interpolate(u, v, 1, 0).real();
+  dv = _Interpolate(u, v, 1, 0).real();
+  duv = _Interpolate(u, v, 1, 1).real();
+
+  x = pxuv + duv * nx + du * nxv + dv * nxu + d * nxuv;
+  y = pyuv + duv * ny + du * nyv + dv * nyu + d * nyuv;
+  z = pzuv + duv * nz + du * nzv + dv * nzu + d * nzuv;
+}
+
+double  BlendedPatch::GetPou(double u, double v)
+{
+  double pouU, pouV;
+
+  if (patch_->_PI->hardEdge[3])
+    pouU = OneSidedPartitionOfUnity(0.,1.,u);
+  else if (patch_->_PI->hardEdge[1])
+    pouU = 1. - OneSidedPartitionOfUnity(0.,1.,u);
+  else
+    pouU = PartitionOfUnity(u, 0., 0.3, 0.7, 1.);
+
+  if (patch_->_PI->hardEdge[0])
+    pouV = OneSidedPartitionOfUnity(0.,1.,v);
+  else if (patch_->_PI->hardEdge[2])
+    pouV = 1. - OneSidedPartitionOfUnity(0.,1.,v);
+  else
+    pouV = PartitionOfUnity(v, 0., 0.3, 0.7, 1.);
+
+  return pouU * pouV;
+}
diff --git a/contrib/FourierModel/BlendedPatch.h b/contrib/FourierModel/BlendedPatch.h
new file mode 100755
index 0000000000000000000000000000000000000000..40d0bcf6f57d50e16a59696096b52514cd90dfad
--- /dev/null
+++ b/contrib/FourierModel/BlendedPatch.h
@@ -0,0 +1,100 @@
+#ifndef _BLENDED_PATCH_H_
+#define _BLENDED_PATCH_H_
+
+#include <fftw3.h>
+#include "Message.h"
+#include "Patch.h"
+#include "BlendOperator.h"
+#include "PartitionOfUnity.h"
+
+class BlendedPatch {
+ private:
+  Patch* patch_;
+  BlendOperator* blendOp_;
+
+  int nPatches_;
+  int patchTag_;
+
+  bool IsUPeriodic, IsVPeriodic;
+
+  // bitfield telling if we also interpolate the derivative(s)
+  int _derivative;
+  // Number of Modes in reprocessed Fourier/Chebyshev series
+  int _uM, _vM;
+   // Period Information
+  double _periodU, _periodV;
+  // Limits in the series
+  int _uMLower, _uMUpper, _vMLower, _vMUpper;
+  // data (and its first 2 derivatives)
+  std::complex<double> **_coeffData, **_coeffDerivU, **_coeffDerivV;
+  std::complex<double> **_coeffDerivUU, **_coeffDerivVV, **_coeffDerivUV;
+  // temporary interpolation variables
+  std::vector< std::complex<double> > _tmpCoeff, _tmpInterp;
+  // polynomial evaluator
+  std::complex<double> _PolyEval(std::vector< std::complex<double> > _coeff,
+                                 std::complex<double> x);
+  // interpolation wrapper
+  std::complex<double> _Interpolate(double u,double v,int uDer=0,int vDer=0);
+  // other internal functions
+  void _ProcessSeriesCoeff();
+  // persistent fftw data (used to avoid recomputing the FFTW plans
+  // and reallocating memory every time)
+  static int _forwardSize, _backwardSize;
+  static fftw_plan _forwardPlan, _backwardPlan;
+  static fftw_complex *_forwardData, *_backwardData;
+  void _SetForwardPlan(int n);
+  void _SetBackwardPlan(int n);
+  // This routine computes the forward FFT (ignoring the last element
+  // of the data)
+  void _ForwardFft(int n, std::complex<double> *fftData);
+  // This routine computes the inverse FFT (ignoring the last element
+  // in the array), returns values in entire array (by using the
+  // periodic extension)
+  void _BackwardFft(int n, std::complex<double> *fftData);
+
+ protected:
+
+ public:
+  BlendedPatch(Patch* patch, BlendOperator* blendOp);
+  ~BlendedPatch();
+
+  double GetPou(double u, double v);
+
+  void F
+    (double u, double v, double &x, double &y, double &z);
+
+  bool Inverse
+    (double x,double y,double z,double &u,double &v);
+
+  void Dfdu
+    (double u, double v, double &x, double &y, double &z);
+
+  void Dfdv
+    (double u, double v, double &x, double &y, double &z);
+
+  void Dfdfdudu
+    (double u,double v,double &x,double &y,double &z);
+
+  void Dfdfdudv
+    (double u,double v,double &x,double &y,double &z);
+
+  void Dfdfdvdv
+    (double u,double v,double &x,double &y,double &z);
+
+  void Dndu
+    (double u, double v, double &x, double &y, double &z);
+
+  void Dndv
+    (double u, double v, double &x, double &y, double &z);
+
+  void GetUnitNormal
+    (double u,double v,double &x,double &y,double &z);
+
+  void GetNormal
+    (double u, double v, double &x, double &y, double &z);
+
+  int GetTag
+    () { return patchTag_; }
+};
+
+#endif
diff --git a/contrib/FourierModel/CylindricalProjectionSurface.cpp b/contrib/FourierModel/CylindricalProjectionSurface.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..ba7b49d33bcd2e7af67f5e4facb6054b9eb54b78
--- /dev/null
+++ b/contrib/FourierModel/CylindricalProjectionSurface.cpp
@@ -0,0 +1,220 @@
+#include "CylindricalProjectionSurface.h"
+
+CylindricalProjectionSurface::CylindricalProjectionSurface
+(int tag) : ProjectionSurface(1.)
+{
+  SetTag(tag);
+  SetName(std::string("cylinder"));
+
+  twoPi_ = 2 * M_PI;
+
+  O_[0] = O_[1] = O_[2] = 0.;
+
+  E0_[0] = 0.; E0_[1] = 0.; E0_[2] = 1.;
+  E1_[0] = 1.; E1_[1] = 0.; E1_[2] = 0.;
+  E2_[0] = 0.; E2_[1] = 1.; E2_[2] = 0.;
+
+  scale_[0] = scale_[1] = scale_[2] = 1.;
+}
+
+CylindricalProjectionSurface::CylindricalProjectionSurface
+(int tag, double O[3], double E0[3], double E1[3], double scale[3])
+  : ProjectionSurface(1.)
+{
+  SetTag(tag);
+  SetName(std::string("cylinder"));
+
+  twoPi_ = 2 * M_PI;
+
+  O_[0] = O[0]; O_[1] = O[1]; O_[2] = O[2];
+
+  E0_[0] = E0[0]; E0_[1] = E0[1]; E0_[2] = E0[2];
+  E1_[0] = E1[0]; E1_[1] = E1[1]; E1_[2] = E1[2];
+
+  E2_[0] = E0_[1] * E1_[2] - E0_[2] * E1_[1];
+  E2_[1] = E0_[2] * E1_[0] - E0_[0] * E1_[2];
+  E2_[2] = E0_[0] * E1_[1] - E0_[1] * E1_[0];
+
+  scale_[0] = scale[0]; scale_[1] = scale[1]; scale_[2] = scale[2];
+}
+
+void CylindricalProjectionSurface::
+F(double u, double v, double &x, double &y, double &z)
+{
+  x = O_[0] + E0_[0] * scale_[0] * v;
+  y = O_[1] + E0_[1] * scale_[0] * v;
+  z = O_[2] + E0_[2] * scale_[0] * v;
+  
+  x += E1_[0] * cos(twoPi_ * (u - 0.5)) + 
+    E2_[0] * sin(twoPi_ * (u - 0.5));
+  y += E1_[1] * cos(twoPi_ * (u - 0.5)) +
+    E2_[1] * sin(twoPi_ * (u - 0.5));
+  z += E1_[2] * cos(twoPi_ * (u - 0.5)) +
+    E2_[2] * sin(twoPi_ * (u - 0.5));
+}
+
+bool CylindricalProjectionSurface::
+Inverse(double x, double y, double z, double &u,double &v)
+{
+  double tol =1.e-12;
+
+  double t = (x - O_[0]) * E0_[0] +
+    (y - O_[1]) * E0_[1] +
+    (z - O_[2]) * E0_[2];
+  v = t / scale_[0];
+  double n[3];
+  n[0] = x - (O_[0] + t * E0_[0]);
+  n[1] = y - (O_[1] + t * E0_[1]);
+  n[2] = z - (O_[2] + t * E0_[2]);
+  double norm = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
+  for (int i=0;i<3;i++)
+    n[i] /= norm;
+  u = atan2((n[0]*E2_[0]+n[1]*E2_[1]+n[2]*E2_[2]),
+	    (n[0]*E1_[0]+n[1]*E1_[1]+
+	     n[2]*E1_[2]));
+  u /= twoPi_;
+  u += 0.5;
+
+  if ((u > - tol) && (u < 1. + tol) && (v > - tol) && (v < 1. + tol))
+    return true;
+  else
+    return false;
+}
+
+void CylindricalProjectionSurface::
+Dfdu(double u, double v, double &x, double &y, double &z)
+{
+  x = twoPi_ * 
+    (- E1_[0] * sin(twoPi_ * (u - 0.5)) +
+     E2_[0] * cos(twoPi_ * (u - 0.5)));
+  y = twoPi_ * 
+    (- E1_[1] * sin(twoPi_ * (u - 0.5)) +
+     E2_[1] * cos(twoPi_ * (u - 0.5)));
+  z = twoPi_ * 
+    (- E1_[2] * sin(twoPi_ * (u - 0.5)) +
+     E2_[2] * cos(twoPi_ * (u - 0.5)));
+}
+
+void CylindricalProjectionSurface::
+Dfdv(double u, double v, double &x, double &y, double &z)
+{
+  x = E0_[0] * scale_[0];
+  y = E0_[1] * scale_[0];
+  z = E0_[2] * scale_[0];
+}
+
+void CylindricalProjectionSurface::
+Dfdfdudu(double u,double v, double &x, double &y, double &z)
+{
+  x = -  twoPi_ *  twoPi_ *
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) +
+     E2_[0] * sin(twoPi_ * (u - 0.5)));
+  y = -  twoPi_ *  twoPi_ *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) +
+     E2_[1] * sin(twoPi_ * (u - 0.5)));
+  z = -  twoPi_ *  twoPi_ *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) +
+     E2_[2] * sin(twoPi_ * (u - 0.5)));
+}
+
+void CylindricalProjectionSurface::
+Dfdfdudv(double u, double v, double &x, double &y, double &z)
+{
+  x = y = z = 0.;
+}
+
+void CylindricalProjectionSurface::
+Dfdfdvdv(double u, double v, double &x, double &y, double &z)
+{
+  x = y = z = 0.;
+}
+
+void CylindricalProjectionSurface::
+Dfdfdfdududu(double u,double v,double &x,double &y,double &z)
+{
+  x = twoPi_ *  twoPi_ * twoPi_ *
+    (E1_[0] * sin(twoPi_ * (u - 0.5)) -
+     E2_[0] * cos(twoPi_ * (u - 0.5)));
+  y = twoPi_ *  twoPi_ * twoPi_ *
+    (E1_[1] * sin(twoPi_ * (u - 0.5)) -
+     E2_[1] * cos(twoPi_ * (u - 0.5)));
+  z = twoPi_ *  twoPi_ * twoPi_ *
+    (E1_[2] * sin(twoPi_ * (u - 0.5)) +
+     E2_[2] * cos(twoPi_ * (u - 0.5)));
+}
+
+void CylindricalProjectionSurface::
+Dfdfdfdududv(double u,double v,double &x,double &y,double &z)
+{
+  x = y = z = 0.;
+}
+
+void CylindricalProjectionSurface::
+Dfdfdfdudvdv(double u,double v,double &x,double &y,double &z)
+{
+  x = y = z = 0.;
+}
+
+void CylindricalProjectionSurface::
+Dfdfdfdvdvdv(double u,double v,double &x,double &y,double &z)
+{
+  x = y = z = 0.;
+}
+
+void CylindricalProjectionSurface::
+GetNormal(double u, double v, double &x, double &y, double &z)
+{
+  x = E1_[0] * cos(twoPi_ * (u - 0.5)) + 
+    E2_[0] * sin(twoPi_ * (u - 0.5));
+  y = E1_[1] * cos(twoPi_ * (u - 0.5)) +
+    E2_[1] * sin(twoPi_ * (u - 0.5));
+  z = E1_[2] * cos(twoPi_ * (u - 0.5)) +
+    E2_[2] * sin(twoPi_ * (u - 0.5));
+}
+
+void CylindricalProjectionSurface::
+Dndu(double u, double v, double &x, double &y, double &z)
+{
+  Dfdu(u,v,x,y,z);
+}
+
+void CylindricalProjectionSurface::
+Dndv(double u, double v, double &x, double &y, double &z)
+{
+  Dfdv(u,v,x,y,z);
+}
+
+void CylindricalProjectionSurface::
+Dndndudu(double u, double v, double &x, double &y, double &z)
+{
+  Dfdfdudu(u,v,x,y,z);
+}
+
+void CylindricalProjectionSurface::
+Dndndudv(double u, double v, double &x, double &y, double &z)
+{
+  Dfdfdudv(u,v,x,y,z);
+}
+
+void CylindricalProjectionSurface::
+Dndndvdv(double u, double v, double &x, double &y, double &z)
+{
+  Dfdfdvdv(u,v,x,y,z);
+}
+
+bool CylindricalProjectionSurface::
+OrthoProjectionOnSurface(double x, double y, double z, double &u,double &v)
+{
+  return Inverse(x,y,z,u,v);
+}
+
+void CylindricalProjectionSurface::
+SetParameter(int i, double x)
+{
+}
+
+double CylindricalProjectionSurface::
+GetParameter(int i)
+{
+  return 0.;
+}
diff --git a/contrib/FourierModel/CylindricalProjectionSurface.h b/contrib/FourierModel/CylindricalProjectionSurface.h
new file mode 100755
index 0000000000000000000000000000000000000000..34fc45b58197c823418389726854bf25d50a40ef
--- /dev/null
+++ b/contrib/FourierModel/CylindricalProjectionSurface.h
@@ -0,0 +1,66 @@
+#ifndef _CYLINDRICAL_PROJECTION_SURFACE_H_
+#define _CYLINDRICAL_PROJECTION_SURFACE_H_
+
+#include <cmath>
+#include "ProjectionSurface.h"
+
+class CylindricalProjectionSurface : public ProjectionSurface {
+ private:
+  double twoPi_;
+ public:
+  CylindricalProjectionSurface
+    (int tag);
+  CylindricalProjectionSurface
+    (int tag, double O[3], double E0[3], double E1[3], double scale[3]);
+
+  virtual ~CylindricalProjectionSurface
+    () {}
+
+  // Abstract methods of ProjectionSurface
+
+  virtual void F
+    (double u, double v, double &x, double &y, double &z);
+  virtual bool Inverse
+    (double x,double y,double z,double &u,double &v);
+  virtual void Dfdu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dfdv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dfdfdudu
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdudv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdududu
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdududv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdudvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdvdvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual bool OrthoProjectionOnSurface
+    (double x, double y, double z, double &u,double &v);
+  virtual void SetParameter
+    (int i, double x);
+  virtual double GetParameter
+    (int i);
+
+  // Redefinitions for CylindricalProjectionSurface
+
+  virtual void GetNormal
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndudu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndudv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndvdv
+    (double u, double v, double &x, double &y, double &z);
+};
+
+#endif
diff --git a/contrib/FourierModel/Interpolator1D.cpp b/contrib/FourierModel/Interpolator1D.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..9d51584f438ab64ae0abcab27ea2442687166229
--- /dev/null
+++ b/contrib/FourierModel/Interpolator1D.cpp
@@ -0,0 +1,602 @@
+#include <vector>
+#include <math.h>
+#include <complex>
+#include "Interpolator1D.h"
+
+FftPolyInterpolator1D::FftPolyInterpolator1D(const std::vector<double> &u,
+					     const std::vector< std::complex<double> > &data,
+					     int refineFactor, int polyOrder, int derivative,
+					     bool storeCoefs)
+  : _refineFactor(refineFactor), _polyOrder(polyOrder), _derivative(derivative), 
+    _storeCoefs(storeCoefs), _uFine(0), _fineData(0), _fineDeriv(0), _fineDeriv2(0)
+{
+  _uIntervals = u.size() - 1;
+  _uFineIntervals = _refineFactor * _uIntervals;
+
+  // min/max of input mesh
+  if(u[_uIntervals] > u[0]) {
+    _uMin = u[0];
+    _uMax = u[_uIntervals];
+  } 
+  else {
+    _uMin = u[_uIntervals];
+    _uMax = u[0];
+  }
+
+  // signed length of interval
+  _uLength = u[_uIntervals] - u[0];
+  
+  // Sanity checks
+  if(std::abs(data[0] - data[_uIntervals]) > 1.e-10){
+    Msg::Warning("Data is not periodic: f(%g)=(%.16g,%.16g), f(%g)=(%.16g,%.16g)",
+		 u[0], data[0].real(), data[0].imag(),
+		 u[_uIntervals], data[_uIntervals].real(), data[_uIntervals].imag());
+  }
+  if(fabs(u[1] - u[0]) - fabs(u[2] - u[1]) > 1.e-10){
+    Msg::Fatal("Input grid is not equispaced");
+  }
+  if(_uFineIntervals < _polyOrder){
+    Msg::Fatal("Number of intervals is smaller than polynomial order (%d < %d)",
+	       _uFineIntervals, _polyOrder);
+  }
+
+  // Compute the fine grid spacing (assuming the u grid is equally spaced)
+  _hUFine = (u[1] - u[0]) / _refineFactor;
+
+  // Compute the points on the fine grid
+  _uFine = new double[_uFineIntervals + 1];
+  for(int i = 0; i < _uFineIntervals + 1; i++)
+    _uFine[i] = u[0] + i * _hUFine;
+
+  // Initialize _fineData to zero
+  _fineData = new std::complex<double>[_uFineIntervals + 1];
+  for(int i = 0; i < _uFineIntervals + 1; i++)
+    _fineData[i] = 0.;
+
+  if(_storeCoefs){
+    // number of local interpolating polynomials
+    _nLocPol = 1;
+    int flag = 0;
+    while ((flag + _polyOrder) < (_uFineIntervals + 1)) {
+      _nLocPol++;
+      flag += _polyOrder;
+    }
+    if ((_uFineIntervals + 1 - flag) == 1) _nLocPol--;
+    
+    // local interpolating polynomial coefficients
+    _locpol = new std::complex<double>[_nLocPol * (_polyOrder + 1)];
+    for(int i = 0; i < _nLocPol * (_polyOrder + 1); i++)
+      _locpol[i] = 0.;
+  }
+  
+  std::complex<double> *forwardData = new std::complex<double>[_uIntervals+1];
+
+  if (_refineFactor == 1){ // No Fourier interpolation
+    // Copy data into _fineData
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      _fineData[i] = data[i];
+  }
+  else {
+    // Compute the forward FFT of the one-dimensional data (only uses
+    // data in i=0,...,uIntervals-1 and scales by 1/uIntervals)
+    for(int i = 0; i < _uIntervals + 1; i++)
+      forwardData[i] = data[i];
+    _ForwardFft(_uIntervals + 1, forwardData);
+    
+    // Copy the Fourier coefficients into _fineData
+    int halfIndexU = _uIntervals / 2;
+    for(int i = 0; i < _uIntervals; i++){
+      int iFine = i;
+      if(i > halfIndexU)
+        iFine = _uFineIntervals + (i - _uIntervals);
+      _fineData[iFine] = forwardData[i];
+    }
+
+    // Compute inverse FFT on _fineData to interpolate the data on the
+    // fine grid
+    _BackwardFft(_uFineIntervals + 1, _fineData);
+  }
+
+  // Check if we need to interpolate the derivative(s)
+  if(_derivative){
+    if(_refineFactor == 1){
+      // No Fourier interpolation was performed, so we need to do it here...
+      for(int i = 0; i < _uIntervals + 1; i++)
+	forwardData[i] = data[i];
+      _ForwardFft(_uIntervals + 1, forwardData);
+    }
+
+    // Initialize _fineDeriv and _fineDeriv2 to zero
+    if(_derivative & 1){
+      _fineDeriv = new std::complex<double>[_uFineIntervals + 1];
+      for(int i = 0; i < _uFineIntervals + 1; i++)
+	_fineDeriv[i] = 0.;
+      if(_storeCoefs){
+	// local interpolating polynomial coefficients
+	_locpolDeriv = new std::complex<double>[_nLocPol*(_polyOrder+1)];
+	for(int i = 0; i < _nLocPol*(_polyOrder+1); i++)
+	  _locpolDeriv[i] = 0.;
+      }
+    }
+    if(_derivative & 2){
+      _fineDeriv2 = new std::complex<double>[_uFineIntervals + 1];
+      for(int i = 0; i < _uFineIntervals + 1; i++)
+	_fineDeriv2[i] = 0.;
+      if(_storeCoefs){
+	// local interpolating polynomial coefficients
+	_locpolDeriv2 = new std::complex<double>[_nLocPol*(_polyOrder+1)];
+	for(int i = 0; i < _nLocPol*(_polyOrder+1); i++)
+	  _locpolDeriv2[i] = 0.;
+      }
+    }
+
+    // Copy the Fourier coefficients into _fineDeriv and _fineDeriv2
+    std::complex<double> I(0., 1.);
+    int halfIndexU = _uIntervals / 2;
+    for(int i = 0; i < _uIntervals; i++){
+      int iFine = i;
+      double k = i;
+      if(i > halfIndexU){
+	k = i - _uIntervals;
+	iFine = _uFineIntervals + (i - _uIntervals);
+      }
+      // multiply by (2*pi*i*k) to get the derivative
+      if(_derivative & 1)
+	_fineDeriv[iFine] = (2. * M_PI * k * I) * forwardData[i] / _uLength;
+      // multiply by (2*pi*i*k)^2 to get the second derivative
+      if(_derivative & 2)
+	_fineDeriv2[iFine] = 
+	  -(4. * M_PI * M_PI * k * k) * forwardData[i] / (_uLength * _uLength);
+    }
+
+    // Perform an inverse FFT on _fineDeriv to interpolate the
+    // derivative to the fine grid
+    if(_derivative & 1)
+      _BackwardFft(_uFineIntervals + 1, _fineDeriv);
+    if(_derivative & 2)
+      _BackwardFft(_uFineIntervals + 1, _fineDeriv2);
+  }
+
+  delete [] forwardData;
+
+  if(_storeCoefs){
+    _interPolyCoeff(_locpol, _fineData, _uFineIntervals, _hUFine, _polyOrder);
+    if(_derivative & 1)
+      _interPolyCoeff(_locpolDeriv, _fineDeriv, _uFineIntervals, _hUFine, 
+		      _polyOrder);
+    if(_derivative & 2)
+      _interPolyCoeff(_locpolDeriv2, _fineDeriv2, _uFineIntervals, _hUFine, 
+		      _polyOrder);
+  }
+
+  // Initialize temp interpolation variables
+  _tmpInterp = new double[_polyOrder + 1];
+  _tmpPnts = new double[_polyOrder + 1];
+  _tmpValsReal = new double[_polyOrder + 1];
+  _tmpValsImag = new double[_polyOrder + 1];
+}
+
+FftPolyInterpolator1D::~FftPolyInterpolator1D()
+{
+  delete[] _uFine;
+  delete[] _fineData;
+  if(_storeCoefs)
+    delete[] _locpol;
+  if(_fineDeriv) {
+    delete[] _fineDeriv; 
+    if(_storeCoefs)
+      delete[] _locpolDeriv;
+  }
+  if(_fineDeriv2) {
+    delete[] _fineDeriv2; 
+    if(_storeCoefs)
+      delete[] _locpolDeriv2;
+  }
+  
+  delete[] _tmpInterp;
+  delete[] _tmpPnts; 
+  delete[] _tmpValsReal; 
+  delete[] _tmpValsImag;
+}
+
+int FftPolyInterpolator1D::_forwardSize = 0;
+int FftPolyInterpolator1D::_backwardSize = 0;
+fftw_plan FftPolyInterpolator1D::_forwardPlan;
+fftw_plan FftPolyInterpolator1D::_backwardPlan;
+fftw_complex *FftPolyInterpolator1D::_forwardData = 0;
+fftw_complex *FftPolyInterpolator1D::_backwardData = 0;
+
+void FftPolyInterpolator1D::_SetForwardPlan(int n)
+{
+  if(n != _forwardSize){
+    if(_forwardSize){
+      fftw_destroy_plan(_forwardPlan);
+      fftw_free(_forwardData);
+    }
+    _forwardSize = n;
+    _forwardData = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * _forwardSize);
+    _forwardPlan = fftw_plan_dft_1d(_forwardSize, _forwardData, _forwardData,
+				    FFTW_FORWARD, FFTW_ESTIMATE);
+  }
+}
+
+void FftPolyInterpolator1D::_SetBackwardPlan(int n)
+{
+  if(n != _backwardSize){
+    if(_backwardSize){
+      fftw_destroy_plan(_backwardPlan);
+      fftw_free(_backwardData);
+    }
+    _backwardSize = n;
+    _backwardData = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * _backwardSize);
+    _backwardPlan = fftw_plan_dft_1d(_backwardSize, _backwardData, _backwardData,
+				     FFTW_BACKWARD, FFTW_ESTIMATE);
+  }
+}
+
+void FftPolyInterpolator1D::_ForwardFft(int n, std::complex<double> *fftData)
+{
+  // Initialize fftw plan and array (ignoring the last element of
+  // fftData, which should just be the periodic extension)
+  _SetForwardPlan(n - 1);
+  for(int i = 0; i < n - 1; i++){
+    _forwardData[i][0] = fftData[i].real();
+    _forwardData[i][1] = fftData[i].imag();
+  }
+
+  // Perform forward FFT
+  fftw_execute(_forwardPlan);
+
+  // Copy data back into fftData and scale by 1/(n - 1)
+  double s = 1. / (double)(n - 1);
+  for(int i = 0; i < n - 1; i++)
+    fftData[i] = s * std::complex<double>(_forwardData[i][0], _forwardData[i][1]);
+}
+
+void FftPolyInterpolator1D::_BackwardFft(int n, std::complex<double> *fftData)
+{
+  // Initialize fftw plan and array (ignoring last element of fftData)
+  _SetBackwardPlan(n - 1);
+  for(int i = 0; i < n - 1; i++){
+    _backwardData[i][0] = fftData[i].real();
+    _backwardData[i][1] = fftData[i].imag();
+  }
+
+  // Perform backward FFT
+  fftw_execute(_backwardPlan);
+
+  // Copy data back into fftData
+  for(int i = 0; i < n - 1; i++)
+    fftData[i] = std::complex<double>(_backwardData[i][0], _backwardData[i][1]);
+
+  // Fill in last element with copy of first element
+  fftData[n - 1] = fftData[0];
+}
+
+double FftPolyInterpolator1D::_PolyInterp(double *pnts, double *vals, double t)
+{
+  // Neville's Algorithm from Stoer and Bulirsch, Section 2.1.2
+  for(int i = 0; i <= _polyOrder; i++){
+    _tmpInterp[i] = vals[i];
+    for(int j = i-1; j >= 0; j--)
+      _tmpInterp[j] = _tmpInterp[j+1] +
+        (_tmpInterp[j+1] - _tmpInterp[j]) * (t - pnts[i]) / (pnts[i] - pnts[j]);
+  }
+  return _tmpInterp[0];
+}
+
+std::complex<double> FftPolyInterpolator1D::_Interpolate(double u, int derivative)
+{
+  if((derivative == 1 && !(_derivative & 1)) ||
+     (derivative == 2 && !(_derivative & 2)) ||
+     derivative < 0 || derivative > 2){
+    Msg::Error("Derivative data not available: check constructor call");
+    return 0.;
+  }
+
+  if(u == _uMax)
+    u = _uMin;
+
+  double epsilon = 1e-12;
+  if(u < _uMin - epsilon || u > _uMax + epsilon){
+    Msg::Error("Trying to interpolate outside interval: u=%.16g not in [%g,%g]", 
+	       u, _uMin, _uMax);
+    return 0.;
+  }
+
+  // Choose uIndexStart so that u is centered in the polynomial
+  // interpolation grid
+  int uIndexStart = (int)floor((u - _uFine[0]) / _hUFine) - _polyOrder / 2;
+  if(uIndexStart < 0)
+    uIndexStart = 0;
+  else if((uIndexStart + _polyOrder) > _uFineIntervals)
+    uIndexStart = _uFineIntervals - _polyOrder;
+  
+  // Interpolate to find value at u
+  for(int i = 0; i <= _polyOrder; i++){
+    _tmpPnts[i] = _uFine[uIndexStart + i];
+    if(derivative == 0){
+      _tmpValsReal[i] = _fineData[uIndexStart + i].real();
+      _tmpValsImag[i] = _fineData[uIndexStart + i].imag();
+    }
+    else if(derivative == 1){
+      _tmpValsReal[i] = _fineDeriv[uIndexStart + i].real();
+      _tmpValsImag[i] = _fineDeriv[uIndexStart + i].imag();
+    }
+    else{
+      _tmpValsReal[i] = _fineDeriv2[uIndexStart + i].real();
+      _tmpValsImag[i] = _fineDeriv2[uIndexStart + i].imag();
+    }
+  }
+
+  return std::complex<double>(_PolyInterp(_tmpPnts, _tmpValsReal, u),
+			      _PolyInterp(_tmpPnts, _tmpValsImag, u));
+}
+
+void polyint(double *xa, double *ya, int n, double x, double &y)
+{
+#define ind(ii) ((ii) - 1)
+  int i, m, ns = 1;
+  double dy, den, dif, dift, ho, hp, w;
+ 
+  double *c = new double[n];
+  double *d = new double[n];
+  
+  dif = fabs(x - xa[ind(1)]);
+  for (i = 1; i <= n; i++) {
+    if ((dift = fabs(x - xa[ind(i)])) < dif) {
+      ns = i;
+      dif = dift;
+    }
+    c[ind(i)] = ya[ind(i)];
+    d[ind(i)] = ya[ind(i)];
+  }
+  y = ya[ind(ns--)];
+  for (m = 1; m < n; m++) {
+    for (i = 1; i <= n - m; i++) {
+      ho = xa[ind(i)] - x;
+      hp = xa[ind(i + m)] - x;
+      w = c[ind(i + 1)] - d[ind(i)];
+      if ((den = ho - hp) == 0) {
+	Msg::Error("Error in POLYINT");
+        return;
+      }
+      den = w / den;
+      d[ind(i)] = hp * den;
+      c[ind(i)] = ho * den;
+    }
+    if (2 * ns < (n - m))
+      dy = c[ind(ns + 1)];
+    else {
+      dy = d[ind(ns)];
+      ns--;
+    }
+    y += dy;
+  }
+  delete[] c;
+  delete[] d;
+}
+
+void polcof(double *x, double *y, int n, double *cof)
+{ 
+  int k;
+  double xmin;
+  
+  double *xtemp = new double[n + 1];
+  double *ytemp = new double[n + 1];
+  
+  for (int j = 0; j <= n; j++) {
+    xtemp[j] = x[j];
+    ytemp[j] = y[j];
+  }
+  for (int j = 0; j <= n; j++) {
+    polyint(xtemp, ytemp, n + 1 - j, 0.0, cof[j]);
+    xmin = 1.0e38;
+    k = -1;
+    for (int i = 0; i <= n - j; i++) {
+      if (fabs(xtemp[i]) < xmin) {
+        xmin = fabs(xtemp[i]);
+        k = i;
+      }
+      if (xtemp[i] != 0) ytemp[i] = (ytemp[i] - cof[j]) / xtemp[i];
+    }
+    for (int i = k + 1; i<= n - j; i++) {
+      xtemp[i - 1] = xtemp[i];
+      ytemp[i - 1] = ytemp[i];
+    }
+  }
+  delete[] xtemp;
+  delete[] ytemp;
+}
+
+void getcoeff(double *f,double *x,int n)
+{
+  double *ya = new double[n];
+  double *cof = new double[n];
+
+  for (int i = 0; i < n; i++) {
+    ya[i] = f[i];
+  }
+  polcof(x, ya, n - 1, cof);
+  for (int i = 0; i < n; i++)
+    f[i] = cof[i];
+
+  delete[] ya;
+  delete[] cof;
+}
+
+void FftPolyInterpolator1D::_interPolyCoeff(std::complex<double> *locpol,
+					    std::complex<double> *u,
+					    int rn, double fineh, int npoly)
+{
+  double *x = new double[npoly + 1];
+  double *freal = new double[npoly + 1];
+  double *fimag = new double[npoly + 1];
+  int rem;
+
+  int l = 0;
+  int flag = 0;
+  while ((flag + npoly) < rn) {
+    for (int i = 0; i <= npoly; i++)
+      x[i] = (flag + i) * fineh;
+      for (int i = 0; i <= npoly; i++) {
+	freal[i] = real(u[flag + i]);
+	fimag[i] = imag(u[flag + i]);
+      }
+      getcoeff(freal, x, npoly + 1);
+      getcoeff(fimag, x, npoly + 1);
+      for (int i = 0; i < npoly + 1; i++)
+	locpol[(npoly + 1) * l + i] = std::complex<double>(freal[i], fimag[i]);
+    l++;
+    flag += npoly;
+  }
+
+  rem = rn - flag;
+  if (rem > 1) {
+    for (int i = 0; i <= npoly; i++)
+      x[i] = (flag + i - (npoly + 1) + rem) * fineh;
+    for (int i=0;i<=npoly;i++) {
+      freal[i] = real(u[flag + i - (npoly + 1) + rem]);
+      fimag[i] = imag(u[flag + i - (npoly + 1) + rem]);
+    }
+    getcoeff(freal, x, npoly + 1);
+    getcoeff(fimag, x, npoly + 1);
+    for (int i = 0; i < npoly + 1; i++)
+      locpol[(npoly + 1) * l + i] = std::complex<double>(freal[i], fimag[i]);
+  }
+  
+  delete[] x;
+  delete[] freal;
+  delete[] fimag;
+}
+
+std::complex<double> FftPolyInterpolator1D::_InterpolateFromCoeffs(double u, 
+								   int derivative)
+{
+  if((derivative == 1 && !(_derivative & 1)) ||
+     (derivative == 2 && !(_derivative & 2)) ||
+     derivative < 0 || derivative > 2){
+    Msg::Error("Derivative data not available: check constructor call");
+    return 0.;
+  }
+
+  if(u == _uMax)
+    u = _uMin;
+
+  double epsilon = 1e-12;
+  if(u < _uMin - epsilon || u > _uMax + epsilon){
+    Msg::Error("Trying to interpolate outside interval: u=%.16g not in [%g,%g]", 
+	       u, _uMin, _uMax);
+    return 0.;
+  }
+  
+  std::complex<double> out(0.,0.);
+  
+  // find the polynomial to be used for interpolating at u
+  int l = (int)floor((u - _uFine[0])/(_polyOrder * _hUFine));
+
+  if (derivative == 0) {
+    out = u * _locpol[(_polyOrder + 1) * l + _polyOrder];
+    for (int r = _polyOrder - 1; r > 0; r--)
+      out = u * (out + _locpol[(_polyOrder + 1) * l + r]);
+    out = out + _locpol[(_polyOrder + 1) * l + 0];
+  }
+  else if (derivative == 1) {
+    out = u * _locpolDeriv[(_polyOrder + 1) * l + _polyOrder];
+    for (int r = _polyOrder - 1; r > 0 ; r--)
+      out = u * (out + _locpolDeriv[(_polyOrder + 1) * l + r]);
+    out = out + _locpolDeriv[(_polyOrder + 1) * l + 0];
+  }
+  else if (derivative == 2) {
+    out = u * _locpolDeriv2[(_polyOrder + 1) * l + _polyOrder];
+    for (int r = _polyOrder - 1; r > 0; r--)
+      out = u * (out + _locpolDeriv2[(_polyOrder + 1) * l + r]);
+    out = out + _locpolDeriv2[(_polyOrder + 1) * l + 0];
+  }
+
+  return out;
+}
+
+std::complex<double> FftPolyInterpolator1D::F(double u)
+{
+  if(_storeCoefs) 
+    return _InterpolateFromCoeffs(u, 0);
+  else
+    return _Interpolate(u, 0);
+}
+
+std::complex<double> FftPolyInterpolator1D::Dfdu(double u)
+{
+  if(_storeCoefs) 
+    return _InterpolateFromCoeffs(u, 1);
+  else
+    return _Interpolate(u, 1);
+}
+
+std::complex<double> FftPolyInterpolator1D::Dfdfdudu(double u)
+{
+  if(_storeCoefs) 
+    return _InterpolateFromCoeffs(u, 2);
+  else
+    return _Interpolate(u, 2);
+}
+
+std::complex<double> FftPolyInterpolator1D::Integrate()
+{
+  std::complex<double> value(0., 0.);
+  for(int i = 0; i < _uFineIntervals; i++){
+    value += (0.5 * _fineData[i] + 0.5 * _fineData[i + 1]) * 
+      fabs(_uFine[i + 1] - _uFine[i]);
+  }
+  return value;
+}
+
+FftSplineInterpolator1D::FftSplineInterpolator1D(const std::vector<double> &u,
+						 const std::vector< std::complex<double> > &data,
+						 int refineFactor)
+  : FftPolyInterpolator1D(u, data, refineFactor, 3, 2)
+{
+}
+
+std::complex<double> FftSplineInterpolator1D::_SplineInterp(double *pnts,
+							    std::complex<double> *vals,
+							    std::complex<double> *deriv,
+							    double t)
+{
+  double h = pnts[1] - pnts[0];
+  double a = (pnts[1] - t) / h;
+  double b = (t - pnts[0]) / h;
+  double a1 = a * a * a - a;
+  double b1 = b * b * b - b;
+  double h1 = (h * h) / 6.;
+  return a * vals[0] + b * vals[1] + (a1 * deriv[0] + b1 * deriv[1]) * h1;
+}
+
+std::complex<double> FftSplineInterpolator1D::F(double u)
+{
+  double pnts[2];
+  std::complex<double> vals[2], deriv[2];
+
+  double epsilon = 1e-12;
+  if(u < _uMin - epsilon || u > _uMax + epsilon){
+    Msg::Error("Trying to interpolate outside interval: u=%.16g not in [%g,%g]", 
+	       u, _uMin, _uMax);
+    return 0.;
+  }
+
+  // Get indices of grid points surrounding u
+  int uIndexStart = (int)floor((u - _uFine[0]) / _hUFine);
+  if(uIndexStart < 0)
+    uIndexStart = 0;
+  else if(uIndexStart > _uFineIntervals - 1)
+    uIndexStart = _uFineIntervals - 1;
+
+  pnts[0] = _uFine[uIndexStart];
+  pnts[1] = _uFine[uIndexStart + 1];
+  vals[0] = _fineData[uIndexStart];
+  vals[1] = _fineData[uIndexStart + 1];
+  deriv[0] = _fineDeriv2[uIndexStart];
+  deriv[1] = _fineDeriv2[uIndexStart + 1];
+
+  return _SplineInterp(pnts, vals, deriv, u);
+}
diff --git a/contrib/FourierModel/Interpolator1D.h b/contrib/FourierModel/Interpolator1D.h
new file mode 100755
index 0000000000000000000000000000000000000000..0db89ae1c4224aef0ae9160cdd7ba07a6c0610c9
--- /dev/null
+++ b/contrib/FourierModel/Interpolator1D.h
@@ -0,0 +1,104 @@
+#ifndef _INTERPOLATOR_1D_H_
+#define _INTERPOLATOR_1D_H_
+
+#include <vector>
+#include <complex>
+#include <fftw3.h>
+#include "Message.h"
+
+// The base class for the 1D interpolators
+class Interpolator1D {
+ public:
+  Interpolator1D(){}
+  virtual ~Interpolator1D(){}
+  // interpolates the data at u
+  virtual std::complex<double> F(double u) = 0;
+  // interpolates the first derivative of the data at u
+  virtual std::complex<double> Dfdu(double u) = 0;
+  // interpolates the second derivative of the data at u
+  virtual std::complex<double> Dfdfdudu(double u) = 0;
+};
+
+// FFT + polynomial interpolation on refined grid (assumes that the
+// input grid is equally spaced and the input data is periodic)
+class FftPolyInterpolator1D : public Interpolator1D {
+ private:
+  // refinement factor (e.g. 16; if equal to 1, we just perform
+  // standard piecewise polynomial interpolation, without any FFTs)
+  int _refineFactor;
+  // order of the interpolating polynomial
+  int _polyOrder;
+  // signed length of the interval
+  double _uLength;
+  // temporary interpolation variables
+  double *_tmpInterp, *_tmpPnts, *_tmpValsReal, *_tmpValsImag;
+  // interpolation polynomial coefficients computation routine
+  void _interPolyCoeff(std::complex<double> *locpol, std::complex<double> *u,
+		       int rn,double fineh,int npoly);
+  // 1D polynomial interpolation routine
+  double _PolyInterp(double *pnts, double *vals, double t);
+  // interpolation wrappers
+  std::complex<double> _Interpolate(double u, int derivative=0);
+  std::complex<double> _InterpolateFromCoeffs(double u, int derivative=0);
+  // persistent fftw data (used to avoid recomputing the FFTW plans
+  // and reallocating memory every time)
+  static int _forwardSize, _backwardSize;
+  static fftw_plan _forwardPlan, _backwardPlan;
+  static fftw_complex *_forwardData, *_backwardData;
+  void _SetForwardPlan(int n);
+  void _SetBackwardPlan(int n);
+ protected:
+  // number of intervals in the original and in the refined mesh
+  int _uIntervals, _uFineIntervals;
+  // fine mesh spacing
+  double _hUFine;
+  // min/max of input mesh
+  double _uMin, _uMax;
+  // bitfield telling if we also interpolate the derivative(s)
+  int _derivative;
+  // flag set if we should store the polynomial coefficients
+  bool _storeCoefs;
+  // grid points of the refined mesh
+  double *_uFine;
+  // data (and its first 2 derivatives) on the refined regular grid
+  std::complex<double> *_fineData, *_fineDeriv, *_fineDeriv2;
+  // number of local interpolating polynomials
+  int _nLocPol;
+  // polynomial coefficients
+  std::complex<double> *_locpol, *_locpolDeriv, *_locpolDeriv2;
+  // This routine computes the forward FFT (ignoring the last element
+  // of the data)
+  void _ForwardFft(int n, std::complex<double> *fftData);
+  // This routine computes the inverse FFT (ignoring the last element
+  // in the array), returns values in entire array (by using the
+  // periodic extension)
+  void _BackwardFft(int n, std::complex<double> *fftData);
+ public:
+  FftPolyInterpolator1D(const std::vector<double> &u,
+			const std::vector< std::complex<double> > &data,
+			int refineFactor=16, int polyOrder=3, 
+			int derivative=0, bool storeCoefs=true);
+  ~FftPolyInterpolator1D();
+  virtual std::complex<double> F(double u);
+  virtual std::complex<double> Dfdu(double u);
+  virtual std::complex<double> Dfdfdudu(double u);
+  std::complex<double> Integrate();
+};
+
+// FFT + spline interpolation on refined grid
+class FftSplineInterpolator1D : public FftPolyInterpolator1D {
+ protected:
+  // 1D spline interpolation
+  std::complex<double> _SplineInterp(double *pnts,
+				     std::complex<double> *vals,
+				     std::complex<double> *deriv,
+				     double t);
+ public:
+  FftSplineInterpolator1D(const std::vector<double> &u,
+			  const std::vector< std::complex<double> > &data,
+			  int refineFactor=16);
+  ~FftSplineInterpolator1D(){}
+  virtual std::complex<double> F(double u);
+};
+
+#endif
diff --git a/contrib/FourierModel/Interpolator2D.cpp b/contrib/FourierModel/Interpolator2D.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..422708376cdea7b66341a964477a5eea8a4bc301
--- /dev/null
+++ b/contrib/FourierModel/Interpolator2D.cpp
@@ -0,0 +1,459 @@
+#include <vector>
+#include <math.h>
+#include <complex>
+#include "Interpolator2D.h"
+
+FftPolyInterpolator2D::
+FftPolyInterpolator2D(const std::vector<double> &u, 
+		      const std::vector<double> &v,
+		      const std::vector< std::vector< std::complex<double> > > &data,
+		      int refineFactor, int polyOrder, int derivative)
+  : _refineFactor(refineFactor), _polyOrder(polyOrder), _derivative(derivative),
+    _uFine(0), _vFine(0), _fineData(0), _fineDerivU(0), _fineDerivV(0), 
+    _fineDerivUU(0), _fineDerivVV(0), _fineDerivUV(0)
+{
+  _uIntervals = u.size() - 1;
+  _uFineIntervals = _refineFactor * _uIntervals;
+  _vIntervals = v.size() - 1;
+  _vFineIntervals = _refineFactor * _vIntervals;
+
+  // min/max of input mesh
+  if(u[_uIntervals] > u[0]) {
+    _uMin = u[0];
+    _uMax = u[_uIntervals];
+  } 
+  else {
+    _uMin = u[_uIntervals];
+    _uMax = u[0];
+  }
+  if(v[_vIntervals] > u[0]) {
+    _vMin = v[0];
+    _vMax = v[_vIntervals];
+  } 
+  else {
+    _vMin = u[_vIntervals];
+    _vMax = u[0];
+  }
+
+  // signed length of interval
+  _uLength = u[_uIntervals] - u[0];
+  _vLength = v[_vIntervals] - v[0];
+
+  // Sanity checks
+  if(std::abs(data[0][0] - data[_uIntervals][0]) > 1.e-10 ||
+     std::abs(data[0][0] - data[0][_vIntervals]) > 1.e-10) {
+    Msg::Warning("Data is not periodic");
+  }
+  if(fabs(u[1] - u[0]) - fabs(u[2] - u[1]) > 1.e-10 ||
+     fabs(v[1] - v[0]) - fabs(v[2] - v[1]) > 1.e-10){
+    Msg::Fatal("Input grid is not equispaced");
+  }
+  if((_uFineIntervals < _polyOrder) || (_vFineIntervals < _polyOrder)){
+    Msg::Fatal("Number of intervals is smaller than polynomial order (%d < %d or %d < %d)",
+               _uFineIntervals, _polyOrder, _vFineIntervals, _polyOrder);
+  }
+
+  // Compute the fine grid spacing (assuming the u and v are equally spaced)
+  _hUFine = (u[1] - u[0]) / _refineFactor;
+  _hVFine = (v[1] - v[0]) / _refineFactor;
+  
+  // Compute the points on the fine grid
+  _uFine = new double[_uFineIntervals + 1];
+  for(int i = 0; i < _uFineIntervals + 1; i++)
+    _uFine[i] = u[0] + i * _hUFine;
+  
+  _vFine = new double[_vFineIntervals + 1];
+  for(int i = 0; i < _vFineIntervals + 1; i++)
+    _vFine[i] = v[0] + i * _hVFine;
+  
+  // Initialize _fineData to zero
+  _fineData = new std::complex<double>*[_uFineIntervals + 1];
+  for(int i = 0; i < _uFineIntervals + 1; i++){
+    _fineData[i] = new std::complex<double>[_vFineIntervals + 1];
+    for(int j = 0; j < _vFineIntervals + 1; j++)
+      _fineData[i][j] = 0.;
+  }
+
+  std::complex<double> **forwardData = new std::complex<double>*[_uIntervals + 1];
+  for(int i = 0; i < _uIntervals + 1; i++)
+    forwardData[i] = new std::complex<double>[_vIntervals + 1];
+  
+  if (_refineFactor == 1){ // No Fourier interpolation
+    // Copy data into _fineData
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      for(int j = 0; j < _vFineIntervals + 1; j++)
+	_fineData[i][j] = data[i][j];
+  }
+  else {
+    // Compute the forward FFT of the two dimensional data (only uses
+    // data in i=0,...,uIntervals-1 and j=0,...,vIntervals-1 and
+    // scales by 1/(uIntervals*vIntervals))
+    for(int i = 0; i < _uIntervals + 1; i++)
+      for(int j = 0; j < _vIntervals + 1; j++)
+	forwardData[i][j] = data[i][j];
+    _ForwardFft(_uIntervals + 1, _vIntervals + 1, forwardData);
+    
+    // Copy the Fourier coefficients into _fineData
+    int halfIndexU = _uIntervals / 2;
+    int halfIndexV = _vIntervals / 2;
+    for(int i = 0; i < _uIntervals; i++)
+      for(int j = 0; j < _vIntervals; j++){
+	int iFine = i;
+	int jFine = j;
+	if(i > halfIndexU)
+	  iFine = _uFineIntervals + (i - _uIntervals);
+	if(j > halfIndexV)
+	  jFine = _vFineIntervals + (j - _vIntervals);
+	_fineData[iFine][jFine] = forwardData[i][j];
+      }
+    
+    // Compute inverse FFT on _fineData to interpolate the data on the
+    // fine grid
+    _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineData);
+  }
+
+  // Check if we need to interpolate the derivative(s)
+  if(_derivative){
+    if(_refineFactor == 1){
+      // No Fourier interpolation was performed, so we need to do it here...
+      for(int i = 0; i < _uIntervals + 1; i++)
+	for(int j = 0; j < _vIntervals + 1; j++)
+	  forwardData[i][j] = data[i][j];
+      _ForwardFft(_uIntervals + 1, _vIntervals + 1, forwardData);
+    }
+    
+    // Initialize _fineDeriv and _fineDeriv2 to zero
+    if(_derivative & 1){
+      _fineDerivU = new std::complex<double>*[_uFineIntervals + 1];
+      _fineDerivV = new std::complex<double>*[_uFineIntervals + 1];
+      for(int i = 0; i < _uFineIntervals + 1; i++){
+	_fineDerivU[i] = new std::complex<double>[_vFineIntervals + 1];
+	_fineDerivV[i] = new std::complex<double>[_vFineIntervals + 1];
+	for(int j = 0; j < _vFineIntervals + 1; j++){
+	  _fineDerivU[i][j] = 0.;
+	  _fineDerivV[i][j] = 0.;
+	}
+      }
+    }
+    
+    if(_derivative & 2){
+      _fineDerivUU = new std::complex<double>*[_uFineIntervals + 1];
+      _fineDerivVV = new std::complex<double>*[_uFineIntervals + 1];
+      _fineDerivUV = new std::complex<double>*[_uFineIntervals + 1];
+      for(int i = 0; i < _uFineIntervals + 1; i++){
+	_fineDerivUU[i] = new std::complex<double>[_vFineIntervals + 1];
+	_fineDerivVV[i] = new std::complex<double>[_vFineIntervals + 1];
+	_fineDerivUV[i] = new std::complex<double>[_vFineIntervals + 1];
+	for(int j = 0; j < _vFineIntervals + 1; j++){
+	  _fineDerivUU[i][j] = 0.;
+	  _fineDerivVV[i][j] = 0.;
+	  _fineDerivUV[i][j] = 0.;
+	}
+      }
+    }
+
+    // Copy the Fourier coefficients into _fineDeriv and _fineDeriv2
+    std::complex<double> I(0., 1.);
+    int halfIndexU = _uIntervals / 2;
+    int halfIndexV = _vIntervals / 2;
+    for(int i = 0; i < _uIntervals; i++){
+      for(int j = 0; j < _vIntervals; j++){
+	int iFine = i;
+	int jFine = j;
+	double kU = i;
+	double kV = j;
+	if(i > halfIndexU){
+	  kU = i - _uIntervals;
+	  iFine = _uFineIntervals + (i - _uIntervals);
+	}
+	if(j > halfIndexV){
+	  kV = j - _vIntervals;
+	  jFine = _vFineIntervals + (j - _vIntervals);
+	}
+	if(_derivative & 1){
+	  _fineDerivU[iFine][jFine] = (2. * M_PI * kU * I) * forwardData[i][j] / _uLength;
+	  _fineDerivV[iFine][jFine] = (2. * M_PI * kV * I) * forwardData[i][j] / _vLength;
+	}
+	if(_derivative & 2){
+	  _fineDerivUU[iFine][jFine] = 
+	    -(4. * M_PI * M_PI * kU * kU) * forwardData[i][j] / (_uLength * _uLength);
+	  _fineDerivVV[iFine][jFine] = 
+	    -(4. * M_PI * M_PI * kV * kV) * forwardData[i][j] / (_vLength * _vLength);
+	  _fineDerivUV[iFine][jFine] = 
+	    -(4. * M_PI * M_PI * kU * kV) * forwardData[i][j] / (_uLength * _vLength);
+	}
+      }
+    }
+    
+    // Perform an inverse FFT on _fineDeriv to interpolate the
+    // derivative to the fine grid
+    if(_derivative & 1){
+      _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineDerivU);
+      _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineDerivV);
+    }
+    if(_derivative & 2){
+      _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineDerivUU);
+      _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineDerivVV);
+      _BackwardFft(_uFineIntervals + 1, _vFineIntervals + 1, _fineDerivUV);
+    }
+  }
+
+  for(int i = 0; i < _uIntervals + 1; i++)
+    delete [] forwardData[i];
+  delete [] forwardData;
+
+  // Initialize interpolation variables
+  _tmpSpace = new double[_polyOrder + 1];
+  _tmpValsReal = new double[_polyOrder + 1];
+  _tmpValsImag = new double[_polyOrder + 1];
+  _tmpInterpReal = new double[_polyOrder + 1];
+  _tmpInterpImag = new double[_polyOrder + 1];
+}
+
+FftPolyInterpolator2D::~FftPolyInterpolator2D()
+{
+  delete[] _uFine; 
+  delete[] _vFine; 
+
+  for(int i = 0; i < _uFineIntervals + 1; i++)
+    delete [] _fineData[i];
+  delete [] _fineData;
+
+  if(_fineDerivU){
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      delete [] _fineDerivU[i];
+    delete [] _fineDerivU;
+  }
+  if(_fineDerivV){
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      delete [] _fineDerivV[i];
+    delete [] _fineDerivV;
+  }
+  if(_fineDerivUU){
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      delete [] _fineDerivUU[i];
+    delete [] _fineDerivUU;
+  }
+  if(_fineDerivVV){
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      delete [] _fineDerivVV[i];
+    delete [] _fineDerivVV;
+  }
+  if(_fineDerivUV){
+    for(int i = 0; i < _uFineIntervals + 1; i++)
+      delete [] _fineDerivUV[i];
+    delete [] _fineDerivUV;
+  }
+  
+  delete[] _tmpSpace;
+  delete[] _tmpValsReal;
+  delete[] _tmpValsImag;
+  delete[] _tmpInterpReal;
+  delete[] _tmpInterpImag;
+}
+
+int FftPolyInterpolator2D::_forwardSizeU = 0;
+int FftPolyInterpolator2D::_forwardSizeV = 0;
+int FftPolyInterpolator2D::_backwardSizeU = 0;
+int FftPolyInterpolator2D::_backwardSizeV = 0;
+fftw_plan FftPolyInterpolator2D::_forwardPlan;
+fftw_plan FftPolyInterpolator2D::_backwardPlan;
+fftw_complex *FftPolyInterpolator2D::_forwardData = 0;
+fftw_complex *FftPolyInterpolator2D::_backwardData = 0;
+
+void FftPolyInterpolator2D::_SetForwardPlan(int n, int m)
+{
+  if(n != _forwardSizeU || m != _forwardSizeV){
+    if(_forwardSizeU || _forwardSizeV){
+      fftw_destroy_plan(_forwardPlan);
+      fftw_free(_forwardData);
+    }
+    _forwardSizeU = n;
+    _forwardSizeV = m;
+    _forwardData = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) *
+					      _forwardSizeU * _forwardSizeV);
+    _forwardPlan = fftw_plan_dft_2d(_forwardSizeU, _forwardSizeV, 
+				    _forwardData, _forwardData,
+				    FFTW_FORWARD, FFTW_ESTIMATE);
+  }
+}
+
+void FftPolyInterpolator2D::_SetBackwardPlan(int n, int m)
+{
+  if(n != _backwardSizeU || m != _backwardSizeV){
+    if(_backwardSizeU || _backwardSizeV){
+      fftw_destroy_plan(_backwardPlan);
+      fftw_free(_backwardData);
+    }
+    _backwardSizeU = n;
+    _backwardSizeV = m;
+    _backwardData = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) *
+					      _backwardSizeU * _backwardSizeV);
+    _backwardPlan = fftw_plan_dft_2d(_backwardSizeU, _backwardSizeV, 
+				    _backwardData, _backwardData,
+				    FFTW_BACKWARD, FFTW_ESTIMATE);
+  }
+}
+
+void FftPolyInterpolator2D::_ForwardFft(int n, int m, std::complex<double> **fftData)
+{
+  // Initialize fftw plan and array (ignoring the last row and column
+  // of fftData, which should just be the periodic extension)
+  _SetForwardPlan(n - 1, m - 1);
+  int k = 0;
+  for(int i = 0; i < n - 1; i++){
+    for(int j = 0; j < m - 1; j++){
+      _forwardData[k][0] = fftData[i][j].real();
+      _forwardData[k][1] = fftData[i][j].imag();
+      k++;
+    }
+  }
+  
+  // Perform forward FFT
+  fftw_execute(_forwardPlan);
+
+  // Copy data back into fftData and scale by 1/((n-1) * (m-1))
+  double s = 1. / (double)((n - 1) * (m - 1));
+  k = 0;
+  for(int i = 0; i < n - 1; i++){
+    for(int j = 0; j < m - 1; j++){
+      fftData[i][j] = s * std::complex<double>(_forwardData[k][0], _forwardData[k][1]);
+      k++;
+    }
+  }
+}
+
+void FftPolyInterpolator2D::_BackwardFft(int n, int m, std::complex<double> **fftData)
+{
+  // Initialize fftw plan and array (ignoring last row and column of fftData)
+  _SetBackwardPlan(n - 1, m - 1);
+  int k = 0;
+  for(int i = 0; i < n - 1; i++){
+    for(int j = 0; j < m - 1; j++){
+      _backwardData[k][0] = fftData[i][j].real();
+      _backwardData[k][1] = fftData[i][j].imag();
+      k++;
+    }
+  }
+
+  // Perform backward FFT
+  fftw_execute(_backwardPlan);
+
+  // Copy data back into fftData 
+  k = 0;
+  for(int i = 0; i < n - 1; i++){
+    for(int j = 0; j < m - 1; j++){
+      fftData[i][j] = std::complex<double>(_backwardData[k][0], _backwardData[k][1]);
+      k++;
+    }
+  }
+
+  // Fill in last row and column with copy of first row and column
+  for(int i = 0; i <= n - 1; i++)
+    fftData[i][m - 1] = fftData[i][0];
+  for(int j = 0; j <= m - 1; j++)
+    fftData[n - 1][j] = fftData[0][j];
+}
+
+double FftPolyInterpolator2D::_PolyInterp(double start, double h, const double *vals, 
+					  double t, double *space)
+{
+  // Neville's Algorithm from Stoer and Bulirsch, Section 2.1.2
+  double tmp = (t - start)/h;
+  for(int i = 0; i <= _polyOrder; i++){
+    space[i] = vals[i];
+    for(int j = i - 1; j >= 0; j--)
+      space[j] = space[j + 1] + (space[j + 1] - space[j]) * ((tmp - i) / (i - j));
+  }
+  return space[0];
+}
+
+std::complex<double> FftPolyInterpolator2D::_Interpolate(double u, double v,
+							 int uDer, int vDer)
+{
+  if( ( (uDer == 2 || vDer == 2 || (uDer == 1 && vDer == 1)) && !(_derivative & 2) ) ||
+      ( (uDer == 1 || vDer == 1) && !(_derivative & 1) ) ||
+      (uDer < 0 || uDer > 2 || vDer < 0 || vDer > 2) ){
+    Msg::Error("Derivative data not available: check contructor call %d %d %d",uDer,vDer,_derivative);
+    return 0.;
+  }
+
+  double epsilon = 1e-12;
+  if(u < _uMin - epsilon || u > _uMax + epsilon){
+    Msg::Error("Trying to interpolate outside interval: (u,v)=(%.16g,%.16g) "
+	       "not in [%g,%g]x[%g,%g]", u, v, _uMin, _uMax, _vMin, _vMax);
+    return 0.;
+  }
+
+  // Choose uIndexStart and vIndexStart so that (u,v) is centered in
+  // the polynomial interpolation grid
+  int uIndexStart = (int)floor((u - _uFine[0]) / _hUFine) - _polyOrder / 2;
+  if(uIndexStart < 0)
+    uIndexStart = 0;
+  else if((uIndexStart + _polyOrder) > _uFineIntervals)
+    uIndexStart = _uFineIntervals - _polyOrder;
+
+  int vIndexStart = (int)floor((v - _vFine[0]) / _hVFine) - _polyOrder / 2;
+  if(vIndexStart < 0)
+    vIndexStart = 0;
+  else if((vIndexStart + _polyOrder) > _vFineIntervals)
+    vIndexStart = _vFineIntervals - _polyOrder;
+  
+  // Interpolate to find value at (u,v)
+  double start = _vFine[vIndexStart];
+  for(int i = 0; i <= _polyOrder; i++){
+    for(int j = 0; j <= _polyOrder; j++){
+      std::complex<double> tmp;
+      if(uDer == 0 && vDer == 0)
+	tmp = _fineData[uIndexStart + i][vIndexStart + j];
+      else if(uDer == 1 && vDer == 0)
+	tmp = _fineDerivU[uIndexStart + i][vIndexStart + j];
+      else if(uDer == 0 && vDer == 1)
+	tmp = _fineDerivV[uIndexStart + i][vIndexStart + j];
+      else if(uDer == 2 && vDer == 0)
+	tmp = _fineDerivUU[uIndexStart + i][vIndexStart + j];
+      else if(uDer == 0 && vDer == 2)
+	tmp = _fineDerivVV[uIndexStart + i][vIndexStart + j];
+      else
+	tmp = _fineDerivUV[uIndexStart + i][vIndexStart + j];
+      _tmpValsReal[j] = tmp.real();
+      _tmpValsImag[j] = tmp.imag();
+    }
+    _tmpInterpReal[i] = _PolyInterp(start, _hVFine, _tmpValsReal, v, _tmpSpace);
+    _tmpInterpImag[i] = _PolyInterp(start, _hVFine, _tmpValsImag, v, _tmpSpace);
+  }
+  
+  start = _uFine[uIndexStart];
+  return std::complex<double>(_PolyInterp(start, _hUFine, _tmpInterpReal, u, _tmpSpace), 
+			      _PolyInterp(start, _hUFine, _tmpInterpImag, u, _tmpSpace));
+}
+
+std::complex<double> FftPolyInterpolator2D::F(double u, double v)
+{
+  return _Interpolate(u, v, 0, 0);
+}
+
+std::complex<double> FftPolyInterpolator2D::Dfdu(double u, double v)
+{
+  return _Interpolate(u, v, 1, 0);
+}
+
+std::complex<double> FftPolyInterpolator2D::Dfdv(double u, double v)
+{
+  return _Interpolate(u, v, 0, 1);
+}
+
+std::complex<double> FftPolyInterpolator2D::Dfdfdudu(double u, double v)
+{
+  return _Interpolate(u, v, 2, 0);
+}
+
+std::complex<double> FftPolyInterpolator2D::Dfdfdvdv(double u, double v)
+{
+  return _Interpolate(u, v, 0, 2);
+}
+
+std::complex<double> FftPolyInterpolator2D::Dfdfdudv(double u, double v)
+{
+  return _Interpolate(u, v, 1, 1);
+}
diff --git a/contrib/FourierModel/Interpolator2D.h b/contrib/FourierModel/Interpolator2D.h
new file mode 100755
index 0000000000000000000000000000000000000000..df44f4c7d3db85aa06230e42ccdc829d8978954d
--- /dev/null
+++ b/contrib/FourierModel/Interpolator2D.h
@@ -0,0 +1,109 @@
+#ifndef _INTERPOLATOR_2D_H_
+#define _INTERPOLATOR_2D_H_
+
+#include <vector>
+#include <complex>
+#include <fftw3.h>
+#include "Message.h"
+
+// The base class for the 2D interpolators
+class Interpolator2D {
+ public:
+  Interpolator2D(){}
+  virtual ~Interpolator2D(){}
+  // interpolates the data at u,v
+  virtual std::complex<double> F(double u, double v) = 0;
+  // interpolates the first u derivative of the data at u,v
+  virtual std::complex<double> Dfdu(double u, double v)
+  {
+    Msg::Error("First derivative not implemented for this interpolator");
+    return 0.; 
+  }
+  // interpolates the first v derivative of the data at u,v
+  virtual std::complex<double> Dfdv(double u, double v)
+  {
+    Msg::Error("First derivative not implemented for this interpolator");
+    return 0.; 
+  }
+  // interpolates the second u derivative of the data at u,v
+  virtual std::complex<double> Dfdfdudu(double u, double v)
+  {
+    Msg::Error("Second derivative not implemented for this interpolator");
+    return 0.; 
+  }
+  // interpolates the second v derivative of the data at u,v
+  virtual std::complex<double> Dfdfdvdv(double u, double v)
+  {
+    Msg::Error("Second derivative not implemented for this interpolator");
+    return 0.; 
+  }
+  // interpolates the second cross derivative of the data at u,v
+  virtual std::complex<double> Dfdfdudv(double u, double v)
+  {
+    Msg::Error("Second derivative not implemented for this interpolator");
+    return 0.; 
+  }
+};
+
+// FFT + polynomial interpolation on refined grid (assumes that the
+// input grid is equally spaced and the input data is periodic)
+class FftPolyInterpolator2D : public Interpolator2D {
+ private:
+  // refinement factor (e.g. 16; if equal to 1, we just perform
+  // standard piecewise polynomial interpolation, without any FFTs)
+  int _refineFactor;
+  // order of the interpolating polynomial
+  int _polyOrder;
+  // signed length of the interval
+  double _uLength, _vLength;
+  // temporary interpolation variables
+  double *_tmpSpace, *_tmpValsReal, *_tmpValsImag, *_tmpInterpReal, *_tmpInterpImag;
+  // 1D polynomial interpolation routine
+  double _PolyInterp(double start, double h, const double *vals, 
+		     double t, double *space);
+  // interpolation wrapper
+  std::complex<double> _Interpolate(double u, double v, int uDer=0, int vDer=0);
+  // persistent fftw data (used to avoid recomputing the FFTW plans
+  // and reallocating memory every time)
+  static int _forwardSizeU, _forwardSizeV;
+  static int _backwardSizeU, _backwardSizeV;
+  static fftw_plan _forwardPlan, _backwardPlan;
+  static fftw_complex *_forwardData, *_backwardData;
+  void _SetForwardPlan(int n, int m);
+  void _SetBackwardPlan(int n, int m);
+ protected:
+  // number of intervals in the original and in the refined mesh
+  int _uIntervals, _vIntervals, _uFineIntervals, _vFineIntervals;
+  // fine mesh spacing
+  double _hUFine, _hVFine;
+  // min/max of input mesh
+  double _uMin, _uMax, _vMin, _vMax;
+  // bitfield telling if we also interpolate the derivative(s)
+  int _derivative;
+  // grid points of the refined mesh
+  double *_uFine, *_vFine;
+  // data (and its first 2 derivatives) on the refined regular grid
+  std::complex<double> **_fineData, **_fineDerivU, **_fineDerivV;
+  std::complex<double> **_fineDerivUU, **_fineDerivVV, **_fineDerivUV;
+  // This routine computes the forward FFT (ignoring the last row and
+  // column of the data)
+  void _ForwardFft(int n, int m, std::complex<double> **fftData);
+  // This routine computes the inverse FFT (ignoring the last row and
+  // column in the array), returns values in entire array (by using
+  // the periodic extension)
+  void _BackwardFft(int n, int m, std::complex<double> **fftData);
+ public:
+  FftPolyInterpolator2D(const std::vector<double> &u,
+			const std::vector<double> &v,
+			const std::vector< std::vector< std::complex<double> > > &data,
+			int refineFactor=16, int polyOrder=3, int derivative=0);
+  ~FftPolyInterpolator2D();
+  virtual std::complex<double> F(double u, double v);
+  virtual std::complex<double> Dfdu(double u, double v);
+  virtual std::complex<double> Dfdv(double u, double v);
+  virtual std::complex<double> Dfdfdudu(double u, double v);
+  virtual std::complex<double> Dfdfdvdv(double u, double v);
+  virtual std::complex<double> Dfdfdudv(double u, double v);
+};
+
+#endif
diff --git a/contrib/FourierModel/PartitionOfUnity.cpp b/contrib/FourierModel/PartitionOfUnity.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..13e079a5c691e3ee2215725dd3364c7fafc2e182
--- /dev/null
+++ b/contrib/FourierModel/PartitionOfUnity.cpp
@@ -0,0 +1 @@
+#include "PartitionOfUnity.h"
diff --git a/contrib/FourierModel/PartitionOfUnity.h b/contrib/FourierModel/PartitionOfUnity.h
new file mode 100755
index 0000000000000000000000000000000000000000..39f1e2e975322fa5d40b01eac95df8784c37ba37
--- /dev/null
+++ b/contrib/FourierModel/PartitionOfUnity.h
@@ -0,0 +1,136 @@
+#ifndef _PARTITION_OF_UNITY_H_
+#define _PARTITION_OF_UNITY_H_
+
+#include <cmath>
+
+inline double OneSidedPartitionOfUnity(double t0,
+				       double t1,
+				       double t)
+{
+  if (t <= t0) {
+    return 1.;
+  }
+  else if (t >= t1) {
+    return 0.;
+  } 
+  else {
+    double x = (t - t0) / (t1 - t0);
+    return exp(2.560851702 * exp(-1. / x) / (x - 1.));
+  }
+}
+
+inline double OneSidedPartitionOfUnityDt(double t0,
+					 double t1,
+					 double t)
+{
+  if (t <= t0) {
+    return 0.;
+  }
+  else if (t >= t1) {
+    return 0.;
+  } 
+  else {
+    // From Maple
+    return (0.2560851702e1 * pow(t - t0, -0.2e1) * (t1 - t0) * 
+	    exp(-0.10e1 / (t - t0) * (t1 - t0)) / ((t - t0) / (t1 - t0) - 0.10e1) - 
+	    0.2560851702e1 * exp(-0.10e1 / (t - t0) * (t1 - t0)) * 
+	    pow((t - t0) / (t1 - t0) - 0.10e1, -0.2e1) / (t1 - t0)) * 
+      exp(0.2560851702e1 * exp(-0.10e1 / (t - t0) * (t1 - t0)) / 
+	  ((t - t0) / (t1 - t0) - 0.10e1));
+  }
+}
+
+inline double OneSidedPartitionOfUnityDtDt(double t0,
+					   double t1,
+					   double t)
+{
+  if (t <= t0) {
+    return 0.;
+  }
+  else if (t >= t1) {
+    return 0.;
+  } 
+  else {
+    // From Maple
+    return ((-0.5121703404E1/pow(-t0+t,3.0)*(t1-t0)*exp(-0.1E1/(-t0+t)*(t1-t0))/
+	     ((-t0+t)/(t1-t0)-0.1E1)+0.2560851702E1/pow(-t0+t,4.0)*pow(t1-t0,2.0)*
+	     exp(-0.1E1/(-t0+t)*(t1-t0))/((-t0+t)/(t1-t0)-0.1E1)-0.5121703404E1/pow(-t0+t,2.0)*
+	     exp(-0.1E1/(-t0+t)*(t1-t0))/pow((-t0+t)/(t1-t0)-0.1E1,2.0)+0.5121703404E1*
+	     exp(-0.1E1/(-t0+t)*(t1-t0))/pow((-t0+t)/(t1-t0)-0.1E1,3.0)/pow(t1-t0,2.0))*
+	    exp(0.2560851702E1*exp(-0.1E1/(-t0+t)*(t1-t0))/((-t0+t)/(t1-t0)-0.1E1))+
+	    pow(0.2560851702E1/pow(-t0+t,2.0)*(t1-t0)*
+		exp(-0.1E1/(-t0+t)*(t1-t0))/((-t0+t)/(t1-t0)-0.1E1)-0.2560851702E1*
+		exp(-0.1E1/(-t0+t)*(t1-t0))/pow((-t0+t)/(t1-t0)-0.1E1,2.0)/(t1-t0),2.0)*
+	    exp(0.2560851702E1*exp(-0.1E1/(-t0+t)*(t1-t0))/((-t0+t)/(t1-t0)-0.1E1)));
+  }
+}
+
+// and we get the two sided POU by multiplying two One sided POUs
+inline double PartitionOfUnityInternalCall(double r,
+					   double start1, double end1,
+					   double end2, double start2)
+{
+  double leftPart = 1. - OneSidedPartitionOfUnity(start1, end1, r);
+  double rightPart = OneSidedPartitionOfUnity(end2, start2, r);
+  return leftPart * rightPart;
+}
+
+// and we get derivative of the the two sided POU by adding two One sided POUs
+inline double PartitionOfUnityDtInternalCall(double r,
+					     double start1, double end1,
+					     double end2, double start2)
+{
+  double leftPart = 1. - OneSidedPartitionOfUnity(start1, end1, r);
+  double rightPart = OneSidedPartitionOfUnity(end2, start2, r);
+  double leftPartDt = OneSidedPartitionOfUnityDt(start1, end1, r);
+  double rightPartDt = OneSidedPartitionOfUnityDt(end2, start2, r);
+  return leftPart * rightPartDt - rightPart * leftPartDt;
+}
+
+// and we get derivative of the the two sided POU by adding two One sided POUs
+inline double PartitionOfUnityDtDtInternalCall(double r,
+					       double start1, double end1,
+					       double end2, double start2)
+{
+  double leftPart = 1. - OneSidedPartitionOfUnity(start1, end1, r);
+  double rightPart = OneSidedPartitionOfUnity(end2, start2, r);
+  double leftPartDt = OneSidedPartitionOfUnityDt(start1, end1, r);
+  double rightPartDt = OneSidedPartitionOfUnityDt(end2, start2, r);
+  double leftPartDtDt = OneSidedPartitionOfUnityDtDt(start1, end1, r);
+  double rightPartDtDt = OneSidedPartitionOfUnityDtDt(end2, start2, r);
+
+  return leftPartDt * rightPartDt + leftPart * rightPartDtDt -
+    (rightPartDt * leftPartDt + rightPart * leftPartDtDt);
+}
+
+// Compute the value of a two sided partition of unity
+inline double PartitionOfUnity(double r,
+			       double start1, double end1,
+			       double end2, double start2)
+{
+  if(r < start1 || r > start2) { return 0.; }
+  if(r > end1 && r < end2) { return 1.; }
+  return PartitionOfUnityInternalCall(r, start1, end1, end2, start2);
+}
+
+// Compute the derivative of a two sided partition of unity
+inline double PartitionOfUnityDt(double r,
+				 double start1, double end1,
+				 double end2, double start2)
+{
+  if(r < start1 || r > start2) { return 0.; }
+  if(r > end1 && r < end2) { return 0.; }
+  return PartitionOfUnityDtInternalCall(r, start1, end1, end2, start2);
+}
+
+// Compute the second derivative of a two sided partition of unity
+inline double PartitionOfUnityDtDt(double r,
+				   double start1, double end1,
+				   double end2, double start2)
+{
+  if(r < start1 || r > start2) { return 0.; }
+  if(r > end1 && r < end2) { return 0.; }
+  return PartitionOfUnityDtDtInternalCall(r, start1, end1, end2, start2);
+}
+
+#endif
diff --git a/contrib/FourierModel/ProjectionSurface.cpp b/contrib/FourierModel/ProjectionSurface.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..a5db40119488cbc3fb2521532b5c725727587b2a
--- /dev/null
+++ b/contrib/FourierModel/ProjectionSurface.cpp
@@ -0,0 +1,355 @@
+#include <cmath>
+#include "ProjectionSurface.h"
+
+ProjectionSurface::ProjectionSurface
+(double uPeriod, double vPeriod)
+{
+  tag_ = -1;
+  name_ = std::string("default");
+  numParameters_ = 0;
+
+  uPeriod_ = uPeriod;
+  vPeriod_ = vPeriod;
+
+  if (uPeriod_ < 0.)
+    uPeriodic_ = false;
+  else
+    uPeriodic_ = true;
+
+  if (vPeriod_ < 0.)
+    vPeriodic_ = false;
+  else
+    vPeriodic_ = true;
+
+  for (int l=0;l<3;l++) {
+    O_[l] = E0_[l] = E1_[l] = E2_[l] = scale_[l] = 0.;
+  }
+}
+
+void ProjectionSurface::GetNormal
+(double u, double v, double &x, double &y, double &z)
+{
+  double dfdu[3], dfdv[3];
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  x = dfdu[1] * dfdv[2] - dfdu[2] * dfdv[1];
+  y = dfdu[2] * dfdv[0] - dfdu[0] * dfdv[2];
+  z = dfdu[0] * dfdv[1] - dfdu[1] * dfdv[0];
+}
+
+void ProjectionSurface::GetUnitNormal
+(double u, double v, double &x, double &y, double &z)
+{
+  GetNormal(u, v, x, y, z);
+  double norm = sqrt(x * x + y * y + z * z);
+  if(norm > 0.) {
+    x /= norm;
+    y /= norm;
+    z /= norm;
+  }  
+}
+
+void ProjectionSurface::Dndu
+(double u, double v, double &x, double &y, double &z) 
+{
+  double n[3],dfdu[3],dfdv[3],dfdfdudu[3],dfdfdudv[3],dfdfdvdv[3],dndu[3];
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  Dfdfdudu(u, v, dfdfdudu[0], dfdfdudu[1], dfdfdudu[2]);
+  Dfdfdudv(u, v, dfdfdudv[0], dfdfdudv[1], dfdfdudv[2]);
+  Dfdfdvdv(u, v, dfdfdvdv[0], dfdfdvdv[1], dfdfdvdv[2]);
+  GetNormal(u,v,n[0],n[1],n[2]);
+  double norm = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
+  double normSquared = norm * norm;
+  double normCubed = normSquared * norm;
+
+  dndu[0] = dfdfdudu[1] * dfdv[2] + dfdu[1] * dfdfdudv[2] - 
+    dfdfdudu[2] * dfdv[1] - dfdu[2] * dfdfdudv[1];
+  dndu[1] = dfdfdudu[2] * dfdv[0] + dfdu[2] * dfdfdudv[0] - 
+    dfdfdudu[0] * dfdv[2] - dfdu[0] * dfdfdudv[2];
+  dndu[2] = dfdfdudu[0] * dfdv[1] + dfdu[0] * dfdfdudv[1] - 
+    dfdfdudu[1] * dfdv[0] - dfdu[1] * dfdfdudv[0];
+
+  x = ((normSquared - n[0]*n[0])*dndu[0] - n[0]*n[1]*dndu[1] - 
+       n[0]*n[2]*dndu[2]) / normCubed;
+  y = ((normSquared - n[1]*n[1])*dndu[1] - n[1]*n[0]*dndu[0] -
+       n[1]*n[2]*dndu[2]) / normCubed;
+  z = ((normSquared - n[2]*n[2])*dndu[2] - n[2]*n[0]*dndu[0] -
+       n[2]*n[1]*dndu[1]) / normCubed;
+}
+
+void ProjectionSurface::
+Dndv(double u, double v, double &x, double &y, double &z) 
+{
+  double n[3],dfdu[3],dfdv[3],dfdfdudu[3],dfdfdudv[3],dfdfdvdv[3],dndv[3];
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  Dfdfdudu(u, v, dfdfdudu[0], dfdfdudu[1], dfdfdudu[2]);
+  Dfdfdudv(u, v, dfdfdudv[0], dfdfdudv[1], dfdfdudv[2]);
+  Dfdfdvdv(u, v, dfdfdvdv[0], dfdfdvdv[1], dfdfdvdv[2]);
+  GetNormal(u,v,n[0],n[1],n[2]);
+  double norm = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
+  double normSquared = norm * norm;
+  double normCubed = normSquared * norm;
+
+  dndv[0] = dfdfdudv[1] * dfdv[2] + dfdu[1] * dfdfdvdv[2] -
+    dfdfdudv[2] * dfdv[1] - dfdu[2] * dfdfdvdv[1];
+  dndv[1] = dfdfdudv[2] * dfdv[0] + dfdu[2] * dfdfdvdv[0] -
+    dfdfdudv[0] * dfdv[2] - dfdu[0] * dfdfdvdv[2];
+  dndv[2] = dfdfdudv[0] * dfdv[1] + dfdu[0] * dfdfdvdv[1] -
+    dfdfdudv[1] * dfdv[0] - dfdu[1] * dfdfdvdv[0];
+
+  x = ((normSquared - n[0]*n[0])*dndv[0] - n[0]*n[1]*dndv[1] - 
+       n[0]*n[2]*dndv[2]) / normCubed;
+  y = ((normSquared - n[1]*n[1])*dndv[1] - n[1]*n[0]*dndv[0] -
+       n[1]*n[2]*dndv[2]) / normCubed;
+  z = ((normSquared - n[2]*n[2])*dndv[2] - n[2]*n[0]*dndv[0] -
+       n[2]*n[1]*dndv[1]) / normCubed;
+}
+
+void ProjectionSurface::
+Dndndudu(double u, double v, double &x, double &y, double &z)
+{
+  double n[3],dfdu[3],dfdv[3],dfdfdudu[3],dfdfdudv[3],dfdfdvdv[3],
+    dfdfdfdududu[3],dfdfdfdududv[3],dfdfdfdudvdv[3],dfdfdfdvdvdv[3],
+    dndu[3],dndndudu[3];
+
+  GetNormal(u,v,n[0],n[1],n[2]);
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  Dfdfdudu(u, v, dfdfdudu[0], dfdfdudu[1], dfdfdudu[2]);
+  Dfdfdudv(u, v, dfdfdudv[0], dfdfdudv[1], dfdfdudv[2]);
+  Dfdfdvdv(u, v, dfdfdvdv[0], dfdfdvdv[1], dfdfdvdv[2]);
+  Dfdfdfdududu(u,v,dfdfdfdududu[0],dfdfdfdududu[1],dfdfdfdududu[2]);
+  Dfdfdfdududv(u,v,dfdfdfdududv[0],dfdfdfdududv[1],dfdfdfdududv[2]);
+  Dfdfdfdudvdv(u,v,dfdfdfdudvdv[0],dfdfdfdudvdv[1],dfdfdfdudvdv[2]);
+  Dfdfdfdvdvdv(u,v,dfdfdfdvdvdv[0],dfdfdfdvdvdv[1],dfdfdfdvdvdv[2]);
+
+  dndu[0] = dfdfdudu[1] * dfdv[2] + dfdu[1] * dfdfdudv[2] -
+    dfdfdudu[2] * dfdv[1] - dfdu[2] * dfdfdudv[1];
+  dndu[1] = dfdfdudu[2] * dfdv[0] + dfdu[2] * dfdfdudv[0] -
+    dfdfdudu[0] * dfdv[2] - dfdu[0] * dfdfdudv[2];
+  dndu[2] = dfdfdudu[0] * dfdv[1] + dfdu[0] * dfdfdudv[1] -
+    dfdfdudu[1] * dfdv[0] - dfdu[1] * dfdfdudv[0];
+
+  dndndudu[0] = dfdfdfdududu[1] * dfdv[2] + dfdfdudu[1] * dfdfdudv[2] + 
+    dfdfdudu[1] * dfdfdudv[2] + dfdu[1] * dfdfdfdududv[2] -
+    dfdfdfdududu[2] * dfdv[1] - dfdfdudu[2] * dfdfdudv[1]  - 
+    dfdfdudu[2] * dfdfdudv[1] - dfdu[2] * dfdfdfdududv[1];
+  dndndudu[1] = dfdfdfdududu[2] * dfdv[0] + dfdfdudu[2] * dfdfdudv[0] +
+    dfdfdudu[2] * dfdfdudv[0] + dfdu[2] * dfdfdfdududv[0]  -
+    dfdfdfdududu[0] * dfdv[2] - dfdfdudu[0] * dfdfdudv[2]  - 
+    dfdfdudu[0] * dfdfdudv[2] - dfdu[0] * dfdfdfdududv[2];
+  dndndudu[2] = dfdfdfdududu[0] * dfdv[1] + dfdfdudu[0] * dfdfdudv[1] +
+    dfdfdudu[0] * dfdfdudv[1] +  dfdu[0] * dfdfdfdududv[1] -
+    dfdfdfdududu[1] * dfdv[0] - dfdfdudu[1] * dfdfdudv[0]  - 
+    dfdfdudu[1] * dfdfdudv[0] - dfdu[1] * dfdfdfdududv[0];
+
+  double nDotN = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+  double nDotNu = n[0] * dndu[0] + n[1] * dndu[1] + n[2] * dndu[2];
+  double nuDotNu = dndu[0] * dndu[0] + dndu[1] * dndu[1] + dndu[2] * dndu[2];
+  double nDotNuu = n[0] * dndndudu[0] + n[1] * dndndudu[1] + 
+    n[2] * dndndudu[2];
+  
+  double norm = sqrt(nDotN);
+  double normCubed = nDotN * norm;
+  double normToFive = nDotN * normCubed;
+
+  x = (nDotN * dndndudu[0] - 2 * nDotNu * dndu[0] - 
+       (nuDotNu + nDotNuu) * n[0]) / normCubed +
+    3 * nDotNu * nDotNu * n[0] / normToFive;
+  y = (nDotN * dndndudu[1] - 2 * nDotNu * dndu[1] - 
+       (nuDotNu + nDotNuu) * n[1]) / normCubed +
+    3 * nDotNu * nDotNu * n[1] / normToFive;
+  z = (nDotN * dndndudu[2] - 2 * nDotNu * dndu[2] - 
+       (nuDotNu + nDotNuu) * n[2]) / normCubed +
+    3 * nDotNu * nDotNu * n[2] / normToFive;
+}
+
+void ProjectionSurface::
+Dndndudv(double u, double v, double &x, double &y, double &z)
+{
+  double n[3],dfdu[3],dfdv[3],dfdfdudu[3],dfdfdudv[3],dfdfdvdv[3],
+    dfdfdfdududu[3],dfdfdfdududv[3],dfdfdfdudvdv[3],dfdfdfdvdvdv[3],
+    dndu[3],dndv[3],dndndudv[3];
+
+  GetNormal(u,v,n[0],n[1],n[2]);
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  Dfdfdudu(u, v, dfdfdudu[0], dfdfdudu[1], dfdfdudu[2]);
+  Dfdfdudv(u, v, dfdfdudv[0], dfdfdudv[1], dfdfdudv[2]);
+  Dfdfdvdv(u, v, dfdfdvdv[0], dfdfdvdv[1], dfdfdvdv[2]);
+  Dfdfdfdududu(u,v,dfdfdfdududu[0],dfdfdfdududu[1],dfdfdfdududu[2]);
+  Dfdfdfdududv(u,v,dfdfdfdududv[0],dfdfdfdududv[1],dfdfdfdududv[2]);
+  Dfdfdfdudvdv(u,v,dfdfdfdudvdv[0],dfdfdfdudvdv[1],dfdfdfdudvdv[2]);
+  Dfdfdfdvdvdv(u,v,dfdfdfdvdvdv[0],dfdfdfdvdvdv[1],dfdfdfdvdvdv[2]);
+
+  dndu[0] = dfdfdudu[1] * dfdv[2] + dfdu[1] * dfdfdudv[2] -
+    dfdfdudu[2] * dfdv[1] - dfdu[2] * dfdfdudv[1];
+  dndu[1] = dfdfdudu[2] * dfdv[0] + dfdu[2] * dfdfdudv[0] -
+    dfdfdudu[0] * dfdv[2] - dfdu[0] * dfdfdudv[2];
+  dndu[2] = dfdfdudu[0] * dfdv[1] + dfdu[0] * dfdfdudv[1] -
+    dfdfdudu[1] * dfdv[0] - dfdu[1] * dfdfdudv[0];
+
+  dndv[0] = dfdfdudv[1] * dfdv[2] + dfdu[1] * dfdfdvdv[2] -
+    dfdfdudv[2] * dfdv[1] - dfdu[2] * dfdfdvdv[1];
+  dndv[1] = dfdfdudv[2] * dfdv[0] + dfdu[2] * dfdfdvdv[0] -
+    dfdfdudv[0] * dfdv[2] - dfdu[0] * dfdfdvdv[2];
+  dndv[2] = dfdfdudv[0] * dfdv[1] + dfdu[0] * dfdfdvdv[1] -
+    dfdfdudv[1] * dfdv[0] - dfdu[1] * dfdfdvdv[0];
+
+  dndndudv[0] = dfdfdfdududv[1] * dfdv[2] + dfdfdudu[1] * dfdfdvdv[2] + 
+    dfdfdudv[1] * dfdfdudv[2] + dfdu[1] * dfdfdfdudvdv[2] -
+    dfdfdfdududv[2] * dfdv[1] - dfdfdudu[2] * dfdfdvdv[1]  - 
+    dfdfdudv[2] * dfdfdudv[1] - dfdu[2] * dfdfdfdudvdv[1];
+  dndndudv[1] = dfdfdfdududv[2] * dfdv[0] + dfdfdudu[2] * dfdfdvdv[0] +
+    dfdfdudv[2] * dfdfdudv[0] + dfdu[2] * dfdfdfdudvdv[0]  -
+    dfdfdfdududv[0] * dfdv[2] - dfdfdudu[0] * dfdfdvdv[2]  - 
+    dfdfdudv[0] * dfdfdudv[2] - dfdu[0] * dfdfdfdudvdv[2];
+  dndndudv[2] = dfdfdfdududv[0] * dfdv[1] + dfdfdudu[0] * dfdfdvdv[1] +
+    dfdfdudv[0] * dfdfdudv[1] +  dfdu[0] * dfdfdfdudvdv[1] -
+    dfdfdfdududv[1] * dfdv[0] - dfdfdudu[1] * dfdfdvdv[0]  - 
+    dfdfdudv[1] * dfdfdudv[0] - dfdu[1] * dfdfdfdudvdv[0];
+
+  double nDotN = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+  double nDotNu = n[0] * dndu[0] + n[1] * dndu[1] + n[2] * dndu[2];
+  double nDotNv = n[0] * dndv[0] + n[1] * dndv[1] + n[2] * dndv[2];
+  double nuDotNv = dndu[0] * dndv[0] + dndu[1] * dndv[1] + dndu[2] * dndv[2];
+  double nDotNuv = n[0] * dndndudv[0] + n[1] * dndndudv[1] + 
+    n[2] * dndndudv[2];
+  
+  double norm = sqrt(nDotN);
+  double normCubed = nDotN * norm;
+  double normToFive = nDotN * normCubed;
+
+  x = (nDotN * dndndudv[0] - nDotNv * dndu[0] - nDotNu * dndv[0] -
+       (nuDotNv + nDotNuv) * n[0]) / normCubed +
+    3 * nDotNu * nDotNv * n[0] / normToFive;
+  y = (nDotN * dndndudv[1] - nDotNv * dndu[1] - nDotNu * dndv[1] -
+       (nuDotNv + nDotNuv) * n[1]) / normCubed +
+    3 * nDotNu * nDotNv * n[1] / normToFive;
+  z = (nDotN * dndndudv[2] - nDotNv * dndu[2] - nDotNu * dndv[2] -
+       (nuDotNv + nDotNuv) * n[2]) / normCubed +
+    3 * nDotNu * nDotNv * n[2] / normToFive;
+}
+
+void ProjectionSurface::
+Dndndvdv(double u, double v, double &x, double &y, double &z)
+{
+  double n[3],dfdu[3],dfdv[3],dfdfdudu[3],dfdfdudv[3],dfdfdvdv[3],
+    dfdfdfdududu[3],dfdfdfdududv[3],dfdfdfdudvdv[3],dfdfdfdvdvdv[3],
+    dndv[3],dndndvdv[3];
+
+  GetNormal(u,v,n[0],n[1],n[2]);
+  Dfdu(u, v, dfdu[0], dfdu[1], dfdu[2]);
+  Dfdv(u, v, dfdv[0], dfdv[1], dfdv[2]);
+  Dfdfdudu(u, v, dfdfdudu[0], dfdfdudu[1], dfdfdudu[2]);
+  Dfdfdudv(u, v, dfdfdudv[0], dfdfdudv[1], dfdfdudv[2]);
+  Dfdfdvdv(u, v, dfdfdvdv[0], dfdfdvdv[1], dfdfdvdv[2]);
+  Dfdfdfdududu(u,v,dfdfdfdududu[0],dfdfdfdududu[1],dfdfdfdududu[2]);
+  Dfdfdfdududv(u,v,dfdfdfdududv[0],dfdfdfdududv[1],dfdfdfdududv[2]);
+  Dfdfdfdudvdv(u,v,dfdfdfdudvdv[0],dfdfdfdudvdv[1],dfdfdfdudvdv[2]);
+  Dfdfdfdvdvdv(u,v,dfdfdfdvdvdv[0],dfdfdfdvdvdv[1],dfdfdfdvdvdv[2]);
+
+  dndv[0] = dfdfdudv[1] * dfdv[2] + dfdu[1] * dfdfdvdv[2] -
+    dfdfdudv[2] * dfdv[1] - dfdu[2] * dfdfdvdv[1];
+  dndv[1] = dfdfdudv[2] * dfdv[0] + dfdu[2] * dfdfdvdv[0] -
+    dfdfdudv[0] * dfdv[2] - dfdu[0] * dfdfdvdv[2];
+  dndv[2] = dfdfdudv[0] * dfdv[1] + dfdu[0] * dfdfdvdv[1] -
+    dfdfdudv[1] * dfdv[0] - dfdu[1] * dfdfdvdv[0];
+
+  dndndvdv[0] = dfdfdfdudvdv[1] * dfdv[2] + dfdfdudv[1] * dfdfdvdv[2] + 
+    dfdfdudv[1] * dfdfdvdv[2] + dfdu[1] * dfdfdfdvdvdv[2] -
+    dfdfdfdudvdv[2] * dfdv[1] - dfdfdudv[2] * dfdfdvdv[1]  - 
+    dfdfdudv[2] * dfdfdvdv[1] - dfdu[2] * dfdfdfdvdvdv[1];
+  dndndvdv[1] = dfdfdfdudvdv[2] * dfdv[0] + dfdfdudv[2] * dfdfdvdv[0] +
+    dfdfdudv[2] * dfdfdvdv[0] + dfdu[2] * dfdfdfdvdvdv[0]  -
+    dfdfdfdudvdv[0] * dfdv[2] - dfdfdudv[0] * dfdfdvdv[2]  - 
+    dfdfdudv[0] * dfdfdvdv[2] - dfdu[0] * dfdfdfdvdvdv[2];
+  dndndvdv[2] = dfdfdfdudvdv[0] * dfdv[1] + dfdfdudv[0] * dfdfdvdv[1] +
+    dfdfdudv[0] * dfdfdvdv[1] +  dfdu[0] * dfdfdfdvdvdv[1] -
+    dfdfdfdudvdv[1] * dfdv[0] - dfdfdudv[1] * dfdfdvdv[0]  - 
+    dfdfdudv[1] * dfdfdvdv[0] - dfdu[1] * dfdfdfdvdvdv[0];
+
+  double nDotN = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+  double nDotNv = n[0] * dndv[0] + n[1] * dndv[1] + n[2] * dndv[2];
+  double nvDotNv = dndv[0] * dndv[0] + dndv[1] * dndv[1] + dndv[2] * dndv[2];
+  double nDotNvv = n[0] * dndndvdv[0] + n[1] * dndndvdv[1] + 
+    n[2] * dndndvdv[2];
+  
+  double norm = sqrt(nDotN);
+  double normCubed = nDotN * norm;
+  double normToFive = nDotN * normCubed;
+
+  x = (nDotN * dndndvdv[0] - 2 * nDotNv * dndv[0] - 
+       (nvDotNv + nDotNvv) * n[0]) / normCubed +
+    3 * nDotNv * nDotNv * n[0] / normToFive;
+  y = (nDotN * dndndvdv[1] - 2 * nDotNv * dndv[1] - 
+       (nvDotNv + nDotNvv) * n[1]) / normCubed +
+    3 * nDotNv * nDotNv * n[1] / normToFive;
+  z = (nDotN * dndndvdv[2] - 2 * nDotNv * dndv[2] - 
+       (nvDotNv + nDotNvv) * n[2]) / normCubed +
+    3 * nDotNv * nDotNv * n[2] / normToFive;
+}
+
+void ProjectionSurface::
+Rotate(double A0, double A1, double A2)
+{
+  double tol = 1.e-14;
+
+  A0 = A0 * M_PI / 180.;
+  A1 = A1 * M_PI / 180.;
+  A2 = A2 * M_PI / 180.;
+
+  double cosA0 = cos(A0);
+  double sinA0 = sin(A0);
+  double cosA1 = cos(A1);
+  double sinA1 = sin(A1);
+  double cosA2 = cos(A2);
+  double sinA2 = sin(A2);
+
+  double c[3], E0[3], E1[3], E2[3];
+
+  for (int l = 0; l < 3; l++) {
+    E0[l] = E0_[l];
+    E1[l] = E1_[l];
+    E2[l] = E2_[l];
+  }
+
+  c[0] = cosA1 * cosA2;
+  c[1] = cosA1 * sinA2;
+  c[2] = - sinA1;
+
+  for (int l = 0; l < 3; l++)
+    E0_[l] = c[0] * E0[l] + c[1] * E1[l] + c[2] * E2[l];
+
+  c[0] = sinA0 * sinA1 * cosA2 - cosA0 * sinA2;
+  c[1] = sinA0 * sinA1 * sinA2 + cosA0 * cosA2;;
+  c[2] = sinA0 * cosA1;
+
+  for (int l = 0; l < 3; l++)
+    E1_[l] = c[0] * E0[l] + c[1] * E1[l] + c[2] * E2[l];
+
+  c[0] = cosA0 * sinA1 * cosA2 + sinA0 * sinA2;
+  c[1] = cosA0 * sinA1 * sinA2 - sinA0 * cosA2;;
+  c[2] = cosA0 * cosA1;
+
+  for (int l = 0; l < 3; l++)
+    E2_[l] = c[0] * E0[l] + c[1] * E1[l] + c[2] * E2[l];
+}
+
+void ProjectionSurface::
+Translate(double D0, double D1, double D2)
+{
+  O_[0] += D0;
+  O_[1] += D1;
+  O_[2] += D2;
+}
+
+void ProjectionSurface::
+Rescale(double S0, double S1, double S2)
+{
+  scale_[0] *= S0;
+  scale_[1] *= S1;
+  scale_[2] *= S2;
+}
diff --git a/contrib/FourierModel/ProjectionSurface.h b/contrib/FourierModel/ProjectionSurface.h
new file mode 100755
index 0000000000000000000000000000000000000000..72a5573ad0976bc5bfe1a5e26d3437cd11fb5bf4
--- /dev/null
+++ b/contrib/FourierModel/ProjectionSurface.h
@@ -0,0 +1,116 @@
+#ifndef _PROJECTION_SURFACE_H_
+#define _PROJECTION_SURFACE_H_
+
+#include <string>
+
+class ProjectionSurface {
+ private:
+  int tag_;
+  std::string name_;
+ protected:
+  int numParameters_;
+  double uPeriod_, vPeriod_;
+  bool uPeriodic_, vPeriodic_;
+  double O_[3], E0_[3], E1_[3], E2_[3], scale_[3];
+ public:
+  ProjectionSurface
+    (double uPeriod = -1., double vPeriod = -1.);
+
+  virtual ~ProjectionSurface() {}
+
+  inline int GetTag() { return tag_; }
+  inline void SetTag(int tag) { tag_ = tag; }
+
+  inline std::string GetName() { return name_; }
+  inline void SetName(std::string name) { name_ = name; }
+
+  inline int GetNumParameters() { return numParameters_; }
+
+  // Public access functions
+
+  inline void GetOrigin
+    (double &x, double &y, double &z)
+    {
+      x = O_[0]; y = O_[1]; z = O_[2];
+    }
+  inline void GetE0
+    (double &x, double &y, double &z)
+    {
+      x = E0_[0]; y = E0_[1]; z = E0_[2];
+    }
+  inline void GetE1
+    (double &x, double &y, double &z)
+    {
+      x = E1_[0]; y = E1_[1]; z = E1_[2];
+    }
+  inline void GetE2
+    (double &x, double &y, double &z)
+    {
+      x = E2_[0]; y = E2_[1]; z = E2_[2];
+    }
+  inline void GetScale
+    (double &x, double &y, double &z)
+    {
+      x = scale_[0]; y = scale_[1]; z = scale_[2];
+    }
+
+  // These are the virtual functions that must be provided 
+  // by all derived projection surfaces
+
+  virtual void F
+    (double u, double v, double &x, double &y, double &z) = 0;
+  virtual bool Inverse
+    (double x,double y,double z,double &u,double &v) = 0;
+  virtual void Dfdu
+    (double u, double v, double &x, double &y, double &z) = 0;
+  virtual void Dfdv
+    (double u, double v, double &x, double &y, double &z) = 0;
+  virtual void Dfdfdudu
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdudv
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdvdv
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdfdududu
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdfdududv
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdfdudvdv
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual void Dfdfdfdvdvdv
+    (double u,double v,double &x,double &y,double &z) = 0;
+  virtual bool OrthoProjectionOnSurface
+    (double x, double y, double z, double &u,double &v) = 0;
+  virtual void SetParameter
+    (int i, double x) = 0;
+  virtual double GetParameter
+    (int i) = 0;
+
+  // These functions may also be provided by the derived 
+  // projection surfaces (usually for better performance), 
+  // but they don't have to
+
+  virtual void GetNormal
+    (double u, double v, double &x, double &y, double &z);
+  virtual void GetUnitNormal
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndudu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndudv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dndndvdv
+    (double u, double v, double &x, double &y, double &z);
+
+  virtual void Rotate
+    (double A0, double A1, double A2);
+  virtual void Translate
+    (double D0, double D1, double D2);
+  virtual void Rescale
+    (double S0, double S1, double S2);
+};
+
+#endif
diff --git a/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp b/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..1e55997506c3aafafd404d226247e4a2ad2b4dc2
--- /dev/null
+++ b/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp
@@ -0,0 +1,266 @@
+#include "RevolvedParabolaProjectionSurface.h"
+
+RevolvedParabolaProjectionSurface::RevolvedParabolaProjectionSurface
+(int tag) : ProjectionSurface(1.) 
+{
+  SetTag(tag);
+  SetName(std::string("revolvedParabola"));
+
+  twoPi_ = 2 * M_PI;
+
+  R_ = 1.;
+  K_[0] = K_[1] = 0.5;
+
+  numParameters_ = 3;
+
+  O_[0] = O_[1] = O_[2] = 0.;
+
+  E0_[0] = 0.; E0_[1] = 0.; E0_[2] = 1.;
+  E1_[0] = 1.; E1_[1] = 0.; E1_[2] = 0.;
+  E2_[0] = 0.; E2_[1] = 1.; E2_[2] = 0.;
+
+  scale_[0] = scale_[1] = scale_[2] = 1.;
+}
+
+RevolvedParabolaProjectionSurface::RevolvedParabolaProjectionSurface
+(int tag, double O[3], double E0[3], double E1[3], double scale[3],
+ double R, double K[2]) : ProjectionSurface(1.) 
+{
+  SetTag(tag);
+  SetName(std::string("revolvedParabola"));
+
+  twoPi_ = 2 * M_PI;
+
+  R_ = R;
+  K_[0] = K[0]; K_[1] = K[1];
+
+  O_[0] = O[0]; O_[1] = O[1]; O_[2] = O[2];
+
+  E0_[0] = E0[0]; E0_[1] = E0[1]; E0_[2] = E0[2];
+  E1_[0] = E1[0]; E1_[1] = E1[1]; E1_[2] = E1[2];
+
+  E2_[0] = E0_[1] * E1_[2] - E0_[2] * E1_[1];
+  E2_[1] = E0_[2] * E1_[0] - E0_[0] * E1_[2];
+  E2_[2] = E0_[0] * E1_[1] - E0_[1] * E1_[0]; 
+
+  scale_[0] = scale[0]; scale_[1] = scale[1]; scale_[2] = scale[2];
+}
+
+void RevolvedParabolaProjectionSurface::F
+(double u, double v, double &x, double &y, double &z)
+{
+  x = O_[0] + (R_ + K_[0] * (v - 0.5)) *
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5))) + 
+    K_[1] * (v - 0.5) * (v - 0.5) * E0_[0];
+  y = O_[1] + (R_ + K_[0] * (v - 0.5)) *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5))) + 
+    K_[1] * (v - 0.5) * (v - 0.5) * E0_[1];
+  z = O_[2] + (R_ + K_[0] * (v - 0.5)) *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5))) + 
+    K_[1] * (v - 0.5) * (v - 0.5) * E0_[2];
+}
+
+bool RevolvedParabolaProjectionSurface::Inverse
+(double x, double y, double z, double &u,double &v)
+{
+  double R[3];
+  R[0] = x - O_[0];
+  R[1] = y - O_[1];
+  R[2] = z - O_[2];
+
+  double RdotT = 0., RdotNcT = 0.;
+  for (int i=0;i<3;i++) {
+    RdotT += R[i] * E1_[i];
+    RdotNcT += R[i] * E2_[i];
+  }
+
+  u = atan2(RdotNcT,RdotT);
+  u /= twoPi_;
+  u += 0.5;
+
+  v = sqrt(RdotT * RdotT + RdotNcT * RdotNcT);
+  v -= R_;
+  v /= K_[0];
+  v += 0.5;
+}
+
+void RevolvedParabolaProjectionSurface::Dfdu
+(double u, double v, double &x, double &y, double &z)
+{
+  x = twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (- E1_[0] * sin(twoPi_ * (u - 0.5)) + E2_[0] * cos(twoPi_ * (u - 0.5)));
+  y = twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (- E1_[1] * sin(twoPi_ * (u - 0.5)) + E2_[1] * cos(twoPi_ * (u - 0.5)));
+  z = twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (- E1_[2] * sin(twoPi_ * (u - 0.5)) + E2_[2] * cos(twoPi_ * (u - 0.5)));
+}
+
+void RevolvedParabolaProjectionSurface::Dfdv
+(double u, double v, double &x, double &y, double &z)
+{
+  x = K_[0] * 
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5))) + 
+    2. * K_[1] * (v - 0.5) * E0_[0];
+  y = K_[0] *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5))) + 
+    2. * K_[1] * (v - 0.5) * E0_[1];
+  z = K_[0] *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5))) + 
+    2. * K_[1] * (v - 0.5) * E0_[2];
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdudu
+(double u,double v, double &x, double &y, double &z)
+{
+  x = -  twoPi_ *  twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5)));
+  y = -  twoPi_ *  twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5)));
+  z = -  twoPi_ *  twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5)));
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdudv
+(double u, double v, double &x, double &y, double &z)
+{
+  x = K_[0] * twoPi_ *
+    (- E1_[0] * sin(twoPi_ * (u - 0.5)) + E2_[0] * cos(twoPi_ * (u - 0.5)));
+  y = K_[0] * twoPi_ *
+    (- E1_[1] * sin(twoPi_ * (u - 0.5)) + E2_[1] * cos(twoPi_ * (u - 0.5)));
+  z = K_[0] * twoPi_ *
+    (- E1_[2] * sin(twoPi_ * (u - 0.5)) + E2_[2] * cos(twoPi_ * (u - 0.5)));
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdvdv
+(double u, double v, double &x, double &y, double &z)
+{
+  x = 2. * K_[1] * E0_[0];
+  y = 2. * K_[1] * E0_[1];
+  z = 2. * K_[1] * E0_[2];
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdfdududu
+(double u,double v,double &x,double &y,double &z)
+{
+  x = twoPi_ *  twoPi_ * twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[0] * sin(twoPi_ * (u - 0.5)) - E2_[0] * cos(twoPi_ * (u - 0.5)));
+  y = twoPi_ *  twoPi_ * twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[1] * sin(twoPi_ * (u - 0.5)) - E2_[1] * cos(twoPi_ * (u - 0.5)));
+  z = twoPi_ *  twoPi_ * twoPi_ * (R_ + K_[0] * (v - 0.5)) *
+    (E1_[2] * sin(twoPi_ * (u - 0.5)) + E2_[2] * cos(twoPi_ * (u - 0.5)));
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdfdududv
+(double u,double v,double &x,double &y,double &z)
+{
+  x = -  twoPi_ *  twoPi_ * K_[0] *
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5)));
+  y = -  twoPi_ *  twoPi_ * K_[0]  *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5)));
+  z = -  twoPi_ *  twoPi_ * K_[0] *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5)));
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdfdudvdv
+(double u,double v,double &x,double &y,double &z)
+{
+  x = y = z = 0.;
+}
+
+void RevolvedParabolaProjectionSurface::Dfdfdfdvdvdv
+(double u,double v,double &x,double &y,double &z)
+{
+  x = y = z = 0.;
+}
+
+bool RevolvedParabolaProjectionSurface::OrthoProjectionOnSurface
+(double x, double y, double z, double& u, double& v)
+{
+  double R[3];
+  R[0] = x - O_[0];
+  R[1] = y - O_[1];
+  R[2] = z - O_[2];
+
+  double RdotT = 0., RdotNcT = 0.;
+  for (int i=0;i<3;i++) {
+    RdotT += R[i] * E1_[i];
+    RdotNcT += R[i] * E2_[i];
+  }
+
+  u = atan2(RdotNcT,RdotT);
+  u /= twoPi_;
+  u += 0.5;      
+
+  double A = - R_, B = 0.;
+  for (int i=0;i<3;i++) {
+    A += R[i] * (E1_[i] * cos(twoPi_ * (u - 0.5)) +
+		 E2_[i] * sin(twoPi_ * (u - 0.5)));
+    B += R[i] * E0_[i];
+  }
+
+  double a = 2 * K_[1] * K_[1];
+  double b = K_[0] * K_[0] - 2 * K_[1] * B;
+  double c = - K_[0] * A;
+
+  std::vector<double> root = SolveCubic(a,b,c);
+
+  if (root.size()) {
+    double xP,yP,zP;
+    double minDist = 1.e12;
+    for (int i=0;i<root.size();i++) {
+      F(u,root[i] + 0.5,xP,yP,zP);
+      double dist = sqrt((x-xP)*(x-xP)+(y-yP)*(y-yP)+(z-zP)*(z-zP));
+      if (dist < minDist) {
+	minDist = dist;
+	v = root[i] + 0.5;
+      }
+    }
+    double tol =1.e-4;
+    if ((u > - tol) && (u < 1. + tol) && (v > - tol) && (v < 1. + tol))
+      return true;
+    else
+      return false;
+  }
+  else
+    return false;
+}
+
+void RevolvedParabolaProjectionSurface::GetNormal
+(double u, double v, double &x, double &y, double &z)
+{
+  x = - 2. * K_[1] * (v - 0.5) * 
+    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5))) + 
+    K_[0] * E0_[0];
+  y = - 2. * K_[1] * (v - 0.5) *
+    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5))) +
+    K_[0] * E0_[1];
+  z = - 2. * K_[1] * (v - 0.5) *
+    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5))) +
+    K_[0] * E0_[2];
+}
+
+void RevolvedParabolaProjectionSurface::
+SetParameter(int i, double x)
+{
+  switch (i) {
+  case 0:
+    R_ = x;
+  case 1:
+    K_[0] = x;
+  case 2:
+    K_[1] = x;
+  }
+}
+
+double RevolvedParabolaProjectionSurface::
+GetParameter(int i)
+{
+  switch (i) {
+  case 0:
+    return R_;
+  case 1:
+    return K_[0];
+  case 2:
+    return K_[1];
+  }
+}
diff --git a/contrib/FourierModel/RevolvedParabolaProjectionSurface.h b/contrib/FourierModel/RevolvedParabolaProjectionSurface.h
new file mode 100755
index 0000000000000000000000000000000000000000..73e7a861ae02b1498ed0aa6c47e5a272d50ca733
--- /dev/null
+++ b/contrib/FourierModel/RevolvedParabolaProjectionSurface.h
@@ -0,0 +1,60 @@
+#ifndef _REVOLVED_PARABOLA_PROJECTION_SURFACE_H_
+#define _REVOLVED_PARABOLA_PROJECTION_SURFACE_H_
+
+#include <cmath>
+#include <vector>
+#include "Utils.h"
+#include "ProjectionSurface.h"
+
+class RevolvedParabolaProjectionSurface : public ProjectionSurface {
+ private:
+  double twoPi_;
+  double R_, K_[2];
+ public:
+  RevolvedParabolaProjectionSurface
+    (int tag);
+  RevolvedParabolaProjectionSurface
+    (int tag, double O[3], double E0[3], double E1[3], double scale[3],
+     double R, double K[2]);
+
+  virtual ~RevolvedParabolaProjectionSurface
+    () {}
+
+  // Abstract methods of ProjectionSurface
+
+  virtual void F
+    (double u, double v, double &x, double &y, double &z);
+  virtual bool Inverse
+    (double x,double y,double z,double &u,double &v);
+  virtual void Dfdu
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dfdv
+    (double u, double v, double &x, double &y, double &z);
+  virtual void Dfdfdudu
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdudv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdududu
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdududv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdudvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual void Dfdfdfdvdvdv
+    (double u,double v,double &x,double &y,double &z);
+  virtual bool OrthoProjectionOnSurface
+    (double x, double y, double z, double &u,double &v);
+  virtual void SetParameter
+    (int i, double x);
+  virtual double GetParameter
+    (int i);
+
+  // Redefinitions for RevolvedParabolaProjectionSurface
+
+  virtual void GetNormal
+    (double u, double v, double &x, double &y, double &z);
+};
+
+#endif
diff --git a/contrib/FourierModel/Utils.cpp b/contrib/FourierModel/Utils.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..956c8f8d9e1927d829b1056a5e755da0856ecf57
--- /dev/null
+++ b/contrib/FourierModel/Utils.cpp
@@ -0,0 +1,87 @@
+#include "Utils.h"
+
+std::vector<double> SolveCubic(double a, double b, double c)
+{
+  std::vector<double> root;
+  // find real roots of polynomial a*x^3+ b*x +c=0
+
+  double tol=pow(10.0, -12.);
+
+  double error=1.;
+  int maxiter=100; int iter=0;
+
+  std::vector<double> initial_guess(5);
+  initial_guess[0]=0.;
+  initial_guess[1]=1.;
+  initial_guess[2]=-1.;
+  initial_guess[3]=0.5;
+  initial_guess[4]=-0.5;
+  
+  bool find=0; int init=0;
+  double x0=0., x1, f, df;
+  
+  while (find==0 && init< 5){
+
+      init=init+1;
+      x0=initial_guess[init-1];
+      error=1.; iter=0;
+
+      while (error>tol && iter<maxiter){
+
+        f=a*x0*x0*x0+b*x0+c;
+        df=a*3.*x0*x0+b;
+
+        x1=x0-f/df;
+
+        error=std::abs(x1-x0);
+        x0=x1;
+        iter=iter+1;
+      }
+
+      if (iter<maxiter){
+        find=1;
+      }
+  }
+
+  if (find) {
+    root.push_back(x0);
+
+    //%polynomial a*x^3+ b*x +c=(x-x0)*(a*x^2+bb*x+cc)
+    //%where bb=a*x0, cc=-c/x0 (=b-a*x^2);
+  
+    double aa=a, bb=a*x0, cc=b-a*x0*x0;
+    double D=bb*bb-4.*aa*cc;
+    
+    if (D>=0.){
+      root.push_back((-bb+sqrt(D))/2./aa);
+      root.push_back((-bb-sqrt(D))/2./aa);
+    }
+  
+    // it seems that the solution obtained by quadratic formula
+    //is not so accurate --> used as initial guess.
+
+    if (root.size() == 3){
+      for (int i=0 ; i < 2 ; i++){
+	x0=root[i+1];
+	error=1.; iter=0;
+	while (error>tol && iter<maxiter){
+	  
+	  f=a*x0*x0*x0+b*x0+c;
+	  df=a*3.*x0*x0+b;
+	  
+	  x1=x0-f/df;
+	  
+	  error=std::abs(x1-x0);
+	  x0=x1;
+	  iter=iter+1;
+	}
+	root[i+1]=x0;
+      }
+    }
+  }
+
+  //  cout << a << ' ' << b << ' ' << c << ' ' <<
+  //     num << ' ' << root[0] << ' ' <<root[1] << ' ' << root[2] << endl; 
+
+  return root;
+}
diff --git a/contrib/FourierModel/Utils.h b/contrib/FourierModel/Utils.h
new file mode 100755
index 0000000000000000000000000000000000000000..9a51797d7e5f154d8dd84d19dc180235ac97974a
--- /dev/null
+++ b/contrib/FourierModel/Utils.h
@@ -0,0 +1,9 @@
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include <cmath>
+#include <vector>
+
+std::vector<double> SolveCubic(double a, double b, double c);
+
+#endif